jpictl: introduce --config-file/-f as alternative to scanning m/ #19
Merged
amery
merged 3 commits from pr-amery-config_file
into main
1 year ago
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