Skip to content

Commit

Permalink
Merge pull request warewulf#1477 from anderbubble/vlans-and-static-route
Browse files Browse the repository at this point in the history
Add support for tagged VLAN interfaces and static routes to network overlays
  • Loading branch information
mslacken authored Nov 7, 2024
2 parents de2a0bd + 6d699a2 commit 0e0b49a
Show file tree
Hide file tree
Showing 16 changed files with 445 additions and 162 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Add `wwctl clean` to remove OCI cache and overlays from deleted nodes
- Add `wwctl container import --platform`. #1381
- Read environment variables from `/etc/default/warewulfd` #725
- Add support for VLANs to NetworkManager, wicked, ifcfg, debian.network_interfaces overlays. #1257
- Add support for static routes to NetworkManager, wicked, ifcfg, debian.network_interfaces overlays. #1257

### Changed

Expand Down
124 changes: 77 additions & 47 deletions overlays/NetworkManager/internal/networkmanager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,66 +13,44 @@ import (
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 string
nodes_conf 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-unmanaged.ww",
nodes_conf: "nodes.conf",
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,
name: "NetworkManager:ww4-managed.ww",
nodes_conf: "nodes.conf",
args: []string{"--render", "node1", "NetworkManager", "etc/NetworkManager/system-connections/ww4-managed.ww"},
log: networkmanager_managed,
},
{
name: "NetworkManager:ww4-unmanaged.ww with empty mac address",
nodes_conf: "nodes_empty_mac.conf",
args: []string{"--render", "node1", "NetworkManager", "etc/NetworkManager/conf.d/ww4-unmanaged.ww"},
log: networkmanager_unmanaged_with_empty_mac,
},
}

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

