From: Julian Sparber Date: Fri, 26 Jun 2026 16:48:42 +0000 (+0200) Subject: test: Add basic test for sysinstall varlink interface X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2acdbae8eb334b3b898f31f5c63acd9f5f6d7fa1;p=thirdparty%2Fsystemd.git test: Add basic test for sysinstall varlink interface This adds a basic test for the newly added varlink interface of sysinstall. --- diff --git a/test/units/TEST-87-AUX-UTILS-VM.sysinstall.sh b/test/units/TEST-87-AUX-UTILS-VM.sysinstall.sh index d4ca6e0a0d1..7c51e89ebbd 100755 --- a/test/units/TEST-87-AUX-UTILS-VM.sysinstall.sh +++ b/test/units/TEST-87-AUX-UTILS-VM.sysinstall.sh @@ -34,12 +34,15 @@ if systemd-detect-virt -cq; then exit 0 fi +# shellcheck source=test/units/test-control.sh +. "$(dirname "$0")"/test-control.sh + # shellcheck source=test/units/util.sh . "$(dirname "$0")"/util.sh -WORKDIR="$(mktemp --directory /tmp/test-sysinstall.XXXXXXXXXX)" -LOOPDEV="" -MOUNTED=0 + +CRED_VALUE="systemd-sysinstall test credential payload" +CRED_VALUE_BASE64=$(echo -n "$CRED_VALUE" | base64 -w0) cleanup() { set +e @@ -53,42 +56,42 @@ cleanup() { fi rm -rf "$WORKDIR" } -trap cleanup EXIT -# 1) Build a small fake "OS source" tree. systemd-sysinstall picks this up via -# the repart.sysinstall.d definitions: CopyFiles= seeds the new root -# partition with these files. -SOURCE_ROOT="$WORKDIR/sourceroot" -mkdir -p "$SOURCE_ROOT/usr/lib" "$SOURCE_ROOT/etc" +create_fake_os_source_tree() { + # 1) Build a small fake "OS source" tree. systemd-sysinstall picks this up via + # the repart.sysinstall.d definitions: CopyFiles= seeds the new root + # partition with these files. + SOURCE_ROOT="$WORKDIR/sourceroot" + mkdir -p "$SOURCE_ROOT/usr/lib" "$SOURCE_ROOT/etc" -cat >"$SOURCE_ROOT/usr/lib/os-release" <<'EOF' + cat >"$SOURCE_ROOT/usr/lib/os-release" <<'EOF' ID=testos NAME="Test OS" PRETTY_NAME="Test OS for systemd-sysinstall" VERSION_ID=1 EOF -ln -s ../usr/lib/os-release "$SOURCE_ROOT/etc/os-release" - -# 2) Build a minimal UKI. bootctl link only requires a valid PE with .osrel and -# the systemd-stub SBAT marker, so the .linux/.initrd contents do not need -# to be a real kernel. -echo "fake-kernel" >"$WORKDIR/vmlinuz" -echo "fake-initrd" >"$WORKDIR/initrd" - -ukify build \ - --linux "$WORKDIR/vmlinuz" \ - --initrd "$WORKDIR/initrd" \ - --os-release "@$SOURCE_ROOT/usr/lib/os-release" \ - --uname "1.2.3-testkernel" \ - --cmdline "quiet" \ - --output "$WORKDIR/testuki.efi" - -# 3) Build a sysinstall partition definition: a single ESP plus a root -# partition seeded from the fake source tree. -DEFS="$WORKDIR/sysinstall.d" -mkdir -p "$DEFS" - -cat >"$DEFS/10-esp.conf" <"$WORKDIR/vmlinuz" + echo "fake-initrd" >"$WORKDIR/initrd" + + ukify build \ + --linux "$WORKDIR/vmlinuz" \ + --initrd "$WORKDIR/initrd" \ + --os-release "@$SOURCE_ROOT/usr/lib/os-release" \ + --uname "1.2.3-testkernel" \ + --cmdline "quiet" \ + --output "$WORKDIR/testuki.efi" + + # 3) Build a sysinstall partition definition: a single ESP plus a root + # partition seeded from the fake source tree. + DEFS="$WORKDIR/sysinstall.d" + mkdir -p "$DEFS" + + cat >"$DEFS/10-esp.conf" <"$DEFS/20-root.conf" <"$DEFS/20-root.conf" </dev/null + + # The UKI file referenced in the entry must exist on the ESP. + UKI_PATH=$(awk '/^uki / { print $2 }' "$ENTRY") + test -n "$UKI_PATH" + test -f "$ESP$UKI_PATH" + + # bootctl install should have placed sd-boot on the ESP. + find "$ESP/EFI/systemd" -type f -iname 'systemd-boot*.efi' | grep . >/dev/null + + # The credential we passed via --set-credential= must have been encrypted and + # placed next to the UKI, and must be referenced as 'extra' from the entry. + UKI_DIR="$(dirname "$ESP$UKI_PATH")" + TOKEN_DIR="$(basename "$UKI_DIR")" + test -s "$UKI_DIR/marker.cred" + grep -E "^extra /$TOKEN_DIR/marker\.cred$" "$ENTRY" >/dev/null + + # Locale/keymap/timezone propagation is off, so those .cred files must NOT + # exist on the ESP. + test ! -e "$UKI_DIR/firstboot.locale.cred" + test ! -e "$UKI_DIR/firstboot.keymap.cred" + test ! -e "$UKI_DIR/firstboot.timezone.cred" + + # 3) The seeded files from the fake source tree must end up in the new root. + test -f "$MNT/usr/lib/os-release" + grep '^ID=testos$' "$MNT/usr/lib/os-release" >/dev/null +} -# 5) Run the installer non-interactively against the target image. Also stash a -# literal credential ('marker') so we can verify it ends up next to the UKI -# and is referenced from the boot loader entry. -CRED_VALUE="systemd-sysinstall test credential payload" -systemd-sysinstall \ - --welcome=no \ - --chrome=no \ - --confirm=no \ - --summary=no \ - --erase=yes \ - --variables=no \ - --reboot=no \ - --mute-console=no \ - --copy-locale=no \ - --copy-keymap=no \ - --copy-timezone=no \ - --set-credential="marker:$CRED_VALUE" \ - --kernel="$WORKDIR/testuki.efi" \ - --definitions="$DEFS" \ - "$WORKDIR/target.img" - -# 6) Attach the freshly installed image as a loopback device for inspection. -LOOPDEV="$(systemd-dissect --attach "$WORKDIR/target.img")" - -# Verify the resulting on-disk layout. The disk must now carry a GPT with at -# least an ESP partition. -sfdisk_dump="$(sfdisk --dump "$LOOPDEV")" -assert_in "C12A7328-F81F-11D2-BA4B-00A0C93EC93B" "$sfdisk_dump" - -# 7) Mount the image read-only and verify the installed artifacts: an entry -# file referencing the UKI on the ESP, the UKI itself, and the systemd-boot -# binary. -MNT="$WORKDIR/mnt" -mkdir -p "$MNT" - -systemd-dissect --mount --read-only "$LOOPDEV" "$MNT" -MOUNTED=1 - -ESP="$MNT/efi" -test -d "$ESP/loader/entries" - -# Exactly one entry should have been linked, and it should reference the UKI -# we passed via --kernel=. -ENTRY=$(find "$ESP/loader/entries" -maxdepth 1 -name '*.conf' -type f | head -n1) -test -n "$ENTRY" -grep -E "^uki /[^/]+/testuki\.efi$" "$ENTRY" >/dev/null - -# The UKI file referenced in the entry must exist on the ESP. -UKI_PATH=$(awk '/^uki / { print $2 }' "$ENTRY") -test -n "$UKI_PATH" -test -f "$ESP$UKI_PATH" - -# bootctl install should have placed sd-boot on the ESP. -find "$ESP/EFI/systemd" -type f -iname 'systemd-boot*.efi' | grep . >/dev/null - -# The credential we passed via --set-credential= must have been encrypted and -# placed next to the UKI, and must be referenced as 'extra' from the entry. -UKI_DIR="$(dirname "$ESP$UKI_PATH")" -TOKEN_DIR="$(basename "$UKI_DIR")" -test -s "$UKI_DIR/marker.cred" -grep -E "^extra /$TOKEN_DIR/marker\.cred$" "$ENTRY" >/dev/null - -# Locale/keymap/timezone propagation is off, so those .cred files must NOT -# exist on the ESP. -test ! -e "$UKI_DIR/firstboot.locale.cred" -test ! -e "$UKI_DIR/firstboot.keymap.cred" -test ! -e "$UKI_DIR/firstboot.timezone.cred" - -# 8) The seeded files from the fake source tree must end up in the new root. -test -f "$MNT/usr/lib/os-release" -grep '^ID=testos$' "$MNT/usr/lib/os-release" >/dev/null +testcase_sysinstall_basic() { + WORKDIR="$(mktemp --directory /tmp/test-sysinstall.XXXXXXXXXX)" + LOOPDEV="" + MOUNTED=0 + + echo "WORKDIR=$WORKDIR" + + trap cleanup RETURN + + create_fake_os_source_tree + + # Run the installer non-interactively against the target image. Also stash a + # literal credential ('marker') so we can verify it ends up next to the UKI + # and is referenced from the boot loader entry. + systemd-sysinstall \ + --welcome=no \ + --chrome=no \ + --confirm=no \ + --summary=no \ + --erase=yes \ + --variables=no \ + --reboot=no \ + --mute-console=no \ + --copy-locale=no \ + --copy-keymap=no \ + --copy-timezone=no \ + --set-credential="marker:$CRED_VALUE" \ + --kernel="$WORKDIR/testuki.efi" \ + --definitions="$DEFS" \ + "$WORKDIR/target.img" + + validate_image + + cleanup +} + +testcase_sysinstall_varlink_basic() { + WORKDIR="$(mktemp --directory /tmp/test-sysinstall.XXXXXXXXXX)" + LOOPDEV="" + MOUNTED=0 + + echo "WORKDIR=$WORKDIR" + + trap cleanup RETURN + + create_fake_os_source_tree + + # Run the installer via varlink against the target image. Also stash a + # literal credential ('marker') so we can verify it ends up next to the UKI + # and is referenced from the boot loader entry. + varlinkctl call /run/systemd/io.systemd.SysInstall io.systemd.SysInstall.Run "{\"erase\": true, \"variables\": false, \"credentials\" : [{ \"id\" : \"marker\", \"value\" : \"$CRED_VALUE_BASE64\" }], \"kernelImagePath\" : \"$WORKDIR/testuki.efi\", \"node\": \"$WORKDIR/target.img\", \"definitions\" : [\"$DEFS\"] }" --more + + validate_image +} + +run_testcases