diff --git a/Makefile b/Makefile index 8ba4ff4d..e0a6d4c3 100644 --- a/Makefile +++ b/Makefile @@ -225,11 +225,16 @@ man_pages: man_page ./man_page ./man_pages cd man_pages; for i in wwctl*1; do echo "Compressing manpage: $$i"; gzip --force $$i; done -config_defaults: +config_defaults: vendor cmd/config_defaults/config_defaults.go cd cmd/config_defaults && go build -ldflags="-X 'github.com/hpcng/warewulf/internal/pkg/warewulfconf.ConfigFile=./etc/warewulf.conf'\ -X 'github.com/hpcng/warewulf/internal/pkg/node.ConfigFile=./etc/nodes.conf'"\ -mod vendor -tags "$(WW_GO_BUILD_TAGS)" -o ../../config_defaults +update_configuration: vendor cmd/update_configuration/update_configuration.go + cd cmd/update_configuration && go build -ldflags="-X 'github.com/hpcng/warewulf/internal/pkg/warewulfconf.ConfigFile=./etc/warewulf.conf'\ + -X 'github.com/hpcng/warewulf/internal/pkg/node.ConfigFile=./etc/nodes.conf'"\ + -mod vendor -tags "$(WW_GO_BUILD_TAGS)" -o ../../update_configuration + warewulfconf: config_defaults ./config_defaults @@ -255,6 +260,7 @@ clean: rm -f Defaults.mk rm -rf $(TOOLS_DIR) rm -f config_defaults + rm -f update_configuration install: files install_wwclient diff --git a/cmd/update_configuration/update_configuration.go b/cmd/update_configuration/update_configuration.go new file mode 100644 index 00000000..2c7e69a2 --- /dev/null +++ b/cmd/update_configuration/update_configuration.go @@ -0,0 +1,212 @@ +package main + +import ( + "flag" + "fmt" + "io/ioutil" + "os" + + "github.com/hpcng/warewulf/cmd/update_configuration/vers42" + "github.com/hpcng/warewulf/cmd/update_configuration/vers43" + "github.com/hpcng/warewulf/internal/pkg/buildconfig" + "github.com/hpcng/warewulf/internal/pkg/util" + "gopkg.in/yaml.v2" +) + +var nowrite bool +var confFile string + +type nodeVersionOnly struct { + WWInternal int `yaml:"WW_INTERNAL"` +} + +func saveConf(conf interface{}) { + out, err := yaml.Marshal(conf) + if err != nil { + fmt.Printf("Error in marshal of conf: %s\n", err) + os.Exit(1) + } + if nowrite { + fmt.Println(string(out)) + } else { + err = util.CopyFile(confFile, confFile+".bak") + if err != nil { + fmt.Printf("Could write file: %s\n", err) + os.Exit(1) + } + info, err := os.Stat(confFile) + if err != nil { + fmt.Printf("Could not get file mode: %s\n", err) + os.Exit(1) + } + err = ioutil.WriteFile(confFile, out, info.Mode()) + } +} + +func printB(x bool) string { + if x { + return "true" + } + return "false" +} + +func main() { + var endVers int + var startVers int + flag.StringVar(&confFile, "f", "", "Config file for update") + flag.IntVar(&endVers, "e", buildconfig.WWVer, "Final version of configuration file") + flag.IntVar(&startVers, "s", 0, "Start version of configuration file, 0 is for autodetection") + flag.BoolVar(&nowrite, "n", false, "Do not write, just print new conf to terminal") + flag.Parse() + if confFile == "" { + fmt.Printf("No config file given\n!") + os.Exit(1) + } + fmt.Printf("Opening node configuration file: %s\n", confFile) + data, err := ioutil.ReadFile(confFile) + if err != nil { + fmt.Printf("Could open file %v\n", err) + os.Exit(1) + } + if startVers == 0 { + var getConf nodeVersionOnly + fmt.Printf("Unmarshaling the node configuration\n") + err = yaml.Unmarshal(data, &getConf) + if err != nil { + fmt.Printf("Could not unmarshall: %v\n", err) + } + fmt.Printf("Got version %v in %s\n", getConf.WWInternal, confFile) + if getConf.WWInternal == 0 { + startVers = 42 + } + } + var conf42 vers42.NodeYaml + conf42.NodeProfiles = make(map[string]*vers42.NodeConf) + conf42.Nodes = make(map[string]*vers42.NodeConf) + + var conf43 vers43.NodeYaml + conf43.NodeProfiles = make(map[string]*vers43.NodeConf) + conf43.Nodes = make(map[string]*vers43.NodeConf) + conf43.WWInternal = 43 + + if startVers == 42 { + fmt.Printf("Unmarshaling the node configuration vers 42\n") + err = yaml.Unmarshal(data, &conf42) + if err != nil { + fmt.Printf("Could not unmarshall version 42: %v\n", err) + } + for pname, profile := range conf42.NodeProfiles { + profileConf := vers43.NodeConf{ + Comment: profile.Comment, + ClusterName: profile.ClusterName, + ContainerName: profile.ContainerName, + Init: profile.Init, + Root: profile.Root, + Discoverable: printB(profile.Discoverable), + Profiles: profile.Profiles, + Ipxe: profile.Ipxe} + conf43.NodeProfiles[pname] = &profileConf + if profile.RuntimeOverlay != "" { + conf43.NodeProfiles[pname].RuntimeOverlay = []string{profile.RuntimeOverlay} + } + if profile.SystemOverlay != "" { + conf43.NodeProfiles[pname].SystemOverlay = []string{profile.SystemOverlay} + } + if profile.KernelArgs != "" || profile.KernelVersion != "" { + conf43.NodeProfiles[pname].Kernel = new(vers43.KernelConf) + conf43.NodeProfiles[pname].Kernel.Override = profile.KernelVersion + conf43.NodeProfiles[pname].Kernel.Args = profile.KernelArgs + + } + if profile.IpmiUserName != "" || profile.IpmiPassword != "" || profile.IpmiIpaddr != "" || + profile.IpmiNetmask != "" || profile.IpmiPort != "" || profile.IpmiGateway != "" || + profile.IpmiInterface != "" { + conf43.NodeProfiles[pname].Ipmi = new(vers43.IpmiConf) + conf43.NodeProfiles[pname].Ipmi.UserName = profile.IpmiUserName + conf43.NodeProfiles[pname].Ipmi.Password = profile.IpmiPassword + conf43.NodeProfiles[pname].Ipmi.Ipaddr = profile.IpmiIpaddr + conf43.NodeProfiles[pname].Ipmi.Netmask = profile.IpmiNetmask + conf43.NodeProfiles[pname].Ipmi.Port = profile.IpmiPort + conf43.NodeProfiles[pname].Ipmi.Gateway = profile.IpmiGateway + conf43.NodeProfiles[pname].Ipmi.Interface = profile.IpmiInterface + } + if len(profile.Keys) != 0 { + conf43.NodeProfiles[pname].Keys = map[string]string{} + for k, v := range profile.Keys { + conf43.NodeProfiles[pname].Keys[k] = v + } + } + conf43.NodeProfiles[pname].NetDevs = make(map[string]*vers43.NetDevs) + for devn, netdev := range profile.NetDevs { + var device vers43.NetDevs = vers43.NetDevs{ + Type: netdev.Type, + Default: printB(netdev.Default), + Hwaddr: netdev.Hwaddr, + Ipaddr: netdev.Ipaddr, + IpCIDR: netdev.IpCIDR, + Prefix: netdev.Prefix, + Netmask: netdev.Netmask, + Gateway: netdev.Gateway} + conf43.NodeProfiles[pname].NetDevs[devn] = &device + } + + } + for nname, node := range conf42.Nodes { + nodeConf := vers43.NodeConf{ + Comment: node.Comment, + ClusterName: node.ClusterName, + ContainerName: node.ContainerName, + Init: node.Init, + Root: node.Root, + Discoverable: printB(node.Discoverable), + Profiles: node.Profiles, + Ipxe: node.Ipxe} + conf43.Nodes[nname] = &nodeConf + if node.RuntimeOverlay != "" { + conf43.Nodes[nname].RuntimeOverlay = []string{node.RuntimeOverlay} + } + if node.SystemOverlay != "" { + conf43.Nodes[nname].SystemOverlay = []string{node.SystemOverlay} + } + if node.KernelArgs != "" || node.KernelVersion != "" { + conf43.Nodes[nname].Kernel = new(vers43.KernelConf) + conf43.Nodes[nname].Kernel.Override = node.KernelVersion + conf43.Nodes[nname].Kernel.Args = node.KernelArgs + + } + if node.IpmiUserName != "" || node.IpmiPassword != "" || node.IpmiIpaddr != "" || + node.IpmiNetmask != "" || node.IpmiPort != "" || node.IpmiGateway != "" || + node.IpmiInterface != "" { + conf43.Nodes[nname].Ipmi = new(vers43.IpmiConf) + conf43.Nodes[nname].Ipmi.UserName = node.IpmiUserName + conf43.Nodes[nname].Ipmi.Password = node.IpmiPassword + conf43.Nodes[nname].Ipmi.Ipaddr = node.IpmiIpaddr + conf43.Nodes[nname].Ipmi.Netmask = node.IpmiNetmask + conf43.Nodes[nname].Ipmi.Port = node.IpmiPort + conf43.Nodes[nname].Ipmi.Gateway = node.IpmiGateway + conf43.Nodes[nname].Ipmi.Interface = node.IpmiInterface + } + if len(node.Keys) != 0 { + conf43.Nodes[nname].Keys = map[string]string{} + for k, v := range node.Keys { + conf43.Nodes[nname].Keys[k] = v + } + } + conf43.Nodes[nname].NetDevs = make(map[string]*vers43.NetDevs) + for devn, netdev := range node.NetDevs { + var device vers43.NetDevs = vers43.NetDevs{ + Type: netdev.Type, + Default: printB(netdev.Default), + Hwaddr: netdev.Hwaddr, + Ipaddr: netdev.Ipaddr, + IpCIDR: netdev.IpCIDR, + Prefix: netdev.Prefix, + Netmask: netdev.Netmask, + Gateway: netdev.Gateway} + conf43.Nodes[nname].NetDevs[devn] = &device + } + } + saveConf(conf43) + + } +} diff --git a/cmd/update_configuration/vers42/datastructure.go b/cmd/update_configuration/vers42/datastructure.go new file mode 100644 index 00000000..b1321786 --- /dev/null +++ b/cmd/update_configuration/vers42/datastructure.go @@ -0,0 +1,97 @@ +package vers42 + +/****** + * YAML data representations + ******/ + +//type nodeYaml struct { +type NodeYaml struct { + NodeProfiles map[string]*NodeConf + Nodes map[string]*NodeConf +} + +type NodeConf struct { + Comment string `yaml:"comment,omitempty"` + ClusterName string `yaml:"cluster name,omitempty"` + ContainerName string `yaml:"container name,omitempty"` + Ipxe string `yaml:"ipxe template,omitempty"` + KernelVersion string `yaml:"kernel version,omitempty"` + KernelArgs string `yaml:"kernel args,omitempty"` + IpmiUserName string `yaml:"ipmi username,omitempty"` + IpmiPassword string `yaml:"ipmi password,omitempty"` + IpmiIpaddr string `yaml:"ipmi ipaddr,omitempty"` + IpmiNetmask string `yaml:"ipmi netmask,omitempty"` + IpmiPort string `yaml:"ipmi port,omitempty"` + IpmiGateway string `yaml:"ipmi gateway,omitempty"` + IpmiInterface string `yaml:"ipmi interface,omitempty"` + RuntimeOverlay string `yaml:"runtime overlay,omitempty"` + SystemOverlay string `yaml:"system overlay,omitempty"` + Init string `yaml:"init,omitempty"` + Root string `yaml:"root,omitempty"` + Discoverable bool `yaml:"discoverable,omitempty"` + Profiles []string `yaml:"profiles,omitempty"` + NetDevs map[string]*NetDevs `yaml:"network devices,omitempty"` + Keys map[string]string `yaml:"keys,omitempty"` +} + +type NetDevs struct { + Type string `yaml:"type,omitempty"` + Default bool `yaml:"default"` + Hwaddr string + Ipaddr string + IpCIDR string + Prefix string + Netmask string + Gateway string `yaml:"gateway,omitempty"` +} + +/****** + * Internal code data representations + ******/ + +type Entry struct { + value string + altvalue string + bool bool + altbool bool + from string + def string +} + +type NodeInfo struct { + Id Entry + Cid Entry + Comment Entry + ClusterName Entry + ContainerName Entry + Ipxe Entry + KernelVersion Entry + KernelArgs Entry + IpmiIpaddr Entry + IpmiNetmask Entry + IpmiPort Entry + IpmiGateway Entry + IpmiUserName Entry + IpmiPassword Entry + IpmiInterface Entry + RuntimeOverlay Entry + SystemOverlay Entry + Root Entry + Discoverable Entry + Init Entry //TODO: Finish adding this... + Profiles []string + GroupProfiles []string + NetDevs map[string]*NetDevEntry + Keys map[string]*Entry +} + +type NetDevEntry struct { + Type Entry `yaml:"type,omitempty"` + Default Entry `yaml:"default"` + Hwaddr Entry + Ipaddr Entry + IpCIDR Entry + Prefix Entry + Netmask Entry + Gateway Entry `yaml:"gateway,omitempty"` +} diff --git a/cmd/update_configuration/vers42/nodes.conf b/cmd/update_configuration/vers42/nodes.conf new file mode 100644 index 00000000..ea8a2073 --- /dev/null +++ b/cmd/update_configuration/vers42/nodes.conf @@ -0,0 +1,27 @@ +nodeprofiles: + default: + comment: This profile is automatically included for each node + runtime overlay: + - generic + discoverable: "false" + leap: + comment: openSUSE leap + kernel: + override: 5.14.21 + ipmi: + netmask: 255.255.255.0 + discoverable: "false" + keys: + foo: baar + network devices: + lan1: + gateway: 1.1.1.1 +nodes: + node01: + system overlay: + - nodeover + discoverable: "true" + network devices: + eth0: + ipaddr: 1.2.3.4 + default: "true" diff --git a/cmd/update_configuration/vers43/datastructure.go b/cmd/update_configuration/vers43/datastructure.go new file mode 100644 index 00000000..48b48988 --- /dev/null +++ b/cmd/update_configuration/vers43/datastructure.go @@ -0,0 +1,139 @@ +package vers43 + +/****** + * YAML data representations + ******/ + +//type nodeYaml struct { +type NodeYaml struct { // <- needs to be exported + WWInternal int `yaml:"WW_INTERNAL"` + NodeProfiles map[string]*NodeConf + Nodes map[string]*NodeConf +} + +/* +NodeConf is the datastructure which is stored on disk. +*/ +type NodeConf struct { + Comment string `yaml:"comment,omitempty"` + ClusterName string `yaml:"cluster name,omitempty"` + ContainerName string `yaml:"container name,omitempty"` + Ipxe string `yaml:"ipxe template,omitempty"` + RuntimeOverlay []string `yaml:"runtime overlay,omitempty"` + SystemOverlay []string `yaml:"system overlay,omitempty"` + Kernel *KernelConf `yaml:"kernel,omitempty"` + Ipmi *IpmiConf `yaml:"ipmi,omitempty"` + Init string `yaml:"init,omitempty"` + Root string `yaml:"root,omitempty"` + AssetKey string `yaml:"asset key,omitempty"` + Discoverable string `yaml:"discoverable,omitempty"` + Profiles []string `yaml:"profiles,omitempty"` + NetDevs map[string]*NetDevs `yaml:"network devices,omitempty"` + Tags map[string]string `yaml:"tags,omitempty"` + Keys map[string]string `yaml:"keys,omitempty"` // Reverse compatibility +} + +type IpmiConf struct { + UserName string `yaml:"username,omitempty"` + Password string `yaml:"password,omitempty"` + Ipaddr string `yaml:"ipaddr,omitempty"` + Netmask string `yaml:"netmask,omitempty"` + Port string `yaml:"port,omitempty"` + Gateway string `yaml:"gateway,omitempty"` + Interface string `yaml:"interface,omitempty"` + Write bool `yaml:"write,omitempty"` +} +type KernelConf struct { + Version string `yaml:"version,omitempty"` + Override string `yaml:"override,omitempty"` + Args string `yaml:"args,omitempty"` +} + +type NetDevs struct { + Type string `yaml:"type,omitempty"` + OnBoot string `yaml:"onboot,omitempty"` + Device string `yaml:"device,omitempty"` + Hwaddr string `yaml:"hwaddr,omitempty"` + Ipaddr string `yaml:"ipaddr,omitempty"` + IpCIDR string `yaml:"ipcidr,omitempty"` + Ipaddr6 string `yaml:"ip6addr,omitempty"` + Prefix string `yaml:"prefix,omitempty"` + Netmask string `yaml:"netmask,omitempty"` + Gateway string `yaml:"gateway,omitempty"` + Default string `yaml:"default,omitempty"` + Tags map[string]string `yaml:"tags,omitempty"` +} + +/****** + * Internal code data representations + ******/ +/* +Holds string values, when accessed via Get, its value +is returned which is the default or if set the value +from the profile or if set the value of the node itself +*/ +type Entry struct { + value []string + altvalue []string + from string + def []string +} + +/* +NodeInfo is the in memory datastructure, which can containe +a default value, which is overwritten by the overlay from the +overlay (altvalue) which is overwitten by the value of the +node itself, for all values of type Entry. +*/ +type NodeInfo struct { + Id Entry + Cid Entry + Comment Entry + ClusterName Entry + ContainerName Entry + Ipxe Entry + RuntimeOverlay Entry + SystemOverlay Entry + Root Entry + Discoverable Entry + Init Entry //TODO: Finish adding this... + AssetKey Entry + Kernel *KernelEntry + Ipmi *IpmiEntry + Profiles []string + GroupProfiles []string + NetDevs map[string]*NetDevEntry + Tags map[string]*Entry +} + +type IpmiEntry struct { + Ipaddr Entry + Netmask Entry + Port Entry + Gateway Entry + UserName Entry + Password Entry + Interface Entry + Write Entry +} + +type KernelEntry struct { + Version Entry + Override Entry + Args Entry +} + +type NetDevEntry struct { + Type Entry + OnBoot Entry + Device Entry + Hwaddr Entry + Ipaddr Entry + Ipaddr6 Entry + IpCIDR Entry + Prefix Entry + Netmask Entry + Gateway Entry + Default Entry + Tags map[string]*Entry +}