diff --git a/.gitignore b/.gitignore index 1262a976..6c69adbb 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ /bash_completion /man_page /config_defaults +/update_configuration # other created files /man_pages @@ -24,3 +25,4 @@ _dist/ config warewulf-*.tar.gz Defaults.mk + 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..f1532851 --- /dev/null +++ b/cmd/update_configuration/update_configuration.go @@ -0,0 +1,184 @@ +package main + +import ( + "flag" + "fmt" + "io/ioutil" + "os" + "reflect" + + "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 quiet bool +var confFile string + +const actvers int = 43 + +type nodeVersionOnly struct { + WWInternal int `yaml:"WW_INTERNAL"` +} + +func saveConf(conf interface{}) { + out, err := yaml.Marshal(conf) + if err != nil { + myprintf("Error in marshal of conf: %s\n", err) + os.Exit(1) + } + if nowrite { + fmt.Print(string(out)) + } else { + err = util.CopyFile(confFile, confFile+".bak") + if err != nil { + myprintf("Could write file: %s\n", err) + os.Exit(1) + } + info, err := os.Stat(confFile) + if err != nil { + myprintf("Could not get file mode: %s\n", err) + os.Exit(1) + } + myprintf("writing configuration file %s as type %s\n", confFile, reflect.TypeOf(conf)) + err = ioutil.WriteFile(confFile, out, info.Mode()) + if err != nil { + myprintf("Could not write file: %s\n", err) + os.Exit(1) + } + } +} + +func printB(x bool) string { + if x { + return "true" + } + return "false" +} + +func update42to43(conf42 vers42.NodeConf) vers43.NodeConf { + ret := vers43.NodeConf{ + Comment: conf42.Comment, + ClusterName: conf42.ClusterName, + ContainerName: conf42.ContainerName, + Init: conf42.Init, + Root: conf42.Root, + Discoverable: printB(conf42.Discoverable), + Profiles: conf42.Profiles, + Ipxe: conf42.Ipxe} + if conf42.RuntimeOverlay != "" { + ret.RuntimeOverlay = []string{conf42.RuntimeOverlay} + } + if conf42.SystemOverlay != "" { + ret.SystemOverlay = []string{conf42.SystemOverlay} + } + if conf42.KernelArgs != "" || conf42.KernelVersion != "" { + ret.Kernel = new(vers43.KernelConf) + ret.Kernel.Override = conf42.KernelVersion + ret.Kernel.Args = conf42.KernelArgs + + } + if conf42.IpmiUserName != "" || conf42.IpmiPassword != "" || conf42.IpmiIpaddr != "" || + conf42.IpmiNetmask != "" || conf42.IpmiPort != "" || conf42.IpmiGateway != "" || + conf42.IpmiInterface != "" { + ret.Ipmi = new(vers43.IpmiConf) + ret.Ipmi.UserName = conf42.IpmiUserName + ret.Ipmi.Password = conf42.IpmiPassword + ret.Ipmi.Ipaddr = conf42.IpmiIpaddr + ret.Ipmi.Netmask = conf42.IpmiNetmask + ret.Ipmi.Port = conf42.IpmiPort + ret.Ipmi.Gateway = conf42.IpmiGateway + ret.Ipmi.Interface = conf42.IpmiInterface + } + if len(conf42.Keys) != 0 { + ret.Keys = map[string]string{} + for k, v := range conf42.Keys { + ret.Keys[k] = v + } + } + ret.NetDevs = make(map[string]*vers43.NetDevs) + for devn, netdev := range conf42.NetDevs { + var device vers43.NetDevs = vers43.NetDevs{ + Type: netdev.Type, + Device: devn, + Default: printB(netdev.Default), + Hwaddr: netdev.Hwaddr, + Ipaddr: netdev.Ipaddr, + IpCIDR: netdev.IpCIDR, + Prefix: netdev.Prefix, + Netmask: netdev.Netmask, + Gateway: netdev.Gateway} + ret.NetDevs[devn] = &device + } + return ret +} + +func myprintf(format string, a ...interface{}) { + if !quiet { + fmt.Printf(format, a...) + } +} + +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.BoolVar(&quiet, "q", false, "Do not print what the program is doing") + flag.Parse() + if confFile == "" { + myprintf("No config file given\n!") + os.Exit(1) + } + myprintf("Opening node configuration file: %s\n", confFile) + data, err := ioutil.ReadFile(confFile) + if err != nil { + myprintf("Could open file %v\n", err) + os.Exit(1) + } + var getConf nodeVersionOnly + myprintf("Unmarshaling the node configuration\n") + err = yaml.Unmarshal(data, &getConf) + if err != nil { + myprintf("Could not unmarshall: %v\n", err) + } + myprintf("Got version %v in %s\n", getConf.WWInternal, confFile) + if getConf.WWInternal == actvers { + myprintf("On actual version, bailing out\n") + os.Exit(0) + } + if startVers == 0 && 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 { + myprintf("Unmarshaling the node configuration vers 42\n") + err = yaml.Unmarshal(data, &conf42) + if err != nil { + myprintf("Could not unmarshall version 42: %v\n", err) + } + for pname, profile := range conf42.NodeProfiles { + p43 := update42to43(*profile) + conf43.NodeProfiles[pname] = &p43 + } + for nname, node := range conf42.Nodes { + n43 := update42to43(*node) + conf43.Nodes[nname] = &n43 + } + saveConf(conf43) + + } +} diff --git a/cmd/update_configuration/vers42/datastructure.go b/cmd/update_configuration/vers42/datastructure.go new file mode 100644 index 00000000..787cc5ce --- /dev/null +++ b/cmd/update_configuration/vers42/datastructure.go @@ -0,0 +1,46 @@ +package vers42 + +/****** + * YAML data representations + ******/ + +//type nodeYaml struct { +type NodeYaml struct { // <-Needs to be exported + 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"` +} diff --git a/cmd/update_configuration/vers42/nodes.conf b/cmd/update_configuration/vers42/nodes.conf new file mode 100644 index 00000000..792e48a2 --- /dev/null +++ b/cmd/update_configuration/vers42/nodes.conf @@ -0,0 +1,22 @@ +nodeprofiles: + default: + comment: This profile is automatically included for each node + runtime overlay: "generic" + discoverable: false + leap: + comment: openSUSE leap + kernel version: "5.14.21" + ipmi netmask: "255.255.255.0" + keys: + foo: baar + network devices: + lan1: + gateway: 1.1.1.1 +nodes: + node01: + system overlay: "nodeoverlay" + discoverable: true + network devices: + eth0: + ipaddr: 1.2.3.4 + default: true diff --git a/cmd/update_configuration/vers42/nodes.conf.bak b/cmd/update_configuration/vers42/nodes.conf.bak new file mode 100644 index 00000000..792e48a2 --- /dev/null +++ b/cmd/update_configuration/vers42/nodes.conf.bak @@ -0,0 +1,22 @@ +nodeprofiles: + default: + comment: This profile is automatically included for each node + runtime overlay: "generic" + discoverable: false + leap: + comment: openSUSE leap + kernel version: "5.14.21" + ipmi netmask: "255.255.255.0" + keys: + foo: baar + network devices: + lan1: + gateway: 1.1.1.1 +nodes: + node01: + system overlay: "nodeoverlay" + 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..eda98449 --- /dev/null +++ b/cmd/update_configuration/vers43/datastructure.go @@ -0,0 +1,65 @@ +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"` +} diff --git a/cmd/update_configuration/vers43/nodes.conf b/cmd/update_configuration/vers43/nodes.conf new file mode 100644 index 00000000..acbf5b96 --- /dev/null +++ b/cmd/update_configuration/vers43/nodes.conf @@ -0,0 +1,32 @@ +WW_INTERNAL: 43 +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" + network devices: + lan1: + device: lan1 + gateway: 1.1.1.1 + default: "false" + keys: + foo: baar +nodes: + node01: + system overlay: + - nodeoverlay + discoverable: "true" + network devices: + eth0: + device: eth0 + ipaddr: 1.2.3.4 + default: "true" +