From dae8d004b3ed2478d055ed687a209997a5ce0391 Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Fri, 27 Dec 2024 13:39:29 -0700 Subject: [PATCH] Use Node literal in MergeNode, not EmptyNode() EmptyNode populates empty sub-structs, which interferes with omitempty during serialization. Signed-off-by: Jonathon Anderson --- internal/app/wwctl/node/list/main_test.go | 66 ++-------- internal/pkg/api/node/list.go | 6 +- internal/pkg/kernel/kernel.go | 2 +- internal/pkg/node/mergo.go | 2 +- internal/pkg/node/mergo_test.go | 116 ++++++++++++++++++ internal/pkg/warewulfd/provision.go | 10 +- overlays/debug/internal/debug_test.go | 16 +-- .../rootfs/warewulf/template-variables.md.ww | 8 ++ 8 files changed, 157 insertions(+), 69 deletions(-) diff --git a/internal/app/wwctl/node/list/main_test.go b/internal/app/wwctl/node/list/main_test.go index 31e3ee4a..8c54e46b 100644 --- a/internal/app/wwctl/node/list/main_test.go +++ b/internal/app/wwctl/node/list/main_test.go @@ -430,8 +430,6 @@ func TestListMultipleFormats(t *testing.T) { stdout: ` - profiles: - default - kernel: {} - ipmi: {} `, inDb: ` nodeprofiles: @@ -459,24 +457,12 @@ nodes: "Ipxe": "", "RuntimeOverlay": null, "SystemOverlay": null, - "Kernel": {}, - "Ipmi": { - "UserName": "", - "Password": "", - "Ipaddr": "", - "Gateway": "", - "Netmask": "", - "Port": "", - "Interface": "", - "EscapeChar": "", - "Write": "", - "Template": "", - "Tags": {} - }, + "Kernel": null, + "Ipmi": null, "Init": "", "Root": "", - "NetDevs": {}, - "Tags": {}, + "NetDevs": null, + "Tags": null, "PrimaryNetDev": "", "Disks": null, "FileSystems": null, @@ -510,24 +496,12 @@ nodes: "Ipxe": "", "RuntimeOverlay": null, "SystemOverlay": null, - "Kernel": {}, - "Ipmi": { - "UserName": "", - "Password": "", - "Ipaddr": "", - "Gateway": "", - "Netmask": "", - "Port": "", - "Interface": "", - "EscapeChar": "", - "Write": "", - "Template": "", - "Tags": {} - }, + "Kernel": null, + "Ipmi": null, "Init": "", "Root": "", - "NetDevs": {}, - "Tags": {}, + "NetDevs": null, + "Tags": null, "PrimaryNetDev": "", "Disks": null, "FileSystems": null, @@ -545,24 +519,12 @@ nodes: "Ipxe": "", "RuntimeOverlay": null, "SystemOverlay": null, - "Kernel": {}, - "Ipmi": { - "UserName": "", - "Password": "", - "Ipaddr": "", - "Gateway": "", - "Netmask": "", - "Port": "", - "Interface": "", - "EscapeChar": "", - "Write": "", - "Template": "", - "Tags": {} - }, + "Kernel": null, + "Ipmi": null, "Init": "", "Root": "", - "NetDevs": {}, - "Tags": {}, + "NetDevs": null, + "Tags": null, "PrimaryNetDev": "", "Disks": null, "FileSystems": null, @@ -588,12 +550,8 @@ nodes: stdout: ` - profiles: - default - kernel: {} - ipmi: {} - profiles: - default - kernel: {} - ipmi: {} `, inDb: ` nodeprofiles: diff --git a/internal/pkg/api/node/list.go b/internal/pkg/api/node/list.go index 6519531e..ceeb4ccb 100644 --- a/internal/pkg/api/node/list.go +++ b/internal/pkg/api/node/list.go @@ -76,9 +76,13 @@ func NodeList(nodeGet *wwapiv1.GetNodeList) (nodeList wwapiv1.NodeList, err erro nodeList.Output = append(nodeList.Output, fmt.Sprintf("%s:=:%s:=:%s:=:%s", "NODE NAME", "KERNEL VERSION", "CONTAINER", "OVERLAYS (S/R)")) for _, n := range node.FilterNodeListByName(nodes, nodeGet.Nodes) { + kernelVersion := "" + if n.Kernel != nil { + kernelVersion = n.Kernel.Version + } nodeList.Output = append(nodeList.Output, fmt.Sprintf("%s:=:%s:=:%s:=:%s", n.Id(), - n.Kernel.Version, + kernelVersion, n.ContainerName, strings.Join(n.SystemOverlay, ",")+"/"+strings.Join(n.RuntimeOverlay, ","))) } diff --git a/internal/pkg/kernel/kernel.go b/internal/pkg/kernel/kernel.go index 49d0c4aa..3da2d21a 100644 --- a/internal/pkg/kernel/kernel.go +++ b/internal/pkg/kernel/kernel.go @@ -75,7 +75,7 @@ func FromNode(node *node.Node) *Kernel { wwlog.Debug("FromNode(%v)", node) if node.ContainerName == "" { return nil - } else if node.Kernel.Version != "" { + } else if node.Kernel != nil && node.Kernel.Version != "" { kernel := &Kernel{ContainerName: node.ContainerName, Path: filepath.Join("/", node.Kernel.Version)} if util.IsFile(kernel.FullPath()) { return kernel diff --git a/internal/pkg/node/mergo.go b/internal/pkg/node/mergo.go index 171cf558..f76e6e50 100644 --- a/internal/pkg/node/mergo.go +++ b/internal/pkg/node/mergo.go @@ -113,7 +113,7 @@ func (config *NodesYaml) MergeNode(id string) (node Node, fields fieldMap, err e return node, fields, err } originalNode := node - node = EmptyNode() + node = Node{} fields = make(fieldMap) diff --git a/internal/pkg/node/mergo_test.go b/internal/pkg/node/mergo_test.go index d79e8776..14410791 100644 --- a/internal/pkg/node/mergo_test.go +++ b/internal/pkg/node/mergo_test.go @@ -822,3 +822,119 @@ nodes: }) } } + +func Test_MergeNodeKernel(t *testing.T) { + var tests = map[string]struct { + nodesConf string + node string + kernel *KernelConf + }{ + "interference": { + nodesConf: ` +nodeprofiles: + default: {} +nodes: + node1: {} + test: + profiles: + - default + kernel: + version: v1.0.0 + args: kernel-args`, + node: "node1", + kernel: nil, + }, + } + + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + env := testenv.New(t) + defer env.RemoveAll() + env.WriteFile("/etc/warewulf/nodes.conf", tt.nodesConf) + + registry, regErr := New() + assert.NoError(t, regErr) + node, _, mergeErr := registry.MergeNode(tt.node) + assert.NoError(t, mergeErr) + assert.Equal(t, tt.kernel, node.Kernel) + }) + } +} + +func Test_MergeNodeIpmi(t *testing.T) { + var tests = map[string]struct { + nodesConf string + node string + ipmi *IpmiConf + }{ + "empty single node": { + nodesConf: ` +nodes: + n1: {}`, + node: "n1", + ipmi: nil, + }, + "empty node among multiple": { + nodesConf: ` +nodes: + n0: {} + n1: {} + n2: {}`, + node: "n1", + ipmi: nil, + }, + "populated node among multiple": { + nodesConf: ` +nodes: + n0: {} + n1: + ipmi: + username: root + password: passw0rd + n2: {}`, + node: "n1", + ipmi: &IpmiConf{ + UserName: "root", + Password: "passw0rd", + }, + }, + "no previous interference": { + nodesConf: ` +nodes: + n0: {} + n1: + ipmi: + username: root + password: passw0rd + n2: {}`, + node: "n0", + ipmi: nil, + }, + "no later interference": { + nodesConf: ` +nodes: + n0: {} + n1: + ipmi: + username: root + password: passw0rd + n2: {}`, + node: "n2", + ipmi: nil, + }, + } + + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + env := testenv.New(t) + defer env.RemoveAll() + env.WriteFile("/etc/warewulf/nodes.conf", tt.nodesConf) + + registry, regErr := New() + assert.NoError(t, regErr) + node, _, mergeErr := registry.MergeNode(tt.node) + assert.NoError(t, mergeErr) + assert.Equal(t, tt.ipmi, node.Ipmi) + }) + } +} diff --git a/internal/pkg/warewulfd/provision.go b/internal/pkg/warewulfd/provision.go index 5f520af3..1ee831d7 100644 --- a/internal/pkg/warewulfd/provision.go +++ b/internal/pkg/warewulfd/provision.go @@ -174,6 +174,12 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) { } case "grub.cfg": stage_file = path.Join(conf.Paths.Sysconfdir, "warewulf/grub/grub.cfg.ww") + kernelArgs := "" + kernelVersion := "" + if remoteNode.Kernel != nil { + kernelArgs = remoteNode.Kernel.Args + kernelVersion = remoteNode.Kernel.Version + } tmpl_data = &templateVars{ Id: remoteNode.Id(), Cluster: remoteNode.ClusterName, @@ -183,8 +189,8 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) { Hostname: remoteNode.Id(), Hwaddr: rinfo.hwaddr, ContainerName: remoteNode.ContainerName, - KernelArgs: remoteNode.Kernel.Args, - KernelVersion: remoteNode.Kernel.Version, + KernelArgs: kernelArgs, + KernelVersion: kernelVersion, NetDevs: remoteNode.NetDevs, Tags: remoteNode.Tags} if stage_file == "" { diff --git a/overlays/debug/internal/debug_test.go b/overlays/debug/internal/debug_test.go index 453a95d8..16107854 100644 --- a/overlays/debug/internal/debug_test.go +++ b/overlays/debug/internal/debug_test.go @@ -85,9 +85,11 @@ data from other structures. - Discoverable: - Profiles: default - Tags: + - Kernel: - Version: - Args: quiet crashkernel=no vga=791 net.naming-scheme=v238 + - Ipmi: - UserName: user - Password: password @@ -195,9 +197,11 @@ data from other structures. - AssetKey: - Profiles: [default] - Tags: + - Kernel - Version: - Args: quiet crashkernel=no vga=791 net.naming-scheme=v238 + - Ipmi: - Ipaddr: 192.168.4.21 - Netmask: 255.255.255.0 @@ -250,19 +254,11 @@ data from other structures. - AssetKey: - Profiles: [default] - Tags: + - Kernel - Version: - Args: quiet crashkernel=no vga=791 net.naming-scheme=v238 - - Ipmi: - - Ipaddr: - - Netmask: - - Port: - - Gateway: - - UserName: - - Password: - - Interface: - - Write: - - Tags: + - NetDevs[default]: - Type: - OnBoot: true diff --git a/overlays/debug/rootfs/warewulf/template-variables.md.ww b/overlays/debug/rootfs/warewulf/template-variables.md.ww index d863d633..810996ae 100644 --- a/overlays/debug/rootfs/warewulf/template-variables.md.ww +++ b/overlays/debug/rootfs/warewulf/template-variables.md.ww @@ -27,9 +27,12 @@ data from other structures. - Discoverable: {{ .Discoverable }} - Profiles: {{ range $index, $value := .Profiles }}{{ if $index }},{{ end }}{{ $value }}{{ end }} - Tags: {{ range $key, $value := .Tags }}{{ $key }}={{ $value }} {{ end }} +{{ if .Kernel }} - Kernel: - Version: {{ .Kernel.Version }} - Args: {{ .Kernel.Args }} +{{- end }} +{{ if .Ipmi }} - Ipmi: - UserName: {{ .Ipmi.UserName }} - Password: {{ .Ipmi.Password }} @@ -40,6 +43,7 @@ data from other structures. - Interface: {{ .Ipmi.Interface }} - Write: {{ .Ipmi.Write }} - Tags: {{ range $key, $value := .Ipmi.Tags }}{{ $key }}={{ $value }} {{ end }} +{{- end }} {{- range $index, $netdev := .NetDevs }} - NetDevs[{{ $index }}]: - Type: {{ $netdev.Type }} @@ -136,9 +140,12 @@ data from other structures. - AssetKey: {{ $node.AssetKey }} - Profiles: {{ $node.Profiles }} - Tags: {{ range $key, $value := $node.Tags }}{{ $key }}={{ $value }} {{ end }} +{{ if .Kernel }} - Kernel - Version: {{ $node.Kernel.Version }} - Args: {{ $node.Kernel.Args }} +{{- end }} +{{ if .Ipmi }} - Ipmi: - Ipaddr: {{ $node.Ipmi.Ipaddr }} - Netmask: {{ $node.Ipmi.Netmask }} @@ -149,6 +156,7 @@ data from other structures. - Interface: {{ $node.Ipmi.Interface }} - Write: {{ $node.Ipmi.Write }} - Tags: {{ range $key, $value := $node.Ipmi.Tags }}{{ $key }}={{ $value }} {{ end }} +{{- end }} {{- range $index, $netdev := $node.NetDevs }} - NetDevs[{{ $index }}]: - Type: {{ $netdev.Type }}