235 lines
4.6 KiB
Go
235 lines
4.6 KiB
Go
package clustersconfig
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
yaml "gopkg.in/yaml.v2"
|
|
)
|
|
|
|
// Debug enables debug logs from this package.
|
|
var Debug = false
|
|
|
|
func FromDir(
|
|
read func(path string) ([]byte, error),
|
|
assemble func(path string) ([]byte, error),
|
|
listBase func(path string) ([]string, error),
|
|
listMerged func(path string) ([]string, error),
|
|
) (*Config, error) {
|
|
|
|
load := func(dir, name string, out any) (err error) {
|
|
ba, err := assemble(filepath.Join(dir, name))
|
|
if err != nil {
|
|
return
|
|
}
|
|
err = yaml.UnmarshalStrict(ba, out)
|
|
if err != nil {
|
|
return
|
|
}
|
|
return nil
|
|
}
|
|
|
|
config := &Config{
|
|
Addons: make(map[string][]*Template),
|
|
StaticPods: make(map[string][]*Template),
|
|
}
|
|
|
|
// load clusters
|
|
names, err := listBase("clusters")
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to list clusters: %v", err)
|
|
}
|
|
|
|
for _, name := range names {
|
|
name, _ = strings.CutSuffix(name, ".yaml")
|
|
cluster := &Cluster{Name: name}
|
|
if err := load("clusters", name, cluster); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
config.Clusters = append(config.Clusters, cluster)
|
|
}
|
|
|
|
// load hosts
|
|
names, err = listBase("hosts")
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to list hosts: %v", err)
|
|
}
|
|
|
|
for _, name := range names {
|
|
name, _ = strings.CutSuffix(name, ".yaml")
|
|
o := &Host{Name: name}
|
|
if err := load("hosts", name, o); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
config.Hosts = append(config.Hosts, o)
|
|
}
|
|
|
|
// load config templates
|
|
loadTemplates := func(dir string, templates *[]*Template) error {
|
|
names, err := listMerged(dir)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to list %s: %v", dir, err)
|
|
}
|
|
|
|
for _, fullName := range names {
|
|
name, _ := strings.CutSuffix(fullName, ".yaml")
|
|
|
|
if hasTemplate(name, *templates) {
|
|
continue
|
|
}
|
|
|
|
ba, err := read(path.Join(dir, fullName))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
*templates = append(*templates, &Template{
|
|
Name: name,
|
|
Template: string(ba),
|
|
})
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
loadTemplates("configs", &config.Configs)
|
|
|
|
// cluster addons
|
|
for _, cluster := range config.Clusters {
|
|
addonSets := cluster.Addons
|
|
if len(addonSets) == 0 {
|
|
continue
|
|
}
|
|
|
|
for _, addonSet := range addonSets {
|
|
if _, ok := config.Addons[addonSet]; ok {
|
|
continue
|
|
}
|
|
|
|
templates := make([]*Template, 0)
|
|
if err = loadTemplates(path.Join("addons", addonSet), &templates); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
config.Addons[addonSet] = templates
|
|
}
|
|
}
|
|
|
|
// cluster static pods
|
|
for _, host := range config.Hosts {
|
|
bpSet := host.StaticPods
|
|
if bpSet == "" {
|
|
continue
|
|
}
|
|
|
|
if _, ok := config.StaticPods[bpSet]; ok {
|
|
continue
|
|
}
|
|
|
|
templates := make([]*Template, 0)
|
|
if err = loadTemplates(path.Join("static-pods", bpSet), &templates); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
config.StaticPods[bpSet] = templates
|
|
}
|
|
|
|
// load SSL configuration
|
|
if ba, err := read("ssl-config.json"); err == nil {
|
|
config.SSLConfig = string(ba)
|
|
|
|
} else if !os.IsNotExist(err) {
|
|
return nil, err
|
|
}
|
|
|
|
if ba, err := read("cert-requests.yaml"); err == nil {
|
|
reqs := make([]*CertRequest, 0)
|
|
if err = yaml.Unmarshal(ba, &reqs); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
config.CertRequests = reqs
|
|
|
|
} else if !os.IsNotExist(err) {
|
|
return nil, err
|
|
}
|
|
|
|
return config, nil
|
|
}
|
|
|
|
func hasTemplate(name string, templates []*Template) bool {
|
|
for _, tmpl := range templates {
|
|
if tmpl.Name == name {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
type dirStore struct {
|
|
path string
|
|
}
|
|
|
|
// listDir
|
|
func (b *dirStore) listDir(prefix string) (subDirs []string, err error) {
|
|
entries, err := ioutil.ReadDir(filepath.Join(b.path, prefix))
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
subDirs = make([]string, 0, len(entries))
|
|
|
|
for _, entry := range entries {
|
|
if !entry.IsDir() {
|
|
continue
|
|
}
|
|
|
|
name := entry.Name()
|
|
|
|
if len(name) == 0 || name[0] == '.' {
|
|
continue
|
|
}
|
|
|
|
subDirs = append(subDirs, name)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// Names is part of the kvStore interface
|
|
func (b *dirStore) List(prefix string) ([]string, error) {
|
|
files, err := filepath.Glob(filepath.Join(b.path, filepath.Join(path.Split(prefix)), "*.yaml"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
names := make([]string, 0, len(files))
|
|
for _, f := range files {
|
|
f2 := strings.TrimSuffix(f, ".yaml")
|
|
f2 = filepath.Base(f2)
|
|
|
|
if f2[0] == '.' { // ignore hidden files
|
|
continue
|
|
}
|
|
|
|
names = append(names, f2)
|
|
}
|
|
|
|
return names, nil
|
|
}
|
|
|
|
// Load is part of the DataBackend interface
|
|
func (b *dirStore) Get(key string) (ba []byte, err error) {
|
|
ba, err = ioutil.ReadFile(filepath.Join(b.path, filepath.Join(path.Split(key))+".yaml"))
|
|
if os.IsNotExist(err) {
|
|
return nil, nil
|
|
}
|
|
return
|
|
}
|