Merge pull request #1306 from anderbubble/split-test-overlays
Split overlays into discrete functionality and test
This commit is contained in:
@@ -31,6 +31,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
- Bump github.com/fatih/color from 1.15.0 to 1.17.0 #1224
|
||||
- Bump github.com/coreos/ignition/v2 from 2.15.0 to 2.19.0 #1239
|
||||
- Disable building containers by default when calling `wwctl container copy`. #1378
|
||||
- Split wwinit and generic overlays into discrete functionality. #987
|
||||
|
||||
### Fixed
|
||||
|
||||
|
||||
15
Makefile
15
Makefile
@@ -100,6 +100,7 @@ install: build docs
|
||||
install -d -m 0755 $(DESTDIR)$(WWCHROOTDIR)
|
||||
install -d -m 0755 $(DESTDIR)$(WWPROVISIONDIR)
|
||||
install -d -m 0755 $(DESTDIR)$(WWOVERLAYDIR)/wwinit/rootfs/$(WWCLIENTDIR)
|
||||
install -d -m 0755 $(DESTDIR)$(WWOVERLAYDIR)/wwclient/rootfs/$(WWCLIENTDIR)
|
||||
install -d -m 0755 $(DESTDIR)$(WWOVERLAYDIR)/host/rootfs/$(TFTPDIR)/warewulf/
|
||||
install -d -m 0755 $(DESTDIR)$(WWCONFIGDIR)/examples
|
||||
install -d -m 0755 $(DESTDIR)$(WWCONFIGDIR)/ipxe
|
||||
@@ -122,15 +123,15 @@ install: build docs
|
||||
install -m 0644 etc/grub/grub.cfg.ww $(DESTDIR)$(WWCONFIGDIR)/grub/grub.cfg.ww
|
||||
install -m 0644 etc/grub/chainload.ww $(DESTDIR)$(WWOVERLAYDIR)/host/rootfs$(TFTPDIR)/warewulf/grub.cfg.ww
|
||||
install -m 0644 etc/logrotate.d/warewulfd.conf $(DESTDIR)$(LOGROTATEDIR)/warewulfd.conf
|
||||
(cd overlays && find * -type f -exec install -D -m 0644 {} $(DESTDIR)$(WWOVERLAYDIR)/{} \;)
|
||||
(cd overlays && find * -type d -exec mkdir -pv $(DESTDIR)$(WWOVERLAYDIR)/{} \;)
|
||||
(cd overlays && find * -type l -exec cp -av {} $(DESTDIR)$(WWOVERLAYDIR)/{} \;)
|
||||
(cd overlays && find * -path '*/internal' -prune -o -type f -exec install -D -m 0644 {} $(DESTDIR)$(WWOVERLAYDIR)/{} \;)
|
||||
(cd overlays && find * -path '*/internal' -prune -o -type d -exec mkdir -pv $(DESTDIR)$(WWOVERLAYDIR)/{} \;)
|
||||
(cd overlays && find * -path '*/internal' -prune -o -type l -exec cp -av {} $(DESTDIR)$(WWOVERLAYDIR)/{} \;)
|
||||
chmod 0755 $(DESTDIR)$(WWOVERLAYDIR)/wwinit/rootfs/init
|
||||
chmod 0755 $(DESTDIR)$(WWOVERLAYDIR)/wwinit/rootfs/$(WWCLIENTDIR)/wwinit
|
||||
chmod 0600 $(DESTDIR)$(WWOVERLAYDIR)/wwinit/rootfs/etc/ssh/ssh*
|
||||
chmod 0600 $(DESTDIR)$(WWOVERLAYDIR)/wwinit/rootfs/etc/NetworkManager/system-connections/ww4-managed.ww
|
||||
chmod 0644 $(DESTDIR)$(WWOVERLAYDIR)/wwinit/rootfs/etc/ssh/ssh*.pub.ww
|
||||
chmod 0600 $(DESTDIR)$(WWOVERLAYDIR)/wwinit/rootfs/warewulf/config.ww
|
||||
chmod 0600 $(DESTDIR)$(WWOVERLAYDIR)/wwinit/rootfs/$(WWCLIENTDIR)/config.ww
|
||||
chmod 0600 $(DESTDIR)$(WWOVERLAYDIR)/ssh.host_keys/rootfs/etc/ssh/ssh*
|
||||
chmod 0644 $(DESTDIR)$(WWOVERLAYDIR)/ssh.host_keys/rootfs/etc/ssh/ssh*.pub.ww
|
||||
chmod 0600 $(DESTDIR)$(WWOVERLAYDIR)/NetworkManager/rootfs/etc/NetworkManager/system-connections/ww4-managed.ww
|
||||
chmod 0750 $(DESTDIR)$(WWOVERLAYDIR)/host/rootfs
|
||||
install -m 0755 wwctl $(DESTDIR)$(BINDIR)
|
||||
install -m 0755 wwclient $(DESTDIR)$(WWOVERLAYDIR)/wwinit/rootfs/$(WWCLIENTDIR)/wwclient
|
||||
|
||||
@@ -18,9 +18,24 @@ structure of a node within \fBnodes.pp\fP.
|
||||
.EX
|
||||
defaultnode:
|
||||
runtime overlay:
|
||||
- generic
|
||||
- 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
|
||||
kernel:
|
||||
args: quiet crashkernel=no vga=791 net.naming-scheme=v238
|
||||
init: /sbin/init
|
||||
|
||||
@@ -145,8 +145,8 @@ nodes:
|
||||
n01 Id -- n01
|
||||
n01 Comment default profilecomment
|
||||
n01 Ipxe -- (default)
|
||||
n01 RuntimeOverlay -- (generic)
|
||||
n01 SystemOverlay -- (wwinit)
|
||||
n01 RuntimeOverlay -- (hosts,ssh.authorized_keys,syncuser)
|
||||
n01 SystemOverlay -- (wwinit,wwclient,fstab,hostname,ssh.host_keys,issue,resolv,udev.netname,systemd.netname,ifcfg,NetworkManager,debian.interfaces,wicked,ignition)
|
||||
n01 Root -- (initramfs)
|
||||
n01 Init -- (/sbin/init)
|
||||
n01 Kernel.Args -- (quiet crashkernel=no vga=791 net.naming-scheme=v238)
|
||||
@@ -168,8 +168,8 @@ nodes:
|
||||
n01 Id -- n01
|
||||
n01 Comment SUPERSEDED nodecomment
|
||||
n01 Ipxe -- (default)
|
||||
n01 RuntimeOverlay -- (generic)
|
||||
n01 SystemOverlay -- (wwinit)
|
||||
n01 RuntimeOverlay -- (hosts,ssh.authorized_keys,syncuser)
|
||||
n01 SystemOverlay -- (wwinit,wwclient,fstab,hostname,ssh.host_keys,issue,resolv,udev.netname,systemd.netname,ifcfg,NetworkManager,debian.interfaces,wicked,ignition)
|
||||
n01 Root -- (initramfs)
|
||||
n01 Init -- (/sbin/init)
|
||||
n01 Kernel.Args -- (quiet crashkernel=no vga=791 net.naming-scheme=v238)
|
||||
@@ -251,8 +251,8 @@ nodes:
|
||||
stdout: `NODE FIELD PROFILE VALUE
|
||||
n01 Id -- n01
|
||||
n01 Ipxe -- (default)
|
||||
n01 RuntimeOverlay -- (generic)
|
||||
n01 SystemOverlay -- (wwinit)
|
||||
n01 RuntimeOverlay -- (hosts,ssh.authorized_keys,syncuser)
|
||||
n01 SystemOverlay -- (wwinit,wwclient,fstab,hostname,ssh.host_keys,issue,resolv,udev.netname,systemd.netname,ifcfg,NetworkManager,debian.interfaces,wicked,ignition)
|
||||
n01 Root -- (initramfs)
|
||||
n01 Init -- (/sbin/init)
|
||||
n01 Kernel.Args -- (quiet crashkernel=no vga=791 net.naming-scheme=v238)
|
||||
@@ -273,12 +273,14 @@ nodes:
|
||||
name: "multiple overlays list",
|
||||
args: []string{"-l"},
|
||||
stdout: `NODE NAME KERNEL OVERRIDE CONTAINER OVERLAYS (S/R)
|
||||
n01 -- -- (wwinit)/rop1,rop2
|
||||
n01 -- -- (wwinit,wwclient,fstab,hostname,ssh.host_keys,issue,resolv,udev.netname,systemd.netname,ifcfg,NetworkManager,debian.interfaces,wicked,ignition)/rop1,rop2
|
||||
`},
|
||||
{
|
||||
inDb: `WW_INTERNAL: 45
|
||||
nodeprofiles:
|
||||
p1:
|
||||
system overlay:
|
||||
- sop1
|
||||
runtime overlay:
|
||||
- rop1
|
||||
- rop2
|
||||
@@ -293,12 +295,14 @@ nodes:
|
||||
name: "multiple overlays list",
|
||||
args: []string{"-l"},
|
||||
stdout: `NODE NAME KERNEL OVERRIDE CONTAINER OVERLAYS (S/R)
|
||||
n01 -- -- (wwinit)/rop2,nop1 ~{rop1}
|
||||
n01 -- -- sop1/rop2,nop1 ~{rop1}
|
||||
`},
|
||||
{
|
||||
inDb: `WW_INTERNAL: 45
|
||||
nodeprofiles:
|
||||
p1:
|
||||
system overlay:
|
||||
- sop1
|
||||
runtime overlay:
|
||||
- rop1
|
||||
- rop2
|
||||
@@ -316,7 +320,7 @@ nodes:
|
||||
n01 Id -- n01
|
||||
n01 Ipxe -- (default)
|
||||
n01 RuntimeOverlay SUPERSEDED rop2,nop1 ~{rop1}
|
||||
n01 SystemOverlay -- (wwinit)
|
||||
n01 SystemOverlay p1 sop1
|
||||
n01 Root -- (initramfs)
|
||||
n01 Init -- (/sbin/init)
|
||||
n01 Kernel.Args -- (quiet crashkernel=no vga=791 net.naming-scheme=v238)
|
||||
@@ -340,7 +344,7 @@ nodes:
|
||||
stdout: `NODE FIELD PROFILE VALUE
|
||||
n01 Id -- n01
|
||||
n01 Ipxe -- (default)
|
||||
n01 RuntimeOverlay -- (generic)
|
||||
n01 RuntimeOverlay -- (hosts,ssh.authorized_keys,syncuser)
|
||||
n01 SystemOverlay SUPERSEDED profileinit,nodeinit
|
||||
n01 Root -- (initramfs)
|
||||
n01 Init -- (/sbin/init)
|
||||
|
||||
@@ -3,6 +3,7 @@ package show
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
@@ -24,30 +25,33 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
overlaySourceDir = overlay.OverlaySourceDir(overlayName)
|
||||
|
||||
if !util.IsDir(overlaySourceDir) {
|
||||
wwlog.Error("Overlay does not exist: %s", overlayName)
|
||||
os.Exit(1)
|
||||
err := errors.New("Overlay does not exist")
|
||||
wwlog.Error("%s: %s", err, overlayName)
|
||||
return err
|
||||
}
|
||||
|
||||
overlayFile := path.Join(overlaySourceDir, fileName)
|
||||
|
||||
if !util.IsFile(overlayFile) {
|
||||
wwlog.Error("File does not exist within overlay: %s:%s", overlayName, fileName)
|
||||
os.Exit(1)
|
||||
err := errors.New("File does not exist within overlay")
|
||||
wwlog.Error("%s: %s:%s", err, overlayName, fileName)
|
||||
return err
|
||||
}
|
||||
|
||||
if NodeName == "" {
|
||||
f, err := os.ReadFile(overlayFile)
|
||||
if err != nil {
|
||||
wwlog.Error("Could not read file: %s", err)
|
||||
os.Exit(1)
|
||||
return err
|
||||
}
|
||||
|
||||
wwlog.Info(string(f))
|
||||
wwlog.Output("%s", string(f))
|
||||
} else {
|
||||
if !util.IsFile(overlayFile) {
|
||||
wwlog.Debug("%s is not a file", overlayFile)
|
||||
wwlog.Error("%s:%s is not a file", overlayName, fileName)
|
||||
os.Exit(1)
|
||||
err := errors.New("Not a file")
|
||||
wwlog.Error("%s: %s:%s", err, overlayName, fileName)
|
||||
return err
|
||||
}
|
||||
if filepath.Ext(overlayFile) != ".ww" {
|
||||
wwlog.Warn("%s lacks the '.ww' suffix, will not be rendered in an overlay", fileName)
|
||||
@@ -56,12 +60,12 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
nodeDB, err := node.New()
|
||||
if err != nil {
|
||||
wwlog.Error("Could not open node configuration: %s", err)
|
||||
os.Exit(1)
|
||||
return err
|
||||
}
|
||||
nodes, err := nodeDB.FindAllNodes()
|
||||
if err != nil {
|
||||
wwlog.Error("Could not get node list: %s", err)
|
||||
os.Exit(1)
|
||||
return err
|
||||
}
|
||||
filteredNodes := node.FilterByName(nodes, []string{NodeName})
|
||||
if hostName, err := os.Hostname(); err != nil {
|
||||
@@ -73,8 +77,9 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
hostNodeInfo.ClusterName.Set(hostName)
|
||||
filteredNodes = append(filteredNodes, *hostNodeInfo)
|
||||
} else if len(filteredNodes) != 1 {
|
||||
wwlog.Error("%v does not identify a single node", NodeName)
|
||||
os.Exit(1)
|
||||
err := errors.New("Not a single node")
|
||||
wwlog.Error("%s: %v", err, NodeName)
|
||||
return err
|
||||
}
|
||||
|
||||
tstruct := overlay.InitStruct(&filteredNodes[0])
|
||||
@@ -97,10 +102,11 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
wwlog.Debug("Found multifile comment, new filename %s", filenameFromTemplate[0][1])
|
||||
if foundFileComment {
|
||||
if !Quiet {
|
||||
wwlog.Info("backupFile: %v\nwriteFile: %v", backupFile, writeFile)
|
||||
wwlog.Info("Filename: %s\n", destFileName)
|
||||
wwlog.Info("backupFile: %v", backupFile)
|
||||
wwlog.Info("writeFile: %v", writeFile)
|
||||
wwlog.Info("Filename: %s", destFileName)
|
||||
}
|
||||
wwlog.Info("%s", outBuffer.String())
|
||||
wwlog.Output("%s", outBuffer.String())
|
||||
outBuffer.Reset()
|
||||
}
|
||||
destFileName = filenameFromTemplate[0][1]
|
||||
@@ -110,10 +116,11 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
}
|
||||
if !Quiet {
|
||||
wwlog.Info("backupFile: %v\nwriteFile: %v", backupFile, writeFile)
|
||||
wwlog.Info("Filename: %s\n", destFileName)
|
||||
wwlog.Info("backupFile: %v", backupFile)
|
||||
wwlog.Info("writeFile: %v", writeFile)
|
||||
wwlog.Info("Filename: %s", destFileName)
|
||||
}
|
||||
wwlog.Info("%s", outBuffer.String())
|
||||
wwlog.Output("%s", outBuffer.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -7,10 +7,9 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/warewulf/warewulf/internal/pkg/wwlog"
|
||||
|
||||
"github.com/warewulf/warewulf/internal/pkg/testenv"
|
||||
"github.com/warewulf/warewulf/internal/pkg/warewulfd"
|
||||
"github.com/warewulf/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -24,6 +23,35 @@ overlay name {{ .Overlay }}
|
||||
|
||||
func Test_Overlay_List(t *testing.T) {
|
||||
env := testenv.New(t)
|
||||
env.WriteFile(t, "etc/warewulf/warewulf.conf", `WW_INTERNAL: 43
|
||||
ipaddr: 192.168.0.1/24
|
||||
netmask: 255.255.255.0
|
||||
network: 192.168.0.0
|
||||
warewulf:
|
||||
port: 9873
|
||||
secure: false
|
||||
update interval: 60
|
||||
autobuild overlays: true
|
||||
host overlay: true
|
||||
syslog: true
|
||||
dhcp:
|
||||
enabled: true
|
||||
range start: 192.168.0.100
|
||||
range end: 192.168.0.199
|
||||
tftp:
|
||||
enabled: false
|
||||
nfs:
|
||||
enabled: true
|
||||
export paths:
|
||||
- path: /home
|
||||
export options: rw,sync
|
||||
mount options: defaults
|
||||
mount: true
|
||||
- path: /opt
|
||||
export options: ro,sync,no_root_squash
|
||||
mount options: defaults
|
||||
mount: false`)
|
||||
|
||||
env.WriteFile(t, "etc/warewulf/nodes.conf",
|
||||
`WW_INTERNAL: 45
|
||||
nodeprofiles:
|
||||
|
||||
@@ -23,9 +23,24 @@ var (
|
||||
var FallBackConf = `---
|
||||
defaultnode:
|
||||
runtime overlay:
|
||||
- generic
|
||||
- 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
|
||||
kernel:
|
||||
args: quiet crashkernel=no vga=791 net.naming-scheme=v238
|
||||
init: /sbin/init
|
||||
|
||||
@@ -26,7 +26,7 @@ var (
|
||||
)
|
||||
|
||||
/*
|
||||
Build all overlays (runtime and generic) for a node
|
||||
Build all overlays for a node
|
||||
*/
|
||||
func BuildAllOverlays(nodes []node.NodeInfo) error {
|
||||
for _, n := range nodes {
|
||||
|
||||
@@ -42,7 +42,6 @@ const Systemddir = "usr/lib/systemd/system"
|
||||
const WWOverlaydir = "var/lib/warewulf/overlays"
|
||||
const WWChrootdir = "var/lib/warewulf/chroots"
|
||||
const WWProvisiondir = "srv/warewulf"
|
||||
const WWClientdir = "warewulf"
|
||||
|
||||
// New creates a test environment in a temporary directory and configures
|
||||
// Warewulf to use it.
|
||||
@@ -79,7 +78,7 @@ func New(t *testing.T) (env *TestEnv) {
|
||||
conf.Paths.WWOverlaydir = env.GetPath(WWOverlaydir)
|
||||
conf.Paths.WWChrootdir = env.GetPath(WWChrootdir)
|
||||
conf.Paths.WWProvisiondir = env.GetPath(WWProvisiondir)
|
||||
conf.Paths.WWClientdir = env.GetPath(WWClientdir)
|
||||
conf.Paths.WWClientdir = "/warewulf"
|
||||
|
||||
for _, confPath := range []string{
|
||||
conf.Paths.Sysconfdir,
|
||||
@@ -93,7 +92,6 @@ func New(t *testing.T) (env *TestEnv) {
|
||||
conf.Paths.WWOverlaydir,
|
||||
conf.Paths.WWChrootdir,
|
||||
conf.Paths.WWProvisiondir,
|
||||
conf.Paths.WWClientdir,
|
||||
} {
|
||||
env.MkdirAll(t, confPath)
|
||||
}
|
||||
@@ -138,6 +136,15 @@ func (env *TestEnv) WriteFile(t *testing.T, fileName string, content string) {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
// ImportFile writes the contents of inputFileName to fileName,
|
||||
// creating any necessary intermediate directories relative to the
|
||||
// test environment.
|
||||
func (env *TestEnv) ImportFile(t *testing.T, fileName string, inputFileName string) {
|
||||
buffer, err := os.ReadFile(inputFileName)
|
||||
assert.NoError(t, err)
|
||||
env.WriteFile(t, fileName, string(buffer))
|
||||
}
|
||||
|
||||
// ReadFile returns the content of fileName as converted to a
|
||||
// string.
|
||||
//
|
||||
|
||||
@@ -117,7 +117,7 @@ func DefaultFormatter(logLevel int, rec *LogRecord) string {
|
||||
}
|
||||
}
|
||||
|
||||
if rec.Level == INFO && logLevel == INFO {
|
||||
if (rec.Level == INFO || rec.Level == OUT) && logLevel == INFO {
|
||||
// NOTE: this is a bit strange, but for user-friendliness it makes sense
|
||||
// to not pollute the messages unless something bad happens (by default).
|
||||
// if logLevel > INFO, then level == INFO messages should not be printed anyway,
|
||||
|
||||
112
overlays/NetworkManager/internal/networkmanager_test.go
Normal file
112
overlays/NetworkManager/internal/networkmanager_test.go
Normal file
@@ -0,0 +1,112 @@
|
||||
package networkmanager
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/warewulf/warewulf/internal/app/wwctl/overlay/show"
|
||||
"github.com/warewulf/warewulf/internal/pkg/testenv"
|
||||
"github.com/warewulf/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
func Test_networkmanagerOverlay(t *testing.T) {
|
||||
env := testenv.New(t)
|
||||
defer env.RemoveAll(t)
|
||||
env.ImportFile(t, "etc/warewulf/nodes.conf", "nodes.conf")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/NetworkManager/rootfs/etc/NetworkManager/conf.d/ww4-unmanaged.ww", "../rootfs/etc/NetworkManager/conf.d/ww4-unmanaged.ww")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/NetworkManager/rootfs/etc/NetworkManager/system-connections/ww4-managed.ww", "../rootfs/etc/NetworkManager/system-connections/ww4-managed.ww")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
log string
|
||||
}{
|
||||
{
|
||||
name: "NetworkManager:ww4-unmanaged.ww",
|
||||
args: []string{"--render", "node1", "NetworkManager", "etc/NetworkManager/conf.d/ww4-unmanaged.ww"},
|
||||
log: networkmanager_unmanaged,
|
||||
},
|
||||
{
|
||||
name: "NetworkManager:ww4-managed.ww",
|
||||
args: []string{"--render", "node1", "NetworkManager", "etc/NetworkManager/system-connections/ww4-managed.ww"},
|
||||
log: networkmanager_managed,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cmd := show.GetCommand()
|
||||
cmd.SetArgs(tt.args)
|
||||
stdout := bytes.NewBufferString("")
|
||||
stderr := bytes.NewBufferString("")
|
||||
logbuf := bytes.NewBufferString("")
|
||||
cmd.SetOut(stdout)
|
||||
cmd.SetErr(stderr)
|
||||
wwlog.SetLogWriter(logbuf)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, stdout.String())
|
||||
assert.Empty(t, stderr.String())
|
||||
assert.Equal(t, tt.log, logbuf.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const networkmanager_unmanaged string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: warewulf-unmanaged.conf
|
||||
# This file is autogenerated by warewulf
|
||||
[main]
|
||||
plugins=keyfile
|
||||
|
||||
[keyfile]
|
||||
unmanaged-devices=except:interface-name:wwnet0,except:interface-name:wwnet1,
|
||||
`
|
||||
|
||||
const networkmanager_managed string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: warewulf-default.conf
|
||||
# This file is autogenerated by warewulf
|
||||
[connection]
|
||||
id=default
|
||||
interface-name=wwnet0
|
||||
|
||||
type=ethernet
|
||||
autoconnect=true
|
||||
[ethernet]
|
||||
mac-address=e6:92:39:49:7b:03
|
||||
# bond
|
||||
[ipv4]
|
||||
address=192.168.3.21/24
|
||||
gateway=192.168.3.1
|
||||
method=manual
|
||||
|
||||
[ipv6]
|
||||
addr-gen-mode=stable-privacy
|
||||
method=ignore
|
||||
never-default=true
|
||||
backupFile: true
|
||||
writeFile: true
|
||||
Filename: warewulf-secondary.conf
|
||||
# This file is autogenerated by warewulf
|
||||
[connection]
|
||||
id=secondary
|
||||
interface-name=wwnet1
|
||||
|
||||
type=ethernet
|
||||
autoconnect=true
|
||||
[ethernet]
|
||||
mac-address=9a:77:29:73:14:f1
|
||||
# bond
|
||||
[ipv4]
|
||||
address=192.168.3.22/24
|
||||
gateway=192.168.3.1
|
||||
method=manual
|
||||
dns=8.8.8.8;8.8.4.4;
|
||||
|
||||
[ipv6]
|
||||
addr-gen-mode=stable-privacy
|
||||
method=ignore
|
||||
never-default=true
|
||||
`
|
||||
58
overlays/NetworkManager/internal/nodes.conf
Normal file
58
overlays/NetworkManager/internal/nodes.conf
Normal file
@@ -0,0 +1,58 @@
|
||||
WW_INTERNAL: 45
|
||||
nodeprofiles:
|
||||
empty: {}
|
||||
nodes:
|
||||
node1:
|
||||
profiles:
|
||||
- empty
|
||||
container name: rockylinux-9
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:03
|
||||
ipaddr: 192.168.3.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
secondary:
|
||||
device: wwnet1
|
||||
hwaddr: 9a:77:29:73:14:f1
|
||||
ipaddr: 192.168.3.22
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
tags:
|
||||
DNS1: 8.8.8.8
|
||||
DNS2: 8.8.4.4
|
||||
ipmi:
|
||||
username: user
|
||||
password: password
|
||||
ipaddr: 192.168.4.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.4.1
|
||||
write: "true"
|
||||
disks:
|
||||
/dev/vda:
|
||||
wipe_table: "true"
|
||||
partitions:
|
||||
scratch:
|
||||
should_exist: "true"
|
||||
swap:
|
||||
number: "1"
|
||||
size_mib: "1024"
|
||||
filesystems:
|
||||
/dev/disk/by-partlabel/scratch:
|
||||
format: btrfs
|
||||
path: /scratch
|
||||
wipe_filesystem: "true"
|
||||
/dev/disk/by-partlabel/swap:
|
||||
format: swap
|
||||
path: swap
|
||||
node2:
|
||||
profiles:
|
||||
- empty
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:04
|
||||
ipaddr: 192.168.3.23
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
@@ -1,12 +1,6 @@
|
||||
{{- $host := .BuildHost }}
|
||||
{{- $time := .BuildTime }}
|
||||
{{- $source := .BuildSource }}
|
||||
{{- $filename := print "warewulf-unmanaged.conf" }}
|
||||
{{- file $filename }}
|
||||
# This file is autogenerated by warewulf
|
||||
# Host: {{ $host }}
|
||||
# Time: {{ $time }}
|
||||
# Source: {{ $source }}
|
||||
[main]
|
||||
plugins=keyfile
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
{{- $host := .BuildHost }}
|
||||
{{- $time := .BuildTime }}
|
||||
{{- $source := .BuildSource }}
|
||||
{{- range $connection_id, $netdev := .NetDevs }}
|
||||
{{- $filename := print "warewulf-" $connection_id ".conf" }}
|
||||
{{- file $filename }}
|
||||
# This file is autogenerated by warewulf
|
||||
# Host: {{ $host }}
|
||||
# Time: {{ $time }}
|
||||
# Source: {{ $source }}
|
||||
[connection]
|
||||
id={{ $connection_id }}
|
||||
interface-name={{ $netdev.Device }}
|
||||
@@ -0,0 +1,73 @@
|
||||
package debian_interfaces
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/warewulf/warewulf/internal/app/wwctl/overlay/show"
|
||||
"github.com/warewulf/warewulf/internal/pkg/testenv"
|
||||
"github.com/warewulf/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
func Test_wickedOverlay(t *testing.T) {
|
||||
env := testenv.New(t)
|
||||
defer env.RemoveAll(t)
|
||||
env.ImportFile(t, "etc/warewulf/nodes.conf", "nodes.conf")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/debian.interfaces/rootfs/etc/network/interfaces.d/default.ww", "../rootfs/etc/network/interfaces.d/default.ww")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
log string
|
||||
}{
|
||||
{
|
||||
name: "debian.interfaces",
|
||||
args: []string{"--render", "node1", "debian.interfaces", "etc/network/interfaces.d/default.ww"},
|
||||
log: debian_interfaces,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cmd := show.GetCommand()
|
||||
cmd.SetArgs(tt.args)
|
||||
stdout := bytes.NewBufferString("")
|
||||
stderr := bytes.NewBufferString("")
|
||||
logbuf := bytes.NewBufferString("")
|
||||
cmd.SetOut(stdout)
|
||||
cmd.SetErr(stderr)
|
||||
wwlog.SetLogWriter(logbuf)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, stdout.String())
|
||||
assert.Empty(t, stderr.String())
|
||||
assert.Equal(t, tt.log, logbuf.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const debian_interfaces string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: default
|
||||
# This file is autogenerated by warewulf
|
||||
auto wwnet0
|
||||
allow-hotplug wwnet0
|
||||
iface wwnet0 inet static
|
||||
address 192.168.3.21
|
||||
netmask 255.255.255.0
|
||||
gateway 192.168.3.1
|
||||
mtu
|
||||
backupFile: true
|
||||
writeFile: true
|
||||
Filename: secondary
|
||||
# This file is autogenerated by warewulf
|
||||
auto wwnet1
|
||||
allow-hotplug wwnet1
|
||||
iface wwnet1 inet static
|
||||
address 192.168.3.22
|
||||
netmask 255.255.255.0
|
||||
gateway 192.168.3.1
|
||||
mtu
|
||||
up ifmetric wwnet1 30
|
||||
`
|
||||
58
overlays/debian.interfaces/internal/nodes.conf
Normal file
58
overlays/debian.interfaces/internal/nodes.conf
Normal file
@@ -0,0 +1,58 @@
|
||||
WW_INTERNAL: 45
|
||||
nodeprofiles:
|
||||
empty: {}
|
||||
nodes:
|
||||
node1:
|
||||
profiles:
|
||||
- empty
|
||||
container name: rockylinux-9
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:03
|
||||
ipaddr: 192.168.3.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
secondary:
|
||||
device: wwnet1
|
||||
hwaddr: 9a:77:29:73:14:f1
|
||||
ipaddr: 192.168.3.22
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
tags:
|
||||
DNS1: 8.8.8.8
|
||||
DNS2: 8.8.4.4
|
||||
ipmi:
|
||||
username: user
|
||||
password: password
|
||||
ipaddr: 192.168.4.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.4.1
|
||||
write: "true"
|
||||
disks:
|
||||
/dev/vda:
|
||||
wipe_table: "true"
|
||||
partitions:
|
||||
scratch:
|
||||
should_exist: "true"
|
||||
swap:
|
||||
number: "1"
|
||||
size_mib: "1024"
|
||||
filesystems:
|
||||
/dev/disk/by-partlabel/scratch:
|
||||
format: btrfs
|
||||
path: /scratch
|
||||
wipe_filesystem: "true"
|
||||
/dev/disk/by-partlabel/swap:
|
||||
format: swap
|
||||
path: swap
|
||||
node2:
|
||||
profiles:
|
||||
- empty
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:04
|
||||
ipaddr: 192.168.3.23
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
@@ -1,13 +1,7 @@
|
||||
{{- $host := .BuildHost }}
|
||||
{{- $time := .BuildTime }}
|
||||
{{- $source := .BuildSource }}
|
||||
{{range $devname, $netdev := .ThisNode.NetDevs -}}
|
||||
{{- $filename := print $devname }}
|
||||
{{- file $filename }}
|
||||
# This file is autogenerated by warewulf
|
||||
# Host: {{ $host }}
|
||||
# Time: {{ $time }}
|
||||
# Source: {{ $source }}
|
||||
{{ if $netdev.OnBoot.GetB -}}
|
||||
auto {{$netdev.Device.Get}}
|
||||
{{ end -}}
|
||||
292
overlays/debug/internal/debug_test.go
Normal file
292
overlays/debug/internal/debug_test.go
Normal file
@@ -0,0 +1,292 @@
|
||||
package debug
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/warewulf/warewulf/internal/app/wwctl/overlay/show"
|
||||
"github.com/warewulf/warewulf/internal/pkg/testenv"
|
||||
"github.com/warewulf/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
func Test_debugOverlay(t *testing.T) {
|
||||
variableData := regexp.MustCompile(`(?m)(BuildTime|BuildTimeUnix|BuildSource|DataStore):.*$`)
|
||||
hostname, _ := os.Hostname()
|
||||
|
||||
env := testenv.New(t)
|
||||
defer env.RemoveAll(t)
|
||||
env.ImportFile(t, "etc/warewulf/nodes.conf", "nodes.conf")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/debug/rootfs/warewulf/template-variables.md.ww", "../rootfs/warewulf/template-variables.md.ww")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
log string
|
||||
}{
|
||||
{
|
||||
name: "debug",
|
||||
args: []string{"--render", "node1", "debug", "warewulf/template-variables.md.ww"},
|
||||
log: debug,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cmd := show.GetCommand()
|
||||
cmd.SetArgs(tt.args)
|
||||
stdout := bytes.NewBufferString("")
|
||||
stderr := bytes.NewBufferString("")
|
||||
logbuf := bytes.NewBufferString("")
|
||||
cmd.SetOut(stdout)
|
||||
cmd.SetErr(stderr)
|
||||
wwlog.SetLogWriter(logbuf)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, stdout.String())
|
||||
assert.Empty(t, stderr.String())
|
||||
assert.Equal(t, strings.Replace(tt.log, "%HOSTNAME%", hostname, -1), variableData.ReplaceAllString(logbuf.String(), "${1}: REMOVED_BY_TEST"))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const debug = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: warewulf/template-variables.md
|
||||
# Warewulf template variables
|
||||
|
||||
This Warewulf template serves as a complete example of the variables
|
||||
available to Warewulf templates. It may also be rendered against a
|
||||
node to debug its apparent configuration.
|
||||
|
||||
wwctl overlay show --render $nodename debug /warewulf/template-variables.md.ww
|
||||
|
||||
The template data structure is defined in
|
||||
internal/pkg/overlay/datastructure.go, though it also references
|
||||
data from other structures.
|
||||
|
||||
|
||||
## Node
|
||||
|
||||
- Id: node1
|
||||
- Hostname: node1
|
||||
- Comment:
|
||||
- ClusterName:
|
||||
- ContainerName: rockylinux-9
|
||||
- Ipxe: default
|
||||
- RuntimeOverlay: hosts,ssh.authorized_keys,syncuser
|
||||
- SystemOverlay: wwinit,wwclient,fstab,hostname,ssh.host_keys,issue,resolv,udev.netname,systemd.netname,ifcfg,NetworkManager,debian.interfaces,wicked,ignition
|
||||
- Init: /sbin/init
|
||||
- Root: initramfs
|
||||
- AssetKey:
|
||||
- Discoverable:
|
||||
- Profiles: empty
|
||||
- Tags:
|
||||
- TagsDel:
|
||||
- Keys:
|
||||
- Kernel:
|
||||
- Version:
|
||||
- Override:
|
||||
- Args: quiet crashkernel=no vga=791 net.naming-scheme=v238
|
||||
- Ipmi:
|
||||
- UserName: user
|
||||
- Password: password
|
||||
- Ipaddr: 192.168.4.21
|
||||
- Netmask: 255.255.255.0
|
||||
- Port:
|
||||
- Gateway: 192.168.4.1
|
||||
- Interface:
|
||||
- Write: true
|
||||
- Tags:
|
||||
- TagsDel:
|
||||
- NetDevs[default]:
|
||||
- Type: ethernet
|
||||
- OnBoot: true
|
||||
- Device: wwnet0
|
||||
- Hwaddr: e6:92:39:49:7b:03
|
||||
- Ipaddr: 192.168.3.21
|
||||
- IpCIDR: 192.168.3.21/24
|
||||
- Ipaddr6:
|
||||
- Prefix:
|
||||
- Netmask: 255.255.255.0
|
||||
- Gateway: 192.168.3.1
|
||||
- MTU:
|
||||
- Primary: true
|
||||
- Default:
|
||||
- Tags:
|
||||
- TagsDel:
|
||||
- NetDevs[secondary]:
|
||||
- Type: ethernet
|
||||
- OnBoot: true
|
||||
- Device: wwnet1
|
||||
- Hwaddr: 9a:77:29:73:14:f1
|
||||
- Ipaddr: 192.168.3.22
|
||||
- IpCIDR: 192.168.3.22/24
|
||||
- Ipaddr6:
|
||||
- Prefix:
|
||||
- Netmask: 255.255.255.0
|
||||
- Gateway: 192.168.3.1
|
||||
- MTU:
|
||||
- Primary:
|
||||
- Default:
|
||||
- Tags: DNS1=8.8.8.8 DNS2=8.8.4.4
|
||||
- TagsDel:
|
||||
|
||||
|
||||
## Build variables
|
||||
|
||||
- BuildHost: %HOSTNAME%
|
||||
- BuildTime: REMOVED_BY_TEST
|
||||
- BuildTimeUnix: REMOVED_BY_TEST
|
||||
- BuildSource: REMOVED_BY_TEST
|
||||
- Overlay: debug
|
||||
|
||||
|
||||
## Network
|
||||
|
||||
- Ipaddr:
|
||||
- Ipaddr6:
|
||||
- Netmask:
|
||||
- Network:
|
||||
- NetworkCIDR: <nil>
|
||||
- Ipv6: false
|
||||
|
||||
|
||||
## Services
|
||||
|
||||
### DHCP
|
||||
|
||||
- Dhcp.Enabled: true
|
||||
- Dhcp.Template: default
|
||||
- Dhcp.RangeStart:
|
||||
- Dhcp.RangeEnd:
|
||||
- Dhcp.SystemdName: dhcpd
|
||||
|
||||
|
||||
### NFS
|
||||
|
||||
- Enabled: true
|
||||
- SystemdName: nfsd
|
||||
|
||||
### SSH
|
||||
- Key types:
|
||||
- rsa
|
||||
- dsa
|
||||
- ecdsa
|
||||
- ed25519
|
||||
- First key type: rsa
|
||||
|
||||
### Warewulf
|
||||
|
||||
- Port: 9983
|
||||
- Secure: true
|
||||
- UpdateInterval: 60
|
||||
- AutobuildOverlays: true
|
||||
- EnableHostOverlay: true
|
||||
- Syslog: false
|
||||
- DataStore: REMOVED_BY_TEST
|
||||
|
||||
|
||||
### Other nodes
|
||||
|
||||
- AllNodes[0]:
|
||||
- Id: node1
|
||||
- Comment:
|
||||
- ClusterName:
|
||||
- ContainerName: rockylinux-9
|
||||
- Ipxe: default
|
||||
- RuntimeOverlay: hosts
|
||||
- SystemOverlay: wwinit
|
||||
- Root: initramfs
|
||||
- Discoverable:
|
||||
- Init: /sbin/init
|
||||
- AssetKey:
|
||||
- Profiles: empty
|
||||
- Tags:
|
||||
- Kernel
|
||||
- Override:
|
||||
- Args: quiet crashkernel=no vga=791 net.naming-scheme=v238
|
||||
- Ipmi:
|
||||
- Ipaddr: 192.168.4.21
|
||||
- Netmask: 255.255.255.0
|
||||
- Port:
|
||||
- Gateway: 192.168.4.1
|
||||
- UserName: user
|
||||
- Password: password
|
||||
- Interface:
|
||||
- Write: true
|
||||
- Tags:
|
||||
- NetDevs[default]:
|
||||
- Type: ethernet
|
||||
- OnBoot: true
|
||||
- Device: wwnet0
|
||||
- Hwaddr: e6:92:39:49:7b:03
|
||||
- Ipaddr: 192.168.3.21
|
||||
- Ipaddr6:
|
||||
- IpCIDR:
|
||||
- Prefix:
|
||||
- Netmask: 255.255.255.0
|
||||
- Gateway: 192.168.3.1
|
||||
- MTU:
|
||||
- Primary: true
|
||||
- Tags:
|
||||
- NetDevs[secondary]:
|
||||
- Type: ethernet
|
||||
- OnBoot: true
|
||||
- Device: wwnet1
|
||||
- Hwaddr: 9a:77:29:73:14:f1
|
||||
- Ipaddr: 192.168.3.22
|
||||
- Ipaddr6:
|
||||
- IpCIDR:
|
||||
- Prefix:
|
||||
- Netmask: 255.255.255.0
|
||||
- Gateway: 192.168.3.1
|
||||
- MTU:
|
||||
- Primary:
|
||||
- Tags: DNS1=8.8.8.8 DNS2=8.8.4.4
|
||||
- AllNodes[1]:
|
||||
- Id: node2
|
||||
- Comment:
|
||||
- ClusterName:
|
||||
- ContainerName:
|
||||
- Ipxe: default
|
||||
- RuntimeOverlay: hosts
|
||||
- SystemOverlay: wwinit
|
||||
- Root: initramfs
|
||||
- Discoverable:
|
||||
- Init: /sbin/init
|
||||
- AssetKey:
|
||||
- Profiles: empty
|
||||
- Tags:
|
||||
- Kernel
|
||||
- Override:
|
||||
- Args: quiet crashkernel=no vga=791 net.naming-scheme=v238
|
||||
- Ipmi:
|
||||
- Ipaddr:
|
||||
- Netmask:
|
||||
- Port:
|
||||
- Gateway:
|
||||
- UserName:
|
||||
- Password:
|
||||
- Interface:
|
||||
- Write:
|
||||
- Tags:
|
||||
- NetDevs[default]:
|
||||
- Type: ethernet
|
||||
- OnBoot: true
|
||||
- Device: wwnet0
|
||||
- Hwaddr: e6:92:39:49:7b:04
|
||||
- Ipaddr: 192.168.3.23
|
||||
- Ipaddr6:
|
||||
- IpCIDR:
|
||||
- Prefix:
|
||||
- Netmask: 255.255.255.0
|
||||
- Gateway: 192.168.3.1
|
||||
- MTU:
|
||||
- Primary: true
|
||||
- Tags:
|
||||
|
||||
`
|
||||
58
overlays/debug/internal/nodes.conf
Normal file
58
overlays/debug/internal/nodes.conf
Normal file
@@ -0,0 +1,58 @@
|
||||
WW_INTERNAL: 45
|
||||
nodeprofiles:
|
||||
empty: {}
|
||||
nodes:
|
||||
node1:
|
||||
profiles:
|
||||
- empty
|
||||
container name: rockylinux-9
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:03
|
||||
ipaddr: 192.168.3.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
secondary:
|
||||
device: wwnet1
|
||||
hwaddr: 9a:77:29:73:14:f1
|
||||
ipaddr: 192.168.3.22
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
tags:
|
||||
DNS1: 8.8.8.8
|
||||
DNS2: 8.8.4.4
|
||||
ipmi:
|
||||
username: user
|
||||
password: password
|
||||
ipaddr: 192.168.4.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.4.1
|
||||
write: "true"
|
||||
disks:
|
||||
/dev/vda:
|
||||
wipe_table: "true"
|
||||
partitions:
|
||||
scratch:
|
||||
should_exist: "true"
|
||||
swap:
|
||||
number: "1"
|
||||
size_mib: "1024"
|
||||
filesystems:
|
||||
/dev/disk/by-partlabel/scratch:
|
||||
format: btrfs
|
||||
path: /scratch
|
||||
wipe_filesystem: "true"
|
||||
/dev/disk/by-partlabel/swap:
|
||||
format: swap
|
||||
path: swap
|
||||
node2:
|
||||
profiles:
|
||||
- empty
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:04
|
||||
ipaddr: 192.168.3.23
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
@@ -4,12 +4,10 @@ This Warewulf template serves as a complete example of the variables
|
||||
available to Warewulf templates. It may also be rendered against a
|
||||
node to debug its apparent configuration.
|
||||
|
||||
```sh
|
||||
wwctl overlay show --render $nodename debug /warewulf/template-variables.md.ww
|
||||
```
|
||||
wwctl overlay show --render $nodename debug /warewulf/template-variables.md.ww
|
||||
|
||||
The template data structure is defined in
|
||||
`internal/pkg/overlay/datastructure.go`, though it also references
|
||||
internal/pkg/overlay/datastructure.go, though it also references
|
||||
data from other structures.
|
||||
|
||||
|
||||
|
||||
68
overlays/fstab/internal/fstab_test.go
Normal file
68
overlays/fstab/internal/fstab_test.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package fstab
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/warewulf/warewulf/internal/app/wwctl/overlay/show"
|
||||
"github.com/warewulf/warewulf/internal/pkg/config"
|
||||
"github.com/warewulf/warewulf/internal/pkg/testenv"
|
||||
"github.com/warewulf/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
func Test_fstabOverlay(t *testing.T) {
|
||||
env := testenv.New(t)
|
||||
defer env.RemoveAll(t)
|
||||
env.ImportFile(t, "etc/warewulf/nodes.conf", "nodes.conf")
|
||||
env.ImportFile(t, "etc/warewulf/warewulf.conf", "warewulf.conf")
|
||||
assert.NoError(t, config.Get().Read(env.GetPath("etc/warewulf/warewulf.conf")))
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/fstab/rootfs/etc/fstab.ww", "../rootfs/etc/fstab.ww")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
log string
|
||||
}{
|
||||
{
|
||||
name: "/etc/fstab",
|
||||
args: []string{"--render", "node1", "fstab", "etc/fstab.ww"},
|
||||
log: fstab,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cmd := show.GetCommand()
|
||||
cmd.SetArgs(tt.args)
|
||||
stdout := bytes.NewBufferString("")
|
||||
stderr := bytes.NewBufferString("")
|
||||
logbuf := bytes.NewBufferString("")
|
||||
cmd.SetOut(stdout)
|
||||
cmd.SetErr(stderr)
|
||||
wwlog.SetLogWriter(logbuf)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, stdout.String())
|
||||
assert.Empty(t, stderr.String())
|
||||
assert.Equal(t, tt.log, logbuf.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const fstab string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: etc/fstab
|
||||
# This file is autogenerated by warewulf
|
||||
rootfs / tmpfs defaults 0 0
|
||||
devpts /dev/pts devpts gid=5,mode=620 0 0
|
||||
tmpfs /run/shm tmpfs defaults 0 0
|
||||
sysfs /sys sysfs defaults 0 0
|
||||
proc /proc proc defaults 0 0
|
||||
# mounts for local file systems created with ignition in nodes.conf
|
||||
# all with noauto as mounts happens with systemd units
|
||||
/dev/disk/by-partlabel/scratch /scratch btrfs noauto,defaults 0 0
|
||||
/dev/disk/by-partlabel/swap swap swap noauto,defaults 0 0
|
||||
# nfs mounts provided in warewulf.conf
|
||||
192.168.0.1:/home /home nfs defaults 0 0
|
||||
`
|
||||
58
overlays/fstab/internal/nodes.conf
Normal file
58
overlays/fstab/internal/nodes.conf
Normal file
@@ -0,0 +1,58 @@
|
||||
WW_INTERNAL: 45
|
||||
nodeprofiles:
|
||||
empty: {}
|
||||
nodes:
|
||||
node1:
|
||||
profiles:
|
||||
- empty
|
||||
container name: rockylinux-9
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:03
|
||||
ipaddr: 192.168.3.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
secondary:
|
||||
device: wwnet1
|
||||
hwaddr: 9a:77:29:73:14:f1
|
||||
ipaddr: 192.168.3.22
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
tags:
|
||||
DNS1: 8.8.8.8
|
||||
DNS2: 8.8.4.4
|
||||
ipmi:
|
||||
username: user
|
||||
password: password
|
||||
ipaddr: 192.168.4.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.4.1
|
||||
write: "true"
|
||||
disks:
|
||||
/dev/vda:
|
||||
wipe_table: "true"
|
||||
partitions:
|
||||
scratch:
|
||||
should_exist: "true"
|
||||
swap:
|
||||
number: "1"
|
||||
size_mib: "1024"
|
||||
filesystems:
|
||||
/dev/disk/by-partlabel/scratch:
|
||||
format: btrfs
|
||||
path: /scratch
|
||||
wipe_filesystem: "true"
|
||||
/dev/disk/by-partlabel/swap:
|
||||
format: swap
|
||||
path: swap
|
||||
node2:
|
||||
profiles:
|
||||
- empty
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:04
|
||||
ipaddr: 192.168.3.23
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
28
overlays/fstab/internal/warewulf.conf
Normal file
28
overlays/fstab/internal/warewulf.conf
Normal file
@@ -0,0 +1,28 @@
|
||||
WW_INTERNAL: 43
|
||||
ipaddr: 192.168.0.1/24
|
||||
netmask: 255.255.255.0
|
||||
network: 192.168.0.0
|
||||
warewulf:
|
||||
port: 9873
|
||||
secure: false
|
||||
update interval: 60
|
||||
autobuild overlays: true
|
||||
host overlay: true
|
||||
syslog: true
|
||||
dhcp:
|
||||
enabled: true
|
||||
range start: 192.168.0.100
|
||||
range end: 192.168.0.199
|
||||
tftp:
|
||||
enabled: false
|
||||
nfs:
|
||||
enabled: true
|
||||
export paths:
|
||||
- path: /home
|
||||
export options: rw,sync
|
||||
mount options: defaults
|
||||
mount: true
|
||||
- path: /opt
|
||||
export options: ro,sync,no_root_squash
|
||||
mount options: defaults
|
||||
mount: false
|
||||
@@ -1,7 +1,4 @@
|
||||
# This file is autogenerated by warewulf
|
||||
# Host: {{.BuildHost}}
|
||||
# Time: {{.BuildTime}}
|
||||
# Source: {{.BuildSource}}
|
||||
rootfs / tmpfs defaults 0 0
|
||||
devpts /dev/pts devpts gid=5,mode=620 0 0
|
||||
tmpfs /run/shm tmpfs defaults 0 0
|
||||
@@ -1,17 +0,0 @@
|
||||
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
|
||||
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
|
||||
|
||||
|
||||
|
||||
# Warewulf Server
|
||||
{{$.Ipaddr}} {{$.BuildHost}} warewulf
|
||||
|
||||
{{- range $node := $.AllNodes}} {{/* for each node */}}
|
||||
# Entry for {{$node.Id.Get}}
|
||||
{{- range $devname, $netdev := $node.NetDevs}} {{/* for each network device on the node */}}
|
||||
{{- if $netdev.Ipaddr.Defined}} {{/* if we have an ip address on this network device */}}
|
||||
{{- /* emit the node name as hostname if this is the primary */}}
|
||||
{{$netdev.Ipaddr.Get}} {{if $netdev.Primary.GetB}}{{$node.Id.Get}}{{end}} {{$node.Id.Get}}-{{$devname}} {{if $netdev.Device.Defined}}{{$node.Id.Get}}-{{$netdev.Device.Get}}{{end}}
|
||||
{{- end }}{{/* if ip */}}
|
||||
{{- end }}{{/* for each network device */}}
|
||||
{{- end }}{{/* for each node */}}
|
||||
359
overlays/host/internal/host_test.go
Normal file
359
overlays/host/internal/host_test.go
Normal file
@@ -0,0 +1,359 @@
|
||||
package host
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/warewulf/warewulf/internal/app/wwctl/overlay/show"
|
||||
"github.com/warewulf/warewulf/internal/pkg/config"
|
||||
"github.com/warewulf/warewulf/internal/pkg/testenv"
|
||||
"github.com/warewulf/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
func Test_hostOverlay(t *testing.T) {
|
||||
hostname, _ := os.Hostname()
|
||||
env := testenv.New(t)
|
||||
defer env.RemoveAll(t)
|
||||
env.ImportFile(t, "etc/warewulf/nodes.conf", "nodes.conf")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/host/rootfs/etc/dhcp/dhcpd.conf.ww", "../rootfs/etc/dhcp/dhcpd.conf.ww")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/host/rootfs/etc/dnsmasq.d/ww4-hosts.conf.ww", "../rootfs/etc/dnsmasq.d/ww4-hosts.conf.ww")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/host/rootfs/etc/exports.ww", "../rootfs/etc/exports.ww")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/host/rootfs/etc/hosts.ww", "../rootfs/etc/hosts.ww")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/host/rootfs/etc/profile.d/ssh_setup.csh.ww", "../rootfs/etc/profile.d/ssh_setup.csh.ww")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/host/rootfs/etc/profile.d/ssh_setup.sh.ww", "../rootfs/etc/profile.d/ssh_setup.sh.ww")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
conf string
|
||||
args []string
|
||||
log string
|
||||
header string
|
||||
}{
|
||||
{
|
||||
name: "host:dhcp",
|
||||
conf: "warewulf.conf",
|
||||
args: []string{"--render", "host", "host", "etc/dhcp/dhcpd.conf.ww"},
|
||||
log: host_dhcp,
|
||||
header: "",
|
||||
},
|
||||
{
|
||||
name: "host:dhcp(static)",
|
||||
conf: "warewulf.conf-static",
|
||||
args: []string{"--render", "host", "host", "etc/dhcp/dhcpd.conf.ww"},
|
||||
log: host_dhcp_static,
|
||||
header: "",
|
||||
},
|
||||
{
|
||||
name: "host:dnsmasq",
|
||||
conf: "warewulf.conf",
|
||||
args: []string{"--render", "host", "host", "etc/dnsmasq.d/ww4-hosts.conf.ww"},
|
||||
log: host_dnsmasq,
|
||||
header: "",
|
||||
},
|
||||
{
|
||||
name: "host:/etc/exports",
|
||||
conf: "",
|
||||
args: []string{"--render", "host", "host", "etc/exports.ww"},
|
||||
log: host_exports,
|
||||
header: "",
|
||||
},
|
||||
{
|
||||
name: "host:/etc/hosts",
|
||||
args: []string{"--render", "host", "host", "etc/hosts.ww"},
|
||||
log: host_hosts,
|
||||
header: "# Do not edit after this line",
|
||||
},
|
||||
{
|
||||
name: "host:ssh_setup.csh",
|
||||
conf: "",
|
||||
args: []string{"--render", "host", "host", "etc/profile.d/ssh_setup.csh.ww"},
|
||||
log: host_ssh_setup_csh,
|
||||
header: "",
|
||||
},
|
||||
{
|
||||
name: "host:ssh_setup.sh",
|
||||
conf: "",
|
||||
args: []string{"--render", "host", "host", "etc/profile.d/ssh_setup.sh.ww"},
|
||||
log: host_ssh_setup_sh,
|
||||
header: "",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.conf != "" {
|
||||
env.ImportFile(t, "etc/warewulf/warewulf.conf", tt.conf)
|
||||
assert.NoError(t, config.Get().Read(env.GetPath("etc/warewulf/warewulf.conf")))
|
||||
}
|
||||
cmd := show.GetCommand()
|
||||
cmd.SetArgs(tt.args)
|
||||
stdout := bytes.NewBufferString("")
|
||||
stderr := bytes.NewBufferString("")
|
||||
logbuf := bytes.NewBufferString("")
|
||||
cmd.SetOut(stdout)
|
||||
cmd.SetErr(stderr)
|
||||
wwlog.SetLogWriter(logbuf)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, stdout.String())
|
||||
assert.Empty(t, stderr.String())
|
||||
var log string
|
||||
if tt.header != "" {
|
||||
log = skipHeader(t, logbuf.String(), tt.header)
|
||||
} else {
|
||||
log = logbuf.String()
|
||||
}
|
||||
assert.Equal(t, strings.Replace(tt.log, "%HOSTNAME%", hostname, -1), log)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func skipHeader(t *testing.T, log string, header string) (newlog string) {
|
||||
newlog = ""
|
||||
found := false
|
||||
for _, line := range strings.SplitAfter(log, "\n") {
|
||||
if strings.Contains(line, header) {
|
||||
found = true
|
||||
}
|
||||
if found || strings.HasPrefix(line, "backupFile:") || strings.HasPrefix(line, "writeFile:") || strings.HasPrefix(line, "Filename:") {
|
||||
newlog = newlog + line
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const host_dhcp string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: etc/dhcp/dhcpd.conf
|
||||
# This file is autogenerated by warewulf
|
||||
|
||||
allow booting;
|
||||
allow bootp;
|
||||
ddns-update-style interim;
|
||||
authoritative;
|
||||
|
||||
option space ipxe;
|
||||
|
||||
# Tell iPXE to not wait for ProxyDHCP requests to speed up boot.
|
||||
option ipxe.no-pxedhcp code 176 = unsigned integer 8;
|
||||
option ipxe.no-pxedhcp 1;
|
||||
|
||||
option space PXE;
|
||||
option PXE.mtftp-ip code 1 = ip-address;
|
||||
option PXE.mtftp-cport code 2 = unsigned integer 16;
|
||||
option PXE.mtftp-sport code 3 = unsigned integer 16;
|
||||
option PXE.mtftp-tmout code 4 = unsigned integer 8;
|
||||
option PXE.mtftp-delay code 5 = unsigned integer 8;
|
||||
|
||||
option architecture-type code 93 = unsigned integer 16;
|
||||
if exists user-class and option user-class = "iPXE" {
|
||||
filename "http://192.168.0.1:9873/ipxe/${mac:hexhyp}?assetkey=${asset}&uuid=${uuid}";
|
||||
} else {
|
||||
|
||||
if option architecture-type = 00:00 {
|
||||
filename "/warewulf/undionly.kpxe";
|
||||
}
|
||||
if option architecture-type = 00:07 {
|
||||
filename "/warewulf/ipxe-snponly-x86_64.efi";
|
||||
}
|
||||
if option architecture-type = 00:09 {
|
||||
filename "/warewulf/ipxe-snponly-x86_64.efi";
|
||||
}
|
||||
if option architecture-type = 00:0B {
|
||||
filename "/warewulf/snponly.efi";
|
||||
}
|
||||
}
|
||||
|
||||
subnet 192.168.0.0 netmask 255.255.255.0 {
|
||||
max-lease-time 120;
|
||||
range 192.168.0.100 192.168.0.199;
|
||||
next-server 192.168.0.1;
|
||||
}
|
||||
`
|
||||
|
||||
const host_dhcp_static string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: etc/dhcp/dhcpd.conf
|
||||
# This file is autogenerated by warewulf
|
||||
|
||||
allow booting;
|
||||
allow bootp;
|
||||
ddns-update-style interim;
|
||||
authoritative;
|
||||
|
||||
option space ipxe;
|
||||
|
||||
# Tell iPXE to not wait for ProxyDHCP requests to speed up boot.
|
||||
option ipxe.no-pxedhcp code 176 = unsigned integer 8;
|
||||
option ipxe.no-pxedhcp 1;
|
||||
|
||||
option space PXE;
|
||||
option PXE.mtftp-ip code 1 = ip-address;
|
||||
option PXE.mtftp-cport code 2 = unsigned integer 16;
|
||||
option PXE.mtftp-sport code 3 = unsigned integer 16;
|
||||
option PXE.mtftp-tmout code 4 = unsigned integer 8;
|
||||
option PXE.mtftp-delay code 5 = unsigned integer 8;
|
||||
|
||||
option architecture-type code 93 = unsigned integer 16;
|
||||
if exists user-class and option user-class = "iPXE" {
|
||||
filename "http://192.168.0.1:9873/ipxe/${mac:hexhyp}?assetkey=${asset}&uuid=${uuid}";
|
||||
} else {
|
||||
|
||||
if option architecture-type = 00:00 {
|
||||
filename "/warewulf/undionly.kpxe";
|
||||
}
|
||||
if option architecture-type = 00:07 {
|
||||
filename "/warewulf/ipxe-snponly-x86_64.efi";
|
||||
}
|
||||
if option architecture-type = 00:09 {
|
||||
filename "/warewulf/ipxe-snponly-x86_64.efi";
|
||||
}
|
||||
if option architecture-type = 00:0B {
|
||||
filename "/warewulf/snponly.efi";
|
||||
}
|
||||
}
|
||||
|
||||
subnet 192.168.0.0 netmask 255.255.255.0 {
|
||||
max-lease-time 120;
|
||||
}
|
||||
host node1-default
|
||||
{
|
||||
hardware ethernet e6:92:39:49:7b:03;
|
||||
fixed-address 192.168.3.21;
|
||||
option host-name "node1";
|
||||
}
|
||||
|
||||
host node1-secondary
|
||||
{
|
||||
hardware ethernet 9a:77:29:73:14:f1;
|
||||
fixed-address 192.168.3.22;
|
||||
}
|
||||
|
||||
|
||||
host node2-default
|
||||
{
|
||||
hardware ethernet e6:92:39:49:7b:04;
|
||||
fixed-address 192.168.3.23;
|
||||
option host-name "node2";
|
||||
}
|
||||
|
||||
|
||||
|
||||
`
|
||||
|
||||
const host_dnsmasq string = `backupFile: false
|
||||
writeFile: true
|
||||
Filename: etc/dnsmasq.d/ww4-hosts.conf
|
||||
# This file was autgenerated by warewulf
|
||||
|
||||
# select the x86 hosts which will get the iXPE binary
|
||||
dhcp-match=set:bios,option:client-arch,0 #legacy boot
|
||||
dhcp-match=set:x86PC,option:client-arch, 7 #EFI x86-64
|
||||
dhcp-match=set:x86PC,option:client-arch, 6 #EFI x86-64
|
||||
dhcp-match=set:x86PC,option:client-arch, 9 #EFI x86-64
|
||||
dhcp-match=set:aarch64,option:client-arch, 11 #EFI aarch64
|
||||
dhcp-match=set:iPXE,77,"iPXE"
|
||||
dhcp-userclass=set:iPXE,iPXE
|
||||
dhcp-vendorclass=set:efi-http,HTTPClient:Arch:00016
|
||||
dhcp-option-force=tag:efi-http,60,HTTPClient
|
||||
# for http boot always use shim/grub
|
||||
dhcp-boot=tag:efi-http,"http://192.168.0.1:9873/efiboot/shim.efi"
|
||||
dhcp-boot=tag:x86PC,"/warewulf/ipxe-snponly-x86_64.efi"
|
||||
dhcp-boot=tag:aarch64,"/warewulf/arm64-efi/snponly.efi"
|
||||
# iPXE binary will get the following configuration file
|
||||
dhcp-boot=tag:iPXE,"http://192.168.0.1:9873/ipxe/${mac:hexhyp}?assetkey=${asset}&uuid=${uuid}"
|
||||
dhcp-no-override
|
||||
# define the the range
|
||||
dhcp-range=192.168.0.100,192.168.0.199,255.255.255.0,6h
|
||||
|
||||
dhcp-host=e6:92:39:49:7b:03,set:warewulf,node1,192.168.3.21,infinite
|
||||
dhcp-host=9a:77:29:73:14:f1,set:warewulf,node1,192.168.3.22,infinite
|
||||
dhcp-host=e6:92:39:49:7b:04,set:warewulf,node2,192.168.3.23,infinite
|
||||
`
|
||||
|
||||
const host_exports string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: etc/exports
|
||||
|
||||
# This file is autogenerated by warewulf
|
||||
/home 192.168.0.0/255.255.255.0(rw,sync)
|
||||
/opt 192.168.0.0/255.255.255.0(ro,sync,no_root_squash)
|
||||
|
||||
`
|
||||
|
||||
const host_hosts string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: etc/hosts
|
||||
# Do not edit after this line
|
||||
# This block is autogenerated by warewulf
|
||||
|
||||
|
||||
# Warewulf Server
|
||||
192.168.0.1 %HOSTNAME% warewulf
|
||||
# Entry for node1
|
||||
192.168.3.21 node1 node1-default node1-wwnet0
|
||||
192.168.3.22 node1-secondary node1-wwnet1
|
||||
# Entry for node2
|
||||
192.168.3.23 node2 node2-default node2-wwnet0
|
||||
`
|
||||
|
||||
const host_ssh_setup_csh = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: etc/profile.d/ssh_setup.csh
|
||||
#!/bin/csh
|
||||
|
||||
## Automatically configure SSH keys for a user on C SHell login
|
||||
## Copy this file to /etc/profile.d along with ssh_setup.sh
|
||||
|
||||
` + "set _UID=`id -u`" + `
|
||||
if ( ( $_UID > 500 || $_UID == 0 ) && ( ! -f "$HOME/.ssh/config" && ! -f "$HOME/.ssh/cluster" ) ) then
|
||||
echo "Configuring SSH for cluster access"
|
||||
install -d -m 700 $HOME/.ssh
|
||||
ssh-keygen -t rsa -f $HOME/.ssh/cluster -N '' -C "Warewulf Cluster key" >& /dev/null
|
||||
cat $HOME/.ssh/cluster.pub >>! $HOME/.ssh/authorized_keys
|
||||
chmod 0600 $HOME/.ssh/authorized_keys
|
||||
|
||||
touch $HOME/.ssh/config
|
||||
echo -n "# Added by Warewulf " >>! $HOME/.ssh/config
|
||||
(date +%Y-%m-%d >> $HOME/.ssh/config) >& /dev/null
|
||||
echo "Host *" >> $HOME/.ssh/config
|
||||
echo " IdentityFile ~/.ssh/cluster" >> $HOME/.ssh/config
|
||||
echo " StrictHostKeyChecking=no" >> $HOME/.ssh/config
|
||||
chmod 0600 $HOME/.ssh/config
|
||||
endif
|
||||
`
|
||||
|
||||
const host_ssh_setup_sh = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: etc/profile.d/ssh_setup.sh
|
||||
#!/bin/sh
|
||||
##
|
||||
## Copyright (c) 2001-2003 Gregory M. Kurtzer
|
||||
##
|
||||
## Copyright (c) 2003-2012, The Regents of the University of California,
|
||||
## through Lawrence Berkeley National Laboratory (subject to receipt of any
|
||||
## required approvals from the U.S. Dept. of Energy). All rights reserved.
|
||||
##
|
||||
## Copied from https://github.com/warewulf/warewulf3/blob/master/cluster/bin/cluster-env
|
||||
|
||||
## Automatically configure SSH keys for a user on login
|
||||
## Copy this file to /etc/profile.d
|
||||
|
||||
` + "_UID=`id -u`" + `
|
||||
if [ $_UID -ge 500 -o $_UID -eq 0 ] && [ ! -f "$HOME/.ssh/config" -a ! -f "$HOME/.ssh/cluster" ]; then
|
||||
echo "Configuring SSH for cluster access"
|
||||
install -d -m 700 $HOME/.ssh
|
||||
ssh-keygen -t rsa -f $HOME/.ssh/cluster -N '' -C "Warewulf Cluster key" > /dev/null 2>&1
|
||||
cat $HOME/.ssh/cluster.pub >> $HOME/.ssh/authorized_keys
|
||||
chmod 0600 $HOME/.ssh/authorized_keys
|
||||
|
||||
echo "# Added by Warewulf ` + "`date +%Y-%m-%d 2>/dev/null`" + `" >> $HOME/.ssh/config
|
||||
echo "Host *" >> $HOME/.ssh/config
|
||||
echo " IdentityFile ~/.ssh/cluster" >> $HOME/.ssh/config
|
||||
echo " StrictHostKeyChecking=no" >> $HOME/.ssh/config
|
||||
chmod 0600 $HOME/.ssh/config
|
||||
fi
|
||||
`
|
||||
58
overlays/host/internal/nodes.conf
Normal file
58
overlays/host/internal/nodes.conf
Normal file
@@ -0,0 +1,58 @@
|
||||
WW_INTERNAL: 45
|
||||
nodeprofiles:
|
||||
empty: {}
|
||||
nodes:
|
||||
node1:
|
||||
profiles:
|
||||
- empty
|
||||
container name: rockylinux-9
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:03
|
||||
ipaddr: 192.168.3.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
secondary:
|
||||
device: wwnet1
|
||||
hwaddr: 9a:77:29:73:14:f1
|
||||
ipaddr: 192.168.3.22
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
tags:
|
||||
DNS1: 8.8.8.8
|
||||
DNS2: 8.8.4.4
|
||||
ipmi:
|
||||
username: user
|
||||
password: password
|
||||
ipaddr: 192.168.4.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.4.1
|
||||
write: "true"
|
||||
disks:
|
||||
/dev/vda:
|
||||
wipe_table: "true"
|
||||
partitions:
|
||||
scratch:
|
||||
should_exist: "true"
|
||||
swap:
|
||||
number: "1"
|
||||
size_mib: "1024"
|
||||
filesystems:
|
||||
/dev/disk/by-partlabel/scratch:
|
||||
format: btrfs
|
||||
path: /scratch
|
||||
wipe_filesystem: "true"
|
||||
/dev/disk/by-partlabel/swap:
|
||||
format: swap
|
||||
path: swap
|
||||
node2:
|
||||
profiles:
|
||||
- empty
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:04
|
||||
ipaddr: 192.168.3.23
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
28
overlays/host/internal/warewulf.conf
Normal file
28
overlays/host/internal/warewulf.conf
Normal file
@@ -0,0 +1,28 @@
|
||||
WW_INTERNAL: 43
|
||||
ipaddr: 192.168.0.1/24
|
||||
netmask: 255.255.255.0
|
||||
network: 192.168.0.0
|
||||
warewulf:
|
||||
port: 9873
|
||||
secure: false
|
||||
update interval: 60
|
||||
autobuild overlays: true
|
||||
host overlay: true
|
||||
syslog: true
|
||||
dhcp:
|
||||
enabled: true
|
||||
range start: 192.168.0.100
|
||||
range end: 192.168.0.199
|
||||
tftp:
|
||||
enabled: false
|
||||
nfs:
|
||||
enabled: true
|
||||
export paths:
|
||||
- path: /home
|
||||
export options: rw,sync
|
||||
mount options: defaults
|
||||
mount: true
|
||||
- path: /opt
|
||||
export options: ro,sync,no_root_squash
|
||||
mount options: defaults
|
||||
mount: false
|
||||
27
overlays/host/internal/warewulf.conf-static
Normal file
27
overlays/host/internal/warewulf.conf-static
Normal file
@@ -0,0 +1,27 @@
|
||||
WW_INTERNAL: 43
|
||||
ipaddr: 192.168.0.1/24
|
||||
netmask: 255.255.255.0
|
||||
network: 192.168.0.0
|
||||
warewulf:
|
||||
port: 9873
|
||||
secure: false
|
||||
update interval: 60
|
||||
autobuild overlays: true
|
||||
host overlay: true
|
||||
syslog: true
|
||||
dhcp:
|
||||
enabled: true
|
||||
template: static
|
||||
tftp:
|
||||
enabled: false
|
||||
nfs:
|
||||
enabled: true
|
||||
export paths:
|
||||
- path: /home
|
||||
export options: rw,sync
|
||||
mount options: defaults
|
||||
mount: true
|
||||
- path: /opt
|
||||
export options: ro,sync,no_root_squash
|
||||
mount options: defaults
|
||||
mount: false
|
||||
@@ -1,8 +1,5 @@
|
||||
{{if $.Dhcp.Enabled -}}
|
||||
# This file is autogenerated by warewulf
|
||||
# Host: {{.BuildHost}}
|
||||
# Time: {{.BuildTime}}
|
||||
# Source: {{.BuildSource}}
|
||||
|
||||
allow booting;
|
||||
allow bootp;
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
# This file was autgenerated by warewulf
|
||||
# Host: {{.BuildHost}}
|
||||
# Time: {{.BuildTime}}
|
||||
# Source {{.BuildSource}}
|
||||
{{ nobackup }}
|
||||
# select the x86 hosts which will get the iXPE binary
|
||||
dhcp-match=set:bios,option:client-arch,0 #legacy boot
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
{{- if .Nfs.Enabled }}
|
||||
# This file is autogenerated by warewulf
|
||||
# Host: {{.BuildHost}}
|
||||
# Time: {{.BuildTime}}
|
||||
# Source: {{.BuildSource}}
|
||||
{{- $network := .Network }}
|
||||
{{- $netmask := .Netmask }}
|
||||
{{- range .Nfs.ExportsExtended }}
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
{{ IncludeBlock "/etc/hosts" "# Do not edit after this line" }}
|
||||
# This block is autogenerated by warewulf
|
||||
# Host: {{.BuildHost}}
|
||||
# Time: {{.BuildTime}}
|
||||
# Source: {{.BuildSource}}
|
||||
|
||||
|
||||
# Warewulf Server
|
||||
{{$.Ipaddr}} {{$.BuildHost}} warewulf
|
||||
|
||||
{{- range $node := $.AllNodes}} {{/* for each node */}}
|
||||
# Entry for {{$node.Id.Get}}
|
||||
{{- range $devname, $netdev := $node.NetDevs}} {{/* for each network device on the node */}}
|
||||
{{- if $netdev.Ipaddr.Defined}} {{/* if we have an ip address on this network device */}}
|
||||
{{- range $node := $.AllNodes }}{{/* for each node */}}
|
||||
# Entry for {{ $node.Id.Get }}
|
||||
{{- range $devname, $netdev := $node.NetDevs }}{{/* for each network device on the node */}}
|
||||
{{- if $netdev.Ipaddr.Defined }}{{/* if we have an ip address on this network device */}}
|
||||
{{- /* emit the node name as hostname if this is the primary */}}
|
||||
{{$netdev.Ipaddr.Get}} {{if $netdev.Primary.GetB}}{{$node.Id.Get}}{{end}} {{$node.Id.Get}}-{{$devname}} {{if $netdev.Device.Defined}}{{$node.Id.Get}}-{{$netdev.Device.Get}}{{end}}
|
||||
{{- end }}{{/* if ip */}}
|
||||
|
||||
54
overlays/hostname/internal/hostname_test.go
Normal file
54
overlays/hostname/internal/hostname_test.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package hostname
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/warewulf/warewulf/internal/app/wwctl/overlay/show"
|
||||
"github.com/warewulf/warewulf/internal/pkg/testenv"
|
||||
"github.com/warewulf/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
func Test_hostnameOverlay(t *testing.T) {
|
||||
env := testenv.New(t)
|
||||
defer env.RemoveAll(t)
|
||||
env.ImportFile(t, "etc/warewulf/nodes.conf", "nodes.conf")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/hostname/rootfs/etc/hostname.ww", "../rootfs/etc/hostname.ww")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
log string
|
||||
}{
|
||||
{
|
||||
name: "/etc/hostname",
|
||||
args: []string{"--render", "node1", "hostname", "etc/hostname.ww"},
|
||||
log: hostname,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cmd := show.GetCommand()
|
||||
cmd.SetArgs(tt.args)
|
||||
stdout := bytes.NewBufferString("")
|
||||
stderr := bytes.NewBufferString("")
|
||||
logbuf := bytes.NewBufferString("")
|
||||
cmd.SetOut(stdout)
|
||||
cmd.SetErr(stderr)
|
||||
wwlog.SetLogWriter(logbuf)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, stdout.String())
|
||||
assert.Empty(t, stderr.String())
|
||||
assert.Equal(t, tt.log, logbuf.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const hostname string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: etc/hostname
|
||||
node1
|
||||
`
|
||||
58
overlays/hostname/internal/nodes.conf
Normal file
58
overlays/hostname/internal/nodes.conf
Normal file
@@ -0,0 +1,58 @@
|
||||
WW_INTERNAL: 45
|
||||
nodeprofiles:
|
||||
empty: {}
|
||||
nodes:
|
||||
node1:
|
||||
profiles:
|
||||
- empty
|
||||
container name: rockylinux-9
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:03
|
||||
ipaddr: 192.168.3.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
secondary:
|
||||
device: wwnet1
|
||||
hwaddr: 9a:77:29:73:14:f1
|
||||
ipaddr: 192.168.3.22
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
tags:
|
||||
DNS1: 8.8.8.8
|
||||
DNS2: 8.8.4.4
|
||||
ipmi:
|
||||
username: user
|
||||
password: password
|
||||
ipaddr: 192.168.4.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.4.1
|
||||
write: "true"
|
||||
disks:
|
||||
/dev/vda:
|
||||
wipe_table: "true"
|
||||
partitions:
|
||||
scratch:
|
||||
should_exist: "true"
|
||||
swap:
|
||||
number: "1"
|
||||
size_mib: "1024"
|
||||
filesystems:
|
||||
/dev/disk/by-partlabel/scratch:
|
||||
format: btrfs
|
||||
path: /scratch
|
||||
wipe_filesystem: "true"
|
||||
/dev/disk/by-partlabel/swap:
|
||||
format: swap
|
||||
path: swap
|
||||
node2:
|
||||
profiles:
|
||||
- empty
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:04
|
||||
ipaddr: 192.168.3.23
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
70
overlays/hosts/internal/hosts_test.go
Normal file
70
overlays/hosts/internal/hosts_test.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package hosts
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/warewulf/warewulf/internal/app/wwctl/overlay/show"
|
||||
"github.com/warewulf/warewulf/internal/pkg/config"
|
||||
"github.com/warewulf/warewulf/internal/pkg/testenv"
|
||||
"github.com/warewulf/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
func Test_hostsOverlay(t *testing.T) {
|
||||
hostname, _ := os.Hostname()
|
||||
env := testenv.New(t)
|
||||
defer env.RemoveAll(t)
|
||||
env.ImportFile(t, "etc/warewulf/warewulf.conf", "warewulf.conf")
|
||||
assert.NoError(t, config.Get().Read(env.GetPath("etc/warewulf/warewulf.conf")))
|
||||
env.ImportFile(t, "etc/warewulf/nodes.conf", "nodes.conf")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/hosts/rootfs/etc/hosts.ww", "../rootfs/etc/hosts.ww")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
log string
|
||||
}{
|
||||
{
|
||||
name: "/etc/hosts",
|
||||
args: []string{"--render", "node1", "hosts", "etc/hosts.ww"},
|
||||
log: hosts,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cmd := show.GetCommand()
|
||||
cmd.SetArgs(tt.args)
|
||||
stdout := bytes.NewBufferString("")
|
||||
stderr := bytes.NewBufferString("")
|
||||
logbuf := bytes.NewBufferString("")
|
||||
cmd.SetOut(stdout)
|
||||
cmd.SetErr(stderr)
|
||||
wwlog.SetLogWriter(logbuf)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, stdout.String())
|
||||
assert.Empty(t, stderr.String())
|
||||
assert.Equal(t, strings.Replace(tt.log, "%HOSTNAME%", hostname, -1), logbuf.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const hosts string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: etc/hosts
|
||||
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
|
||||
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
|
||||
|
||||
# Warewulf Server
|
||||
192.168.0.1 %HOSTNAME% warewulf
|
||||
# Entry for node1
|
||||
192.168.3.21 node1 node1-default node1-wwnet0
|
||||
192.168.3.22 node1-secondary node1-wwnet1
|
||||
# Entry for node2
|
||||
192.168.3.23 node2 node2-default node2-wwnet0
|
||||
`
|
||||
58
overlays/hosts/internal/nodes.conf
Normal file
58
overlays/hosts/internal/nodes.conf
Normal file
@@ -0,0 +1,58 @@
|
||||
WW_INTERNAL: 45
|
||||
nodeprofiles:
|
||||
empty: {}
|
||||
nodes:
|
||||
node1:
|
||||
profiles:
|
||||
- empty
|
||||
container name: rockylinux-9
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:03
|
||||
ipaddr: 192.168.3.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
secondary:
|
||||
device: wwnet1
|
||||
hwaddr: 9a:77:29:73:14:f1
|
||||
ipaddr: 192.168.3.22
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
tags:
|
||||
DNS1: 8.8.8.8
|
||||
DNS2: 8.8.4.4
|
||||
ipmi:
|
||||
username: user
|
||||
password: password
|
||||
ipaddr: 192.168.4.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.4.1
|
||||
write: "true"
|
||||
disks:
|
||||
/dev/vda:
|
||||
wipe_table: "true"
|
||||
partitions:
|
||||
scratch:
|
||||
should_exist: "true"
|
||||
swap:
|
||||
number: "1"
|
||||
size_mib: "1024"
|
||||
filesystems:
|
||||
/dev/disk/by-partlabel/scratch:
|
||||
format: btrfs
|
||||
path: /scratch
|
||||
wipe_filesystem: "true"
|
||||
/dev/disk/by-partlabel/swap:
|
||||
format: swap
|
||||
path: swap
|
||||
node2:
|
||||
profiles:
|
||||
- empty
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:04
|
||||
ipaddr: 192.168.3.23
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
28
overlays/hosts/internal/warewulf.conf
Normal file
28
overlays/hosts/internal/warewulf.conf
Normal file
@@ -0,0 +1,28 @@
|
||||
WW_INTERNAL: 43
|
||||
ipaddr: 192.168.0.1/24
|
||||
netmask: 255.255.255.0
|
||||
network: 192.168.0.0
|
||||
warewulf:
|
||||
port: 9873
|
||||
secure: false
|
||||
update interval: 60
|
||||
autobuild overlays: true
|
||||
host overlay: true
|
||||
syslog: true
|
||||
dhcp:
|
||||
enabled: true
|
||||
range start: 192.168.0.100
|
||||
range end: 192.168.0.199
|
||||
tftp:
|
||||
enabled: false
|
||||
nfs:
|
||||
enabled: true
|
||||
export paths:
|
||||
- path: /home
|
||||
export options: rw,sync
|
||||
mount options: defaults
|
||||
mount: true
|
||||
- path: /opt
|
||||
export options: ro,sync,no_root_squash
|
||||
mount options: defaults
|
||||
mount: false
|
||||
14
overlays/hosts/rootfs/etc/hosts.ww
Normal file
14
overlays/hosts/rootfs/etc/hosts.ww
Normal file
@@ -0,0 +1,14 @@
|
||||
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
|
||||
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
|
||||
|
||||
# Warewulf Server
|
||||
{{$.Ipaddr}} {{$.BuildHost}} warewulf
|
||||
|
||||
{{- range $node := $.AllNodes }}
|
||||
# Entry for {{$node.Id.Get}}
|
||||
{{- range $devname, $netdev := $node.NetDevs }}
|
||||
{{- if $netdev.Ipaddr.Defined }}
|
||||
{{$netdev.Ipaddr.Get}} {{if $netdev.Primary.GetB}}{{$node.Id.Get}}{{end}} {{$node.Id.Get}}-{{$devname}} {{if $netdev.Device.Defined}}{{$node.Id.Get}}-{{$netdev.Device.Get}}{{end}}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
103
overlays/ifcfg/internal/ifcfg_test.go
Normal file
103
overlays/ifcfg/internal/ifcfg_test.go
Normal file
@@ -0,0 +1,103 @@
|
||||
package ifcfg
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/warewulf/warewulf/internal/app/wwctl/overlay/show"
|
||||
"github.com/warewulf/warewulf/internal/pkg/testenv"
|
||||
"github.com/warewulf/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
func Test_ifcfgOverlay(t *testing.T) {
|
||||
env := testenv.New(t)
|
||||
defer env.RemoveAll(t)
|
||||
env.ImportFile(t, "etc/warewulf/nodes.conf", "nodes.conf")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/ifcfg/rootfs/etc/sysconfig/network-scripts/ifcfg.ww", "../rootfs/etc/sysconfig/network-scripts/ifcfg.ww")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/ifcfg/rootfs/etc/sysconfig/network.ww", "../rootfs/etc/sysconfig/network.ww")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
log string
|
||||
}{
|
||||
{
|
||||
name: "ifcfg:ifcfg.ww",
|
||||
args: []string{"--render", "node1", "ifcfg", "etc/sysconfig/network-scripts/ifcfg.ww"},
|
||||
log: ifcfg,
|
||||
},
|
||||
{
|
||||
name: "ifcfg:network.ww",
|
||||
args: []string{"--render", "node1", "ifcfg", "etc/sysconfig/network.ww"},
|
||||
log: ifcfg_network,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cmd := show.GetCommand()
|
||||
cmd.SetArgs(tt.args)
|
||||
stdout := bytes.NewBufferString("")
|
||||
stderr := bytes.NewBufferString("")
|
||||
logbuf := bytes.NewBufferString("")
|
||||
cmd.SetOut(stdout)
|
||||
cmd.SetErr(stderr)
|
||||
wwlog.SetLogWriter(logbuf)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, stdout.String())
|
||||
assert.Empty(t, stderr.String())
|
||||
assert.Equal(t, tt.log, logbuf.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const ifcfg string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: ifcfg-default.conf
|
||||
# This file is autogenerated by warewulf
|
||||
TYPE=ethernet
|
||||
DEVICE=wwnet0
|
||||
NAME=default
|
||||
BOOTPROTO=static
|
||||
DEVTIMEOUT=10
|
||||
IPADDR=192.168.3.21
|
||||
NETMASK=255.255.255.0
|
||||
GATEWAY=192.168.3.1
|
||||
HWADDR=e6:92:39:49:7b:03
|
||||
TYPE=ethernet
|
||||
ONBOOT=true
|
||||
IPV6INIT=yes
|
||||
IPV6_AUTOCONF=yes
|
||||
IPV6_DEFROUTE=yes
|
||||
IPV6_FAILURE_FATAL=no
|
||||
backupFile: true
|
||||
writeFile: true
|
||||
Filename: ifcfg-secondary.conf
|
||||
# This file is autogenerated by warewulf
|
||||
TYPE=ethernet
|
||||
DEVICE=wwnet1
|
||||
NAME=secondary
|
||||
BOOTPROTO=static
|
||||
DEVTIMEOUT=10
|
||||
IPADDR=192.168.3.22
|
||||
NETMASK=255.255.255.0
|
||||
GATEWAY=192.168.3.1
|
||||
HWADDR=9a:77:29:73:14:f1
|
||||
TYPE=ethernet
|
||||
ONBOOT=true
|
||||
IPV6INIT=yes
|
||||
IPV6_AUTOCONF=yes
|
||||
IPV6_DEFROUTE=yes
|
||||
IPV6_FAILURE_FATAL=no
|
||||
DNS1=8.8.8.8
|
||||
DNS2=8.8.4.4
|
||||
`
|
||||
|
||||
const ifcfg_network string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: etc/sysconfig/network
|
||||
NETWORKING=yes
|
||||
HOSTNAME=node1
|
||||
`
|
||||
58
overlays/ifcfg/internal/nodes.conf
Normal file
58
overlays/ifcfg/internal/nodes.conf
Normal file
@@ -0,0 +1,58 @@
|
||||
WW_INTERNAL: 45
|
||||
nodeprofiles:
|
||||
empty: {}
|
||||
nodes:
|
||||
node1:
|
||||
profiles:
|
||||
- empty
|
||||
container name: rockylinux-9
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:03
|
||||
ipaddr: 192.168.3.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
secondary:
|
||||
device: wwnet1
|
||||
hwaddr: 9a:77:29:73:14:f1
|
||||
ipaddr: 192.168.3.22
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
tags:
|
||||
DNS1: 8.8.8.8
|
||||
DNS2: 8.8.4.4
|
||||
ipmi:
|
||||
username: user
|
||||
password: password
|
||||
ipaddr: 192.168.4.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.4.1
|
||||
write: "true"
|
||||
disks:
|
||||
/dev/vda:
|
||||
wipe_table: "true"
|
||||
partitions:
|
||||
scratch:
|
||||
should_exist: "true"
|
||||
swap:
|
||||
number: "1"
|
||||
size_mib: "1024"
|
||||
filesystems:
|
||||
/dev/disk/by-partlabel/scratch:
|
||||
format: btrfs
|
||||
path: /scratch
|
||||
wipe_filesystem: "true"
|
||||
/dev/disk/by-partlabel/swap:
|
||||
format: swap
|
||||
path: swap
|
||||
node2:
|
||||
profiles:
|
||||
- empty
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:04
|
||||
ipaddr: 192.168.3.23
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
@@ -1,13 +1,7 @@
|
||||
{{- $host := .BuildHost }}
|
||||
{{- $time := .BuildTime }}
|
||||
{{- $source := .BuildSource }}
|
||||
{{range $devname, $netdev := .NetDevs -}}
|
||||
{{- $filename := print "ifcfg-" $devname ".conf" }}
|
||||
{{- file $filename }}
|
||||
# This file is autogenerated by warewulf
|
||||
# Host: {{ $host }}
|
||||
# Time: {{ $time }}
|
||||
# Source: {{ $source }}
|
||||
TYPE={{ $netdev.Type }}
|
||||
DEVICE={{ $netdev.Device }}
|
||||
NAME={{ $devname }}
|
||||
120
overlays/ignition/internal/ignition_test.go
Normal file
120
overlays/ignition/internal/ignition_test.go
Normal file
@@ -0,0 +1,120 @@
|
||||
package ignition
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/warewulf/warewulf/internal/app/wwctl/overlay/show"
|
||||
"github.com/warewulf/warewulf/internal/pkg/testenv"
|
||||
"github.com/warewulf/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
func Test_ignitionOverlay(t *testing.T) {
|
||||
env := testenv.New(t)
|
||||
defer env.RemoveAll(t)
|
||||
env.ImportFile(t, "etc/warewulf/nodes.conf", "nodes.conf")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/ignition/rootfs/etc/systemd/system/ww4-disks.target.ww", "../rootfs/etc/systemd/system/ww4-disks.target.ww")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/ignition/rootfs/etc/systemd/system/ww4-mounts.ww", "../rootfs/etc/systemd/system/ww4-mounts.ww")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/ignition/rootfs/warewulf/ignition.json.ww", "../rootfs/warewulf/ignition.json.ww")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
log string
|
||||
json bool
|
||||
}{
|
||||
{
|
||||
name: "ignition:ww4-disks.target",
|
||||
args: []string{"--render", "node1", "ignition", "etc/systemd/system/ww4-disks.target.ww"},
|
||||
log: ignition_disks,
|
||||
json: false,
|
||||
},
|
||||
{
|
||||
name: "ignition:ww4-mounts",
|
||||
args: []string{"--render", "node1", "ignition", "etc/systemd/system/ww4-mounts.ww"},
|
||||
log: ignition_mounts,
|
||||
json: false,
|
||||
},
|
||||
{
|
||||
name: "ignition:ignition.json",
|
||||
args: []string{"--quiet", "--render", "node1", "ignition", "warewulf/ignition.json.ww"},
|
||||
log: ignition_json,
|
||||
json: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cmd := show.GetCommand()
|
||||
cmd.SetArgs(tt.args)
|
||||
stdout := bytes.NewBufferString("")
|
||||
stderr := bytes.NewBufferString("")
|
||||
logbuf := bytes.NewBufferString("")
|
||||
cmd.SetOut(stdout)
|
||||
cmd.SetErr(stderr)
|
||||
wwlog.SetLogWriter(logbuf)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, stdout.String())
|
||||
assert.Empty(t, stderr.String())
|
||||
if tt.json {
|
||||
var expected, actual interface{}
|
||||
assert.NoError(t, json.Unmarshal([]byte(tt.log), &expected))
|
||||
assert.NoError(t, json.Unmarshal(logbuf.Bytes(), &actual))
|
||||
assert.True(t, reflect.DeepEqual(expected, actual), "expected: %v\nactual : %v", expected, actual)
|
||||
} else {
|
||||
assert.Equal(t, tt.log, logbuf.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const ignition_disks string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: etc/systemd/system/ww4-disks.target
|
||||
# This file is autogenerated by warewulf
|
||||
[Unit]
|
||||
Description=mount ww4 disks
|
||||
# make sure that the disks are available
|
||||
Requires=ignition-ww4-disks.service
|
||||
After=ignition-ww4-disks.service
|
||||
Requisite=ignition-ww4-disks.service
|
||||
# Get the mounts
|
||||
Wants=scratch.mount
|
||||
Wants=dev-disk-by\x2dpartlabel-swap.swap
|
||||
`
|
||||
|
||||
const ignition_mounts string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: scratch.mount
|
||||
|
||||
# This file is autogenerated by warewulf
|
||||
[Unit]
|
||||
ConditionPathExists=/warewulf/ignition.json
|
||||
Before=local-fs.target
|
||||
After=ignition-ww4-disks.service
|
||||
[Mount]
|
||||
Where=/scratch
|
||||
What=/dev/disk/by-partlabel/scratch
|
||||
Type=btrfs
|
||||
[Install]
|
||||
RequiredBy=local-fs.target
|
||||
backupFile: true
|
||||
writeFile: true
|
||||
Filename: dev-disk-by\x2dpartlabel-swap.swap
|
||||
# This file is autogenerated by warewulf
|
||||
[Unit]
|
||||
ConditionPathExists=/warewulf/ignition.json
|
||||
After=ignition-ww4-disks.service
|
||||
Before=swap.target
|
||||
[Swap]
|
||||
What=/dev/disk/by-partlabel/swap
|
||||
[Install]
|
||||
RequiredBy=swap.target
|
||||
`
|
||||
|
||||
const ignition_json string = `{"ignition":{"version":"3.1.0"},"storage":{"disks":[{"device":"/dev/vda","partitions":[{"label":"scratch","shouldExist":true,"wipePartitionEntry":false},{"label":"swap","number":1,"shouldExist":false,"sizeMiB":1024,"wipePartitionEntry":false}],"wipeTable":true}],"filesystems":[{"device":"/dev/disk/by-partlabel/scratch","format":"btrfs","path":"/scratch","wipeFilesystem":true},{"device":"/dev/disk/by-partlabel/swap","format":"swap","path":"swap","wipeFilesystem":false}]}}
|
||||
`
|
||||
58
overlays/ignition/internal/nodes.conf
Normal file
58
overlays/ignition/internal/nodes.conf
Normal file
@@ -0,0 +1,58 @@
|
||||
WW_INTERNAL: 45
|
||||
nodeprofiles:
|
||||
empty: {}
|
||||
nodes:
|
||||
node1:
|
||||
profiles:
|
||||
- empty
|
||||
container name: rockylinux-9
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:03
|
||||
ipaddr: 192.168.3.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
secondary:
|
||||
device: wwnet1
|
||||
hwaddr: 9a:77:29:73:14:f1
|
||||
ipaddr: 192.168.3.22
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
tags:
|
||||
DNS1: 8.8.8.8
|
||||
DNS2: 8.8.4.4
|
||||
ipmi:
|
||||
username: user
|
||||
password: password
|
||||
ipaddr: 192.168.4.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.4.1
|
||||
write: "true"
|
||||
disks:
|
||||
/dev/vda:
|
||||
wipe_table: "true"
|
||||
partitions:
|
||||
scratch:
|
||||
should_exist: "true"
|
||||
swap:
|
||||
number: "1"
|
||||
size_mib: "1024"
|
||||
filesystems:
|
||||
/dev/disk/by-partlabel/scratch:
|
||||
format: btrfs
|
||||
path: /scratch
|
||||
wipe_filesystem: "true"
|
||||
/dev/disk/by-partlabel/swap:
|
||||
format: swap
|
||||
path: swap
|
||||
node2:
|
||||
profiles:
|
||||
- empty
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:04
|
||||
ipaddr: 192.168.3.23
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
@@ -1,7 +1,4 @@
|
||||
# This file is autogenerated by warewulf
|
||||
# Host: {{.BuildHost}}
|
||||
# Time: {{.BuildTime}}
|
||||
# Source: {{.BuildSource}}
|
||||
[Unit]
|
||||
Description=mount ww4 disks
|
||||
# make sure that the disks are available
|
||||
@@ -1,6 +1,3 @@
|
||||
{{- $host := .BuildHost }}
|
||||
{{- $time := .BuildTime }}
|
||||
{{- $source := .BuildSource }}
|
||||
{{- range $fsdevice,$fs := .FileSystems }}
|
||||
{{- $prefix := replace "-" "\\x2d" $fs.Path }}
|
||||
{{- $prefix = replace "/" "-" $prefix }}
|
||||
@@ -11,9 +8,6 @@
|
||||
{{- $filename := print $prefix "." $suffix }}
|
||||
{{- file $filename }}
|
||||
# This file is autogenerated by warewulf
|
||||
# Host: {{ $host }}
|
||||
# Time: {{ $time }}
|
||||
# Source: {{ $source }}
|
||||
{{- if eq $fs.Format "swap"}}
|
||||
[Unit]
|
||||
ConditionPathExists=/warewulf/ignition.json
|
||||
64
overlays/issue/internal/issue_test.go
Normal file
64
overlays/issue/internal/issue_test.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package issue
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/warewulf/warewulf/internal/app/wwctl/overlay/show"
|
||||
"github.com/warewulf/warewulf/internal/pkg/testenv"
|
||||
"github.com/warewulf/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
func Test_issueOverlay(t *testing.T) {
|
||||
env := testenv.New(t)
|
||||
defer env.RemoveAll(t)
|
||||
env.ImportFile(t, "etc/warewulf/nodes.conf", "nodes.conf")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/issue/rootfs/etc/issue.ww", "../rootfs/etc/issue.ww")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
log string
|
||||
}{
|
||||
{
|
||||
name: "/etc/issue",
|
||||
args: []string{"--render", "node1", "issue", "etc/issue.ww"},
|
||||
log: issue,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cmd := show.GetCommand()
|
||||
cmd.SetArgs(tt.args)
|
||||
stdout := bytes.NewBufferString("")
|
||||
stderr := bytes.NewBufferString("")
|
||||
logbuf := bytes.NewBufferString("")
|
||||
cmd.SetOut(stdout)
|
||||
cmd.SetErr(stderr)
|
||||
wwlog.SetLogWriter(logbuf)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, stdout.String())
|
||||
assert.Empty(t, stderr.String())
|
||||
assert.Equal(t, tt.log, logbuf.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const issue string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: etc/issue
|
||||
Warewulf Node: node1
|
||||
Container: rockylinux-9
|
||||
Kernelargs: quiet crashkernel=no vga=791 net.naming-scheme=v238
|
||||
|
||||
Network:
|
||||
default: wwnet0
|
||||
default: 192.168.3.21/24
|
||||
default: e6:92:39:49:7b:03
|
||||
secondary: wwnet1
|
||||
secondary: 192.168.3.22/24
|
||||
secondary: 9a:77:29:73:14:f1
|
||||
`
|
||||
58
overlays/issue/internal/nodes.conf
Normal file
58
overlays/issue/internal/nodes.conf
Normal file
@@ -0,0 +1,58 @@
|
||||
WW_INTERNAL: 45
|
||||
nodeprofiles:
|
||||
empty: {}
|
||||
nodes:
|
||||
node1:
|
||||
profiles:
|
||||
- empty
|
||||
container name: rockylinux-9
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:03
|
||||
ipaddr: 192.168.3.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
secondary:
|
||||
device: wwnet1
|
||||
hwaddr: 9a:77:29:73:14:f1
|
||||
ipaddr: 192.168.3.22
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
tags:
|
||||
DNS1: 8.8.8.8
|
||||
DNS2: 8.8.4.4
|
||||
ipmi:
|
||||
username: user
|
||||
password: password
|
||||
ipaddr: 192.168.4.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.4.1
|
||||
write: "true"
|
||||
disks:
|
||||
/dev/vda:
|
||||
wipe_table: "true"
|
||||
partitions:
|
||||
scratch:
|
||||
should_exist: "true"
|
||||
swap:
|
||||
number: "1"
|
||||
size_mib: "1024"
|
||||
filesystems:
|
||||
/dev/disk/by-partlabel/scratch:
|
||||
format: btrfs
|
||||
path: /scratch
|
||||
wipe_filesystem: "true"
|
||||
/dev/disk/by-partlabel/swap:
|
||||
format: swap
|
||||
path: swap
|
||||
node2:
|
||||
profiles:
|
||||
- empty
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:04
|
||||
ipaddr: 192.168.3.23
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
58
overlays/resolv/internal/nodes.conf
Normal file
58
overlays/resolv/internal/nodes.conf
Normal file
@@ -0,0 +1,58 @@
|
||||
WW_INTERNAL: 45
|
||||
nodeprofiles:
|
||||
empty: {}
|
||||
nodes:
|
||||
node1:
|
||||
profiles:
|
||||
- empty
|
||||
container name: rockylinux-9
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:03
|
||||
ipaddr: 192.168.3.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
secondary:
|
||||
device: wwnet1
|
||||
hwaddr: 9a:77:29:73:14:f1
|
||||
ipaddr: 192.168.3.22
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
tags:
|
||||
DNS1: 8.8.8.8
|
||||
DNS2: 8.8.4.4
|
||||
ipmi:
|
||||
username: user
|
||||
password: password
|
||||
ipaddr: 192.168.4.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.4.1
|
||||
write: "true"
|
||||
disks:
|
||||
/dev/vda:
|
||||
wipe_table: "true"
|
||||
partitions:
|
||||
scratch:
|
||||
should_exist: "true"
|
||||
swap:
|
||||
number: "1"
|
||||
size_mib: "1024"
|
||||
filesystems:
|
||||
/dev/disk/by-partlabel/scratch:
|
||||
format: btrfs
|
||||
path: /scratch
|
||||
wipe_filesystem: "true"
|
||||
/dev/disk/by-partlabel/swap:
|
||||
format: swap
|
||||
path: swap
|
||||
node2:
|
||||
profiles:
|
||||
- empty
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:04
|
||||
ipaddr: 192.168.3.23
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
56
overlays/resolv/internal/resolv_test.go
Normal file
56
overlays/resolv/internal/resolv_test.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package resolv
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/warewulf/warewulf/internal/app/wwctl/overlay/show"
|
||||
"github.com/warewulf/warewulf/internal/pkg/testenv"
|
||||
"github.com/warewulf/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
func Test_resolvOverlay(t *testing.T) {
|
||||
env := testenv.New(t)
|
||||
defer env.RemoveAll(t)
|
||||
env.ImportFile(t, "etc/warewulf/nodes.conf", "nodes.conf")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/resolv/rootfs/etc/resolv.conf.ww", "../rootfs/etc/resolv.conf.ww")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
log string
|
||||
}{
|
||||
{
|
||||
name: "/etc/resolv.conf",
|
||||
args: []string{"--render", "node1", "resolv", "etc/resolv.conf.ww"},
|
||||
log: resolv_conf,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cmd := show.GetCommand()
|
||||
cmd.SetArgs(tt.args)
|
||||
stdout := bytes.NewBufferString("")
|
||||
stderr := bytes.NewBufferString("")
|
||||
logbuf := bytes.NewBufferString("")
|
||||
cmd.SetOut(stdout)
|
||||
cmd.SetErr(stderr)
|
||||
wwlog.SetLogWriter(logbuf)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, stdout.String())
|
||||
assert.Empty(t, stderr.String())
|
||||
assert.Equal(t, tt.log, logbuf.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const resolv_conf string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: etc/resolv.conf
|
||||
# This file is autogenerated by warewulf
|
||||
nameserver 8.8.8.8
|
||||
nameserver 8.8.4.4
|
||||
`
|
||||
@@ -1,10 +1,4 @@
|
||||
{{- $host := .BuildHost }}
|
||||
{{- $time := .BuildTime }}
|
||||
{{- $source := .BuildSource }}
|
||||
# This file is autogenerated by warewulf
|
||||
# Host: {{ $host }}
|
||||
# Time: {{ $time }}
|
||||
# Source: {{ $source }}
|
||||
{{range $devname, $netdev := .NetDevs -}}
|
||||
{{range $tk, $tv := $netdev.Tags -}}
|
||||
{{ $prefix := substr 0 3 $tk -}}
|
||||
58
overlays/ssh.authorized_keys/internal/nodes.conf
Normal file
58
overlays/ssh.authorized_keys/internal/nodes.conf
Normal file
@@ -0,0 +1,58 @@
|
||||
WW_INTERNAL: 45
|
||||
nodeprofiles:
|
||||
empty: {}
|
||||
nodes:
|
||||
node1:
|
||||
profiles:
|
||||
- empty
|
||||
container name: rockylinux-9
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:03
|
||||
ipaddr: 192.168.3.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
secondary:
|
||||
device: wwnet1
|
||||
hwaddr: 9a:77:29:73:14:f1
|
||||
ipaddr: 192.168.3.22
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
tags:
|
||||
DNS1: 8.8.8.8
|
||||
DNS2: 8.8.4.4
|
||||
ipmi:
|
||||
username: user
|
||||
password: password
|
||||
ipaddr: 192.168.4.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.4.1
|
||||
write: "true"
|
||||
disks:
|
||||
/dev/vda:
|
||||
wipe_table: "true"
|
||||
partitions:
|
||||
scratch:
|
||||
should_exist: "true"
|
||||
swap:
|
||||
number: "1"
|
||||
size_mib: "1024"
|
||||
filesystems:
|
||||
/dev/disk/by-partlabel/scratch:
|
||||
format: btrfs
|
||||
path: /scratch
|
||||
wipe_filesystem: "true"
|
||||
/dev/disk/by-partlabel/swap:
|
||||
format: swap
|
||||
path: swap
|
||||
node2:
|
||||
profiles:
|
||||
- empty
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:04
|
||||
ipaddr: 192.168.3.23
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
@@ -0,0 +1,56 @@
|
||||
package ssh_authorized_keys
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/warewulf/warewulf/internal/app/wwctl/overlay/show"
|
||||
"github.com/warewulf/warewulf/internal/pkg/testenv"
|
||||
"github.com/warewulf/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
func Test_ssh_authorized_keysOverlay(t *testing.T) {
|
||||
t.Skip("ssh.authorized_keys is not yet isolated from the host")
|
||||
|
||||
env := testenv.New(t)
|
||||
defer env.RemoveAll(t)
|
||||
env.ImportFile(t, "etc/warewulf/nodes.conf", "nodes.conf")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/ssh.authorized_keys/rootfs/root/.ssh/authorized_keys.ww", "../rootfs/root/.ssh/authorized_keys.ww")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
log string
|
||||
}{
|
||||
{
|
||||
name: "ssh.authorized_keys:authorized_keys.ww",
|
||||
args: []string{"--render", "node1", "ssh.authorized_keys", "root/.ssh/authorized_keys.ww"},
|
||||
log: ssh_authorized_keys,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cmd := show.GetCommand()
|
||||
cmd.SetArgs(tt.args)
|
||||
stdout := bytes.NewBufferString("")
|
||||
stderr := bytes.NewBufferString("")
|
||||
logbuf := bytes.NewBufferString("")
|
||||
cmd.SetOut(stdout)
|
||||
cmd.SetErr(stderr)
|
||||
wwlog.SetLogWriter(logbuf)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, stdout.String())
|
||||
assert.Empty(t, stderr.String())
|
||||
assert.Equal(t, tt.log, logbuf.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const ssh_authorized_keys string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: root/.ssh/authorized_keys
|
||||
|
||||
`
|
||||
58
overlays/ssh.host_keys/internal/nodes.conf
Normal file
58
overlays/ssh.host_keys/internal/nodes.conf
Normal file
@@ -0,0 +1,58 @@
|
||||
WW_INTERNAL: 45
|
||||
nodeprofiles:
|
||||
empty: {}
|
||||
nodes:
|
||||
node1:
|
||||
profiles:
|
||||
- empty
|
||||
container name: rockylinux-9
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:03
|
||||
ipaddr: 192.168.3.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
secondary:
|
||||
device: wwnet1
|
||||
hwaddr: 9a:77:29:73:14:f1
|
||||
ipaddr: 192.168.3.22
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
tags:
|
||||
DNS1: 8.8.8.8
|
||||
DNS2: 8.8.4.4
|
||||
ipmi:
|
||||
username: user
|
||||
password: password
|
||||
ipaddr: 192.168.4.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.4.1
|
||||
write: "true"
|
||||
disks:
|
||||
/dev/vda:
|
||||
wipe_table: "true"
|
||||
partitions:
|
||||
scratch:
|
||||
should_exist: "true"
|
||||
swap:
|
||||
number: "1"
|
||||
size_mib: "1024"
|
||||
filesystems:
|
||||
/dev/disk/by-partlabel/scratch:
|
||||
format: btrfs
|
||||
path: /scratch
|
||||
wipe_filesystem: "true"
|
||||
/dev/disk/by-partlabel/swap:
|
||||
format: swap
|
||||
path: swap
|
||||
node2:
|
||||
profiles:
|
||||
- empty
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:04
|
||||
ipaddr: 192.168.3.23
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
146
overlays/ssh.host_keys/internal/ssh_host_keys_test.go
Normal file
146
overlays/ssh.host_keys/internal/ssh_host_keys_test.go
Normal file
@@ -0,0 +1,146 @@
|
||||
package ssh_host_keys
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/warewulf/warewulf/internal/app/wwctl/overlay/show"
|
||||
"github.com/warewulf/warewulf/internal/pkg/testenv"
|
||||
"github.com/warewulf/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
func Test_ssh_host_keysOverlay(t *testing.T) {
|
||||
env := testenv.New(t)
|
||||
defer env.RemoveAll(t)
|
||||
env.ImportFile(t, "etc/warewulf/nodes.conf", "nodes.conf")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/ssh.host_keys/rootfs/etc/ssh/ssh_host_dsa_key.pub.ww", "../rootfs/etc/ssh/ssh_host_dsa_key.pub.ww")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/ssh.host_keys/rootfs/etc/ssh/ssh_host_dsa_key.ww", "../rootfs/etc/ssh/ssh_host_dsa_key.ww")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/ssh.host_keys/rootfs/etc/ssh/ssh_host_ecdsa_key.pub.ww", "../rootfs/etc/ssh/ssh_host_ecdsa_key.pub.ww")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/ssh.host_keys/rootfs/etc/ssh/ssh_host_ecdsa_key.ww", "../rootfs/etc/ssh/ssh_host_ecdsa_key.ww")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/ssh.host_keys/rootfs/etc/ssh/ssh_host_ed25519_key.pub.ww", "../rootfs/etc/ssh/ssh_host_ed25519_key.pub.ww")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/ssh.host_keys/rootfs/etc/ssh/ssh_host_ed25519_key.ww", "../rootfs/etc/ssh/ssh_host_ed25519_key.ww")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/ssh.host_keys/rootfs/etc/ssh/ssh_host_rsa_key.pub.ww", "../rootfs/etc/ssh/ssh_host_rsa_key.pub.ww")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/ssh.host_keys/rootfs/etc/ssh/ssh_host_rsa_key.ww", "../rootfs/etc/ssh/ssh_host_rsa_key.ww")
|
||||
env.WriteFile(t, "etc/warewulf/keys/ssh_host_dsa_key.pub", `dsa pubkey sentinel`)
|
||||
env.WriteFile(t, "etc/warewulf/keys/ssh_host_dsa_key", `dsa key sentinel`)
|
||||
env.WriteFile(t, "etc/warewulf/keys/ssh_host_ecdsa_key.pub", `ecdsa pubkey sentinel`)
|
||||
env.WriteFile(t, "etc/warewulf/keys/ssh_host_ecdsa_key", `ecdsa key sentinel`)
|
||||
env.WriteFile(t, "etc/warewulf/keys/ssh_host_ed25519_key.pub", `ed25519 pubkey sentinel`)
|
||||
env.WriteFile(t, "etc/warewulf/keys/ssh_host_ed25519_key", `ed25519 key sentinel`)
|
||||
env.WriteFile(t, "etc/warewulf/keys/ssh_host_rsa_key.pub", `rsa pubkey sentinel`)
|
||||
env.WriteFile(t, "etc/warewulf/keys/ssh_host_rsa_key", `rsa key sentinel`)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
log string
|
||||
}{
|
||||
{
|
||||
name: "ssh.host_keys:dsa pub",
|
||||
args: []string{"--render", "node1", "ssh.host_keys", "etc/ssh/ssh_host_dsa_key.pub.ww"},
|
||||
log: ssh_host_dsa_key_pub,
|
||||
},
|
||||
{
|
||||
name: "ssh.host_keys:dsa",
|
||||
args: []string{"--render", "node1", "ssh.host_keys", "etc/ssh/ssh_host_dsa_key.ww"},
|
||||
log: ssh_host_dsa_key,
|
||||
},
|
||||
{
|
||||
name: "ssh.host_keys:ecdsa pub",
|
||||
args: []string{"--render", "node1", "ssh.host_keys", "etc/ssh/ssh_host_ecdsa_key.pub.ww"},
|
||||
log: ssh_host_ecdsa_key_pub,
|
||||
},
|
||||
{
|
||||
name: "ssh.host_keys:ecdsa",
|
||||
args: []string{"--render", "node1", "ssh.host_keys", "etc/ssh/ssh_host_ecdsa_key.ww"},
|
||||
log: ssh_host_ecdsa_key,
|
||||
},
|
||||
{
|
||||
name: "ssh.host_keys:rsa pub",
|
||||
args: []string{"--render", "node1", "ssh.host_keys", "etc/ssh/ssh_host_rsa_key.pub.ww"},
|
||||
log: ssh_host_rsa_key_pub,
|
||||
},
|
||||
{
|
||||
name: "ssh.host_keys:dsa",
|
||||
args: []string{"--render", "node1", "ssh.host_keys", "etc/ssh/ssh_host_rsa_key.ww"},
|
||||
log: ssh_host_rsa_key,
|
||||
},
|
||||
{
|
||||
name: "ssh.host_keys:ed25519 pub",
|
||||
args: []string{"--render", "node1", "ssh.host_keys", "etc/ssh/ssh_host_ed25519_key.pub.ww"},
|
||||
log: ssh_host_ed25519_key_pub,
|
||||
},
|
||||
{
|
||||
name: "ssh.host_keys:ed25519",
|
||||
args: []string{"--render", "node1", "ssh.host_keys", "etc/ssh/ssh_host_ed25519_key.ww"},
|
||||
log: ssh_host_ed25519_key,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cmd := show.GetCommand()
|
||||
cmd.SetArgs(tt.args)
|
||||
stdout := bytes.NewBufferString("")
|
||||
stderr := bytes.NewBufferString("")
|
||||
logbuf := bytes.NewBufferString("")
|
||||
cmd.SetOut(stdout)
|
||||
cmd.SetErr(stderr)
|
||||
wwlog.SetLogWriter(logbuf)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, stdout.String())
|
||||
assert.Empty(t, stderr.String())
|
||||
assert.Equal(t, tt.log, logbuf.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const ssh_host_dsa_key_pub string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: etc/ssh/ssh_host_dsa_key.pub
|
||||
dsa pubkey sentinel
|
||||
`
|
||||
|
||||
const ssh_host_dsa_key string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: etc/ssh/ssh_host_dsa_key
|
||||
dsa key sentinel
|
||||
`
|
||||
|
||||
const ssh_host_ecdsa_key_pub string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: etc/ssh/ssh_host_ecdsa_key.pub
|
||||
ecdsa pubkey sentinel
|
||||
`
|
||||
|
||||
const ssh_host_ecdsa_key string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: etc/ssh/ssh_host_ecdsa_key
|
||||
ecdsa key sentinel
|
||||
`
|
||||
|
||||
const ssh_host_ed25519_key_pub string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: etc/ssh/ssh_host_ed25519_key.pub
|
||||
ed25519 pubkey sentinel
|
||||
`
|
||||
|
||||
const ssh_host_ed25519_key string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: etc/ssh/ssh_host_ed25519_key
|
||||
ed25519 key sentinel
|
||||
`
|
||||
|
||||
const ssh_host_rsa_key_pub string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: etc/ssh/ssh_host_rsa_key.pub
|
||||
rsa pubkey sentinel
|
||||
`
|
||||
|
||||
const ssh_host_rsa_key string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: etc/ssh/ssh_host_rsa_key
|
||||
rsa key sentinel
|
||||
`
|
||||
58
overlays/syncuser/internal/nodes.conf
Normal file
58
overlays/syncuser/internal/nodes.conf
Normal file
@@ -0,0 +1,58 @@
|
||||
WW_INTERNAL: 45
|
||||
nodeprofiles:
|
||||
empty: {}
|
||||
nodes:
|
||||
node1:
|
||||
profiles:
|
||||
- empty
|
||||
container name: rockylinux-9
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:03
|
||||
ipaddr: 192.168.3.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
secondary:
|
||||
device: wwnet1
|
||||
hwaddr: 9a:77:29:73:14:f1
|
||||
ipaddr: 192.168.3.22
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
tags:
|
||||
DNS1: 8.8.8.8
|
||||
DNS2: 8.8.4.4
|
||||
ipmi:
|
||||
username: user
|
||||
password: password
|
||||
ipaddr: 192.168.4.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.4.1
|
||||
write: "true"
|
||||
disks:
|
||||
/dev/vda:
|
||||
wipe_table: "true"
|
||||
partitions:
|
||||
scratch:
|
||||
should_exist: "true"
|
||||
swap:
|
||||
number: "1"
|
||||
size_mib: "1024"
|
||||
filesystems:
|
||||
/dev/disk/by-partlabel/scratch:
|
||||
format: btrfs
|
||||
path: /scratch
|
||||
wipe_filesystem: "true"
|
||||
/dev/disk/by-partlabel/swap:
|
||||
format: swap
|
||||
path: swap
|
||||
node2:
|
||||
profiles:
|
||||
- empty
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:04
|
||||
ipaddr: 192.168.3.23
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
72
overlays/syncuser/internal/syncuser_test.go
Normal file
72
overlays/syncuser/internal/syncuser_test.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package syncuser
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/warewulf/warewulf/internal/app/wwctl/overlay/show"
|
||||
"github.com/warewulf/warewulf/internal/pkg/testenv"
|
||||
"github.com/warewulf/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
func Test_syncuserOverlay(t *testing.T) {
|
||||
t.Skip("syncuser is not yet isolated from the host")
|
||||
|
||||
env := testenv.New(t)
|
||||
defer env.RemoveAll(t)
|
||||
env.ImportFile(t, "etc/warewulf/nodes.conf", "nodes.conf")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/syncuser/rootfs/etc/passwd.ww", "../../../../../overlays/syncuser/rootfs/etc/passwd.ww")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/syncuser/rootfs/etc/group.ww", "../../../../../overlays/syncuser/rootfs/etc/group.ww")
|
||||
env.WriteFile(t, "var/lib/warewulf/chroots/rockylinux-9/rootfs/etc/passwd", `root:x:0:0:root:/root:/bin/bash`)
|
||||
env.WriteFile(t, "var/lib/warewulf/chroots/rockylinux-9/rootfs/etc/group", `root:x:0:`)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
log string
|
||||
}{
|
||||
{
|
||||
name: "syncuser:passwd.ww",
|
||||
args: []string{"--render", "node1", "syncuser", "etc/passwd.ww"},
|
||||
log: syncuser_passwd,
|
||||
},
|
||||
{
|
||||
name: "syncuser:group.ww",
|
||||
args: []string{"--render", "node1", "syncuser", "etc/group.ww"},
|
||||
log: syncuser_group,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cmd := show.GetCommand()
|
||||
cmd.SetArgs(tt.args)
|
||||
stdout := bytes.NewBufferString("")
|
||||
stderr := bytes.NewBufferString("")
|
||||
logbuf := bytes.NewBufferString("")
|
||||
cmd.SetOut(stdout)
|
||||
cmd.SetErr(stderr)
|
||||
wwlog.SetLogWriter(logbuf)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, stdout.String())
|
||||
assert.Empty(t, stderr.String())
|
||||
assert.Equal(t, tt.log, logbuf.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const syncuser_passwd string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: etc/passwd
|
||||
# Uncomment the following line to enable passwordless root login
|
||||
# root::0:0:root:/root:/bin/bash
|
||||
root:x:0:0:root:/root:/bin/bash
|
||||
`
|
||||
|
||||
const syncuser_group string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: etc/group
|
||||
root:x:0:
|
||||
`
|
||||
58
overlays/systemd.netname/internal/nodes.conf
Normal file
58
overlays/systemd.netname/internal/nodes.conf
Normal file
@@ -0,0 +1,58 @@
|
||||
WW_INTERNAL: 45
|
||||
nodeprofiles:
|
||||
empty: {}
|
||||
nodes:
|
||||
node1:
|
||||
profiles:
|
||||
- empty
|
||||
container name: rockylinux-9
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:03
|
||||
ipaddr: 192.168.3.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
secondary:
|
||||
device: wwnet1
|
||||
hwaddr: 9a:77:29:73:14:f1
|
||||
ipaddr: 192.168.3.22
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
tags:
|
||||
DNS1: 8.8.8.8
|
||||
DNS2: 8.8.4.4
|
||||
ipmi:
|
||||
username: user
|
||||
password: password
|
||||
ipaddr: 192.168.4.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.4.1
|
||||
write: "true"
|
||||
disks:
|
||||
/dev/vda:
|
||||
wipe_table: "true"
|
||||
partitions:
|
||||
scratch:
|
||||
should_exist: "true"
|
||||
swap:
|
||||
number: "1"
|
||||
size_mib: "1024"
|
||||
filesystems:
|
||||
/dev/disk/by-partlabel/scratch:
|
||||
format: btrfs
|
||||
path: /scratch
|
||||
wipe_filesystem: "true"
|
||||
/dev/disk/by-partlabel/swap:
|
||||
format: swap
|
||||
path: swap
|
||||
node2:
|
||||
profiles:
|
||||
- empty
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:04
|
||||
ipaddr: 192.168.3.23
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
66
overlays/systemd.netname/internal/systemd_netname_test.go
Normal file
66
overlays/systemd.netname/internal/systemd_netname_test.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package systemd_netname
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/warewulf/warewulf/internal/app/wwctl/overlay/show"
|
||||
"github.com/warewulf/warewulf/internal/pkg/testenv"
|
||||
"github.com/warewulf/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
func Test_udev_netnameOverlay(t *testing.T) {
|
||||
env := testenv.New(t)
|
||||
defer env.RemoveAll(t)
|
||||
env.ImportFile(t, "etc/warewulf/nodes.conf", "nodes.conf")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/systemd.netname/rootfs/etc/systemd/network/10-ww4-netname.link.ww", "../rootfs/etc/systemd/network/10-ww4-netname.link.ww")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
log string
|
||||
}{
|
||||
{
|
||||
name: "systemd network links",
|
||||
args: []string{"--render", "node1", "systemd.netname", "etc/systemd/network/10-ww4-netname.link.ww"},
|
||||
log: systemd_network_links,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cmd := show.GetCommand()
|
||||
cmd.SetArgs(tt.args)
|
||||
stdout := bytes.NewBufferString("")
|
||||
stderr := bytes.NewBufferString("")
|
||||
logbuf := bytes.NewBufferString("")
|
||||
cmd.SetOut(stdout)
|
||||
cmd.SetErr(stderr)
|
||||
wwlog.SetLogWriter(logbuf)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, stdout.String())
|
||||
assert.Empty(t, stderr.String())
|
||||
assert.Equal(t, tt.log, logbuf.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const systemd_network_links string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: 10-ww4-netname-default.link
|
||||
# This file is autogenerated by warewulf
|
||||
[Match]
|
||||
MACAddress=e6:92:39:49:7b:03
|
||||
[Link]
|
||||
Name=wwnet0
|
||||
backupFile: true
|
||||
writeFile: true
|
||||
Filename: 10-ww4-netname-secondary.link
|
||||
# This file is autogenerated by warewulf
|
||||
[Match]
|
||||
MACAddress=9a:77:29:73:14:f1
|
||||
[Link]
|
||||
Name=wwnet1
|
||||
`
|
||||
@@ -1,10 +1,7 @@
|
||||
{{ range $devname, $netdev := .NetDevs -}}
|
||||
{{- $filename := print "10-persistent-net-" $devname ".link" }}
|
||||
{{- $filename := print "10-ww4-netname-" $devname ".link" }}
|
||||
{{- file $filename }}
|
||||
# This file is autogenerated by warewulf
|
||||
# Host: {{$.BuildHost}}
|
||||
# Time: {{$.BuildTime}}
|
||||
# Source: {{$.BuildSource}}
|
||||
{{- if and $netdev.Hwaddr $netdev.Device }}
|
||||
[Match]
|
||||
MACAddress={{$netdev.Hwaddr}}
|
||||
58
overlays/udev.netname/internal/nodes.conf
Normal file
58
overlays/udev.netname/internal/nodes.conf
Normal file
@@ -0,0 +1,58 @@
|
||||
WW_INTERNAL: 45
|
||||
nodeprofiles:
|
||||
empty: {}
|
||||
nodes:
|
||||
node1:
|
||||
profiles:
|
||||
- empty
|
||||
container name: rockylinux-9
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:03
|
||||
ipaddr: 192.168.3.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
secondary:
|
||||
device: wwnet1
|
||||
hwaddr: 9a:77:29:73:14:f1
|
||||
ipaddr: 192.168.3.22
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
tags:
|
||||
DNS1: 8.8.8.8
|
||||
DNS2: 8.8.4.4
|
||||
ipmi:
|
||||
username: user
|
||||
password: password
|
||||
ipaddr: 192.168.4.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.4.1
|
||||
write: "true"
|
||||
disks:
|
||||
/dev/vda:
|
||||
wipe_table: "true"
|
||||
partitions:
|
||||
scratch:
|
||||
should_exist: "true"
|
||||
swap:
|
||||
number: "1"
|
||||
size_mib: "1024"
|
||||
filesystems:
|
||||
/dev/disk/by-partlabel/scratch:
|
||||
format: btrfs
|
||||
path: /scratch
|
||||
wipe_filesystem: "true"
|
||||
/dev/disk/by-partlabel/swap:
|
||||
format: swap
|
||||
path: swap
|
||||
node2:
|
||||
profiles:
|
||||
- empty
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:04
|
||||
ipaddr: 192.168.3.23
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
58
overlays/udev.netname/internal/udev_netname_test.go
Normal file
58
overlays/udev.netname/internal/udev_netname_test.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package udev_netname
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/warewulf/warewulf/internal/app/wwctl/overlay/show"
|
||||
"github.com/warewulf/warewulf/internal/pkg/testenv"
|
||||
"github.com/warewulf/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
func Test_udev_netnameOverlay(t *testing.T) {
|
||||
env := testenv.New(t)
|
||||
defer env.RemoveAll(t)
|
||||
env.ImportFile(t, "etc/warewulf/nodes.conf", "nodes.conf")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/udev.netname/rootfs/etc/udev/rules.d/70-ww4-netname.rules.ww", "../rootfs/etc/udev/rules.d/70-ww4-netname.rules.ww")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
log string
|
||||
}{
|
||||
{
|
||||
name: "udev.netname",
|
||||
args: []string{"--render", "node1", "udev.netname", "etc/udev/rules.d/70-ww4-netname.rules.ww"},
|
||||
log: udev_netname,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cmd := show.GetCommand()
|
||||
cmd.SetArgs(tt.args)
|
||||
stdout := bytes.NewBufferString("")
|
||||
stderr := bytes.NewBufferString("")
|
||||
logbuf := bytes.NewBufferString("")
|
||||
cmd.SetOut(stdout)
|
||||
cmd.SetErr(stderr)
|
||||
wwlog.SetLogWriter(logbuf)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, stdout.String())
|
||||
assert.Empty(t, stderr.String())
|
||||
assert.Equal(t, tt.log, logbuf.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const udev_netname string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: etc/udev/rules.d/70-ww4-netname.rules
|
||||
# This file is autogenerated by warewulf
|
||||
|
||||
SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="e6:92:39:49:7b:03", NAME="wwnet0"
|
||||
|
||||
SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="9a:77:29:73:14:f1", NAME="wwnet1"
|
||||
`
|
||||
@@ -1,9 +1,6 @@
|
||||
# This file is autogenerated by warewulf
|
||||
# Host: {{.BuildHost}}
|
||||
# Time: {{.BuildTime}}
|
||||
# Source: {{.BuildSource}}
|
||||
{{range $devname, $netdev := .NetDevs}}
|
||||
{{- if $netdev.Hwaddr }}
|
||||
SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="{{ $netdev.Hwaddr }}", NAME="{{ $netdev.Device }}"
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
58
overlays/wicked/internal/nodes.conf
Normal file
58
overlays/wicked/internal/nodes.conf
Normal file
@@ -0,0 +1,58 @@
|
||||
WW_INTERNAL: 45
|
||||
nodeprofiles:
|
||||
empty: {}
|
||||
nodes:
|
||||
node1:
|
||||
profiles:
|
||||
- empty
|
||||
container name: rockylinux-9
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:03
|
||||
ipaddr: 192.168.3.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
secondary:
|
||||
device: wwnet1
|
||||
hwaddr: 9a:77:29:73:14:f1
|
||||
ipaddr: 192.168.3.22
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
tags:
|
||||
DNS1: 8.8.8.8
|
||||
DNS2: 8.8.4.4
|
||||
ipmi:
|
||||
username: user
|
||||
password: password
|
||||
ipaddr: 192.168.4.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.4.1
|
||||
write: "true"
|
||||
disks:
|
||||
/dev/vda:
|
||||
wipe_table: "true"
|
||||
partitions:
|
||||
scratch:
|
||||
should_exist: "true"
|
||||
swap:
|
||||
number: "1"
|
||||
size_mib: "1024"
|
||||
filesystems:
|
||||
/dev/disk/by-partlabel/scratch:
|
||||
format: btrfs
|
||||
path: /scratch
|
||||
wipe_filesystem: "true"
|
||||
/dev/disk/by-partlabel/swap:
|
||||
format: swap
|
||||
path: swap
|
||||
node2:
|
||||
profiles:
|
||||
- empty
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:04
|
||||
ipaddr: 192.168.3.23
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
118
overlays/wicked/internal/wicked_test.go
Normal file
118
overlays/wicked/internal/wicked_test.go
Normal file
@@ -0,0 +1,118 @@
|
||||
package wicked
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/warewulf/warewulf/internal/app/wwctl/overlay/show"
|
||||
"github.com/warewulf/warewulf/internal/pkg/testenv"
|
||||
"github.com/warewulf/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
func Test_wickedOverlay(t *testing.T) {
|
||||
env := testenv.New(t)
|
||||
defer env.RemoveAll(t)
|
||||
env.ImportFile(t, "etc/warewulf/nodes.conf", "nodes.conf")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/wicked/rootfs/etc/wicked/ifconfig/ifcfg.xml.ww", "../rootfs/etc/wicked/ifconfig/ifcfg.xml.ww")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
log string
|
||||
}{
|
||||
{
|
||||
name: "wicked",
|
||||
args: []string{"--render", "node1", "wicked", "etc/wicked/ifconfig/ifcfg.xml.ww"},
|
||||
log: wicked,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cmd := show.GetCommand()
|
||||
cmd.SetArgs(tt.args)
|
||||
stdout := bytes.NewBufferString("")
|
||||
stderr := bytes.NewBufferString("")
|
||||
logbuf := bytes.NewBufferString("")
|
||||
cmd.SetOut(stdout)
|
||||
cmd.SetErr(stderr)
|
||||
wwlog.SetLogWriter(logbuf)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, stdout.String())
|
||||
assert.Empty(t, stderr.String())
|
||||
assert.Equal(t, tt.log, logbuf.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const wicked string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: ifcfg-default.xml
|
||||
<!--
|
||||
This file is autogenerated by warewulf
|
||||
-->
|
||||
<interface origin="static generated warewulf config">
|
||||
<name>wwnet0</name>
|
||||
<link-type>ethernet</link-type>
|
||||
<control>
|
||||
<mode>boot</mode>
|
||||
</control>
|
||||
<firewall/>
|
||||
<link/>
|
||||
<ipv4>
|
||||
<enabled>true</enabled>
|
||||
<arp-verify>true</arp-verify>
|
||||
</ipv4>
|
||||
<ipv4:static>
|
||||
<address>
|
||||
<local>192.168.3.21/24</local>
|
||||
</address>
|
||||
<route>
|
||||
<nexthop>
|
||||
<gateway>192.168.3.1</gateway>
|
||||
</nexthop>
|
||||
</route>
|
||||
</ipv4:static>
|
||||
<ipv6>
|
||||
<enabled>true</enabled>
|
||||
<privacy>prefer-public</privacy>
|
||||
<accept-redirects>false</accept-redirects>
|
||||
</ipv6>
|
||||
</interface>
|
||||
backupFile: true
|
||||
writeFile: true
|
||||
Filename: ifcfg-secondary.xml
|
||||
<!--
|
||||
This file is autogenerated by warewulf
|
||||
-->
|
||||
<interface origin="static generated warewulf config">
|
||||
<name>wwnet1</name>
|
||||
<link-type>ethernet</link-type>
|
||||
<control>
|
||||
<mode>boot</mode>
|
||||
</control>
|
||||
<firewall/>
|
||||
<link/>
|
||||
<ipv4>
|
||||
<enabled>true</enabled>
|
||||
<arp-verify>true</arp-verify>
|
||||
</ipv4>
|
||||
<ipv4:static>
|
||||
<address>
|
||||
<local>192.168.3.22/24</local>
|
||||
</address>
|
||||
<route>
|
||||
<nexthop>
|
||||
<gateway>192.168.3.1</gateway>
|
||||
</nexthop>
|
||||
</route>
|
||||
</ipv4:static>
|
||||
<ipv6>
|
||||
<enabled>true</enabled>
|
||||
<privacy>prefer-public</privacy>
|
||||
<accept-redirects>false</accept-redirects>
|
||||
</ipv6>
|
||||
</interface>
|
||||
`
|
||||
@@ -1,15 +1,9 @@
|
||||
{{- $host := .BuildHost }}
|
||||
{{- $time := .BuildTime }}
|
||||
{{- $source := .BuildSource }}
|
||||
{{ $NetDevs := .NetDevs -}}{{/* FIX: 1413 */ -}}
|
||||
{{range $devname, $netdev := .ThisNode.NetDevs -}}
|
||||
{{- $filename := print "ifcfg-" $devname ".xml" }}
|
||||
{{- file $filename }}
|
||||
<!--
|
||||
This file is autogenerated by warewulf
|
||||
Host: {{ $host }}
|
||||
Time: {{ $time }}
|
||||
Source: {{ $source }}
|
||||
-->
|
||||
<interface origin="static generated warewulf config">
|
||||
<name>{{$netdev.Device.Get}}</name>
|
||||
58
overlays/wwclient/internal/nodes.conf
Normal file
58
overlays/wwclient/internal/nodes.conf
Normal file
@@ -0,0 +1,58 @@
|
||||
WW_INTERNAL: 45
|
||||
nodeprofiles:
|
||||
empty: {}
|
||||
nodes:
|
||||
node1:
|
||||
profiles:
|
||||
- empty
|
||||
container name: rockylinux-9
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:03
|
||||
ipaddr: 192.168.3.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
secondary:
|
||||
device: wwnet1
|
||||
hwaddr: 9a:77:29:73:14:f1
|
||||
ipaddr: 192.168.3.22
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
tags:
|
||||
DNS1: 8.8.8.8
|
||||
DNS2: 8.8.4.4
|
||||
ipmi:
|
||||
username: user
|
||||
password: password
|
||||
ipaddr: 192.168.4.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.4.1
|
||||
write: "true"
|
||||
disks:
|
||||
/dev/vda:
|
||||
wipe_table: "true"
|
||||
partitions:
|
||||
scratch:
|
||||
should_exist: "true"
|
||||
swap:
|
||||
number: "1"
|
||||
size_mib: "1024"
|
||||
filesystems:
|
||||
/dev/disk/by-partlabel/scratch:
|
||||
format: btrfs
|
||||
path: /scratch
|
||||
wipe_filesystem: "true"
|
||||
/dev/disk/by-partlabel/swap:
|
||||
format: swap
|
||||
path: swap
|
||||
node2:
|
||||
profiles:
|
||||
- empty
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:04
|
||||
ipaddr: 192.168.3.23
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
61
overlays/wwclient/internal/wwclient_test.go
Normal file
61
overlays/wwclient/internal/wwclient_test.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package wwclient
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/warewulf/warewulf/internal/app/wwctl/overlay/show"
|
||||
"github.com/warewulf/warewulf/internal/pkg/testenv"
|
||||
"github.com/warewulf/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
func Test_wwclientOverlay(t *testing.T) {
|
||||
env := testenv.New(t)
|
||||
defer env.RemoveAll(t)
|
||||
env.ImportFile(t, "etc/warewulf/nodes.conf", "nodes.conf")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/wwclient/rootfs/warewulf/init.d/80-wwclient.ww", "../rootfs/warewulf/init.d/80-wwclient.ww")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
log string
|
||||
}{
|
||||
{
|
||||
name: "wwclient:wwclient.ww",
|
||||
args: []string{"--render", "node1", "wwclient", "warewulf/init.d/80-wwclient.ww"},
|
||||
log: wwinit_wwclient,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cmd := show.GetCommand()
|
||||
cmd.SetArgs(tt.args)
|
||||
stdout := bytes.NewBufferString("")
|
||||
stderr := bytes.NewBufferString("")
|
||||
logbuf := bytes.NewBufferString("")
|
||||
cmd.SetOut(stdout)
|
||||
cmd.SetErr(stderr)
|
||||
wwlog.SetLogWriter(logbuf)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, stdout.String())
|
||||
assert.Empty(t, stderr.String())
|
||||
assert.Equal(t, tt.log, logbuf.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const wwinit_wwclient string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: warewulf/init.d/80-wwclient
|
||||
#!/bin/sh
|
||||
# This file is autogenerated by warewulf
|
||||
|
||||
. /warewulf/config
|
||||
# Only start if the systemd is not available
|
||||
test -e /usr/lib/systemd/systemd && exit 0
|
||||
echo "Starting wwclient"
|
||||
nohup /warewulf/wwclient >/var/log/wwclient.log 2>&1 </dev/null &
|
||||
`
|
||||
@@ -1,8 +1,5 @@
|
||||
#!/bin/sh
|
||||
# This file is autogenerated by warewulf
|
||||
# Host: {{.BuildHost}}
|
||||
# Time: {{.BuildTime}}
|
||||
# Source: {{.BuildSource}}
|
||||
|
||||
. /warewulf/config
|
||||
# Only start if the systemd is not available
|
||||
58
overlays/wwinit/internal/nodes.conf
Normal file
58
overlays/wwinit/internal/nodes.conf
Normal file
@@ -0,0 +1,58 @@
|
||||
WW_INTERNAL: 45
|
||||
nodeprofiles:
|
||||
empty: {}
|
||||
nodes:
|
||||
node1:
|
||||
profiles:
|
||||
- empty
|
||||
container name: rockylinux-9
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:03
|
||||
ipaddr: 192.168.3.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
secondary:
|
||||
device: wwnet1
|
||||
hwaddr: 9a:77:29:73:14:f1
|
||||
ipaddr: 192.168.3.22
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
tags:
|
||||
DNS1: 8.8.8.8
|
||||
DNS2: 8.8.4.4
|
||||
ipmi:
|
||||
username: user
|
||||
password: password
|
||||
ipaddr: 192.168.4.21
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.4.1
|
||||
write: "true"
|
||||
disks:
|
||||
/dev/vda:
|
||||
wipe_table: "true"
|
||||
partitions:
|
||||
scratch:
|
||||
should_exist: "true"
|
||||
swap:
|
||||
number: "1"
|
||||
size_mib: "1024"
|
||||
filesystems:
|
||||
/dev/disk/by-partlabel/scratch:
|
||||
format: btrfs
|
||||
path: /scratch
|
||||
wipe_filesystem: "true"
|
||||
/dev/disk/by-partlabel/swap:
|
||||
format: swap
|
||||
path: swap
|
||||
node2:
|
||||
profiles:
|
||||
- empty
|
||||
network devices:
|
||||
default:
|
||||
device: wwnet0
|
||||
hwaddr: e6:92:39:49:7b:04
|
||||
ipaddr: 192.168.3.23
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.3.1
|
||||
28
overlays/wwinit/internal/warewulf.conf
Normal file
28
overlays/wwinit/internal/warewulf.conf
Normal file
@@ -0,0 +1,28 @@
|
||||
WW_INTERNAL: 43
|
||||
ipaddr: 192.168.0.1/24
|
||||
netmask: 255.255.255.0
|
||||
network: 192.168.0.0
|
||||
warewulf:
|
||||
port: 9873
|
||||
secure: false
|
||||
update interval: 60
|
||||
autobuild overlays: true
|
||||
host overlay: true
|
||||
syslog: true
|
||||
dhcp:
|
||||
enabled: true
|
||||
range start: 192.168.0.100
|
||||
range end: 192.168.0.199
|
||||
tftp:
|
||||
enabled: false
|
||||
nfs:
|
||||
enabled: true
|
||||
export paths:
|
||||
- path: /home
|
||||
export options: rw,sync
|
||||
mount options: defaults
|
||||
mount: true
|
||||
- path: /opt
|
||||
export options: ro,sync,no_root_squash
|
||||
mount options: defaults
|
||||
mount: false
|
||||
103
overlays/wwinit/internal/wwinit_test.go
Normal file
103
overlays/wwinit/internal/wwinit_test.go
Normal file
@@ -0,0 +1,103 @@
|
||||
package wwinit
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/warewulf/warewulf/internal/app/wwctl/overlay/show"
|
||||
"github.com/warewulf/warewulf/internal/pkg/testenv"
|
||||
"github.com/warewulf/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
func Test_wwinitOverlay(t *testing.T) {
|
||||
env := testenv.New(t)
|
||||
defer env.RemoveAll(t)
|
||||
env.ImportFile(t, "etc/warewulf/warewulf.conf", "warewulf.conf")
|
||||
env.ImportFile(t, "etc/warewulf/nodes.conf", "nodes.conf")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/wwinit/rootfs/etc/warewulf/warewulf.conf.ww", "../rootfs/etc/warewulf/warewulf.conf.ww")
|
||||
env.ImportFile(t, "var/lib/warewulf/overlays/wwinit/rootfs/warewulf/config.ww", "../rootfs/warewulf/config.ww")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
log string
|
||||
}{
|
||||
{
|
||||
name: "wwinit:warewulf.conf.ww",
|
||||
args: []string{"--render", "node1", "wwinit", "etc/warewulf/warewulf.conf.ww"},
|
||||
log: wwinit_warewulf_conf,
|
||||
},
|
||||
{
|
||||
name: "wwinit:config.ww",
|
||||
args: []string{"--render", "node1", "wwinit", "warewulf/config.ww"},
|
||||
log: wwinit_config,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cmd := show.GetCommand()
|
||||
cmd.SetArgs(tt.args)
|
||||
stdout := bytes.NewBufferString("")
|
||||
stderr := bytes.NewBufferString("")
|
||||
logbuf := bytes.NewBufferString("")
|
||||
cmd.SetOut(stdout)
|
||||
cmd.SetErr(stderr)
|
||||
wwlog.SetLogWriter(logbuf)
|
||||
err := cmd.Execute()
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, stdout.String())
|
||||
assert.Empty(t, stderr.String())
|
||||
assert.Equal(t, tt.log, logbuf.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const wwinit_warewulf_conf string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: etc/warewulf/warewulf.conf
|
||||
WW_INTERNAL: 43
|
||||
ipaddr: 192.168.0.1/24
|
||||
netmask: 255.255.255.0
|
||||
network: 192.168.0.0
|
||||
warewulf:
|
||||
port: 9873
|
||||
secure: false
|
||||
update interval: 60
|
||||
autobuild overlays: true
|
||||
host overlay: true
|
||||
syslog: true
|
||||
dhcp:
|
||||
enabled: true
|
||||
range start: 192.168.0.100
|
||||
range end: 192.168.0.199
|
||||
tftp:
|
||||
enabled: false
|
||||
nfs:
|
||||
enabled: true
|
||||
export paths:
|
||||
- path: /home
|
||||
export options: rw,sync
|
||||
mount options: defaults
|
||||
mount: true
|
||||
- path: /opt
|
||||
export options: ro,sync,no_root_squash
|
||||
mount options: defaults
|
||||
mount: false
|
||||
`
|
||||
|
||||
const wwinit_config string = `backupFile: true
|
||||
writeFile: true
|
||||
Filename: warewulf/config
|
||||
WWCONTAINER=rockylinux-9
|
||||
WWHOSTNAME=node1
|
||||
WWROOT=initramfs
|
||||
WWINIT=/sbin/init
|
||||
WWIPMI_IPADDR="192.168.4.21"
|
||||
WWIPMI_NETMASK="255.255.255.0"
|
||||
WWIPMI_GATEWAY="192.168.4.1"
|
||||
WWIPMI_USER="user"
|
||||
WWIPMI_PASSWORD="password"
|
||||
WWIPMI_WRITE="true"
|
||||
`
|
||||
@@ -1,48 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/warewulf/warewulf/internal/pkg/batch"
|
||||
)
|
||||
|
||||
func exampleJob(name string, id int) string {
|
||||
fmt.Printf("[%d] %s started...\n", id, name)
|
||||
time.Sleep(time.Second * time.Duration(id))
|
||||
fmt.Printf("[%d] %s ending...\n", id, name)
|
||||
return name
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
fmt.Printf("GOMAXPROCS=%d\n", runtime.GOMAXPROCS(0))
|
||||
|
||||
jobstorun := 100
|
||||
|
||||
// create batch pool to run 100 jobs at a time every 10 seconds
|
||||
batchpool := batch.New(10)
|
||||
retvalues := make(chan string, jobstorun)
|
||||
|
||||
// submit a bunch of jobs
|
||||
for i := 0; i < jobstorun; i++ {
|
||||
|
||||
name := fmt.Sprintf("job-%04d", i)
|
||||
id := i
|
||||
batchpool.Submit(func() {
|
||||
retvalues <- exampleJob(name, id)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
// Run all batch jobs to completion
|
||||
batchpool.Run()
|
||||
|
||||
close(retvalues)
|
||||
|
||||
for s := range retvalues {
|
||||
fmt.Printf("Return value is %s\n", s)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -98,7 +98,7 @@ explained as follows:
|
||||
When ``true``, ``wwclient`` uses TCP port 987.
|
||||
|
||||
Changing this option requires rebuilding node overlays and rebooting
|
||||
compute nodes, to configure them to use a privileged port.
|
||||
compute nodes to configure them to use a privileged port.
|
||||
|
||||
* ``warewulf:update interval``: This defines the frequency (in
|
||||
seconds) with which the Warewulf client on the compute node fetches
|
||||
@@ -205,29 +205,7 @@ a "runtime overlay" specified, the respective value from
|
||||
``defaultnode`` is used. If a network device does not specify a
|
||||
"device," the device value of the ``dummy`` device is used.
|
||||
|
||||
If ``defaults.conf`` does not exist, the following values are used as
|
||||
compiled into Warewulf at build-time:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
--
|
||||
defaultnode:
|
||||
runtime overlay:
|
||||
- generic
|
||||
system overlay:
|
||||
- wwinit
|
||||
kernel:
|
||||
args: quiet crashkernel=no vga=791 net.naming-scheme=v238
|
||||
init: /sbin/init
|
||||
root: initramfs
|
||||
ipxe template: default
|
||||
profiles:
|
||||
- default
|
||||
network devices:
|
||||
dummy:
|
||||
device: eth0
|
||||
type: ethernet
|
||||
netmask: 255.255.255.0
|
||||
If ``defaults.conf`` does not exist, compiled-in defaults are used.
|
||||
|
||||
There should never be a need to change this file: all site-local
|
||||
parameters should be specified using either nodes or profiles.
|
||||
|
||||
@@ -57,7 +57,7 @@ Ignition Implementation
|
||||
=======================
|
||||
|
||||
The ignition implementation uses systemd services, as the underlying ``sgdisk`` command relies on dbus notifications.
|
||||
All necessary services are distributed by the ``wwinit`` overlay and depends on the existence of the file ``/warewulf/ignition.json``.
|
||||
All necessary services are distributed by the ``ignition`` overlay and depends on the existence of the file ``/warewulf/ignition.json``.
|
||||
This file is created by the template function ``{{ createIgnitionJson }}`` only if the configuration contains necessary specifications for disks, partitions, and file systems.
|
||||
If the file ``/warewulf/ignition.json`` exists, the service ``ignition-disks-ww4.service`` calls the ignition binary which takes creates partitions and file systems.
|
||||
A systemd ``.mount`` unit is created for each configured file system, which also creates the necessary mount points in the root file system.
|
||||
|
||||
@@ -22,10 +22,10 @@ properly. Here are the things it will do:
|
||||
the system service.
|
||||
* **hostfile**: Update the system's /etc/hosts file based on the
|
||||
**host** template ``/etc/hosts.ww``.
|
||||
* **nfs**: Configure the NFS server on the control node as well as the
|
||||
``/etc/fstab`` in the system overlay based on the configuration in
|
||||
``/etc/warewulf/warewulf.conf`` and enable the system service. Also
|
||||
the file ``/etc/exports.ww`` from the **host** template is installed.
|
||||
* **nfs**: Configure the NFS server on the control node based on the
|
||||
configuration in ``/etc/warewulf/warewulf.conf`` and enable the NFS
|
||||
service. Also the file ``/etc/exports.ww`` from the **host** template is
|
||||
installed.
|
||||
* **ssh**: Create the appropriate host keys (stored in
|
||||
``/etc/warewulf/keys/``) and user keys for passwordless ``ssh`` into
|
||||
the nodes. Addionally the shell profiles
|
||||
|
||||
@@ -15,7 +15,7 @@ individual node would be the IP address.
|
||||
|
||||
The settings are only written to the IPMI interface if ``--ipmiwrite``
|
||||
is set to `true`. The write process happens at every boot of the node
|
||||
through the script ``/warewulf/init.d/50-ipmi`` in the **system**
|
||||
through the script ``/warewulf/init.d/50-ipmi`` in the wwinit
|
||||
overlay.
|
||||
|
||||
If an individual node has different settings, you can set the IPMI
|
||||
@@ -99,8 +99,8 @@ Node View
|
||||
n001 cluster -- --
|
||||
n001 container default sle-micro-5.3
|
||||
n001 ipxe -- (default)
|
||||
n001 runtime -- (generic)
|
||||
n001 wwinit -- (wwinit)
|
||||
n001 runtime -- (hosts,ssh.authorized_keys,syncuser)
|
||||
n001 wwinit -- (wwinit,wwclient,fstab,hostname,ssh.host_keys,issue,resolv,udev.netname,systemd.netname,ifcfg,NetworkManager,debian.interfaces,wicked,ignition)
|
||||
n001 root -- (initramfs)
|
||||
n001 discoverable -- --
|
||||
n001 init -- (/sbin/init)
|
||||
|
||||
@@ -87,8 +87,8 @@ You can also see the node's full attribute list by specifying the
|
||||
n001 cluster -- --
|
||||
n001 container default sle-micro-5.3
|
||||
n001 ipxe -- (default)
|
||||
n001 runtime -- (generic)
|
||||
n001 wwinit -- (wwinit)
|
||||
n001 runtime -- (hosts,ssh.authorized_keys,syncuser)
|
||||
n001 wwinit -- (wwinit,wwclient,fstab,hostname,ssh.host_keys,issue,resolv,udev.netname,systemd.netname,ifcfg,NetworkManager,debian.interfaces,wicked,ignition)
|
||||
n001 root -- (initramfs)
|
||||
n001 discoverable -- --
|
||||
n001 init -- (/sbin/init)
|
||||
@@ -193,8 +193,8 @@ container, kernel, and network:
|
||||
n001 cluster -- --
|
||||
n001 container default sle-micro-5.3
|
||||
n001 ipxe -- (default)
|
||||
n001 runtime -- (generic)
|
||||
n001 wwinit -- (wwinit)
|
||||
n001 runtime -- (hosts,ssh.authorized_keys,syncuser)
|
||||
n001 wwinit -- (wwinit,wwclient,fstab,hostname,ssh.host_keys,issue,resolv,udev.netname,systemd.netname,ifcfg,NetworkManager,debian.interfaces,wicked,ignition)
|
||||
n001 root -- (initramfs)
|
||||
n001 discoverable -- --
|
||||
n001 init -- (/sbin/init)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user