mirror of
https://github.com/systemd/systemd.git
synced 2026-08-13 17:08:14 +00:00
test: Add basic test for sysinstall varlink interface
This adds a basic test for the newly added varlink interface of sysinstall.
This commit is contained in:
@@ -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"
|
||||
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"
|
||||
# 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"
|
||||
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"
|
||||
# 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" <<EOF
|
||||
cat >"$DEFS/10-esp.conf" <<EOF
|
||||
[Partition]
|
||||
Type=esp
|
||||
Format=vfat
|
||||
@@ -96,7 +99,7 @@ SizeMinBytes=64M
|
||||
SizeMaxBytes=64M
|
||||
EOF
|
||||
|
||||
cat >"$DEFS/20-root.conf" <<EOF
|
||||
cat >"$DEFS/20-root.conf" <<EOF
|
||||
[Partition]
|
||||
Type=root
|
||||
Format=ext4
|
||||
@@ -104,80 +107,119 @@ SizeMinBytes=128M
|
||||
CopyFiles=$SOURCE_ROOT:/
|
||||
EOF
|
||||
|
||||
# 4) Allocate a sparse target file. systemd-sysinstall accepts a regular file
|
||||
# path here — systemd-repart and the in-process dissect logic transparently
|
||||
# handle the loop attach during install. We can't pre-attach the empty file
|
||||
# via systemd-dissect --attach since that requires a valid DDI.
|
||||
truncate -s 512M "$WORKDIR/target.img"
|
||||
# 4) Allocate a sparse target file. systemd-sysinstall accepts a regular file
|
||||
# path here — systemd-repart and the in-process dissect logic transparently
|
||||
# handle the loop attach during install. We can't pre-attach the empty file
|
||||
# via systemd-dissect --attach since that requires a valid DDI.
|
||||
truncate -s 512M "$WORKDIR/target.img"
|
||||
}
|
||||
|
||||
# 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"
|
||||
validate_image() {
|
||||
# 1) Attach the freshly installed image as a loopback device for inspection.
|
||||
LOOPDEV="$(systemd-dissect --attach "$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"
|
||||
|
||||
# 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"
|
||||
# 2) 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"
|
||||
|
||||
# 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
|
||||
|
||||
systemd-dissect --mount --read-only "$LOOPDEV" "$MNT"
|
||||
MOUNTED=1
|
||||
ESP="$MNT/efi"
|
||||
test -d "$ESP/loader/entries"
|
||||
|
||||
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
|
||||
|
||||
# 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"
|
||||
|
||||
# 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
|
||||
|
||||
# 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
|
||||
|
||||
# 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"
|
||||
|
||||
# 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
|
||||
}
|
||||
|
||||
# 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
|
||||
|
||||
Reference in New Issue
Block a user