local-server/pkg/clustersconfig/dir.go

331 lines
7.0 KiB
Go
Raw Normal View History

2018-06-17 07:32:44 +00:00
package clustersconfig
import (
2019-02-28 08:27:09 +00:00
"fmt"
2018-06-17 07:32:44 +00:00
"io/ioutil"
2019-02-28 08:27:09 +00:00
"log"
2018-06-17 07:32:44 +00:00
"os"
"path"
"path/filepath"
"strings"
yaml "gopkg.in/yaml.v2"
)
2019-02-28 08:27:09 +00:00
// Debug enables debug logs from this package.
var Debug = false
func FromDir(dirPath, defaultsPath string) (*Config, error) {
if Debug {
log.Printf("loading config from dir %s (defaults from %s)", dirPath, defaultsPath)
}
defaults, err := NewDefaults(defaultsPath)
if err != nil {
2019-03-01 01:37:51 +00:00
return nil, fmt.Errorf("failed to load defaults: %v", err)
2019-02-28 08:27:09 +00:00
}
2018-06-17 07:32:44 +00:00
2019-02-28 08:27:09 +00:00
store := &dirStore{dirPath}
load := func(dir, name string, out Rev) error {
2018-06-17 07:32:44 +00:00
ba, err := store.Get(path.Join(dir, name))
if err != nil {
2019-03-01 01:37:51 +00:00
return fmt.Errorf("failed to load %s/%s from dir: %v", dir, name, err)
2018-06-17 07:32:44 +00:00
}
2019-03-01 01:37:51 +00:00
if err = defaults.Load(dir, ".yaml", out, ba); err != nil {
return fmt.Errorf("failed to enrich %s/%s from defaults: %v", dir, name, err)
}
return nil
2018-06-17 07:32:44 +00:00
}
2019-10-09 05:58:28 +00:00
config := &Config{
Addons: make(map[string][]*Template),
BootstrapPods: make(map[string][]*Template),
}
2019-02-28 08:27:09 +00:00
2018-06-17 07:32:44 +00:00
// load clusters
names, err := store.List("clusters")
if err != nil {
2019-03-01 01:37:51 +00:00
return nil, fmt.Errorf("failed to list clusters: %v", err)
2018-06-17 07:32:44 +00:00
}
for _, name := range names {
cluster := &Cluster{Name: name}
if err := load("clusters", name, cluster); err != nil {
return nil, err
}
config.Clusters = append(config.Clusters, cluster)
}
// load groups
names, err = store.List("groups")
if err != nil {
2019-03-01 01:37:51 +00:00
return nil, fmt.Errorf("failed to list groups: %v", err)
2018-06-17 07:32:44 +00:00
}
2019-02-28 08:27:09 +00:00
read := func(rev, filePath string) (data []byte, fromDefaults bool, err error) {
data, err = store.Get(filePath)
if err != nil {
2019-03-01 01:37:51 +00:00
err = fmt.Errorf("faild to read %s: %v", filePath, err)
2019-02-28 08:27:09 +00:00
return
}
2019-03-01 01:37:51 +00:00
if data != nil {
return // ok
}
2019-02-28 08:27:09 +00:00
2019-03-01 01:37:51 +00:00
if len(rev) == 0 {
err = fmt.Errorf("entry not found: %s", filePath)
return
}
2019-02-28 08:27:09 +00:00
2019-03-01 01:37:51 +00:00
data, err = defaults.ReadAll(rev, filePath+".yaml")
if err != nil {
err = fmt.Errorf("failed to read %s:%s: %v", rev, filePath, err)
return
2019-02-28 08:27:09 +00:00
}
2019-03-01 01:37:51 +00:00
fromDefaults = true
2019-02-28 08:27:09 +00:00
return
}
template := func(rev, dir, name string, templates *[]*Template) (ref string, err error) {
ref = name
if len(name) == 0 {
return
}
ba, fromDefaults, err := read(rev, path.Join(dir, name))
if err != nil {
return
}
if fromDefaults {
ref = rev + ":" + name
}
if !hasTemplate(ref, *templates) {
if Debug {
log.Printf("new template in %s: %s", dir, ref)
}
*templates = append(*templates, &Template{
Name: ref,
Template: string(ba),
})
}
return
}
2018-06-17 07:32:44 +00:00
for _, name := range names {
2019-02-28 08:27:09 +00:00
group := &Group{Name: name}
if err := load("groups", name, group); err != nil {
2018-06-17 07:32:44 +00:00
return nil, err
}
2022-04-28 01:33:19 +00:00
group.BootstrapConfig, err = template(group.Rev(), "configs", group.BootstrapConfig, &config.Configs)
if err != nil {
return nil, fmt.Errorf("failed to load config for group %q: %v", name, err)
}
2019-02-28 08:27:09 +00:00
group.Config, err = template(group.Rev(), "configs", group.Config, &config.Configs)
if err != nil {
return nil, fmt.Errorf("failed to load config for group %q: %v", name, err)
}
if Debug {
2019-10-09 05:58:28 +00:00
log.Printf("group %q: config=%q static_pods=%q",
group.Name, group.Config, group.StaticPods)
2019-02-28 08:27:09 +00:00
}
group.StaticPods, err = template(group.Rev(), "static-pods", group.StaticPods, &config.StaticPods)
if err != nil {
return nil, fmt.Errorf("failed to load static pods for group %q: %v", name, err)
}
config.Groups = append(config.Groups, group)
2018-06-17 07:32:44 +00:00
}
// load hosts
names, err = store.List("hosts")
if err != nil {
2019-03-01 01:37:51 +00:00
return nil, fmt.Errorf("failed to list hosts: %v", err)
2018-06-17 07:32:44 +00:00
}
for _, name := range names {
o := &Host{Name: name}
if err := load("hosts", name, o); err != nil {
return nil, err
}
config.Hosts = append(config.Hosts, o)
}
// load config templates
2019-02-28 08:27:09 +00:00
loadTemplates := func(rev, dir string, templates *[]*Template) error {
names, err := store.List(dir)
2018-06-17 07:32:44 +00:00
if err != nil {
2019-03-01 01:37:51 +00:00
return fmt.Errorf("failed to list %s: %v", dir, err)
2018-06-17 07:32:44 +00:00
}
2019-02-28 08:27:09 +00:00
if len(rev) != 0 {
var defaultsNames []string
defaultsNames, err = defaults.List(rev, dir)
2018-06-17 07:32:44 +00:00
if err != nil {
2019-03-01 01:37:51 +00:00
return fmt.Errorf("failed to list %s:%s: %v", rev, dir, err)
2018-06-17 07:32:44 +00:00
}
2019-02-28 08:27:09 +00:00
names = append(names, defaultsNames...)
}
2018-06-17 07:32:44 +00:00
2019-02-28 08:27:09 +00:00
for _, name := range names {
if hasTemplate(name, *templates) {
continue
}
ba, _, err := read(rev, path.Join(dir, name))
if err != nil {
return err
}
*templates = append(*templates, &Template{
Name: name,
Template: string(ba),
})
2018-06-17 07:32:44 +00:00
}
return nil
}
2019-10-09 05:58:28 +00:00
// cluster addons
2019-02-28 08:27:09 +00:00
for _, cluster := range config.Clusters {
addonSet := cluster.Addons
if len(addonSet) == 0 {
continue
2018-07-07 01:22:35 +00:00
}
2019-02-28 08:27:09 +00:00
if _, ok := config.Addons[addonSet]; ok {
continue
}
2018-07-07 01:22:35 +00:00
2019-02-28 08:27:09 +00:00
templates := make([]*Template, 0)
if err = loadTemplates(cluster.Rev(), path.Join("addons", addonSet), &templates); err != nil {
return nil, err
2018-07-07 01:22:35 +00:00
}
2019-02-28 08:27:09 +00:00
config.Addons[addonSet] = templates
2018-07-07 01:22:35 +00:00
}
2019-10-09 05:58:28 +00:00
// cluster bootstrap pods
for _, cluster := range config.Clusters {
bpSet := cluster.BootstrapPods
if bpSet == "" {
continue
}
if _, ok := config.BootstrapPods[bpSet]; ok {
continue
}
templates := make([]*Template, 0)
if err = loadTemplates(cluster.Rev(), path.Join("bootstrap-pods", bpSet), &templates); err != nil {
return nil, err
}
config.BootstrapPods[bpSet] = templates
}
2018-07-07 01:22:35 +00:00
// load SSL configuration
2018-06-17 07:32:44 +00:00
if ba, err := ioutil.ReadFile(filepath.Join(dirPath, "ssl-config.json")); err == nil {
config.SSLConfig = string(ba)
} else if !os.IsNotExist(err) {
return nil, err
}
if ba, err := ioutil.ReadFile(filepath.Join(dirPath, "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
}
2019-02-28 08:27:09 +00:00
func hasTemplate(name string, templates []*Template) bool {
for _, tmpl := range templates {
if tmpl.Name == name {
return true
}
}
return false
}
2018-06-17 07:32:44 +00:00
type dirStore struct {
path string
}
2018-07-07 01:22:35 +00:00
// 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
}
2018-06-17 07:32:44 +00:00
// 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
2019-02-28 08:27:09 +00:00
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
2018-06-17 07:32:44 +00:00
}