Files
xc/backend/localini/localini.go
Pavel Vorobyov 7e2dec0ef0 project move
2019-09-24 11:04:48 +03:00

271 lines
5.5 KiB
Go

package localini
import (
"bufio"
"fmt"
"os"
"strings"
"github.com/viert/xc/config"
"github.com/viert/xc/store"
)
type parseSection int
const (
sectionWorkgroups parseSection = iota
sectionDatacenters
sectionGroups
sectionHosts
sectionNone
)
var (
lineCount = 0
)
// LocalIni backend loads hosts data from ini file
type LocalIni struct {
filename string
hosts []*store.Host
groups []*store.Group
workgroups []*store.WorkGroup
datacenters []*store.Datacenter
}
// New creates a new LocalIni backend
func New(cfg *config.XCConfig) (*LocalIni, error) {
filename, found := cfg.BackendCfg.Options["filename"]
if !found {
return nil, fmt.Errorf("localini backend filename option is missing")
}
return &LocalIni{filename: filename}, nil
}
// Hosts exported backend method
func (li *LocalIni) Hosts() []*store.Host {
return li.hosts
}
// Groups exported backend method
func (li *LocalIni) Groups() []*store.Group {
return li.groups
}
// WorkGroups exported backend method
func (li *LocalIni) WorkGroups() []*store.WorkGroup {
return li.workgroups
}
// Datacenters exported backend method
func (li *LocalIni) Datacenters() []*store.Datacenter {
return li.datacenters
}
// Load loads the data from file
func (li *LocalIni) Load() error {
f, err := os.Open(li.filename)
if err != nil {
return err
}
defer f.Close()
return li.read(f)
}
// Reload force reloads data from file
func (li *LocalIni) Reload() error {
return li.Load()
}
func (li *LocalIni) read(f *os.File) error {
var line string
li.datacenters = make([]*store.Datacenter, 0)
li.hosts = make([]*store.Host, 0)
li.groups = make([]*store.Group, 0)
li.workgroups = make([]*store.WorkGroup, 0)
lineCount = 0
section := sectionNone
scan := bufio.NewScanner(f)
for scan.Scan() {
lineCount++
line = strings.TrimSpace(scan.Text())
if line == "" || strings.HasPrefix(line, "#") {
continue
}
switch line {
case "[workgroups]":
section = sectionWorkgroups
case "[groups]":
section = sectionGroups
case "[datacenters]":
section = sectionDatacenters
case "[hosts]":
section = sectionHosts
default:
var err error
switch section {
case sectionNone:
err = fmt.Errorf("Unexpected line #%d outside sections: %s", lineCount, line)
case sectionWorkgroups:
err = li.addWorkgroup(line)
case sectionGroups:
err = li.addGroup(line)
case sectionDatacenters:
err = li.addDatacenter(line)
case sectionHosts:
err = li.addHost(line)
}
if err != nil {
return err
}
}
}
return nil
}
func parseLine(line string) (map[string]string, error) {
data := make(map[string]string)
tokens := strings.Split(line, " ")
if len(tokens) < 1 {
return nil, fmt.Errorf("Malformed line, can't read workgroup name at line %d: %s", lineCount, line)
}
data["id"] = tokens[0]
data["name"] = tokens[0]
tokens = tokens[1:]
for _, token := range tokens {
kv := strings.Split(token, "=")
if len(kv) != 2 {
return nil, fmt.Errorf("Invalid token \"%s\", expected key=value format at line %d", token, lineCount)
}
data[kv[0]] = kv[1]
}
return data, nil
}
func (li *LocalIni) addWorkgroup(line string) error {
data, err := parseLine(line)
if err != nil {
return err
}
wg := new(store.WorkGroup)
for key, value := range data {
switch key {
case "id":
wg.ID = value
case "name":
wg.Name = value
case "description":
wg.Description = value
default:
return fmt.Errorf("Invalid token %s at line %d: %s", key, lineCount, line)
}
}
li.workgroups = append(li.workgroups, wg)
return nil
}
func (li *LocalIni) addDatacenter(line string) error {
data, err := parseLine(line)
if err != nil {
return err
}
dc := new(store.Datacenter)
for key, value := range data {
switch key {
case "id":
dc.ID = value
case "name":
dc.Name = value
case "parent_id":
fallthrough
case "parent":
dc.ParentID = value
case "desc":
fallthrough
case "description":
dc.Description = value
default:
return fmt.Errorf("Invalid token %s at line %d: %s", key, lineCount, line)
}
}
li.datacenters = append(li.datacenters, dc)
return nil
}
func (li *LocalIni) addGroup(line string) error {
data, err := parseLine(line)
if err != nil {
return err
}
group := new(store.Group)
for key, value := range data {
switch key {
case "id":
group.ID = value
case "name":
group.Name = value
case "parent_id":
fallthrough
case "parent":
group.ParentID = value
case "tags":
group.Tags = strings.Split(value, ",")
case "description":
group.Description = value
case "workgroup":
fallthrough
case "wg":
fallthrough
case "wg_id":
group.WorkGroupID = value
default:
return fmt.Errorf("Invalid token %s at line %d: %s", key, lineCount, line)
}
}
li.groups = append(li.groups, group)
return nil
}
func (li *LocalIni) addHost(line string) error {
data, err := parseLine(line)
if err != nil {
return err
}
host := new(store.Host)
for key, value := range data {
switch key {
case "id":
host.ID = value
case "name":
host.FQDN = value
case "group_id":
fallthrough
case "group":
host.GroupID = value
case "aliases":
host.Aliases = strings.Split(value, ",")
case "tags":
host.Tags = strings.Split(value, ",")
case "description":
host.Description = value
case "datacenter":
fallthrough
case "datacenter_id":
fallthrough
case "dc":
fallthrough
case "dc_id":
host.DatacenterID = value
default:
return fmt.Errorf("Invalid token %s at line %d: %s", key, lineCount, line)
}
}
li.hosts = append(li.hosts, host)
return nil
}