367 lines
11 KiB
Go
367 lines
11 KiB
Go
package info
|
|
|
|
import (
|
|
"bytes"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/warewulf/warewulf/internal/pkg/testenv"
|
|
"github.com/warewulf/warewulf/internal/pkg/warewulfd"
|
|
"github.com/warewulf/warewulf/internal/pkg/wwlog"
|
|
)
|
|
|
|
func Test_Overlay_Variables(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
writeFiles map[string]string
|
|
args []string
|
|
expectError bool
|
|
expectedOutput string
|
|
}{
|
|
{
|
|
name: "overlay variables",
|
|
writeFiles: map[string]string{
|
|
"var/lib/warewulf/overlays/test-overlay/test.ww": `
|
|
{{/* .Kernel.Tags.foo: "some help text" */}}
|
|
{{/* wwdoc1: First Line */}}
|
|
{{ .Node.Tags.bar }}
|
|
{{/* wwdoc2: Second Line */}}
|
|
`,
|
|
},
|
|
args: []string{"test-overlay", "test.ww"},
|
|
expectError: false,
|
|
expectedOutput: "First Line\n" +
|
|
"Second Line\n" +
|
|
"\n" +
|
|
"VARIABLE OPTION TYPE HELP\n" +
|
|
"-------- ------ ---- ----\n" +
|
|
".Node.Tags.bar string \n",
|
|
},
|
|
{
|
|
name: "overlay variables no file",
|
|
writeFiles: map[string]string{
|
|
"var/lib/warewulf/overlays/test-overlay/test.ww": ``,
|
|
},
|
|
args: []string{"test-overlay", "no-file.ww"},
|
|
expectError: true,
|
|
},
|
|
{
|
|
name: "overlay variables no overlay",
|
|
args: []string{"no-overlay", "test.ww"},
|
|
expectError: true,
|
|
},
|
|
{
|
|
name: "nested fields multiple levels",
|
|
writeFiles: map[string]string{
|
|
"var/lib/warewulf/overlays/test-overlay/nested.ww": `
|
|
{{ .Kernel.Args }}
|
|
{{ .Ipmi.UserName }}
|
|
{{ .Ipmi.Ipaddr }}
|
|
{{ .Warewulf.Port }}
|
|
`,
|
|
},
|
|
args: []string{"test-overlay", "nested.ww"},
|
|
expectError: false,
|
|
expectedOutput: "VARIABLE OPTION TYPE HELP\n" +
|
|
"-------- ------ ---- ----\n" +
|
|
".Ipmi.Ipaddr --ipmiaddr IP Set the IPMI IP address\n" +
|
|
".Ipmi.UserName --ipmiuser string Set the IPMI username\n" +
|
|
".Kernel.Args --kernelargs []string Set kernel arguments\n" +
|
|
".Warewulf.Port int \n",
|
|
},
|
|
{
|
|
name: "template without variables",
|
|
writeFiles: map[string]string{
|
|
"var/lib/warewulf/overlays/test-overlay/no-vars.ww": `
|
|
# Static configuration file
|
|
# This file has no template variables
|
|
static_value=true
|
|
`,
|
|
},
|
|
args: []string{"test-overlay", "no-vars.ww"},
|
|
expectError: false,
|
|
expectedOutput: `VARIABLE OPTION TYPE HELP
|
|
-------- ------ ---- ----
|
|
`,
|
|
},
|
|
{
|
|
name: "only documentation no variables",
|
|
writeFiles: map[string]string{
|
|
"var/lib/warewulf/overlays/test-overlay/doc-only.ww": `
|
|
{{/* wwdoc: This is just documentation */}}
|
|
{{/* wwdoc2: No actual template variables used */}}
|
|
Static content here
|
|
`,
|
|
},
|
|
args: []string{"test-overlay", "doc-only.ww"},
|
|
expectError: false,
|
|
expectedOutput: `This is just documentation
|
|
No actual template variables used
|
|
|
|
VARIABLE OPTION TYPE HELP
|
|
-------- ------ ---- ----
|
|
`,
|
|
},
|
|
{
|
|
name: "template parse error",
|
|
writeFiles: map[string]string{
|
|
"var/lib/warewulf/overlays/test-overlay/invalid.ww": `
|
|
{{ .Id }
|
|
{{ unclosed range .NetDevs }}
|
|
`,
|
|
},
|
|
args: []string{"test-overlay", "invalid.ww"},
|
|
expectError: true,
|
|
},
|
|
{
|
|
name: "inline comment documentation",
|
|
writeFiles: map[string]string{
|
|
"var/lib/warewulf/overlays/test-overlay/inline-doc.ww": `
|
|
{{/* .Id: The unique node identifier */}}
|
|
{{/* .Hostname: The node's hostname in DNS */}}
|
|
{{/* .Tags.env: Environment tag (prod, dev, test) */}}
|
|
{{ .Id }}
|
|
{{ .Hostname }}
|
|
{{ .Tags.env }}
|
|
`,
|
|
},
|
|
args: []string{"test-overlay", "inline-doc.ww"},
|
|
expectError: false,
|
|
expectedOutput: `VARIABLE OPTION TYPE HELP
|
|
-------- ------ ---- ----
|
|
.Hostname string The node's hostname in DNS
|
|
.Id string The unique node identifier
|
|
.Tags.env string Environment tag (prod, dev, test)
|
|
`,
|
|
},
|
|
{
|
|
name: "complex conditional branches",
|
|
writeFiles: map[string]string{
|
|
"var/lib/warewulf/overlays/test-overlay/conditionals.ww": `
|
|
{{ if eq .Kernel.Version "5.15" }}
|
|
Old kernel
|
|
{{ else if gt (len .NetDevs) 0 }}
|
|
Has network: {{ .Id }}
|
|
{{ else }}
|
|
Default: {{ .Hostname }}
|
|
{{ end }}
|
|
`,
|
|
},
|
|
args: []string{"test-overlay", "conditionals.ww"},
|
|
expectError: false,
|
|
expectedOutput: "VARIABLE OPTION TYPE HELP\n" +
|
|
"-------- ------ ---- ----\n" +
|
|
".Hostname string \n" +
|
|
".Id string \n" +
|
|
".Kernel.Version --kernelversion string Set kernel version\n" +
|
|
".NetDevs map[string]*node.NetDev \n",
|
|
},
|
|
{
|
|
name: "sprig function pipelines",
|
|
writeFiles: map[string]string{
|
|
"var/lib/warewulf/overlays/test-overlay/sprig.ww": `
|
|
{{ .Id | upper }}
|
|
{{ .Hostname | lower }}
|
|
{{ .Kernel.Args | join " " }}
|
|
{{ .Tags.foo | default "bar" }}
|
|
`,
|
|
},
|
|
args: []string{"test-overlay", "sprig.ww"},
|
|
expectError: false,
|
|
expectedOutput: "VARIABLE OPTION TYPE HELP\n" +
|
|
"-------- ------ ---- ----\n" +
|
|
".Hostname string \n" +
|
|
".Id string \n" +
|
|
".Kernel.Args --kernelargs []string Set kernel arguments\n" +
|
|
".Tags.foo string \n",
|
|
},
|
|
{
|
|
name: "include function usage",
|
|
writeFiles: map[string]string{
|
|
"var/lib/warewulf/overlays/test-overlay/include.ww": `
|
|
{{ Include "/etc/passwd" }}
|
|
{{ IncludeFrom .ImageName "/etc/group" }}
|
|
`,
|
|
},
|
|
args: []string{"test-overlay", "include.ww"},
|
|
expectError: false,
|
|
expectedOutput: "VARIABLE OPTION TYPE HELP\n" +
|
|
"-------- ------ ---- ----\n" +
|
|
".ImageName --image string Set image name\n",
|
|
},
|
|
{
|
|
name: "mixed documentation types",
|
|
writeFiles: map[string]string{
|
|
"var/lib/warewulf/overlays/test-overlay/mixed-doc.ww": `
|
|
{{/* wwdoc: Configuration for network interfaces */}}
|
|
{{/* wwdoc-details: This template generates network configs */}}
|
|
{{/* .NetDevs: Map of network devices by name */}}
|
|
{{/* .Id: Node identifier */}}
|
|
{{ .Id }}
|
|
{{ .NetDevs }}
|
|
`,
|
|
},
|
|
args: []string{"test-overlay", "mixed-doc.ww"},
|
|
expectError: false,
|
|
expectedOutput: "Configuration for network interfaces\n" +
|
|
"This template generates network configs\n" +
|
|
"\n" +
|
|
"VARIABLE OPTION TYPE HELP\n" +
|
|
"-------- ------ ---- ----\n" +
|
|
".Id string Node identifier\n" +
|
|
".NetDevs map[string]*node.NetDev Map of network devices by name\n",
|
|
},
|
|
{
|
|
name: "tag field access",
|
|
writeFiles: map[string]string{
|
|
"var/lib/warewulf/overlays/test-overlay/tags.ww": `
|
|
{{ .Tags.foo }}
|
|
{{ .Ipmi.Tags.vlan }}
|
|
{{ .NetDevs }}
|
|
`,
|
|
},
|
|
args: []string{"test-overlay", "tags.ww"},
|
|
expectError: false,
|
|
expectedOutput: "VARIABLE OPTION TYPE HELP\n" +
|
|
"-------- ------ ---- ----\n" +
|
|
".Ipmi.Tags.vlan string \n" +
|
|
".NetDevs map[string]*node.NetDev \n" +
|
|
".Tags.foo string \n",
|
|
},
|
|
{
|
|
name: "dollar sign root context",
|
|
writeFiles: map[string]string{
|
|
"var/lib/warewulf/overlays/test-overlay/dollar.ww": `
|
|
{{ $.Id }}
|
|
{{ $.BuildHost }}
|
|
{{ $.Ipaddr }}
|
|
`,
|
|
},
|
|
args: []string{"test-overlay", "dollar.ww"},
|
|
expectError: false,
|
|
expectedOutput: "VARIABLE OPTION TYPE HELP\n" +
|
|
"-------- ------ ---- ----\n" +
|
|
"$.BuildHost string \n" +
|
|
"$.Id string \n" +
|
|
"$.Ipaddr string \n",
|
|
},
|
|
{
|
|
name: "range over map basic",
|
|
writeFiles: map[string]string{
|
|
"var/lib/warewulf/overlays/test-overlay/range-map.ww": `
|
|
{{/* wwdoc: Network device iteration */}}
|
|
{{- range $devname, $netdev := .NetDevs }}
|
|
Device: {{ $netdev.Device }}
|
|
Type: {{ $netdev.Type }}
|
|
IP: {{ $netdev.Ipaddr }}
|
|
{{- end }}
|
|
`,
|
|
},
|
|
args: []string{"test-overlay", "range-map.ww"},
|
|
expectError: false,
|
|
expectedOutput: "Network device iteration\n" +
|
|
"\n" +
|
|
"VARIABLE OPTION TYPE HELP\n" +
|
|
"-------- ------ ---- ----\n" +
|
|
"$netdev.Device --netdev string Set the device for given network\n" +
|
|
"$netdev.Ipaddr --ipaddr IP IPv4 address in given network\n" +
|
|
"$netdev.Type --type string Set device type of given network\n" +
|
|
".NetDevs map[string]*node.NetDev \n",
|
|
},
|
|
{
|
|
name: "range over map with output verification",
|
|
writeFiles: map[string]string{
|
|
"var/lib/warewulf/overlays/test-overlay/range-verify.ww": `
|
|
{{- range $devname, $netdev := .NetDevs }}
|
|
{{ $devname }}
|
|
{{ $netdev.Device }}
|
|
{{ $netdev.Type }}
|
|
{{- end }}
|
|
`,
|
|
},
|
|
args: []string{"test-overlay", "range-verify.ww"},
|
|
expectError: false,
|
|
expectedOutput: "VARIABLE OPTION TYPE HELP\n" +
|
|
"-------- ------ ---- ----\n" +
|
|
"$netdev.Device --netdev string Set the device for given network\n" +
|
|
"$netdev.Type --type string Set device type of given network\n" +
|
|
".NetDevs map[string]*node.NetDev \n",
|
|
},
|
|
{
|
|
name: "empty collection checks",
|
|
writeFiles: map[string]string{
|
|
"var/lib/warewulf/overlays/test-overlay/empty.ww": `
|
|
{{ if gt (len .NetDevs) 0 }}
|
|
Has devices
|
|
{{ end }}
|
|
{{ if .FileSystems }}
|
|
Has filesystems
|
|
{{ end }}
|
|
`,
|
|
},
|
|
args: []string{"test-overlay", "empty.ww"},
|
|
expectError: false,
|
|
expectedOutput: "VARIABLE OPTION TYPE HELP\n" +
|
|
"-------- ------ ---- ----\n" +
|
|
".FileSystems map[string]*node.FileSystem \n" +
|
|
".NetDevs map[string]*node.NetDev \n",
|
|
},
|
|
{
|
|
name: "file and abort directives",
|
|
writeFiles: map[string]string{
|
|
"var/lib/warewulf/overlays/test-overlay/control.ww": `
|
|
{{ file "output.conf" }}
|
|
{{ if .Tags.enabled }}
|
|
Config: {{ .Tags.value }}
|
|
{{ else }}
|
|
{{ abort }}
|
|
{{ end }}
|
|
`,
|
|
},
|
|
args: []string{"test-overlay", "control.ww"},
|
|
expectError: false,
|
|
expectedOutput: "VARIABLE OPTION TYPE HELP\n" +
|
|
"-------- ------ ---- ----\n" +
|
|
".Tags.enabled string \n" +
|
|
".Tags.value string \n",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
env := testenv.New(t)
|
|
defer env.RemoveAll()
|
|
warewulfd.SetNoDaemon()
|
|
|
|
for path, content := range tt.writeFiles {
|
|
env.WriteFile(path, content)
|
|
}
|
|
baseCmd := GetCommand()
|
|
buf := new(bytes.Buffer)
|
|
baseCmd.SetOut(buf)
|
|
baseCmd.SetErr(buf)
|
|
wwlog.SetLogWriter(buf)
|
|
|
|
baseCmd.SetArgs(tt.args)
|
|
err := baseCmd.Execute()
|
|
|
|
if tt.expectError {
|
|
assert.Error(t, err)
|
|
} else {
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
if tt.expectedOutput != "" {
|
|
output := buf.String()
|
|
assert.Equal(t, tt.expectedOutput, output)
|
|
} else {
|
|
// For tests without expected output, print actual output for debugging
|
|
// This helps understand what variables are being detected
|
|
if testing.Verbose() {
|
|
t.Logf("Output:\n%s", buf.String())
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|