local-server/pkg/clustersconfig/clustersconfig.go

257 lines
4.8 KiB
Go
Raw Normal View History

2018-06-17 07:32:44 +00:00
package clustersconfig
import (
2019-10-16 06:08:52 +00:00
"flag"
2018-06-17 07:32:44 +00:00
"fmt"
"io"
2019-10-16 06:08:52 +00:00
"log"
2018-06-17 07:32:44 +00:00
"net"
2019-10-16 06:08:52 +00:00
"os"
"path/filepath"
2018-06-17 07:32:44 +00:00
"strings"
"text/template"
yaml "gopkg.in/yaml.v2"
)
2019-10-16 06:08:52 +00:00
var (
templateDetailsDir = flag.String("template-details-dir",
2019-10-23 00:03:35 +00:00
filepath.Join(os.TempDir(), "dkl-dir2config"),
2019-10-16 06:08:52 +00:00
"write details of template execute in this dir")
templateID = 0
)
2018-06-17 07:32:44 +00:00
type Config struct {
2023-05-15 14:22:04 +00:00
Hosts []*Host
Clusters []*Cluster
Configs []*Template
StaticPods map[string][]*Template `yaml:"static_pods"`
Addons map[string][]*Template
SSLConfig string `yaml:"ssl_config"`
CertRequests []*CertRequest `yaml:"cert_requests"`
2018-06-17 07:32:44 +00:00
}
func FromBytes(data []byte) (*Config, error) {
2018-07-07 01:22:35 +00:00
config := &Config{Addons: make(map[string][]*Template)}
2018-06-17 07:32:44 +00:00
if err := yaml.Unmarshal(data, config); err != nil {
return nil, err
}
return config, nil
}
func FromFile(path string) (*Config, error) {
2024-04-15 13:32:43 +00:00
ba, err := os.ReadFile(path)
2018-06-17 07:32:44 +00:00
if err != nil {
return nil, err
}
return FromBytes(ba)
}
func (c *Config) Host(name string) *Host {
for _, host := range c.Hosts {
if host.Name == name {
return host
}
}
return nil
}
func (c *Config) HostByIP(ip string) *Host {
for _, host := range c.Hosts {
if host.IP == ip {
return host
}
for _, otherIP := range host.IPs {
if otherIP == ip {
return host
}
}
}
return nil
}
func (c *Config) HostByMAC(mac string) *Host {
// a bit of normalization
mac = strings.Replace(strings.ToLower(mac), "-", ":", -1)
for _, host := range c.Hosts {
if strings.ToLower(host.MAC) == mac {
return host
}
}
return nil
}
func (c *Config) Cluster(name string) *Cluster {
for _, cluster := range c.Clusters {
if cluster.Name == name {
return cluster
}
}
return nil
}
func (c *Config) ConfigTemplate(name string) *Template {
for _, cfg := range c.Configs {
if cfg.Name == name {
return cfg
}
}
return nil
}
func (c *Config) CSR(name string) *CertRequest {
for _, s := range c.CertRequests {
if s.Name == name {
return s
}
}
return nil
}
func (c *Config) SaveTo(path string) error {
ba, err := yaml.Marshal(c)
if err != nil {
return err
}
2024-04-15 13:32:43 +00:00
return os.WriteFile(path, ba, 0600)
2018-06-17 07:32:44 +00:00
}
type Template struct {
Name string
Template string
}
2019-10-23 00:03:35 +00:00
func (t *Template) Execute(contextName, elementName string, wr io.Writer, data interface{}, extraFuncs map[string]interface{}) error {
var templateFuncs = map[string]interface{}{
"indent": func(indent, s string) (indented string) {
indented = indent + strings.Replace(s, "\n", "\n"+indent, -1)
return
},
2023-05-15 13:54:23 +00:00
"yaml": func(v any) (s string, err error) {
ba, err := yaml.Marshal(v)
s = string(ba)
return
},
}
2018-06-17 07:32:44 +00:00
for name, f := range extraFuncs {
templateFuncs[name] = f
}
2018-06-17 07:32:44 +00:00
tmpl, err := template.New(t.Name).
Funcs(templateFuncs).
Parse(t.Template)
if err != nil {
return err
2018-06-17 07:32:44 +00:00
}
2019-10-16 06:08:52 +00:00
if *templateDetailsDir != "" {
templateID++
2019-10-23 00:03:35 +00:00
base := filepath.Join(*templateDetailsDir, contextName, fmt.Sprintf("%s-%03d", elementName, templateID))
os.MkdirAll(base, 0700)
2019-10-16 06:08:52 +00:00
2019-10-23 00:03:35 +00:00
base += string(filepath.Separator)
2019-10-16 06:08:52 +00:00
log.Print("writing template details: ", base, "{in,data,out}")
2024-04-15 13:32:43 +00:00
if err := os.WriteFile(base+"in", []byte(t.Template), 0600); err != nil {
2019-10-16 06:08:52 +00:00
return err
}
yamlBytes, err := yaml.Marshal(data)
if err != nil {
return err
}
2024-04-15 13:32:43 +00:00
if err := os.WriteFile(base+"data", yamlBytes, 0600); err != nil {
2019-10-16 06:08:52 +00:00
return err
}
out, err := os.Create(base + "out")
if err != nil {
return err
}
defer out.Close()
wr = io.MultiWriter(wr, out)
}
return tmpl.Execute(wr, data)
2018-06-17 07:32:44 +00:00
}
// Host represents a host served by this server.
type Host struct {
2019-02-28 08:27:09 +00:00
WithRev
2019-12-16 07:00:57 +00:00
2024-04-15 13:32:43 +00:00
Template bool `json:",omitempty"`
2019-12-16 07:00:57 +00:00
Name string
2024-04-15 13:32:43 +00:00
Labels map[string]string `json:",omitempty"`
Annotations map[string]string `json:",omitempty"`
2019-12-16 07:00:57 +00:00
2024-04-15 13:32:43 +00:00
MAC string `json:",omitempty"`
2018-06-17 07:32:44 +00:00
IP string
2024-04-15 13:32:43 +00:00
IPs []string `json:",omitempty"`
2018-06-17 07:32:44 +00:00
Cluster string
Group string
2024-04-15 13:32:43 +00:00
IPXE string `json:",omitempty"`
2022-04-28 01:33:19 +00:00
Kernel string
Initrd string
BootstrapConfig string `yaml:"bootstrap_config"`
Config string
Versions map[string]string
2023-05-15 14:22:04 +00:00
StaticPods string `yaml:"static_pods"`
Vars Vars
2018-06-17 07:32:44 +00:00
}
// Vars store user-defined key-values
type Vars map[string]interface{}
// Cluster represents a cluster of hosts, allowing for cluster-wide variables.
type Cluster struct {
2019-02-28 08:27:09 +00:00
WithRev
2019-12-16 07:00:57 +00:00
Name string
Labels map[string]string
Annotations map[string]string
Domain string
2023-05-15 12:47:53 +00:00
Addons []string
Subnets struct {
2018-06-17 07:32:44 +00:00
Services string
Pods string
}
2018-06-17 07:32:44 +00:00
Vars Vars
}
func (c *Cluster) KubernetesSvcIP() net.IP {
return c.NthSvcIP(1)
}
func (c *Cluster) DNSSvcIP() net.IP {
return c.NthSvcIP(2)
}
func (c *Cluster) NthSvcIP(n byte) net.IP {
_, cidr, err := net.ParseCIDR(c.Subnets.Services)
if err != nil {
panic(fmt.Errorf("invalid services CIDR: %v", err))
2018-06-17 07:32:44 +00:00
}
ip := cidr.IP
ip[len(ip)-1] += n
return ip
}