Skip to content

Commit

Permalink
test: backport TEST-81-GENERATORS (fstab-generator only)
Browse files Browse the repository at this point in the history
Some fstab-generator features are not present on RHEL 7 or they behave
differently - in such case there's an inline comment explaining what's
different with a reference to an upstream commit that introduced the
changed behavior.

Also, RHEL 7 systemd doesn't allow overriding (/sysroot)/etc/fstab or
/proc/cmdline, so instead of backporting another bunch of potential
risky commits, let's temporarily bind-mount a modified copy of necessary
files in place of the expected ones. One exception is
$SYSTEMD_IN_INITRD, since systemd checks if the mount for / is a tmpfs,
which is a pain to mock, but the patch for that is, thankfully, pretty
small.

Related: RHEL-17394

rhel-only
  • Loading branch information
mrc0mmand committed Nov 27, 2023
1 parent 656de45 commit c83846d
Show file tree
Hide file tree
Showing 6 changed files with 622 additions and 1 deletion.
1 change: 1 addition & 0 deletions test/TEST-81-GENERATORS/Makefile
110 changes: 110 additions & 0 deletions test/TEST-81-GENERATORS/generator-utils.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later

link_endswith() {
[[ -h "${1:?}" && "$(readlink "${1:?}")" =~ ${2:?}$ ]]
}

link_eq() {
[[ -h "${1:?}" && "$(readlink "${1:?}")" == "${2:?}" ]]
}

# Get the value from a 'key=value' assignment
opt_get_arg() {
local arg

IFS="=" read -r _ arg <<< "${1:?}"
test -n "$arg"
echo "$arg"
}

in_initrd() {
[[ "${SYSTEMD_IN_INITRD:-0}" -ne 0 ]]
}

# Check if we're parsing host's fstab in initrd
in_initrd_host() {
in_initrd && [[ "${SYSTEMD_SYSROOT_FSTAB:-/dev/null}" != /dev/null ]]
}

in_container() {
systemd-detect-virt -qc
}

opt_filter() (
set +x
local opt split_options filtered_options

IFS="," read -ra split_options <<< "${1:?}"
for opt in "${split_options[@]}"; do
if [[ "$opt" =~ ${2:?} ]]; then
continue
fi

filtered_options+=("$opt")
done

IFS=","; printf "%s" "${filtered_options[*]}"
)

# Run the given generator $1 with target directory $2 - clean the target
# directory beforehand
run_and_list() {
local generator="${1:?}"
local out_dir="${2:?}"
local environ
local cmdline

# If $PID1_ENVIRON is set temporarily overmount /proc/1/environ with
# a temporary file that contains contents of $PID1_ENVIRON. This is
# necessary in cases where the generator reads the environment through
# getenv_for_pid(1, ...) or similar like getty-generator does.
#
# Note: $PID1_ENVIRON should be a NUL separated list of env assignments
if [[ -n "${PID1_ENVIRON:-}" ]]; then
environ="$(mktemp)"
echo -ne "${PID1_ENVIRON}\0" >"${environ:?}"
mount -v --bind "$environ" /proc/1/environ
fi

if [[ -n "${SYSTEMD_PROC_CMDLINE:-}" ]]; then
cmdline="$(mktemp)"
echo "$SYSTEMD_PROC_CMDLINE" >"$cmdline"
mount --bind "$cmdline" /proc/cmdline
fi

if [[ -n "${SYSTEMD_FSTAB:-}" ]]; then
touch /etc/fstab
mount --bind "$SYSTEMD_FSTAB" /etc/fstab
fi

if [[ -n "${SYSTEMD_SYSROOT_FSTAB:-}" ]]; then
mkdir -p /sysroot/etc
touch /sysroot/etc/fstab
mount --bind "$SYSTEMD_SYSROOT_FSTAB" /sysroot/etc/fstab
fi

rm -fr "${out_dir:?}"/*
mkdir -p "$out_dir"/{normal,early,late}
SYSTEMD_LOG_LEVEL="${SYSTEMD_LOG_LEVEL:-debug}" "$generator" "$out_dir/normal" "$out_dir/early" "$out_dir/late"
ls -lR "$out_dir"

if [[ -n "${SYSTEMD_SYSROOT_FSTAB:-}" ]]; then
umount /sysroot/etc/fstab
rm -rf /sysroot
fi

if [[ -n "${SYSTEMD_FSTAB:-}" ]]; then
umount /etc/fstab
fi

if [[ -n "${SYSTEMD_PROC_CMDLINE:-}" ]]; then
umount /proc/cmdline
rm -f "$cmdline"
fi

if [[ -n "${environ:-}" ]]; then
umount /proc/1/environ
rm -f "$environ"
fi
}
85 changes: 85 additions & 0 deletions test/TEST-81-GENERATORS/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/usr/bin/bash
set -e
TEST_DESCRIPTION="Test systemd generators"

# shellcheck source=test/test-functions
. "$TEST_BASE_DIR/test-functions"

check_result_qemu() {
ret=1
mkdir -p $TESTDIR/root
mount ${LOOPDEV}p1 $TESTDIR/root
[[ -e $TESTDIR/root/testok ]] && ret=0
[[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR
[[ -f $TESTDIR/root/var/log/journal ]] && cp -a $TESTDIR/root/var/log/journal $TESTDIR
umount $TESTDIR/root
[[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed
ls -l $TESTDIR/journal/*/*.journal
test -s $TESTDIR/failed && ret=$(($ret+1))
return $ret
}

test_run() {
if run_qemu; then
check_result_qemu || return 1
else
dwarn "can't run QEMU, skipping"
fi
if check_nspawn; then
run_nspawn
check_result_nspawn || return 1
else
dwarn "can't run systemd-nspawn, skipping"
fi
return 0
}

test_setup() {
create_empty_image
mkdir -p "${TESTDIR:?}/root"
mount "${LOOPDEV:?}p1" "$TESTDIR/root"

(
LOG_LEVEL=5
# shellcheck disable=SC2046
eval $(udevadm info --export --query=env --name="${LOOPDEV}p2")

setup_basic_environment

# mask some services that we do not want to run in these tests
ln -fs /dev/null "$initdir/etc/systemd/system/systemd-hwdb-update.service"
ln -fs /dev/null "$initdir/etc/systemd/system/systemd-journal-catalog-update.service"
ln -fs /dev/null "$initdir/etc/systemd/system/systemd-networkd.service"
ln -fs /dev/null "$initdir/etc/systemd/system/systemd-networkd.socket"
ln -fs /dev/null "$initdir/etc/systemd/system/systemd-resolved.service"
ln -fs /dev/null "$initdir/etc/systemd/system/systemd-machined.service"

# setup the testsuite service
cat >"$initdir/etc/systemd/system/testsuite.service" <<EOF
[Unit]
Description=Testsuite service
[Service]
ExecStart=/bin/bash -x /testsuite.sh
Type=oneshot
StandardOutput=tty
StandardError=tty
NotifyAccess=all
EOF
cp generator-utils.sh testsuite*.sh "$initdir/"

setup_testsuite
) || return 1
setup_nspawn_root

ddebug "umount $TESTDIR/root"
umount "$TESTDIR/root"
}

test_cleanup() {
umount $TESTDIR/root 2>/dev/null
[[ $LOOPDEV ]] && losetup -d $LOOPDEV
return 0
}

do_test "$@"

0 comments on commit c83846d

Please sign in to comment.