4 changed files with 201 additions and 3 deletions
@ -0,0 +1,25 @@ |
|||||||
|
package cluster |
||||||
|
|
||||||
|
import ( |
||||||
|
"io/fs" |
||||||
|
"path/filepath" |
||||||
|
|
||||||
|
"github.com/hack-pad/hackpadfs/os" |
||||||
|
) |
||||||
|
|
||||||
|
// DirFS returns a file system (an [fs.FS]) for the tree
|
||||||
|
// of files rooted at the directory dir.
|
||||||
|
func DirFS(dir string) (fs.FS, error) { |
||||||
|
dir = filepath.Clean(dir) |
||||||
|
fullPath, err := filepath.Abs(dir) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
sub, err := os.NewFS().Sub(fullPath[1:]) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
return sub, nil |
||||||
|
} |
@ -0,0 +1,137 @@ |
|||||||
|
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, |
||||||
|
} { |
||||||
|
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 |
||||||
|
} |
Loading…
Reference in new issue