Optionally replace wwinit and generic overlays during upgrade
Signed-off-by: Jonathon Anderson <janderson@ciq.com>
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)))
|
||||
|
||||
Reference in New Issue
Block a user