diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-dracut-rootfs.sh b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-dracut-rootfs.sh new file mode 100755 index 0000000000..82cf886857 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-dracut-rootfs.sh @@ -0,0 +1,46 @@ +#!/bin/bash +set -euo pipefail + +rootdisk=/dev/disk/by-label/root +rootmnt=/sysroot +tmproot=/run/ignition-ostree-rootfs +saved_rootmnt=${tmproot}/orig-sysroot +memdev=/dev/ram0 + +# Note that save & restore run in private mount namespaces, hence why we don't +# bother unmounting things here. + +case "${1:-}" in + detect) + # This is obviously crude; perhaps in the future we could change ignition's `fetch` + # stage to write out a file if the rootfs is being replaced or so. But eh, it + # works for now. + wipes_rootfs=$(jq '.storage?.filesystems? // [] | map(select(.label == "root" and .wipeFilesystem == true)) | length' < /run/ignition.json) + if [ "${wipes_rootfs}" = "0" ]; then + exit 0 + fi + echo "Detected rootfs replacement in fetched Ignition config: /run/ignition.json" + mkdir "${tmproot}" + ;; + save) + size=$(lsblk -bn -o SIZE "${rootdisk}") + sizekbs="$(($size / 1024 + 1))" + modprobe --first-time brd rd_nr=1 rd_size="$sizekbs" max_part=1 + echo "Moving rootfs to RAM..." + dd "if=${rootdisk}" "of=${memdev}" bs=8M + echo "Moved rootfs to RAM, pending redeployment: ${memdev}" + ;; + restore) + mount "$rootdisk" $rootmnt + echo "Restoring rootfs from RAM..." + mkdir "${saved_rootmnt}" + mount "${memdev}" "${saved_rootmnt}" + rsync -aXHA "${saved_rootmnt}/" "${rootmnt}" + umount $saved_rootmnt + rmmod brd + rm -rf "${tmproot}" + ;; + *) + echo "Unsupported operation: ${1:-}" 1>&2; exit 1 + ;; +esac diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-rootfs-detect.service b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-rootfs-detect.service new file mode 100644 index 0000000000..5a969a7edc --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-rootfs-detect.service @@ -0,0 +1,18 @@ +[Unit] +Description=Ignition OSTree: detect rootfs replacement +DefaultDependencies=false +After=ignition-fetch.service +Before=ignition-disks.service +Before=initrd-root-fs.target +Before=sysroot.mount +ConditionKernelCommandLine=ostree + +# This stage requires udevd to detect disks +Requires=systemd-udevd.service +After=systemd-udevd.service + +[Service] +Type=oneshot +RemainAfterExit=yes +EnvironmentFile=/run/ignition.env +ExecStart=/usr/libexec/ignition-ostree-dracut-rootfs detect diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-rootfs-restore.service b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-rootfs-restore.service new file mode 100644 index 0000000000..f02d729325 --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-rootfs-restore.service @@ -0,0 +1,17 @@ +[Unit] +Description=Ignition OSTree: restore rootfs +DefaultDependencies=false +After=ignition-disks.service +Before=ignition-ostree-growfs.service +Before=ignition-ostree-mount-firstboot-sysroot.service + +ConditionKernelCommandLine=ostree +ConditionPathIsDirectory=/run/ignition-ostree-rootfs + +[Service] +Type=oneshot +RemainAfterExit=yes +EnvironmentFile=/run/ignition.env +# So we can transiently mount sysroot +MountFlags=slave +ExecStart=/usr/libexec/ignition-ostree-dracut-rootfs restore diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-rootfs-save.service b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-rootfs-save.service new file mode 100644 index 0000000000..8bc3eecf9e --- /dev/null +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/ignition-ostree-rootfs-save.service @@ -0,0 +1,15 @@ +[Unit] +Description=Ignition OSTree: save rootfs +DefaultDependencies=false +After=ignition-ostree-rootfs-detect.service +Before=ignition-disks.service +ConditionKernelCommandLine=ostree +ConditionPathIsDirectory=/run/ignition-ostree-rootfs + +[Service] +Type=oneshot +RemainAfterExit=yes +EnvironmentFile=/run/ignition.env +# So we can transiently mount sysroot +MountFlags=slave +ExecStart=/usr/libexec/ignition-ostree-dracut-rootfs save diff --git a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/module-setup.sh b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/module-setup.sh index 58197213fe..1ad94e6d3e 100755 --- a/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/module-setup.sh +++ b/overlay.d/05core/usr/lib/dracut/modules.d/40ignition-ostree/module-setup.sh @@ -52,7 +52,8 @@ install() { rm \ sed \ sfdisk \ - sgdisk + sgdisk \ + rsync for x in mount populate; do install_ignition_unit ignition-ostree-${x}-var.service @@ -65,6 +66,12 @@ install() { inst_simple "$moddir/multipath-generator" \ "$systemdutildir/system-generators/multipath-generator" + inst_multiple jq chattr getfattr lsmod dd modprobe + inst_script "$moddir/ignition-ostree-dracut-rootfs.sh" "/usr/libexec/ignition-ostree-dracut-rootfs" + for x in detect save restore; do + install_ignition_unit ignition-ostree-rootfs-${x}.service + done + # Disk support install_ignition_unit ignition-ostree-mount-firstboot-sysroot.service diskful install_ignition_unit ignition-ostree-mount-subsequent-sysroot.service diskful-subsequent