From 0665d5dc8821ceee7e15e3ebf6fb26aeeb11ebed Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Fri, 25 Oct 2024 14:17:00 -0600 Subject: [PATCH 01/19] Refactor node Signed-off-by: Jonathon Anderson --- internal/app/wwctl/node/add/root.go | 2 +- internal/app/wwctl/node/delete/main.go | 2 +- internal/app/wwctl/node/edit/main.go | 6 +-- internal/app/wwctl/node/imprt/main.go | 4 +- internal/app/wwctl/node/list/main_test.go | 3 ++ internal/app/wwctl/node/set/root.go | 2 +- internal/app/wwctl/overlay/imprt/main.go | 2 +- internal/app/wwctl/profile/add/main_test.go | 4 +- internal/app/wwctl/profile/add/root.go | 9 +---- internal/app/wwctl/profile/edit/main.go | 6 +-- internal/app/wwctl/profile/set/root.go | 2 +- internal/pkg/api/node/delete.go | 4 +- internal/pkg/api/node/edit.go | 2 +- internal/pkg/api/node/set.go | 2 +- internal/pkg/api/profile/edit.go | 2 +- internal/pkg/api/profile/list.go | 4 +- internal/pkg/api/profile/set.go | 2 +- internal/pkg/node/checkconf.go | 8 ++-- internal/pkg/node/constructors.go | 22 +++++------ internal/pkg/node/constuctors_test.go | 2 +- internal/pkg/node/datastructure.go | 22 +++++------ internal/pkg/node/flags.go | 4 +- internal/pkg/node/ignition.go | 4 +- internal/pkg/node/list.go | 4 +- internal/pkg/node/methods.go | 42 ++++++++++----------- internal/pkg/node/methods_test.go | 4 +- internal/pkg/node/modifiers.go | 8 ++-- internal/pkg/node/util.go | 14 +++---- internal/pkg/overlay/datastructure.go | 10 ++--- internal/pkg/overlay/funcmap.go | 2 +- internal/pkg/overlay/overlay.go | 8 ++-- internal/pkg/overlay/overlay_test.go | 4 +- internal/pkg/warewulfd/nodedb.go | 2 +- internal/pkg/warewulfd/provision.go | 2 +- internal/pkg/warewulfd/util.go | 6 +-- 35 files changed, 112 insertions(+), 114 deletions(-) diff --git a/internal/app/wwctl/node/add/root.go b/internal/app/wwctl/node/add/root.go index 4fb7e5e8..4626e325 100644 --- a/internal/app/wwctl/node/add/root.go +++ b/internal/app/wwctl/node/add/root.go @@ -12,7 +12,7 @@ import ( // Holds the variables which are needed in CobraRunE type variables struct { - nodeConf node.NodeConf + nodeConf node.Node nodeAdd node.NodeConfAdd } diff --git a/internal/app/wwctl/node/delete/main.go b/internal/app/wwctl/node/delete/main.go index 40ad2554..7da7c19f 100644 --- a/internal/app/wwctl/node/delete/main.go +++ b/internal/app/wwctl/node/delete/main.go @@ -18,7 +18,7 @@ func CobraRunE(cmd *cobra.Command, args []string) (err error) { } if !SetYes { - var nodeList []node.NodeConf + var nodeList []node.Node // The checks run twice in the prompt case. // Avoiding putting in a blocking prompt in an API. nodeList, err = apiNode.NodeDeleteParameterCheck(&ndp, false) diff --git a/internal/app/wwctl/node/edit/main.go b/internal/app/wwctl/node/edit/main.go index 34660743..82a81f43 100644 --- a/internal/app/wwctl/node/edit/main.go +++ b/internal/app/wwctl/node/edit/main.go @@ -38,7 +38,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { Output: args, } nodeListMsg := apinode.FilteredNodes(&filterList) - nodeMap := make(map[string]*node.NodeConf) + nodeMap := make(map[string]*node.Node) // got proper yaml back _ = yaml.Unmarshal([]byte(nodeListMsg.NodeConfMapYaml), nodeMap) file, err := os.CreateTemp(os.TempDir(), "ww4NodeEdit*.yaml") @@ -50,7 +50,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { _ = file.Truncate(0) _, _ = file.Seek(0, 0) if !NoHeader { - yamlTemplate := node.UnmarshalConf(node.NodeConf{}, []string{"tagsdel"}) + yamlTemplate := node.UnmarshalConf(node.Node{}, []string{"tagsdel"}) _, _ = file.WriteString("#nodename:\n# " + strings.Join(yamlTemplate, "\n# ") + "\n") } _, _ = file.WriteString(nodeListMsg.NodeConfMapYaml) @@ -73,7 +73,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { wwlog.Debug("Hashes are before %s and after %s\n", sum1, sum2) if sum1 != sum2 { wwlog.Debug("Nodes were modified") - modifiedNodeMap := make(map[string]*node.NodeConf) + modifiedNodeMap := make(map[string]*node.Node) _, _ = file.Seek(0, 0) // ignore error as only may occurs under strange circumstances buffer, _ := io.ReadAll(file) diff --git a/internal/app/wwctl/node/imprt/main.go b/internal/app/wwctl/node/imprt/main.go index 2a7156c2..5bc1e81c 100644 --- a/internal/app/wwctl/node/imprt/main.go +++ b/internal/app/wwctl/node/imprt/main.go @@ -22,7 +22,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } defer file.Close() - importMap := make(map[string]*node.NodeConf) + importMap := make(map[string]*node.Node) buffer, err := io.ReadAll(file) if err != nil { return fmt.Errorf("could not read: %s", err) @@ -64,7 +64,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { continue } if importMap[line[0]] == nil { - importMap[line[0]] = new(node.NodeConf) + importMap[line[0]] = new(node.Node) } } } diff --git a/internal/app/wwctl/node/list/main_test.go b/internal/app/wwctl/node/list/main_test.go index a821d626..b105579b 100644 --- a/internal/app/wwctl/node/list/main_test.go +++ b/internal/app/wwctl/node/list/main_test.go @@ -496,6 +496,7 @@ nodes: "Interface": "", "EscapeChar": "", "Write": "", + "Template": "", "Tags": {} }, "Init": "", @@ -545,6 +546,7 @@ nodes: "Interface": "", "EscapeChar": "", "Write": "", + "Template": "", "Tags": {} }, "Init": "", @@ -578,6 +580,7 @@ nodes: "Interface": "", "EscapeChar": "", "Write": "", + "Template": "", "Tags": {} }, "Init": "", diff --git a/internal/app/wwctl/node/set/root.go b/internal/app/wwctl/node/set/root.go index 3e016e2a..6821614d 100644 --- a/internal/app/wwctl/node/set/root.go +++ b/internal/app/wwctl/node/set/root.go @@ -14,7 +14,7 @@ type variables struct { setNodeAll bool setYes bool setForce bool - nodeConf node.NodeConf + nodeConf node.Node nodeDel node.NodeConfDel nodeAdd node.NodeConfAdd } diff --git a/internal/app/wwctl/overlay/imprt/main.go b/internal/app/wwctl/overlay/imprt/main.go index 190747ce..acad75ec 100644 --- a/internal/app/wwctl/overlay/imprt/main.go +++ b/internal/app/wwctl/overlay/imprt/main.go @@ -72,7 +72,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { return fmt.Errorf("could not get node list: %s", err) } - var updateNodes []node.NodeConf + var updateNodes []node.Node for _, node := range nodes { if util.InSlice(node.SystemOverlay, overlayName) { diff --git a/internal/app/wwctl/profile/add/main_test.go b/internal/app/wwctl/profile/add/main_test.go index d44f3c68..b1e211ff 100644 --- a/internal/app/wwctl/profile/add/main_test.go +++ b/internal/app/wwctl/profile/add/main_test.go @@ -20,7 +20,7 @@ func Test_Add(t *testing.T) { }{ { name: "single profile add", - args: []string{"--yes", "p01"}, + args: []string{"p01"}, wantErr: false, stdout: "", outDb: `WW_INTERNAL: 45 @@ -31,7 +31,7 @@ nodes: {} }, { name: "single profile add with netname and netdev", - args: []string{"--yes", "--netname", "primary", "--netdev", "eno3", "p02"}, + args: []string{"--netname", "primary", "--netdev", "eno3", "p02"}, wantErr: false, stdout: "", outDb: `WW_INTERNAL: 45 diff --git a/internal/app/wwctl/profile/add/root.go b/internal/app/wwctl/profile/add/root.go index f55eb7f8..cb9d30af 100644 --- a/internal/app/wwctl/profile/add/root.go +++ b/internal/app/wwctl/profile/add/root.go @@ -11,12 +11,8 @@ import ( ) type variables struct { - profileConf node.ProfileConf - nodeAdd node.NodeConfAdd - SetNetDevDel string - SetNodeAll bool - SetYes bool - SetForce bool + profileConf node.Profile + nodeAdd node.NodeConfAdd } // GetRootCommand returns the root cobra.Command for the application. @@ -59,6 +55,5 @@ func GetCommand() *cobra.Command { }); err != nil { log.Println(err) } - baseCmd.PersistentFlags().BoolVarP(&vars.SetYes, "yes", "y", false, "Set 'yes' to all questions asked") return baseCmd } diff --git a/internal/app/wwctl/profile/edit/main.go b/internal/app/wwctl/profile/edit/main.go index c3ec9437..f981ada4 100644 --- a/internal/app/wwctl/profile/edit/main.go +++ b/internal/app/wwctl/profile/edit/main.go @@ -39,7 +39,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { Output: args, } profileListMsg := apiprofile.FilteredProfiles(&filterList) - profileMap := make(map[string]*node.ProfileConf) + profileMap := make(map[string]*node.Profile) // got proper yaml back _ = yaml.Unmarshal([]byte(profileListMsg.NodeConfMapYaml), profileMap) file, err := os.CreateTemp(os.TempDir(), "ww4ProfileEdit*.yaml") @@ -51,7 +51,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { _ = file.Truncate(0) _, _ = file.Seek(0, 0) if !NoHeader { - yamlTemplate := node.UnmarshalConf(node.ProfileConf{}, []string{"tagsdel"}) + yamlTemplate := node.UnmarshalConf(node.Profile{}, []string{"tagsdel"}) _, _ = file.WriteString("#profilename:\n# " + strings.Join(yamlTemplate, "\n# ") + "\n") } _, _ = file.WriteString(profileListMsg.NodeConfMapYaml) @@ -74,7 +74,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { wwlog.Debug("Hashes are before %s and after %s\n", sum1, sum2) if sum1 != sum2 { wwlog.Debug("Profiles were modified") - modifiedProfileMap := make(map[string]*node.ProfileConf) + modifiedProfileMap := make(map[string]*node.Profile) _, _ = file.Seek(0, 0) // ignore error as only may occurs under strange circumstances buffer, _ := io.ReadAll(file) diff --git a/internal/app/wwctl/profile/set/root.go b/internal/app/wwctl/profile/set/root.go index 332fd0d5..b341bfd3 100644 --- a/internal/app/wwctl/profile/set/root.go +++ b/internal/app/wwctl/profile/set/root.go @@ -21,7 +21,7 @@ type variables struct { partName string diskName string fsName string - profileConf node.ProfileConf + profileConf node.Profile profileDel node.NodeConfDel profileAdd node.NodeConfAdd } diff --git a/internal/pkg/api/node/delete.go b/internal/pkg/api/node/delete.go index 7128c2bc..41e60917 100644 --- a/internal/pkg/api/node/delete.go +++ b/internal/pkg/api/node/delete.go @@ -15,7 +15,7 @@ import ( // NodeDelete adds nodes for management by Warewulf. func NodeDelete(ndp *wwapiv1.NodeDeleteParameter) (err error) { - var nodeList []node.NodeConf + var nodeList []node.Node nodeList, err = NodeDeleteParameterCheck(ndp, false) if err != nil { return @@ -55,7 +55,7 @@ func NodeDelete(ndp *wwapiv1.NodeDeleteParameter) (err error) { // NodeDeleteParameterCheck does error checking on NodeDeleteParameter. // Output to the console if console is true. // Returns the nodes to delete. -func NodeDeleteParameterCheck(ndp *wwapiv1.NodeDeleteParameter, console bool) (nodeList []node.NodeConf, err error) { +func NodeDeleteParameterCheck(ndp *wwapiv1.NodeDeleteParameter, console bool) (nodeList []node.Node, err error) { if ndp == nil { err = fmt.Errorf("NodeDeleteParameter is nil") diff --git a/internal/pkg/api/node/edit.go b/internal/pkg/api/node/edit.go index 79324c59..dc988bde 100644 --- a/internal/pkg/api/node/edit.go +++ b/internal/pkg/api/node/edit.go @@ -37,7 +37,7 @@ func NodeAddFromYaml(nodeList *wwapiv1.NodeYaml) (err error) { if err != nil { return fmt.Errorf("could not open NodeDB: %w", err) } - nodeMap := make(map[string]*node.NodeConf) + nodeMap := make(map[string]*node.Node) err = yaml.Unmarshal([]byte(nodeList.NodeConfMapYaml), nodeMap) if err != nil { return fmt.Errorf("could not unmarshal Yaml: %w", err) diff --git a/internal/pkg/api/node/set.go b/internal/pkg/api/node/set.go index e6f4c142..cfa3b0e8 100644 --- a/internal/pkg/api/node/set.go +++ b/internal/pkg/api/node/set.go @@ -60,7 +60,7 @@ func NodeSetParameterCheck(set *wwapiv1.ConfSetParameter) (nodeDB node.NodeYaml, for _, nId := range set.ConfList { if util.InSlice(set.ConfList, nId) { wwlog.Debug("evaluating node: %s", nId) - var nodePtr *node.NodeConf + var nodePtr *node.Node nodePtr, err = nodeDB.GetNodeOnlyPtr(nId) if err != nil { wwlog.Warn("invalid node: %s", nId) diff --git a/internal/pkg/api/profile/edit.go b/internal/pkg/api/profile/edit.go index 059a3272..c8a384a0 100644 --- a/internal/pkg/api/profile/edit.go +++ b/internal/pkg/api/profile/edit.go @@ -40,7 +40,7 @@ func ProfileAddFromYaml(nodeList *wwapiv1.NodeAddParameter) (err error) { return fmt.Errorf("got wrong hash, not modifying profile database") } - profileMap := make(map[string]*node.ProfileConf) + profileMap := make(map[string]*node.Profile) err = yaml.Unmarshal([]byte(nodeList.NodeConfYaml), profileMap) if err != nil { return fmt.Errorf("couldn't unmarshall Yaml: %w", err) diff --git a/internal/pkg/api/profile/list.go b/internal/pkg/api/profile/list.go index 5d027943..be8073eb 100644 --- a/internal/pkg/api/profile/list.go +++ b/internal/pkg/api/profile/list.go @@ -38,7 +38,7 @@ func ProfileList(ShowOpt *wwapiv1.GetProfileList) (profileList wwapiv1.ProfileLi } } } else if ShowOpt.ShowYaml { - profileMap := make(map[string]node.ProfileConf) + profileMap := make(map[string]node.Profile) for _, profile := range profiles { profileMap[profile.Id()] = profile } @@ -46,7 +46,7 @@ func ProfileList(ShowOpt *wwapiv1.GetProfileList) (profileList wwapiv1.ProfileLi buf, _ := yaml.Marshal(profileMap) profileList.Output = append(profileList.Output, string(buf)) } else if ShowOpt.ShowJson { - profileMap := make(map[string]node.ProfileConf) + profileMap := make(map[string]node.Profile) for _, profile := range profiles { profileMap[profile.Id()] = profile } diff --git a/internal/pkg/api/profile/set.go b/internal/pkg/api/profile/set.go index 97c25c51..17b18888 100644 --- a/internal/pkg/api/profile/set.go +++ b/internal/pkg/api/profile/set.go @@ -60,7 +60,7 @@ func ProfileSetParameterCheck(set *wwapiv1.ConfSetParameter) (nodeDB node.NodeYa for _, profileId := range set.ConfList { if util.InSlice(set.ConfList, profileId) { wwlog.Verbose("evaluating profile: %s", profileId) - var profilePtr *node.ProfileConf + var profilePtr *node.Profile profilePtr, err = nodeDB.GetProfilePtr(profileId) if err != nil { wwlog.Warn("invalid profile: %s", profileId) diff --git a/internal/pkg/node/checkconf.go b/internal/pkg/node/checkconf.go index 623f078f..e80ecd01 100644 --- a/internal/pkg/node/checkconf.go +++ b/internal/pkg/node/checkconf.go @@ -14,13 +14,13 @@ import ( /* Checks if for NodeConf all values can be parsed according to their type. */ -func (nodeConf *NodeConf) Check() (err error) { +func (nodeConf *Node) Check() (err error) { nodeInfoType := reflect.TypeOf(nodeConf) nodeInfoVal := reflect.ValueOf(nodeConf) return check(nodeInfoType, nodeInfoVal) } -func (profileConf *ProfileConf) Check() (err error) { +func (profileConf *Profile) Check() (err error) { profileInfoType := reflect.TypeOf(profileConf) profileInfoVal := reflect.ValueOf(profileConf) return check(profileInfoType, profileInfoVal) @@ -49,8 +49,8 @@ func check(infoType reflect.Type, infoVal reflect.Value) (err error) { } } } - } else if infoType.Elem().Field(i).Type == reflect.TypeOf(map[string]*NetDevs(nil)) { - netMap := infoVal.Elem().Field(i).Interface().(map[string]*NetDevs) + } else if infoType.Elem().Field(i).Type == reflect.TypeOf(map[string]*NetDev(nil)) { + netMap := infoVal.Elem().Field(i).Interface().(map[string]*NetDev) for _, val := range netMap { netType := reflect.TypeOf(val) netVal := reflect.ValueOf(val) diff --git a/internal/pkg/node/constructors.go b/internal/pkg/node/constructors.go index 88fec481..ac9b220c 100644 --- a/internal/pkg/node/constructors.go +++ b/internal/pkg/node/constructors.go @@ -46,10 +46,10 @@ func Parse(data []byte) (nodeList NodeYaml, err error) { } wwlog.Debug("Checking nodes for types") if nodeList.nodes == nil { - nodeList.nodes = map[string]*NodeConf{} + nodeList.nodes = map[string]*Node{} } if nodeList.nodeProfiles == nil { - nodeList.nodeProfiles = map[string]*ProfileConf{} + nodeList.nodeProfiles = map[string]*Profile{} } wwlog.Debug("returning node object") return nodeList, nil @@ -58,7 +58,7 @@ func Parse(data []byte) (nodeList NodeYaml, err error) { /* Get a node with its merged in nodes */ -func (config *NodeYaml) GetNode(id string) (node NodeConf, err error) { +func (config *NodeYaml) GetNode(id string) (node Node, err error) { if _, ok := config.nodes[id]; !ok { return node, ErrNotFound } @@ -82,7 +82,7 @@ func (config *NodeYaml) GetNode(id string) (node NodeConf, err error) { wwlog.Warn("profile not found: %s", p) continue } - err = mergo.Merge(&node.ProfileConf, includedProfile, mergo.WithAppendSlice) + err = mergo.Merge(&node.Profile, includedProfile, mergo.WithAppendSlice) if err != nil { return node, err } @@ -112,7 +112,7 @@ func (config *NodeYaml) GetNode(id string) (node NodeConf, err error) { Return the node with the id string without the merged in nodes, return ErrNotFound otherwise */ -func (config *NodeYaml) GetNodeOnly(id string) (node NodeConf, err error) { +func (config *NodeYaml) GetNodeOnly(id string) (node Node, err error) { node = EmptyNode() if found, ok := config.nodes[id]; ok { return *found, nil @@ -124,7 +124,7 @@ func (config *NodeYaml) GetNodeOnly(id string) (node NodeConf, err error) { Return pointer to the node with the id string without the merged in nodes, return ErrMotFound otherwise */ -func (config *NodeYaml) GetNodeOnlyPtr(id string) (*NodeConf, error) { +func (config *NodeYaml) GetNodeOnlyPtr(id string) (*Node, error) { node := EmptyNode() if found, ok := config.nodes[id]; ok { return found, nil @@ -135,7 +135,7 @@ func (config *NodeYaml) GetNodeOnlyPtr(id string) (*NodeConf, error) { /* Get the profile with id, return ErrNotFound otherwise */ -func (config *NodeYaml) GetProfile(id string) (profile ProfileConf, err error) { +func (config *NodeYaml) GetProfile(id string) (profile Profile, err error) { if found, ok := config.nodeProfiles[id]; ok { found.id = id return *found, nil @@ -146,7 +146,7 @@ func (config *NodeYaml) GetProfile(id string) (profile ProfileConf, err error) { /* Get the profile with id, return ErrNotFound otherwise */ -func (config *NodeYaml) GetProfilePtr(id string) (profile *ProfileConf, err error) { +func (config *NodeYaml) GetProfilePtr(id string) (profile *Profile, err error) { if found, ok := config.nodeProfiles[id]; ok { found.id = id return found, nil @@ -158,7 +158,7 @@ func (config *NodeYaml) GetProfilePtr(id string) (profile *ProfileConf, err erro Get the nodes from the loaded configuration. This function also merges the nodes with the given nodes. */ -func (config *NodeYaml) FindAllNodes(nodes ...string) (nodeList []NodeConf, err error) { +func (config *NodeYaml) FindAllNodes(nodes ...string) (nodeList []Node, err error) { if len(nodes) == 0 { for n := range config.nodes { nodes = append(nodes, n) @@ -188,7 +188,7 @@ func (config *NodeYaml) FindAllNodes(nodes ...string) (nodeList []NodeConf, err /* Return all nodes as ProfileConf */ -func (config *NodeYaml) FindAllProfiles(nodes ...string) (profileList []ProfileConf, err error) { +func (config *NodeYaml) FindAllProfiles(nodes ...string) (profileList []Profile, err error) { if len(nodes) == 0 { for n := range config.nodeProfiles { nodes = append(nodes, n) @@ -246,7 +246,7 @@ without a hardware address is returned. If no unconfigured node is found, an error is returned. */ -func (config *NodeYaml) FindDiscoverableNode() (NodeConf, string, error) { +func (config *NodeYaml) FindDiscoverableNode() (Node, string, error) { nodes, _ := config.FindAllNodes() diff --git a/internal/pkg/node/constuctors_test.go b/internal/pkg/node/constuctors_test.go index ec0171cf..246b852a 100644 --- a/internal/pkg/node/constuctors_test.go +++ b/internal/pkg/node/constuctors_test.go @@ -199,7 +199,7 @@ nodes: wwlog.SetLogLevel(wwlog.DEBUG) nodes, err := ymlSrc.FindAllNodes() assert.NoError(err) - nodemap := make(map[string]*NodeConf) + nodemap := make(map[string]*Node) for i := range nodes { nodemap[nodes[i].Id()] = &nodes[i] } diff --git a/internal/pkg/node/datastructure.go b/internal/pkg/node/datastructure.go index bf44236b..0efb21fa 100644 --- a/internal/pkg/node/datastructure.go +++ b/internal/pkg/node/datastructure.go @@ -18,27 +18,27 @@ Structure of which goes to disk */ type NodeYaml struct { WWInternal int `yaml:"WW_INTERNAL,omitempty" json:"WW_INTERNAL,omitempty"` - nodeProfiles map[string]*ProfileConf - nodes map[string]*NodeConf + nodeProfiles map[string]*Profile + nodes map[string]*Node } /* -NodeConf is the datastructure describing a node and a profile which in disk format. +Node is the datastructure describing a node and a profile which in disk format. */ -type NodeConf struct { +type Node struct { id string valid bool // Is set true, if called by the constructor // exported values Discoverable wwtype.WWbool `yaml:"discoverable,omitempty" lopt:"discoverable" sopt:"e" comment:"Make discoverable in given network (true/false)"` AssetKey string `yaml:"asset key,omitempty" lopt:"asset" comment:"Set the node's Asset tag (key)"` Profiles []string `yaml:"profiles,omitempty" lopt:"profile" sopt:"P" comment:"Set the node's profile members (comma separated)"` - ProfileConf `yaml:"-,inline"` // include all values set in the profile, but inline them in yaml output if these are part of NodeConf + Profile `yaml:"-,inline"` // include all values set in the profile, but inline them in yaml output if these are part of Node } /* Holds the data which can be set for profiles and nodes. */ -type ProfileConf struct { +type Profile struct { id string // exported values Comment string `yaml:"comment,omitempty" lopt:"comment" comment:"Set arbitrary string comment"` @@ -51,7 +51,7 @@ type ProfileConf struct { Ipmi *IpmiConf `yaml:"ipmi,omitempty"` Init string `yaml:"init,omitempty" lopt:"init" sopt:"i" comment:"Define the init process to boot the container"` Root string `yaml:"root,omitempty" lopt:"root" comment:"Define the rootfs" ` - NetDevs map[string]*NetDevs `yaml:"network devices,omitempty"` + NetDevs map[string]*NetDev `yaml:"network devices,omitempty"` Tags map[string]string `yaml:"tags,omitempty"` PrimaryNetDev string `yaml:"primary network,omitempty" lopt:"primarynet" sopt:"p" comment:"Set the primary network interface"` Disks map[string]*Disk `yaml:"disks,omitempty"` @@ -78,7 +78,7 @@ type KernelConf struct { Args string `yaml:"args,omitempty" lopt:"kernelargs" sopt:"A" comment:"Set Kernel argument" json:"args,omitempty"` } -type NetDevs struct { +type NetDev struct { Type string `yaml:"type,omitempty" lopt:"type" sopt:"T" comment:"Set device type of given network"` OnBoot *bool `yaml:"onboot,omitempty" lopt:"onboot" comment:"Enable/disable network device (true/false)"` Device string `yaml:"device,omitempty" lopt:"netdev" sopt:"N" comment:"Set the device for given network"` @@ -134,9 +134,9 @@ interface so that nodes and profiles which aren't exported will be marshaled */ type ExportedYml struct { - WWInternal int `yaml:"WW_INTERNAL"` - NodeProfiles map[string]*ProfileConf `yaml:"nodeprofiles"` - Nodes map[string]*NodeConf `yaml:"nodes"` + WWInternal int `yaml:"WW_INTERNAL"` + NodeProfiles map[string]*Profile `yaml:"nodeprofiles"` + Nodes map[string]*Node `yaml:"nodes"` } /* diff --git a/internal/pkg/node/flags.go b/internal/pkg/node/flags.go index e87c750d..62dad5e1 100644 --- a/internal/pkg/node/flags.go +++ b/internal/pkg/node/flags.go @@ -31,11 +31,11 @@ type NodeConfAdd struct { Create cmd line flags from the NodeConf fields. Returns a []func() where every function must be called, as the command line parser returns e.g. netip.IP objects which must be parsed back to strings. */ -func (nodeConf *NodeConf) CreateFlags(baseCmd *cobra.Command) { +func (nodeConf *Node) CreateFlags(baseCmd *cobra.Command) { recursiveCreateFlags(nodeConf, baseCmd) } -func (profileConf *ProfileConf) CreateFlags(baseCmd *cobra.Command) { +func (profileConf *Profile) CreateFlags(baseCmd *cobra.Command) { recursiveCreateFlags(profileConf, baseCmd) } diff --git a/internal/pkg/node/ignition.go b/internal/pkg/node/ignition.go index fbffab87..c3ac4e96 100644 --- a/internal/pkg/node/ignition.go +++ b/internal/pkg/node/ignition.go @@ -13,7 +13,7 @@ import ( /* Create a ignition struct class for ignition */ -func (node *NodeConf) GetStorage() (stor types_3_4.Storage, err error, rep string) { +func (node *Node) GetStorage() (stor types_3_4.Storage, err error, rep string) { var fileSystems []types_3_4.Filesystem for fsdevice, fs := range node.FileSystems { var mountOptions []types_3_4.MountOption @@ -141,7 +141,7 @@ type SimpleIgnitionConfig struct { /* Get a simple config which can be marshalled to json */ -func (node *NodeConf) GetConfig() (conf SimpleIgnitionConfig, rep string, err error) { +func (node *Node) GetConfig() (conf SimpleIgnitionConfig, rep string, err error) { conf.Storage, err, rep = node.GetStorage() conf.Ignition.Version = "3.1.0" return diff --git a/internal/pkg/node/list.go b/internal/pkg/node/list.go index 17d9ba02..490205d6 100644 --- a/internal/pkg/node/list.go +++ b/internal/pkg/node/list.go @@ -41,7 +41,7 @@ type fieldMap map[string]*NodeFields /* Get all the info out of NodeConf. If emptyFields is set true, all fields are shown not only the ones with effective values */ -func (nodeYml *NodeYaml) GetFields(node NodeConf) (output []NodeFields) { +func (nodeYml *NodeYaml) GetFields(node Node) (output []NodeFields) { nodeMap := make(fieldMap) for _, p := range node.Profiles { if profile, ok := nodeYml.nodeProfiles[p]; ok { @@ -64,7 +64,7 @@ func (nodeYml *NodeYaml) GetFields(node NodeConf) (output []NodeFields) { /* Get all the info out of ProfileConf. If emptyFields is set true, all fields are shown not only the ones with effective values */ -func (nodeYml *NodeYaml) GetFieldsProfile(profile ProfileConf) (output []NodeFields) { +func (nodeYml *NodeYaml) GetFieldsProfile(profile Profile) (output []NodeFields) { profileMap := make(fieldMap) profileMap.importFields(&profile, "", "") for _, elem := range profileMap { diff --git a/internal/pkg/node/methods.go b/internal/pkg/node/methods.go index ea449145..4e1ca218 100644 --- a/internal/pkg/node/methods.go +++ b/internal/pkg/node/methods.go @@ -10,13 +10,13 @@ import ( "github.com/warewulf/warewulf/internal/pkg/util" ) -type nodeList []NodeConf +type nodeList []Node func (a nodeList) Len() int { return len(a) } func (a nodeList) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a nodeList) Less(i, j int) bool { return a[i].id < a[j].id } -type profileList []ProfileConf +type profileList []Profile func (a profileList) Len() int { return len(a) } func (a profileList) Swap(i, j int) { a[i], a[j] = a[j], a[i] } @@ -32,9 +32,9 @@ func (a profileList) Less(i, j int) bool { return a[i].id < a[j].id } Filter a given slice of NodeConf against a given regular expression */ -func FilterNodeListByName(set []NodeConf, searchList []string) []NodeConf { - var ret []NodeConf - unique := make(map[string]NodeConf) +func FilterNodeListByName(set []Node, searchList []string) []Node { + var ret []Node + unique := make(map[string]Node) if len(searchList) > 0 { for _, search := range searchList { @@ -59,9 +59,9 @@ func FilterNodeListByName(set []NodeConf, searchList []string) []NodeConf { Filter a given slice of ProfileConf against a given regular expression */ -func FilterProfileListByName(set []ProfileConf, searchList []string) []ProfileConf { - var ret []ProfileConf - unique := make(map[string]ProfileConf) +func FilterProfileListByName(set []Profile, searchList []string) []Profile { + var ret []Profile + unique := make(map[string]Profile) if len(searchList) > 0 { for _, search := range searchList { @@ -85,23 +85,23 @@ func FilterProfileListByName(set []ProfileConf, searchList []string) []ProfileCo /* Creates an NodeConf with the given id. Doesn't add it to the database */ -func NewNode(id string) (nodeconf NodeConf) { +func NewNode(id string) (nodeconf Node) { nodeconf = EmptyNode() nodeconf.id = id return nodeconf } -func NewProfile(id string) (profileconf ProfileConf) { +func NewProfile(id string) (profileconf Profile) { profileconf = EmptyProfile() profileconf.id = id return profileconf } -func EmptyNode() (nodeconf NodeConf) { +func EmptyNode() (nodeconf Node) { nodeconf.Ipmi = new(IpmiConf) nodeconf.Ipmi.Tags = map[string]string{} nodeconf.Kernel = new(KernelConf) - nodeconf.NetDevs = make(map[string]*NetDevs) + nodeconf.NetDevs = make(map[string]*NetDev) nodeconf.Tags = map[string]string{} return nodeconf } @@ -109,11 +109,11 @@ func EmptyNode() (nodeconf NodeConf) { /* Creates a ProfileConf but doesn't add it to the database. */ -func EmptyProfile() (profileconf ProfileConf) { +func EmptyProfile() (profileconf Profile) { profileconf.Ipmi = new(IpmiConf) profileconf.Ipmi.Tags = map[string]string{} profileconf.Kernel = new(KernelConf) - profileconf.NetDevs = make(map[string]*NetDevs) + profileconf.NetDevs = make(map[string]*NetDev) profileconf.Tags = map[string]string{} return profileconf } @@ -123,7 +123,7 @@ Flattens out a NodeConf, which means if there are no explicit values in *IpmiCon or *KernelConf, these pointer will set to nil. This will remove something like ipmi: {} from nodes.conf */ -func (info *NodeConf) Flatten() { +func (info *Node) Flatten() { recursiveFlatten(info) } @@ -132,7 +132,7 @@ Flattens out a ProfileConf, which means if there are no explicit values in *Ipmi or *KernelConf, these pointer will set to nil. This will remove something like ipmi: {} from nodes.conf */ -func (info *ProfileConf) Flatten() { +func (info *Profile) Flatten() { recursiveFlatten(info) } @@ -296,28 +296,28 @@ Getters for unexported fields /* Returns the id of the node */ -func (node *NodeConf) Id() string { +func (node *Node) Id() string { return node.id } /* Returns the id of the profile */ -func (node *ProfileConf) Id() string { +func (node *Profile) Id() string { return node.id } /* Returns if the node is a valid in the database */ -func (node *NodeConf) Valid() bool { +func (node *Node) Valid() bool { return node.valid } /* Check if the netdev is the primary one */ -func (dev *NetDevs) Primary() bool { +func (dev *NetDev) Primary() bool { return dev.primary } @@ -353,7 +353,7 @@ func cleanList(list []string) (ret []string) { Return the ipv4 address and mask in CIDR format. Aimed for the use in templates. */ -func (netdev *NetDevs) IpCIDR() string { +func (netdev *NetDev) IpCIDR() string { if netdev.Ipaddr.IsUnspecified() || netdev.Netmask.IsUnspecified() { return "" } diff --git a/internal/pkg/node/methods_test.go b/internal/pkg/node/methods_test.go index a629ecb4..860e8257 100644 --- a/internal/pkg/node/methods_test.go +++ b/internal/pkg/node/methods_test.go @@ -6,8 +6,8 @@ import ( ) func Test_Empty(t *testing.T) { - var netdev NetDevs - var netdevPtr *NetDevs + var netdev NetDev + var netdevPtr *NetDev t.Run("test for empty", func(t *testing.T) { if ObjectIsEmpty(netdev) != true { diff --git a/internal/pkg/node/modifiers.go b/internal/pkg/node/modifiers.go index 6abf88a1..c6b3f7d6 100644 --- a/internal/pkg/node/modifiers.go +++ b/internal/pkg/node/modifiers.go @@ -14,7 +14,7 @@ import ( /* Add a node with the given ID and return a pointer to it */ -func (config *NodeYaml) AddNode(nodeID string) (*NodeConf, error) { +func (config *NodeYaml) AddNode(nodeID string) (*Node, error) { newNode := NewNode(nodeID) wwlog.Verbose("Adding new node: %s", nodeID) if _, ok := config.nodes[nodeID]; ok { @@ -42,7 +42,7 @@ func (config *NodeYaml) DelNode(nodeID string) error { /* set node for the node with id the values of vals */ -func (config *NodeYaml) SetNode(nodeID string, vals NodeConf) error { +func (config *NodeYaml) SetNode(nodeID string, vals Node) error { node, ok := config.nodes[nodeID] if !ok { return ErrNotFound @@ -61,7 +61,7 @@ func (config *NodeYaml) SetNode(nodeID string, vals NodeConf) error { /* set profile for the node with id the values of vals */ -func (config *NodeYaml) SetProfile(profileId string, vals ProfileConf) error { +func (config *NodeYaml) SetProfile(profileId string, vals Profile) error { profile, ok := config.nodeProfiles[profileId] if !ok { return ErrNotFound @@ -80,7 +80,7 @@ func (config *NodeYaml) SetProfile(profileId string, vals ProfileConf) error { /* Add a node with the given ID and return a pointer to it */ -func (config *NodeYaml) AddProfile(profileId string) (*ProfileConf, error) { +func (config *NodeYaml) AddProfile(profileId string) (*Profile, error) { profile := EmptyProfile() wwlog.Verbose("adding new profile: %s", profileId) if _, ok := config.nodeProfiles[profileId]; ok { diff --git a/internal/pkg/node/util.go b/internal/pkg/node/util.go index c3924da1..325f88ad 100644 --- a/internal/pkg/node/util.go +++ b/internal/pkg/node/util.go @@ -10,9 +10,9 @@ import ( /* Gets a node by its hardware(mac) address */ -func (config *NodeYaml) FindByHwaddr(hwa string) (NodeConf, error) { +func (config *NodeYaml) FindByHwaddr(hwa string) (Node, error) { if _, err := net.ParseMAC(hwa); err != nil { - return NodeConf{}, errors.New("invalid hardware address: " + hwa) + return Node{}, errors.New("invalid hardware address: " + hwa) } nodeList, _ := config.FindAllNodes() for _, node := range nodeList { @@ -23,20 +23,20 @@ func (config *NodeYaml) FindByHwaddr(hwa string) (NodeConf, error) { } } - return NodeConf{}, ErrNotFound + return Node{}, ErrNotFound } /* Find a node by its ip address */ -func (config *NodeYaml) FindByIpaddr(ipaddr string) (NodeConf, error) { +func (config *NodeYaml) FindByIpaddr(ipaddr string) (Node, error) { addr := net.ParseIP(ipaddr) if addr == nil { - return NodeConf{}, errors.New("invalid IP:" + ipaddr) + return Node{}, errors.New("invalid IP:" + ipaddr) } nodeList, err := config.FindAllNodes() if err != nil { - return NodeConf{}, err + return Node{}, err } for _, node := range nodeList { for _, dev := range node.NetDevs { @@ -46,7 +46,7 @@ func (config *NodeYaml) FindByIpaddr(ipaddr string) (NodeConf, error) { } } - return NodeConf{}, ErrNotFound + return Node{}, ErrNotFound } /* diff --git a/internal/pkg/overlay/datastructure.go b/internal/pkg/overlay/datastructure.go index 8a996023..240fcb2b 100644 --- a/internal/pkg/overlay/datastructure.go +++ b/internal/pkg/overlay/datastructure.go @@ -35,17 +35,17 @@ type TemplateStruct struct { Warewulf warewulfconf.WarewulfConf Tftp warewulfconf.TFTPConf Paths warewulfconf.BuildConfig - AllNodes []node.NodeConf - node.NodeConf + AllNodes []node.Node + node.Node // backward compatiblity Container string - ThisNode *node.NodeConf + ThisNode *node.Node } /* Initialize an TemplateStruct with the given node.NodeInfo */ -func InitStruct(nodeData node.NodeConf) (TemplateStruct, error) { +func InitStruct(nodeData node.Node) (TemplateStruct, error) { var tstruct TemplateStruct hostname, _ := os.Hostname() tstruct.BuildHost = hostname @@ -78,7 +78,7 @@ func InitStruct(nodeData node.NodeConf) (TemplateStruct, error) { dt := time.Now() tstruct.BuildTime = dt.Format("01-02-2006 15:04:05 MST") tstruct.BuildTimeUnix = strconv.FormatInt(dt.Unix(), 10) - tstruct.NodeConf.Tags = map[string]string{} + tstruct.Node.Tags = map[string]string{} var buf bytes.Buffer enc := gob.NewEncoder(&buf) dec := gob.NewDecoder(&buf) diff --git a/internal/pkg/overlay/funcmap.go b/internal/pkg/overlay/funcmap.go index 751a97d0..a9758d76 100644 --- a/internal/pkg/overlay/funcmap.go +++ b/internal/pkg/overlay/funcmap.go @@ -106,7 +106,7 @@ func templateContainerFileInclude(containername string, filepath string) string // don't return an error as we use this function for template evaluation, // so error will turn up there as the return string -func createIgnitionJson(node *node.NodeConf) string { +func createIgnitionJson(node *node.Node) string { conf, rep, err := node.GetConfig() if len(conf.Storage.Disks) == 0 && len(conf.Storage.Filesystems) == 0 { wwlog.Debug("no disks or filesystems present, don't create a json object") diff --git a/internal/pkg/overlay/overlay.go b/internal/pkg/overlay/overlay.go index d14747aa..8542b346 100644 --- a/internal/pkg/overlay/overlay.go +++ b/internal/pkg/overlay/overlay.go @@ -28,7 +28,7 @@ var ( /* Build all overlays for a node */ -func BuildAllOverlays(nodes []node.NodeConf) error { +func BuildAllOverlays(nodes []node.Node) error { for _, n := range nodes { sysOverlays := n.SystemOverlay @@ -50,7 +50,7 @@ func BuildAllOverlays(nodes []node.NodeConf) error { // TODO: Add an Overlay Delete for both sourcedir and image -func BuildSpecificOverlays(nodes []node.NodeConf, overlayNames []string) error { +func BuildSpecificOverlays(nodes []node.Node, overlayNames []string) error { for _, n := range nodes { wwlog.Info("Building overlay for %s: %v", n, overlayNames) for _, overlayName := range overlayNames { @@ -123,7 +123,7 @@ func OverlayInit(overlayName string) error { /* Build the given overlays for a node and create a Image for them */ -func BuildOverlay(nodeConf node.NodeConf, context string, overlayNames []string) error { +func BuildOverlay(nodeConf node.Node, context string, overlayNames []string) error { if len(overlayNames) == 0 && context == "" { return nil } @@ -172,7 +172,7 @@ func BuildOverlay(nodeConf node.NodeConf, context string, overlayNames []string) Build the given overlays for a node in the given directory. If the given does not exists it will be created. */ -func BuildOverlayIndir(nodeData node.NodeConf, overlayNames []string, outputDir string) error { +func BuildOverlayIndir(nodeData node.Node, overlayNames []string, outputDir string) error { if len(overlayNames) == 0 { return nil } diff --git a/internal/pkg/overlay/overlay_test.go b/internal/pkg/overlay/overlay_test.go index d1a02a28..56dab2f4 100644 --- a/internal/pkg/overlay/overlay_test.go +++ b/internal/pkg/overlay/overlay_test.go @@ -265,7 +265,7 @@ func Test_BuildAllOverlays(t *testing.T) { defer os.RemoveAll(provisionDir) conf.Paths.WWProvisiondir = provisionDir - var nodes []node.NodeConf + var nodes []node.Node for i, nodeName := range tt.nodes { nodeInfo := node.NewNode(nodeName) if tt.systemOverlays != nil { @@ -363,7 +363,7 @@ func Test_BuildSpecificOverlays(t *testing.T) { defer os.RemoveAll(provisionDir) conf.Paths.WWProvisiondir = provisionDir - var nodes []node.NodeConf + var nodes []node.Node for _, nodeName := range tt.nodes { nodeInfo := node.NewNode(nodeName) nodes = append(nodes, nodeInfo) diff --git a/internal/pkg/warewulfd/nodedb.go b/internal/pkg/warewulfd/nodedb.go index 32903c4a..4ed997b0 100644 --- a/internal/pkg/warewulfd/nodedb.go +++ b/internal/pkg/warewulfd/nodedb.go @@ -53,7 +53,7 @@ func loadNodeDB() (err error) { return nil } -func GetNodeOrSetDiscoverable(hwaddr string) (node.NodeConf, error) { +func GetNodeOrSetDiscoverable(hwaddr string) (node.Node, error) { db.lock.RLock() defer db.lock.RUnlock() // NOTE: since discoverable nodes will write an updated DB to file and then diff --git a/internal/pkg/warewulfd/provision.go b/internal/pkg/warewulfd/provision.go index 9426e067..71c05679 100644 --- a/internal/pkg/warewulfd/provision.go +++ b/internal/pkg/warewulfd/provision.go @@ -35,7 +35,7 @@ type templateVars struct { KernelArgs string KernelOverride string Tags map[string]string - NetDevs map[string]*node.NetDevs + NetDevs map[string]*node.NetDev } func ProvisionSend(w http.ResponseWriter, req *http.Request) { diff --git a/internal/pkg/warewulfd/util.go b/internal/pkg/warewulfd/util.go index 0ba04921..7938d343 100644 --- a/internal/pkg/warewulfd/util.go +++ b/internal/pkg/warewulfd/util.go @@ -44,7 +44,7 @@ func sendFile( return nil } -func getOverlayFile(n node.NodeConf, context string, stage_overlays []string, autobuild bool) (stage_file string, err error) { +func getOverlayFile(n node.Node, context string, stage_overlays []string, autobuild bool) (stage_file string, err error) { stage_file = overlay.OverlayImage(n.Id(), context, stage_overlays) err = nil @@ -60,9 +60,9 @@ func getOverlayFile(n node.NodeConf, context string, stage_overlays []string, au if build { if len(stage_overlays) > 0 { - err = overlay.BuildSpecificOverlays([]node.NodeConf{n}, stage_overlays) + err = overlay.BuildSpecificOverlays([]node.Node{n}, stage_overlays) } else { - err = overlay.BuildAllOverlays([]node.NodeConf{n}) + err = overlay.BuildAllOverlays([]node.Node{n}) } if err != nil { wwlog.Error("Failed to build overlay: %s, %s, %s\n%s", From ab293d88ea10ac274670ec6e8f996afe7b7f4aff Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Mon, 4 Nov 2024 23:04:25 -0700 Subject: [PATCH 02/19] Fix extraneous whitespace in flag definition Signed-off-by: Jonathon Anderson --- internal/pkg/node/datastructure.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/pkg/node/datastructure.go b/internal/pkg/node/datastructure.go index 0efb21fa..27acdcf4 100644 --- a/internal/pkg/node/datastructure.go +++ b/internal/pkg/node/datastructure.go @@ -107,7 +107,7 @@ Partitions map */ type Partition struct { Number string `yaml:"number,omitempty" lopt:"partnumber" comment:"set the partition number, if not set next free slot is used" type:"uint"` - SizeMiB string `yaml:"size_mib,omitempty" lopt:"partsize " comment:"set the size of the partition, if not set maximal possible size is used" type:"uint"` + SizeMiB string `yaml:"size_mib,omitempty" lopt:"partsize" comment:"set the size of the partition, if not set maximal possible size is used" type:"uint"` StartMiB string `yaml:"start_mib,omitempty" comment:"the start of the partition" type:"uint"` TypeGuid string `yaml:"type_guid,omitempty" comment:"Linux filesystem data will be used if empty"` Guid string `yaml:"guid,omitempty" comment:"the GPT unique partition GUID"` From a7325b6ffaf3a1c0aacc79b343b98370ee719386 Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Sat, 2 Nov 2024 19:54:14 -0600 Subject: [PATCH 03/19] Remove WW_INTERNAL Signed-off-by: Jonathon Anderson --- docs/man/man5/warewulf.conf.5 | 7 - etc/nodes.conf | 1 - etc/warewulf.conf | 1 - internal/app/wwctl/clean/main_test.go | 3 +- .../app/wwctl/container/list/main_test.go | 2 +- internal/app/wwctl/node/add/main_test.go | 57 +++----- internal/app/wwctl/node/list/main_test.go | 64 ++++----- internal/app/wwctl/node/sensors/root_test.go | 2 +- internal/app/wwctl/node/set/main_test.go | 128 ++++++------------ internal/app/wwctl/overlay/imprt/main_test.go | 7 +- internal/app/wwctl/overlay/show/main_test.go | 9 +- internal/app/wwctl/power/cycle/root_test.go | 2 +- internal/app/wwctl/power/off/root_test.go | 2 +- internal/app/wwctl/power/on/root_test.go | 2 +- internal/app/wwctl/power/reset/root_test.go | 2 +- internal/app/wwctl/power/soft/root_test.go | 2 +- internal/app/wwctl/power/status/root_test.go | 2 +- internal/app/wwctl/profile/add/main_test.go | 9 +- internal/app/wwctl/profile/list/main_test.go | 20 +-- internal/app/wwctl/profile/set/main_test.go | 18 +-- internal/app/wwctl/root.go | 2 +- internal/pkg/config/buildconfig.go.in | 3 - internal/pkg/config/root.go | 1 - internal/pkg/config/root_test.go | 4 +- internal/pkg/node/datastructure.go | 4 - internal/pkg/node/hash_test.go | 3 - internal/pkg/overlay/funcmap_test.go | 3 +- internal/pkg/testenv/testenv.go | 5 +- internal/pkg/testenv/testenv_test.go | 3 +- internal/pkg/warewulfd/provision_test.go | 3 +- overlays/NetworkManager/internal/nodes.conf | 1 - .../internal/nodes_empty_mac.conf | 1 - overlays/fstab/internal/warewulf.conf | 1 - overlays/host/internal/warewulf.conf | 1 - overlays/host/internal/warewulf.conf-static | 1 - overlays/hosts/internal/warewulf.conf | 1 - overlays/wwinit/internal/warewulf.conf | 1 - overlays/wwinit/internal/wwinit_test.go | 1 - userdocs/contents/configuration.rst | 1 - .../development-environment-vagrant.rst | 1 - userdocs/quickstart/debian12.rst | 1 - userdocs/quickstart/el.rst | 1 - userdocs/quickstart/suse15.rst | 1 - 43 files changed, 126 insertions(+), 258 deletions(-) diff --git a/docs/man/man5/warewulf.conf.5 b/docs/man/man5/warewulf.conf.5 index 78716a41..bb22172d 100644 --- a/docs/man/man5/warewulf.conf.5 +++ b/docs/man/man5/warewulf.conf.5 @@ -16,12 +16,6 @@ warewulf.conf is defined using YAML document markup syntax. .LP The configuration parameters available include: -.TP -\fBWW_INTERNAL\fP -Specifies the version of the configuration file format. The current -version is 43. -.IP - .TP \fBipaddr\fP This is the control node's networking interface connecting to the @@ -279,7 +273,6 @@ A sample configuration file for a typical deployment, with all dependent services enabled. .EX -WW_INTERNAL: 45 ipaddr: 10.0.0.1 network: 10.0.0.0 netmask: 255.255.0.0 diff --git a/etc/nodes.conf b/etc/nodes.conf index 62d5b496..1b8c983a 100644 --- a/etc/nodes.conf +++ b/etc/nodes.conf @@ -1,4 +1,3 @@ -WW_INTERNAL: 46 nodeprofiles: default: comment: This profile is automatically included for each node diff --git a/etc/warewulf.conf b/etc/warewulf.conf index ae9203e4..b0589a91 100644 --- a/etc/warewulf.conf +++ b/etc/warewulf.conf @@ -1,4 +1,3 @@ -WW_INTERNAL: 45 ipaddr: 10.0.0.1 netmask: 255.255.252.0 warewulf: diff --git a/internal/app/wwctl/clean/main_test.go b/internal/app/wwctl/clean/main_test.go index 23d8c38b..6396e8bd 100644 --- a/internal/app/wwctl/clean/main_test.go +++ b/internal/app/wwctl/clean/main_test.go @@ -12,8 +12,7 @@ func Test_Clean(t *testing.T) { wwlog.SetLogLevel(wwlog.DEBUG) env := testenv.New(t) env.WriteFile(t, "etc/warewulf/nodes.conf", - `WW_INTERNAL: 45 -nodeprofiles: {} + `nodeprofiles: {} nodes: node1: {} `) diff --git a/internal/app/wwctl/container/list/main_test.go b/internal/app/wwctl/container/list/main_test.go index 1e841128..1baf769c 100644 --- a/internal/app/wwctl/container/list/main_test.go +++ b/internal/app/wwctl/container/list/main_test.go @@ -29,7 +29,7 @@ CONTAINER NAME NODES KERNEL VERSION CREATION TIME MODIFICATION TIME -------------- ----- -------------- ------------- ----------------- ---- test 1 kernel 01 Jan 70 00:00 UTC 01 Jan 70 00:00 UTC 0 B `, - inDb: `WW_INTERNAL: 43 + inDb: ` nodeprofiles: default: {} nodes: diff --git a/internal/app/wwctl/node/add/main_test.go b/internal/app/wwctl/node/add/main_test.go index 01a2811c..104cca51 100644 --- a/internal/app/wwctl/node/add/main_test.go +++ b/internal/app/wwctl/node/add/main_test.go @@ -23,8 +23,7 @@ func Test_Add(t *testing.T) { args: []string{"n01"}, wantErr: false, stdout: "", - outDb: `WW_INTERNAL: 45 -nodeprofiles: {} + outDb: `nodeprofiles: {} nodes: n01: profiles: @@ -34,8 +33,7 @@ nodes: args: []string{"--profile=foo", "n01"}, wantErr: false, stdout: "", - outDb: `WW_INTERNAL: 45 -nodeprofiles: {} + outDb: `nodeprofiles: {} nodes: n01: profiles: @@ -45,8 +43,7 @@ nodes: args: []string{"--discoverable=true", "n01"}, wantErr: false, stdout: "", - outDb: `WW_INTERNAL: 45 -nodeprofiles: {} + outDb: `nodeprofiles: {} nodes: n01: discoverable: "true" @@ -57,8 +54,7 @@ nodes: args: []string{"--discoverable", "n01"}, wantErr: false, stdout: "", - outDb: `WW_INTERNAL: 45 -nodeprofiles: {} + outDb: `nodeprofiles: {} nodes: n01: discoverable: "true" @@ -70,16 +66,14 @@ nodes: wantErr: true, stdout: "", chkout: false, - outDb: `WW_INTERNAL: 45 -nodeprofiles: {} + outDb: `nodeprofiles: {} nodes: {} `}, {name: "single node add, discoverable false", args: []string{"--discoverable=false", "n01"}, wantErr: false, stdout: "", - outDb: `WW_INTERNAL: 45 -nodeprofiles: {} + outDb: `nodeprofiles: {} nodes: n01: discoverable: "false" @@ -90,8 +84,7 @@ nodes: args: []string{"--kernelargs=foo", "n01"}, wantErr: false, stdout: "", - outDb: `WW_INTERNAL: 45 -nodeprofiles: {} + outDb: `nodeprofiles: {} nodes: n01: kernel: @@ -103,8 +96,7 @@ nodes: args: []string{"n01", "n02"}, wantErr: false, stdout: "", - outDb: `WW_INTERNAL: 45 -nodeprofiles: {} + outDb: `nodeprofiles: {} nodes: n01: profiles: @@ -117,8 +109,7 @@ nodes: args: []string{"--ipaddr6=fdaa::1", "n01"}, wantErr: false, stdout: "", - outDb: `WW_INTERNAL: 45 -nodeprofiles: {} + outDb: `nodeprofiles: {} nodes: n01: profiles: @@ -131,8 +122,7 @@ nodes: args: []string{"--ipaddr=10.0.0.1", "n01"}, wantErr: false, stdout: "", - outDb: `WW_INTERNAL: 45 -nodeprofiles: {} + outDb: `nodeprofiles: {} nodes: n01: profiles: @@ -146,16 +136,14 @@ nodes: wantErr: true, stdout: "", chkout: false, - outDb: `WW_INTERNAL: 45 -nodeprofiles: {} + outDb: `nodeprofiles: {} nodes: {} `}, {name: "three nodes with ipaddr", args: []string{"--ipaddr=10.10.0.1", "n[01-02,03]"}, wantErr: false, stdout: "", - outDb: `WW_INTERNAL: 45 -nodeprofiles: {} + outDb: `nodeprofiles: {} nodes: n01: profiles: @@ -180,8 +168,7 @@ nodes: args: []string{"--ipaddr=10.10.0.1", "--netname=foo", "n[01-03]"}, wantErr: false, stdout: "", - outDb: `WW_INTERNAL: 45 -nodeprofiles: {} + outDb: `nodeprofiles: {} nodes: n01: profiles: @@ -206,8 +193,7 @@ nodes: args: []string{"--ipaddr=10.10.0.1", "--netname=foo", "--ipmiaddr=10.20.0.1", "n[01-03]"}, wantErr: false, stdout: "", - outDb: `WW_INTERNAL: 45 -nodeprofiles: {} + outDb: `nodeprofiles: {} nodes: n01: ipmi: @@ -238,8 +224,7 @@ nodes: args: []string{"--fsname=/dev/vda1", "--fspath=/var", "n01"}, wantErr: false, stdout: "", - outDb: `WW_INTERNAL: 45 -nodeprofiles: {} + outDb: `nodeprofiles: {} nodes: n01: profiles: @@ -252,16 +237,14 @@ nodes: args: []string{"--fsname=dev/vda1", "--fspath=/var", "n01"}, wantErr: true, stdout: "", - outDb: `WW_INTERNAL: 45 -nodeprofiles: {} + outDb: `nodeprofiles: {} nodes: {} `}, {name: "one node with filesystem and partition ", args: []string{"--fsname=var", "--fspath=/var", "--partname=var", "--diskname=/dev/vda", "--partnumber=1", "n01"}, wantErr: false, stdout: "", - outDb: `WW_INTERNAL: 45 -nodeprofiles: {} + outDb: `nodeprofiles: {} nodes: n01: profiles: @@ -279,8 +262,7 @@ nodes: args: []string{"--fsname=var", "--fspath=/var", "--fsformat=btrfs", "--partname=var", "--diskname=/dev/vda", "--partnumber=1", "n01"}, wantErr: false, stdout: "", - outDb: `WW_INTERNAL: 45 -nodeprofiles: {} + outDb: `nodeprofiles: {} nodes: n01: profiles: @@ -299,8 +281,7 @@ nodes: warewulfd.SetNoDaemon() for _, tt := range tests { env := testenv.New(t) - env.WriteFile(t, "etc/warewulf/nodes.conf", - `WW_INTERNAL: 45`) + env.WriteFile(t, "etc/warewulf/nodes.conf", ``) var err error t.Run(tt.name, func(t *testing.T) { baseCmd := GetCommand() diff --git a/internal/app/wwctl/node/list/main_test.go b/internal/app/wwctl/node/list/main_test.go index b105579b..e0dcdb9e 100644 --- a/internal/app/wwctl/node/list/main_test.go +++ b/internal/app/wwctl/node/list/main_test.go @@ -33,8 +33,7 @@ NODE NAME PROFILES NETWORK --------- -------- ------- n01 [default] -- `, - inDb: `WW_INTERNAL: 45 -nodeprofiles: + inDb: `nodeprofiles: default: {} nodes: n01: @@ -52,8 +51,7 @@ NODE NAME PROFILES NETWORK n01 [default] -- n02 [default] -- `, - inDb: `WW_INTERNAL: 45 -nodeprofiles: + inDb: `nodeprofiles: default: {} nodes: n01: @@ -74,8 +72,7 @@ NODE NAME PROFILES NETWORK n01 [default] -- n02 [default] -- `, - inDb: `WW_INTERNAL: 45 -nodeprofiles: + inDb: `nodeprofiles: default: {} nodes: n01: @@ -96,8 +93,7 @@ NODE NAME PROFILES NETWORK n01 [default] -- n03 [default] -- `, - inDb: `WW_INTERNAL: 45 -nodeprofiles: + inDb: `nodeprofiles: default: {} nodes: n01: @@ -126,8 +122,7 @@ NODE NAME PROFILES NETWORK --------- -------- ------- n01 [default] -- `, - inDb: `WW_INTERNAL: 45 -nodeprofiles: + inDb: `nodeprofiles: default: {} nodes: n01: @@ -147,8 +142,7 @@ NODE NAME PROFILES NETWORK --------- -------- ------- n01 [default] default `, - inDb: `WW_INTERNAL: 45 -nodeprofiles: + inDb: `nodeprofiles: default: network devices: default: @@ -168,8 +162,7 @@ NODE FIELD PROFILE VALUE n01 Comment default profilecomment n01 Profiles -- default `, - inDb: `WW_INTERNAL: 45 -nodeprofiles: + inDb: `nodeprofiles: default: comment: profilecomment nodes: @@ -187,8 +180,7 @@ NODE FIELD PROFILE VALUE n01 Comment SUPERSEDED nodecomment n01 Profiles -- default `, - inDb: `WW_INTERNAL: 45 -nodeprofiles: + inDb: `nodeprofiles: default: comment: profilecomment nodes: @@ -206,8 +198,7 @@ NODE IPMI IPADDR IPMI PORT IPMI USERNAME IPMI INTERFACE ---- ----------- --------- ------------- -------------- n01 -- admin -- `, - inDb: `WW_INTERNAL: 45 -nodeprofiles: + inDb: `nodeprofiles: default: ipmi: username: admin @@ -225,8 +216,7 @@ NODE IPMI IPADDR IPMI PORT IPMI USERNAME IPMI INTERFACE ---- ----------- --------- ------------- -------------- n01 -- user -- `, - inDb: `WW_INTERNAL: 45 -nodeprofiles: + inDb: `nodeprofiles: default: ipmi: username: admin @@ -246,8 +236,7 @@ NODE NAME PROFILES NETWORK --------- -------- ------- n01 [p1 p2] -- `, - inDb: `WW_INTERNAL: 45 -nodeprofiles: + inDb: `nodeprofiles: p1: {} p2: {} nodes: @@ -265,8 +254,7 @@ NODE FIELD PROFILE VALUE ---- ----- ------- ----- n01 Profiles -- p1,p2 `, - inDb: `WW_INTERNAL: 45 -nodeprofiles: + inDb: `nodeprofiles: p1: {} p2: {} nodes: @@ -284,8 +272,7 @@ NODE NAME KERNEL OVERRIDE CONTAINER OVERLAYS (S/R) --------- --------------- --------- -------------- n01 -- -- /rop1,rop2 `, - inDb: `WW_INTERNAL: 45 -nodeprofiles: + inDb: `nodeprofiles: p1: runtime overlay: - rop1 @@ -304,8 +291,7 @@ NODE NAME KERNEL OVERRIDE CONTAINER OVERLAYS (S/R) --------- --------------- --------- -------------- n01 -- -- sop1/nop1,~rop1,rop1,rop2 `, - inDb: `WW_INTERNAL: 45 -nodeprofiles: + inDb: `nodeprofiles: p1: system overlay: - sop1 @@ -331,8 +317,7 @@ n01 Profiles -- p1 n01 RuntimeOverlay p1+ nop1,~rop1,rop1,rop2 n01 SystemOverlay p1 sop1 `, - inDb: `WW_INTERNAL: 45 -nodeprofiles: + inDb: `nodeprofiles: p1: system overlay: - sop1 @@ -357,8 +342,7 @@ NODE FIELD PROFILE VALUE n01 Profiles -- p1 n01 RuntimeOverlay p1+ nop1,rop1,rop2 `, - inDb: `WW_INTERNAL: 45 -nodeprofiles: + inDb: `nodeprofiles: p1: runtime overlay: - rop1 @@ -379,8 +363,7 @@ NODE FIELD PROFILE VALUE ---- ----- ------- ----- n1 NetDevs[default].OnBoot -- true `, - inDb: `WW_INTERNAL: 45 -nodes: + inDb: `nodes: n1: network devices: default: @@ -394,15 +377,14 @@ nodes: NODE FIELD PROFILE VALUE ---- ----- ------- ----- `, - inDb: `WW_INTERNAL: 46 -nodes: + inDb: `nodes: wwnode1: network devices: default: {} `}, } - conf_yml := `WW_INTERNAL: 0` + conf_yml := `` tempWarewulfConf, warewulfConfErr := os.CreateTemp("", "warewulf.conf-") assert.NoError(t, warewulfConfErr) defer os.Remove(tempWarewulfConf.Name()) @@ -459,7 +441,7 @@ func TestListMultipleFormats(t *testing.T) { kernel: {} ipmi: {} `, - inDb: `WW_INTERNAL: 43 + inDb: ` nodeprofiles: default: {} nodes: @@ -509,7 +491,7 @@ nodes: } ] `, - inDb: `WW_INTERNAL: 43 + inDb: ` nodeprofiles: default: {} nodes: @@ -593,7 +575,7 @@ nodes: } ] `, - inDb: `WW_INTERNAL: 43 + inDb: ` nodeprofiles: default: {} nodes: @@ -618,7 +600,7 @@ nodes: kernel: {} ipmi: {} `, - inDb: `WW_INTERNAL: 43 + inDb: ` nodeprofiles: default: {} nodes: diff --git a/internal/app/wwctl/node/sensors/root_test.go b/internal/app/wwctl/node/sensors/root_test.go index 3fff5f6a..450aab4c 100644 --- a/internal/app/wwctl/node/sensors/root_test.go +++ b/internal/app/wwctl/node/sensors/root_test.go @@ -15,7 +15,7 @@ func Test_Sensors(t *testing.T) { warewulfd.SetNoDaemon() env := testenv.New(t) defer env.RemoveAll(t) - env.WriteFile(t, "etc/warewulf/nodes.conf", `WW_INTERNAL: 43 + env.WriteFile(t, "etc/warewulf/nodes.conf", ` nodeprofiles: default: ipmi: diff --git a/internal/app/wwctl/node/set/main_test.go b/internal/app/wwctl/node/set/main_test.go index 6d099a61..a9ecd8e3 100644 --- a/internal/app/wwctl/node/set/main_test.go +++ b/internal/app/wwctl/node/set/main_test.go @@ -56,16 +56,14 @@ func Test_Single_Node_Change_Profile(t *testing.T) { args: []string{"--profile=foo", "n01"}, wantErr: false, stdout: "", - inDB: `WW_INTERNAL: 45 -nodeprofiles: + inDB: `nodeprofiles: default: comment: testit nodes: n01: profiles: - default`, - outDb: `WW_INTERNAL: 45 -nodeprofiles: + outDb: `nodeprofiles: default: comment: testit nodes: @@ -81,15 +79,13 @@ func Test_Node_Unset(t *testing.T) { args: []string{"--comment=UNDEF", "n01"}, wantErr: false, stdout: "", - inDB: `WW_INTERNAL: 43 -nodeprofiles: {} + inDB: `nodeprofiles: {} nodes: n01: comment: foo profiles: - default`, - outDb: `WW_INTERNAL: 43 -nodeprofiles: {} + outDb: `nodeprofiles: {} nodes: n01: profiles: @@ -103,13 +99,11 @@ func Test_Set_Ipmi_Write_Explicit(t *testing.T) { args: []string{"--ipmiwrite", "true", "n01"}, wantErr: false, stdout: "", - inDB: `WW_INTERNAL: 43 -nodeprofiles: {} + inDB: `nodeprofiles: {} nodes: n01: {} `, - outDb: `WW_INTERNAL: 43 -nodeprofiles: {} + outDb: `nodeprofiles: {} nodes: n01: ipmi: @@ -122,13 +116,11 @@ func Test_Set_Ipmi_Write_Implicit(t *testing.T) { args: []string{"--ipmiwrite", "n01"}, wantErr: false, stdout: "", - inDB: `WW_INTERNAL: 43 -nodeprofiles: {} + inDB: `nodeprofiles: {} nodes: n01: {} `, - outDb: `WW_INTERNAL: 43 -nodeprofiles: {} + outDb: `nodeprofiles: {} nodes: n01: ipmi: @@ -142,15 +134,13 @@ func Test_Unset_Ipmi_Write(t *testing.T) { args: []string{"--ipmiwrite=UNDEF", "n01"}, wantErr: false, stdout: "", - inDB: `WW_INTERNAL: 43 -nodeprofiles: {} + inDB: `nodeprofiles: {} nodes: n01: ipmi: write: "true" `, - outDb: `WW_INTERNAL: 43 -nodeprofiles: {} + outDb: `nodeprofiles: {} nodes: n01: {} `} @@ -161,15 +151,13 @@ func Test_Unset_Ipmi_Write_False(t *testing.T) { args: []string{"--ipmiwrite=UNDEF", "n01"}, wantErr: false, stdout: "", - inDB: `WW_INTERNAL: 43 -nodeprofiles: {} + inDB: `nodeprofiles: {} nodes: n01: ipmi: write: "false" `, - outDb: `WW_INTERNAL: 43 -nodeprofiles: {} + outDb: `nodeprofiles: {} nodes: n01: {} `} @@ -180,8 +168,7 @@ func Test_Ipmi_Hidden_False(t *testing.T) { args: []string{"--ipmiwrite=false", "n01"}, wantErr: false, stdout: "", - inDB: `WW_INTERNAL: 43 -nodeprofiles: + inDB: `nodeprofiles: default: ipmi: write: "true" @@ -190,8 +177,7 @@ nodes: profiles: - default `, - outDb: `WW_INTERNAL: 43 -nodeprofiles: + outDb: `nodeprofiles: default: ipmi: write: "true" @@ -211,16 +197,14 @@ func Test_Multiple_Set_Tests(t *testing.T) { args: []string{"--profile=foo", "n01"}, wantErr: false, stdout: "", - inDB: `WW_INTERNAL: 45 -nodeprofiles: + inDB: `nodeprofiles: default: comment: testit nodes: n01: profiles: - default`, - outDb: `WW_INTERNAL: 45 -nodeprofiles: + outDb: `nodeprofiles: default: comment: testit nodes: @@ -232,8 +216,7 @@ nodes: args: []string{"--profile=foo", "n0[1-2]"}, wantErr: false, stdout: "", - inDB: `WW_INTERNAL: 45 -nodeprofiles: + inDB: `nodeprofiles: default: comment: testit nodes: @@ -243,8 +226,7 @@ nodes: n02: profiles: - default`, - outDb: `WW_INTERNAL: 45 -nodeprofiles: + outDb: `nodeprofiles: default: comment: testit nodes: @@ -259,16 +241,14 @@ nodes: args: []string{"--ipmitagadd", "foo=baar", "n01"}, wantErr: false, stdout: "", - inDB: `WW_INTERNAL: 45 -nodeprofiles: + inDB: `nodeprofiles: default: comment: testit nodes: n01: profiles: - default`, - outDb: `WW_INTERNAL: 45 -nodeprofiles: + outDb: `nodeprofiles: default: comment: testit nodes: @@ -283,8 +263,7 @@ nodes: args: []string{"--tagdel", "tag1", "n01"}, wantErr: false, stdout: "", - inDB: `WW_INTERNAL: 45 -nodeprofiles: + inDB: `nodeprofiles: default: comment: testit nodes: @@ -294,8 +273,7 @@ nodes: tags: tag1: value1 tag2: value2`, - outDb: `WW_INTERNAL: 45 -nodeprofiles: + outDb: `nodeprofiles: default: comment: testit nodes: @@ -309,8 +287,7 @@ nodes: args: []string{"--fsname=var", "--fspath=/var", "--fsformat=btrfs", "--partname=var", "--partnumber=1", "--diskname=/dev/vda", "n01"}, wantErr: false, stdout: "", - inDB: `WW_INTERNAL: 45 -nodeprofiles: + inDB: `nodeprofiles: default: comment: testit nodes: @@ -318,8 +295,7 @@ nodes: profiles: - default `, - outDb: `WW_INTERNAL: 45 -nodeprofiles: + outDb: `nodeprofiles: default: comment: testit nodes: @@ -340,8 +316,7 @@ nodes: args: []string{"--fsdel=foo", "n01"}, wantErr: true, stdout: "", - inDB: `WW_INTERNAL: 45 -nodeprofiles: + inDB: `nodeprofiles: default: comment: testit nodes: @@ -359,8 +334,7 @@ nodes: format: btrfs path: /var `, - outDb: `WW_INTERNAL: 45 -nodeprofiles: + outDb: `nodeprofiles: default: comment: testit nodes: @@ -381,8 +355,7 @@ nodes: args: []string{"--fsdel=/dev/disk/by-partlabel/var", "n01"}, wantErr: false, stdout: "", - inDB: `WW_INTERNAL: 45 -nodeprofiles: + inDB: `nodeprofiles: default: comment: testit nodes: @@ -400,8 +373,7 @@ nodes: format: btrfs path: /var `, - outDb: `WW_INTERNAL: 45 -nodeprofiles: + outDb: `nodeprofiles: default: comment: testit nodes: @@ -418,8 +390,7 @@ nodes: args: []string{"--partdel=var", "n01"}, wantErr: false, stdout: "", - inDB: `WW_INTERNAL: 45 -nodeprofiles: + inDB: `nodeprofiles: default: comment: testit nodes: @@ -437,8 +408,7 @@ nodes: format: btrfs path: /var `, - outDb: `WW_INTERNAL: 45 -nodeprofiles: + outDb: `nodeprofiles: default: comment: testit nodes: @@ -454,8 +424,7 @@ nodes: args: []string{"--diskdel=/dev/vda", "n01"}, wantErr: false, stdout: "", - inDB: `WW_INTERNAL: 45 -nodeprofiles: + inDB: `nodeprofiles: default: comment: testit nodes: @@ -472,8 +441,7 @@ nodes: format: btrfs path: /var `, - outDb: `WW_INTERNAL: 45 -nodeprofiles: + outDb: `nodeprofiles: default: comment: testit nodes: @@ -489,16 +457,14 @@ nodes: args: []string{"--mtu", "1234", "--netname=mynet", "n01"}, wantErr: false, stdout: "", - inDB: `WW_INTERNAL: 45 -nodeprofiles: + inDB: `nodeprofiles: default: comment: testit nodes: n01: profiles: - default`, - outDb: `WW_INTERNAL: 45 -nodeprofiles: + outDb: `nodeprofiles: default: comment: testit nodes: @@ -513,8 +479,7 @@ nodes: args: []string{"--tagadd", "nodetag1=nodevalue1", "n01"}, wantErr: false, stdout: "", - inDB: `WW_INTERNAL: 45 -nodeprofiles: + inDB: `nodeprofiles: p1: comment: testit 1 tags: @@ -528,8 +493,7 @@ nodes: profiles: - p1 - p2`, - outDb: `WW_INTERNAL: 45 -nodeprofiles: + outDb: `nodeprofiles: p1: comment: testit 1 tags: @@ -550,20 +514,18 @@ nodes: args: []string{"n01", "--comment", "This is a , comment"}, wantErr: false, stdout: "", - inDB: `WW_INTERNAL: 43 -nodes: + inDB: `nodes: n01: comment: old comment `, - outDb: `WW_INTERNAL: 43 -nodeprofiles: {} + outDb: `nodeprofiles: {} nodes: n01: comment: This is a , comment `}, } - conf_yml := `WW_INTERNAL: 0` + conf_yml := `` tempWarewulfConf, warewulfConfErr := os.CreateTemp("", "warewulf.conf-") assert.NoError(t, warewulfConfErr) defer os.Remove(tempWarewulfConf.Name()) @@ -588,8 +550,7 @@ func Test_Node_Add(t *testing.T) { args: []string{"--tagadd=email=node", "n01"}, wantErr: false, stdout: "", - inDB: `WW_INTERNAL: 43 -nodeprofiles: + inDB: `nodeprofiles: default: comment: testit tags: @@ -598,8 +559,7 @@ nodes: n01: profiles: - default`, - outDb: `WW_INTERNAL: 43 -nodeprofiles: + outDb: `nodeprofiles: default: comment: testit tags: @@ -615,8 +575,7 @@ nodes: args: []string{"--tagadd=newtag=newval", "n01"}, wantErr: false, stdout: "", - inDB: `WW_INTERNAL: 43 -nodeprofiles: + inDB: `nodeprofiles: default: comment: testit tags: @@ -627,8 +586,7 @@ nodes: - default tags: email: node`, - outDb: `WW_INTERNAL: 43 -nodeprofiles: + outDb: `nodeprofiles: default: comment: testit tags: diff --git a/internal/app/wwctl/overlay/imprt/main_test.go b/internal/app/wwctl/overlay/imprt/main_test.go index 8d8ef486..b78ea764 100644 --- a/internal/app/wwctl/overlay/imprt/main_test.go +++ b/internal/app/wwctl/overlay/imprt/main_test.go @@ -45,14 +45,11 @@ func Test_List(t *testing.T) { t.FailNow() } - inDb := `WW_INTERNAL: 45 -nodeprofiles: + inDb := `nodeprofiles: default: {} nodes: {} ` - conf_yml := ` -WW_INTERNAL: 0 - ` + conf_yml := `` conf := warewulfconf.New() err = conf.Parse([]byte(conf_yml)) diff --git a/internal/app/wwctl/overlay/show/main_test.go b/internal/app/wwctl/overlay/show/main_test.go index 451feb0a..e341b644 100644 --- a/internal/app/wwctl/overlay/show/main_test.go +++ b/internal/app/wwctl/overlay/show/main_test.go @@ -23,8 +23,7 @@ overlay name {{ .Overlay }} func Test_Overlay_List(t *testing.T) { env := testenv.New(t) - env.WriteFile(t, "etc/warewulf/warewulf.conf", `WW_INTERNAL: 43 -ipaddr: 192.168.0.1/24 + env.WriteFile(t, "etc/warewulf/warewulf.conf", `ipaddr: 192.168.0.1/24 netmask: 255.255.255.0 network: 192.168.0.0 warewulf: @@ -53,8 +52,7 @@ nfs: mount: false`) env.WriteFile(t, "etc/warewulf/nodes.conf", - `WW_INTERNAL: 45 -nodeprofiles: + `nodeprofiles: default: tags: email: admin@localhost @@ -141,8 +139,7 @@ func TestShowServerTemplate(t *testing.T) { env := testenv.New(t) env.WriteFile(t, "etc/warewulf/nodes.conf", - `WW_INTERNAL: 45 -nodeprofiles: + `nodeprofiles: default: tags: email: admin@localhost diff --git a/internal/app/wwctl/power/cycle/root_test.go b/internal/app/wwctl/power/cycle/root_test.go index 89ba118c..9e20db8f 100644 --- a/internal/app/wwctl/power/cycle/root_test.go +++ b/internal/app/wwctl/power/cycle/root_test.go @@ -15,7 +15,7 @@ func Test_PowerCycle(t *testing.T) { warewulfd.SetNoDaemon() env := testenv.New(t) defer env.RemoveAll(t) - env.WriteFile(t, "etc/warewulf/nodes.conf", `WW_INTERNAL: 43 + env.WriteFile(t, "etc/warewulf/nodes.conf", ` nodeprofiles: default: ipmi: diff --git a/internal/app/wwctl/power/off/root_test.go b/internal/app/wwctl/power/off/root_test.go index 4dd31141..5dc368c8 100644 --- a/internal/app/wwctl/power/off/root_test.go +++ b/internal/app/wwctl/power/off/root_test.go @@ -15,7 +15,7 @@ func Test_Power_Status(t *testing.T) { warewulfd.SetNoDaemon() env := testenv.New(t) defer env.RemoveAll(t) - env.WriteFile(t, "etc/warewulf/nodes.conf", `WW_INTERNAL: 43 + env.WriteFile(t, "etc/warewulf/nodes.conf", ` nodeprofiles: default: ipmi: diff --git a/internal/app/wwctl/power/on/root_test.go b/internal/app/wwctl/power/on/root_test.go index 82485f10..8ea62f84 100644 --- a/internal/app/wwctl/power/on/root_test.go +++ b/internal/app/wwctl/power/on/root_test.go @@ -15,7 +15,7 @@ func Test_Power_Status(t *testing.T) { warewulfd.SetNoDaemon() env := testenv.New(t) defer env.RemoveAll(t) - env.WriteFile(t, "etc/warewulf/nodes.conf", `WW_INTERNAL: 43 + env.WriteFile(t, "etc/warewulf/nodes.conf", ` nodeprofiles: default: ipmi: diff --git a/internal/app/wwctl/power/reset/root_test.go b/internal/app/wwctl/power/reset/root_test.go index 131f831a..8c9a0629 100644 --- a/internal/app/wwctl/power/reset/root_test.go +++ b/internal/app/wwctl/power/reset/root_test.go @@ -15,7 +15,7 @@ func Test_Power_Status(t *testing.T) { warewulfd.SetNoDaemon() env := testenv.New(t) defer env.RemoveAll(t) - env.WriteFile(t, "etc/warewulf/nodes.conf", `WW_INTERNAL: 43 + env.WriteFile(t, "etc/warewulf/nodes.conf", ` nodeprofiles: default: ipmi: diff --git a/internal/app/wwctl/power/soft/root_test.go b/internal/app/wwctl/power/soft/root_test.go index 14728692..565f2d07 100644 --- a/internal/app/wwctl/power/soft/root_test.go +++ b/internal/app/wwctl/power/soft/root_test.go @@ -15,7 +15,7 @@ func Test_Power_Status(t *testing.T) { warewulfd.SetNoDaemon() env := testenv.New(t) defer env.RemoveAll(t) - env.WriteFile(t, "etc/warewulf/nodes.conf", `WW_INTERNAL: 43 + env.WriteFile(t, "etc/warewulf/nodes.conf", ` nodeprofiles: default: ipmi: diff --git a/internal/app/wwctl/power/status/root_test.go b/internal/app/wwctl/power/status/root_test.go index e7160e3e..998dee14 100644 --- a/internal/app/wwctl/power/status/root_test.go +++ b/internal/app/wwctl/power/status/root_test.go @@ -15,7 +15,7 @@ func Test_Power_Status(t *testing.T) { warewulfd.SetNoDaemon() env := testenv.New(t) defer env.RemoveAll(t) - env.WriteFile(t, "etc/warewulf/nodes.conf", `WW_INTERNAL: 43 + env.WriteFile(t, "etc/warewulf/nodes.conf", ` nodeprofiles: default: ipmi: diff --git a/internal/app/wwctl/profile/add/main_test.go b/internal/app/wwctl/profile/add/main_test.go index b1e211ff..d0c3fb4a 100644 --- a/internal/app/wwctl/profile/add/main_test.go +++ b/internal/app/wwctl/profile/add/main_test.go @@ -23,8 +23,7 @@ func Test_Add(t *testing.T) { args: []string{"p01"}, wantErr: false, stdout: "", - outDb: `WW_INTERNAL: 45 -nodeprofiles: + outDb: `nodeprofiles: p01: {} nodes: {} `, @@ -34,8 +33,7 @@ nodes: {} args: []string{"--netname", "primary", "--netdev", "eno3", "p02"}, wantErr: false, stdout: "", - outDb: `WW_INTERNAL: 45 -nodeprofiles: + outDb: `nodeprofiles: p02: network devices: primary: @@ -48,8 +46,7 @@ nodes: {} warewulfd.SetNoDaemon() for _, tt := range tests { env := testenv.New(t) - env.WriteFile(t, "etc/warewulf/nodes.conf", - `WW_INTERNAL: 45`) + env.WriteFile(t, "etc/warewulf/nodes.conf", ``) var err error t.Run(tt.name, func(t *testing.T) { baseCmd := GetCommand() diff --git a/internal/app/wwctl/profile/list/main_test.go b/internal/app/wwctl/profile/list/main_test.go index 39362f5d..da7e6a0a 100644 --- a/internal/app/wwctl/profile/list/main_test.go +++ b/internal/app/wwctl/profile/list/main_test.go @@ -29,7 +29,7 @@ PROFILE NAME COMMENT/DESCRIPTION ------------ ------------------- default -- `, - inDb: `WW_INTERNAL: 45 + inDb: ` nodeprofiles: default: {} nodes: @@ -47,7 +47,7 @@ PROFILE NAME COMMENT/DESCRIPTION default -- test -- `, - inDb: `WW_INTERNAL: 45 + inDb: ` nodeprofiles: default: {} test: {} @@ -65,7 +65,7 @@ PROFILE NAME COMMENT/DESCRIPTION ------------ ------------------- test -- `, - inDb: `WW_INTERNAL: 45 + inDb: ` nodeprofiles: default: {} test: {} @@ -84,7 +84,7 @@ PROFILE NAME COMMENT/DESCRIPTION default -- test -- `, - inDb: `WW_INTERNAL: 45 + inDb: ` nodeprofiles: default: {} test: {} @@ -96,7 +96,7 @@ nodes: }, } - conf_yml := `WW_INTERNAL: 0` + conf_yml := `` tempWarewulfConf, warewulfConfErr := os.CreateTemp("", "warewulf.conf-") assert.NoError(t, warewulfConfErr) defer os.Remove(tempWarewulfConf.Name()) @@ -158,7 +158,7 @@ func TestListMultipleFormats(t *testing.T) { name: "single profile list yaml output", args: []string{"-y"}, output: `default: {}`, - inDb: `WW_INTERNAL: 43 + inDb: ` nodeprofiles: default: {} nodes: @@ -191,7 +191,7 @@ nodes: } } `, - inDb: `WW_INTERNAL: 43 + inDb: ` nodeprofiles: default: {} nodes: @@ -207,7 +207,7 @@ nodes: default: {} test: {} `, - inDb: `WW_INTERNAL: 43 + inDb: ` nodeprofiles: default: {} test: {} @@ -258,7 +258,7 @@ nodes: } } `, - inDb: `WW_INTERNAL: 43 + inDb: ` nodeprofiles: default: {} test: {} @@ -270,7 +270,7 @@ nodes: }, } - conf_yml := `WW_INTERNAL: 0` + conf_yml := `` tempWarewulfConf, warewulfConfErr := os.CreateTemp("", "warewulf.conf-") assert.NoError(t, warewulfConfErr) defer os.Remove(tempWarewulfConf.Name()) diff --git a/internal/app/wwctl/profile/set/main_test.go b/internal/app/wwctl/profile/set/main_test.go index 538d6f0b..ef677dd3 100644 --- a/internal/app/wwctl/profile/set/main_test.go +++ b/internal/app/wwctl/profile/set/main_test.go @@ -54,13 +54,11 @@ func Test_Set_Netdev(t *testing.T) { args: []string{"--netname=default", "--netdev=eth0", "default"}, wantErr: false, stdout: "", - inDB: `WW_INTERNAL: 45 -nodeprofiles: + inDB: `nodeprofiles: default: {} nodes: {} `, - outDb: `WW_INTERNAL: 45 -nodeprofiles: + outDb: `nodeprofiles: default: network devices: default: @@ -74,13 +72,11 @@ func Test_Set_Netdev_and_Mask(t *testing.T) { args: []string{"--netname=default", "--netdev=eth0", "-M=255.255.255.0", "default"}, wantErr: false, stdout: "", - inDB: `WW_INTERNAL: 45 -nodeprofiles: + inDB: `nodeprofiles: default: {} nodes: {} `, - outDb: `WW_INTERNAL: 45 -nodeprofiles: + outDb: `nodeprofiles: default: network devices: default: @@ -96,16 +92,14 @@ func Test_Set_Mask_Existing_NetDev(t *testing.T) { args: []string{"--netname=default", "-M=255.255.255.0", "default"}, wantErr: false, stdout: "", - inDB: `WW_INTERNAL: 45 -nodeprofiles: + inDB: `nodeprofiles: default: network devices: default: device: eth0 nodes: {} `, - outDb: `WW_INTERNAL: 45 -nodeprofiles: + outDb: `nodeprofiles: default: network devices: default: diff --git a/internal/app/wwctl/root.go b/internal/app/wwctl/root.go index fb730d48..cd86b128 100644 --- a/internal/app/wwctl/root.go +++ b/internal/app/wwctl/root.go @@ -89,7 +89,7 @@ func rootPersistentPreRunE(cmd *cobra.Command, args []string) (err error) { } } if err != nil { - wwlog.Error("version: %s relase: %s WW_INTERNAL: %s", warewulfconf.Version, warewulfconf.Release, warewulfconf.Confversion) + wwlog.Error("version: %s relase: %s", warewulfconf.Version, warewulfconf.Release) return } err = conf.SetDynamicDefaults() diff --git a/internal/pkg/config/buildconfig.go.in b/internal/pkg/config/buildconfig.go.in index 560afccd..767e254a 100644 --- a/internal/pkg/config/buildconfig.go.in +++ b/internal/pkg/config/buildconfig.go.in @@ -24,9 +24,6 @@ type BuildConfig struct { const Version = "@VERSION@" const Release = "@RELEASE@" -// must be set .in file so that its available for tests -const Confversion = "45" - type TFTPConf struct { Enabled bool `yaml:"enabled" default:"true"` TftpRoot string `yaml:"tftproot" default:"@TFTPDIR@"` diff --git a/internal/pkg/config/root.go b/internal/pkg/config/root.go index 94fae599..d5db4896 100644 --- a/internal/pkg/config/root.go +++ b/internal/pkg/config/root.go @@ -26,7 +26,6 @@ var cachedConf RootConf // some information about the Warewulf server locally, and has // [WarewulfConf], [DHCPConf], [TFTPConf], and [NFSConf] sub-sections. type RootConf struct { - WWInternal int `yaml:"WW_INTERNAL"` Comment string `yaml:"comment,omitempty"` Ipaddr string `yaml:"ipaddr"` Ipaddr6 string `yaml:"ipaddr6,omitempty"` diff --git a/internal/pkg/config/root_test.go b/internal/pkg/config/root_test.go index 38104ffd..9546fb04 100644 --- a/internal/pkg/config/root_test.go +++ b/internal/pkg/config/root_test.go @@ -54,7 +54,7 @@ func TestDefaultRootConf(t *testing.T) { } func TestInitializedFromFile(t *testing.T) { - example_warewulf_conf := "WW_INTERNAL: 45" + example_warewulf_conf := "" tempWarewulfConf, warewulfConfErr := os.CreateTemp("", "warewulf.conf-") assert.NoError(t, warewulfConfErr) defer os.Remove(tempWarewulfConf.Name()) @@ -70,7 +70,7 @@ func TestInitializedFromFile(t *testing.T) { } func TestExampleRootConf(t *testing.T) { - example_warewulf_conf := `WW_INTERNAL: 45 + example_warewulf_conf := ` ipaddr: 192.168.200.1 netmask: 255.255.255.0 network: 192.168.200.0 diff --git a/internal/pkg/node/datastructure.go b/internal/pkg/node/datastructure.go index 27acdcf4..e26908fc 100644 --- a/internal/pkg/node/datastructure.go +++ b/internal/pkg/node/datastructure.go @@ -17,7 +17,6 @@ const undef string = "UNDEF" Structure of which goes to disk */ type NodeYaml struct { - WWInternal int `yaml:"WW_INTERNAL,omitempty" json:"WW_INTERNAL,omitempty"` nodeProfiles map[string]*Profile nodes map[string]*Node } @@ -134,7 +133,6 @@ interface so that nodes and profiles which aren't exported will be marshaled */ type ExportedYml struct { - WWInternal int `yaml:"WW_INTERNAL"` NodeProfiles map[string]*Profile `yaml:"nodeprofiles"` Nodes map[string]*Node `yaml:"nodes"` } @@ -145,7 +143,6 @@ Marshall Exported stuff, not NodeYaml directly func (yml *NodeYaml) MarshalYAML() (interface{}, error) { wwlog.Debug("marshall yml") var exp ExportedYml - exp.WWInternal = yml.WWInternal exp.Nodes = yml.nodes exp.NodeProfiles = yml.nodeProfiles node := yaml.Node{} @@ -168,7 +165,6 @@ func (yml *NodeYaml) UnmarshalYAML( if err != nil { return } - yml.WWInternal = exp.WWInternal yml.nodes = exp.Nodes yml.nodeProfiles = exp.NodeProfiles return nil diff --git a/internal/pkg/node/hash_test.go b/internal/pkg/node/hash_test.go index 482a7ef8..637ce3d4 100644 --- a/internal/pkg/node/hash_test.go +++ b/internal/pkg/node/hash_test.go @@ -10,7 +10,6 @@ import ( func TestHash(t *testing.T) { nodeConfYml1 := ` -WW_INTERNAL: 45 nodeprofiles: default: comment: This profile is automatically included for each node @@ -33,7 +32,6 @@ nodes: ipaddr: 10.0.10.2 ` nodeConfYml2 := ` -WW_INTERNAL: 45 nodeprofiles: default: comment: This profile is automatically included for each node @@ -56,7 +54,6 @@ nodes: ipaddr: 10.0.10.1 ` nodeConfYml3 := ` -WW_INTERNAL: 45 nodeprofiles: default: comment: This profile is automatically included for each node diff --git a/internal/pkg/overlay/funcmap_test.go b/internal/pkg/overlay/funcmap_test.go index b68e3bd0..641bc50e 100644 --- a/internal/pkg/overlay/funcmap_test.go +++ b/internal/pkg/overlay/funcmap_test.go @@ -9,8 +9,7 @@ import ( ) func Test_createIgnitionJson(t *testing.T) { - node_config := `WW_INTERNAL: 45 -nodes: + node_config := `nodes: n1: disks: /dev/vda: diff --git a/internal/pkg/testenv/testenv.go b/internal/pkg/testenv/testenv.go index 94d88a83..24ab8e50 100644 --- a/internal/pkg/testenv/testenv.go +++ b/internal/pkg/testenv/testenv.go @@ -18,9 +18,8 @@ import ( "github.com/warewulf/warewulf/internal/pkg/node" ) -const initWarewulfConf = `WW_INTERNAL: 0` -const initNodesConf = `WW_INTERNAL: 45 -nodeprofiles: +const initWarewulfConf = `` +const initNodesConf = `nodeprofiles: default: {} nodes: node1: {} diff --git a/internal/pkg/testenv/testenv_test.go b/internal/pkg/testenv/testenv_test.go index 46623c96..25ea7929 100644 --- a/internal/pkg/testenv/testenv_test.go +++ b/internal/pkg/testenv/testenv_test.go @@ -19,8 +19,7 @@ func Test_Basic(t *testing.T) { func Test_two_nodes(t *testing.T) { env := New(t) - env.WriteFile(t, "etc/warewulf/nodes.conf", `WW_INTERNAL: 45 -nodeprofiles: + env.WriteFile(t, "etc/warewulf/nodes.conf", `nodeprofiles: default: {} nodes: node1: {} diff --git a/internal/pkg/warewulfd/provision_test.go b/internal/pkg/warewulfd/provision_test.go index ba1bc977..24e3cb46 100644 --- a/internal/pkg/warewulfd/provision_test.go +++ b/internal/pkg/warewulfd/provision_test.go @@ -37,8 +37,7 @@ var provisionSendTests = []struct { func Test_ProvisionSend(t *testing.T) { env := testenv.New(t) - env.WriteFile(t, "etc/warewulf/nodes.conf", `WW_INTERNAL: 45 -nodeprofiles: + env.WriteFile(t, "etc/warewulf/nodes.conf", `nodeprofiles: default: container name: suse nodes: diff --git a/overlays/NetworkManager/internal/nodes.conf b/overlays/NetworkManager/internal/nodes.conf index fefbdbc8..33a7b4d2 100644 --- a/overlays/NetworkManager/internal/nodes.conf +++ b/overlays/NetworkManager/internal/nodes.conf @@ -1,4 +1,3 @@ -WW_INTERNAL: 45 nodes: node1: network devices: diff --git a/overlays/NetworkManager/internal/nodes_empty_mac.conf b/overlays/NetworkManager/internal/nodes_empty_mac.conf index 7f95f690..b1aa5217 100644 --- a/overlays/NetworkManager/internal/nodes_empty_mac.conf +++ b/overlays/NetworkManager/internal/nodes_empty_mac.conf @@ -1,4 +1,3 @@ -WW_INTERNAL: 45 nodes: node1: network devices: diff --git a/overlays/fstab/internal/warewulf.conf b/overlays/fstab/internal/warewulf.conf index 56d81ac5..7c5f020c 100644 --- a/overlays/fstab/internal/warewulf.conf +++ b/overlays/fstab/internal/warewulf.conf @@ -1,4 +1,3 @@ -WW_INTERNAL: 43 ipaddr: 192.168.0.1/24 netmask: 255.255.255.0 network: 192.168.0.0 diff --git a/overlays/host/internal/warewulf.conf b/overlays/host/internal/warewulf.conf index 56d81ac5..7c5f020c 100644 --- a/overlays/host/internal/warewulf.conf +++ b/overlays/host/internal/warewulf.conf @@ -1,4 +1,3 @@ -WW_INTERNAL: 43 ipaddr: 192.168.0.1/24 netmask: 255.255.255.0 network: 192.168.0.0 diff --git a/overlays/host/internal/warewulf.conf-static b/overlays/host/internal/warewulf.conf-static index 4e3207c5..cd4b744d 100644 --- a/overlays/host/internal/warewulf.conf-static +++ b/overlays/host/internal/warewulf.conf-static @@ -1,4 +1,3 @@ -WW_INTERNAL: 43 ipaddr: 192.168.0.1/24 netmask: 255.255.255.0 network: 192.168.0.0 diff --git a/overlays/hosts/internal/warewulf.conf b/overlays/hosts/internal/warewulf.conf index 56d81ac5..7c5f020c 100644 --- a/overlays/hosts/internal/warewulf.conf +++ b/overlays/hosts/internal/warewulf.conf @@ -1,4 +1,3 @@ -WW_INTERNAL: 43 ipaddr: 192.168.0.1/24 netmask: 255.255.255.0 network: 192.168.0.0 diff --git a/overlays/wwinit/internal/warewulf.conf b/overlays/wwinit/internal/warewulf.conf index 56d81ac5..7c5f020c 100644 --- a/overlays/wwinit/internal/warewulf.conf +++ b/overlays/wwinit/internal/warewulf.conf @@ -1,4 +1,3 @@ -WW_INTERNAL: 43 ipaddr: 192.168.0.1/24 netmask: 255.255.255.0 network: 192.168.0.0 diff --git a/overlays/wwinit/internal/wwinit_test.go b/overlays/wwinit/internal/wwinit_test.go index 0ef11229..cb51a407 100644 --- a/overlays/wwinit/internal/wwinit_test.go +++ b/overlays/wwinit/internal/wwinit_test.go @@ -57,7 +57,6 @@ func Test_wwinitOverlay(t *testing.T) { const wwinit_warewulf_conf string = `backupFile: true writeFile: true Filename: etc/warewulf/warewulf.conf -WW_INTERNAL: 43 ipaddr: 192.168.0.1/24 netmask: 255.255.255.0 network: 192.168.0.0 diff --git a/userdocs/contents/configuration.rst b/userdocs/contents/configuration.rst index b46443f6..9c0bee4b 100644 --- a/userdocs/contents/configuration.rst +++ b/userdocs/contents/configuration.rst @@ -14,7 +14,6 @@ Warewulf (4.5.2): .. code-block:: yaml - WW_INTERNAL: 45 ipaddr: 10.0.0.1 netmask: 255.255.252.0 network: 10.0.0.0 diff --git a/userdocs/contributing/development-environment-vagrant.rst b/userdocs/contributing/development-environment-vagrant.rst index 8d8944b7..cbfab328 100644 --- a/userdocs/contributing/development-environment-vagrant.rst +++ b/userdocs/contributing/development-environment-vagrant.rst @@ -190,7 +190,6 @@ Vagrantfile head.vm.provision "shell", inline: <<-SHELL cat << 'CONF' | sudo tee /etc/warewulf/warewulf.conf - WW_INTERNAL: 45 ipaddr: 192.168.200.254 netmask: 255.255.255.0 network: 192.168.200.0 diff --git a/userdocs/quickstart/debian12.rst b/userdocs/quickstart/debian12.rst index eaf4a9b8..f2692fa4 100644 --- a/userdocs/quickstart/debian12.rst +++ b/userdocs/quickstart/debian12.rst @@ -65,7 +65,6 @@ address of your cluster's private network interface: .. code-block:: yaml - WW_INTERNAL: 45 ipaddr: 192.168.200.1 netmask: 255.255.255.0 network: 192.168.200.0 diff --git a/userdocs/quickstart/el.rst b/userdocs/quickstart/el.rst index 3edc50e7..e41de7b8 100644 --- a/userdocs/quickstart/el.rst +++ b/userdocs/quickstart/el.rst @@ -58,7 +58,6 @@ address of your cluster's private network interface. .. code-block:: yaml - WW_INTERNAL: 45 ipaddr: 10.0.0.1 netmask: 255.255.252.0 network: 10.0.0.0 diff --git a/userdocs/quickstart/suse15.rst b/userdocs/quickstart/suse15.rst index a6039c7f..355f36c7 100644 --- a/userdocs/quickstart/suse15.rst +++ b/userdocs/quickstart/suse15.rst @@ -46,7 +46,6 @@ address of your cluster's private network interface: .. code-block:: yaml - WW_INTERNAL: 45 ipaddr: 192.168.200.1 netmask: 255.255.255.0 network: 192.168.200.0 From 8a602e8a7604a7d867dec906b08d1db64989e6c0 Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Mon, 4 Nov 2024 16:41:02 -0700 Subject: [PATCH 04/19] Return OnBoot to wwtype.WWbool Signed-off-by: Jonathon Anderson --- internal/pkg/node/datastructure.go | 2 +- overlays/NetworkManager/internal/nodes.conf-vlan | 2 ++ .../etc/NetworkManager/system-connections/ww4-managed.ww | 2 +- overlays/debian.interfaces/internal/debian_interfaces_test.go | 2 -- .../rootfs/etc/network/interfaces.d/default.ww | 2 +- overlays/ifcfg/internal/ifcfg_test.go | 2 -- overlays/ifcfg/internal/nodes.conf-vlan | 2 ++ overlays/ifcfg/rootfs/etc/sysconfig/network-scripts/ifcfg.ww | 2 +- overlays/wicked/internal/nodes.conf-vlan | 2 ++ overlays/wicked/internal/wicked_test.go | 4 ++-- overlays/wicked/rootfs/etc/wicked/ifconfig/ifcfg.xml.ww | 2 +- 11 files changed, 13 insertions(+), 11 deletions(-) diff --git a/internal/pkg/node/datastructure.go b/internal/pkg/node/datastructure.go index e26908fc..40e635be 100644 --- a/internal/pkg/node/datastructure.go +++ b/internal/pkg/node/datastructure.go @@ -79,7 +79,7 @@ type KernelConf struct { type NetDev struct { Type string `yaml:"type,omitempty" lopt:"type" sopt:"T" comment:"Set device type of given network"` - OnBoot *bool `yaml:"onboot,omitempty" lopt:"onboot" comment:"Enable/disable network device (true/false)"` + OnBoot wwtype.WWbool `yaml:"onboot,omitempty" lopt:"onboot" comment:"Enable/disable network device (true/false)"` Device string `yaml:"device,omitempty" lopt:"netdev" sopt:"N" comment:"Set the device for given network"` Hwaddr string `yaml:"hwaddr,omitempty" lopt:"hwaddr" sopt:"H" comment:"Set the device's HW address for given network" type:"MAC"` Ipaddr net.IP `yaml:"ipaddr,omitempty" comment:"IPv4 address in given network" sopt:"I" lopt:"ipaddr" type:"IP"` diff --git a/overlays/NetworkManager/internal/nodes.conf-vlan b/overlays/NetworkManager/internal/nodes.conf-vlan index 3302207f..71338a9a 100644 --- a/overlays/NetworkManager/internal/nodes.conf-vlan +++ b/overlays/NetworkManager/internal/nodes.conf-vlan @@ -3,8 +3,10 @@ nodes: primary network: untagged network devices: untagged: + onboot: true device: eth0 tagged: + onboot: true type: vlan device: eth0.902 tags: diff --git a/overlays/NetworkManager/rootfs/etc/NetworkManager/system-connections/ww4-managed.ww b/overlays/NetworkManager/rootfs/etc/NetworkManager/system-connections/ww4-managed.ww index 2640b892..1c0e5c7c 100644 --- a/overlays/NetworkManager/rootfs/etc/NetworkManager/system-connections/ww4-managed.ww +++ b/overlays/NetworkManager/rootfs/etc/NetworkManager/system-connections/ww4-managed.ww @@ -14,7 +14,7 @@ master={{ $master }} type=ethernet {{- else }} type={{if $netdev.Type}}{{ $netdev.Type }}{{ else }}ethernet{{end}} -{{- if or $netdev.OnBoot (eq $netdev.OnBoot nil) }} +{{- if $netdev.OnBoot }} autoconnect=true {{- end }} {{- end }} diff --git a/overlays/debian.interfaces/internal/debian_interfaces_test.go b/overlays/debian.interfaces/internal/debian_interfaces_test.go index ad0a3ade..2b2e5f97 100644 --- a/overlays/debian.interfaces/internal/debian_interfaces_test.go +++ b/overlays/debian.interfaces/internal/debian_interfaces_test.go @@ -53,7 +53,6 @@ const debian_interfaces string = `backupFile: true writeFile: true Filename: default # This file is autogenerated by warewulf -auto wwnet0 allow-hotplug wwnet0 iface wwnet0 inet static address 192.168.3.21 @@ -64,7 +63,6 @@ backupFile: true writeFile: true Filename: secondary # This file is autogenerated by warewulf -auto wwnet1 allow-hotplug wwnet1 iface wwnet1 inet static address 192.168.3.22 diff --git a/overlays/debian.interfaces/rootfs/etc/network/interfaces.d/default.ww b/overlays/debian.interfaces/rootfs/etc/network/interfaces.d/default.ww index 178ec263..e1fe1cdb 100644 --- a/overlays/debian.interfaces/rootfs/etc/network/interfaces.d/default.ww +++ b/overlays/debian.interfaces/rootfs/etc/network/interfaces.d/default.ww @@ -1,7 +1,7 @@ {{- range $devname, $netdev := .ThisNode.NetDevs }} {{- file $devname }} # This file is autogenerated by warewulf -{{- if or $netdev.OnBoot (eq $netdev.OnBoot nil) }} +{{- if $netdev.OnBoot }} auto {{ $netdev.Device }} {{- end }} allow-hotplug {{ $netdev.Device }} diff --git a/overlays/ifcfg/internal/ifcfg_test.go b/overlays/ifcfg/internal/ifcfg_test.go index 3725f4b6..c78b73f3 100644 --- a/overlays/ifcfg/internal/ifcfg_test.go +++ b/overlays/ifcfg/internal/ifcfg_test.go @@ -83,7 +83,6 @@ IPADDR=192.168.3.21 NETMASK=255.255.255.0 GATEWAY=192.168.3.1 HWADDR=e6:92:39:49:7b:03 -ONBOOT=true IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes @@ -102,7 +101,6 @@ IPADDR=192.168.3.22 NETMASK=255.255.255.0 GATEWAY=192.168.3.1 HWADDR=9a:77:29:73:14:f1 -ONBOOT=true IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes diff --git a/overlays/ifcfg/internal/nodes.conf-vlan b/overlays/ifcfg/internal/nodes.conf-vlan index 1f418c08..1345481e 100644 --- a/overlays/ifcfg/internal/nodes.conf-vlan +++ b/overlays/ifcfg/internal/nodes.conf-vlan @@ -3,8 +3,10 @@ nodes: primary network: untagged network devices: untagged: + onboot: true device: eth0 tagged: + onboot: true type: vlan device: eth0.902 tags: diff --git a/overlays/ifcfg/rootfs/etc/sysconfig/network-scripts/ifcfg.ww b/overlays/ifcfg/rootfs/etc/sysconfig/network-scripts/ifcfg.ww index ffe040d5..f89b7c36 100644 --- a/overlays/ifcfg/rootfs/etc/sysconfig/network-scripts/ifcfg.ww +++ b/overlays/ifcfg/rootfs/etc/sysconfig/network-scripts/ifcfg.ww @@ -27,7 +27,7 @@ GATEWAY={{ $netdev.Gateway }} {{- if $netdev.Hwaddr }} HWADDR={{ $netdev.Hwaddr }} {{- end }} -{{ if or $netdev.OnBoot (eq $netdev.OnBoot nil) -}} +{{- if $netdev.OnBoot }} ONBOOT=true {{- end }} IPV6INIT=yes diff --git a/overlays/wicked/internal/nodes.conf-vlan b/overlays/wicked/internal/nodes.conf-vlan index 3302207f..71338a9a 100644 --- a/overlays/wicked/internal/nodes.conf-vlan +++ b/overlays/wicked/internal/nodes.conf-vlan @@ -3,8 +3,10 @@ nodes: primary network: untagged network devices: untagged: + onboot: true device: eth0 tagged: + onboot: true type: vlan device: eth0.902 tags: diff --git a/overlays/wicked/internal/wicked_test.go b/overlays/wicked/internal/wicked_test.go index 7b835d07..ffa7c32b 100644 --- a/overlays/wicked/internal/wicked_test.go +++ b/overlays/wicked/internal/wicked_test.go @@ -65,7 +65,7 @@ This file is autogenerated by warewulf wwnet0 ethernet - boot + manual @@ -99,7 +99,7 @@ This file is autogenerated by warewulf wwnet1 ethernet - boot + manual diff --git a/overlays/wicked/rootfs/etc/wicked/ifconfig/ifcfg.xml.ww b/overlays/wicked/rootfs/etc/wicked/ifconfig/ifcfg.xml.ww index 19012c0d..4fd01a6a 100644 --- a/overlays/wicked/rootfs/etc/wicked/ifconfig/ifcfg.xml.ww +++ b/overlays/wicked/rootfs/etc/wicked/ifconfig/ifcfg.xml.ww @@ -18,7 +18,7 @@ This file is autogenerated by warewulf {{ $netdev.MTU }} {{- end }} - {{ if or $netdev.OnBoot (eq $netdev.OnBoot nil) }}boot{{ else }}manual{{end}} + {{ if $netdev.OnBoot }}boot{{ else }}manual{{ end }} From 1acbfc1ffa12286ea24a06da9ac4bde020f7ac8e Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Sun, 3 Nov 2024 00:37:36 -0600 Subject: [PATCH 05/19] First commit of backwards-compatible config datastructures Signed-off-by: Jonathon Anderson --- internal/pkg/upgrade/conf.go | 91 +++++++++++++++++++++++++ internal/pkg/upgrade/node.go | 128 +++++++++++++++++++++++++++++++++++ 2 files changed, 219 insertions(+) create mode 100644 internal/pkg/upgrade/conf.go create mode 100644 internal/pkg/upgrade/node.go diff --git a/internal/pkg/upgrade/conf.go b/internal/pkg/upgrade/conf.go new file mode 100644 index 00000000..13254dbf --- /dev/null +++ b/internal/pkg/upgrade/conf.go @@ -0,0 +1,91 @@ +package upgrade + +type RootConf struct { + WWInternal int `yaml:"WW_INTERNAL"` + Comment string `yaml:"comment,omitempty"` + Ipaddr string `yaml:"ipaddr"` + Ipaddr6 string `yaml:"ipaddr6,omitempty"` + Netmask string `yaml:"netmask"` + Network string `yaml:"network,omitempty"` + Ipv6net string `yaml:"ipv6net,omitempty"` + Fqdn string `yaml:"fqdn,omitempty"` + Warewulf *WarewulfConf `yaml:"warewulf"` + DHCP *DHCPConf `yaml:"dhcp"` + TFTP *TFTPConf `yaml:"tftp"` + NFS *NFSConf `yaml:"nfs"` + SSH *SSHConf `yaml:"ssh,omitempty"` + MountsContainer []*MountEntry `yaml:"container mounts"` + Paths *BuildConfig `yaml:"paths"` + WWClient *WWClientConf `yaml:"wwclient"` +} + +type WarewulfConf struct { + Port int `yaml:"port"` + Secure bool `yaml:"secure"` + UpdateInterval int `yaml:"update interval"` + AutobuildOverlays bool `yaml:"autobuild overlays"` + EnableHostOverlay bool `yaml:"host overlay"` + Syslog bool `yaml:"syslog"` + DataStore string `yaml:"datastore"` + GrubBoot bool `yaml:"grubboot"` +} + +type DHCPConf struct { + Enabled bool `yaml:"enabled"` + Template string `yaml:"template"` + RangeStart string `yaml:"range start,omitempty"` + RangeEnd string `yaml:"range end,omitempty"` + SystemdName string `yaml:"systemd name"` +} + +type TFTPConf struct { + Enabled bool `yaml:"enabled"` + TftpRoot string `yaml:"tftproot"` + SystemdName string `yaml:"systemd name"` + + IpxeBinaries map[string]string `yaml:"ipxe"` +} + +type NFSConf struct { + Enabled bool `yaml:"enabled"` + ExportsExtended []*NFSExportConf `yaml:"export paths"` + SystemdName string `yaml:"systemd name"` +} + +type NFSExportConf struct { + Path string `yaml:"path"` + ExportOptions string `yaml:"export options"` + MountOptions string `yaml:"mount options"` + Mount bool `yaml:"mount"` +} + +type SSHConf struct { + KeyTypes []string `yaml:"key types"` +} + +type MountEntry struct { + Source string `yaml:"source"` + Dest string `yaml:"dest,omitempty"` + ReadOnly bool `yaml:"readonly,omitempty"` + Options string `yaml:"options,omitempty"` + Copy bool `yaml:"copy,omitempty"` +} + +type BuildConfig struct { + Bindir string + Sysconfdir string + Localstatedir string + Cachedir string + Ipxesource string + Srvdir string + Firewallddir string + Systemddir string + WWOverlaydir string + WWChrootdir string + WWProvisiondir string + WWClientdir string +} + +type WWClientConf struct { + Port uint16 `yaml:"port"` +} diff --git a/internal/pkg/upgrade/node.go b/internal/pkg/upgrade/node.go new file mode 100644 index 00000000..460a75f6 --- /dev/null +++ b/internal/pkg/upgrade/node.go @@ -0,0 +1,128 @@ +package upgrade + +import ( + "gopkg.in/yaml.v3" +) + +func Parse(data []byte) (nodeYaml NodeYaml, err error) { + if err = yaml.Unmarshal(data, &nodeYaml); err != nil { + return nodeYaml, err + } + if nodeYaml.Nodes == nil { + nodeYaml.Nodes = map[string]*Node{} + } + if nodeYaml.NodeProfiles == nil { + nodeYaml.NodeProfiles = map[string]*Profile{} + } + return nodeYaml, nil +} + +type NodeYaml struct { + NodeProfiles map[string]*Profile + Nodes map[string]*Node +} + +type Node struct { + Profile `yaml:"-,inline"` +} + +type Profile struct { + AssetKey string `yaml:"asset key,omitempty"` + ClusterName string `yaml:"cluster name,omitempty"` + Comment string `yaml:"comment,omitempty"` + ContainerName string `yaml:"container name,omitempty"` + Disabled string `yaml:"disabled,omitempty"` + Discoverable string `yaml:"discoverable,omitempty"` + Disks map[string]*Disk `yaml:"disks,omitempty"` + FileSystems map[string]*FileSystem `yaml:"filesystems,omitempty"` + Init string `yaml:"init,omitempty"` + Ipmi *IpmiConf `yaml:"ipmi,omitempty"` + IpmiEscapeChar string `yaml:"ipmi escapechar,omitempty"` + IpmiGateway string `yaml:"ipmi gateway,omitempty"` + IpmiInterface string `yaml:"ipmi interface,omitempty"` + IpmiIpaddr string `yaml:"ipmi ipaddr,omitempty"` + IpmiNetmask string `yaml:"ipmi netmask,omitempty"` + IpmiPassword string `yaml:"ipmi password,omitempty"` + IpmiPort string `yaml:"ipmi port,omitempty"` + IpmiUserName string `yaml:"ipmi username,omitempty"` + IpmiWrite string `yaml:"ipmi write,omitempty"` + Ipxe string `yaml:"ipxe template,omitempty"` + Kernel *KernelConf `yaml:"kernel,omitempty"` + KernelArgs string `yaml:"kernel args,omitempty"` + KernelOverride string `yaml:"kernel override,omitempty"` + KernelVersion string `yaml:"kernel version,omitempty"` + Keys map[string]string `yaml:"keys,omitempty"` + NetDevs map[string]*NetDev `yaml:"network devices,omitempty"` + PrimaryNetDev string `yaml:"primary network,omitempty"` + Profiles []string `yaml:"profiles,omitempty"` + Root string `yaml:"root,omitempty"` + RuntimeOverlay []string `yaml:"runtime overlay,omitempty"` + SystemOverlay []string `yaml:"system overlay,omitempty"` + Tags map[string]string `yaml:"tags,omitempty"` + TagsDel []string `yaml:"tagsdel,omitempty"` +} + +type IpmiConf struct { + EscapeChar string `yaml:"escapechar,omitempty"` + Gateway string `yaml:"gateway,omitempty"` + Interface string `yaml:"interface,omitempty"` + Ipaddr string `yaml:"ipaddr,omitempty"` + Netmask string `yaml:"netmask,omitempty"` + Password string `yaml:"password,omitempty"` + Port string `yaml:"port,omitempty"` + Tags map[string]string `yaml:"tags,omitempty"` + TagsDel []string `yaml:"tagsdel,omitempty"` + UserName string `yaml:"username,omitempty"` + Write string `yaml:"write,omitempty"` +} + +type KernelConf struct { + Args string `yaml:"args,omitempty"` + Override string `yaml:"override,omitempty"` + Version string `yaml:"version,omitempty"` +} + +type NetDev struct { + Default string `yaml:"default"` + Device string `yaml:"device,omitempty"` + Gateway string `yaml:"gateway,omitempty"` + Hwaddr string `yaml:"hwaddr,omitempty"` + IpCIDR string `yaml:"ipcidr,omitempty"` + Ipaddr string `yaml:"ipaddr,omitempty"` + Ipaddr6 string `yaml:"ip6addr,omitempty"` + MTU string `yaml:"mtu,omitempty"` + Netmask string `yaml:"netmask,omitempty"` + OnBoot string `yaml:"onboot,omitempty"` + Prefix string `yaml:"prefix,omitempty"` + Primary string `yaml:"primary,omitempty"` + Tags map[string]string `yaml:"tags,omitempty"` + TagsDel []string `yaml:"tagsdel,omitempty"` + Type string `yaml:"type,omitempty"` +} + +type Disk struct { + Partitions map[string]*Partition `yaml:"partitions,omitempty"` + WipeTable string `yaml:"wipe_table,omitempty"` +} + +type Partition struct { + Guid string `yaml:"guid,omitempty"` + Number string `yaml:"number,omitempty"` + Resize string `yaml:"resize,omitempty"` + ShouldExist string `yaml:"should_exist,omitempty"` + SizeMiB string `yaml:"size_mib,omitempty"` + StartMiB string `yaml:"start_mib,omitempty"` + TypeGuid string `yaml:"type_guid,omitempty"` + WipePartitionEntry string `yaml:"wipe_partition_entry,omitempty"` +} + +type FileSystem struct { + Format string `yaml:"format,omitempty"` + Label string `yaml:"label,omitempty"` + MountOptions string `yaml:"mount_options,omitempty"` + //MountOptions []string `yaml:"mount_options,omitempty"` + Options []string `yaml:"options,omitempty"` + Path string `yaml:"path,omitempty"` + Uuid string `yaml:"uuid,omitempty"` + WipeFileSystem string `yaml:"wipe_filesystem,omitempty"` +} From a2c778b7ee20c387049e2f417615a09d7f50a218 Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Sun, 3 Nov 2024 01:04:15 -0600 Subject: [PATCH 06/19] Remove ExportedYml Signed-off-by: Jonathon Anderson --- internal/pkg/node/constructors.go | 32 ++++++------- ...nstuctors_test.go => constructors_test.go} | 2 +- internal/pkg/node/datastructure.go | 48 +------------------ internal/pkg/node/hash.go | 4 +- internal/pkg/node/list.go | 2 +- internal/pkg/node/modifiers.go | 24 +++++----- 6 files changed, 34 insertions(+), 78 deletions(-) rename internal/pkg/node/{constuctors_test.go => constructors_test.go} (99%) diff --git a/internal/pkg/node/constructors.go b/internal/pkg/node/constructors.go index ac9b220c..e22390a3 100644 --- a/internal/pkg/node/constructors.go +++ b/internal/pkg/node/constructors.go @@ -45,11 +45,11 @@ func Parse(data []byte) (nodeList NodeYaml, err error) { return nodeList, err } wwlog.Debug("Checking nodes for types") - if nodeList.nodes == nil { - nodeList.nodes = map[string]*Node{} + if nodeList.Nodes == nil { + nodeList.Nodes = map[string]*Node{} } - if nodeList.nodeProfiles == nil { - nodeList.nodeProfiles = map[string]*Profile{} + if nodeList.NodeProfiles == nil { + nodeList.NodeProfiles = map[string]*Profile{} } wwlog.Debug("returning node object") return nodeList, nil @@ -59,7 +59,7 @@ func Parse(data []byte) (nodeList NodeYaml, err error) { Get a node with its merged in nodes */ func (config *NodeYaml) GetNode(id string) (node Node, err error) { - if _, ok := config.nodes[id]; !ok { + if _, ok := config.Nodes[id]; !ok { return node, ErrNotFound } node = EmptyNode() @@ -68,7 +68,7 @@ func (config *NodeYaml) GetNode(id string) (node Node, err error) { var buf bytes.Buffer enc := gob.NewEncoder(&buf) dec := gob.NewDecoder(&buf) - err = enc.Encode(config.nodes[id]) + err = enc.Encode(config.Nodes[id]) if err != nil { return node, err } @@ -76,7 +76,7 @@ func (config *NodeYaml) GetNode(id string) (node Node, err error) { if err != nil { return node, err } - for _, p := range cleanList(config.nodes[id].Profiles) { + for _, p := range cleanList(config.Nodes[id].Profiles) { includedProfile, err := config.GetProfile(p) if err != nil { wwlog.Warn("profile not found: %s", p) @@ -114,7 +114,7 @@ otherwise */ func (config *NodeYaml) GetNodeOnly(id string) (node Node, err error) { node = EmptyNode() - if found, ok := config.nodes[id]; ok { + if found, ok := config.Nodes[id]; ok { return *found, nil } return node, ErrNotFound @@ -126,7 +126,7 @@ otherwise */ func (config *NodeYaml) GetNodeOnlyPtr(id string) (*Node, error) { node := EmptyNode() - if found, ok := config.nodes[id]; ok { + if found, ok := config.Nodes[id]; ok { return found, nil } return &node, ErrNotFound @@ -136,7 +136,7 @@ func (config *NodeYaml) GetNodeOnlyPtr(id string) (*Node, error) { Get the profile with id, return ErrNotFound otherwise */ func (config *NodeYaml) GetProfile(id string) (profile Profile, err error) { - if found, ok := config.nodeProfiles[id]; ok { + if found, ok := config.NodeProfiles[id]; ok { found.id = id return *found, nil } @@ -147,7 +147,7 @@ func (config *NodeYaml) GetProfile(id string) (profile Profile, err error) { Get the profile with id, return ErrNotFound otherwise */ func (config *NodeYaml) GetProfilePtr(id string) (profile *Profile, err error) { - if found, ok := config.nodeProfiles[id]; ok { + if found, ok := config.NodeProfiles[id]; ok { found.id = id return found, nil } @@ -160,7 +160,7 @@ the nodes with the given nodes. */ func (config *NodeYaml) FindAllNodes(nodes ...string) (nodeList []Node, err error) { if len(nodes) == 0 { - for n := range config.nodes { + for n := range config.Nodes { nodes = append(nodes, n) } } @@ -190,7 +190,7 @@ Return all nodes as ProfileConf */ func (config *NodeYaml) FindAllProfiles(nodes ...string) (profileList []Profile, err error) { if len(nodes) == 0 { - for n := range config.nodeProfiles { + for n := range config.NodeProfiles { nodes = append(nodes, n) } } @@ -220,8 +220,8 @@ func (config *NodeYaml) FindAllProfiles(nodes ...string) (profileList []Profile, Return the names of all available nodes */ func (config *NodeYaml) ListAllNodes() []string { - nodeList := make([]string, len(config.nodes)) - for name := range config.nodes { + nodeList := make([]string, len(config.Nodes)) + for name := range config.Nodes { nodeList = append(nodeList, name) } return nodeList @@ -232,7 +232,7 @@ Return the names of all available nodes */ func (config *NodeYaml) ListAllProfiles() []string { var nodeList []string - for name := range config.nodeProfiles { + for name := range config.NodeProfiles { nodeList = append(nodeList, name) } return nodeList diff --git a/internal/pkg/node/constuctors_test.go b/internal/pkg/node/constructors_test.go similarity index 99% rename from internal/pkg/node/constuctors_test.go rename to internal/pkg/node/constructors_test.go index 246b852a..382f8814 100644 --- a/internal/pkg/node/constuctors_test.go +++ b/internal/pkg/node/constructors_test.go @@ -138,7 +138,7 @@ func Test_FindDiscoverableNode(t *testing.T) { t.Run(tt.description, func(t *testing.T) { config := newConstructorPrimaryNetworkTest(t) for _, node := range tt.discoverable_nodes { - config.nodes[node].Discoverable = "true" + config.Nodes[node].Discoverable = "true" } discovered_node, discovered_interface, err := config.FindDiscoverableNode() if !tt.succeed { diff --git a/internal/pkg/node/datastructure.go b/internal/pkg/node/datastructure.go index 40e635be..6735fc3d 100644 --- a/internal/pkg/node/datastructure.go +++ b/internal/pkg/node/datastructure.go @@ -3,9 +3,7 @@ package node import ( "net" - "github.com/warewulf/warewulf/internal/pkg/wwlog" "github.com/warewulf/warewulf/internal/pkg/wwtype" - "gopkg.in/yaml.v3" ) const undef string = "UNDEF" @@ -17,8 +15,8 @@ const undef string = "UNDEF" Structure of which goes to disk */ type NodeYaml struct { - nodeProfiles map[string]*Profile - nodes map[string]*Node + NodeProfiles map[string]*Profile + Nodes map[string]*Node } /* @@ -127,45 +125,3 @@ type FileSystem struct { Options []string `yaml:"options,omitempty" comment:"any additional options to be passed to the format-specific mkfs utility"` MountOptions string `yaml:"mount_options,omitempty" comment:"any special options to be passed to the mount command"` } - -/* -interface so that nodes and profiles which aren't exported will -be marshaled -*/ -type ExportedYml struct { - NodeProfiles map[string]*Profile `yaml:"nodeprofiles"` - Nodes map[string]*Node `yaml:"nodes"` -} - -/* -Marshall Exported stuff, not NodeYaml directly -*/ -func (yml *NodeYaml) MarshalYAML() (interface{}, error) { - wwlog.Debug("marshall yml") - var exp ExportedYml - exp.Nodes = yml.nodes - exp.NodeProfiles = yml.nodeProfiles - node := yaml.Node{} - err := node.Encode(exp) - if err != nil { - return node, err - } - return node, err -} - -/* -Unmarshal to intermediate format -*/ -func (yml *NodeYaml) UnmarshalYAML( - unmarshal func(interface{}) (err error), -) (err error) { - wwlog.Debug("UnmarshalYAML called") - var exp ExportedYml - err = unmarshal(&exp) - if err != nil { - return - } - yml.nodes = exp.Nodes - yml.nodeProfiles = exp.NodeProfiles - return nil -} diff --git a/internal/pkg/node/hash.go b/internal/pkg/node/hash.go index 1c57dce9..18814bac 100644 --- a/internal/pkg/node/hash.go +++ b/internal/pkg/node/hash.go @@ -13,10 +13,10 @@ Calculate the hash of NodeYaml in an orderder fashion */ func (config *NodeYaml) Hash() [32]byte { // flatten out profiles and nodes - for _, val := range config.nodeProfiles { + for _, val := range config.NodeProfiles { val.Flatten() } - for _, val := range config.nodes { + for _, val := range config.Nodes { val.Flatten() } data, err := yaml.Marshal(config) diff --git a/internal/pkg/node/list.go b/internal/pkg/node/list.go index 490205d6..9ca4e59a 100644 --- a/internal/pkg/node/list.go +++ b/internal/pkg/node/list.go @@ -44,7 +44,7 @@ Get all the info out of NodeConf. If emptyFields is set true, all fields are sho func (nodeYml *NodeYaml) GetFields(node Node) (output []NodeFields) { nodeMap := make(fieldMap) for _, p := range node.Profiles { - if profile, ok := nodeYml.nodeProfiles[p]; ok { + if profile, ok := nodeYml.NodeProfiles[p]; ok { nodeMap.importFields(profile, "", p) } } diff --git a/internal/pkg/node/modifiers.go b/internal/pkg/node/modifiers.go index c6b3f7d6..6063614e 100644 --- a/internal/pkg/node/modifiers.go +++ b/internal/pkg/node/modifiers.go @@ -17,10 +17,10 @@ Add a node with the given ID and return a pointer to it func (config *NodeYaml) AddNode(nodeID string) (*Node, error) { newNode := NewNode(nodeID) wwlog.Verbose("Adding new node: %s", nodeID) - if _, ok := config.nodes[nodeID]; ok { + if _, ok := config.Nodes[nodeID]; ok { return nil, errors.New("nodename already exists: " + nodeID) } else { - config.nodes[nodeID] = &newNode + config.Nodes[nodeID] = &newNode } return &newNode, nil } @@ -29,12 +29,12 @@ func (config *NodeYaml) AddNode(nodeID string) (*Node, error) { delete node with the given id */ func (config *NodeYaml) DelNode(nodeID string) error { - if _, ok := config.nodes[nodeID]; !ok { + if _, ok := config.Nodes[nodeID]; !ok { return errors.New("nodename does not exist: " + nodeID) } wwlog.Verbose("Deleting node: %s", nodeID) - delete(config.nodes, nodeID) + delete(config.Nodes, nodeID) return nil } @@ -43,7 +43,7 @@ func (config *NodeYaml) DelNode(nodeID string) error { set node for the node with id the values of vals */ func (config *NodeYaml) SetNode(nodeID string, vals Node) error { - node, ok := config.nodes[nodeID] + node, ok := config.Nodes[nodeID] if !ok { return ErrNotFound } @@ -62,7 +62,7 @@ func (config *NodeYaml) SetNode(nodeID string, vals Node) error { set profile for the node with id the values of vals */ func (config *NodeYaml) SetProfile(profileId string, vals Profile) error { - profile, ok := config.nodeProfiles[profileId] + profile, ok := config.NodeProfiles[profileId] if !ok { return ErrNotFound } @@ -83,10 +83,10 @@ Add a node with the given ID and return a pointer to it func (config *NodeYaml) AddProfile(profileId string) (*Profile, error) { profile := EmptyProfile() wwlog.Verbose("adding new profile: %s", profileId) - if _, ok := config.nodeProfiles[profileId]; ok { + if _, ok := config.NodeProfiles[profileId]; ok { return nil, errors.New("profile already exists: " + profileId) } else { - config.nodeProfiles[profileId] = &profile + config.NodeProfiles[profileId] = &profile } return &profile, nil } @@ -95,12 +95,12 @@ func (config *NodeYaml) AddProfile(profileId string) (*Profile, error) { delete node with the given id */ func (config *NodeYaml) DelProfile(nodeID string) error { - if _, ok := config.nodes[nodeID]; !ok { + if _, ok := config.Nodes[nodeID]; !ok { return errors.New("profile does not exist: " + nodeID) } wwlog.Verbose("deleting profile: %s", nodeID) - delete(config.nodes, nodeID) + delete(config.Nodes, nodeID) return nil } @@ -134,10 +134,10 @@ instance. Passes through any errors generated by yaml.Marshal. */ func (config *NodeYaml) Dump() ([]byte, error) { // flatten out profiles and nodes - for _, val := range config.nodeProfiles { + for _, val := range config.NodeProfiles { val.Flatten() } - for _, val := range config.nodes { + for _, val := range config.Nodes { val.Flatten() } var buf bytes.Buffer From 76acd8ff8094ec6d7d14bf040a9dcdb9481f1836 Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Sun, 3 Nov 2024 15:27:24 -0700 Subject: [PATCH 07/19] Rename RootConf to WarewulfYaml Matches the new name of NodesYaml Signed-off-by: Jonathon Anderson --- internal/pkg/config/root.go | 36 ++++++++++++++++---------------- internal/pkg/config/root_test.go | 4 ++-- internal/pkg/upgrade/conf.go | 2 +- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/internal/pkg/config/root.go b/internal/pkg/config/root.go index d5db4896..8c223707 100644 --- a/internal/pkg/config/root.go +++ b/internal/pkg/config/root.go @@ -20,12 +20,12 @@ import ( "gopkg.in/yaml.v3" ) -var cachedConf RootConf +var cachedConf WarewulfYaml -// RootConf is the main Warewulf configuration structure. It stores +// WarewulfYaml is the main Warewulf configuration structure. It stores // some information about the Warewulf server locally, and has // [WarewulfConf], [DHCPConf], [TFTPConf], and [NFSConf] sub-sections. -type RootConf struct { +type WarewulfYaml struct { Comment string `yaml:"comment,omitempty"` Ipaddr string `yaml:"ipaddr"` Ipaddr6 string `yaml:"ipaddr6,omitempty"` @@ -45,10 +45,10 @@ type RootConf struct { warewulfconf string } -// New caches and returns a new [RootConf] initialized with empty +// New caches and returns a new [WarewulfYaml] initialized with empty // values, clearing replacing any previously cached value. -func New() *RootConf { - cachedConf = RootConf{} +func New() *WarewulfYaml { + cachedConf = WarewulfYaml{} cachedConf.warewulfconf = "" cachedConf.Warewulf = new(WarewulfConf) cachedConf.DHCP = new(DHCPConf) @@ -62,9 +62,9 @@ func New() *RootConf { return &cachedConf } -// Get returns a previously cached [RootConf] if it exists, or returns -// a new RootConf. -func Get() *RootConf { +// Get returns a previously cached [WarewulfYaml] if it exists, or returns +// a new WarewulfYaml. +func Get() *WarewulfYaml { // NOTE: This function can be called before any log level is set // so using wwlog.Verbose or wwlog.Debug won't work if reflect.ValueOf(cachedConf).IsZero() { @@ -73,9 +73,9 @@ func Get() *RootConf { return &cachedConf } -// Read populates [RootConf] with the values from a configuration +// Read populates [WarewulfYaml] with the values from a configuration // file. -func (conf *RootConf) Read(confFileName string) error { +func (conf *WarewulfYaml) Read(confFileName string) error { wwlog.Debug("Reading warewulf.conf from: %s", confFileName) conf.warewulfconf = confFileName if data, err := os.ReadFile(confFileName); err != nil { @@ -87,8 +87,8 @@ func (conf *RootConf) Read(confFileName string) error { } } -// Parse populates [RootConf] with the values from a yaml document. -func (conf *RootConf) Parse(data []byte) error { +// Parse populates [WarewulfYaml] with the values from a yaml document. +func (conf *WarewulfYaml) Parse(data []byte) error { // ipxe binaries are merged not overwritten, store defaults separate defIpxe := make(map[string]string) for k, v := range conf.TFTP.IpxeBinaries { @@ -117,9 +117,9 @@ func (conf *RootConf) Parse(data []byte) error { return nil } -// SetDynamicDefaults populates [RootConf] with plausible defaults for +// SetDynamicDefaults populates [WarewulfYaml] with plausible defaults for // the runtime environment. -func (conf *RootConf) SetDynamicDefaults() (err error) { +func (conf *WarewulfYaml) SetDynamicDefaults() (err error) { if conf.Ipaddr == "" || conf.Netmask == "" || conf.Network == "" { var mask net.IPMask var network *net.IPNet @@ -197,12 +197,12 @@ func (conf *RootConf) SetDynamicDefaults() (err error) { return } -// InitializedFromFile returns true if [RootConf] memory was read from +// InitializedFromFile returns true if [WarewulfYaml] memory was read from // a file, or false otherwise. -func (conf *RootConf) InitializedFromFile() bool { +func (conf *WarewulfYaml) InitializedFromFile() bool { return conf.warewulfconf != "" } -func (conf *RootConf) GetWarewulfConf() string { +func (conf *WarewulfYaml) GetWarewulfConf() string { return conf.warewulfconf } diff --git a/internal/pkg/config/root_test.go b/internal/pkg/config/root_test.go index 9546fb04..df625a33 100644 --- a/internal/pkg/config/root_test.go +++ b/internal/pkg/config/root_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/assert" ) -func TestDefaultRootConf(t *testing.T) { +func TestDefaultWarewulfYaml(t *testing.T) { conf := New() assert.Equal(t, 9873, conf.Warewulf.Port) @@ -69,7 +69,7 @@ func TestInitializedFromFile(t *testing.T) { assert.Equal(t, conf.GetWarewulfConf(), tempWarewulfConf.Name()) } -func TestExampleRootConf(t *testing.T) { +func TestExampleWarewulfYaml(t *testing.T) { example_warewulf_conf := ` ipaddr: 192.168.200.1 netmask: 255.255.255.0 diff --git a/internal/pkg/upgrade/conf.go b/internal/pkg/upgrade/conf.go index 13254dbf..24803844 100644 --- a/internal/pkg/upgrade/conf.go +++ b/internal/pkg/upgrade/conf.go @@ -1,6 +1,6 @@ package upgrade -type RootConf struct { +type WarewulfYaml struct { WWInternal int `yaml:"WW_INTERNAL"` Comment string `yaml:"comment,omitempty"` Ipaddr string `yaml:"ipaddr"` From fdbdf88df06b8fe6190c8f73b0754e08b5b89fb6 Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Sun, 3 Nov 2024 15:29:37 -0700 Subject: [PATCH 08/19] Rename NodeConf to NodesConf Signed-off-by: Jonathon Anderson --- internal/pkg/api/container/container.go | 4 ++-- internal/pkg/api/node/set.go | 4 ++-- internal/pkg/api/profile/delete.go | 2 +- internal/pkg/api/profile/set.go | 2 +- internal/pkg/node/constructors.go | 26 ++++++++++++------------- internal/pkg/node/constructors_test.go | 6 +++--- internal/pkg/node/datastructure.go | 2 +- internal/pkg/node/hash.go | 4 ++-- internal/pkg/node/hash_test.go | 4 ++-- internal/pkg/node/list.go | 4 ++-- internal/pkg/node/modifiers.go | 16 +++++++-------- internal/pkg/node/util.go | 4 ++-- internal/pkg/node/util_test.go | 8 ++++---- internal/pkg/warewulfd/nodedb.go | 2 +- 14 files changed, 44 insertions(+), 44 deletions(-) diff --git a/internal/pkg/api/container/container.go b/internal/pkg/api/container/container.go index c9cc97e8..92618180 100644 --- a/internal/pkg/api/container/container.go +++ b/internal/pkg/api/container/container.go @@ -82,7 +82,7 @@ func ContainerBuild(cbp *wwapiv1.ContainerBuildParameter) (err error) { if len(containers) != 1 { return fmt.Errorf("can only set default for one container") } else { - var nodeDB node.NodeYaml + var nodeDB node.NodesYaml nodeDB, err = node.New() if err != nil { return fmt.Errorf("could not open node configuration: %s", err) @@ -238,7 +238,7 @@ func ContainerImport(cip *wwapiv1.ContainerImportParameter) (containerName strin } if cip.Default { - var nodeDB node.NodeYaml + var nodeDB node.NodesYaml nodeDB, err = node.New() if err != nil { err = fmt.Errorf("could not open node configuration: %s", err.Error()) diff --git a/internal/pkg/api/node/set.go b/internal/pkg/api/node/set.go index cfa3b0e8..3dff91aa 100644 --- a/internal/pkg/api/node/set.go +++ b/internal/pkg/api/node/set.go @@ -17,7 +17,7 @@ func NodeSet(set *wwapiv1.ConfSetParameter) (err error) { if set == nil { return fmt.Errorf("NodeSetParameter is nil") } - var nodeDB node.NodeYaml + var nodeDB node.NodesYaml nodeDB, _, err = NodeSetParameterCheck(set) if err != nil { return err @@ -35,7 +35,7 @@ func NodeSet(set *wwapiv1.ConfSetParameter) (err error) { NodeSetParameterCheck does error checking and returns a modified NodeYml which than can be persisted */ -func NodeSetParameterCheck(set *wwapiv1.ConfSetParameter) (nodeDB node.NodeYaml, count uint, err error) { +func NodeSetParameterCheck(set *wwapiv1.ConfSetParameter) (nodeDB node.NodesYaml, count uint, err error) { nodeDB, err = node.New() if err != nil { wwlog.Error("Could not open configuration: %s", err) diff --git a/internal/pkg/api/profile/delete.go b/internal/pkg/api/profile/delete.go index d0dc4cc4..b219da33 100644 --- a/internal/pkg/api/profile/delete.go +++ b/internal/pkg/api/profile/delete.go @@ -40,7 +40,7 @@ func ProfileDelete(ndp *wwapiv1.NodeDeleteParameter) (err error) { // ProfileDeleteParameterCheck does error checking on ProfileDeleteParameter. // Output to the console if console is true. // Returns the profiles to delete. -func ProfileDeleteParameterCheck(ndp *wwapiv1.NodeDeleteParameter, console bool) (nodeDB node.NodeYaml, profileList []string, err error) { +func ProfileDeleteParameterCheck(ndp *wwapiv1.NodeDeleteParameter, console bool) (nodeDB node.NodesYaml, profileList []string, err error) { if ndp == nil { err = fmt.Errorf("profileDeleteParameter is nil") diff --git a/internal/pkg/api/profile/set.go b/internal/pkg/api/profile/set.go index 17b18888..e20cd55c 100644 --- a/internal/pkg/api/profile/set.go +++ b/internal/pkg/api/profile/set.go @@ -35,7 +35,7 @@ func ProfileSet(set *wwapiv1.ConfSetParameter) (err error) { NodeSetParameterCheck does error checking and returns a modified NodeYml which than can be persisted */ -func ProfileSetParameterCheck(set *wwapiv1.ConfSetParameter) (nodeDB node.NodeYaml, count uint, err error) { +func ProfileSetParameterCheck(set *wwapiv1.ConfSetParameter) (nodeDB node.NodesYaml, count uint, err error) { nodeDB, err = node.New() if err != nil { wwlog.Error("Could not open configuration: %s", err) diff --git a/internal/pkg/node/constructors.go b/internal/pkg/node/constructors.go index e22390a3..7e7c6b0c 100644 --- a/internal/pkg/node/constructors.go +++ b/internal/pkg/node/constructors.go @@ -21,7 +21,7 @@ var ( /* Creates a new nodeDb object from the on-disk configuration */ -func New() (NodeYaml, error) { +func New() (NodesYaml, error) { conf := warewulfconf.Get() if ConfigFile == "" { ConfigFile = path.Join(conf.Paths.Sysconfdir, "warewulf/nodes.conf") @@ -29,7 +29,7 @@ func New() (NodeYaml, error) { wwlog.Verbose("Opening node configuration file: %s", ConfigFile) data, err := os.ReadFile(ConfigFile) if err != nil { - return NodeYaml{}, err + return NodesYaml{}, err } return Parse(data) } @@ -38,7 +38,7 @@ func New() (NodeYaml, error) { // document. Passes any errors return from yaml.Unmarshal. Returns an // error if any parsed value is not of a valid type for the given // parameter. -func Parse(data []byte) (nodeList NodeYaml, err error) { +func Parse(data []byte) (nodeList NodesYaml, err error) { wwlog.Debug("Unmarshaling the node configuration") err = yaml.Unmarshal(data, &nodeList) if err != nil { @@ -58,7 +58,7 @@ func Parse(data []byte) (nodeList NodeYaml, err error) { /* Get a node with its merged in nodes */ -func (config *NodeYaml) GetNode(id string) (node Node, err error) { +func (config *NodesYaml) GetNode(id string) (node Node, err error) { if _, ok := config.Nodes[id]; !ok { return node, ErrNotFound } @@ -112,7 +112,7 @@ func (config *NodeYaml) GetNode(id string) (node Node, err error) { Return the node with the id string without the merged in nodes, return ErrNotFound otherwise */ -func (config *NodeYaml) GetNodeOnly(id string) (node Node, err error) { +func (config *NodesYaml) GetNodeOnly(id string) (node Node, err error) { node = EmptyNode() if found, ok := config.Nodes[id]; ok { return *found, nil @@ -124,7 +124,7 @@ func (config *NodeYaml) GetNodeOnly(id string) (node Node, err error) { Return pointer to the node with the id string without the merged in nodes, return ErrMotFound otherwise */ -func (config *NodeYaml) GetNodeOnlyPtr(id string) (*Node, error) { +func (config *NodesYaml) GetNodeOnlyPtr(id string) (*Node, error) { node := EmptyNode() if found, ok := config.Nodes[id]; ok { return found, nil @@ -135,7 +135,7 @@ func (config *NodeYaml) GetNodeOnlyPtr(id string) (*Node, error) { /* Get the profile with id, return ErrNotFound otherwise */ -func (config *NodeYaml) GetProfile(id string) (profile Profile, err error) { +func (config *NodesYaml) GetProfile(id string) (profile Profile, err error) { if found, ok := config.NodeProfiles[id]; ok { found.id = id return *found, nil @@ -146,7 +146,7 @@ func (config *NodeYaml) GetProfile(id string) (profile Profile, err error) { /* Get the profile with id, return ErrNotFound otherwise */ -func (config *NodeYaml) GetProfilePtr(id string) (profile *Profile, err error) { +func (config *NodesYaml) GetProfilePtr(id string) (profile *Profile, err error) { if found, ok := config.NodeProfiles[id]; ok { found.id = id return found, nil @@ -158,7 +158,7 @@ func (config *NodeYaml) GetProfilePtr(id string) (profile *Profile, err error) { Get the nodes from the loaded configuration. This function also merges the nodes with the given nodes. */ -func (config *NodeYaml) FindAllNodes(nodes ...string) (nodeList []Node, err error) { +func (config *NodesYaml) FindAllNodes(nodes ...string) (nodeList []Node, err error) { if len(nodes) == 0 { for n := range config.Nodes { nodes = append(nodes, n) @@ -188,7 +188,7 @@ func (config *NodeYaml) FindAllNodes(nodes ...string) (nodeList []Node, err erro /* Return all nodes as ProfileConf */ -func (config *NodeYaml) FindAllProfiles(nodes ...string) (profileList []Profile, err error) { +func (config *NodesYaml) FindAllProfiles(nodes ...string) (profileList []Profile, err error) { if len(nodes) == 0 { for n := range config.NodeProfiles { nodes = append(nodes, n) @@ -219,7 +219,7 @@ func (config *NodeYaml) FindAllProfiles(nodes ...string) (profileList []Profile, /* Return the names of all available nodes */ -func (config *NodeYaml) ListAllNodes() []string { +func (config *NodesYaml) ListAllNodes() []string { nodeList := make([]string, len(config.Nodes)) for name := range config.Nodes { nodeList = append(nodeList, name) @@ -230,7 +230,7 @@ func (config *NodeYaml) ListAllNodes() []string { /* Return the names of all available nodes */ -func (config *NodeYaml) ListAllProfiles() []string { +func (config *NodesYaml) ListAllProfiles() []string { var nodeList []string for name := range config.NodeProfiles { nodeList = append(nodeList, name) @@ -246,7 +246,7 @@ without a hardware address is returned. If no unconfigured node is found, an error is returned. */ -func (config *NodeYaml) FindDiscoverableNode() (Node, string, error) { +func (config *NodesYaml) FindDiscoverableNode() (Node, string, error) { nodes, _ := config.FindAllNodes() diff --git a/internal/pkg/node/constructors_test.go b/internal/pkg/node/constructors_test.go index 382f8814..cec97419 100644 --- a/internal/pkg/node/constructors_test.go +++ b/internal/pkg/node/constructors_test.go @@ -8,7 +8,7 @@ import ( "gopkg.in/yaml.v3" ) -func newConstructorPrimaryNetworkTest(t *testing.T) NodeYaml { +func newConstructorPrimaryNetworkTest(t *testing.T) NodesYaml { var data = ` nodeprofiles: default: @@ -53,7 +53,7 @@ nodes: override: device: ib1 ` - var ret NodeYaml + var ret NodesYaml err := yaml.Unmarshal([]byte(data), &ret) assert.NoError(t, err) return ret @@ -193,7 +193,7 @@ nodes: - profile2 ` assert := assert.New(t) - var ymlSrc NodeYaml + var ymlSrc NodesYaml err := yaml.Unmarshal([]byte(nodesconf), &ymlSrc) assert.NoError(err) wwlog.SetLogLevel(wwlog.DEBUG) diff --git a/internal/pkg/node/datastructure.go b/internal/pkg/node/datastructure.go index 6735fc3d..cc48b5d3 100644 --- a/internal/pkg/node/datastructure.go +++ b/internal/pkg/node/datastructure.go @@ -14,7 +14,7 @@ const undef string = "UNDEF" /* Structure of which goes to disk */ -type NodeYaml struct { +type NodesYaml struct { NodeProfiles map[string]*Profile Nodes map[string]*Node } diff --git a/internal/pkg/node/hash.go b/internal/pkg/node/hash.go index 18814bac..757a1879 100644 --- a/internal/pkg/node/hash.go +++ b/internal/pkg/node/hash.go @@ -11,7 +11,7 @@ import ( /* Calculate the hash of NodeYaml in an orderder fashion */ -func (config *NodeYaml) Hash() [32]byte { +func (config *NodesYaml) Hash() [32]byte { // flatten out profiles and nodes for _, val := range config.NodeProfiles { val.Flatten() @@ -29,7 +29,7 @@ func (config *NodeYaml) Hash() [32]byte { /* Return the hash as string */ -func (config *NodeYaml) StringHash() string { +func (config *NodesYaml) StringHash() string { buffer := config.Hash() return hex.EncodeToString(buffer[:]) } diff --git a/internal/pkg/node/hash_test.go b/internal/pkg/node/hash_test.go index 637ce3d4..8fc66e79 100644 --- a/internal/pkg/node/hash_test.go +++ b/internal/pkg/node/hash_test.go @@ -75,7 +75,7 @@ nodes: default: ipaddr: 10.0.10.3 ` - var nodeConf1, nodeConf2, nodeConf3 NodeYaml + var nodeConf1, nodeConf2, nodeConf3 NodesYaml err := yaml.Unmarshal([]byte(nodeConfYml1), &nodeConf1) assert.NoError(t, err) err = yaml.Unmarshal([]byte(nodeConfYml2), &nodeConf2) @@ -84,7 +84,7 @@ nodes: assert.NoError(t, err) t.Run("Same NodeYaml with same conf", func(t *testing.T) { - var testConf NodeYaml + var testConf NodesYaml err = yaml.Unmarshal([]byte(nodeConfYml1), &testConf) assert.NoError(t, err) if testConf.Hash() != nodeConf1.Hash() { diff --git a/internal/pkg/node/list.go b/internal/pkg/node/list.go index 9ca4e59a..0cabf65e 100644 --- a/internal/pkg/node/list.go +++ b/internal/pkg/node/list.go @@ -41,7 +41,7 @@ type fieldMap map[string]*NodeFields /* Get all the info out of NodeConf. If emptyFields is set true, all fields are shown not only the ones with effective values */ -func (nodeYml *NodeYaml) GetFields(node Node) (output []NodeFields) { +func (nodeYml *NodesYaml) GetFields(node Node) (output []NodeFields) { nodeMap := make(fieldMap) for _, p := range node.Profiles { if profile, ok := nodeYml.NodeProfiles[p]; ok { @@ -64,7 +64,7 @@ func (nodeYml *NodeYaml) GetFields(node Node) (output []NodeFields) { /* Get all the info out of ProfileConf. If emptyFields is set true, all fields are shown not only the ones with effective values */ -func (nodeYml *NodeYaml) GetFieldsProfile(profile Profile) (output []NodeFields) { +func (nodeYml *NodesYaml) GetFieldsProfile(profile Profile) (output []NodeFields) { profileMap := make(fieldMap) profileMap.importFields(&profile, "", "") for _, elem := range profileMap { diff --git a/internal/pkg/node/modifiers.go b/internal/pkg/node/modifiers.go index 6063614e..be44d520 100644 --- a/internal/pkg/node/modifiers.go +++ b/internal/pkg/node/modifiers.go @@ -14,7 +14,7 @@ import ( /* Add a node with the given ID and return a pointer to it */ -func (config *NodeYaml) AddNode(nodeID string) (*Node, error) { +func (config *NodesYaml) AddNode(nodeID string) (*Node, error) { newNode := NewNode(nodeID) wwlog.Verbose("Adding new node: %s", nodeID) if _, ok := config.Nodes[nodeID]; ok { @@ -28,7 +28,7 @@ func (config *NodeYaml) AddNode(nodeID string) (*Node, error) { /* delete node with the given id */ -func (config *NodeYaml) DelNode(nodeID string) error { +func (config *NodesYaml) DelNode(nodeID string) error { if _, ok := config.Nodes[nodeID]; !ok { return errors.New("nodename does not exist: " + nodeID) } @@ -42,7 +42,7 @@ func (config *NodeYaml) DelNode(nodeID string) error { /* set node for the node with id the values of vals */ -func (config *NodeYaml) SetNode(nodeID string, vals Node) error { +func (config *NodesYaml) SetNode(nodeID string, vals Node) error { node, ok := config.Nodes[nodeID] if !ok { return ErrNotFound @@ -61,7 +61,7 @@ func (config *NodeYaml) SetNode(nodeID string, vals Node) error { /* set profile for the node with id the values of vals */ -func (config *NodeYaml) SetProfile(profileId string, vals Profile) error { +func (config *NodesYaml) SetProfile(profileId string, vals Profile) error { profile, ok := config.NodeProfiles[profileId] if !ok { return ErrNotFound @@ -80,7 +80,7 @@ func (config *NodeYaml) SetProfile(profileId string, vals Profile) error { /* Add a node with the given ID and return a pointer to it */ -func (config *NodeYaml) AddProfile(profileId string) (*Profile, error) { +func (config *NodesYaml) AddProfile(profileId string) (*Profile, error) { profile := EmptyProfile() wwlog.Verbose("adding new profile: %s", profileId) if _, ok := config.NodeProfiles[profileId]; ok { @@ -94,7 +94,7 @@ func (config *NodeYaml) AddProfile(profileId string) (*Profile, error) { /* delete node with the given id */ -func (config *NodeYaml) DelProfile(nodeID string) error { +func (config *NodesYaml) DelProfile(nodeID string) error { if _, ok := config.Nodes[nodeID]; !ok { return errors.New("profile does not exist: " + nodeID) } @@ -108,7 +108,7 @@ func (config *NodeYaml) DelProfile(nodeID string) error { /* Write the the NodeYaml to disk. */ -func (config *NodeYaml) Persist() error { +func (config *NodesYaml) Persist() error { out, dumpErr := config.Dump() if dumpErr != nil { wwlog.Error("%s", dumpErr) @@ -132,7 +132,7 @@ func (config *NodeYaml) Persist() error { Dump returns a YAML document representing the nodeDb instance. Passes through any errors generated by yaml.Marshal. */ -func (config *NodeYaml) Dump() ([]byte, error) { +func (config *NodesYaml) Dump() ([]byte, error) { // flatten out profiles and nodes for _, val := range config.NodeProfiles { val.Flatten() diff --git a/internal/pkg/node/util.go b/internal/pkg/node/util.go index 325f88ad..478e55a4 100644 --- a/internal/pkg/node/util.go +++ b/internal/pkg/node/util.go @@ -10,7 +10,7 @@ import ( /* Gets a node by its hardware(mac) address */ -func (config *NodeYaml) FindByHwaddr(hwa string) (Node, error) { +func (config *NodesYaml) FindByHwaddr(hwa string) (Node, error) { if _, err := net.ParseMAC(hwa); err != nil { return Node{}, errors.New("invalid hardware address: " + hwa) } @@ -29,7 +29,7 @@ func (config *NodeYaml) FindByHwaddr(hwa string) (Node, error) { /* Find a node by its ip address */ -func (config *NodeYaml) FindByIpaddr(ipaddr string) (Node, error) { +func (config *NodesYaml) FindByIpaddr(ipaddr string) (Node, error) { addr := net.ParseIP(ipaddr) if addr == nil { return Node{}, errors.New("invalid IP:" + ipaddr) diff --git a/internal/pkg/node/util_test.go b/internal/pkg/node/util_test.go index 54f2dbbc..ecbc4fef 100644 --- a/internal/pkg/node/util_test.go +++ b/internal/pkg/node/util_test.go @@ -8,7 +8,7 @@ import ( "gopkg.in/yaml.v3" ) -func NewUtilTestNode() (NodeYaml, error) { +func NewUtilTestNode() (NodesYaml, error) { var data = ` nodeprofiles: default: @@ -41,7 +41,7 @@ nodes: default: false ipaddr: fd1a:2b3c:4d5e:06f0:1234:5678:90ab:cdef ` - var ret NodeYaml + var ret NodesYaml err := yaml.Unmarshal([]byte(data), &ret) if err != nil { return ret, err @@ -62,7 +62,7 @@ func Test_nodeYaml_FindByHwaddr(t *testing.T) { tests := []struct { name string //fields fields - config NodeYaml + config NodesYaml args args want string wantErr bool @@ -100,7 +100,7 @@ func Test_nodeYaml_FindByIpaddr(t *testing.T) { } tests := []struct { name string - config NodeYaml + config NodesYaml args args want string wantErr bool diff --git a/internal/pkg/warewulfd/nodedb.go b/internal/pkg/warewulfd/nodedb.go index 4ed997b0..e9f23986 100644 --- a/internal/pkg/warewulfd/nodedb.go +++ b/internal/pkg/warewulfd/nodedb.go @@ -12,7 +12,7 @@ import ( type nodeDB struct { lock sync.RWMutex NodeInfo map[string]string - yml node.NodeYaml + yml node.NodesYaml } var ( From ff40c0fed2ccb4745dd4e89b9e2598996a2585d8 Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Mon, 4 Nov 2024 10:38:28 -0700 Subject: [PATCH 09/19] Node upgrade tests Signed-off-by: Jonathon Anderson --- .../update_configuration.go | 182 ------- .../vers42/datastructure.go | 46 -- cmd/update_configuration/vers42/nodes.conf | 22 - .../vers43/datastructure.go | 65 --- cmd/update_configuration/vers43/nodes.conf | 32 -- internal/pkg/upgrade/conf.go | 2 +- internal/pkg/upgrade/node.go | 465 +++++++++++++++- internal/pkg/upgrade/node_test.go | 502 ++++++++++++++++++ 8 files changed, 945 insertions(+), 371 deletions(-) delete mode 100644 cmd/update_configuration/update_configuration.go delete mode 100644 cmd/update_configuration/vers42/datastructure.go delete mode 100644 cmd/update_configuration/vers42/nodes.conf delete mode 100644 cmd/update_configuration/vers43/datastructure.go delete mode 100644 cmd/update_configuration/vers43/nodes.conf create mode 100644 internal/pkg/upgrade/node_test.go diff --git a/cmd/update_configuration/update_configuration.go b/cmd/update_configuration/update_configuration.go deleted file mode 100644 index bc394445..00000000 --- a/cmd/update_configuration/update_configuration.go +++ /dev/null @@ -1,182 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "os" - "reflect" - - "github.com/warewulf/warewulf/cmd/update_configuration/vers42" - "github.com/warewulf/warewulf/cmd/update_configuration/vers43" - "github.com/warewulf/warewulf/internal/pkg/util" - "gopkg.in/yaml.v3" -) - -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 = os.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, - Primary: 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", 0, "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 := os.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 deleted file mode 100644 index 188419d8..00000000 --- a/cmd/update_configuration/vers42/datastructure.go +++ /dev/null @@ -1,46 +0,0 @@ -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 deleted file mode 100644 index 792e48a2..00000000 --- a/cmd/update_configuration/vers42/nodes.conf +++ /dev/null @@ -1,22 +0,0 @@ -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 deleted file mode 100644 index 24e8f185..00000000 --- a/cmd/update_configuration/vers43/datastructure.go +++ /dev/null @@ -1,65 +0,0 @@ -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"` - Primary string `yaml:"primary,omitempty"` - Tags map[string]string `yaml:"tags,omitempty"` -} diff --git a/cmd/update_configuration/vers43/nodes.conf b/cmd/update_configuration/vers43/nodes.conf deleted file mode 100644 index 22772050..00000000 --- a/cmd/update_configuration/vers43/nodes.conf +++ /dev/null @@ -1,32 +0,0 @@ -WW_INTERNAL: 45 -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" - diff --git a/internal/pkg/upgrade/conf.go b/internal/pkg/upgrade/conf.go index 24803844..ddba7018 100644 --- a/internal/pkg/upgrade/conf.go +++ b/internal/pkg/upgrade/conf.go @@ -1,7 +1,7 @@ package upgrade type WarewulfYaml struct { - WWInternal int `yaml:"WW_INTERNAL"` + WWInternal string `yaml:"WW_INTERNAL"` Comment string `yaml:"comment,omitempty"` Ipaddr string `yaml:"ipaddr"` Ipaddr6 string `yaml:"ipaddr6,omitempty"` diff --git a/internal/pkg/upgrade/node.go b/internal/pkg/upgrade/node.go index 460a75f6..e6d57cf7 100644 --- a/internal/pkg/upgrade/node.go +++ b/internal/pkg/upgrade/node.go @@ -1,31 +1,194 @@ package upgrade import ( + "net" + "strconv" + "strings" + "gopkg.in/yaml.v3" + + "github.com/warewulf/warewulf/internal/pkg/node" + "github.com/warewulf/warewulf/internal/pkg/wwlog" ) -func Parse(data []byte) (nodeYaml NodeYaml, err error) { - if err = yaml.Unmarshal(data, &nodeYaml); err != nil { - return nodeYaml, err - } - if nodeYaml.Nodes == nil { - nodeYaml.Nodes = map[string]*Node{} - } - if nodeYaml.NodeProfiles == nil { - nodeYaml.NodeProfiles = map[string]*Profile{} - } - return nodeYaml, nil +func logIgnore(name string, value interface{}, reason string) { + wwlog.Warn("ignore: %s: %v (%s)", name, value, reason) } -type NodeYaml struct { +func Parse(data []byte) (nodesYaml *NodesYaml, err error) { + nodesYaml = new(NodesYaml) + if err = yaml.Unmarshal(data, nodesYaml); err != nil { + return nodesYaml, err + } + return nodesYaml, nil +} + +type NodesYaml struct { + WWInternal string `yaml:"WW_INTERNAL"` NodeProfiles map[string]*Profile Nodes map[string]*Node } +func (this *NodesYaml) Upgrade() (upgraded *node.NodesYaml) { + upgraded = new(node.NodesYaml) + upgraded.NodeProfiles = make(map[string]*node.Profile) + upgraded.Nodes = make(map[string]*node.Node) + if this.WWInternal != "" { + logIgnore("WW_INTERNAL", this.WWInternal, "obsolete") + } + if this.NodeProfiles != nil { + for name, profile := range this.NodeProfiles { + upgraded.NodeProfiles[name] = profile.Upgrade() + } + } + if this.Nodes != nil { + for name, node := range this.Nodes { + upgraded.Nodes[name] = node.Upgrade() + } + } + return upgraded +} + type Node struct { Profile `yaml:"-,inline"` } +func (this *Node) Upgrade() (upgraded *node.Node) { + upgraded = new(node.Node) + upgraded.Tags = make(map[string]string) + upgraded.Disks = make(map[string]*node.Disk) + upgraded.FileSystems = make(map[string]*node.FileSystem) + upgraded.Ipmi = new(node.IpmiConf) + upgraded.Kernel = new(node.KernelConf) + upgraded.NetDevs = make(map[string]*node.NetDev) + upgraded.AssetKey = this.AssetKey + upgraded.ClusterName = this.ClusterName + upgraded.Comment = this.Comment + upgraded.ContainerName = this.ContainerName + if this.Disabled != "" { + logIgnore("Disabled", this.Disabled, "obsolete") + } + if this.Discoverable != "" { + upgraded.Discoverable.Set(this.Discoverable) + } + if this.Disks != nil { + for name, disk := range this.Disks { + upgraded.Disks[name] = disk.Upgrade() + } + } + if this.FileSystems != nil { + for name, fileSystem := range this.FileSystems { + upgraded.FileSystems[name] = fileSystem.Upgrade() + } + } + upgraded.Init = this.Init + if this.Ipmi != nil { + upgraded.Ipmi = this.Ipmi.Upgrade() + } else { + upgraded.Ipmi = new(node.IpmiConf) + } + if upgraded.Ipmi.EscapeChar == "" { + upgraded.Ipmi.EscapeChar = this.IpmiEscapeChar + } + if upgraded.Ipmi.Gateway.Equal(net.IP{}) { + upgraded.Ipmi.Gateway = net.ParseIP(this.IpmiGateway) + } + if upgraded.Ipmi.Interface == "" { + upgraded.Ipmi.Interface = this.IpmiInterface + } + if upgraded.Ipmi.Ipaddr.Equal(net.IP{}) { + upgraded.Ipmi.Ipaddr = net.ParseIP(this.IpmiIpaddr) + } + if upgraded.Ipmi.Netmask.Equal(net.IP{}) { + upgraded.Ipmi.Netmask = net.ParseIP(this.IpmiNetmask) + } + if upgraded.Ipmi.Password == "" { + upgraded.Ipmi.Password = this.IpmiPassword + } + if upgraded.Ipmi.Port == "" { + upgraded.Ipmi.Port = this.IpmiPort + } + if upgraded.Ipmi.UserName == "" { + upgraded.Ipmi.UserName = this.IpmiUserName + } + if upgraded.Ipmi.Write == "" { + upgraded.Ipmi.Write.Set(this.IpmiWrite) + } + upgraded.Ipxe = this.Ipxe + if this.Kernel != nil { + upgraded.Kernel = this.Kernel.Upgrade() + } else { + upgraded.Kernel = new(node.KernelConf) + } + if upgraded.Kernel.Args == "" { + upgraded.Kernel.Args = this.KernelArgs + } + if upgraded.Kernel.Override == "" { + upgraded.Kernel.Override = this.KernelOverride + } + if upgraded.Kernel.Version == "" { + upgraded.Kernel.Version = this.KernelVersion + } + if this.Keys != nil { + for key, value := range this.Keys { + upgraded.Tags[key] = value + } + } + if this.NetDevs != nil { + for name, netDev := range this.NetDevs { + upgraded.NetDevs[name] = netDev.Upgrade() + } + } + if this.PrimaryNetDev != "" { + upgraded.PrimaryNetDev = this.PrimaryNetDev + } else { + for name, netDev := range this.NetDevs { + if b, _ := strconv.ParseBool(netDev.Primary); b { + upgraded.PrimaryNetDev = name + break + } else if b, _ := strconv.ParseBool(netDev.Default); b { + upgraded.PrimaryNetDev = name + break + } + } + } + upgraded.Profiles = append(upgraded.Profiles, this.Profiles...) + upgraded.Root = this.Root + if this.RuntimeOverlay != nil { + switch overlay := this.RuntimeOverlay.(type) { + case string: + upgraded.RuntimeOverlay = append(upgraded.RuntimeOverlay, strings.Split(overlay, ",")...) + case []interface{}: + for _, each := range overlay { + upgraded.RuntimeOverlay = append(upgraded.RuntimeOverlay, each.(string)) + } + default: + wwlog.Error("unparsable RuntimeOverlay: %v", overlay) + } + } + if this.SystemOverlay != nil { + switch overlay := this.SystemOverlay.(type) { + case string: + upgraded.SystemOverlay = append(upgraded.SystemOverlay, strings.Split(overlay, ",")...) + case []interface{}: + for _, each := range overlay { + upgraded.SystemOverlay = append(upgraded.SystemOverlay, each.(string)) + } + default: + wwlog.Error("unparsable SystemOverlay: %v", overlay) + } + } + if this.Tags != nil { + for key, value := range this.Tags { + upgraded.Tags[key] = value + } + } + for _, tag := range this.TagsDel { + delete(upgraded.Tags, tag) + } + return +} + type Profile struct { AssetKey string `yaml:"asset key,omitempty"` ClusterName string `yaml:"cluster name,omitempty"` @@ -56,12 +219,152 @@ type Profile struct { PrimaryNetDev string `yaml:"primary network,omitempty"` Profiles []string `yaml:"profiles,omitempty"` Root string `yaml:"root,omitempty"` - RuntimeOverlay []string `yaml:"runtime overlay,omitempty"` - SystemOverlay []string `yaml:"system overlay,omitempty"` + RuntimeOverlay interface{} `yaml:"runtime overlay,omitempty"` + SystemOverlay interface{} `yaml:"system overlay,omitempty"` Tags map[string]string `yaml:"tags,omitempty"` TagsDel []string `yaml:"tagsdel,omitempty"` } +func (this *Profile) Upgrade() (upgraded *node.Profile) { + upgraded = new(node.Profile) + upgraded.Tags = make(map[string]string) + upgraded.Disks = make(map[string]*node.Disk) + upgraded.FileSystems = make(map[string]*node.FileSystem) + upgraded.Kernel = new(node.KernelConf) + upgraded.NetDevs = make(map[string]*node.NetDev) + if this.AssetKey != "" { + logIgnore("AssetKey", this.AssetKey, "invalid for profiles") + } + upgraded.ClusterName = this.ClusterName + upgraded.Comment = this.Comment + upgraded.ContainerName = this.ContainerName + if this.Disabled != "" { + logIgnore("Disabled", this.Disabled, "obsolete") + } + if this.Discoverable != "" { + logIgnore("Discoverable", this.Discoverable, "invalid for profiles") + } + if this.Disks != nil { + for name, disk := range this.Disks { + upgraded.Disks[name] = disk.Upgrade() + } + } + if this.FileSystems != nil { + for name, fileSystem := range this.FileSystems { + upgraded.FileSystems[name] = fileSystem.Upgrade() + } + } + upgraded.Init = this.Init + upgraded.Ipmi = new(node.IpmiConf) + if this.Ipmi != nil { + upgraded.Ipmi = this.Ipmi.Upgrade() + } else { + upgraded.Ipmi = new(node.IpmiConf) + } + if upgraded.Ipmi.EscapeChar == "" { + upgraded.Ipmi.EscapeChar = this.IpmiEscapeChar + } + if upgraded.Ipmi.Gateway.Equal(net.IP{}) { + upgraded.Ipmi.Gateway = net.ParseIP(this.IpmiGateway) + } + if upgraded.Ipmi.Interface == "" { + upgraded.Ipmi.Interface = this.IpmiInterface + } + if upgraded.Ipmi.Ipaddr.Equal(net.IP{}) { + upgraded.Ipmi.Ipaddr = net.ParseIP(this.IpmiIpaddr) + } + if upgraded.Ipmi.Netmask.Equal(net.IP{}) { + upgraded.Ipmi.Netmask = net.ParseIP(this.IpmiNetmask) + } + if upgraded.Ipmi.Password == "" { + upgraded.Ipmi.Password = this.IpmiPassword + } + if upgraded.Ipmi.Port == "" { + upgraded.Ipmi.Port = this.IpmiPort + } + if upgraded.Ipmi.UserName == "" { + upgraded.Ipmi.UserName = this.IpmiUserName + } + if upgraded.Ipmi.Write == "" { + upgraded.Ipmi.Write.Set(this.IpmiWrite) + } + upgraded.Ipxe = this.Ipxe + if this.Kernel != nil { + upgraded.Kernel = this.Kernel.Upgrade() + } else { + upgraded.Kernel = new(node.KernelConf) + } + if upgraded.Kernel.Args == "" { + upgraded.Kernel.Args = this.KernelArgs + } + if upgraded.Kernel.Override == "" { + upgraded.Kernel.Override = this.KernelOverride + } + if upgraded.Kernel.Version == "" { + upgraded.Kernel.Version = this.KernelVersion + } + if this.Keys != nil { + for key, value := range this.Keys { + upgraded.Tags[key] = value + } + } + if this.NetDevs != nil { + for name, netDev := range this.NetDevs { + upgraded.NetDevs[name] = netDev.Upgrade() + } + } + if this.PrimaryNetDev != "" { + upgraded.PrimaryNetDev = this.PrimaryNetDev + } else { + for name, netDev := range this.NetDevs { + if b, _ := strconv.ParseBool(netDev.Primary); b { + upgraded.PrimaryNetDev = name + break + } else if b, _ := strconv.ParseBool(netDev.Default); b { + upgraded.PrimaryNetDev = name + break + } + } + } + if this.Profiles != nil { + logIgnore("Profiles", this.Profiles, "invalid for profiles") + } + upgraded.Root = this.Root + if this.RuntimeOverlay != nil { + switch overlay := this.RuntimeOverlay.(type) { + case string: + upgraded.RuntimeOverlay = append(upgraded.RuntimeOverlay, strings.Split(overlay, ",")...) + case []interface{}: + for _, each := range overlay { + upgraded.RuntimeOverlay = append(upgraded.RuntimeOverlay, each.(string)) + } + default: + wwlog.Error("unparsable RuntimeOverlay: %v", overlay) + } + } + if this.SystemOverlay != nil { + switch overlay := this.SystemOverlay.(type) { + case string: + upgraded.SystemOverlay = append(upgraded.SystemOverlay, strings.Split(overlay, ",")...) + case []interface{}: + for _, each := range overlay { + upgraded.SystemOverlay = append(upgraded.SystemOverlay, each.(string)) + } + default: + wwlog.Error("unparsable SystemOverlay: %v", overlay) + } + } + if this.Tags != nil { + for key, value := range this.Tags { + upgraded.Tags[key] = value + } + } + for _, tag := range this.TagsDel { + delete(upgraded.Tags, tag) + } + return +} + type IpmiConf struct { EscapeChar string `yaml:"escapechar,omitempty"` Gateway string `yaml:"gateway,omitempty"` @@ -76,12 +379,43 @@ type IpmiConf struct { Write string `yaml:"write,omitempty"` } +func (this *IpmiConf) Upgrade() (upgraded *node.IpmiConf) { + upgraded = new(node.IpmiConf) + upgraded.Tags = make(map[string]string) + upgraded.EscapeChar = this.EscapeChar + upgraded.Gateway = net.ParseIP(this.Gateway) + upgraded.Interface = this.Interface + upgraded.Ipaddr = net.ParseIP(this.Ipaddr) + upgraded.Netmask = net.ParseIP(this.Netmask) + upgraded.Password = this.Password + upgraded.Port = this.Port + if this.Tags != nil { + for key, value := range this.Tags { + upgraded.Tags[key] = value + } + } + for _, tag := range this.TagsDel { + delete(upgraded.Tags, tag) + } + upgraded.UserName = this.UserName + upgraded.Write.Set(this.Write) + return +} + type KernelConf struct { Args string `yaml:"args,omitempty"` Override string `yaml:"override,omitempty"` Version string `yaml:"version,omitempty"` } +func (this *KernelConf) Upgrade() (upgraded *node.KernelConf) { + upgraded = new(node.KernelConf) + upgraded.Args = this.Args + upgraded.Override = this.Override + upgraded.Version = this.Version + return +} + type NetDev struct { Default string `yaml:"default"` Device string `yaml:"device,omitempty"` @@ -100,11 +434,60 @@ type NetDev struct { Type string `yaml:"type,omitempty"` } +func (this *NetDev) Upgrade() (upgraded *node.NetDev) { + upgraded = new(node.NetDev) + upgraded.Tags = make(map[string]string) + upgraded.Device = this.Device + upgraded.Gateway = net.ParseIP(this.Gateway) + upgraded.Hwaddr = this.Hwaddr + upgraded.Ipaddr = net.ParseIP(this.Ipaddr) + upgraded.Ipaddr6 = net.ParseIP(this.Ipaddr6) + upgraded.MTU = this.MTU + upgraded.Netmask = net.ParseIP(this.Netmask) + if this.IpCIDR != "" { + cidrIP, cidrIPNet, err := net.ParseCIDR(this.IpCIDR) + if err != nil { + wwlog.Error("%v is not a valid CIDR address: %w", this.IpCIDR, err) + } else { + if upgraded.Ipaddr == nil { + upgraded.Ipaddr = cidrIP + } + if upgraded.Netmask == nil { + upgraded.Netmask = net.IP(cidrIPNet.Mask) + } + } + } + upgraded.OnBoot.Set(this.OnBoot) + upgraded.Prefix = net.ParseIP(this.Prefix) + if this.Tags != nil { + for key, value := range this.Tags { + upgraded.Tags[key] = value + } + } + for _, tag := range this.TagsDel { + delete(upgraded.Tags, tag) + } + upgraded.Type = this.Type + return +} + type Disk struct { Partitions map[string]*Partition `yaml:"partitions,omitempty"` WipeTable string `yaml:"wipe_table,omitempty"` } +func (this *Disk) Upgrade() (upgraded *node.Disk) { + upgraded = new(node.Disk) + upgraded.Partitions = make(map[string]*node.Partition) + if this.Partitions != nil { + for name, partition := range this.Partitions { + upgraded.Partitions[name] = partition.Upgrade() + } + } + upgraded.WipeTable, _ = strconv.ParseBool(this.WipeTable) + return +} + type Partition struct { Guid string `yaml:"guid,omitempty"` Number string `yaml:"number,omitempty"` @@ -116,13 +499,49 @@ type Partition struct { WipePartitionEntry string `yaml:"wipe_partition_entry,omitempty"` } -type FileSystem struct { - Format string `yaml:"format,omitempty"` - Label string `yaml:"label,omitempty"` - MountOptions string `yaml:"mount_options,omitempty"` - //MountOptions []string `yaml:"mount_options,omitempty"` - Options []string `yaml:"options,omitempty"` - Path string `yaml:"path,omitempty"` - Uuid string `yaml:"uuid,omitempty"` - WipeFileSystem string `yaml:"wipe_filesystem,omitempty"` +func (this *Partition) Upgrade() (upgraded *node.Partition) { + upgraded = new(node.Partition) + upgraded.Guid = this.Guid + upgraded.Number = this.Number + upgraded.Resize, _ = strconv.ParseBool(this.Resize) + upgraded.ShouldExist, _ = strconv.ParseBool(this.ShouldExist) + upgraded.SizeMiB = this.SizeMiB + upgraded.StartMiB = this.StartMiB + upgraded.TypeGuid = this.TypeGuid + upgraded.WipePartitionEntry, _ = strconv.ParseBool(this.WipePartitionEntry) + return +} + +type FileSystem struct { + Format string `yaml:"format,omitempty"` + Label string `yaml:"label,omitempty"` + MountOptions interface{} `yaml:"mount_options,omitempty"` + Options []string `yaml:"options,omitempty"` + Path string `yaml:"path,omitempty"` + Uuid string `yaml:"uuid,omitempty"` + WipeFileSystem string `yaml:"wipe_filesystem,omitempty"` +} + +func (this *FileSystem) Upgrade() (upgraded *node.FileSystem) { + upgraded = new(node.FileSystem) + upgraded.Options = make([]string, 0) + upgraded.Format = this.Format + upgraded.Label = this.Label + switch mountOptions := this.MountOptions.(type) { + case string: + upgraded.MountOptions = mountOptions + case []interface{}: + mountOptionsStrings := make([]string, 0) + for _, option := range mountOptions { + mountOptionsStrings = append(mountOptionsStrings, option.(string)) + } + upgraded.MountOptions = strings.Join(mountOptionsStrings, " ") + default: + wwlog.Error("unparsable MountOptions: %v", mountOptions) + } + upgraded.Options = append(upgraded.Options, this.Options...) + upgraded.Path = this.Path + upgraded.Uuid = this.Uuid + upgraded.WipeFileSystem, _ = strconv.ParseBool(this.WipeFileSystem) + return } diff --git a/internal/pkg/upgrade/node_test.go b/internal/pkg/upgrade/node_test.go new file mode 100644 index 00000000..06ae79ee --- /dev/null +++ b/internal/pkg/upgrade/node_test.go @@ -0,0 +1,502 @@ +package upgrade + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +var nodesYamlUpgradeTests = []struct { + name string + legacyYaml string + upgradedYaml string +}{ + { + name: "captured vers42 example", + legacyYaml: ` +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 +`, + upgradedYaml: ` +nodeprofiles: + default: + comment: This profile is automatically included for each node + runtime overlay: + - generic + leap: + comment: openSUSE leap + kernel: + version: 5.14.21 + ipmi: + netmask: 255.255.255.0 + network devices: + lan1: + gateway: 1.1.1.1 + tags: + foo: baar +nodes: + node01: + discoverable: "true" + system overlay: + - nodeoverlay + network devices: + eth0: + ipaddr: 1.2.3.4 + primary network: eth0 +`, + }, + { + name: "captured vers43 example", + legacyYaml: ` +WW_INTERNAL: 45 +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" +`, + upgradedYaml: ` +nodeprofiles: + default: + comment: This profile is automatically included for each node + runtime overlay: + - generic + leap: + comment: openSUSE leap + kernel: + override: 5.14.21 + ipmi: + netmask: 255.255.255.0 + network devices: + lan1: + device: lan1 + gateway: 1.1.1.1 + tags: + foo: baar +nodes: + node01: + discoverable: "true" + system overlay: + - nodeoverlay + network devices: + eth0: + device: eth0 + ipaddr: 1.2.3.4 + primary network: eth0 +`, + }, + { + name: "remove WW_INTERNAL", + legacyYaml: `WW_INTERNAL: 45`, + upgradedYaml: ` +nodeprofiles: {} +nodes: {} +`, + }, + { + name: "disabled is obsolete", + legacyYaml: ` +nodes: + n1: + disabled: true +nodeprofiles: + default: + disabled: true +`, + upgradedYaml: ` +nodeprofiles: + default: {} +nodes: + n1: {} +`, + }, + { + name: "inline IPMI settings", + legacyYaml: ` +nodes: + n1: + ipmi escapechar: "~" + ipmi gateway: 192.168.0.1 + ipmi interface: lanplus + ipmi ipaddr: 192.168.0.100 + ipmi netmask: 255.255.255.0 + ipmi password: password + ipmi port: 623 + ipmi username: admin + ipmi write: true +nodeprofiles: + default: + ipmi escapechar: "~" + ipmi gateway: 192.168.0.1 + ipmi interface: lanplus + ipmi ipaddr: 192.168.0.100 + ipmi netmask: 255.255.255.0 + ipmi password: password + ipmi port: 623 + ipmi username: admin + ipmi write: true +`, + upgradedYaml: ` +nodeprofiles: + default: + ipmi: + username: admin + password: password + ipaddr: 192.168.0.100 + gateway: 192.168.0.1 + netmask: 255.255.255.0 + port: "623" + interface: lanplus + escapechar: "~" + write: "true" +nodes: + n1: + ipmi: + username: admin + password: password + ipaddr: 192.168.0.100 + gateway: 192.168.0.1 + netmask: 255.255.255.0 + port: "623" + interface: lanplus + escapechar: "~" + write: "true" +`, + }, + { + name: "inline Kernel settings", + legacyYaml: ` +nodeprofiles: + default: + kernel args: quiet + kernel override: rockylinux-9 + kernel version: 2.6 +nodes: + n1: + kernel args: quiet + kernel override: rockylinux-9 + kernel version: 2.6 +`, + upgradedYaml: ` +nodeprofiles: + default: + kernel: + version: "2.6" + override: rockylinux-9 + args: quiet +nodes: + n1: + kernel: + version: "2.6" + override: rockylinux-9 + args: quiet +`, + }, + { + name: "keys and tags", + legacyYaml: ` +nodeprofiles: + default: + keys: + key1: val1 + key2: val2 + tags: + key2: valB + key3: valC + key4: valD + tagsdel: + - key4 + network devices: + default: + tags: + key2: valB + key3: valC + key4: valD + tagsdel: + - key4 + ipmi: + tags: + key2: valB + key3: valC + key4: valD + tagsdel: + - key4 +nodes: + n1: + keys: + key1: val1 + key2: val2 + tags: + key2: valB + key3: valC + key4: valD + tagsdel: + - key4 + network devices: + default: + tags: + key2: valB + key3: valC + key4: valD + tagsdel: + - key4 + ipmi: + tags: + key2: valB + key3: valC + key4: valD + tagsdel: + - key4 +`, + upgradedYaml: ` +nodeprofiles: + default: + ipmi: + tags: + key2: valB + key3: valC + network devices: + default: + tags: + key2: valB + key3: valC + tags: + key1: val1 + key2: valB + key3: valC +nodes: + n1: + ipmi: + tags: + key2: valB + key3: valC + network devices: + default: + tags: + key2: valB + key3: valC + tags: + key1: val1 + key2: valB + key3: valC +`, + }, + { + name: "primary network", + legacyYaml: ` +nodes: + n1: + network devices: + eth0: {} + eth1: + default: true + n2: + network devices: + eth0: + primary: true + eth1: {} + n3: + network devices: + eth0: + primary: true + eth1: {} + primary network: eth1 +nodeprofiles: + p1: + network devices: + eth0: {} + eth1: + default: true + p2: + network devices: + eth0: + primary: true + eth1: {} + p3: + network devices: + eth0: + primary: true + eth1: {} + primary network: eth1 +`, + upgradedYaml: ` +nodeprofiles: + p1: + primary network: eth1 + p2: + primary network: eth0 + p3: + primary network: eth1 +nodes: + n1: + primary network: eth1 + n2: + primary network: eth0 + n3: + primary network: eth1 +`, + }, + { + name: "overlays", + legacyYaml: ` +nodes: + n1: + runtime overlay: + - r1 + - r2 + system overlay: + - s1 + - s2 + n2: + runtime overlay: r1,r2 + system overlay: s1,s2 +nodeprofiles: + p1: + runtime overlay: + - r1 + - r2 + system overlay: + - s1 + - s2 + p2: + runtime overlay: r1,r2 + system overlay: s1,s2 +`, + upgradedYaml: ` +nodeprofiles: + p1: + runtime overlay: + - r1 + - r2 + system overlay: + - s1 + - s2 + p2: + runtime overlay: + - r1 + - r2 + system overlay: + - s1 + - s2 +nodes: + n1: + runtime overlay: + - r1 + - r2 + system overlay: + - s1 + - s2 + n2: + runtime overlay: + - r1 + - r2 + system overlay: + - s1 + - s2 +`, + }, + { + name: "disk example", + legacyYaml: ` +nodes: + n1: + disks: + /dev/vda: + wipe_table: true + partitions: + scratch: + number: "1" + should_exist: true + swap: + number: "2" + size_mib: "1024" + filesystems: + /dev/disk/by-partlabel/scratch: + format: btrfs + path: /scratch + /dev/disk/by-partlabel/swap: + format: swap + path: swap +`, + upgradedYaml: ` +nodeprofiles: {} +nodes: + n1: + disks: + /dev/vda: + wipe_table: true + partitions: + scratch: + number: "1" + should_exist: true + swap: + number: "2" + size_mib: "1024" + filesystems: + /dev/disk/by-partlabel/scratch: + format: btrfs + path: /scratch + /dev/disk/by-partlabel/swap: + format: swap + path: swap +`, + }, +} + +func Test_UpgradeNodesYaml(t *testing.T) { + for _, tt := range nodesYamlUpgradeTests { + t.Run(tt.name, func(t *testing.T) { + legacy, err := Parse([]byte(tt.legacyYaml)) + assert.NoError(t, err) + upgraded := legacy.Upgrade() + upgradedYaml, err := upgraded.Dump() + assert.Equal(t, strings.TrimSpace(tt.upgradedYaml), strings.TrimSpace(string(upgradedYaml))) + }) + } +} From 835506f5e8c7c29c8305d0d4a9371c9c3e3685ae Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Tue, 5 Nov 2024 10:25:58 -0700 Subject: [PATCH 10/19] Support inserting defaults during config upgrade Signed-off-by: Jonathon Anderson --- internal/pkg/upgrade/node.go | 103 ++++++++++++++++----- internal/pkg/upgrade/node_test.go | 145 +++++++++++++++++++++++++++--- 2 files changed, 214 insertions(+), 34 deletions(-) diff --git a/internal/pkg/upgrade/node.go b/internal/pkg/upgrade/node.go index e6d57cf7..363b6a22 100644 --- a/internal/pkg/upgrade/node.go +++ b/internal/pkg/upgrade/node.go @@ -8,6 +8,7 @@ import ( "gopkg.in/yaml.v3" "github.com/warewulf/warewulf/internal/pkg/node" + "github.com/warewulf/warewulf/internal/pkg/util" "github.com/warewulf/warewulf/internal/pkg/wwlog" ) @@ -29,21 +30,64 @@ type NodesYaml struct { Nodes map[string]*Node } -func (this *NodesYaml) Upgrade() (upgraded *node.NodesYaml) { +func (this *NodesYaml) Upgrade(addDefaults bool) (upgraded *node.NodesYaml) { upgraded = new(node.NodesYaml) upgraded.NodeProfiles = make(map[string]*node.Profile) upgraded.Nodes = make(map[string]*node.Node) if this.WWInternal != "" { logIgnore("WW_INTERNAL", this.WWInternal, "obsolete") } - if this.NodeProfiles != nil { - for name, profile := range this.NodeProfiles { - upgraded.NodeProfiles[name] = profile.Upgrade() + for name, profile := range this.NodeProfiles { + upgraded.NodeProfiles[name] = profile.Upgrade(addDefaults) + } + for name, node := range this.Nodes { + upgraded.Nodes[name] = node.Upgrade(addDefaults) + if addDefaults && !util.InSlice(upgraded.Nodes[name].Profiles, "default") { + wwlog.Warn("node %s does not include the default profile: verify default settings manually", name) } } - if this.Nodes != nil { - for name, node := range this.Nodes { - upgraded.Nodes[name] = node.Upgrade() + if addDefaults { + if _, ok := upgraded.NodeProfiles["default"]; !ok { + upgraded.NodeProfiles["default"] = new(node.Profile) + upgraded.NodeProfiles["default"].Kernel = new(node.KernelConf) + } + defaultProfile := upgraded.NodeProfiles["default"] + if len(defaultProfile.SystemOverlay) == 0 { + defaultProfile.SystemOverlay = append( + defaultProfile.SystemOverlay, + "wwinit", + "wwclient", + "fstab", + "hostname", + "ssh.host_keys", + "issue", + "resolv", + "udev.netname", + "systemd.netname", + "ifcfg", + "NetworkManager", + "debian.interfaces", + "wicked", + "ignition") + } + if len(defaultProfile.RuntimeOverlay) == 0 { + defaultProfile.RuntimeOverlay = append( + defaultProfile.RuntimeOverlay, + "hosts", + "ssh.authorized_keys", + "syncuser") + } + if defaultProfile.Kernel.Args == "" { + defaultProfile.Kernel.Args = "quiet crashkernel=no vga=791 net.naming-scheme=v238" + } + if defaultProfile.Init == "" { + defaultProfile.Init = "/sbin/init" + } + if defaultProfile.Root == "" { + defaultProfile.Root = "initramfs" + } + if defaultProfile.Ipxe == "" { + defaultProfile.Ipxe = "default" } } return upgraded @@ -53,7 +97,7 @@ type Node struct { Profile `yaml:"-,inline"` } -func (this *Node) Upgrade() (upgraded *node.Node) { +func (this *Node) Upgrade(addDefaults bool) (upgraded *node.Node) { upgraded = new(node.Node) upgraded.Tags = make(map[string]string) upgraded.Disks = make(map[string]*node.Disk) @@ -136,7 +180,7 @@ func (this *Node) Upgrade() (upgraded *node.Node) { } if this.NetDevs != nil { for name, netDev := range this.NetDevs { - upgraded.NetDevs[name] = netDev.Upgrade() + upgraded.NetDevs[name] = netDev.Upgrade(addDefaults) } } if this.PrimaryNetDev != "" { @@ -153,6 +197,11 @@ func (this *Node) Upgrade() (upgraded *node.Node) { } } upgraded.Profiles = append(upgraded.Profiles, this.Profiles...) + if addDefaults { + if len(upgraded.Profiles) == 0 { + upgraded.Profiles = append(upgraded.Profiles, "default") + } + } upgraded.Root = this.Root if this.RuntimeOverlay != nil { switch overlay := this.RuntimeOverlay.(type) { @@ -225,7 +274,7 @@ type Profile struct { TagsDel []string `yaml:"tagsdel,omitempty"` } -func (this *Profile) Upgrade() (upgraded *node.Profile) { +func (this *Profile) Upgrade(addDefaults bool) (upgraded *node.Profile) { upgraded = new(node.Profile) upgraded.Tags = make(map[string]string) upgraded.Disks = make(map[string]*node.Disk) @@ -310,7 +359,7 @@ func (this *Profile) Upgrade() (upgraded *node.Profile) { } if this.NetDevs != nil { for name, netDev := range this.NetDevs { - upgraded.NetDevs[name] = netDev.Upgrade() + upgraded.NetDevs[name] = netDev.Upgrade(addDefaults) } } if this.PrimaryNetDev != "" { @@ -434,7 +483,7 @@ type NetDev struct { Type string `yaml:"type,omitempty"` } -func (this *NetDev) Upgrade() (upgraded *node.NetDev) { +func (this *NetDev) Upgrade(addDefaults bool) (upgraded *node.NetDev) { upgraded = new(node.NetDev) upgraded.Tags = make(map[string]string) upgraded.Device = this.Device @@ -468,6 +517,14 @@ func (this *NetDev) Upgrade() (upgraded *node.NetDev) { delete(upgraded.Tags, tag) } upgraded.Type = this.Type + if addDefaults { + if upgraded.Type == "" { + upgraded.Type = "ethernet" + } + if upgraded.Netmask == nil { + upgraded.Netmask = net.ParseIP("255.255.255.0") + } + } return } @@ -527,17 +584,19 @@ func (this *FileSystem) Upgrade() (upgraded *node.FileSystem) { upgraded.Options = make([]string, 0) upgraded.Format = this.Format upgraded.Label = this.Label - switch mountOptions := this.MountOptions.(type) { - case string: - upgraded.MountOptions = mountOptions - case []interface{}: - mountOptionsStrings := make([]string, 0) - for _, option := range mountOptions { - mountOptionsStrings = append(mountOptionsStrings, option.(string)) + if this.MountOptions != nil { + switch mountOptions := this.MountOptions.(type) { + case string: + upgraded.MountOptions = mountOptions + case []interface{}: + mountOptionsStrings := make([]string, 0) + for _, option := range mountOptions { + mountOptionsStrings = append(mountOptionsStrings, option.(string)) + } + upgraded.MountOptions = strings.Join(mountOptionsStrings, " ") + default: + wwlog.Error("unparsable MountOptions: %v", mountOptions) } - upgraded.MountOptions = strings.Join(mountOptionsStrings, " ") - default: - wwlog.Error("unparsable MountOptions: %v", mountOptions) } upgraded.Options = append(upgraded.Options, this.Options...) upgraded.Path = this.Path diff --git a/internal/pkg/upgrade/node_test.go b/internal/pkg/upgrade/node_test.go index 06ae79ee..ae4bec8a 100644 --- a/internal/pkg/upgrade/node_test.go +++ b/internal/pkg/upgrade/node_test.go @@ -9,11 +9,13 @@ import ( var nodesYamlUpgradeTests = []struct { name string + addDefaults bool legacyYaml string upgradedYaml string }{ { - name: "captured vers42 example", + name: "captured vers42 example", + addDefaults: false, legacyYaml: ` nodeprofiles: default: @@ -67,7 +69,8 @@ nodes: `, }, { - name: "captured vers43 example", + name: "captured vers43 example", + addDefaults: false, legacyYaml: ` WW_INTERNAL: 45 nodeprofiles: @@ -132,15 +135,17 @@ nodes: `, }, { - name: "remove WW_INTERNAL", - legacyYaml: `WW_INTERNAL: 45`, + name: "remove WW_INTERNAL", + addDefaults: false, + legacyYaml: `WW_INTERNAL: 45`, upgradedYaml: ` nodeprofiles: {} nodes: {} `, }, { - name: "disabled is obsolete", + name: "disabled is obsolete", + addDefaults: false, legacyYaml: ` nodes: n1: @@ -157,7 +162,8 @@ nodes: `, }, { - name: "inline IPMI settings", + name: "inline IPMI settings", + addDefaults: false, legacyYaml: ` nodes: n1: @@ -210,7 +216,8 @@ nodes: `, }, { - name: "inline Kernel settings", + name: "inline Kernel settings", + addDefaults: false, legacyYaml: ` nodeprofiles: default: @@ -239,7 +246,8 @@ nodes: `, }, { - name: "keys and tags", + name: "keys and tags", + addDefaults: false, legacyYaml: ` nodeprofiles: default: @@ -328,7 +336,8 @@ nodes: `, }, { - name: "primary network", + name: "primary network", + addDefaults: false, legacyYaml: ` nodes: n1: @@ -383,7 +392,8 @@ nodes: `, }, { - name: "overlays", + name: "overlays", + addDefaults: false, legacyYaml: ` nodes: n1: @@ -442,7 +452,8 @@ nodes: `, }, { - name: "disk example", + name: "disk example", + addDefaults: false, legacyYaml: ` nodes: n1: @@ -485,6 +496,116 @@ nodes: /dev/disk/by-partlabel/swap: format: swap path: swap +`, + }, + { + name: "add defaults", + addDefaults: true, + legacyYaml: ` +nodes: + n1: + network devices: + default: + ipaddr: 192.168.0.100 +`, + upgradedYaml: ` +nodeprofiles: + default: + ipxe template: default + runtime overlay: + - hosts + - ssh.authorized_keys + - syncuser + system overlay: + - wwinit + - wwclient + - fstab + - hostname + - ssh.host_keys + - issue + - resolv + - udev.netname + - systemd.netname + - ifcfg + - NetworkManager + - debian.interfaces + - wicked + - ignition + kernel: + args: quiet crashkernel=no vga=791 net.naming-scheme=v238 + init: /sbin/init + root: initramfs +nodes: + n1: + profiles: + - default + network devices: + default: + type: ethernet + ipaddr: 192.168.0.100 + netmask: 255.255.255.0 +`, + }, + { + name: "add defaults conflicts", + addDefaults: true, + legacyYaml: ` +nodeprofiles: + default: + system overlay: + - wwinit + - wwclient + - fstab + - hostname + - ssh.host_keys + - issue + - resolv + - udev.netname + - systemd.netname + - NetworkManager + custom: {} +nodes: + n1: + profiles: + - custom + network devices: + default: + ipaddr: 10.0.0.100 + netmask: 255.255.0.0 +`, + upgradedYaml: ` +nodeprofiles: + custom: {} + default: + ipxe template: default + runtime overlay: + - hosts + - ssh.authorized_keys + - syncuser + system overlay: + - wwinit + - wwclient + - fstab + - hostname + - ssh.host_keys + - issue + - resolv + - udev.netname + - systemd.netname + - NetworkManager + kernel: + args: quiet crashkernel=no vga=791 net.naming-scheme=v238 + init: /sbin/init + root: initramfs +nodes: + n1: + profiles: + - custom + network devices: + default: + type: ethernet + ipaddr: 10.0.0.100 + netmask: 255.255.0.0 `, }, } @@ -494,7 +615,7 @@ func Test_UpgradeNodesYaml(t *testing.T) { t.Run(tt.name, func(t *testing.T) { legacy, err := Parse([]byte(tt.legacyYaml)) assert.NoError(t, err) - upgraded := legacy.Upgrade() + upgraded := legacy.Upgrade(tt.addDefaults) upgradedYaml, err := upgraded.Dump() assert.Equal(t, strings.TrimSpace(tt.upgradedYaml), strings.TrimSpace(string(upgradedYaml))) }) From 336577c221d0add3eccada4f46360d4605a4c0e5 Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Tue, 5 Nov 2024 10:32:13 -0700 Subject: [PATCH 11/19] Fix linter errors Capture and generate warnings for boolean conversion errors. Signed-off-by: Jonathon Anderson --- internal/pkg/upgrade/node.go | 16 +++++++++++----- internal/pkg/upgrade/node_test.go | 2 +- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/internal/pkg/upgrade/node.go b/internal/pkg/upgrade/node.go index 363b6a22..d93a34c8 100644 --- a/internal/pkg/upgrade/node.go +++ b/internal/pkg/upgrade/node.go @@ -16,6 +16,12 @@ func logIgnore(name string, value interface{}, reason string) { wwlog.Warn("ignore: %s: %v (%s)", name, value, reason) } +func warnError(err error) { + if err != nil { + wwlog.Warn("%w", err) + } +} + func Parse(data []byte) (nodesYaml *NodesYaml, err error) { nodesYaml = new(NodesYaml) if err = yaml.Unmarshal(data, nodesYaml); err != nil { @@ -113,7 +119,7 @@ func (this *Node) Upgrade(addDefaults bool) (upgraded *node.Node) { logIgnore("Disabled", this.Disabled, "obsolete") } if this.Discoverable != "" { - upgraded.Discoverable.Set(this.Discoverable) + warnError(upgraded.Discoverable.Set(this.Discoverable)) } if this.Disks != nil { for name, disk := range this.Disks { @@ -156,7 +162,7 @@ func (this *Node) Upgrade(addDefaults bool) (upgraded *node.Node) { upgraded.Ipmi.UserName = this.IpmiUserName } if upgraded.Ipmi.Write == "" { - upgraded.Ipmi.Write.Set(this.IpmiWrite) + warnError(upgraded.Ipmi.Write.Set(this.IpmiWrite)) } upgraded.Ipxe = this.Ipxe if this.Kernel != nil { @@ -335,7 +341,7 @@ func (this *Profile) Upgrade(addDefaults bool) (upgraded *node.Profile) { upgraded.Ipmi.UserName = this.IpmiUserName } if upgraded.Ipmi.Write == "" { - upgraded.Ipmi.Write.Set(this.IpmiWrite) + warnError(upgraded.Ipmi.Write.Set(this.IpmiWrite)) } upgraded.Ipxe = this.Ipxe if this.Kernel != nil { @@ -447,7 +453,7 @@ func (this *IpmiConf) Upgrade() (upgraded *node.IpmiConf) { delete(upgraded.Tags, tag) } upgraded.UserName = this.UserName - upgraded.Write.Set(this.Write) + warnError(upgraded.Write.Set(this.Write)) return } @@ -506,7 +512,7 @@ func (this *NetDev) Upgrade(addDefaults bool) (upgraded *node.NetDev) { } } } - upgraded.OnBoot.Set(this.OnBoot) + warnError(upgraded.OnBoot.Set(this.OnBoot)) upgraded.Prefix = net.ParseIP(this.Prefix) if this.Tags != nil { for key, value := range this.Tags { diff --git a/internal/pkg/upgrade/node_test.go b/internal/pkg/upgrade/node_test.go index ae4bec8a..334199ed 100644 --- a/internal/pkg/upgrade/node_test.go +++ b/internal/pkg/upgrade/node_test.go @@ -616,7 +616,7 @@ func Test_UpgradeNodesYaml(t *testing.T) { legacy, err := Parse([]byte(tt.legacyYaml)) assert.NoError(t, err) upgraded := legacy.Upgrade(tt.addDefaults) - upgradedYaml, err := upgraded.Dump() + upgradedYaml, _ := upgraded.Dump() assert.Equal(t, strings.TrimSpace(tt.upgradedYaml), strings.TrimSpace(string(upgradedYaml))) }) } From 981d11a012829ca3a021aab278858d28172513aa Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Tue, 5 Nov 2024 12:03:03 -0700 Subject: [PATCH 12/19] Initial wwctl upgrade command Signed-off-by: Jonathon Anderson --- internal/app/wwctl/root.go | 2 ++ internal/app/wwctl/upgrade/cobra.go | 48 +++++++++++++++++++++++++++++ internal/pkg/node/constructors.go | 11 ++++--- internal/pkg/node/modifiers.go | 11 +++++-- internal/pkg/upgrade/node_test.go | 3 +- 5 files changed, 68 insertions(+), 7 deletions(-) create mode 100644 internal/app/wwctl/upgrade/cobra.go diff --git a/internal/app/wwctl/root.go b/internal/app/wwctl/root.go index cd86b128..d225e7df 100644 --- a/internal/app/wwctl/root.go +++ b/internal/app/wwctl/root.go @@ -15,6 +15,7 @@ import ( "github.com/warewulf/warewulf/internal/app/wwctl/profile" "github.com/warewulf/warewulf/internal/app/wwctl/server" "github.com/warewulf/warewulf/internal/app/wwctl/ssh" + "github.com/warewulf/warewulf/internal/app/wwctl/upgrade" "github.com/warewulf/warewulf/internal/app/wwctl/version" warewulfconf "github.com/warewulf/warewulf/internal/pkg/config" "github.com/warewulf/warewulf/internal/pkg/help" @@ -60,6 +61,7 @@ func init() { rootCmd.AddCommand(ssh.GetCommand()) rootCmd.AddCommand(genconf.GetCommand()) rootCmd.AddCommand(clean.GetCommand()) + rootCmd.AddCommand(upgrade.Command) } // GetRootCommand returns the root cobra.Command for the application. diff --git a/internal/app/wwctl/upgrade/cobra.go b/internal/app/wwctl/upgrade/cobra.go new file mode 100644 index 00000000..22b57d6f --- /dev/null +++ b/internal/app/wwctl/upgrade/cobra.go @@ -0,0 +1,48 @@ +package upgrade + +import ( + "os" + + "github.com/spf13/cobra" + + "github.com/warewulf/warewulf/internal/pkg/node" + libupgrade "github.com/warewulf/warewulf/internal/pkg/upgrade" + "github.com/warewulf/warewulf/internal/pkg/util" +) + +var ( + Command = &cobra.Command{ + DisableFlagsInUseLine: true, + Use: "upgrade [OPTIONS]", + Short: "Upgrade an existing nodes.conf", + Long: `Upgrades nodes.conf from a previous version of Warewulf 4 to a format +supported by the current version.`, + RunE: UpgradeNodesConf, + } + + addDefaults bool + inputPath string + outputPath string +) + +func init() { + Command.Flags().BoolVar(&addDefaults, "add-defaults", false, "Configure a default profile and set default node values") + Command.Flags().StringVarP(&inputPath, "input-path", "i", node.ConfigFile, "Path to a legacy nodes.conf") + Command.Flags().StringVarP(&outputPath, "output-path", "o", node.ConfigFile, "Path to write the upgraded nodes.conf to") +} + +func UpgradeNodesConf(cmd *cobra.Command, args []string) error { + data, err := os.ReadFile(inputPath) + if err != nil { + return err + } + legacy, err := libupgrade.Parse(data) + if err != nil { + return err + } + upgraded := legacy.Upgrade(addDefaults) + if err := util.CopyFile(outputPath, outputPath+"-old"); err != nil { + return err + } + return upgraded.PersistToFile(outputPath) +} diff --git a/internal/pkg/node/constructors.go b/internal/pkg/node/constructors.go index 7e7c6b0c..7e00ed7a 100644 --- a/internal/pkg/node/constructors.go +++ b/internal/pkg/node/constructors.go @@ -18,14 +18,17 @@ var ( ConfigFile string ) -/* -Creates a new nodeDb object from the on-disk configuration -*/ -func New() (NodesYaml, error) { +func init() { conf := warewulfconf.Get() if ConfigFile == "" { ConfigFile = path.Join(conf.Paths.Sysconfdir, "warewulf/nodes.conf") } +} + +/* +Creates a new nodeDb object from the on-disk configuration +*/ +func New() (NodesYaml, error) { wwlog.Verbose("Opening node configuration file: %s", ConfigFile) data, err := os.ReadFile(ConfigFile) if err != nil { diff --git a/internal/pkg/node/modifiers.go b/internal/pkg/node/modifiers.go index be44d520..1bd5e03b 100644 --- a/internal/pkg/node/modifiers.go +++ b/internal/pkg/node/modifiers.go @@ -109,12 +109,19 @@ func (config *NodesYaml) DelProfile(nodeID string) error { Write the the NodeYaml to disk. */ func (config *NodesYaml) Persist() error { + return config.PersistToFile(ConfigFile) +} + +func (config *NodesYaml) PersistToFile(configFile string) error { + if configFile == "" { + configFile = ConfigFile + } out, dumpErr := config.Dump() if dumpErr != nil { wwlog.Error("%s", dumpErr) return dumpErr } - file, err := os.OpenFile(ConfigFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o644) + file, err := os.OpenFile(configFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o644) if err != nil { wwlog.Error("%s", err) return err @@ -124,7 +131,7 @@ func (config *NodesYaml) Persist() error { if err != nil { return err } - wwlog.Debug("persisted: %s", ConfigFile) + wwlog.Debug("persisted: %s", configFile) return nil } diff --git a/internal/pkg/upgrade/node_test.go b/internal/pkg/upgrade/node_test.go index 334199ed..4e1d99dd 100644 --- a/internal/pkg/upgrade/node_test.go +++ b/internal/pkg/upgrade/node_test.go @@ -616,7 +616,8 @@ func Test_UpgradeNodesYaml(t *testing.T) { legacy, err := Parse([]byte(tt.legacyYaml)) assert.NoError(t, err) upgraded := legacy.Upgrade(tt.addDefaults) - upgradedYaml, _ := upgraded.Dump() + upgradedYaml, err := upgraded.Dump() + assert.NoError(t, err) assert.Equal(t, strings.TrimSpace(tt.upgradedYaml), strings.TrimSpace(string(upgradedYaml))) }) } From 263e3959c2ab6063b53a7982ded9253be04ab33d Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Tue, 5 Nov 2024 12:29:53 -0700 Subject: [PATCH 13/19] Fix handling of upgrading booleans Signed-off-by: Jonathon Anderson --- internal/pkg/upgrade/node.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/internal/pkg/upgrade/node.go b/internal/pkg/upgrade/node.go index d93a34c8..9f066ff2 100644 --- a/internal/pkg/upgrade/node.go +++ b/internal/pkg/upgrade/node.go @@ -18,7 +18,7 @@ func logIgnore(name string, value interface{}, reason string) { func warnError(err error) { if err != nil { - wwlog.Warn("%w", err) + wwlog.Warn("%s", err) } } @@ -161,7 +161,7 @@ func (this *Node) Upgrade(addDefaults bool) (upgraded *node.Node) { if upgraded.Ipmi.UserName == "" { upgraded.Ipmi.UserName = this.IpmiUserName } - if upgraded.Ipmi.Write == "" { + if upgraded.Ipmi.Write == "" && this.IpmiWrite != "" { warnError(upgraded.Ipmi.Write.Set(this.IpmiWrite)) } upgraded.Ipxe = this.Ipxe @@ -340,7 +340,7 @@ func (this *Profile) Upgrade(addDefaults bool) (upgraded *node.Profile) { if upgraded.Ipmi.UserName == "" { upgraded.Ipmi.UserName = this.IpmiUserName } - if upgraded.Ipmi.Write == "" { + if upgraded.Ipmi.Write == "" && this.IpmiWrite != "" { warnError(upgraded.Ipmi.Write.Set(this.IpmiWrite)) } upgraded.Ipxe = this.Ipxe @@ -453,7 +453,9 @@ func (this *IpmiConf) Upgrade() (upgraded *node.IpmiConf) { delete(upgraded.Tags, tag) } upgraded.UserName = this.UserName - warnError(upgraded.Write.Set(this.Write)) + if this.Write != "" { + warnError(upgraded.Write.Set(this.Write)) + } return } @@ -512,7 +514,9 @@ func (this *NetDev) Upgrade(addDefaults bool) (upgraded *node.NetDev) { } } } - warnError(upgraded.OnBoot.Set(this.OnBoot)) + if this.OnBoot != "" { + warnError(upgraded.OnBoot.Set(this.OnBoot)) + } upgraded.Prefix = net.ParseIP(this.Prefix) if this.Tags != nil { for key, value := range this.Tags { From 393629321c2ae274dc75ee1390d39c5a955f8f4c Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Tue, 5 Nov 2024 13:16:22 -0700 Subject: [PATCH 14/19] Optionally replace wwinit and generic overlays during upgrade Signed-off-by: Jonathon Anderson --- internal/app/wwctl/upgrade/cobra.go | 10 +- internal/pkg/upgrade/node.go | 98 +++++++++++++++----- internal/pkg/upgrade/node_test.go | 136 ++++++++++++++++++++++------ 3 files changed, 186 insertions(+), 58 deletions(-) diff --git a/internal/app/wwctl/upgrade/cobra.go b/internal/app/wwctl/upgrade/cobra.go index 22b57d6f..87448452 100644 --- a/internal/app/wwctl/upgrade/cobra.go +++ b/internal/app/wwctl/upgrade/cobra.go @@ -20,13 +20,15 @@ supported by the current version.`, RunE: UpgradeNodesConf, } - addDefaults bool - inputPath string - outputPath string + addDefaults bool + replaceOverlays bool + inputPath string + outputPath string ) func init() { Command.Flags().BoolVar(&addDefaults, "add-defaults", false, "Configure a default profile and set default node values") + Command.Flags().BoolVar(&replaceOverlays, "replace-overlays", false, "Replace 'wwinit' and 'generic' overlays with their split replacements") Command.Flags().StringVarP(&inputPath, "input-path", "i", node.ConfigFile, "Path to a legacy nodes.conf") Command.Flags().StringVarP(&outputPath, "output-path", "o", node.ConfigFile, "Path to write the upgraded nodes.conf to") } @@ -40,7 +42,7 @@ func UpgradeNodesConf(cmd *cobra.Command, args []string) error { if err != nil { return err } - upgraded := legacy.Upgrade(addDefaults) + upgraded := legacy.Upgrade(addDefaults, replaceOverlays) if err := util.CopyFile(outputPath, outputPath+"-old"); err != nil { return err } diff --git a/internal/pkg/upgrade/node.go b/internal/pkg/upgrade/node.go index 9f066ff2..f237da48 100644 --- a/internal/pkg/upgrade/node.go +++ b/internal/pkg/upgrade/node.go @@ -12,6 +12,45 @@ import ( "github.com/warewulf/warewulf/internal/pkg/wwlog" ) +var wwinitSplitOverlays = []string{ + "wwinit", + "wwclient", + "fstab", + "hostname", + "ssh.host_keys", + "issue", + "resolv", + "udev.netname", + "systemd.netname", + "ifcfg", + "NetworkManager", + "debian.interfaces", + "wicked", + "ignition", +} + +var genericSplitOverlays = []string{ + "hosts", + "ssh.authorized_keys", + "syncuser", +} + +func indexOf[T comparable](slice []T, item T) int { + for i, v := range slice { + if v == item { + return i + } + } + return -1 +} + +func replaceSliceElement[T any](original []T, index int, replacement []T) []T { + if index < 0 || index >= len(original) { + return original + } + return append(original[:index], append(replacement, original[index+1:]...)...) +} + func logIgnore(name string, value interface{}, reason string) { wwlog.Warn("ignore: %s: %v (%s)", name, value, reason) } @@ -36,7 +75,7 @@ type NodesYaml struct { Nodes map[string]*Node } -func (this *NodesYaml) Upgrade(addDefaults bool) (upgraded *node.NodesYaml) { +func (this *NodesYaml) Upgrade(addDefaults bool, replaceOverlays bool) (upgraded *node.NodesYaml) { upgraded = new(node.NodesYaml) upgraded.NodeProfiles = make(map[string]*node.Profile) upgraded.Nodes = make(map[string]*node.Node) @@ -44,10 +83,10 @@ func (this *NodesYaml) Upgrade(addDefaults bool) (upgraded *node.NodesYaml) { logIgnore("WW_INTERNAL", this.WWInternal, "obsolete") } for name, profile := range this.NodeProfiles { - upgraded.NodeProfiles[name] = profile.Upgrade(addDefaults) + upgraded.NodeProfiles[name] = profile.Upgrade(addDefaults, replaceOverlays) } for name, node := range this.Nodes { - upgraded.Nodes[name] = node.Upgrade(addDefaults) + upgraded.Nodes[name] = node.Upgrade(addDefaults, replaceOverlays) if addDefaults && !util.InSlice(upgraded.Nodes[name].Profiles, "default") { wwlog.Warn("node %s does not include the default profile: verify default settings manually", name) } @@ -60,28 +99,11 @@ func (this *NodesYaml) Upgrade(addDefaults bool) (upgraded *node.NodesYaml) { defaultProfile := upgraded.NodeProfiles["default"] if len(defaultProfile.SystemOverlay) == 0 { defaultProfile.SystemOverlay = append( - defaultProfile.SystemOverlay, - "wwinit", - "wwclient", - "fstab", - "hostname", - "ssh.host_keys", - "issue", - "resolv", - "udev.netname", - "systemd.netname", - "ifcfg", - "NetworkManager", - "debian.interfaces", - "wicked", - "ignition") + defaultProfile.SystemOverlay, wwinitSplitOverlays...) } if len(defaultProfile.RuntimeOverlay) == 0 { defaultProfile.RuntimeOverlay = append( - defaultProfile.RuntimeOverlay, - "hosts", - "ssh.authorized_keys", - "syncuser") + defaultProfile.RuntimeOverlay, genericSplitOverlays...) } if defaultProfile.Kernel.Args == "" { defaultProfile.Kernel.Args = "quiet crashkernel=no vga=791 net.naming-scheme=v238" @@ -103,7 +125,7 @@ type Node struct { Profile `yaml:"-,inline"` } -func (this *Node) Upgrade(addDefaults bool) (upgraded *node.Node) { +func (this *Node) Upgrade(addDefaults bool, replaceOverlays bool) (upgraded *node.Node) { upgraded = new(node.Node) upgraded.Tags = make(map[string]string) upgraded.Disks = make(map[string]*node.Disk) @@ -233,6 +255,20 @@ func (this *Node) Upgrade(addDefaults bool) (upgraded *node.Node) { wwlog.Error("unparsable SystemOverlay: %v", overlay) } } + if replaceOverlays { + if indexOf(upgraded.SystemOverlay, "wwinit") != -1 { + upgraded.SystemOverlay = replaceSliceElement( + upgraded.SystemOverlay, + indexOf(upgraded.SystemOverlay, "wwinit"), + wwinitSplitOverlays) + } + if indexOf(upgraded.RuntimeOverlay, "generic") != -1 { + upgraded.RuntimeOverlay = replaceSliceElement( + upgraded.RuntimeOverlay, + indexOf(upgraded.RuntimeOverlay, "generic"), + genericSplitOverlays) + } + } if this.Tags != nil { for key, value := range this.Tags { upgraded.Tags[key] = value @@ -280,7 +316,7 @@ type Profile struct { TagsDel []string `yaml:"tagsdel,omitempty"` } -func (this *Profile) Upgrade(addDefaults bool) (upgraded *node.Profile) { +func (this *Profile) Upgrade(addDefaults bool, replaceOverlays bool) (upgraded *node.Profile) { upgraded = new(node.Profile) upgraded.Tags = make(map[string]string) upgraded.Disks = make(map[string]*node.Disk) @@ -409,6 +445,20 @@ func (this *Profile) Upgrade(addDefaults bool) (upgraded *node.Profile) { wwlog.Error("unparsable SystemOverlay: %v", overlay) } } + if replaceOverlays { + if indexOf(upgraded.SystemOverlay, "wwinit") != -1 { + upgraded.SystemOverlay = replaceSliceElement( + upgraded.SystemOverlay, + indexOf(upgraded.SystemOverlay, "wwinit"), + wwinitSplitOverlays) + } + if indexOf(upgraded.RuntimeOverlay, "generic") != -1 { + upgraded.RuntimeOverlay = replaceSliceElement( + upgraded.RuntimeOverlay, + indexOf(upgraded.RuntimeOverlay, "generic"), + genericSplitOverlays) + } + } if this.Tags != nil { for key, value := range this.Tags { upgraded.Tags[key] = value diff --git a/internal/pkg/upgrade/node_test.go b/internal/pkg/upgrade/node_test.go index 4e1d99dd..cfd98117 100644 --- a/internal/pkg/upgrade/node_test.go +++ b/internal/pkg/upgrade/node_test.go @@ -8,14 +8,16 @@ import ( ) var nodesYamlUpgradeTests = []struct { - name string - addDefaults bool - legacyYaml string - upgradedYaml string + name string + addDefaults bool + replaceOverlays bool + legacyYaml string + upgradedYaml string }{ { - name: "captured vers42 example", - addDefaults: false, + name: "captured vers42 example", + addDefaults: false, + replaceOverlays: false, legacyYaml: ` nodeprofiles: default: @@ -69,8 +71,9 @@ nodes: `, }, { - name: "captured vers43 example", - addDefaults: false, + name: "captured vers43 example", + addDefaults: false, + replaceOverlays: false, legacyYaml: ` WW_INTERNAL: 45 nodeprofiles: @@ -135,17 +138,19 @@ nodes: `, }, { - name: "remove WW_INTERNAL", - addDefaults: false, - legacyYaml: `WW_INTERNAL: 45`, + name: "remove WW_INTERNAL", + addDefaults: false, + replaceOverlays: false, + legacyYaml: `WW_INTERNAL: 45`, upgradedYaml: ` nodeprofiles: {} nodes: {} `, }, { - name: "disabled is obsolete", - addDefaults: false, + name: "disabled is obsolete", + addDefaults: false, + replaceOverlays: false, legacyYaml: ` nodes: n1: @@ -162,8 +167,9 @@ nodes: `, }, { - name: "inline IPMI settings", - addDefaults: false, + name: "inline IPMI settings", + addDefaults: false, + replaceOverlays: false, legacyYaml: ` nodes: n1: @@ -216,8 +222,9 @@ nodes: `, }, { - name: "inline Kernel settings", - addDefaults: false, + name: "inline Kernel settings", + addDefaults: false, + replaceOverlays: false, legacyYaml: ` nodeprofiles: default: @@ -246,8 +253,9 @@ nodes: `, }, { - name: "keys and tags", - addDefaults: false, + name: "keys and tags", + addDefaults: false, + replaceOverlays: false, legacyYaml: ` nodeprofiles: default: @@ -336,8 +344,9 @@ nodes: `, }, { - name: "primary network", - addDefaults: false, + name: "primary network", + addDefaults: false, + replaceOverlays: false, legacyYaml: ` nodes: n1: @@ -392,8 +401,9 @@ nodes: `, }, { - name: "overlays", - addDefaults: false, + name: "overlays", + addDefaults: false, + replaceOverlays: false, legacyYaml: ` nodes: n1: @@ -452,8 +462,9 @@ nodes: `, }, { - name: "disk example", - addDefaults: false, + name: "disk example", + addDefaults: false, + replaceOverlays: false, legacyYaml: ` nodes: n1: @@ -499,8 +510,9 @@ nodes: `, }, { - name: "add defaults", - addDefaults: true, + name: "add defaults", + addDefaults: true, + replaceOverlays: false, legacyYaml: ` nodes: n1: @@ -547,8 +559,9 @@ nodes: `, }, { - name: "add defaults conflicts", - addDefaults: true, + name: "add defaults conflicts", + addDefaults: true, + replaceOverlays: false, legacyYaml: ` nodeprofiles: default: @@ -606,6 +619,69 @@ nodes: type: ethernet ipaddr: 10.0.0.100 netmask: 255.255.0.0 +`, + }, + { + name: "add defaults conflicts", + addDefaults: false, + replaceOverlays: true, + legacyYaml: ` +nodeprofiles: + default: + runtime overlay: + - generic + system overlay: + - wwinit +nodes: + n1: + runtime overlay: + - generic + system overlay: + - wwinit +`, + upgradedYaml: ` +nodeprofiles: + default: + runtime overlay: + - hosts + - ssh.authorized_keys + - syncuser + system overlay: + - wwinit + - wwclient + - fstab + - hostname + - ssh.host_keys + - issue + - resolv + - udev.netname + - systemd.netname + - ifcfg + - NetworkManager + - debian.interfaces + - wicked + - ignition +nodes: + n1: + runtime overlay: + - hosts + - ssh.authorized_keys + - syncuser + system overlay: + - wwinit + - wwclient + - fstab + - hostname + - ssh.host_keys + - issue + - resolv + - udev.netname + - systemd.netname + - ifcfg + - NetworkManager + - debian.interfaces + - wicked + - ignition `, }, } @@ -615,7 +691,7 @@ func Test_UpgradeNodesYaml(t *testing.T) { t.Run(tt.name, func(t *testing.T) { legacy, err := Parse([]byte(tt.legacyYaml)) assert.NoError(t, err) - upgraded := legacy.Upgrade(tt.addDefaults) + upgraded := legacy.Upgrade(tt.addDefaults, tt.replaceOverlays) upgradedYaml, err := upgraded.Dump() assert.NoError(t, err) assert.Equal(t, strings.TrimSpace(tt.upgradedYaml), strings.TrimSpace(string(upgradedYaml))) From 6a1abd52a59ad706058cad648908e787ced9475a Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Tue, 5 Nov 2024 13:24:41 -0700 Subject: [PATCH 15/19] Support printing upgraded nodes.conf Signed-off-by: Jonathon Anderson --- internal/app/wwctl/upgrade/cobra.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/internal/app/wwctl/upgrade/cobra.go b/internal/app/wwctl/upgrade/cobra.go index 87448452..c871c1f2 100644 --- a/internal/app/wwctl/upgrade/cobra.go +++ b/internal/app/wwctl/upgrade/cobra.go @@ -1,6 +1,7 @@ package upgrade import ( + "fmt" "os" "github.com/spf13/cobra" @@ -43,8 +44,17 @@ func UpgradeNodesConf(cmd *cobra.Command, args []string) error { return err } upgraded := legacy.Upgrade(addDefaults, replaceOverlays) - if err := util.CopyFile(outputPath, outputPath+"-old"); err != nil { - return err + if outputPath == "-" { + upgradedYaml, err := upgraded.Dump() + if err != nil { + return err + } + fmt.Print(string(upgradedYaml)) + return nil + } else { + if err := util.CopyFile(outputPath, outputPath+"-old"); err != nil { + return err + } + return upgraded.PersistToFile(outputPath) } - return upgraded.PersistToFile(outputPath) } From b37d49d6dee396597c4d59a6c78487267f19d211 Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Tue, 5 Nov 2024 15:58:43 -0700 Subject: [PATCH 16/19] Support upgrading warewulf.conf Signed-off-by: Jonathon Anderson --- internal/app/wwctl/upgrade/cobra.go | 51 +-- internal/app/wwctl/upgrade/config/cobra.go | 56 +++ internal/app/wwctl/upgrade/nodes/cobra.go | 60 +++ internal/pkg/config/buildconfig.go.in | 18 +- internal/pkg/config/dhcp.go | 4 +- internal/pkg/config/nfs.go | 10 +- internal/pkg/config/root.go | 45 ++- internal/pkg/config/ssh.go | 2 +- internal/pkg/config/wwclient.go | 2 +- internal/pkg/upgrade/conf.go | 91 ----- internal/pkg/upgrade/config.go | 237 ++++++++++++ internal/pkg/upgrade/config_test.go | 415 +++++++++++++++++++++ internal/pkg/upgrade/logging.go | 15 + internal/pkg/upgrade/node.go | 28 +- internal/pkg/upgrade/node_test.go | 2 +- internal/pkg/upgrade/slices.go | 17 + 16 files changed, 864 insertions(+), 189 deletions(-) create mode 100644 internal/app/wwctl/upgrade/config/cobra.go create mode 100644 internal/app/wwctl/upgrade/nodes/cobra.go delete mode 100644 internal/pkg/upgrade/conf.go create mode 100644 internal/pkg/upgrade/config.go create mode 100644 internal/pkg/upgrade/config_test.go create mode 100644 internal/pkg/upgrade/logging.go create mode 100644 internal/pkg/upgrade/slices.go diff --git a/internal/app/wwctl/upgrade/cobra.go b/internal/app/wwctl/upgrade/cobra.go index c871c1f2..88e1a611 100644 --- a/internal/app/wwctl/upgrade/cobra.go +++ b/internal/app/wwctl/upgrade/cobra.go @@ -1,60 +1,23 @@ package upgrade import ( - "fmt" - "os" - "github.com/spf13/cobra" - "github.com/warewulf/warewulf/internal/pkg/node" - libupgrade "github.com/warewulf/warewulf/internal/pkg/upgrade" - "github.com/warewulf/warewulf/internal/pkg/util" + "github.com/warewulf/warewulf/internal/app/wwctl/upgrade/config" + "github.com/warewulf/warewulf/internal/app/wwctl/upgrade/nodes" ) var ( Command = &cobra.Command{ DisableFlagsInUseLine: true, - Use: "upgrade [OPTIONS]", - Short: "Upgrade an existing nodes.conf", - Long: `Upgrades nodes.conf from a previous version of Warewulf 4 to a format + Use: "upgrade [OPTIONS]", + Short: "Upgrade configuration files", + Long: `Upgrade warewulf.conf or nodes.conf from a previous version of Warewulf 4 to a format supported by the current version.`, - RunE: UpgradeNodesConf, } - - addDefaults bool - replaceOverlays bool - inputPath string - outputPath string ) func init() { - Command.Flags().BoolVar(&addDefaults, "add-defaults", false, "Configure a default profile and set default node values") - Command.Flags().BoolVar(&replaceOverlays, "replace-overlays", false, "Replace 'wwinit' and 'generic' overlays with their split replacements") - Command.Flags().StringVarP(&inputPath, "input-path", "i", node.ConfigFile, "Path to a legacy nodes.conf") - Command.Flags().StringVarP(&outputPath, "output-path", "o", node.ConfigFile, "Path to write the upgraded nodes.conf to") -} - -func UpgradeNodesConf(cmd *cobra.Command, args []string) error { - data, err := os.ReadFile(inputPath) - if err != nil { - return err - } - legacy, err := libupgrade.Parse(data) - if err != nil { - return err - } - upgraded := legacy.Upgrade(addDefaults, replaceOverlays) - if outputPath == "-" { - upgradedYaml, err := upgraded.Dump() - if err != nil { - return err - } - fmt.Print(string(upgradedYaml)) - return nil - } else { - if err := util.CopyFile(outputPath, outputPath+"-old"); err != nil { - return err - } - return upgraded.PersistToFile(outputPath) - } + Command.AddCommand(config.Command) + Command.AddCommand(nodes.Command) } diff --git a/internal/app/wwctl/upgrade/config/cobra.go b/internal/app/wwctl/upgrade/config/cobra.go new file mode 100644 index 00000000..a660a32f --- /dev/null +++ b/internal/app/wwctl/upgrade/config/cobra.go @@ -0,0 +1,56 @@ +package config + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" + + "github.com/warewulf/warewulf/internal/pkg/config" + libupgrade "github.com/warewulf/warewulf/internal/pkg/upgrade" + "github.com/warewulf/warewulf/internal/pkg/util" +) + +var ( + Command = &cobra.Command{ + DisableFlagsInUseLine: true, + Use: "config [OPTIONS]", + Short: "Upgrade an existing nodes.conf", + Long: `Upgrades nodes.conf from a previous version of Warewulf 4 to a format +supported by the current version.`, + RunE: UpgradeNodesConf, + } + + inputPath string + outputPath string +) + +func init() { + Command.Flags().StringVarP(&inputPath, "input-path", "i", config.ConfigFile, "Path to a legacy nodes.conf") + Command.Flags().StringVarP(&outputPath, "output-path", "o", config.ConfigFile, "Path to write the upgraded nodes.conf to") +} + +func UpgradeNodesConf(cmd *cobra.Command, args []string) error { + data, err := os.ReadFile(inputPath) + if err != nil { + return err + } + legacy, err := libupgrade.ParseConfig(data) + if err != nil { + return err + } + upgraded := legacy.Upgrade() + if outputPath == "-" { + upgradedYaml, err := upgraded.Dump() + if err != nil { + return err + } + fmt.Print(string(upgradedYaml)) + return nil + } else { + if err := util.CopyFile(outputPath, outputPath+"-old"); err != nil { + return err + } + return upgraded.PersistToFile(outputPath) + } +} diff --git a/internal/app/wwctl/upgrade/nodes/cobra.go b/internal/app/wwctl/upgrade/nodes/cobra.go new file mode 100644 index 00000000..d138130a --- /dev/null +++ b/internal/app/wwctl/upgrade/nodes/cobra.go @@ -0,0 +1,60 @@ +package nodes + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" + + "github.com/warewulf/warewulf/internal/pkg/node" + libupgrade "github.com/warewulf/warewulf/internal/pkg/upgrade" + "github.com/warewulf/warewulf/internal/pkg/util" +) + +var ( + Command = &cobra.Command{ + DisableFlagsInUseLine: true, + Use: "nodes [OPTIONS]", + Short: "Upgrade an existing nodes.conf", + Long: `Upgrades nodes.conf from a previous version of Warewulf 4 to a format +supported by the current version.`, + RunE: UpgradeNodesConf, + } + + addDefaults bool + replaceOverlays bool + inputPath string + outputPath string +) + +func init() { + Command.Flags().BoolVar(&addDefaults, "add-defaults", false, "Configure a default profile and set default node values") + Command.Flags().BoolVar(&replaceOverlays, "replace-overlays", false, "Replace 'wwinit' and 'generic' overlays with their split replacements") + Command.Flags().StringVarP(&inputPath, "input-path", "i", node.ConfigFile, "Path to a legacy nodes.conf") + Command.Flags().StringVarP(&outputPath, "output-path", "o", node.ConfigFile, "Path to write the upgraded nodes.conf to") +} + +func UpgradeNodesConf(cmd *cobra.Command, args []string) error { + data, err := os.ReadFile(inputPath) + if err != nil { + return err + } + legacy, err := libupgrade.ParseNodes(data) + if err != nil { + return err + } + upgraded := legacy.Upgrade(addDefaults, replaceOverlays) + if outputPath == "-" { + upgradedYaml, err := upgraded.Dump() + if err != nil { + return err + } + fmt.Print(string(upgradedYaml)) + return nil + } else { + if err := util.CopyFile(outputPath, outputPath+"-old"); err != nil { + return err + } + return upgraded.PersistToFile(outputPath) + } +} diff --git a/internal/pkg/config/buildconfig.go.in b/internal/pkg/config/buildconfig.go.in index 767e254a..2ebc7de4 100644 --- a/internal/pkg/config/buildconfig.go.in +++ b/internal/pkg/config/buildconfig.go.in @@ -26,23 +26,23 @@ const Release = "@RELEASE@" type TFTPConf struct { Enabled bool `yaml:"enabled" default:"true"` - TftpRoot string `yaml:"tftproot" default:"@TFTPDIR@"` - SystemdName string `yaml:"systemd name" default:"tftp"` + TftpRoot string `yaml:"tftproot,omitempty" default:"@TFTPDIR@"` + SystemdName string `yaml:"systemd name,omitempty" default:"tftp"` - IpxeBinaries map[string]string `yaml:"ipxe" default:"{\"00:09\": \"ipxe-snponly-x86_64.efi\",\"00:00\": \"undionly.kpxe\",\"00:0B\": \"arm64-efi/snponly.efi\",\"00:07\": \"ipxe-snponly-x86_64.efi\"}"` + IpxeBinaries map[string]string `yaml:"ipxe,omitempty" default:"{\"00:09\": \"ipxe-snponly-x86_64.efi\",\"00:00\": \"undionly.kpxe\",\"00:0B\": \"arm64-efi/snponly.efi\",\"00:07\": \"ipxe-snponly-x86_64.efi\"}"` } // WarewulfConf adds additional Warewulf-specific configuration to // BaseConf. type WarewulfConf struct { - Port int `yaml:"port" default:"9873"` + Port int `yaml:"port,omitempty" default:"9873"` Secure bool `yaml:"secure" default:"true"` - UpdateInterval int `yaml:"update interval" default:"60"` - AutobuildOverlays bool `yaml:"autobuild overlays" default:"true"` + UpdateInterval int `yaml:"update interval,omitempty" default:"60"` + AutobuildOverlays bool `yaml:"autobuild overlays,omitempty" default:"true"` EnableHostOverlay bool `yaml:"host overlay" default:"true"` - Syslog bool `yaml:"syslog" default:"false"` - DataStore string `yaml:"datastore" default:"@DATADIR@"` - GrubBoot bool `yaml:"grubboot" default:"false"` + Syslog bool `yaml:"syslog,omitempty" default:"false"` + DataStore string `yaml:"datastore,omitempty" default:"@DATADIR@"` + GrubBoot bool `yaml:"grubboot,omitempty" default:"false"` } func (paths BuildConfig) OciBlobCachedir() string { diff --git a/internal/pkg/config/dhcp.go b/internal/pkg/config/dhcp.go index b1b8790e..f496f431 100644 --- a/internal/pkg/config/dhcp.go +++ b/internal/pkg/config/dhcp.go @@ -4,8 +4,8 @@ package config // Warewulf will configure. type DHCPConf struct { Enabled bool `yaml:"enabled" default:"true"` - Template string `yaml:"template" default:"default"` + Template string `yaml:"template,omitempty" default:"default"` RangeStart string `yaml:"range start,omitempty"` RangeEnd string `yaml:"range end,omitempty"` - SystemdName string `yaml:"systemd name" default:"dhcpd"` + SystemdName string `yaml:"systemd name,omitempty" default:"dhcpd"` } diff --git a/internal/pkg/config/nfs.go b/internal/pkg/config/nfs.go index c7ad986e..baaf411d 100644 --- a/internal/pkg/config/nfs.go +++ b/internal/pkg/config/nfs.go @@ -9,16 +9,16 @@ import ( // nodes. type NFSConf struct { Enabled bool `yaml:"enabled" default:"true"` - ExportsExtended []*NFSExportConf `yaml:"export paths" default:"[]"` - SystemdName string `yaml:"systemd name" default:"nfsd"` + ExportsExtended []*NFSExportConf `yaml:"export paths,omitempty" default:"[]"` + SystemdName string `yaml:"systemd name,omitempty" default:"nfsd"` } // An NFSExportConf reprents a single NFS export / mount. type NFSExportConf struct { Path string `yaml:"path" default:"/dev/null"` - ExportOptions string `default:"rw,sync,no_subtree_check" yaml:"export options"` - MountOptions string `default:"defaults" yaml:"mount options"` - Mount bool `default:"true" yaml:"mount"` + ExportOptions string `yaml:"export options,omitempty" default:"rw,sync,no_subtree_check"` + MountOptions string `yaml:"mount options,omitempty" default:"defaults"` + Mount bool `yaml:"mount" default:"true"` } // Implements the Unmarshal interface for NFSConf to set default diff --git a/internal/pkg/config/root.go b/internal/pkg/config/root.go index 8c223707..b8ca89f0 100644 --- a/internal/pkg/config/root.go +++ b/internal/pkg/config/root.go @@ -7,6 +7,7 @@ package config import ( + "bytes" "fmt" "net" "net/netip" @@ -27,19 +28,19 @@ var cachedConf WarewulfYaml // [WarewulfConf], [DHCPConf], [TFTPConf], and [NFSConf] sub-sections. type WarewulfYaml struct { Comment string `yaml:"comment,omitempty"` - Ipaddr string `yaml:"ipaddr"` + Ipaddr string `yaml:"ipaddr,omitempty"` Ipaddr6 string `yaml:"ipaddr6,omitempty"` - Netmask string `yaml:"netmask"` + Netmask string `yaml:"netmask,omitempty"` Network string `yaml:"network,omitempty"` Ipv6net string `yaml:"ipv6net,omitempty"` Fqdn string `yaml:"fqdn,omitempty"` - Warewulf *WarewulfConf `yaml:"warewulf"` - DHCP *DHCPConf `yaml:"dhcp"` - TFTP *TFTPConf `yaml:"tftp"` - NFS *NFSConf `yaml:"nfs"` + Warewulf *WarewulfConf `yaml:"warewulf,omitempty"` + DHCP *DHCPConf `yaml:"dhcp,omitempty"` + TFTP *TFTPConf `yaml:"tftp,omitempty"` + NFS *NFSConf `yaml:"nfs,omitempty"` SSH *SSHConf `yaml:"ssh,omitempty"` - MountsContainer []*MountEntry `yaml:"container mounts" default:"[{\"source\": \"/etc/resolv.conf\", \"dest\": \"/etc/resolv.conf\"}]"` - Paths *BuildConfig `yaml:"paths"` + MountsContainer []*MountEntry `yaml:"container mounts,omitempty" default:"[{\"source\": \"/etc/resolv.conf\", \"dest\": \"/etc/resolv.conf\"}]"` + Paths *BuildConfig `yaml:"paths,omitempty"` WWClient *WWClientConf `yaml:"wwclient,omitempty"` warewulfconf string @@ -206,3 +207,31 @@ func (conf *WarewulfYaml) InitializedFromFile() bool { func (conf *WarewulfYaml) GetWarewulfConf() string { return conf.warewulfconf } + +func (config *WarewulfYaml) Dump() ([]byte, error) { + var buf bytes.Buffer + yamlEncoder := yaml.NewEncoder(&buf) + yamlEncoder.SetIndent(2) + err := yamlEncoder.Encode(config) + return buf.Bytes(), err +} + +func (config *WarewulfYaml) PersistToFile(configFile string) error { + out, dumpErr := config.Dump() + if dumpErr != nil { + wwlog.Error("%s", dumpErr) + return dumpErr + } + file, err := os.OpenFile(configFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o644) + if err != nil { + wwlog.Error("%s", err) + return err + } + defer file.Close() + _, err = file.WriteString(string(out)) + if err != nil { + return err + } + wwlog.Debug("persisted: %s", configFile) + return nil +} diff --git a/internal/pkg/config/ssh.go b/internal/pkg/config/ssh.go index a9abe4dc..5e08aac7 100644 --- a/internal/pkg/config/ssh.go +++ b/internal/pkg/config/ssh.go @@ -1,5 +1,5 @@ package config type SSHConf struct { - KeyTypes []string `yaml:"key types" default:"[\"rsa\",\"dsa\",\"ecdsa\",\"ed25519\"]"` + KeyTypes []string `yaml:"key types,omitempty" default:"[\"rsa\",\"dsa\",\"ecdsa\",\"ed25519\"]"` } diff --git a/internal/pkg/config/wwclient.go b/internal/pkg/config/wwclient.go index 13993be6..52d92d04 100644 --- a/internal/pkg/config/wwclient.go +++ b/internal/pkg/config/wwclient.go @@ -1,5 +1,5 @@ package config type WWClientConf struct { - Port uint16 `yaml:"port" default:"0"` + Port uint16 `yaml:"port,omitempty" default:"0"` } diff --git a/internal/pkg/upgrade/conf.go b/internal/pkg/upgrade/conf.go deleted file mode 100644 index ddba7018..00000000 --- a/internal/pkg/upgrade/conf.go +++ /dev/null @@ -1,91 +0,0 @@ -package upgrade - -type WarewulfYaml struct { - WWInternal string `yaml:"WW_INTERNAL"` - Comment string `yaml:"comment,omitempty"` - Ipaddr string `yaml:"ipaddr"` - Ipaddr6 string `yaml:"ipaddr6,omitempty"` - Netmask string `yaml:"netmask"` - Network string `yaml:"network,omitempty"` - Ipv6net string `yaml:"ipv6net,omitempty"` - Fqdn string `yaml:"fqdn,omitempty"` - Warewulf *WarewulfConf `yaml:"warewulf"` - DHCP *DHCPConf `yaml:"dhcp"` - TFTP *TFTPConf `yaml:"tftp"` - NFS *NFSConf `yaml:"nfs"` - SSH *SSHConf `yaml:"ssh,omitempty"` - MountsContainer []*MountEntry `yaml:"container mounts"` - Paths *BuildConfig `yaml:"paths"` - WWClient *WWClientConf `yaml:"wwclient"` -} - -type WarewulfConf struct { - Port int `yaml:"port"` - Secure bool `yaml:"secure"` - UpdateInterval int `yaml:"update interval"` - AutobuildOverlays bool `yaml:"autobuild overlays"` - EnableHostOverlay bool `yaml:"host overlay"` - Syslog bool `yaml:"syslog"` - DataStore string `yaml:"datastore"` - GrubBoot bool `yaml:"grubboot"` -} - -type DHCPConf struct { - Enabled bool `yaml:"enabled"` - Template string `yaml:"template"` - RangeStart string `yaml:"range start,omitempty"` - RangeEnd string `yaml:"range end,omitempty"` - SystemdName string `yaml:"systemd name"` -} - -type TFTPConf struct { - Enabled bool `yaml:"enabled"` - TftpRoot string `yaml:"tftproot"` - SystemdName string `yaml:"systemd name"` - - IpxeBinaries map[string]string `yaml:"ipxe"` -} - -type NFSConf struct { - Enabled bool `yaml:"enabled"` - ExportsExtended []*NFSExportConf `yaml:"export paths"` - SystemdName string `yaml:"systemd name"` -} - -type NFSExportConf struct { - Path string `yaml:"path"` - ExportOptions string `yaml:"export options"` - MountOptions string `yaml:"mount options"` - Mount bool `yaml:"mount"` -} - -type SSHConf struct { - KeyTypes []string `yaml:"key types"` -} - -type MountEntry struct { - Source string `yaml:"source"` - Dest string `yaml:"dest,omitempty"` - ReadOnly bool `yaml:"readonly,omitempty"` - Options string `yaml:"options,omitempty"` - Copy bool `yaml:"copy,omitempty"` -} - -type BuildConfig struct { - Bindir string - Sysconfdir string - Localstatedir string - Cachedir string - Ipxesource string - Srvdir string - Firewallddir string - Systemddir string - WWOverlaydir string - WWChrootdir string - WWProvisiondir string - WWClientdir string -} - -type WWClientConf struct { - Port uint16 `yaml:"port"` -} diff --git a/internal/pkg/upgrade/config.go b/internal/pkg/upgrade/config.go new file mode 100644 index 00000000..10476efe --- /dev/null +++ b/internal/pkg/upgrade/config.go @@ -0,0 +1,237 @@ +package upgrade + +import ( + "gopkg.in/yaml.v3" + + "github.com/warewulf/warewulf/internal/pkg/config" +) + +func ParseConfig(data []byte) (warewulfYaml *WarewulfYaml, err error) { + warewulfYaml = new(WarewulfYaml) + if err = yaml.Unmarshal(data, warewulfYaml); err != nil { + return warewulfYaml, err + } + return warewulfYaml, nil +} + +type WarewulfYaml struct { + WWInternal string `yaml:"WW_INTERNAL"` + Comment string `yaml:"comment"` + Ipaddr string `yaml:"ipaddr"` + Ipaddr6 string `yaml:"ipaddr6"` + Netmask string `yaml:"netmask"` + Network string `yaml:"network"` + Ipv6net string `yaml:"ipv6net"` + Fqdn string `yaml:"fqdn"` + Warewulf *WarewulfConf `yaml:"warewulf"` + DHCP *DHCPConf `yaml:"dhcp"` + TFTP *TFTPConf `yaml:"tftp"` + NFS *NFSConf `yaml:"nfs"` + SSH *SSHConf `yaml:"ssh"` + MountsContainer []*MountEntry `yaml:"container mounts"` + Paths *BuildConfig `yaml:"paths"` + WWClient *WWClientConf `yaml:"wwclient"` +} + +func (this *WarewulfYaml) Upgrade() (upgraded *config.WarewulfYaml) { + upgraded = new(config.WarewulfYaml) + if this.WWInternal != "" { + logIgnore("WW_INTERNAL", this.WWInternal, "obsolete") + } + upgraded.Comment = this.Comment + upgraded.Ipaddr = this.Ipaddr + upgraded.Ipaddr6 = this.Ipaddr6 + upgraded.Netmask = this.Netmask + upgraded.Network = this.Network + upgraded.Ipv6net = this.Ipv6net + upgraded.Fqdn = this.Fqdn + if this.Warewulf != nil { + upgraded.Warewulf = this.Warewulf.Upgrade() + } + if this.DHCP != nil { + upgraded.DHCP = this.DHCP.Upgrade() + } + if this.TFTP != nil { + upgraded.TFTP = this.TFTP.Upgrade() + } + if this.NFS != nil { + upgraded.NFS = this.NFS.Upgrade() + } + if this.SSH != nil { + upgraded.SSH = this.SSH.Upgrade() + } + upgraded.MountsContainer = make([]*config.MountEntry, 0) + for _, mount := range this.MountsContainer { + upgraded.MountsContainer = append(upgraded.MountsContainer, mount.Upgrade()) + } + if this.Paths != nil { + upgraded.Paths = this.Paths.Upgrade() + } + if this.WWClient != nil { + upgraded.WWClient = this.WWClient.Upgrade() + } + return upgraded +} + +type WarewulfConf struct { + Port int `yaml:"port"` + Secure bool `yaml:"secure"` + UpdateInterval int `yaml:"update interval"` + AutobuildOverlays bool `yaml:"autobuild overlays"` + EnableHostOverlay bool `yaml:"host overlay"` + Syslog bool `yaml:"syslog"` + DataStore string `yaml:"datastore"` + GrubBoot bool `yaml:"grubboot"` +} + +func (this *WarewulfConf) Upgrade() (upgraded *config.WarewulfConf) { + upgraded = new(config.WarewulfConf) + upgraded.Port = this.Port + upgraded.Secure = this.Secure + upgraded.UpdateInterval = this.UpdateInterval + upgraded.AutobuildOverlays = this.AutobuildOverlays + upgraded.EnableHostOverlay = this.EnableHostOverlay + upgraded.Syslog = this.Syslog + upgraded.DataStore = this.DataStore + upgraded.GrubBoot = this.GrubBoot + return upgraded +} + +type DHCPConf struct { + Enabled bool `yaml:"enabled"` + Template string `yaml:"template"` + RangeStart string `yaml:"range start"` + RangeEnd string `yaml:"range end"` + SystemdName string `yaml:"systemd name"` +} + +func (this *DHCPConf) Upgrade() (upgraded *config.DHCPConf) { + upgraded = new(config.DHCPConf) + upgraded.Enabled = this.Enabled + upgraded.Template = this.Template + upgraded.RangeStart = this.RangeStart + upgraded.RangeEnd = this.RangeEnd + upgraded.SystemdName = this.SystemdName + return upgraded +} + +type TFTPConf struct { + Enabled bool `yaml:"enabled"` + TftpRoot string `yaml:"tftproot"` + SystemdName string `yaml:"systemd name"` + IpxeBinaries map[string]string `yaml:"ipxe"` +} + +func (this *TFTPConf) Upgrade() (upgraded *config.TFTPConf) { + upgraded = new(config.TFTPConf) + upgraded.Enabled = this.Enabled + upgraded.TftpRoot = this.TftpRoot + upgraded.SystemdName = this.SystemdName + upgraded.IpxeBinaries = make(map[string]string) + for name, binary := range this.IpxeBinaries { + upgraded.IpxeBinaries[name] = binary + } + return upgraded +} + +type NFSConf struct { + Enabled bool `yaml:"enabled"` + ExportsExtended []*NFSExportConf `yaml:"export paths"` + SystemdName string `yaml:"systemd name"` +} + +func (this *NFSConf) Upgrade() (upgraded *config.NFSConf) { + upgraded = new(config.NFSConf) + upgraded.Enabled = this.Enabled + upgraded.ExportsExtended = make([]*config.NFSExportConf, 0) + for _, export := range this.ExportsExtended { + upgraded.ExportsExtended = append(upgraded.ExportsExtended, export.Upgrade()) + } + upgraded.SystemdName = this.SystemdName + return upgraded +} + +type NFSExportConf struct { + Path string `yaml:"path"` + ExportOptions string `yaml:"export options"` + MountOptions string `yaml:"mount options"` + Mount bool `yaml:"mount"` +} + +func (this *NFSExportConf) Upgrade() (upgraded *config.NFSExportConf) { + upgraded = new(config.NFSExportConf) + upgraded.Path = this.Path + upgraded.ExportOptions = this.ExportOptions + upgraded.MountOptions = this.MountOptions + upgraded.Mount = this.Mount + return upgraded +} + +type SSHConf struct { + KeyTypes []string `yaml:"key types"` +} + +func (this *SSHConf) Upgrade() (upgraded *config.SSHConf) { + upgraded = new(config.SSHConf) + upgraded.KeyTypes = append([]string{}, this.KeyTypes...) + return upgraded +} + +type MountEntry struct { + Source string `yaml:"source"` + Dest string `yaml:"dest"` + ReadOnly bool `yaml:"readonly"` + Options string `yaml:"options"` + Copy bool `yaml:"copy"` +} + +func (this *MountEntry) Upgrade() (upgraded *config.MountEntry) { + upgraded = new(config.MountEntry) + upgraded.Source = this.Source + upgraded.Dest = this.Dest + upgraded.ReadOnly = this.ReadOnly + upgraded.Options = this.Options + upgraded.Copy = this.Copy + return upgraded +} + +type BuildConfig struct { + Bindir string + Sysconfdir string + Localstatedir string + Cachedir string + Ipxesource string + Srvdir string + Firewallddir string + Systemddir string + WWOverlaydir string + WWChrootdir string + WWProvisiondir string + WWClientdir string +} + +func (this *BuildConfig) Upgrade() (upgraded *config.BuildConfig) { + upgraded = new(config.BuildConfig) + upgraded.Bindir = this.Bindir + upgraded.Sysconfdir = this.Sysconfdir + upgraded.Localstatedir = this.Localstatedir + upgraded.Cachedir = this.Cachedir + upgraded.Ipxesource = this.Ipxesource + upgraded.Srvdir = this.Srvdir + upgraded.Firewallddir = this.Firewallddir + upgraded.WWOverlaydir = this.WWOverlaydir + upgraded.WWChrootdir = this.WWChrootdir + upgraded.WWProvisiondir = this.WWProvisiondir + upgraded.WWClientdir = this.WWClientdir + return upgraded +} + +type WWClientConf struct { + Port uint16 `yaml:"port"` +} + +func (this *WWClientConf) Upgrade() (upgraded *config.WWClientConf) { + upgraded = new(config.WWClientConf) + upgraded.Port = this.Port + return upgraded +} diff --git a/internal/pkg/upgrade/config_test.go b/internal/pkg/upgrade/config_test.go new file mode 100644 index 00000000..50cf474b --- /dev/null +++ b/internal/pkg/upgrade/config_test.go @@ -0,0 +1,415 @@ +package upgrade + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +var configUpgradeTests = []struct { + name string + legacyYaml string + upgradedYaml string +}{ + { + name: "empty", + legacyYaml: ``, + upgradedYaml: `{}`, + }, + { + name: "v4.0.0", + legacyYaml: ` +ipaddr: 192.168.1.1 +netmask: 255.255.255.0 +warewulf: + port: 9873 + secure: true + update interval: 60 +dhcp: + enabled: true + range start: 192.168.1.150 + range end: 192.168.1.200 + template: default + systemd name: dhcpd +tftp: + enabled: true + tftproot: /var/lib/tftpboot + systemd name: tftp +nfs: + systemd name: nfs-server + exports: + - /home + - /var/warewulf +`, + upgradedYaml: ` +ipaddr: 192.168.1.1 +netmask: 255.255.255.0 +warewulf: + port: 9873 + secure: true + update interval: 60 + host overlay: false +dhcp: + enabled: true + template: default + range start: 192.168.1.150 + range end: 192.168.1.200 + systemd name: dhcpd +tftp: + enabled: true + tftproot: /var/lib/tftpboot + systemd name: tftp +nfs: + enabled: false + systemd name: nfs-server +`, + }, + { + name: "v4.1.0", + legacyYaml: ` +ipaddr: 192.168.1.1 +netmask: 255.255.255.0 +warewulf: + port: 9873 + secure: true + update interval: 60 +dhcp: + enabled: true + range start: 192.168.1.150 + range end: 192.168.1.200 + template: default + systemd name: dhcpd +tftp: + enabled: true + tftproot: /var/lib/tftpboot + systemd name: tftp +nfs: + systemd name: nfs-server + exports: + - /home + - /var/warewulf +`, + upgradedYaml: ` +ipaddr: 192.168.1.1 +netmask: 255.255.255.0 +warewulf: + port: 9873 + secure: true + update interval: 60 + host overlay: false +dhcp: + enabled: true + template: default + range start: 192.168.1.150 + range end: 192.168.1.200 + systemd name: dhcpd +tftp: + enabled: true + tftproot: /var/lib/tftpboot + systemd name: tftp +nfs: + enabled: false + systemd name: nfs-server +`, + }, + { + name: "v4.2.0", + legacyYaml: ` +ipaddr: 192.168.200.1 +netmask: 255.255.255.0 +warewulf: + port: 9873 + secure: true + autobuild overlays: true + update interval: 60 + syslog: false +dhcp: + enabled: true + range start: 192.168.200.50 + range end: 192.168.200.99 + template: default + systemd name: dhcpd +tftp: + enabled: true + tftproot: /var/lib/tftpboot + systemd name: tftp +nfs: + systemd name: nfs-server + exports: + - /home + - /var/warewulf +`, + upgradedYaml: ` +ipaddr: 192.168.200.1 +netmask: 255.255.255.0 +warewulf: + port: 9873 + secure: true + update interval: 60 + autobuild overlays: true + host overlay: false +dhcp: + enabled: true + template: default + range start: 192.168.200.50 + range end: 192.168.200.99 + systemd name: dhcpd +tftp: + enabled: true + tftproot: /var/lib/tftpboot + systemd name: tftp +nfs: + enabled: false + systemd name: nfs-server +`, + }, + { + name: "v4.3.0", + legacyYaml: ` +WW_INTERNAL: 43 +ipaddr: 192.168.200.1 +netmask: 255.255.255.0 +network: 192.168.200.0 +warewulf: + port: 9873 + secure: false + update interval: 60 + autobuild overlays: true + host overlay: true + syslog: false + datastore: "" +dhcp: + enabled: true + template: default + range start: 192.168.200.50 + range end: 192.168.200.99 + systemd name: dhcpd +tftp: + enabled: true + tftproot: "" + systemd name: tftp +nfs: + enabled: true + export paths: + - path: /home + export options: rw,sync + mount options: defaults + mount: true + - path: /opt + export options: ro,sync,no_root_squash + mount options: defaults + mount: false + systemd name: nfs-server +`, + upgradedYaml: ` +ipaddr: 192.168.200.1 +netmask: 255.255.255.0 +network: 192.168.200.0 +warewulf: + port: 9873 + secure: false + update interval: 60 + autobuild overlays: true + host overlay: true +dhcp: + enabled: true + template: default + range start: 192.168.200.50 + range end: 192.168.200.99 + systemd name: dhcpd +tftp: + enabled: true + systemd name: tftp +nfs: + enabled: true + export paths: + - path: /home + export options: rw,sync + mount options: defaults + mount: true + - path: /opt + export options: ro,sync,no_root_squash + mount options: defaults + mount: false + systemd name: nfs-server +`, + }, + { + name: "v4.4.1", + legacyYaml: ` +WW_INTERNAL: 43 +ipaddr: 192.168.200.1 +netmask: 255.255.255.0 +network: 192.168.200.0 +warewulf: + port: 9873 + secure: false + update interval: 60 + autobuild overlays: true + host overlay: true + syslog: false +dhcp: + enabled: true + range start: 192.168.200.50 + range end: 192.168.200.99 + systemd name: dhcpd +tftp: + enabled: true + systemd name: tftp +nfs: + enabled: true + export paths: + - path: /home + export options: rw,sync + mount options: defaults + mount: true + - path: /opt + export options: ro,sync,no_root_squash + mount options: defaults + mount: false + systemd name: nfs-server +`, + upgradedYaml: ` +ipaddr: 192.168.200.1 +netmask: 255.255.255.0 +network: 192.168.200.0 +warewulf: + port: 9873 + secure: false + update interval: 60 + autobuild overlays: true + host overlay: true +dhcp: + enabled: true + range start: 192.168.200.50 + range end: 192.168.200.99 + systemd name: dhcpd +tftp: + enabled: true + systemd name: tftp +nfs: + enabled: true + export paths: + - path: /home + export options: rw,sync + mount options: defaults + mount: true + - path: /opt + export options: ro,sync,no_root_squash + mount options: defaults + mount: false + systemd name: nfs-server +`, + }, + { + name: "v4.5.8", + legacyYaml: ` +WW_INTERNAL: 45 +ipaddr: 10.0.0.1 +netmask: 255.255.252.0 +network: 10.0.0.0 +warewulf: + port: 9873 + secure: false + update interval: 60 + autobuild overlays: true + host overlay: true + syslog: false +dhcp: + enabled: true + range start: 10.0.1.1 + range end: 10.0.1.255 + systemd name: dhcpd +tftp: + enabled: true + systemd name: tftp + ipxe: + 00:09: ipxe-snponly-x86_64.efi + 00:00: undionly.kpxe + 00:0B: arm64-efi/snponly.efi + 00:07: ipxe-snponly-x86_64.efi +nfs: + enabled: true + export paths: + - path: /home + export options: rw,sync + mount options: defaults + mount: true + - path: /opt + export options: ro,sync,no_root_squash + mount options: defaults + mount: false + systemd name: nfs-server +container mounts: + - source: /etc/resolv.conf + dest: /etc/resolv.conf + readonly: true +ssh: + key types: + - rsa + - dsa + - ecdsa + - ed25519 +`, + upgradedYaml: ` +ipaddr: 10.0.0.1 +netmask: 255.255.252.0 +network: 10.0.0.0 +warewulf: + port: 9873 + secure: false + update interval: 60 + autobuild overlays: true + host overlay: true +dhcp: + enabled: true + range start: 10.0.1.1 + range end: 10.0.1.255 + systemd name: dhcpd +tftp: + enabled: true + systemd name: tftp + ipxe: + 00:0B: arm64-efi/snponly.efi + "00:00": undionly.kpxe + "00:07": ipxe-snponly-x86_64.efi + "00:09": ipxe-snponly-x86_64.efi +nfs: + enabled: true + export paths: + - path: /home + export options: rw,sync + mount options: defaults + mount: true + - path: /opt + export options: ro,sync,no_root_squash + mount options: defaults + mount: false + systemd name: nfs-server +ssh: + key types: + - rsa + - dsa + - ecdsa + - ed25519 +container mounts: + - source: /etc/resolv.conf + dest: /etc/resolv.conf + readonly: true +`, + }, +} + +func Test_UpgradeConfig(t *testing.T) { + for _, tt := range configUpgradeTests { + t.Run(tt.name, func(t *testing.T) { + legacy, err := ParseConfig([]byte(tt.legacyYaml)) + assert.NoError(t, err) + upgraded := legacy.Upgrade() + upgradedYaml, err := upgraded.Dump() + assert.NoError(t, err) + assert.Equal(t, strings.TrimSpace(tt.upgradedYaml), strings.TrimSpace(string(upgradedYaml))) + }) + } +} diff --git a/internal/pkg/upgrade/logging.go b/internal/pkg/upgrade/logging.go new file mode 100644 index 00000000..68b1e01d --- /dev/null +++ b/internal/pkg/upgrade/logging.go @@ -0,0 +1,15 @@ +package upgrade + +import ( + "github.com/warewulf/warewulf/internal/pkg/wwlog" +) + +func logIgnore(name string, value interface{}, reason string) { + wwlog.Warn("ignore: %s: %v (%s)", name, value, reason) +} + +func warnError(err error) { + if err != nil { + wwlog.Warn("%s", err) + } +} diff --git a/internal/pkg/upgrade/node.go b/internal/pkg/upgrade/node.go index f237da48..d02e1a5f 100644 --- a/internal/pkg/upgrade/node.go +++ b/internal/pkg/upgrade/node.go @@ -35,33 +35,7 @@ var genericSplitOverlays = []string{ "syncuser", } -func indexOf[T comparable](slice []T, item T) int { - for i, v := range slice { - if v == item { - return i - } - } - return -1 -} - -func replaceSliceElement[T any](original []T, index int, replacement []T) []T { - if index < 0 || index >= len(original) { - return original - } - return append(original[:index], append(replacement, original[index+1:]...)...) -} - -func logIgnore(name string, value interface{}, reason string) { - wwlog.Warn("ignore: %s: %v (%s)", name, value, reason) -} - -func warnError(err error) { - if err != nil { - wwlog.Warn("%s", err) - } -} - -func Parse(data []byte) (nodesYaml *NodesYaml, err error) { +func ParseNodes(data []byte) (nodesYaml *NodesYaml, err error) { nodesYaml = new(NodesYaml) if err = yaml.Unmarshal(data, nodesYaml); err != nil { return nodesYaml, err diff --git a/internal/pkg/upgrade/node_test.go b/internal/pkg/upgrade/node_test.go index cfd98117..1f28f563 100644 --- a/internal/pkg/upgrade/node_test.go +++ b/internal/pkg/upgrade/node_test.go @@ -689,7 +689,7 @@ nodes: func Test_UpgradeNodesYaml(t *testing.T) { for _, tt := range nodesYamlUpgradeTests { t.Run(tt.name, func(t *testing.T) { - legacy, err := Parse([]byte(tt.legacyYaml)) + legacy, err := ParseNodes([]byte(tt.legacyYaml)) assert.NoError(t, err) upgraded := legacy.Upgrade(tt.addDefaults, tt.replaceOverlays) upgradedYaml, err := upgraded.Dump() diff --git a/internal/pkg/upgrade/slices.go b/internal/pkg/upgrade/slices.go new file mode 100644 index 00000000..780350d3 --- /dev/null +++ b/internal/pkg/upgrade/slices.go @@ -0,0 +1,17 @@ +package upgrade + +func indexOf[T comparable](slice []T, item T) int { + for i, v := range slice { + if v == item { + return i + } + } + return -1 +} + +func replaceSliceElement[T any](original []T, index int, replacement []T) []T { + if index < 0 || index >= len(original) { + return original + } + return append(original[:index], append(replacement, original[index+1:]...)...) +} From 2bae87e244c093604574a451d0832f68e7a00f65 Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Tue, 5 Nov 2024 16:05:28 -0700 Subject: [PATCH 17/19] Documentation for wwctl upgrade Signed-off-by: Jonathon Anderson --- CHANGELOG.md | 1 + userdocs/contents/configuration.rst | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a5ff074c..3e8628cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Read environment variables from `/etc/default/warewulfd` #725 - Add support for VLANs to NetworkManager, wicked, ifcfg, debian.network_interfaces overlays. #1257 - Add support for static routes to NetworkManager, wicked, ifcfg, debian.network_interfaces overlays. #1257 +- Add `wwctl upgrade `. #230, #517 ### Changed diff --git a/userdocs/contents/configuration.rst b/userdocs/contents/configuration.rst index 9c0bee4b..13309244 100644 --- a/userdocs/contents/configuration.rst +++ b/userdocs/contents/configuration.rst @@ -201,6 +201,26 @@ command. This also goes for ``warewulf.conf`` as well - any changes made also require ``warewulfd`` to be restarted. The restart should be done using the following command: ``systemctl restart warewulfd`` +Upgrades +======== + +New versions of Warewulf might introduce changes to ``warewulf.conf`` and ``nodes.conf``. +The ``wwctl upgrade`` command can help ease the transition between versions. + +.. note:: + + ``wwctl upgrade`` will back up any files before it changes them (to ``-old``) + but it is good practice to back up your configuration manually. + +.. code-block:: console + + # wwctl upgrade config + # wwctl upgrade nodes --add-defaults --replace-overlays + +Both upgrade commands support specifying ``--output-path=-`` +to print the upgraded configuration file to standard out +for inspection before replacing the configuration files. + Directories =========== From e80c639b11bf4cef80db3149d0a0598f31f26a25 Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Wed, 6 Nov 2024 14:49:23 -0700 Subject: [PATCH 18/19] Convert config to *bool Supports leaving booleans unspecified in YAML. Boolean methods allow the templates to continue using previous names for boolean values. Signed-off-by: Jonathon Anderson --- internal/app/wwclient/root.go | 2 +- .../app/wwctl/container/exec/child/main.go | 6 +-- internal/app/wwctl/container/exec/main.go | 2 +- internal/app/wwctl/overlay/build/main.go | 2 +- internal/pkg/config/buildconfig.go.in | 44 ++++++++++++---- internal/pkg/config/dhcp.go | 10 +++- internal/pkg/config/mounts.go | 22 ++++++-- internal/pkg/config/nfs.go | 14 +++++- internal/pkg/config/root.go | 1 - internal/pkg/config/root_test.go | 36 ++++++------- internal/pkg/configure/dhcp.go | 4 +- internal/pkg/configure/nfs.go | 4 +- internal/pkg/configure/tftp.go | 4 +- internal/pkg/container/mountpoints.go | 8 +-- internal/pkg/upgrade/config.go | 50 +++++++++++-------- internal/pkg/upgrade/config_test.go | 19 ++++--- internal/pkg/util/util.go | 4 ++ internal/pkg/warewulfd/daemon.go | 2 +- internal/pkg/warewulfd/provision.go | 4 +- internal/pkg/warewulfd/provision_test.go | 3 +- 20 files changed, 157 insertions(+), 84 deletions(-) diff --git a/internal/app/wwclient/root.go b/internal/app/wwclient/root.go index 3e1fa799..8034deb2 100644 --- a/internal/app/wwclient/root.go +++ b/internal/app/wwclient/root.go @@ -102,7 +102,7 @@ func CobraRunE(cmd *cobra.Command, args []string) (err error) { if conf.WWClient != nil && conf.WWClient.Port > 0 { localTCPAddr.Port = int(conf.WWClient.Port) wwlog.Info("Running from configured port %d", conf.WWClient.Port) - } else if conf.Warewulf.Secure { + } else if conf.Warewulf.Secure() { // Setup local port to something privileged (<1024) localTCPAddr.Port = 987 wwlog.Info("Running from trusted port") diff --git a/internal/app/wwctl/container/exec/child/main.go b/internal/app/wwctl/container/exec/child/main.go index 9e9c064f..455ef9f9 100644 --- a/internal/app/wwctl/container/exec/child/main.go +++ b/internal/app/wwctl/container/exec/child/main.go @@ -134,14 +134,14 @@ func CobraRunE(cmd *cobra.Command, args []string) (err error) { } for _, mntPnt := range mountPts { - if mntPnt.Copy { + if mntPnt.Copy() { continue } wwlog.Debug("bind mounting: %s -> %s", mntPnt.Source, path.Join(containerPath, mntPnt.Dest)) err = syscall.Mount(mntPnt.Source, path.Join(containerPath, mntPnt.Dest), "", syscall.MS_BIND, "") if err != nil { wwlog.Warn("Couldn't mount %s to %s: %s", mntPnt.Source, mntPnt.Dest, err) - } else if mntPnt.ReadOnly { + } else if mntPnt.ReadOnly() { err = syscall.Mount(mntPnt.Source, path.Join(containerPath, mntPnt.Dest), "", syscall.MS_REMOUNT|syscall.MS_RDONLY|syscall.MS_BIND, "") if err != nil { wwlog.Warn("failed to following mount readonly: %s", mntPnt.Source) @@ -191,7 +191,7 @@ the invalid mount points. Directories always have '/' as suffix func checkMountPoints(containerName string, binds []*warewulfconf.MountEntry) (overlayObjects []string) { overlayObjects = []string{} for _, b := range binds { - if b.Copy { + if b.Copy() { continue } _, err := os.Stat(b.Source) diff --git a/internal/app/wwctl/container/exec/main.go b/internal/app/wwctl/container/exec/main.go index 195775e4..a087338c 100644 --- a/internal/app/wwctl/container/exec/main.go +++ b/internal/app/wwctl/container/exec/main.go @@ -229,7 +229,7 @@ Check the objects we want to copy in, instead of mounting */ func getCopyFiles(binds []*warewulfconf.MountEntry) (copyObjects []*copyFile) { for _, bind := range binds { - if bind.Copy { + if bind.Copy() { copyObjects = append(copyObjects, ©File{ fileName: bind.Dest, src: bind.Source, diff --git a/internal/app/wwctl/overlay/build/main.go b/internal/app/wwctl/overlay/build/main.go index 5f347bc6..819d08df 100644 --- a/internal/app/wwctl/overlay/build/main.go +++ b/internal/app/wwctl/overlay/build/main.go @@ -71,7 +71,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } - if BuildHost && controller.Warewulf.EnableHostOverlay { + if BuildHost && controller.Warewulf.EnableHostOverlay() { err := overlay.BuildHostOverlay() if err != nil { return fmt.Errorf("host overlay could not be built: %s", err) diff --git a/internal/pkg/config/buildconfig.go.in b/internal/pkg/config/buildconfig.go.in index 2ebc7de4..d92a5128 100644 --- a/internal/pkg/config/buildconfig.go.in +++ b/internal/pkg/config/buildconfig.go.in @@ -2,6 +2,8 @@ package config import ( "path" + + "github.com/warewulf/warewulf/internal/pkg/util" ) var ConfigFile = "@SYSCONFDIR@/warewulf/warewulf.conf" @@ -25,24 +27,48 @@ const Version = "@VERSION@" const Release = "@RELEASE@" type TFTPConf struct { - Enabled bool `yaml:"enabled" default:"true"` + EnabledP *bool `yaml:"enabled" default:"true"` TftpRoot string `yaml:"tftproot,omitempty" default:"@TFTPDIR@"` SystemdName string `yaml:"systemd name,omitempty" default:"tftp"` IpxeBinaries map[string]string `yaml:"ipxe,omitempty" default:"{\"00:09\": \"ipxe-snponly-x86_64.efi\",\"00:00\": \"undionly.kpxe\",\"00:0B\": \"arm64-efi/snponly.efi\",\"00:07\": \"ipxe-snponly-x86_64.efi\"}"` } +func (this TFTPConf) Enabled() bool { + return util.BoolP(this.EnabledP) +} + // WarewulfConf adds additional Warewulf-specific configuration to // BaseConf. type WarewulfConf struct { - Port int `yaml:"port,omitempty" default:"9873"` - Secure bool `yaml:"secure" default:"true"` - UpdateInterval int `yaml:"update interval,omitempty" default:"60"` - AutobuildOverlays bool `yaml:"autobuild overlays,omitempty" default:"true"` - EnableHostOverlay bool `yaml:"host overlay" default:"true"` - Syslog bool `yaml:"syslog,omitempty" default:"false"` - DataStore string `yaml:"datastore,omitempty" default:"@DATADIR@"` - GrubBoot bool `yaml:"grubboot,omitempty" default:"false"` + Port int `yaml:"port,omitempty" default:"9873"` + SecureP *bool `yaml:"secure,omitempty" default:"true"` + UpdateInterval int `yaml:"update interval,omitempty" default:"60"` + AutobuildOverlaysP *bool `yaml:"autobuild overlays,omitempty" default:"true"` + EnableHostOverlayP *bool `yaml:"host overlay,omitempty" default:"true"` + SyslogP *bool `yaml:"syslog,omitempty" default:"false"` + DataStore string `yaml:"datastore,omitempty" default:"@DATADIR@"` + GrubBootP *bool `yaml:"grubboot,omitempty" default:"false"` +} + +func (this WarewulfConf) Secure() bool { + return util.BoolP(this.SecureP) +} + +func (this WarewulfConf) AutobuildOverlays() bool { + return util.BoolP(this.AutobuildOverlaysP) +} + +func (this WarewulfConf) EnableHostOverlay() bool { + return util.BoolP(this.EnableHostOverlayP) +} + +func (this WarewulfConf) Syslog() bool { + return util.BoolP(this.SyslogP) +} + +func (this WarewulfConf) GrubBoot() bool { + return util.BoolP(this.GrubBootP) } func (paths BuildConfig) OciBlobCachedir() string { diff --git a/internal/pkg/config/dhcp.go b/internal/pkg/config/dhcp.go index f496f431..56c70986 100644 --- a/internal/pkg/config/dhcp.go +++ b/internal/pkg/config/dhcp.go @@ -1,11 +1,19 @@ package config +import ( + "github.com/warewulf/warewulf/internal/pkg/util" +) + // DHCPConf represents the configuration for the DHCP service that // Warewulf will configure. type DHCPConf struct { - Enabled bool `yaml:"enabled" default:"true"` + EnabledP *bool `yaml:"enabled,omitempty" default:"true"` Template string `yaml:"template,omitempty" default:"default"` RangeStart string `yaml:"range start,omitempty"` RangeEnd string `yaml:"range end,omitempty"` SystemdName string `yaml:"systemd name,omitempty" default:"dhcpd"` } + +func (this DHCPConf) Enabled() bool { + return util.BoolP(this.EnabledP) +} diff --git a/internal/pkg/config/mounts.go b/internal/pkg/config/mounts.go index 305fbad4..f228a4e5 100644 --- a/internal/pkg/config/mounts.go +++ b/internal/pkg/config/mounts.go @@ -1,11 +1,23 @@ package config +import ( + "github.com/warewulf/warewulf/internal/pkg/util" +) + // A MountEntry represents a bind mount that is applied to a container // during exec and shell. type MountEntry struct { - Source string `yaml:"source"` - Dest string `yaml:"dest,omitempty"` - ReadOnly bool `yaml:"readonly,omitempty"` - Options string `yaml:"options,omitempty"` // ignored at the moment - Copy bool `yaml:"copy,omitempty"` // temporarily copy the file into the container + Source string `yaml:"source"` + Dest string `yaml:"dest,omitempty"` + ReadOnlyP *bool `yaml:"readonly,omitempty"` + Options string `yaml:"options,omitempty"` // ignored at the moment + CopyP *bool `yaml:"copy,omitempty"` // temporarily copy the file into the container +} + +func (this MountEntry) ReadOnly() bool { + return util.BoolP(this.ReadOnlyP) +} + +func (this MountEntry) Copy() bool { + return util.BoolP(this.CopyP) } diff --git a/internal/pkg/config/nfs.go b/internal/pkg/config/nfs.go index baaf411d..ca6fc8b3 100644 --- a/internal/pkg/config/nfs.go +++ b/internal/pkg/config/nfs.go @@ -2,23 +2,33 @@ package config import ( "github.com/creasty/defaults" + + "github.com/warewulf/warewulf/internal/pkg/util" ) // NFSConf represents the NFS configuration that will be used by // Warewulf to generate exports on the server and mounts on compute // nodes. type NFSConf struct { - Enabled bool `yaml:"enabled" default:"true"` + EnabledP *bool `yaml:"enabled,omitempty" default:"true"` ExportsExtended []*NFSExportConf `yaml:"export paths,omitempty" default:"[]"` SystemdName string `yaml:"systemd name,omitempty" default:"nfsd"` } +func (this NFSConf) Enabled() bool { + return util.BoolP(this.EnabledP) +} + // An NFSExportConf reprents a single NFS export / mount. type NFSExportConf struct { Path string `yaml:"path" default:"/dev/null"` ExportOptions string `yaml:"export options,omitempty" default:"rw,sync,no_subtree_check"` MountOptions string `yaml:"mount options,omitempty" default:"defaults"` - Mount bool `yaml:"mount" default:"true"` + MountP *bool `yaml:"mount,omitempty" default:"true"` +} + +func (this NFSExportConf) Mount() bool { + return util.BoolP(this.MountP) } // Implements the Unmarshal interface for NFSConf to set default diff --git a/internal/pkg/config/root.go b/internal/pkg/config/root.go index b8ca89f0..8655b901 100644 --- a/internal/pkg/config/root.go +++ b/internal/pkg/config/root.go @@ -114,7 +114,6 @@ func (conf *WarewulfYaml) Parse(data []byte) error { conf.Netmask = fmt.Sprintf("%d.%d.%d.%d", mask[0], mask[1], mask[2], mask[3]) } } - return nil } diff --git a/internal/pkg/config/root_test.go b/internal/pkg/config/root_test.go index df625a33..9b466b29 100644 --- a/internal/pkg/config/root_test.go +++ b/internal/pkg/config/root_test.go @@ -11,19 +11,19 @@ func TestDefaultWarewulfYaml(t *testing.T) { conf := New() assert.Equal(t, 9873, conf.Warewulf.Port) - assert.True(t, conf.Warewulf.Secure) + assert.True(t, conf.Warewulf.Secure()) assert.Equal(t, 60, conf.Warewulf.UpdateInterval) - assert.True(t, conf.Warewulf.AutobuildOverlays) - assert.True(t, conf.Warewulf.EnableHostOverlay) - assert.False(t, conf.Warewulf.Syslog) + assert.True(t, conf.Warewulf.AutobuildOverlays()) + assert.True(t, conf.Warewulf.EnableHostOverlay()) + assert.False(t, conf.Warewulf.Syslog()) - assert.True(t, conf.DHCP.Enabled) + assert.True(t, conf.DHCP.Enabled()) assert.Equal(t, "default", conf.DHCP.Template) assert.Empty(t, conf.DHCP.RangeStart) assert.Empty(t, conf.DHCP.RangeEnd) assert.Equal(t, "dhcpd", conf.DHCP.SystemdName) - assert.True(t, conf.TFTP.Enabled) + assert.True(t, conf.TFTP.Enabled()) assert.NotEmpty(t, conf.TFTP.TftpRoot) assert.Equal(t, "tftp", conf.TFTP.SystemdName) assert.NotEmpty(t, conf.TFTP.IpxeBinaries["00:00"]) @@ -31,13 +31,13 @@ func TestDefaultWarewulfYaml(t *testing.T) { assert.NotEmpty(t, conf.TFTP.IpxeBinaries["00:09"]) assert.NotEmpty(t, conf.TFTP.IpxeBinaries["00:0B"]) - assert.True(t, conf.NFS.Enabled) + assert.True(t, conf.NFS.Enabled()) assert.Empty(t, conf.NFS.ExportsExtended) assert.Equal(t, "nfsd", conf.NFS.SystemdName) assert.Equal(t, "/etc/resolv.conf", conf.MountsContainer[0].Source) assert.Equal(t, "/etc/resolv.conf", conf.MountsContainer[0].Dest) - assert.False(t, conf.MountsContainer[0].ReadOnly) + assert.False(t, conf.MountsContainer[0].ReadOnly()) assert.Empty(t, conf.MountsContainer[0].Options) assert.NotEmpty(t, conf.Paths.Bindir) @@ -121,34 +121,34 @@ container mounts: assert.Equal(t, "192.168.200.0", conf.Network) assert.Equal(t, 9873, conf.Warewulf.Port) - assert.False(t, conf.Warewulf.Secure) + assert.False(t, conf.Warewulf.Secure()) assert.Equal(t, 60, conf.Warewulf.UpdateInterval) - assert.True(t, conf.Warewulf.AutobuildOverlays) - assert.True(t, conf.Warewulf.EnableHostOverlay) - assert.False(t, conf.Warewulf.Syslog) + assert.True(t, conf.Warewulf.AutobuildOverlays()) + assert.True(t, conf.Warewulf.EnableHostOverlay()) + assert.False(t, conf.Warewulf.Syslog()) - assert.True(t, conf.DHCP.Enabled) + assert.True(t, conf.DHCP.Enabled()) assert.Equal(t, "192.168.200.50", conf.DHCP.RangeStart) assert.Equal(t, "192.168.200.99", conf.DHCP.RangeEnd) assert.Equal(t, "dhcpd", conf.DHCP.SystemdName) - assert.True(t, conf.TFTP.Enabled) + assert.True(t, conf.TFTP.Enabled()) assert.Equal(t, "tftp", conf.TFTP.SystemdName) - assert.True(t, conf.NFS.Enabled) + assert.True(t, conf.NFS.Enabled()) assert.Equal(t, "/home", conf.NFS.ExportsExtended[0].Path) assert.Equal(t, "rw,sync", conf.NFS.ExportsExtended[0].ExportOptions) assert.Equal(t, "defaults", conf.NFS.ExportsExtended[0].MountOptions) - assert.True(t, conf.NFS.ExportsExtended[0].Mount) + assert.True(t, conf.NFS.ExportsExtended[0].Mount()) assert.Equal(t, "/opt", conf.NFS.ExportsExtended[1].Path) assert.Equal(t, "ro,sync,no_root_squash", conf.NFS.ExportsExtended[1].ExportOptions) assert.Equal(t, "defaults", conf.NFS.ExportsExtended[1].MountOptions) - assert.False(t, conf.NFS.ExportsExtended[1].Mount) + assert.False(t, conf.NFS.ExportsExtended[1].Mount()) assert.Equal(t, "nfs-server", conf.NFS.SystemdName) assert.Equal(t, "/etc/resolv.conf", conf.MountsContainer[0].Source) assert.Equal(t, "/etc/resolv.conf", conf.MountsContainer[0].Dest) - assert.True(t, conf.MountsContainer[0].ReadOnly) + assert.True(t, conf.MountsContainer[0].ReadOnly()) } func TestCache(t *testing.T) { diff --git a/internal/pkg/configure/dhcp.go b/internal/pkg/configure/dhcp.go index 85fd2c03..95f6c816 100644 --- a/internal/pkg/configure/dhcp.go +++ b/internal/pkg/configure/dhcp.go @@ -17,7 +17,7 @@ func DHCP() (err error) { controller := warewulfconf.Get() - if !controller.DHCP.Enabled { + if !controller.DHCP.Enabled() { wwlog.Warn("This system is not configured as a Warewulf DHCP controller") return } @@ -29,7 +29,7 @@ func DHCP() (err error) { if controller.DHCP.RangeEnd == "" { return fmt.Errorf("configuration is not defined: `dhcpd range end`") } - if controller.Warewulf.EnableHostOverlay { + if controller.Warewulf.EnableHostOverlay() { err = overlay.BuildHostOverlay() if err != nil { wwlog.Warn("host overlay could not be built: %s", err) diff --git a/internal/pkg/configure/nfs.go b/internal/pkg/configure/nfs.go index d68916d3..62a9dd1a 100644 --- a/internal/pkg/configure/nfs.go +++ b/internal/pkg/configure/nfs.go @@ -17,8 +17,8 @@ func NFS() error { controller := warewulfconf.Get() - if controller.NFS.Enabled { - if controller.Warewulf.EnableHostOverlay { + if controller.NFS.Enabled() { + if controller.Warewulf.EnableHostOverlay() { err := overlay.BuildHostOverlay() if err != nil { wwlog.Warn("host overlay could not be built: %s", err) diff --git a/internal/pkg/configure/tftp.go b/internal/pkg/configure/tftp.go index c693cb5d..41c8d556 100644 --- a/internal/pkg/configure/tftp.go +++ b/internal/pkg/configure/tftp.go @@ -21,7 +21,7 @@ func TFTP() (err error) { return } - if controller.Warewulf.GrubBoot { + if controller.Warewulf.GrubBoot() { err := warewulfd.CopyShimGrub() if err != nil { wwlog.Warn("error when copying shim/grub binaries: %s", err) @@ -43,7 +43,7 @@ func TFTP() (err error) { } } } - if !controller.TFTP.Enabled { + if !controller.TFTP.Enabled() { wwlog.Warn("Warewulf does not auto start TFTP services due to disable by warewulf.conf") return nil } diff --git a/internal/pkg/container/mountpoints.go b/internal/pkg/container/mountpoints.go index 961513fb..07c7b57e 100644 --- a/internal/pkg/container/mountpoints.go +++ b/internal/pkg/container/mountpoints.go @@ -30,10 +30,10 @@ func InitMountPnts(binds []string) (mounts []*warewulfconf.MountEntry) { } } mntPnt := warewulfconf.MountEntry{ - Source: bind[0], - Dest: dest, - ReadOnly: readonly, - Copy: copy_, + Source: bind[0], + Dest: dest, + ReadOnlyP: &readonly, + CopyP: ©_, } mounts = append(mounts, &mntPnt) } diff --git a/internal/pkg/upgrade/config.go b/internal/pkg/upgrade/config.go index 10476efe..ac597911 100644 --- a/internal/pkg/upgrade/config.go +++ b/internal/pkg/upgrade/config.go @@ -75,30 +75,30 @@ func (this *WarewulfYaml) Upgrade() (upgraded *config.WarewulfYaml) { type WarewulfConf struct { Port int `yaml:"port"` - Secure bool `yaml:"secure"` + Secure *bool `yaml:"secure"` UpdateInterval int `yaml:"update interval"` - AutobuildOverlays bool `yaml:"autobuild overlays"` - EnableHostOverlay bool `yaml:"host overlay"` - Syslog bool `yaml:"syslog"` + AutobuildOverlays *bool `yaml:"autobuild overlays"` + EnableHostOverlay *bool `yaml:"host overlay"` + Syslog *bool `yaml:"syslog"` DataStore string `yaml:"datastore"` - GrubBoot bool `yaml:"grubboot"` + GrubBoot *bool `yaml:"grubboot"` } func (this *WarewulfConf) Upgrade() (upgraded *config.WarewulfConf) { upgraded = new(config.WarewulfConf) upgraded.Port = this.Port - upgraded.Secure = this.Secure + upgraded.SecureP = this.Secure upgraded.UpdateInterval = this.UpdateInterval - upgraded.AutobuildOverlays = this.AutobuildOverlays - upgraded.EnableHostOverlay = this.EnableHostOverlay - upgraded.Syslog = this.Syslog + upgraded.AutobuildOverlaysP = this.AutobuildOverlays + upgraded.EnableHostOverlayP = this.EnableHostOverlay + upgraded.SyslogP = this.Syslog upgraded.DataStore = this.DataStore - upgraded.GrubBoot = this.GrubBoot + upgraded.GrubBootP = this.GrubBoot return upgraded } type DHCPConf struct { - Enabled bool `yaml:"enabled"` + Enabled *bool `yaml:"enabled"` Template string `yaml:"template"` RangeStart string `yaml:"range start"` RangeEnd string `yaml:"range end"` @@ -107,7 +107,7 @@ type DHCPConf struct { func (this *DHCPConf) Upgrade() (upgraded *config.DHCPConf) { upgraded = new(config.DHCPConf) - upgraded.Enabled = this.Enabled + upgraded.EnabledP = this.Enabled upgraded.Template = this.Template upgraded.RangeStart = this.RangeStart upgraded.RangeEnd = this.RangeEnd @@ -116,7 +116,7 @@ func (this *DHCPConf) Upgrade() (upgraded *config.DHCPConf) { } type TFTPConf struct { - Enabled bool `yaml:"enabled"` + Enabled *bool `yaml:"enabled"` TftpRoot string `yaml:"tftproot"` SystemdName string `yaml:"systemd name"` IpxeBinaries map[string]string `yaml:"ipxe"` @@ -124,7 +124,7 @@ type TFTPConf struct { func (this *TFTPConf) Upgrade() (upgraded *config.TFTPConf) { upgraded = new(config.TFTPConf) - upgraded.Enabled = this.Enabled + upgraded.EnabledP = this.Enabled upgraded.TftpRoot = this.TftpRoot upgraded.SystemdName = this.SystemdName upgraded.IpxeBinaries = make(map[string]string) @@ -135,15 +135,21 @@ func (this *TFTPConf) Upgrade() (upgraded *config.TFTPConf) { } type NFSConf struct { - Enabled bool `yaml:"enabled"` + Enabled *bool `yaml:"enabled"` + Exports []string `yaml:"exports"` ExportsExtended []*NFSExportConf `yaml:"export paths"` SystemdName string `yaml:"systemd name"` } func (this *NFSConf) Upgrade() (upgraded *config.NFSConf) { upgraded = new(config.NFSConf) - upgraded.Enabled = this.Enabled + upgraded.EnabledP = this.Enabled upgraded.ExportsExtended = make([]*config.NFSExportConf, 0) + for _, export := range this.Exports { + extendedExport := new(config.NFSExportConf) + extendedExport.Path = export + upgraded.ExportsExtended = append(upgraded.ExportsExtended, extendedExport) + } for _, export := range this.ExportsExtended { upgraded.ExportsExtended = append(upgraded.ExportsExtended, export.Upgrade()) } @@ -155,7 +161,7 @@ type NFSExportConf struct { Path string `yaml:"path"` ExportOptions string `yaml:"export options"` MountOptions string `yaml:"mount options"` - Mount bool `yaml:"mount"` + Mount *bool `yaml:"mount"` } func (this *NFSExportConf) Upgrade() (upgraded *config.NFSExportConf) { @@ -163,7 +169,7 @@ func (this *NFSExportConf) Upgrade() (upgraded *config.NFSExportConf) { upgraded.Path = this.Path upgraded.ExportOptions = this.ExportOptions upgraded.MountOptions = this.MountOptions - upgraded.Mount = this.Mount + upgraded.MountP = this.Mount return upgraded } @@ -180,18 +186,18 @@ func (this *SSHConf) Upgrade() (upgraded *config.SSHConf) { type MountEntry struct { Source string `yaml:"source"` Dest string `yaml:"dest"` - ReadOnly bool `yaml:"readonly"` + ReadOnly *bool `yaml:"readonly"` Options string `yaml:"options"` - Copy bool `yaml:"copy"` + Copy *bool `yaml:"copy"` } func (this *MountEntry) Upgrade() (upgraded *config.MountEntry) { upgraded = new(config.MountEntry) upgraded.Source = this.Source upgraded.Dest = this.Dest - upgraded.ReadOnly = this.ReadOnly + upgraded.ReadOnlyP = this.ReadOnly upgraded.Options = this.Options - upgraded.Copy = this.Copy + upgraded.CopyP = this.Copy return upgraded } diff --git a/internal/pkg/upgrade/config_test.go b/internal/pkg/upgrade/config_test.go index 50cf474b..cd29511d 100644 --- a/internal/pkg/upgrade/config_test.go +++ b/internal/pkg/upgrade/config_test.go @@ -49,7 +49,6 @@ warewulf: port: 9873 secure: true update interval: 60 - host overlay: false dhcp: enabled: true template: default @@ -61,7 +60,9 @@ tftp: tftproot: /var/lib/tftpboot systemd name: tftp nfs: - enabled: false + export paths: + - path: /home + - path: /var/warewulf systemd name: nfs-server `, }, @@ -97,7 +98,6 @@ warewulf: port: 9873 secure: true update interval: 60 - host overlay: false dhcp: enabled: true template: default @@ -109,7 +109,9 @@ tftp: tftproot: /var/lib/tftpboot systemd name: tftp nfs: - enabled: false + export paths: + - path: /home + - path: /var/warewulf systemd name: nfs-server `, }, @@ -148,7 +150,7 @@ warewulf: secure: true update interval: 60 autobuild overlays: true - host overlay: false + syslog: false dhcp: enabled: true template: default @@ -160,7 +162,9 @@ tftp: tftproot: /var/lib/tftpboot systemd name: tftp nfs: - enabled: false + export paths: + - path: /home + - path: /var/warewulf systemd name: nfs-server `, }, @@ -212,6 +216,7 @@ warewulf: update interval: 60 autobuild overlays: true host overlay: true + syslog: false dhcp: enabled: true template: default @@ -280,6 +285,7 @@ warewulf: update interval: 60 autobuild overlays: true host overlay: true + syslog: false dhcp: enabled: true range start: 192.168.200.50 @@ -362,6 +368,7 @@ warewulf: update interval: 60 autobuild overlays: true host overlay: true + syslog: false dhcp: enabled: true range start: 10.0.1.1 diff --git a/internal/pkg/util/util.go b/internal/pkg/util/util.go index 67b95378..e2099844 100644 --- a/internal/pkg/util/util.go +++ b/internal/pkg/util/util.go @@ -18,6 +18,10 @@ import ( "github.com/warewulf/warewulf/internal/pkg/wwlog" ) +func BoolP(p *bool) bool { + return p != nil && *p +} + func FirstError(errs ...error) (err error) { for _, e := range errs { if err == nil { diff --git a/internal/pkg/warewulfd/daemon.go b/internal/pkg/warewulfd/daemon.go index 2ab8f6ba..1a338f71 100644 --- a/internal/pkg/warewulfd/daemon.go +++ b/internal/pkg/warewulfd/daemon.go @@ -57,7 +57,7 @@ func DaemonInitLogging() error { conf := warewulfconf.Get() - if conf.Warewulf.Syslog { + if conf.Warewulf.Syslog() { wwlog.Debug("Changing log output to syslog") diff --git a/internal/pkg/warewulfd/provision.go b/internal/pkg/warewulfd/provision.go index 71c05679..5a165a55 100644 --- a/internal/pkg/warewulfd/provision.go +++ b/internal/pkg/warewulfd/provision.go @@ -50,7 +50,7 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) { wwlog.Info("request from hwaddr:%s ipaddr:%s | stage:%s", rinfo.hwaddr, req.RemoteAddr, rinfo.stage) - if (rinfo.stage == "runtime" || len(rinfo.overlay) > 0) && conf.Warewulf.Secure { + if (rinfo.stage == "runtime" || len(rinfo.overlay) > 0) && conf.Warewulf.Secure() { if rinfo.remoteport >= 1024 { wwlog.Denied("Non-privileged port: %s", req.RemoteAddr) w.WriteHeader(http.StatusUnauthorized) @@ -149,7 +149,7 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) { remoteNode, context, request_overlays, - conf.Warewulf.AutobuildOverlays) + conf.Warewulf.AutobuildOverlays()) if err != nil { if errors.Is(err, overlay.ErrDoesNotExist) { diff --git a/internal/pkg/warewulfd/provision_test.go b/internal/pkg/warewulfd/provision_test.go index 24e3cb46..cc35f909 100644 --- a/internal/pkg/warewulfd/provision_test.go +++ b/internal/pkg/warewulfd/provision_test.go @@ -101,7 +101,8 @@ nodes: dbErr := LoadNodeDB() assert.NoError(t, dbErr) - conf.Warewulf.Secure = false + secureFalse := false + conf.Warewulf.SecureP = &secureFalse assert.NoError(t, os.MkdirAll(path.Join(conf.Paths.OverlayProvisiondir(), "n1"), 0700)) assert.NoError(t, os.WriteFile(path.Join(conf.Paths.OverlayProvisiondir(), "n1", "__SYSTEM__.img"), []byte("system overlay"), 0600)) assert.NoError(t, os.WriteFile(path.Join(conf.Paths.OverlayProvisiondir(), "n1", "__RUNTIME__.img"), []byte("runtime overlay"), 0600)) From ab6c6d2a05beff6b816593cc79234819c4bcc936 Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Wed, 6 Nov 2024 15:42:46 -0700 Subject: [PATCH 19/19] Mark two upgrade arguments as required Based on TSC feedback. Signed-off-by: Jonathon Anderson --- internal/app/wwctl/upgrade/nodes/cobra.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/internal/app/wwctl/upgrade/nodes/cobra.go b/internal/app/wwctl/upgrade/nodes/cobra.go index d138130a..b652562b 100644 --- a/internal/app/wwctl/upgrade/nodes/cobra.go +++ b/internal/app/wwctl/upgrade/nodes/cobra.go @@ -32,6 +32,12 @@ func init() { Command.Flags().BoolVar(&replaceOverlays, "replace-overlays", false, "Replace 'wwinit' and 'generic' overlays with their split replacements") Command.Flags().StringVarP(&inputPath, "input-path", "i", node.ConfigFile, "Path to a legacy nodes.conf") Command.Flags().StringVarP(&outputPath, "output-path", "o", node.ConfigFile, "Path to write the upgraded nodes.conf to") + if err := Command.MarkFlagRequired("add-defaults"); err != nil { + panic(err) + } + if err := Command.MarkFlagRequired("replace-overlays"); err != nil { + panic(err) + } } func UpgradeNodesConf(cmd *cobra.Command, args []string) error {