From 2355fce6299ca997d8843dd2d561f8e157aee572 Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Tue, 6 Jan 2026 16:22:44 -0700 Subject: [PATCH 1/2] Prevent ignition from running twice in a provision-to-disk configuration Ignition runs during provision-to-disk, and then also tries to run again during sytsemd. This commit adds a sentinel file during the initial provision-to-disk that is detected by systemd to prevent re-running ignition partitioning / formatting. - Fixes: #1981 Signed-off-by: Jonathon Anderson --- CHANGELOG.md | 1 + dracut/modules.d/90wwinit/load-wwinit.sh | 8 ++++++++ .../rootfs/etc/systemd/system/ignition-ww4-disks.service | 3 +-- .../ignition/rootfs/warewulf/wwinit.d/10-ignition.sh | 9 ++++++++- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4228de84..18f124ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Fix warewulf-dracut to not run the wwinit module if root is not set to `root=wwclient*` - Fix `wwctl image import --update` #2066 - Fix filesystem overwrite/force behavior in mkfs overlay. #2028 +- Prevent ignition from running twice in a provision-to-disk configuration. #1981 ### Dependencies diff --git a/dracut/modules.d/90wwinit/load-wwinit.sh b/dracut/modules.d/90wwinit/load-wwinit.sh index 5bf3c29d..a06c33b8 100644 --- a/dracut/modules.d/90wwinit/load-wwinit.sh +++ b/dracut/modules.d/90wwinit/load-wwinit.sh @@ -46,3 +46,11 @@ info "warewulf: mounting ${wwinit_root_device} at ${NEWROOT}" for stage in "image" "system" "runtime"; do get_stage "${stage}" done + +# Copy /warewulf/run from initramfs to NEWROOT +# This preserves state files created by wwinit.d scripts (e.g., ignition marker) +if [ -d /tmp/wwinit/warewulf/run ]; then + info "warewulf: preserving /warewulf/run to mounted root" + mkdir -p "${NEWROOT}/warewulf" + cp -a /tmp/wwinit/warewulf/run "${NEWROOT}/warewulf/" +fi diff --git a/overlays/ignition/rootfs/etc/systemd/system/ignition-ww4-disks.service b/overlays/ignition/rootfs/etc/systemd/system/ignition-ww4-disks.service index 8c2b039c..c99d89f5 100644 --- a/overlays/ignition/rootfs/etc/systemd/system/ignition-ww4-disks.service +++ b/overlays/ignition/rootfs/etc/systemd/system/ignition-ww4-disks.service @@ -3,10 +3,9 @@ Description=Ignition warewulf (disks) Documentation=https://warewulf.org/ ConditionPathExists=/warewulf/ignition.json ConditionPathExists=/usr/lib/dracut/modules.d/30ignition/ignition +ConditionPathExists=!/warewulf/run/.ignition-done DefaultDependencies=false -Before=ignition-ww4-mount.service - # This stage runs between `basic.target` and `initrd-root-device.target`, # see https://www.freedesktop.org/software/systemd/man/bootup.html # Make sure to run before the file system checks, as sgdisk will trigger diff --git a/overlays/ignition/rootfs/warewulf/wwinit.d/10-ignition.sh b/overlays/ignition/rootfs/warewulf/wwinit.d/10-ignition.sh index 77856ce6..dd47d1a9 100644 --- a/overlays/ignition/rootfs/warewulf/wwinit.d/10-ignition.sh +++ b/overlays/ignition/rootfs/warewulf/wwinit.d/10-ignition.sh @@ -17,7 +17,14 @@ fi if command -v ignition >/dev/null; then : info "warewulf: ignition: partition and format disks" - ignition --config-cache="${PREFIX}/warewulf/ignition.json" --platform=metal --stage=disks || die "warewulf: ignition: failed to partition/format disk" + if ignition --config-cache="${PREFIX}/warewulf/ignition.json" --platform=metal --stage=disks; then + # Create marker file to signal successful completion + # This prevents the systemd service from running ignition again after switch_root + mkdir -p "${PREFIX}/warewulf/run" + echo "ignition run by 10-ignition.sh" >"${PREFIX}/warewulf/run/.ignition-done" + else + die "warewulf: ignition: failed to partition/format disk" + fi else info "warewulf: ignition not found" fi From 44eeba13f7e961f0fbce65c9fd66816e1b955237 Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Tue, 6 Jan 2026 16:59:28 -0700 Subject: [PATCH 2/2] Rename systemd templates in the `ignition` overlay for clarity Signed-off-by: Jonathon Anderson --- CHANGELOG.md | 1 + overlays/ignition/internal/ignition_test.go | 90 +++++++++++-------- .../{ww4-mounts.ww => ignition.mount.ww} | 46 +++------- .../etc/systemd/system/ignition.swap.ww | 35 ++++++++ .../ignition-ww4-disks.service | 1 - .../ww-ignition-disks.target | 1 + .../local-fs.target.wants/ww-ignition.service | 1 + .../local-fs.target.wants/ww4-disks.target | 1 - ....target.ww => ww-ignition-disks.target.ww} | 6 +- ...-ww4-disks.service => ww-ignition.service} | 0 10 files changed, 104 insertions(+), 78 deletions(-) rename overlays/ignition/rootfs/etc/systemd/system/{ww4-mounts.ww => ignition.mount.ww} (50%) create mode 100644 overlays/ignition/rootfs/etc/systemd/system/ignition.swap.ww delete mode 120000 overlays/ignition/rootfs/etc/systemd/system/local-fs.target.wants/ignition-ww4-disks.service create mode 120000 overlays/ignition/rootfs/etc/systemd/system/local-fs.target.wants/ww-ignition-disks.target create mode 120000 overlays/ignition/rootfs/etc/systemd/system/local-fs.target.wants/ww-ignition.service delete mode 120000 overlays/ignition/rootfs/etc/systemd/system/local-fs.target.wants/ww4-disks.target rename overlays/ignition/rootfs/etc/systemd/system/{ww4-disks.target.ww => ww-ignition-disks.target.ww} (86%) rename overlays/ignition/rootfs/etc/systemd/system/{ignition-ww4-disks.service => ww-ignition.service} (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18f124ea..fa11d020 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Added Ipv6 support to `/etc/hosts` on host and nodes. - Added IPv6 support to wwclient - `sfdisk` overlay creates a GPT label when wiping disks. #2025 +- Renamed systemd templates in the `ignition` overlay for clarity. ### Removed diff --git a/overlays/ignition/internal/ignition_test.go b/overlays/ignition/internal/ignition_test.go index 10633944..792561a2 100644 --- a/overlays/ignition/internal/ignition_test.go +++ b/overlays/ignition/internal/ignition_test.go @@ -17,8 +17,8 @@ func Test_ignitionOverlay(t *testing.T) { output string isJson bool }{ - "ignition:ww4-disks.target": { - args: []string{"--quiet", "--render", "node1", "ignition", "etc/systemd/system/ww4-disks.target.ww"}, + "ignition:ww-ignition-disks.target": { + args: []string{"--quiet", "--render", "node1", "ignition", "etc/systemd/system/ww-ignition-disks.target.ww"}, nodesConf: ` nodes: node1: @@ -44,17 +44,17 @@ nodes: [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 +Requires=ww-ignition.service +After=ww-ignition.service +Requisite=ww-ignition.service # Get the mounts Wants=scratch.mount Wants=dev-disk-by\x2dpartlabel-swap.swap `, isJson: false, }, - "ignition:ww4-disks.target (resources)": { - args: []string{"--quiet", "--render", "node1", "ignition", "etc/systemd/system/ww4-disks.target.ww"}, + "ignition:ww-ignition-disks.target (resources)": { + args: []string{"--quiet", "--render", "node1", "ignition", "etc/systemd/system/ww-ignition-disks.target.ww"}, nodesConf: ` nodes: node1: @@ -83,17 +83,17 @@ nodes: [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 +Requires=ww-ignition.service +After=ww-ignition.service +Requisite=ww-ignition.service # Get the mounts Wants=scratch.mount Wants=dev-disk-by\x2dpartlabel-swap.swap `, isJson: false, }, - "ignition:ww4-mounts": { - args: []string{"--quiet=false", "--render", "node1", "ignition", "etc/systemd/system/ww4-mounts.ww"}, + "ignition:ignition.mount": { + args: []string{"--quiet=false", "--render", "node1", "ignition", "etc/systemd/system/ignition.mount.ww"}, nodesConf: ` nodes: node1: @@ -124,8 +124,8 @@ Filename: scratch.mount [Unit] ConditionPathExists=/warewulf/ignition.json Before=local-fs.target -Requires=ignition-ww4-disks.service -After=ignition-ww4-disks.service +Requires=ww-ignition.service +After=ww-ignition.service [Mount] Where=/scratch What=/dev/disk/by-partlabel/scratch @@ -133,25 +133,11 @@ Type=btrfs Options=nondefault [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 -Requires=ignition-ww4-disks.service -After=ignition-ww4-disks.service -Before=swap.target -[Swap] -What=/dev/disk/by-partlabel/swap -[Install] -RequiredBy=swap.target `, isJson: false, }, - "ignition:ww4-mounts (resources)": { - args: []string{"--quiet=false", "--render", "node1", "ignition", "etc/systemd/system/ww4-mounts.ww"}, + "ignition:ignition.mount (resources)": { + args: []string{"--quiet=false", "--render", "node1", "ignition", "etc/systemd/system/ignition.mount.ww"}, nodesConf: ` nodes: node1: @@ -184,23 +170,52 @@ Filename: scratch.mount [Unit] ConditionPathExists=/warewulf/ignition.json Before=local-fs.target -Requires=ignition-ww4-disks.service -After=ignition-ww4-disks.service +Requires=ww-ignition.service +After=ww-ignition.service [Mount] Where=/scratch What=/dev/disk/by-partlabel/scratch Type=btrfs [Install] RequiredBy=local-fs.target -backupFile: true +`, + isJson: false, + }, + "ignition:ignition.swap (resources)": { + args: []string{"--quiet=false", "--render", "node1", "ignition", "etc/systemd/system/ignition.swap.ww"}, + nodesConf: ` +nodes: + node1: + resources: + ignition: + storage: + disks: + - device: /dev/vda + wipeTable: true + partitions: + scratch: + shouldExist: true + swap: + number: 1 + sizeMiB: 1024 + filesystems: + - device: /dev/disk/by-partlabel/scratch + format: btrfs + path: /scratch + wipeFilesystem: true + - device: /dev/disk/by-partlabel/swap + format: swap + path: swap`, + output: `backupFile: true writeFile: true Filename: dev-disk-by\x2dpartlabel-swap.swap + # This file is autogenerated by warewulf [Unit] ConditionPathExists=/warewulf/ignition.json -Requires=ignition-ww4-disks.service -After=ignition-ww4-disks.service +Requires=ww-ignition.service +After=ww-ignition.service Before=swap.target [Swap] What=/dev/disk/by-partlabel/swap @@ -325,8 +340,9 @@ nodes: t.Run(name, func(t *testing.T) { env := testenv.New(t) defer env.RemoveAll() - env.ImportFile("var/lib/warewulf/overlays/ignition/rootfs/etc/systemd/system/ww4-disks.target.ww", "../rootfs/etc/systemd/system/ww4-disks.target.ww") - env.ImportFile("var/lib/warewulf/overlays/ignition/rootfs/etc/systemd/system/ww4-mounts.ww", "../rootfs/etc/systemd/system/ww4-mounts.ww") + env.ImportFile("var/lib/warewulf/overlays/ignition/rootfs/etc/systemd/system/ww-ignition-disks.target.ww", "../rootfs/etc/systemd/system/ww-ignition-disks.target.ww") + env.ImportFile("var/lib/warewulf/overlays/ignition/rootfs/etc/systemd/system/ignition.mount.ww", "../rootfs/etc/systemd/system/ignition.mount.ww") + env.ImportFile("var/lib/warewulf/overlays/ignition/rootfs/etc/systemd/system/ignition.swap.ww", "../rootfs/etc/systemd/system/ignition.swap.ww") env.ImportFile("var/lib/warewulf/overlays/ignition/rootfs/warewulf/ignition.json.ww", "../rootfs/warewulf/ignition.json.ww") env.WriteFile("etc/warewulf/nodes.conf", tt.nodesConf) cmd := show.GetCommand() diff --git a/overlays/ignition/rootfs/etc/systemd/system/ww4-mounts.ww b/overlays/ignition/rootfs/etc/systemd/system/ignition.mount.ww similarity index 50% rename from overlays/ignition/rootfs/etc/systemd/system/ww4-mounts.ww rename to overlays/ignition/rootfs/etc/systemd/system/ignition.mount.ww index b666fef5..545e7acc 100644 --- a/overlays/ignition/rootfs/etc/systemd/system/ww4-mounts.ww +++ b/overlays/ignition/rootfs/etc/systemd/system/ignition.mount.ww @@ -1,27 +1,15 @@ {{- if .FileSystems }} {{- range $fsdevice, $fs := .FileSystems }} -{{- if eq $fs.Format "swap" }} -{{ file (print ($fsdevice | SystemdEscapePath) ".swap") }} -# This file is autogenerated by warewulf - -[Unit] -ConditionPathExists=/warewulf/ignition.json -Requires=ignition-ww4-disks.service -After=ignition-ww4-disks.service -Before=swap.target -[Swap] -What={{ $fsdevice }} -[Install] -RequiredBy=swap.target -{{- else if ne $fs.Path "" }} +{{- if ne $fs.Format "swap" }} +{{- if ne $fs.Path "" }} {{ file (print ($fs.Path | SystemdEscapePath) ".mount") }} # This file is autogenerated by warewulf [Unit] ConditionPathExists=/warewulf/ignition.json Before=local-fs.target -Requires=ignition-ww4-disks.service -After=ignition-ww4-disks.service +Requires=ww-ignition.service +After=ww-ignition.service [Mount] Where={{ $fs.Path }} What={{ $fsdevice }} @@ -31,34 +19,21 @@ Options={{ $fs.MountOptions }} {{- end }} [Install] RequiredBy=local-fs.target -{{- else }} -{{- continue }} +{{- end }} {{- end }} {{- end }} {{- else if .Resources.ignition.storage.filesystems }} {{- range $fs := .Resources.ignition.storage.filesystems }} -{{- if eq $fs.format "swap" }} -{{ file (print ($fs.device | SystemdEscapePath) ".swap") }} -# This file is autogenerated by warewulf - -[Unit] -ConditionPathExists=/warewulf/ignition.json -Requires=ignition-ww4-disks.service -After=ignition-ww4-disks.service -Before=swap.target -[Swap] -What={{ $fs.device }} -[Install] -RequiredBy=swap.target -{{- else if ne $fs.path "" }} +{{- if ne $fs.format "swap" }} +{{- if ne $fs.path "" }} {{ file (print ($fs.path | SystemdEscapePath) ".mount") }} # This file is autogenerated by warewulf [Unit] ConditionPathExists=/warewulf/ignition.json Before=local-fs.target -Requires=ignition-ww4-disks.service -After=ignition-ww4-disks.service +Requires=ww-ignition.service +After=ww-ignition.service [Mount] Where={{ $fs.path }} What={{ $fs.device }} @@ -68,8 +43,7 @@ Options={{ $fs.mountOptions | join "." }} {{- end }} [Install] RequiredBy=local-fs.target -{{- else }} -{{- continue }} +{{- end }} {{- end }} {{- end }} {{- end }} diff --git a/overlays/ignition/rootfs/etc/systemd/system/ignition.swap.ww b/overlays/ignition/rootfs/etc/systemd/system/ignition.swap.ww new file mode 100644 index 00000000..81ce00c2 --- /dev/null +++ b/overlays/ignition/rootfs/etc/systemd/system/ignition.swap.ww @@ -0,0 +1,35 @@ +{{- if .FileSystems }} +{{- range $fsdevice, $fs := .FileSystems }} +{{- if eq $fs.Format "swap" }} +{{ file (print ($fsdevice | SystemdEscapePath) ".swap") }} +# This file is autogenerated by warewulf + +[Unit] +ConditionPathExists=/warewulf/ignition.json +Requires=ww-ignition.service +After=ww-ignition.service +Before=swap.target +[Swap] +What={{ $fsdevice }} +[Install] +RequiredBy=swap.target +{{- end }} +{{- end }} +{{- else if .Resources.ignition.storage.filesystems }} +{{- range $fs := .Resources.ignition.storage.filesystems }} +{{- if eq $fs.format "swap" }} +{{ file (print ($fs.device | SystemdEscapePath) ".swap") }} +# This file is autogenerated by warewulf + +[Unit] +ConditionPathExists=/warewulf/ignition.json +Requires=ww-ignition.service +After=ww-ignition.service +Before=swap.target +[Swap] +What={{ $fs.device }} +[Install] +RequiredBy=swap.target +{{- end }} +{{- end }} +{{- end }} diff --git a/overlays/ignition/rootfs/etc/systemd/system/local-fs.target.wants/ignition-ww4-disks.service b/overlays/ignition/rootfs/etc/systemd/system/local-fs.target.wants/ignition-ww4-disks.service deleted file mode 120000 index 726d662c..00000000 --- a/overlays/ignition/rootfs/etc/systemd/system/local-fs.target.wants/ignition-ww4-disks.service +++ /dev/null @@ -1 +0,0 @@ -/etc/systemd/system/ignition-ww4-disks.service \ No newline at end of file diff --git a/overlays/ignition/rootfs/etc/systemd/system/local-fs.target.wants/ww-ignition-disks.target b/overlays/ignition/rootfs/etc/systemd/system/local-fs.target.wants/ww-ignition-disks.target new file mode 120000 index 00000000..ca2f6763 --- /dev/null +++ b/overlays/ignition/rootfs/etc/systemd/system/local-fs.target.wants/ww-ignition-disks.target @@ -0,0 +1 @@ +../ww-ignition-disks.target \ No newline at end of file diff --git a/overlays/ignition/rootfs/etc/systemd/system/local-fs.target.wants/ww-ignition.service b/overlays/ignition/rootfs/etc/systemd/system/local-fs.target.wants/ww-ignition.service new file mode 120000 index 00000000..3c0abb46 --- /dev/null +++ b/overlays/ignition/rootfs/etc/systemd/system/local-fs.target.wants/ww-ignition.service @@ -0,0 +1 @@ +../ww-ignition.service \ No newline at end of file diff --git a/overlays/ignition/rootfs/etc/systemd/system/local-fs.target.wants/ww4-disks.target b/overlays/ignition/rootfs/etc/systemd/system/local-fs.target.wants/ww4-disks.target deleted file mode 120000 index 6bebd069..00000000 --- a/overlays/ignition/rootfs/etc/systemd/system/local-fs.target.wants/ww4-disks.target +++ /dev/null @@ -1 +0,0 @@ -/etc/systemd/system/ww4-disks.target \ No newline at end of file diff --git a/overlays/ignition/rootfs/etc/systemd/system/ww4-disks.target.ww b/overlays/ignition/rootfs/etc/systemd/system/ww-ignition-disks.target.ww similarity index 86% rename from overlays/ignition/rootfs/etc/systemd/system/ww4-disks.target.ww rename to overlays/ignition/rootfs/etc/systemd/system/ww-ignition-disks.target.ww index d61a184c..c23da4c6 100644 --- a/overlays/ignition/rootfs/etc/systemd/system/ww4-disks.target.ww +++ b/overlays/ignition/rootfs/etc/systemd/system/ww-ignition-disks.target.ww @@ -3,9 +3,9 @@ [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 +Requires=ww-ignition.service +After=ww-ignition.service +Requisite=ww-ignition.service # Get the mounts {{- if .FileSystems }} {{- range $fsdevice, $fs := .FileSystems }} diff --git a/overlays/ignition/rootfs/etc/systemd/system/ignition-ww4-disks.service b/overlays/ignition/rootfs/etc/systemd/system/ww-ignition.service similarity index 100% rename from overlays/ignition/rootfs/etc/systemd/system/ignition-ww4-disks.service rename to overlays/ignition/rootfs/etc/systemd/system/ww-ignition.service