diff --git a/cmd/dkl-dir2config/main.go b/cmd/dkl-dir2config/main.go index df5b536..aa9dd86 100644 --- a/cmd/dkl-dir2config/main.go +++ b/cmd/dkl-dir2config/main.go @@ -52,11 +52,6 @@ func main() { openIncludes() - if false { - assemble("hosts/m1") - log.Fatal("--- debug: end ---") - } - loadSrc() dst = &localconfig.Config{ diff --git a/cmd/dkl-dir2config/render-cluster.go b/cmd/dkl-dir2config/render-cluster.go index c3bf955..6b80962 100644 --- a/cmd/dkl-dir2config/render-cluster.go +++ b/cmd/dkl-dir2config/render-cluster.go @@ -9,10 +9,10 @@ import ( "novit.tech/direktil/local-server/pkg/clustersconfig" ) -func clusterFuncs(clusterSpec *clustersconfig.Cluster) map[string]interface{} { +func clusterFuncs(clusterSpec *clustersconfig.Cluster) map[string]any { cluster := clusterSpec.Name - return map[string]interface{}{ + return map[string]any{ "password": func(name, hash string) (s string) { return fmt.Sprintf("{{ password %q %q %q | quote }}", cluster, name, hash) }, @@ -36,7 +36,7 @@ func clusterFuncs(clusterSpec *clustersconfig.Cluster) map[string]interface{} { return fmt.Sprintf("{{ ca_dir %q %q }}", cluster, name), nil }, - "hosts_by_cluster": func(cluster string) (hosts []interface{}) { + "hosts_by_cluster": func(cluster string) (hosts []any) { for _, host := range src.Hosts { if host.Cluster == cluster { hosts = append(hosts, asMap(host)) @@ -50,7 +50,7 @@ func clusterFuncs(clusterSpec *clustersconfig.Cluster) map[string]interface{} { return }, - "hosts_by_group": func(group string) (hosts []interface{}) { + "hosts_by_group": func(group string) (hosts []any) { for _, host := range src.Hosts { if host.Cluster == cluster && host.Group == group { hosts = append(hosts, asMap(host)) @@ -63,6 +63,26 @@ func clusterFuncs(clusterSpec *clustersconfig.Cluster) map[string]interface{} { return }, + + "host_ip_from": func(hostName, net string) string { + host := src.Host(hostName) + if host == nil { + log.Printf("WARNING: no host named %q", hostName) + return "" + } + + ipFrom := host.IPFrom + if ipFrom == nil { + ipFrom = map[string]string{} + } + + ip, ok := ipFrom[net] + if !ok { + ip = host.IP + } + + return ip + }, } } diff --git a/cmd/dkl-dir2config/render-context.go b/cmd/dkl-dir2config/render-context.go index b4e6a4d..bc0ff3a 100644 --- a/cmd/dkl-dir2config/render-context.go +++ b/cmd/dkl-dir2config/render-context.go @@ -5,10 +5,12 @@ import ( "fmt" "io" "log" + "math/rand" "path" "reflect" "strings" + "github.com/cespare/xxhash" yaml "gopkg.in/yaml.v2" "novit.tech/direktil/pkg/config" @@ -201,7 +203,7 @@ func (ctx *renderContext) renderConfigTo(buf io.Writer, configTemplate *clusters } } -func (ctx *renderContext) templateFuncs(ctxMap map[string]interface{}) map[string]interface{} { +func (ctx *renderContext) templateFuncs(ctxMap map[string]any) map[string]interface{} { cluster := ctx.Cluster.Name getKeyCert := func(name, funcName string) (s string, err error) { @@ -242,7 +244,7 @@ func (ctx *renderContext) templateFuncs(ctxMap map[string]interface{}) map[strin } funcs := clusterFuncs(ctx.Cluster) - for k, v := range map[string]interface{}{ + for k, v := range map[string]any{ "default": func(value, defaultValue any) any { switch v := value.(type) { case string: @@ -281,11 +283,11 @@ func (ctx *renderContext) templateFuncs(ctxMap map[string]interface{}) map[strin return "{{ host_download_token }}" }, - "hosts_of_group": func() (hosts []interface{}) { - hosts = make([]interface{}, 0) + "hosts_of_group": func() (hosts []any) { + hosts = make([]any, 0) for _, host := range ctx.clusterConfig.Hosts { - if host.Group != ctx.Host.Group { + if host.Cluster == ctx.Cluster.Name && host.Group != ctx.Host.Group { continue } @@ -297,12 +299,31 @@ func (ctx *renderContext) templateFuncs(ctxMap map[string]interface{}) map[strin "hosts_of_group_count": func() (count int) { for _, host := range ctx.clusterConfig.Hosts { - if host.Group == ctx.Host.Group { + if host.Cluster == ctx.Cluster.Name && host.Group == ctx.Host.Group { count++ } } return }, + + "shuffled_hosts_by_group": func(group string) (hosts []any) { + for _, host := range src.Hosts { + if host.Cluster == ctx.Cluster.Name && host.Group == group { + hosts = append(hosts, asMap(host)) + } + } + + if len(hosts) == 0 { + log.Printf("WARNING: no hosts in group %q", group) + return + } + + seed := xxhash.Sum64String(ctx.Host.Name) + rng := rand.New(rand.NewSource(int64(seed))) + rng.Shuffle(len(hosts), func(i, j int) { hosts[i], hosts[j] = hosts[j], hosts[i] }) + + return + }, } { funcs[k] = v } diff --git a/cmd/dkl-local-server/state.go b/cmd/dkl-local-server/state.go index 916314a..e8ff842 100644 --- a/cmd/dkl-local-server/state.go +++ b/cmd/dkl-local-server/state.go @@ -148,9 +148,9 @@ func updateState() { hosts = append(hosts, h) } - hostTemplates := make([]string, 0, len(cfg.HostTemplates)) - for _, ht := range cfg.HostTemplates { - hostTemplates = append(hostTemplates, ht.Name) + hostTemplates := make([]string, len(cfg.HostTemplates)) + for i, ht := range cfg.HostTemplates { + hostTemplates[i] = ht.Name } // done diff --git a/pkg/clustersconfig/clustersconfig.go b/pkg/clustersconfig/clustersconfig.go index 9eb5ea3..bc46f0f 100644 --- a/pkg/clustersconfig/clustersconfig.go +++ b/pkg/clustersconfig/clustersconfig.go @@ -202,6 +202,9 @@ type Host struct { Cluster string Group string + Net string + IPFrom map[string]string `json:",omitempty" yaml:"ip_from"` + IPXE string `json:",omitempty"` Kernel string Initrd string