func Test_unmanaged_networkmanagerOverlay_with_empty_mac(t *testing.T) {
env := testenv.New(t)
defer env.RemoveAll(t)
env.ImportFile(t, "etc/warewulf/nodes.conf", "nodes_empty_mac.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")

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_with_empty_mac,
name: "NetworkManager:ww4-managed.ww with vlan",
nodes_conf: "nodes.conf-vlan",
args: []string{"--render", "node1", "NetworkManager", "etc/NetworkManager/system-connections/ww4-managed.ww"},
log: networkmanager_managed_with_vlan,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
env.ImportFile(t, "etc/warewulf/nodes.conf", tt.nodes_conf)
cmd := show.GetCommand()
cmd.SetArgs(tt.args)
stdout := bytes.NewBufferString("")
Expand All @@ -94,6 +72,7 @@ const networkmanager_unmanaged_with_empty_mac string = `backupFile: true
writeFile: true
Filename: warewulf-unmanaged.conf
# This file is autogenerated by warewulf
[main]
plugins=keyfile
Expand All @@ -105,6 +84,7 @@ const networkmanager_unmanaged string = `backupFile: true
writeFile: true
Filename: warewulf-unmanaged.conf
# This file is autogenerated by warewulf
[main]
plugins=keyfile
Expand All @@ -116,14 +96,16 @@ 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
Expand All @@ -137,14 +119,16 @@ 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
Expand All @@ -156,3 +140,49 @@ addr-gen-mode=stable-privacy
method=ignore
never-default=true
`

const networkmanager_managed_with_vlan string = `backupFile: true
writeFile: true
Filename: warewulf-tagged.conf
# This file is autogenerated by warewulf
[connection]
id=tagged
interface-name=eth0.902
type=vlan
autoconnect=true
[ipv4]
address=<nil>
method=manual
route1=192.168.1.0/24,192.168.2.254
[vlan]
interface-name=eth0.902
parent=eth0
id=902
[ipv6]
addr-gen-mode=stable-privacy
method=ignore
never-default=true
backupFile: true
writeFile: true
Filename: warewulf-untagged.conf
# This file is autogenerated by warewulf
[connection]
id=untagged
interface-name=eth0
type=ethernet
autoconnect=true
[ipv4]
address=<nil>
method=manual
[ipv6]
addr-gen-mode=stable-privacy
method=ignore
never-default=true
`
13 changes: 13 additions & 0 deletions overlays/NetworkManager/internal/nodes.conf-vlan
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
nodes:
node1:
primary network: untagged
network devices:
untagged:
device: eth0
tagged:
type: vlan
device: eth0.902
tags:
vlan_id: 902
parent_device: eth0
route1: "192.168.1.0/24,192.168.2.254"
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{{- $filename := print "warewulf-unmanaged.conf" }}
{{- file $filename }}
# This file is autogenerated by warewulf

[main]
plugins=keyfile

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,78 +2,84 @@
{{- $filename := print "warewulf-" $connection_id ".conf" }}
{{- file $filename }}
# This file is autogenerated by warewulf

[connection]
id={{ $connection_id }}
interface-name={{ $netdev.Device }}
{{ if eq $netdev.Type "bond-slave" -}}
{{- if eq $netdev.Type "bond-slave" }}
slave-type=bond
{{- $conn := split "_" $connection_id }}
{{- $master := $conn._0 }}
master={{ $master }}
type=ethernet
{{ else -}}
{{- else }}
type={{if $netdev.Type}}{{ $netdev.Type }}{{ else }}ethernet{{end}}
{{ if or $netdev.OnBoot (eq $netdev.OnBoot nil) -}}
{{- if or $netdev.OnBoot (eq $netdev.OnBoot nil) }}
autoconnect=true
{{ end -}}
{{ end -}}
{{ if $netdev.Hwaddr -}}
{{ if or (eq $netdev.Type "ethernet") (not $netdev.Type ) -}}
{{- end }}
{{- end }}
{{- if $netdev.Hwaddr }}
{{- if or (eq $netdev.Type "ethernet") (not $netdev.Type ) }}

[ethernet]
mac-address={{ $netdev.Hwaddr }}
{{ if $netdev.MTU -}}
{{- if $netdev.MTU }}
mtu={{ $netdev.MTU }}
{{ end -}}
{{ end -}}
{{ end -}}
{{- end }}
{{- end }}
{{- end }}
{{- if eq $netdev.Type "bond" }}

# bond
{{ if eq $netdev.Type "bond" -}}
[ethernet]
{{ if $netdev.MTU -}}
mtu={{ $netdev.MTU }}
{{ end -}}
[bond]
downdelay=0
miimon=100
mode=802.3ad
xmit_hash_policy=layer2+3
updelay=0
{{ end -}}
{{- end }}
{{- if eq $netdev.Type "infiniband" }}

{{ if eq $netdev.Type "infiniband" -}}
[infiniband]
transport-mode=datagram
{{ if $netdev.MTU -}}
{{- if $netdev.MTU }}
mtu={{ $netdev.MTU }}
{{ end -}}
{{ end -}}
{{- end }}
{{- end }}
{{- if ne $netdev.Type "bond-slave" }}

{{ if and ($netdev.IpCIDR) (ne $netdev.Type "bond-slave") -}}
[ipv4]
{{- if not (eq $netdev.IpCIDR nil) }}
address={{ $netdev.IpCIDR }}
{{ if $netdev.Gateway -}}
{{- end }}
{{- if $netdev.Gateway }}
gateway={{ $netdev.Gateway }}
{{ end -}}
{{- end }}
method=manual
{{- $dns := "" }}
{{range $tk, $tv := $netdev.Tags -}}
{{ $prefix := substr 0 3 $tk -}}
{{ if eq $prefix "DNS" -}}
{{ $dns = print $dns $tv ";" -}}
{{ end -}}
{{ end -}}
{{ if ne $dns "" -}}
{{- range $tk, $tv := $netdev.Tags }}
{{- if eq (substr 0 3 $tk) "DNS" }}
{{- $dns = print $dns $tv ";" }}
{{- else if eq (substr 0 5 $tk) "route" }}
{{$tk}}={{$tv}}
{{- end }}
{{- end }}
{{- if ne $dns "" }}
dns={{$dns}}
{{ end -}}
{{ end -}}
{{- end }}
{{- end }}
{{- if eq $netdev.Type "vlan" }}

[vlan]
interface-name={{ $netdev.Device }}
parent={{ $netdev.Tags.parent_device }}
id={{ $netdev.Tags.vlan_id }}
{{- end }}

{{/* always autoconfigure ipv6 */}}
[ipv6]
addr-gen-mode=stable-privacy
method=ignore
never-default=true
{{ if $netdev.Ipaddr6 -}}
ipaddr="{{ $netdev.Ipaddr6 }}"
{{ end -}}
{{ end -}}
{{- end }}
{{- end -}}
18 changes: 10 additions & 8 deletions overlays/debian.interfaces/internal/debian_interfaces_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,25 @@ import (
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 string
nodes_conf string
args []string
log string
}{
{
name: "debian.interfaces",
args: []string{"--render", "node1", "debian.interfaces", "etc/network/interfaces.d/default.ww"},
log: debian_interfaces,
name: "debian.interfaces",
nodes_conf: "nodes.conf",
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) {
env.ImportFile(t, "etc/warewulf/nodes.conf", tt.nodes_conf)
cmd := show.GetCommand()
cmd.SetArgs(tt.args)
stdout := bytes.NewBufferString("")
Expand Down Expand Up @@ -69,5 +71,5 @@ iface wwnet1 inet static
netmask 255.255.255.0
gateway 192.168.3.1
mtu 9000
up ifmetric wwnet1 30
up ip route add 192.168.1.0/24 via 192.168.3.254 dev wwnet1
`
2 changes: 2 additions & 0 deletions overlays/debian.interfaces/internal/nodes.conf
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ nodes:
netmask: 255.255.255.0
gateway: 192.168.3.1
mtu: 9000
tags:
route1: "192.168.1.0/24,192.168.3.254"
Loading

0 comments on commit 0e0b49a

Please sign in to comment.