diff --git a/pkg/cluster/cluster_scan.go b/pkg/cluster/cluster_scan.go index 781619b..4b453d4 100644 --- a/pkg/cluster/cluster_scan.go +++ b/pkg/cluster/cluster_scan.go @@ -2,17 +2,25 @@ package cluster import ( "io/fs" + "path" "sort" "darvaza.org/core" ) +const ( + // ZoneRegionsFileName indicates the file containing + // region names as references + ZoneRegionsFileName = "regions" +) + func (m *Cluster) scan(opts *ScanOptions) error { for _, fn := range []func(*ScanOptions) error{ m.scanDirectory, m.scanMachines, m.scanZoneIDs, m.scanSort, + m.initRegions, m.scanGateways, m.scanCephMonitors, } { @@ -24,7 +32,7 @@ func (m *Cluster) scan(opts *ScanOptions) error { return nil } -func (m *Cluster) scanDirectory(_ *ScanOptions) error { +func (m *Cluster) scanDirectory(opts *ScanOptions) error { // each directory is a zone entries, err := fs.ReadDir(m.dir, ".") if err != nil { @@ -33,16 +41,14 @@ func (m *Cluster) scanDirectory(_ *ScanOptions) error { for _, e := range entries { if e.IsDir() { - z, err := m.newZone(e.Name()) + ok, err := m.scanSubdirectory(opts, e.Name()) switch { case err != nil: return core.Wrap(err, e.Name()) - case z.Machines.Len() == 0: - z.warn(nil). - WithField("zone", z.Name). + case !ok: + m.warn(nil). + WithField("zone", e.Name()). Print("empty") - default: - m.Zones = append(m.Zones, z) } } } @@ -50,6 +56,27 @@ func (m *Cluster) scanDirectory(_ *ScanOptions) error { return nil } +func (m *Cluster) scanSubdirectory(_ *ScanOptions, name string) (bool, error) { + z, err := m.newZone(name) + switch { + case err != nil: + // somewhere went wrong scanning the subdirectory + return false, err + case z.Machines.Len() > 0: + // zones have machines and the regions they belong + m.Zones = append(m.Zones, z) + return true, nil + case len(z.Regions) > 0: + // regions have no machines but can include + // other regions + m.appendRegionRegions(name, z.Regions...) + return true, nil + default: + // empty + return false, nil + } +} + func (m *Cluster) newZone(name string) (*Zone, error) { z := &Zone{ zones: m, @@ -154,31 +181,65 @@ func (z *Zone) scan() error { } for _, e := range entries { - if e.IsDir() { - m := &Machine{ - zone: z, - logger: z, - Name: e.Name(), - } + name := e.Name() - m.debug(). - WithField("node", m.Name). + switch { + case name == ZoneRegionsFileName: + err = z.loadRegions() + case e.IsDir(): + err = z.scanSubdirectory(name) + default: + z.warn(nil). WithField("zone", z.Name). - Print("found") + WithField("filename", name). + Print("unknown") + } - if err := m.init(); err != nil { - m.error(err). - WithField("node", m.Name). - WithField("zone", z.Name). - Print() + if err != nil { + return err + } + } - return err - } + return nil +} - z.Machines = append(z.Machines, m) +func (z *Zone) loadRegions() error { + filename := path.Join(z.Name, ZoneRegionsFileName) + regions, err := z.zones.ReadLines(filename) + + if err == nil { + // parsed + err = z.appendRegions(regions...) + if err != nil { + err = core.Wrap(err, filename) } } + return err +} + +func (z *Zone) scanSubdirectory(name string) error { + m := &Machine{ + zone: z, + logger: z, + Name: name, + } + + m.debug(). + WithField("node", m.Name). + WithField("zone", z.Name). + Print("found") + + if err := m.init(); err != nil { + m.error(err). + WithField("node", m.Name). + WithField("zone", z.Name). + Print() + + return err + } + + z.Machines = append(z.Machines, m) return nil } diff --git a/pkg/cluster/regions.go b/pkg/cluster/regions.go index 9f367e0..7745435 100644 --- a/pkg/cluster/regions.go +++ b/pkg/cluster/regions.go @@ -106,6 +106,38 @@ func (m *Cluster) setRegionZones(name string, zones ...*Zone) { }) } +func (m *Cluster) appendRegionRegions(name string, subs ...string) { + for i := range m.Regions { + r := &m.Regions[i] + + if name == r.Name { + // found + r.Regions = append(r.Regions, subs...) + return + } + } + + // new + m.Regions = append(m.Regions, Region{ + Name: name, + Regions: subs, + }) +} + +func (z *Zone) appendRegions(regions ...string) error { + for _, s := range regions { + // TODO: validate + z.debug(). + WithField("zone", z.Name). + WithField("region", s). + Print("attached") + + z.Regions = append(z.Regions, s) + } + + return nil +} + func (m *Cluster) finishRegion(r *Region) { if r.m != nil { // ready