Optionally replace wwinit and generic overlays during upgrade

Signed-off-by: Jonathon Anderson <janderson@ciq.com>
This commit is contained in:
Jonathon Anderson
2024-11-05 13:16:22 -07:00
parent 263e3959c2
commit 393629321c
3 changed files with 186 additions and 58 deletions

View File

@@ -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
}

View File

@@ -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

View File

@@ -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)))