package cluster import ( "encoding/json" "fmt" "os" "gopkg.in/yaml.v3" ) func (m *Cluster) init(opts *ScanOptions) error { for _, fn := range []func(*ScanOptions) error{ m.initZones, m.scanZoneIDs, m.scanSort, m.scanGateways, m.initRegions, } { if err := fn(opts); err != nil { return err } } return nil } func (m *Cluster) initZones(opts *ScanOptions) error { var err error sub, err := DirFS(m.BaseDir) if err != nil { return err } m.dir = sub m.ForEachZone(func(z *Zone) bool { err = m.initZone(z, opts) return err != nil }) return err } func (m *Cluster) initZone(z *Zone, _ *ScanOptions) error { var hasMissing bool var lastMachineID int z.zones = m z.logger = m z.ForEachMachine(func(p *Machine) bool { p.zone = z p.logger = z switch { case p.ID == 0: hasMissing = true case p.ID > lastMachineID: lastMachineID = z.ID } return false }) if hasMissing { next := lastMachineID + 1 z.ForEachMachine(func(p *Machine) bool { if p.ID == 0 { p.ID, next = next, next+1 } return false }) } z.ForEachMachine(func(p *Machine) bool { p.Name = fmt.Sprintf("%s-%v", z.Name, p.ID) return false }) return nil } func decodeConfigData(data []byte) (out *Cluster, err error) { // try JSON first out = new(Cluster) err = json.Unmarshal(data, out) if err == nil { // good json return out, nil } else if _, ok := err.(*json.SyntaxError); !ok { // bad json return nil, err } out = new(Cluster) err = yaml.Unmarshal(data, out) if err != nil { // bad yaml too return nil, err } // good yaml return out, nil } // NewFromConfig loads the cluster data from the given file func NewFromConfig(filename string, opts ...ScanOption) (*Cluster, error) { var scanOptions ScanOptions data, err := os.ReadFile(filename) if err != nil { return nil, err } m, err := decodeConfigData(data) if err != nil { return nil, err } for _, opt := range opts { if err = opt(m, &scanOptions); err != nil { return nil, err } } if err = m.setScanDefaults(&scanOptions); err != nil { return nil, err } if err := m.init(&scanOptions); err != nil { return nil, err } return m, nil }