1
0
mirror of https://github.com/systemd/systemd.git synced 2024-12-26 03:22:00 +03:00
systemd/test/units/util.sh
Daan De Meyer c77dad706b mkosi: Build minimal images and enable related integration tests
This commit adds definitions to build the minimal_0 and minimal_1
images with mkosi and includes them into the system image. We also
move the building of the various app-xxx and similar images that are
extremely minimal into the tests itself by moving the related logic
from install_verity_minimal() into a new function
install_extension_images() in util.sh. Because the mkosi /usr is
read-only, we now place the extension images in /tmp instead of
/usr/share.

Co-authored-by: Richard Maw <richard.maw@codethink.co.uk>
Co-authored-by: sam-leonard-ct <sam.leonard@codethink.co.uk>
2024-04-25 21:06:30 +02:00

364 lines
10 KiB
Bash
Executable File

#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
# Utility functions for shell tests
# shellcheck disable=SC2034
[[ -e /var/tmp/.systemd_reboot_count ]] && REBOOT_COUNT="$(</var/tmp/.systemd_reboot_count)" || REBOOT_COUNT=0
assert_true() {(
set +ex
local rc
"$@"
rc=$?
if [[ $rc -ne 0 ]]; then
echo "FAIL: command '$*' failed with exit code $rc" >&2
exit 1
fi
)}
assert_eq() {(
set +ex
if [[ "${1?}" != "${2?}" ]]; then
echo "FAIL: expected: '$2' actual: '$1'" >&2
exit 1
fi
)}
assert_le() {(
set +ex
if [[ "${1:?}" -gt "${2:?}" ]]; then
echo "FAIL: '$1' > '$2'" >&2
exit 1
fi
)}
assert_in() {(
set +ex
if ! [[ "${2?}" =~ ${1?} ]]; then
echo "FAIL: '$1' not found in:" >&2
echo "$2" >&2
exit 1
fi
)}
assert_not_in() {(
set +ex
if [[ "${2?}" =~ ${1?} ]]; then
echo "FAIL: '$1' found in:" >&2
echo "$2" >&2
exit 1
fi
)}
assert_rc() {(
set +ex
local rc exp="${1?}"
shift
"$@"
rc=$?
assert_eq "$rc" "$exp"
)}
assert_not_reached() {
echo >&2 "Code should not be reached at ${BASH_SOURCE[1]}:${BASH_LINENO[1]}, function ${FUNCNAME[1]}()"
exit 1
}
run_and_grep() {(
set +ex
local expression
local log ec
local exp_ec=0
# Invert the grep condition - i.e. check if the expression is _not_ in command's output
if [[ "${1:?}" == "-n" ]]; then
exp_ec=1
shift
fi
expression="${1:?}"
shift
if [[ $# -eq 0 ]]; then
echo >&2 "FAIL: Not enough arguments for ${FUNCNAME[0]}()"
return 1
fi
log="$(mktemp)"
if ! "$@" |& tee "${log:?}"; then
echo >&2 "FAIL: Command '$*' failed"
return 1
fi
grep -qE "$expression" "$log" && ec=0 || ec=$?
if [[ "$exp_ec" -eq 0 && "$ec" -ne 0 ]]; then
echo >&2 "FAIL: Expression '$expression' not found in the output of '$*'"
return 1
elif [[ "$exp_ec" -ne 0 && "$ec" -eq 0 ]]; then
echo >&2 "FAIL: Expression '$expression' found in the output of '$*'"
return 1
fi
rm -f "$log"
)}
get_cgroup_hierarchy() {
case "$(stat -c '%T' -f /sys/fs/cgroup)" in
cgroup2fs)
echo "unified"
;;
tmpfs)
if [[ -d /sys/fs/cgroup/unified && "$(stat -c '%T' -f /sys/fs/cgroup/unified)" == cgroup2fs ]]; then
echo "hybrid"
else
echo "legacy"
fi
;;
*)
echo >&2 "Failed to determine host's cgroup hierarchy"
exit 1
esac
}
runas() {
local userid="${1:?}"
shift
XDG_RUNTIME_DIR=/run/user/"$(id -u "$userid")" setpriv --reuid="$userid" --init-groups "$@"
}
coverage_create_nspawn_dropin() {
# If we're collecting coverage, bind mount the $BUILD_DIR into the nspawn
# container so gcov can update the counters. This is mostly for standalone
# containers, as machinectl stuff is handled by overriding the systemd-nspawn@.service
# (see test/test-functions:install_systemd())
local root="${1:?}"
local container
if [[ -z "${COVERAGE_BUILD_DIR:-}" ]]; then
return 0
fi
container="$(basename "$root")"
mkdir -p "/run/systemd/nspawn"
echo -ne "[Files]\nBind=$COVERAGE_BUILD_DIR\n" >"/run/systemd/nspawn/${container:?}.nspawn"
}
create_dummy_container() {
local root="${1:?}"
if [[ ! -d /testsuite-13-container-template ]]; then
echo >&2 "Missing container template, probably not running in TEST-13-NSPAWN?"
exit 1
fi
mkdir -p "$root"
cp -a /testsuite-13-container-template/* "$root"
coverage_create_nspawn_dropin "$root"
}
# Bump the reboot counter and call systemctl with the given arguments
systemctl_final() {
local counter
if [[ $# -eq 0 ]]; then
echo >&2 "Missing arguments"
exit 1
fi
[[ -e /var/tmp/.systemd_reboot_count ]] && counter="$(</var/tmp/.systemd_reboot_count)" || counter=0
echo "$((counter + 1))" >/var/tmp/.systemd_reboot_count
systemctl "$@"
}
cgroupfs_supports_user_xattrs() {
local xattr
xattr="user.supported_$RANDOM"
# shellcheck disable=SC2064
trap "setfattr --remove=$xattr /sys/fs/cgroup || :" RETURN
setfattr --name="$xattr" --value=254 /sys/fs/cgroup
[[ "$(getfattr --name="$xattr" --absolute-names --only-values /sys/fs/cgroup)" -eq 254 ]]
}
tpm_has_pcr() {
local algorithm="${1:?}"
local pcr="${2:?}"
[[ -f "/sys/class/tpm/tpm0/pcr-$algorithm/$pcr" ]]
}
openssl_supports_kdf() {
local kdf="${1:?}"
# The arguments will need to be adjusted to make this work for other KDFs than SSKDF,
# but let's do that when/if the need arises
openssl kdf -keylen 16 -kdfopt digest:SHA2-256 -kdfopt key:foo -out /dev/null "$kdf"
}
kernel_supports_lsm() {
local lsm="${1:?}"
local items item
if [[ ! -e /sys/kernel/security/lsm ]]; then
echo "/sys/kernel/security/lsm doesn't exist, assuming $lsm is not supported"
return 1
fi
mapfile -t -d, items </sys/kernel/security/lsm
for item in "${items[@]}"; do
if [[ "$item" == "$lsm" ]]; then
return 0
fi
done
return 1
}
MOUNTED_USR_OVERLAY=false
maybe_mount_usr_overlay() {
if [[ ! -w /usr ]]; then
mkdir -p /tmp/usr-overlay/{upperdir,workdir}
mount -t overlay -o lowerdir=/usr,upperdir=/tmp/usr-overlay/upperdir,workdir=/tmp/usr-overlay/workdir overlay /usr
MOUNTED_USR_OVERLAY=true
fi
}
maybe_umount_usr_overlay() {
if "$MOUNTED_USR_OVERLAY"; then
umount -l /usr
fi
}
install_extension_images() {
local os_release
os_release="$(test -e /etc/os-release && echo /etc/os-release || echo /usr/lib/os-release)"
# Rolling distros like Arch do not set VERSION_ID
local version_id=""
if grep -q "^VERSION_ID=" "$os_release"; then
version_id="$(grep "^VERSION_ID=" "$os_release")"
fi
local initdir="/var/tmp/app0"
mkdir -p "$initdir/usr/lib/extension-release.d" "$initdir/usr/lib/systemd/system" "$initdir/opt"
grep "^ID=" "$os_release" >"$initdir/usr/lib/extension-release.d/extension-release.app0"
echo "$version_id" >>"$initdir/usr/lib/extension-release.d/extension-release.app0"
(
echo "$version_id"
echo "SYSEXT_IMAGE_ID=app"
) >>"$initdir/usr/lib/extension-release.d/extension-release.app0"
cat >"$initdir/usr/lib/systemd/system/app0.service" <<EOF
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/opt/script0.sh
TemporaryFileSystem=/var/lib
StateDirectory=app0
RuntimeDirectory=app0
EOF
cat >"$initdir/opt/script0.sh" <<EOF
#!/bin/bash
set -e
test -e /usr/lib/os-release
echo bar >\${STATE_DIRECTORY}/foo
cat /usr/lib/extension-release.d/extension-release.app0
EOF
chmod +x "$initdir/opt/script0.sh"
echo MARKER=1 >"$initdir/usr/lib/systemd/system/some_file"
mksquashfs "$initdir" /tmp/app0.raw -noappend
initdir="/var/tmp/conf0"
mkdir -p "$initdir/etc/extension-release.d" "$initdir/etc/systemd/system" "$initdir/opt"
grep "^ID=" "$os_release" >"$initdir/etc/extension-release.d/extension-release.conf0"
echo "$version_id" >>"$initdir/etc/extension-release.d/extension-release.conf0"
(
echo "$version_id"
echo "CONFEXT_IMAGE_ID=app"
) >>"$initdir/etc/extension-release.d/extension-release.conf0"
echo MARKER_1 >"$initdir/etc/systemd/system/some_file"
mksquashfs "$initdir" /tmp/conf0.raw -noappend
initdir="/var/tmp/app1"
mkdir -p "$initdir/usr/lib/extension-release.d" "$initdir/usr/lib/systemd/system" "$initdir/opt"
grep "^ID=" "$os_release" >"$initdir/usr/lib/extension-release.d/extension-release.app2"
(
echo "$version_id"
echo "SYSEXT_SCOPE=portable"
echo "SYSEXT_IMAGE_ID=app"
echo "SYSEXT_IMAGE_VERSION=1"
echo "PORTABLE_PREFIXES=app1"
) >>"$initdir/usr/lib/extension-release.d/extension-release.app2"
setfattr -n user.extension-release.strict -v false "$initdir/usr/lib/extension-release.d/extension-release.app2"
cat >"$initdir/usr/lib/systemd/system/app1.service" <<EOF
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/opt/script1.sh
StateDirectory=app1
RuntimeDirectory=app1
EOF
cat >"$initdir/opt/script1.sh" <<EOF
#!/bin/bash
set -e
test -e /usr/lib/os-release
echo baz >\${STATE_DIRECTORY}/foo
cat /usr/lib/extension-release.d/extension-release.app2
EOF
chmod +x "$initdir/opt/script1.sh"
echo MARKER=1 >"$initdir/usr/lib/systemd/system/other_file"
mksquashfs "$initdir" /tmp/app1.raw -noappend
initdir="/var/tmp/app-nodistro"
mkdir -p "$initdir/usr/lib/extension-release.d" "$initdir/usr/lib/systemd/system"
(
echo "ID=_any"
echo "ARCHITECTURE=_any"
) >"$initdir/usr/lib/extension-release.d/extension-release.app-nodistro"
echo MARKER=1 >"$initdir/usr/lib/systemd/system/some_file"
mksquashfs "$initdir" /tmp/app-nodistro.raw -noappend
initdir="/var/tmp/service-scoped-test"
mkdir -p "$initdir/etc/extension-release.d" "$initdir/etc/systemd/system"
(
echo "ID=_any"
echo "ARCHITECTURE=_any"
) >"$initdir/etc/extension-release.d/extension-release.service-scoped-test"
echo MARKER_CONFEXT_123 >"$initdir/etc/systemd/system/some_file"
mksquashfs "$initdir" /etc/service-scoped-test.raw -noappend
# We need to create a dedicated sysext image to test the reload mechanism. If we share an image to install the
# 'foo.service' it will be loaded from another test run, which will impact the targeted test.
initdir="/var/tmp/app-reload"
mkdir -p "$initdir/usr/lib/extension-release.d" "$initdir/usr/lib/systemd/system"
(
echo "ID=_any"
echo "ARCHITECTURE=_any"
echo "EXTENSION_RELOAD_MANAGER=1"
) >"$initdir/usr/lib/extension-release.d/extension-release.app-reload"
mkdir -p "$initdir/usr/lib/systemd/system/multi-user.target.d"
cat >"$initdir/usr/lib/systemd/system/foo.service" <<EOF
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=echo foo
[Install]
WantedBy=multi-user.target
EOF
echo -e "[Unit]\nUpholds=foo.service" >"$initdir/usr/lib/systemd/system/multi-user.target.d/10-foo-service.conf"
mksquashfs "$initdir" /tmp/app-reload.raw -noappend
}