Use Node literal in MergeNode, not EmptyNode()

EmptyNode populates empty sub-structs, which interferes with omitempty during
serialization.

Signed-off-by: Jonathon Anderson <janderson@ciq.com>
This commit is contained in:
Jonathon Anderson
2024-12-27 13:39:29 -07:00
parent f0e634183e
commit dae8d004b3
8 changed files with 157 additions and 69 deletions

View File

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

View File

@@ -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, ",")))
}

View File

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

View File

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

View File

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

View File

@@ -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 == "" {

View File

@@ -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: <nil>
- Netmask: <nil>
- Port:
- Gateway: <nil>
- UserName:
- Password:
- Interface:
- Write:
- Tags:
- NetDevs[default]:
- Type:
- OnBoot: true

View File

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