Merge pull request #1846 from anderbubble/unset-image
Fix processing of UNDEF and UNSET during `wwctl <node|profile> set`
This commit is contained in:
@@ -23,6 +23,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
- If init is not specified, wwinit looks for /sbin/init, /etc/init, and /bin/init. #1808
|
||||
- assume ipxe template=default if not set. #1808, #1813
|
||||
- Display a warning during overlay build if an overlay list is empty. #1808
|
||||
- Fix processing of UNDEF and UNSET during `wwctl <node|profile> set`. #1837
|
||||
|
||||
### Changed
|
||||
|
||||
|
||||
@@ -9,179 +9,120 @@ import (
|
||||
"github.com/warewulf/warewulf/internal/pkg/warewulfd"
|
||||
)
|
||||
|
||||
type test_description struct {
|
||||
name string
|
||||
args []string
|
||||
wantErr bool
|
||||
stdout string
|
||||
inDB string
|
||||
outDb string
|
||||
}
|
||||
|
||||
func run_test(t *testing.T, test test_description) {
|
||||
env := testenv.New(t)
|
||||
defer env.RemoveAll()
|
||||
env.WriteFile("etc/warewulf/nodes.conf", test.inDB)
|
||||
warewulfd.SetNoDaemon()
|
||||
name := test.name
|
||||
if name == "" {
|
||||
name = t.Name()
|
||||
}
|
||||
t.Run(name, func(t *testing.T) {
|
||||
baseCmd := GetCommand()
|
||||
test.args = append(test.args, "--yes")
|
||||
baseCmd.SetArgs(test.args)
|
||||
buf := new(bytes.Buffer)
|
||||
baseCmd.SetOut(buf)
|
||||
baseCmd.SetErr(buf)
|
||||
err := baseCmd.Execute()
|
||||
if test.wantErr {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, buf.String(), test.stdout)
|
||||
content := env.ReadFile("etc/warewulf/nodes.conf")
|
||||
assert.YAMLEq(t, test.outDb, content)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Single_Node_Change_Profile(t *testing.T) {
|
||||
test := test_description{
|
||||
args: []string{"--profile=foo", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
inDB: `nodeprofiles:
|
||||
func Test_Node_Set(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
args []string
|
||||
wantErr bool
|
||||
inDB string
|
||||
outDB string
|
||||
}{
|
||||
"--profile=foo": {
|
||||
args: []string{"--profile=foo", "n01"},
|
||||
wantErr: false,
|
||||
inDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
comment: testit
|
||||
nodes:
|
||||
n01:
|
||||
profiles:
|
||||
- default`,
|
||||
outDb: `nodeprofiles:
|
||||
outDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
comment: testit
|
||||
nodes:
|
||||
n01:
|
||||
profiles:
|
||||
- foo
|
||||
`,
|
||||
}
|
||||
run_test(t, test)
|
||||
}
|
||||
|
||||
func Test_Node_Unset(t *testing.T) {
|
||||
test := test_description{
|
||||
args: []string{"--comment=UNDEF", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
inDB: `nodeprofiles: {}
|
||||
- foo`,
|
||||
},
|
||||
"--comment=UNDEF": {
|
||||
args: []string{"--comment=UNDEF", "n01"},
|
||||
wantErr: false,
|
||||
inDB: `
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
comment: foo
|
||||
profiles:
|
||||
- default`,
|
||||
outDb: `nodeprofiles: {}
|
||||
outDB: `
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
profiles:
|
||||
- default
|
||||
`,
|
||||
}
|
||||
run_test(t, test)
|
||||
}
|
||||
|
||||
func Test_Set_Ipmi_Write_Explicit(t *testing.T) {
|
||||
test := test_description{
|
||||
args: []string{"--ipmiwrite", "true", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
inDB: `nodeprofiles: {}
|
||||
- default`,
|
||||
},
|
||||
"--ipmiwrite=true": {
|
||||
args: []string{"--ipmiwrite", "true", "n01"},
|
||||
wantErr: false,
|
||||
inDB: `
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01: {}
|
||||
`,
|
||||
outDb: `nodeprofiles: {}
|
||||
n01: {}`,
|
||||
outDB: `
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
ipmi:
|
||||
write: "true"
|
||||
`,
|
||||
}
|
||||
run_test(t, test)
|
||||
}
|
||||
|
||||
func Test_Set_Ipmi_Write_Implicit(t *testing.T) {
|
||||
test := test_description{
|
||||
args: []string{"--ipmiwrite", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
inDB: `nodeprofiles: {}
|
||||
write: "true"`,
|
||||
},
|
||||
"--ipmiwrite": {
|
||||
args: []string{"--ipmiwrite", "n01"},
|
||||
wantErr: false,
|
||||
inDB: `
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01: {}
|
||||
`,
|
||||
outDb: `nodeprofiles: {}
|
||||
n01: {}`,
|
||||
outDB: `
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
ipmi:
|
||||
write: "true"
|
||||
`,
|
||||
}
|
||||
run_test(t, test)
|
||||
}
|
||||
|
||||
func Test_Unset_Ipmi_Write(t *testing.T) {
|
||||
test := test_description{
|
||||
args: []string{"--ipmiwrite=UNDEF", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
inDB: `nodeprofiles: {}
|
||||
write: "true"`,
|
||||
},
|
||||
"--ipmiwrite=UNDEF": {
|
||||
args: []string{"--ipmiwrite=UNDEF", "n01"},
|
||||
wantErr: false,
|
||||
inDB: `
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
ipmi:
|
||||
write: "true"
|
||||
`,
|
||||
outDb: `nodeprofiles: {}
|
||||
write: "true"`,
|
||||
outDB: `
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01: {}
|
||||
`,
|
||||
}
|
||||
run_test(t, test)
|
||||
}
|
||||
|
||||
func Test_Unset_Ipmi_Write_False(t *testing.T) {
|
||||
test := test_description{
|
||||
args: []string{"--ipmiwrite=UNDEF", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
inDB: `nodeprofiles: {}
|
||||
n01: {}`,
|
||||
},
|
||||
"--ipmiwrite=false": {
|
||||
args: []string{"--ipmiwrite=false", "n01"},
|
||||
wantErr: false,
|
||||
inDB: `
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01: {}`,
|
||||
outDB: `
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
ipmi:
|
||||
write: "false"
|
||||
`,
|
||||
outDb: `nodeprofiles: {}
|
||||
nodes:
|
||||
n01: {}
|
||||
`,
|
||||
}
|
||||
run_test(t, test)
|
||||
}
|
||||
|
||||
func Test_Ipmi_Hidden_False(t *testing.T) {
|
||||
test := test_description{
|
||||
args: []string{"--ipmiwrite=false", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
inDB: `nodeprofiles:
|
||||
write: "false"`,
|
||||
},
|
||||
"--ipmiwrite=false (override)": {
|
||||
args: []string{"--ipmiwrite=false", "n01"},
|
||||
wantErr: false,
|
||||
inDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
ipmi:
|
||||
write: "true"
|
||||
nodes:
|
||||
n01:
|
||||
profiles:
|
||||
- default
|
||||
`,
|
||||
outDb: `nodeprofiles:
|
||||
- default`,
|
||||
outDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
ipmi:
|
||||
write: "true"
|
||||
@@ -190,84 +131,66 @@ nodes:
|
||||
profiles:
|
||||
- default
|
||||
ipmi:
|
||||
write: "false"
|
||||
`,
|
||||
}
|
||||
run_test(t, test)
|
||||
}
|
||||
|
||||
func Test_Add_NetTags(t *testing.T) {
|
||||
test := test_description{
|
||||
args: []string{"--nettagadd=dns=1.1.1.1", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
inDB: `nodeprofiles: {}
|
||||
write: "false"`,
|
||||
},
|
||||
"--nettagadd": {
|
||||
args: []string{"--nettagadd=dns=1.1.1.1", "n01"},
|
||||
wantErr: false,
|
||||
inDB: `
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01: {}
|
||||
`,
|
||||
outDb: `nodeprofiles: {}
|
||||
n01: {}`,
|
||||
outDB: `
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
network devices:
|
||||
default:
|
||||
tags:
|
||||
dns: 1.1.1.1
|
||||
`,
|
||||
}
|
||||
run_test(t, test)
|
||||
}
|
||||
|
||||
func Test_Del_NetTags(t *testing.T) {
|
||||
test := test_description{
|
||||
args: []string{"--netname=default", "--nettagdel=dns1,dns2", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
inDB: `nodeprofiles: {}
|
||||
dns: 1.1.1.1`,
|
||||
},
|
||||
"--nettagdel": {
|
||||
args: []string{"--nettagdel=dns1,dns2", "n01"},
|
||||
wantErr: false,
|
||||
inDB: `
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
network devices:
|
||||
default:
|
||||
tags:
|
||||
dns1: 1.1.1.1
|
||||
dns2: 2.2.2.2
|
||||
`,
|
||||
outDb: `nodeprofiles: {}
|
||||
dns2: 2.2.2.2`,
|
||||
outDB: `
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01: {}
|
||||
`,
|
||||
}
|
||||
run_test(t, test)
|
||||
}
|
||||
|
||||
func Test_Multiple_Set_Tests(t *testing.T) {
|
||||
tests := []test_description{
|
||||
{
|
||||
name: "single node change profile",
|
||||
n01: {}`,
|
||||
},
|
||||
"single node change profile": {
|
||||
args: []string{"--profile=foo", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
inDB: `nodeprofiles:
|
||||
inDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
comment: testit
|
||||
nodes:
|
||||
n01:
|
||||
profiles:
|
||||
- default`,
|
||||
outDb: `nodeprofiles:
|
||||
outDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
comment: testit
|
||||
nodes:
|
||||
n01:
|
||||
profiles:
|
||||
- foo
|
||||
`,
|
||||
- foo`,
|
||||
},
|
||||
{
|
||||
name: "multiple nodes change profile",
|
||||
"multiple nodes change profile": {
|
||||
args: []string{"--profile=foo", "n0[1-2]"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
inDB: `nodeprofiles:
|
||||
inDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
comment: testit
|
||||
nodes:
|
||||
@@ -277,7 +200,8 @@ nodes:
|
||||
n02:
|
||||
profiles:
|
||||
- default`,
|
||||
outDb: `nodeprofiles:
|
||||
outDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
comment: testit
|
||||
nodes:
|
||||
@@ -286,22 +210,21 @@ nodes:
|
||||
- foo
|
||||
n02:
|
||||
profiles:
|
||||
- foo
|
||||
`,
|
||||
- foo`,
|
||||
},
|
||||
{
|
||||
name: "single node set ipmitag",
|
||||
"single node set ipmitag": {
|
||||
args: []string{"--ipmitagadd", "foo=baar", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
inDB: `nodeprofiles:
|
||||
inDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
comment: testit
|
||||
nodes:
|
||||
n01:
|
||||
profiles:
|
||||
- default`,
|
||||
outDb: `nodeprofiles:
|
||||
outDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
comment: testit
|
||||
nodes:
|
||||
@@ -310,15 +233,13 @@ nodes:
|
||||
- default
|
||||
ipmi:
|
||||
tags:
|
||||
foo: baar
|
||||
`,
|
||||
foo: baar`,
|
||||
},
|
||||
{
|
||||
name: "single node delete tag",
|
||||
"single node delete tag": {
|
||||
args: []string{"--tagdel", "tag1", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
inDB: `nodeprofiles:
|
||||
inDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
comment: testit
|
||||
nodes:
|
||||
@@ -328,7 +249,8 @@ nodes:
|
||||
tags:
|
||||
tag1: value1
|
||||
tag2: value2`,
|
||||
outDb: `nodeprofiles:
|
||||
outDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
comment: testit
|
||||
nodes:
|
||||
@@ -336,42 +258,37 @@ nodes:
|
||||
profiles:
|
||||
- default
|
||||
tags:
|
||||
tag2: value2
|
||||
`,
|
||||
tag2: value2`,
|
||||
},
|
||||
{
|
||||
name: "single node add tag",
|
||||
"single node add tag": {
|
||||
args: []string{"--tagadd", "tag1=foobaar", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
inDB: `nodeprofiles:
|
||||
inDB: `
|
||||
nodeprofiles:
|
||||
default: {}
|
||||
nodes:
|
||||
n01: {}
|
||||
`,
|
||||
outDb: `nodeprofiles:
|
||||
n01: {}`,
|
||||
outDB: `
|
||||
nodeprofiles:
|
||||
default: {}
|
||||
nodes:
|
||||
n01:
|
||||
tags:
|
||||
tag1: foobaar
|
||||
`,
|
||||
tag1: foobaar`,
|
||||
},
|
||||
{
|
||||
name: "single node add tag with netdev",
|
||||
"single node add tag with netdev": {
|
||||
args: []string{"--tagadd", "tag1=foobaar", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
inDB: `nodeprofiles:
|
||||
inDB: `
|
||||
nodeprofiles:
|
||||
default: {}
|
||||
nodes:
|
||||
n01:
|
||||
network devices:
|
||||
default:
|
||||
ipaddr: 172.16.130.101
|
||||
|
||||
`,
|
||||
outDb: `nodeprofiles:
|
||||
ipaddr: 172.16.130.101`,
|
||||
outDB: `
|
||||
nodeprofiles:
|
||||
default: {}
|
||||
nodes:
|
||||
n01:
|
||||
@@ -379,48 +296,43 @@ nodes:
|
||||
tag1: foobaar
|
||||
network devices:
|
||||
default:
|
||||
ipaddr: 172.16.130.101
|
||||
`,
|
||||
ipaddr: 172.16.130.101`,
|
||||
},
|
||||
{
|
||||
name: "single node set onboot",
|
||||
"single node set onboot": {
|
||||
args: []string{"--netname", "default", "--onboot=true", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
inDB: `nodeprofiles:
|
||||
inDB: `
|
||||
nodeprofiles:
|
||||
default: {}
|
||||
nodes:
|
||||
n01:
|
||||
network devices:
|
||||
default:
|
||||
ipaddr: 172.16.130.101`,
|
||||
outDB: `
|
||||
nodeprofiles:
|
||||
default: {}
|
||||
nodes:
|
||||
n01:
|
||||
network devices:
|
||||
default:
|
||||
ipaddr: 172.16.130.101
|
||||
|
||||
`,
|
||||
outDb: `nodeprofiles:
|
||||
default: {}
|
||||
nodes:
|
||||
n01:
|
||||
network devices:
|
||||
default:
|
||||
ipaddr: 172.16.130.101
|
||||
onboot: "true"
|
||||
`,
|
||||
onboot: "true"`,
|
||||
},
|
||||
|
||||
{
|
||||
name: "single node set fs,part and disk",
|
||||
"single node set fs,part and disk": {
|
||||
args: []string{"--fsname=var", "--fspath=/var", "--fsformat=btrfs", "--partname=var", "--partnumber=1", "--diskname=/dev/vda", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
inDB: `nodeprofiles:
|
||||
inDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
comment: testit
|
||||
nodes:
|
||||
n01:
|
||||
profiles:
|
||||
- default
|
||||
`,
|
||||
outDb: `nodeprofiles:
|
||||
- default`,
|
||||
outDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
comment: testit
|
||||
nodes:
|
||||
@@ -435,15 +347,13 @@ nodes:
|
||||
filesystems:
|
||||
/dev/disk/by-partlabel/var:
|
||||
format: btrfs
|
||||
path: /var
|
||||
`,
|
||||
path: /var`,
|
||||
},
|
||||
{
|
||||
name: "single delete not existing fs",
|
||||
"single delete not existing fs": {
|
||||
args: []string{"--fsdel=foo", "n01"},
|
||||
wantErr: true,
|
||||
stdout: "",
|
||||
inDB: `nodeprofiles:
|
||||
inDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
comment: testit
|
||||
nodes:
|
||||
@@ -459,9 +369,9 @@ nodes:
|
||||
filesystems:
|
||||
/dev/disk/by-partlabel/var:
|
||||
format: btrfs
|
||||
path: /var
|
||||
`,
|
||||
outDb: `nodeprofiles:
|
||||
path: /var`,
|
||||
outDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
comment: testit
|
||||
nodes:
|
||||
@@ -476,15 +386,13 @@ nodes:
|
||||
filesystems:
|
||||
/dev/disk/by-partlabel/var:
|
||||
format: btrfs
|
||||
path: /var
|
||||
`,
|
||||
path: /var`,
|
||||
},
|
||||
{
|
||||
name: "single node delete existing fs",
|
||||
"single node delete existing fs": {
|
||||
args: []string{"--fsdel=/dev/disk/by-partlabel/var", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
inDB: `nodeprofiles:
|
||||
inDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
comment: testit
|
||||
nodes:
|
||||
@@ -500,9 +408,9 @@ nodes:
|
||||
filesystems:
|
||||
/dev/disk/by-partlabel/var:
|
||||
format: btrfs
|
||||
path: /var
|
||||
`,
|
||||
outDb: `nodeprofiles:
|
||||
path: /var`,
|
||||
outDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
comment: testit
|
||||
nodes:
|
||||
@@ -513,15 +421,13 @@ nodes:
|
||||
/dev/vda:
|
||||
partitions:
|
||||
var:
|
||||
number: "1"
|
||||
`,
|
||||
number: "1"`,
|
||||
},
|
||||
{
|
||||
name: "single node delete existing partition",
|
||||
"single node delete existing partition": {
|
||||
args: []string{"--partdel=var", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
inDB: `nodeprofiles:
|
||||
inDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
comment: testit
|
||||
nodes:
|
||||
@@ -537,9 +443,9 @@ nodes:
|
||||
filesystems:
|
||||
/dev/disk/by-partlabel/var:
|
||||
format: btrfs
|
||||
path: /var
|
||||
`,
|
||||
outDb: `nodeprofiles:
|
||||
path: /var`,
|
||||
outDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
comment: testit
|
||||
nodes:
|
||||
@@ -551,15 +457,13 @@ nodes:
|
||||
filesystems:
|
||||
/dev/disk/by-partlabel/var:
|
||||
format: btrfs
|
||||
path: /var
|
||||
`,
|
||||
path: /var`,
|
||||
},
|
||||
{
|
||||
name: "single node delete existing disk",
|
||||
"single node delete existing disk": {
|
||||
args: []string{"--diskdel=/dev/vda", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
inDB: `nodeprofiles:
|
||||
inDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
comment: testit
|
||||
nodes:
|
||||
@@ -574,9 +478,9 @@ nodes:
|
||||
filesystems:
|
||||
/dev/disk/by-partlabel/var:
|
||||
format: btrfs
|
||||
path: /var
|
||||
`,
|
||||
outDb: `nodeprofiles:
|
||||
path: /var`,
|
||||
outDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
comment: testit
|
||||
nodes:
|
||||
@@ -586,22 +490,21 @@ nodes:
|
||||
filesystems:
|
||||
/dev/disk/by-partlabel/var:
|
||||
format: btrfs
|
||||
path: /var
|
||||
`,
|
||||
path: /var`,
|
||||
},
|
||||
{
|
||||
name: "single node set mtu",
|
||||
"single node set mtu": {
|
||||
args: []string{"--mtu", "1234", "--netname=mynet", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
inDB: `nodeprofiles:
|
||||
inDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
comment: testit
|
||||
nodes:
|
||||
n01:
|
||||
profiles:
|
||||
- default`,
|
||||
outDb: `nodeprofiles:
|
||||
outDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
comment: testit
|
||||
nodes:
|
||||
@@ -610,15 +513,13 @@ nodes:
|
||||
- default
|
||||
network devices:
|
||||
mynet:
|
||||
mtu: "1234"
|
||||
`,
|
||||
mtu: "1234"`,
|
||||
},
|
||||
{
|
||||
name: "single node set ipmitag",
|
||||
"single node set tag": {
|
||||
args: []string{"--tagadd", "nodetag1=nodevalue1", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
inDB: `nodeprofiles:
|
||||
inDB: `
|
||||
nodeprofiles:
|
||||
p1:
|
||||
comment: testit 1
|
||||
tags:
|
||||
@@ -632,7 +533,8 @@ nodes:
|
||||
profiles:
|
||||
- p1
|
||||
- p2`,
|
||||
outDb: `nodeprofiles:
|
||||
outDB: `
|
||||
nodeprofiles:
|
||||
p1:
|
||||
comment: testit 1
|
||||
tags:
|
||||
@@ -647,39 +549,25 @@ nodes:
|
||||
- p1
|
||||
- p2
|
||||
tags:
|
||||
nodetag1: nodevalue1
|
||||
`,
|
||||
nodetag1: nodevalue1`,
|
||||
},
|
||||
{
|
||||
name: "single node set comma in comment",
|
||||
"single node set comma in comment": {
|
||||
args: []string{"n01", "--comment", "This is a , comment"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
inDB: `nodes:
|
||||
n01:
|
||||
comment: old comment
|
||||
`,
|
||||
outDb: `nodeprofiles: {}
|
||||
comment: old comment`,
|
||||
outDB: `
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
comment: This is a , comment
|
||||
`,
|
||||
comment: This is a , comment`,
|
||||
},
|
||||
}
|
||||
|
||||
warewulfd.SetNoDaemon()
|
||||
for _, tt := range tests {
|
||||
run_test(t, tt)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Node_Add(t *testing.T) {
|
||||
tests := []test_description{
|
||||
{
|
||||
"--tagadd (one)": {
|
||||
args: []string{"--tagadd=email=node", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
inDB: `nodeprofiles:
|
||||
inDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
comment: testit
|
||||
tags:
|
||||
@@ -688,24 +576,8 @@ nodes:
|
||||
n01:
|
||||
profiles:
|
||||
- default`,
|
||||
outDb: `nodeprofiles:
|
||||
default:
|
||||
comment: testit
|
||||
tags:
|
||||
email: profile
|
||||
nodes:
|
||||
n01:
|
||||
profiles:
|
||||
- default
|
||||
tags:
|
||||
email: node
|
||||
`,
|
||||
},
|
||||
{
|
||||
args: []string{"--tagadd=newtag=newval", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
inDB: `nodeprofiles:
|
||||
outDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
comment: testit
|
||||
tags:
|
||||
@@ -716,7 +588,24 @@ nodes:
|
||||
- default
|
||||
tags:
|
||||
email: node`,
|
||||
outDb: `nodeprofiles:
|
||||
},
|
||||
"--tagadd (second)": {
|
||||
args: []string{"--tagadd=newtag=newval", "n01"},
|
||||
wantErr: false,
|
||||
inDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
comment: testit
|
||||
tags:
|
||||
email: profile
|
||||
nodes:
|
||||
n01:
|
||||
profiles:
|
||||
- default
|
||||
tags:
|
||||
email: node`,
|
||||
outDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
comment: testit
|
||||
tags:
|
||||
@@ -727,12 +616,72 @@ nodes:
|
||||
- default
|
||||
tags:
|
||||
email: node
|
||||
newtag: newval
|
||||
`,
|
||||
newtag: newval`,
|
||||
},
|
||||
"--image=UNDEF": {
|
||||
args: []string{"--image=UNDEF", "n1"},
|
||||
wantErr: false,
|
||||
inDB: `
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n1:
|
||||
image: rockylinux-9`,
|
||||
outDB: `
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n1: {}`,
|
||||
},
|
||||
"--image=UNSET": {
|
||||
args: []string{"--image=UNSET", "n1"},
|
||||
wantErr: false,
|
||||
inDB: `
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n1:
|
||||
image: rockylinux-9`,
|
||||
outDB: `
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n1: {}`,
|
||||
},
|
||||
"--ipaddr=0.0.0.0 (unset)": {
|
||||
args: []string{"--ipaddr=0.0.0.0", "n1"},
|
||||
wantErr: false,
|
||||
inDB: `
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n1:
|
||||
network devices:
|
||||
default:
|
||||
ipadddr: 192.168.0.1`,
|
||||
outDB: `
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n1: {}`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
run_test(t, tt)
|
||||
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.inDB)
|
||||
warewulfd.SetNoDaemon()
|
||||
|
||||
baseCmd := GetCommand()
|
||||
args := append(tt.args, "--yes")
|
||||
baseCmd.SetArgs(args)
|
||||
buf := new(bytes.Buffer)
|
||||
baseCmd.SetOut(buf)
|
||||
baseCmd.SetErr(buf)
|
||||
err := baseCmd.Execute()
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
content := env.ReadFile("etc/warewulf/nodes.conf")
|
||||
assert.YAMLEq(t, tt.outDB, content)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,105 +5,130 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/warewulf/warewulf/internal/pkg/testenv"
|
||||
"github.com/warewulf/warewulf/internal/pkg/warewulfd"
|
||||
)
|
||||
|
||||
type test_description struct {
|
||||
name string
|
||||
args []string
|
||||
wantErr bool
|
||||
stdout string
|
||||
inDB string
|
||||
outDb string
|
||||
}
|
||||
|
||||
func run_test(t *testing.T, test test_description) {
|
||||
env := testenv.New(t)
|
||||
defer env.RemoveAll()
|
||||
env.WriteFile("etc/warewulf/nodes.conf", test.inDB)
|
||||
warewulfd.SetNoDaemon()
|
||||
name := test.name
|
||||
if name == "" {
|
||||
name = t.Name()
|
||||
func Test_Profile_Set(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
args []string
|
||||
wantErr bool
|
||||
inDB string
|
||||
outDb string
|
||||
}{
|
||||
"Test_Set_Netdev": {
|
||||
args: []string{"--netdev=eth0", "default"},
|
||||
wantErr: false,
|
||||
inDB: `
|
||||
nodeprofiles:
|
||||
default: {}
|
||||
nodes: {}`,
|
||||
outDb: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
network devices:
|
||||
default:
|
||||
device: eth0
|
||||
nodes: {}`,
|
||||
},
|
||||
"Test_Set_Netdev_and_Mask": {
|
||||
args: []string{"--netdev=eth0", "-M=255.255.255.0", "default"},
|
||||
wantErr: false,
|
||||
inDB: `
|
||||
nodeprofiles:
|
||||
default: {}
|
||||
nodes: {}`,
|
||||
outDb: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
network devices:
|
||||
default:
|
||||
device: eth0
|
||||
netmask: 255.255.255.0
|
||||
nodes: {}`,
|
||||
},
|
||||
"Set Mask Existing NetDev": {
|
||||
args: []string{"-M=255.255.255.0", "default"},
|
||||
wantErr: false,
|
||||
inDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
network devices:
|
||||
default:
|
||||
device: eth0
|
||||
nodes: {}`,
|
||||
outDb: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
network devices:
|
||||
default:
|
||||
device: eth0
|
||||
netmask: 255.255.255.0
|
||||
nodes: {}`,
|
||||
},
|
||||
"--image=UNSET": {
|
||||
args: []string{"--image=UNSET", "default"},
|
||||
wantErr: false,
|
||||
inDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
image: rockylinux-9
|
||||
nodes: {}`,
|
||||
outDb: `
|
||||
nodeprofiles:
|
||||
default: {}
|
||||
nodes: {}`,
|
||||
},
|
||||
"--image=UNDEF": {
|
||||
args: []string{"--image=UNDEF", "default"},
|
||||
wantErr: false,
|
||||
inDB: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
image: rockylinux-9
|
||||
nodes: {}`,
|
||||
outDb: `
|
||||
nodeprofiles:
|
||||
default: {}
|
||||
nodes: {}`,
|
||||
},
|
||||
"--tagadd=mytag=0.0.0.0": {
|
||||
args: []string{"--tagadd=mytag=0.0.0.0", "default"},
|
||||
wantErr: false,
|
||||
inDB: `
|
||||
nodeprofiles:
|
||||
default: {}
|
||||
nodes: {}`,
|
||||
outDb: `
|
||||
nodeprofiles:
|
||||
default:
|
||||
tags:
|
||||
mytag: 0.0.0.0
|
||||
nodes: {}`,
|
||||
},
|
||||
}
|
||||
t.Run(name, func(t *testing.T) {
|
||||
baseCmd := GetCommand()
|
||||
test.args = append(test.args, "--yes")
|
||||
baseCmd.SetArgs(test.args)
|
||||
buf := new(bytes.Buffer)
|
||||
baseCmd.SetOut(buf)
|
||||
baseCmd.SetErr(buf)
|
||||
err := baseCmd.Execute()
|
||||
if test.wantErr {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, buf.String(), test.stdout)
|
||||
content := env.ReadFile("etc/warewulf/nodes.conf")
|
||||
assert.YAMLEq(t, test.outDb, content)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Set_Netdev(t *testing.T) {
|
||||
test := test_description{
|
||||
args: []string{"--netname=default", "--netdev=eth0", "default"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
inDB: `nodeprofiles:
|
||||
default: {}
|
||||
nodes: {}
|
||||
`,
|
||||
outDb: `nodeprofiles:
|
||||
default:
|
||||
network devices:
|
||||
default:
|
||||
device: eth0
|
||||
nodes: {}
|
||||
`}
|
||||
run_test(t, test)
|
||||
}
|
||||
func Test_Set_Netdev_and_Mask(t *testing.T) {
|
||||
test := test_description{
|
||||
args: []string{"--netname=default", "--netdev=eth0", "-M=255.255.255.0", "default"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
inDB: `nodeprofiles:
|
||||
default: {}
|
||||
nodes: {}
|
||||
`,
|
||||
outDb: `nodeprofiles:
|
||||
default:
|
||||
network devices:
|
||||
default:
|
||||
device: eth0
|
||||
netmask: 255.255.255.0
|
||||
nodes: {}
|
||||
`}
|
||||
run_test(t, test)
|
||||
}
|
||||
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.inDB)
|
||||
warewulfd.SetNoDaemon()
|
||||
baseCmd := GetCommand()
|
||||
args := append(tt.args, "--yes")
|
||||
baseCmd.SetArgs(args)
|
||||
buf := new(bytes.Buffer)
|
||||
baseCmd.SetOut(buf)
|
||||
baseCmd.SetErr(buf)
|
||||
err := baseCmd.Execute()
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
content := env.ReadFile("etc/warewulf/nodes.conf")
|
||||
assert.YAMLEq(t, tt.outDb, content)
|
||||
}
|
||||
|
||||
func Test_Set_Mask_Existing_NetDev(t *testing.T) {
|
||||
test := test_description{
|
||||
args: []string{"--netname=default", "-M=255.255.255.0", "default"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
inDB: `nodeprofiles:
|
||||
default:
|
||||
network devices:
|
||||
default:
|
||||
device: eth0
|
||||
nodes: {}
|
||||
`,
|
||||
outDb: `nodeprofiles:
|
||||
default:
|
||||
network devices:
|
||||
default:
|
||||
device: eth0
|
||||
netmask: 255.255.255.0
|
||||
nodes: {}
|
||||
`}
|
||||
run_test(t, test)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/warewulf/warewulf/internal/pkg/wwtype"
|
||||
)
|
||||
|
||||
/*
|
||||
Checks if for NodeConf all values can be parsed according to their type.
|
||||
*/
|
||||
func (nodeConf *Node) Check() (err error) {
|
||||
nodeInfoType := reflect.TypeOf(nodeConf)
|
||||
nodeInfoVal := reflect.ValueOf(nodeConf)
|
||||
return check(nodeInfoType, nodeInfoVal)
|
||||
}
|
||||
|
||||
func (profileConf *Profile) Check() (err error) {
|
||||
profileInfoType := reflect.TypeOf(profileConf)
|
||||
profileInfoVal := reflect.ValueOf(profileConf)
|
||||
return check(profileInfoType, profileInfoVal)
|
||||
}
|
||||
|
||||
func check(infoType reflect.Type, infoVal reflect.Value) (err error) {
|
||||
if !infoVal.Elem().IsValid() {
|
||||
return nil
|
||||
}
|
||||
// now iterate of every field
|
||||
for i := 0; i < infoVal.Elem().NumField(); i++ {
|
||||
if !infoType.Elem().Field(i).IsExported() {
|
||||
continue
|
||||
} else if infoType.Elem().Field(i).Type.Kind() == reflect.String {
|
||||
newFmt, err := checker(infoVal.Elem().Field(i).String(), infoType.Elem().Field(i).Tag.Get("type"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("field: %s value:%s err: %s", infoType.Elem().Field(i).Name, infoVal.Elem().Field(i).String(), err)
|
||||
} else if newFmt != "" {
|
||||
infoVal.Elem().Field(i).SetString(newFmt)
|
||||
}
|
||||
} else if infoType.Elem().Field(i).Type.Kind() == reflect.Ptr && !infoVal.Elem().Field(i).IsNil() {
|
||||
nestType := reflect.TypeOf(infoVal.Elem().Field(i).Interface())
|
||||
nestVal := reflect.ValueOf(infoVal.Elem().Field(i).Interface())
|
||||
for j := 0; j < nestType.Elem().NumField(); j++ {
|
||||
if nestType.Elem().Field(j).Type.Kind() == reflect.String {
|
||||
newFmt, err := checker(nestVal.Elem().Field(j).Interface().(string), nestType.Elem().Field(j).Tag.Get("type"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("field: %s value:%s err: %s", nestType.Elem().Field(j).Name, nestVal.Elem().Field(j).String(), err)
|
||||
} else if newFmt != "" {
|
||||
nestVal.Elem().Field(j).SetString(newFmt)
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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)
|
||||
for j := 0; j < netType.Elem().NumField(); j++ {
|
||||
newFmt, err := checker(netVal.Elem().Field(j).String(), netType.Elem().Field(j).Tag.Get("type"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("field: %s value:%s err: %s", netType.Elem().Field(j).Name, netVal.Elem().Field(j).String(), err)
|
||||
} else if newFmt != "" {
|
||||
netVal.Elem().Field(j).SetString(newFmt)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checker(value string, valType string) (niceValue string, err error) {
|
||||
if valType == "" || value == "" || wwtype.IsUnsetVerb(value) {
|
||||
return "", nil
|
||||
}
|
||||
switch valType {
|
||||
case "":
|
||||
return "", nil
|
||||
case "bool":
|
||||
if strings.ToLower(value) == "yes" {
|
||||
return "true", nil
|
||||
}
|
||||
if strings.ToLower(value) == "no" {
|
||||
return "false", nil
|
||||
}
|
||||
myBool, err := strconv.ParseBool(value)
|
||||
return strconv.FormatBool(myBool), err
|
||||
case "IP":
|
||||
if addr := net.ParseIP(value); addr == nil {
|
||||
return "", fmt.Errorf("%s can't be parsed to ip address", value)
|
||||
} else {
|
||||
return addr.String(), nil
|
||||
}
|
||||
case "MAC":
|
||||
if mac, err := net.ParseMAC(value); err != nil {
|
||||
return "", fmt.Errorf("%s can't be parsed to MAC address: %s", value, err)
|
||||
} else {
|
||||
return mac.String(), nil
|
||||
}
|
||||
case "uint":
|
||||
if _, err := strconv.ParseUint(value, 10, 64); err != nil {
|
||||
return "", fmt.Errorf("%s is not a uint: %s", value, err)
|
||||
}
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
@@ -6,8 +6,6 @@ import (
|
||||
"github.com/warewulf/warewulf/internal/pkg/wwtype"
|
||||
)
|
||||
|
||||
const undef string = "UNDEF"
|
||||
|
||||
/******
|
||||
* YAML data representations
|
||||
******/
|
||||
|
||||
@@ -201,7 +201,7 @@ func recursiveFlatten(obj interface{}) (hasContent bool) {
|
||||
if typeObj.Elem().Field(i).Type == reflect.TypeOf([]string{}) {
|
||||
del := false
|
||||
for _, elem := range (valObj.Elem().Field(i).Interface()).([]string) {
|
||||
if strings.EqualFold(elem, undef) {
|
||||
if isUnsetValue(elem) {
|
||||
del = true
|
||||
}
|
||||
}
|
||||
@@ -213,7 +213,7 @@ func recursiveFlatten(obj interface{}) (hasContent bool) {
|
||||
hasContent = true
|
||||
}
|
||||
case reflect.String:
|
||||
if strings.EqualFold(valObj.Elem().Field(i).String(), undef) {
|
||||
if isUnsetValue(valObj.Elem().Field(i).String()) {
|
||||
valObj.Elem().Field(i).SetString("")
|
||||
}
|
||||
if valObj.Elem().Field(i).String() != "" {
|
||||
@@ -421,3 +421,9 @@ func (netdev *NetDev) IpCIDR() string {
|
||||
}
|
||||
return ipCIDR.String()
|
||||
}
|
||||
|
||||
var unsetValues = []string{"UNSET", "UNDEF"}
|
||||
|
||||
func isUnsetValue(value string) bool {
|
||||
return util.InSlice(unsetValues, value)
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
package wwtype
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/warewulf/warewulf/internal/pkg/util"
|
||||
)
|
||||
|
||||
func GetUnsetVerbs() []string {
|
||||
return []string{"unset", "delete", "undef", "--", "nil", "0.0.0.0"}
|
||||
}
|
||||
|
||||
func IsUnsetVerb(value string) bool {
|
||||
return util.InSlice(GetUnsetVerbs(), strings.ToLower(value))
|
||||
}
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/warewulf/warewulf/internal/pkg/util"
|
||||
)
|
||||
|
||||
// Simple string which can be converted to bool. Backend storage
|
||||
@@ -15,7 +17,7 @@ Transform the underlying string value to bool
|
||||
*/
|
||||
func (val WWbool) Bool() bool {
|
||||
str := strings.ToLower(string(val))
|
||||
if IsUnsetVerb(str) {
|
||||
if isUnsetValue(str) {
|
||||
return false
|
||||
}
|
||||
switch str {
|
||||
@@ -33,7 +35,7 @@ func (val WWbool) Bool() bool {
|
||||
|
||||
func (val WWbool) BoolDefaultTrue() bool {
|
||||
str := strings.ToLower(string(val))
|
||||
if IsUnsetVerb(str) {
|
||||
if isUnsetValue(str) {
|
||||
return false
|
||||
}
|
||||
switch str {
|
||||
@@ -53,7 +55,7 @@ func (val WWbool) BoolDefaultTrue() bool {
|
||||
Set the string, only accept bool values like true, false, but also UNDEF
|
||||
*/
|
||||
func (val *WWbool) Set(str string) error {
|
||||
if IsUnsetVerb(str) {
|
||||
if isUnsetValue(str) {
|
||||
// run the unset verb trough, will be filtered out later
|
||||
*val = WWbool(str)
|
||||
return nil
|
||||
@@ -81,3 +83,9 @@ func (val WWbool) String() string {
|
||||
func (b WWbool) Type() string {
|
||||
return "WWbool"
|
||||
}
|
||||
|
||||
var unsetValues = []string{"unset", "delete", "undef", "--", "nil", "0.0.0.0"}
|
||||
|
||||
func isUnsetValue(value string) bool {
|
||||
return util.InSlice(unsetValues, strings.ToLower(value))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user