You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
185 lines
2.9 KiB
185 lines
2.9 KiB
package zones |
|
|
|
import ( |
|
"io/fs" |
|
"sort" |
|
) |
|
|
|
func (m *Zones) scan(opts *ScanOptions) error { |
|
for _, fn := range []func(*ScanOptions) error{ |
|
m.scanDirectory, |
|
m.scanMachines, |
|
m.scanZoneIDs, |
|
m.scanSort, |
|
m.scanGateways, |
|
} { |
|
if err := fn(opts); err != nil { |
|
return err |
|
} |
|
} |
|
|
|
return nil |
|
} |
|
|
|
func (m *Zones) scanDirectory(_ *ScanOptions) error { |
|
// each directory is a zone |
|
entries, err := fs.ReadDir(m.dir, ".") |
|
if err != nil { |
|
return err |
|
} |
|
|
|
for _, e := range entries { |
|
if e.IsDir() { |
|
z := &Zone{ |
|
zones: m, |
|
Name: e.Name(), |
|
} |
|
|
|
if err := z.scan(); err != nil { |
|
return err |
|
} |
|
|
|
m.Zones = append(m.Zones, z) |
|
} |
|
} |
|
|
|
return nil |
|
} |
|
|
|
func (m *Zones) scanMachines(opts *ScanOptions) error { |
|
var err error |
|
m.ForEachMachine(func(p *Machine) bool { |
|
err = p.scan(opts) |
|
return err != nil |
|
}) |
|
return err |
|
} |
|
|
|
func (m *Zones) scanZoneIDs(_ *ScanOptions) error { |
|
var hasMissing bool |
|
var lastZoneID int |
|
|
|
m.ForEachZone(func(z *Zone) bool { |
|
switch { |
|
case z.ID == 0: |
|
hasMissing = true |
|
case z.ID > lastZoneID: |
|
lastZoneID = z.ID |
|
} |
|
|
|
return false |
|
}) |
|
|
|
if hasMissing { |
|
next := lastZoneID + 1 |
|
|
|
m.ForEachZone(func(z *Zone) bool { |
|
if z.ID == 0 { |
|
z.ID, next = next, next+1 |
|
} |
|
|
|
return false |
|
}) |
|
} |
|
|
|
return nil |
|
} |
|
|
|
func (m *Zones) scanSort(_ *ScanOptions) error { |
|
sort.SliceStable(m.Zones, func(i, j int) bool { |
|
id1 := m.Zones[i].ID |
|
id2 := m.Zones[j].ID |
|
return id1 < id2 |
|
}) |
|
|
|
m.ForEachZone(func(z *Zone) bool { |
|
sort.Sort(z) |
|
return false |
|
}) |
|
|
|
m.ForEachMachine(func(p *Machine) bool { |
|
sort.SliceStable(p.Rings, func(i, j int) bool { |
|
ri1 := p.Rings[i] |
|
ri2 := p.Rings[j] |
|
|
|
return ri1.Ring < ri2.Ring |
|
}) |
|
|
|
return false |
|
}) |
|
|
|
return nil |
|
} |
|
|
|
func (m *Zones) scanGateways(_ *ScanOptions) error { |
|
var err error |
|
|
|
m.ForEachZone(func(z *Zone) bool { |
|
_, _, err = z.GetGateway() |
|
return err != nil |
|
}) |
|
return err |
|
} |
|
|
|
func (z *Zone) scan() error { |
|
// each directory is a machine |
|
entries, err := fs.ReadDir(z.zones.dir, z.Name) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
for _, e := range entries { |
|
if e.IsDir() { |
|
m := &Machine{ |
|
zone: z, |
|
Name: e.Name(), |
|
} |
|
|
|
if err := m.init(); err != nil { |
|
return err |
|
} |
|
|
|
z.Machines = append(z.Machines, m) |
|
} |
|
} |
|
|
|
return nil |
|
} |
|
|
|
// GetGateway returns the first gateway found, if none |
|
// files will be created to enable the first [Machine] to |
|
// be one |
|
func (z *Zone) GetGateway() (*Machine, bool, error) { |
|
var first *Machine |
|
var gateway *Machine |
|
|
|
z.zones.ForEachMachine(func(p *Machine) bool { |
|
switch { |
|
case p.IsGateway(): |
|
// found |
|
gateway = p |
|
case first == nil: |
|
// remember |
|
first = p |
|
default: |
|
// keep looking |
|
} |
|
|
|
return gateway != nil |
|
}) |
|
|
|
switch { |
|
case gateway != nil: |
|
// found one |
|
return gateway, false, nil |
|
case first != nil: |
|
// make one |
|
if err := first.SetGateway(true); err != nil { |
|
return first, false, err |
|
} |
|
return first, true, nil |
|
default: |
|
// Zone without nodes? |
|
panic("unreachable") |
|
} |
|
}
|
|
|