diff options
Diffstat (limited to 'test')
167 files changed, 7854 insertions, 0 deletions
diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 0000000..dfaa450 --- /dev/null +++ b/test/Makefile @@ -0,0 +1,23 @@ +.PHONY: all check clean $(wildcard TEST-??-*) + +$(wildcard TEST-??-*): + @[ "$(shell id -u)" = 0 ] || { echo "'check' must be run as root! Please use 'sudo'."; exit 1; } + @{ \ + [ -d $@ ] || exit 0; \ + [ -f $@/Makefile ] || exit 0; \ + if [ -n "$$TESTS" ]; then t=$${$@##TEST-}; t=$${t%%-*}; [ "$${TESTS#*$$t*}" != "$$TESTS" ] || exit 0; fi; \ + if [ -n "$$SKIP" ]; then t=$${$@##TEST-}; t=$${t%%-*}; [ "$${SKIP#*$$t*}" != "$$SKIP" ] && exit 0; fi; \ + $(MAKE) -C $@ all ; \ + } + +check: $(wildcard TEST-??-*) + +clean: + @for i in TEST-[0-9]*; do \ + [ -d $$i ] || continue ; \ + [ -f $$i/Makefile ] || continue ; \ + $(MAKE) -C $$i clean ; \ + done + +all: + diff --git a/test/Makefile.testdir b/test/Makefile.testdir new file mode 100644 index 0000000..e3b31b1 --- /dev/null +++ b/test/Makefile.testdir @@ -0,0 +1,10 @@ +.PHONY: all setup clean run + +all: + @V=$(V) testdir="$(realpath ../)" ./test.sh --all +setup: + @testdir="$(realpath ../)" ./test.sh --setup +clean: + @testdir="$(realpath ../)" ./test.sh --clean +run: + @testdir="$(realpath ../)" ./test.sh --run diff --git a/test/TEST-01-BASIC/Makefile b/test/TEST-01-BASIC/Makefile new file mode 100644 index 0000000..2dcab81 --- /dev/null +++ b/test/TEST-01-BASIC/Makefile @@ -0,0 +1 @@ +-include ../Makefile.testdir diff --git a/test/TEST-01-BASIC/create-root.sh b/test/TEST-01-BASIC/create-root.sh new file mode 100755 index 0000000..633b11f --- /dev/null +++ b/test/TEST-01-BASIC/create-root.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +trap 'poweroff -f' EXIT + +# don't let udev and this script step on eachother's toes +for x in 64-lvm.rules 70-mdadm.rules 99-mount-rules; do + : > "/etc/udev/rules.d/$x" +done +rm -f -- /etc/lvm/lvm.conf +udevadm control --reload +udevadm settle + +set -ex + +mkfs.ext4 -L ' rdinit=/bin/sh' /dev/disk/by-id/ata-disk_root +mkdir -p /root +mount -t ext4 /dev/disk/by-id/ata-disk_root /root +cp -a -t /root /source/* +mkdir -p /root/run +umount /root +echo "dracut-root-block-created" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker +poweroff -f diff --git a/test/TEST-01-BASIC/test-init.sh b/test/TEST-01-BASIC/test-init.sh new file mode 100755 index 0000000..108e626 --- /dev/null +++ b/test/TEST-01-BASIC/test-init.sh @@ -0,0 +1,24 @@ +#!/bin/sh +: > /dev/watchdog + +. /lib/dracut-lib.sh + +export PATH=/usr/sbin:/usr/bin:/sbin:/bin +command -v plymouth > /dev/null 2>&1 && plymouth --quit +exec > /dev/console 2>&1 + +echo "dracut-root-block-success" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker + +export TERM=linux +export PS1='initramfs-test:\w\$ ' +[ -f /etc/mtab ] || ln -sfn /proc/mounts /etc/mtab +[ -f /etc/fstab ] || ln -sfn /proc/mounts /etc/fstab +stty sane +echo "made it to the rootfs!" +if getargbool 0 rd.shell; then + strstr "$(setsid --help)" "control" && CTTY="-c" + setsid $CTTY sh -i +fi +echo "Powering down." +mount -n -o remount,ro / +poweroff -f diff --git a/test/TEST-01-BASIC/test.sh b/test/TEST-01-BASIC/test.sh new file mode 100755 index 0000000..b3a8656 --- /dev/null +++ b/test/TEST-01-BASIC/test.sh @@ -0,0 +1,71 @@ +#!/bin/bash +# shellcheck disable=SC2034 +TEST_DESCRIPTION="root filesystem on a ext4 filesystem" + +# Uncomment this to debug failures +# DEBUGFAIL="rd.shell rd.break" + +test_run() { + declare -a disk_args=() + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker + qemu_add_drive_args disk_index disk_args "$TESTDIR"/root.img root + + test_marker_reset + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -device i6300esb -watchdog-action poweroff \ + -append "panic=1 oops=panic softlockup_panic=1 systemd.crash_reboot \"root=LABEL= rdinit=/bin/sh\" rw systemd.log_level=debug systemd.log_target=console rd.retry=3 rd.debug console=ttyS0,115200n81 rd.shell=0 $DEBUGFAIL" \ + -initrd "$TESTDIR"/initramfs.testing || return 1 + + test_marker_check || return 1 +} + +test_setup() { + # Create what will eventually be our root filesystem onto an overlay + "$DRACUT" -l --keep --tmpdir "$TESTDIR" \ + -m "test-root" \ + -i ./test-init.sh /sbin/init \ + -i "${PKGLIBDIR}/modules.d/99base/dracut-lib.sh" "/lib/dracut-lib.sh" \ + -i "${PKGLIBDIR}/modules.d/99base/dracut-dev-lib.sh" "/lib/dracut-dev-lib.sh" \ + --no-hostonly --no-hostonly-cmdline --nomdadmconf --nohardlink \ + -f "$TESTDIR"/initramfs.root "$KVERSION" || return 1 + mkdir -p "$TESTDIR"/overlay/source && mv "$TESTDIR"/dracut.*/initramfs/* "$TESTDIR"/overlay/source && rm -rf "$TESTDIR"/dracut.* + + # second, install the files needed to make the root filesystem + # create an initramfs that will create the target root filesystem. + # We do it this way so that we do not risk trashing the host mdraid + # devices, volume groups, encrypted partitions, etc. + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -m "test-makeroot" \ + -I "mkfs.ext4" \ + -i ./create-root.sh /lib/dracut/hooks/initqueue/01-create-root.sh \ + --nomdadmconf \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.makeroot "$KVERSION" || return 1 + rm -rf -- "$TESTDIR"/overlay + + declare -a disk_args=() + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker 1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/root.img root 80 + + # Invoke KVM and/or QEMU to actually create the target filesystem. + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "root=/dev/dracut/root rw rootfstype=ext4 quiet console=ttyS0,115200n81 selinux=0" \ + -initrd "$TESTDIR"/initramfs.makeroot || return 1 + test_marker_check dracut-root-block-created || return 1 + rm -- "$TESTDIR"/marker.img + + # make sure --omit-drivers does not filter out drivers using regexp to test for an earlier regression (assuming there is no one letter linux kernel module needed to run the test) + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -a "test watchdog" \ + -d "piix ide-gd_mod ata_piix ext4 sd_mod i6300esb ib700wdt" \ + --omit-drivers 'a b c d e f g h i j k l m n o p q r s t u v w x y z' \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.testing "$KVERSION" || return 1 +} + +# shellcheck disable=SC1090 +. "$testdir"/test-functions diff --git a/test/TEST-02-SYSTEMD/Makefile b/test/TEST-02-SYSTEMD/Makefile new file mode 100644 index 0000000..2dcab81 --- /dev/null +++ b/test/TEST-02-SYSTEMD/Makefile @@ -0,0 +1 @@ +-include ../Makefile.testdir diff --git a/test/TEST-02-SYSTEMD/create-root.sh b/test/TEST-02-SYSTEMD/create-root.sh new file mode 100755 index 0000000..c1fbe76 --- /dev/null +++ b/test/TEST-02-SYSTEMD/create-root.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +trap 'poweroff -f' EXIT + +# don't let udev and this script step on eachother's toes +for x in 64-lvm.rules 70-mdadm.rules 99-mount-rules; do + : > "/etc/udev/rules.d/$x" +done +rm -f -- /etc/lvm/lvm.conf +udevadm control --reload +set -e + +udevadm settle +mkfs.ext4 -L dracut /dev/disk/by-id/ata-disk_root +mkdir -p /root +mount -t ext4 /dev/disk/by-id/ata-disk_root /root +cp -a -t /root /source/* +mkdir -p /root/run +umount /root +echo "dracut-root-block-created" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker +poweroff -f diff --git a/test/TEST-02-SYSTEMD/systemd-analyze.sh b/test/TEST-02-SYSTEMD/systemd-analyze.sh new file mode 100755 index 0000000..55f8728 --- /dev/null +++ b/test/TEST-02-SYSTEMD/systemd-analyze.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +for i in \ + sysinit.target \ + basic.target \ + initrd-fs.target \ + initrd.target \ + initrd-switch-root.target \ + emergency.target \ + shutdown.target; do + if ! systemd-analyze verify "$i"; then + warn "systemd-analyze verify $i failed" + poweroff + fi +done diff --git a/test/TEST-02-SYSTEMD/test-init.sh b/test/TEST-02-SYSTEMD/test-init.sh new file mode 100755 index 0000000..108e626 --- /dev/null +++ b/test/TEST-02-SYSTEMD/test-init.sh @@ -0,0 +1,24 @@ +#!/bin/sh +: > /dev/watchdog + +. /lib/dracut-lib.sh + +export PATH=/usr/sbin:/usr/bin:/sbin:/bin +command -v plymouth > /dev/null 2>&1 && plymouth --quit +exec > /dev/console 2>&1 + +echo "dracut-root-block-success" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker + +export TERM=linux +export PS1='initramfs-test:\w\$ ' +[ -f /etc/mtab ] || ln -sfn /proc/mounts /etc/mtab +[ -f /etc/fstab ] || ln -sfn /proc/mounts /etc/fstab +stty sane +echo "made it to the rootfs!" +if getargbool 0 rd.shell; then + strstr "$(setsid --help)" "control" && CTTY="-c" + setsid $CTTY sh -i +fi +echo "Powering down." +mount -n -o remount,ro / +poweroff -f diff --git a/test/TEST-02-SYSTEMD/test.sh b/test/TEST-02-SYSTEMD/test.sh new file mode 100755 index 0000000..40d1b3e --- /dev/null +++ b/test/TEST-02-SYSTEMD/test.sh @@ -0,0 +1,76 @@ +#!/bin/bash +# shellcheck disable=SC2034 +TEST_DESCRIPTION="root filesystem on a ext4 filesystem" + +test_check() { + command -v systemctl &> /dev/null +} + +# Uncomment this to debug failures +#DEBUGFAIL="rd.shell=1 rd.break=pre-mount" +test_run() { + declare -a disk_args=() + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker + qemu_add_drive_args disk_index disk_args "$TESTDIR"/root.img root + + test_marker_reset + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "panic=1 oops=panic softlockup_panic=1 systemd.crash_reboot root=LABEL=dracut rw loglevel=77 systemd.log_level=debug systemd.log_target=console rd.retry=3 rd.info console=ttyS0,115200n81 selinux=0 init=/sbin/init rd.shell=0 $DEBUGFAIL" \ + -initrd "$TESTDIR"/initramfs.testing || return 1 + + test_marker_check || return 1 +} + +test_setup() { + # Create what will eventually be our root filesystem onto an overlay + "$DRACUT" -l --keep --tmpdir "$TESTDIR" \ + -m "test-root" \ + -i ./test-init.sh /sbin/init \ + -i "${PKGLIBDIR}/modules.d/99base/dracut-lib.sh" "/lib/dracut-lib.sh" \ + -i "${PKGLIBDIR}/modules.d/99base/dracut-dev-lib.sh" "/lib/dracut-dev-lib.sh" \ + --no-hostonly --no-hostonly-cmdline --nomdadmconf --nohardlink \ + -f "$TESTDIR"/initramfs.root "$KVERSION" || return 1 + mkdir -p "$TESTDIR"/overlay/source && mv "$TESTDIR"/dracut.*/initramfs/* "$TESTDIR"/overlay/source && rm -rf "$TESTDIR"/dracut.* + + # second, install the files needed to make the root filesystem + # create an initramfs that will create the target root filesystem. + # We do it this way so that we do not risk trashing the host mdraid + # devices, volume groups, encrypted partitions, etc. + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -m "test-makeroot" \ + -I "mkfs.ext4" \ + -i ./create-root.sh /lib/dracut/hooks/initqueue/01-create-root.sh \ + --nomdadmconf \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.makeroot "$KVERSION" || return 1 + rm -rf -- "$TESTDIR"/overlay + + declare -a disk_args=() + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker 1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/root.img root 80 + + # Invoke KVM and/or QEMU to actually create the target filesystem. + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "root=/dev/fakeroot rw rootfstype=ext4 quiet console=ttyS0,115200n81 selinux=0" \ + -initrd "$TESTDIR"/initramfs.makeroot || return 1 + test_marker_check dracut-root-block-created || return 1 + rm -- "$TESTDIR"/marker.img + + # systemd-analyze.sh calls man indirectly + # make the man command succeed always + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -a "test systemd" \ + -o "network kernel-network-modules" \ + -d "piix ide-gd_mod ata_piix ext4 sd_mod" \ + -i ./systemd-analyze.sh /lib/dracut/hooks/pre-pivot/00-systemd-analyze.sh \ + -i "/bin/true" "/usr/bin/man" \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.testing "$KVERSION" || return 1 +} + +# shellcheck disable=SC1090 +. "$testdir"/test-functions diff --git a/test/TEST-03-USR-MOUNT/Makefile b/test/TEST-03-USR-MOUNT/Makefile new file mode 100644 index 0000000..2dcab81 --- /dev/null +++ b/test/TEST-03-USR-MOUNT/Makefile @@ -0,0 +1 @@ +-include ../Makefile.testdir diff --git a/test/TEST-03-USR-MOUNT/create-root.sh b/test/TEST-03-USR-MOUNT/create-root.sh new file mode 100755 index 0000000..411fa99 --- /dev/null +++ b/test/TEST-03-USR-MOUNT/create-root.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +trap 'poweroff -f' EXIT + +# don't let udev and this script step on eachother's toes +for x in 64-lvm.rules 70-mdadm.rules 99-mount-rules; do + : > "/etc/udev/rules.d/$x" +done +rm -f -- /etc/lvm/lvm.conf +udevadm control --reload +set -e + +udevadm settle +modprobe btrfs || : +mkfs.btrfs -L dracut /dev/disk/by-id/ata-disk_root +mkfs.btrfs -L dracutusr /dev/disk/by-id/ata-disk_usr +btrfs device scan /dev/disk/by-id/ata-disk_root +btrfs device scan /dev/disk/by-id/ata-disk_usr +mkdir -p /root +mount -t btrfs /dev/disk/by-id/ata-disk_root /root +[ -d /root/usr ] || mkdir -p /root/usr +mount -t btrfs /dev/disk/by-id/ata-disk_usr /root/usr +btrfs subvolume create /root/usr/usr +umount /root/usr +mount -t btrfs -o subvol=usr /dev/disk/by-id/ata-disk_usr /root/usr +cp -a -t /root /source/* +mkdir -p /root/run +btrfs filesystem sync /root/usr +btrfs filesystem sync /root +umount /root/usr +umount /root +echo "dracut-root-block-created" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker +poweroff -f diff --git a/test/TEST-03-USR-MOUNT/fstab b/test/TEST-03-USR-MOUNT/fstab new file mode 100644 index 0000000..feac57a --- /dev/null +++ b/test/TEST-03-USR-MOUNT/fstab @@ -0,0 +1,2 @@ +/dev/disk/by-id/ata-disk_root / btrfs defaults 0 0 +/dev/disk/by-id/ata-disk_usr /usr btrfs subvol=usr,ro 0 0 diff --git a/test/TEST-03-USR-MOUNT/test-init.sh b/test/TEST-03-USR-MOUNT/test-init.sh new file mode 100755 index 0000000..108e626 --- /dev/null +++ b/test/TEST-03-USR-MOUNT/test-init.sh @@ -0,0 +1,24 @@ +#!/bin/sh +: > /dev/watchdog + +. /lib/dracut-lib.sh + +export PATH=/usr/sbin:/usr/bin:/sbin:/bin +command -v plymouth > /dev/null 2>&1 && plymouth --quit +exec > /dev/console 2>&1 + +echo "dracut-root-block-success" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker + +export TERM=linux +export PS1='initramfs-test:\w\$ ' +[ -f /etc/mtab ] || ln -sfn /proc/mounts /etc/mtab +[ -f /etc/fstab ] || ln -sfn /proc/mounts /etc/fstab +stty sane +echo "made it to the rootfs!" +if getargbool 0 rd.shell; then + strstr "$(setsid --help)" "control" && CTTY="-c" + setsid $CTTY sh -i +fi +echo "Powering down." +mount -n -o remount,ro / +poweroff -f diff --git a/test/TEST-03-USR-MOUNT/test.sh b/test/TEST-03-USR-MOUNT/test.sh new file mode 100755 index 0000000..69ffda3 --- /dev/null +++ b/test/TEST-03-USR-MOUNT/test.sh @@ -0,0 +1,96 @@ +#!/bin/bash + +# shellcheck disable=SC2034 +TEST_DESCRIPTION="root filesystem on a btrfs filesystem with /usr subvolume" + +# Uncomment this to debug failures +#DEBUGFAIL="rd.shell rd.break" + +client_run() { + local test_name="$1" + shift + local client_opts="$*" + + echo "CLIENT TEST START: $test_name" + + declare -a disk_args=() + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker + qemu_add_drive_args disk_index disk_args "$TESTDIR"/root.btrfs root + qemu_add_drive_args disk_index disk_args "$TESTDIR"/usr.btrfs usr + + test_marker_reset + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -device i6300esb -watchdog-action poweroff \ + -append "panic=1 oops=panic softlockup_panic=1 systemd.crash_reboot root=LABEL=dracut $client_opts loglevel=7 rd.retry=3 rd.info console=ttyS0,115200n81 selinux=0 rd.debug rd.shell=0 $DEBUGFAIL" \ + -initrd "$TESTDIR"/initramfs.testing || return 1 + + if ! test_marker_check; then + echo "CLIENT TEST END: $test_name [FAILED]" + return 1 + fi + echo "CLIENT TEST END: $test_name [OK]" +} + +test_run() { + client_run "no option specified" || return 1 + client_run "readonly root" "ro" || return 1 + client_run "writeable root" "rw" || return 1 +} + +test_setup() { + # Create what will eventually be our root filesystem onto an overlay + "$DRACUT" -l --keep --tmpdir "$TESTDIR" \ + -m "test-root" \ + -i ./test-init.sh /sbin/init \ + -i ./fstab /etc/fstab \ + -i "${PKGLIBDIR}/modules.d/99base/dracut-lib.sh" "/lib/dracut-lib.sh" \ + -i "${PKGLIBDIR}/modules.d/99base/dracut-dev-lib.sh" "/lib/dracut-dev-lib.sh" \ + --no-hostonly --no-hostonly-cmdline --nomdadmconf --nohardlink \ + -f "$TESTDIR"/initramfs.root "$KVERSION" || return 1 + mkdir -p "$TESTDIR"/overlay/source && mv "$TESTDIR"/dracut.*/initramfs/* "$TESTDIR"/overlay/source && rm -rf "$TESTDIR"/dracut.* + + # second, install the files needed to make the root filesystem + # create an initramfs that will create the target root filesystem. + # We do it this way so that we do not risk trashing the host mdraid + # devices, volume groups, encrypted partitions, etc. + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -m "test-makeroot" \ + -I "mkfs.btrfs" \ + -i ./create-root.sh /lib/dracut/hooks/initqueue/01-create-root.sh \ + --nomdadmconf \ + --nohardlink \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.makeroot "$KVERSION" || return 1 + rm -rf -- "$TESTDIR"/overlay + + # Create the blank file to use as a root filesystem + declare -a disk_args=() + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker 1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/root.btrfs root 160 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/usr.btrfs usr 160 + + # Invoke KVM and/or QEMU to actually create the target filesystem. + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "root=/dev/dracut/root rw rootfstype=btrfs quiet console=ttyS0,115200n81 selinux=0" \ + -initrd "$TESTDIR"/initramfs.makeroot || return 1 + + if ! test_marker_check dracut-root-block-created; then + echo "Could not create root filesystem" + return 1 + fi + + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -a "test watchdog" \ + -o "network kernel-network-modules" \ + -d "piix ide-gd_mod ata_piix btrfs sd_mod i6300esb ib700wdt" \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.testing "$KVERSION" || return 1 + rm -rf -- "$TESTDIR"/overlay +} + +# shellcheck disable=SC1090 +. "$testdir"/test-functions diff --git a/test/TEST-04-FULL-SYSTEMD/Makefile b/test/TEST-04-FULL-SYSTEMD/Makefile new file mode 100644 index 0000000..2dcab81 --- /dev/null +++ b/test/TEST-04-FULL-SYSTEMD/Makefile @@ -0,0 +1 @@ +-include ../Makefile.testdir diff --git a/test/TEST-04-FULL-SYSTEMD/create-root.sh b/test/TEST-04-FULL-SYSTEMD/create-root.sh new file mode 100755 index 0000000..411fa99 --- /dev/null +++ b/test/TEST-04-FULL-SYSTEMD/create-root.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +trap 'poweroff -f' EXIT + +# don't let udev and this script step on eachother's toes +for x in 64-lvm.rules 70-mdadm.rules 99-mount-rules; do + : > "/etc/udev/rules.d/$x" +done +rm -f -- /etc/lvm/lvm.conf +udevadm control --reload +set -e + +udevadm settle +modprobe btrfs || : +mkfs.btrfs -L dracut /dev/disk/by-id/ata-disk_root +mkfs.btrfs -L dracutusr /dev/disk/by-id/ata-disk_usr +btrfs device scan /dev/disk/by-id/ata-disk_root +btrfs device scan /dev/disk/by-id/ata-disk_usr +mkdir -p /root +mount -t btrfs /dev/disk/by-id/ata-disk_root /root +[ -d /root/usr ] || mkdir -p /root/usr +mount -t btrfs /dev/disk/by-id/ata-disk_usr /root/usr +btrfs subvolume create /root/usr/usr +umount /root/usr +mount -t btrfs -o subvol=usr /dev/disk/by-id/ata-disk_usr /root/usr +cp -a -t /root /source/* +mkdir -p /root/run +btrfs filesystem sync /root/usr +btrfs filesystem sync /root +umount /root/usr +umount /root +echo "dracut-root-block-created" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker +poweroff -f diff --git a/test/TEST-04-FULL-SYSTEMD/fstab b/test/TEST-04-FULL-SYSTEMD/fstab new file mode 100644 index 0000000..feac57a --- /dev/null +++ b/test/TEST-04-FULL-SYSTEMD/fstab @@ -0,0 +1,2 @@ +/dev/disk/by-id/ata-disk_root / btrfs defaults 0 0 +/dev/disk/by-id/ata-disk_usr /usr btrfs subvol=usr,ro 0 0 diff --git a/test/TEST-04-FULL-SYSTEMD/test-init.sh b/test/TEST-04-FULL-SYSTEMD/test-init.sh new file mode 100755 index 0000000..b7261b5 --- /dev/null +++ b/test/TEST-04-FULL-SYSTEMD/test-init.sh @@ -0,0 +1,41 @@ +#!/bin/sh +: > /dev/watchdog + +. /lib/dracut-lib.sh + +export PATH=/usr/sbin:/usr/bin:/sbin:/bin +command -v plymouth > /dev/null 2>&1 && plymouth --quit +exec > /dev/console 2>&1 + +systemctl --failed --no-legend --no-pager > /failed + +if ! ismounted /usr; then + echo "**************************FAILED**************************" + echo "/usr not mounted!!" + cat /proc/mounts + echo "**************************FAILED**************************" +else + if [ -s /failed ]; then + echo "**************************FAILED**************************" + cat /failed + echo "**************************FAILED**************************" + + else + echo "dracut-root-block-success" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker + echo "All OK" + fi +fi + +export TERM=linux +export PS1='initramfs-test:\w\$ ' +[ -f /etc/mtab ] || ln -sfn /proc/mounts /etc/mtab +[ -f /etc/fstab ] || ln -sfn /proc/mounts /etc/fstab +stty sane +echo "made it to the rootfs!" +if getargbool 0 rd.shell; then + strstr "$(setsid --help)" "control" && CTTY="-c" + setsid $CTTY sh -i +fi +echo "Powering down." +systemctl --no-block poweroff +exit 0 diff --git a/test/TEST-04-FULL-SYSTEMD/test.sh b/test/TEST-04-FULL-SYSTEMD/test.sh new file mode 100755 index 0000000..160104f --- /dev/null +++ b/test/TEST-04-FULL-SYSTEMD/test.sh @@ -0,0 +1,163 @@ +#!/bin/bash + +# shellcheck disable=SC2034 +TEST_DESCRIPTION="Full systemd serialization/deserialization test with /usr mount" + +test_check() { + command -v systemctl &> /dev/null +} + +# Uncomment this to debug failures +#DEBUGFAIL="rd.shell rd.break" +#DEBUGOUT="quiet systemd.log_level=debug systemd.log_target=console loglevel=77 rd.info rd.debug" +DEBUGOUT="loglevel=0 " +client_run() { + local test_name="$1" + shift + local client_opts="$*" + + echo "CLIENT TEST START: $test_name" + + declare -a disk_args=() + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker + qemu_add_drive_args disk_index disk_args "$TESTDIR"/root.btrfs root + qemu_add_drive_args disk_index disk_args "$TESTDIR"/usr.btrfs usr + + test_marker_reset + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "systemd.unit=testsuite.target systemd.mask=systemd-firstboot panic=1 oops=panic softlockup_panic=1 systemd.crash_reboot root=LABEL=dracut $client_opts rd.retry=3 console=ttyS0,115200n81 selinux=0 $DEBUGOUT rd.shell=0 $DEBUGFAIL" \ + -initrd "$TESTDIR"/initramfs.testing || return 1 + + if ! test_marker_check; then + echo "CLIENT TEST END: $test_name [FAILED]" + return 1 + fi + echo "CLIENT TEST END: $test_name [OK]" + +} + +test_run() { + client_run "no option specified" || return 1 + client_run "readonly root" "ro" || return 1 + client_run "writeable root" "rw" || return 1 + return 0 +} + +test_setup() { + # shellcheck disable=SC2064 + trap "$(shopt -p globstar)" RETURN + shopt -q -s globstar + + # Create what will eventually be our root filesystem onto an overlay + "$DRACUT" -l --keep --tmpdir "$TESTDIR" \ + -m "test-root dbus" \ + -I "ldconfig" \ + -i ./test-init.sh /sbin/test-init \ + -i ./fstab /etc/fstab \ + -i "${PKGLIBDIR}/modules.d/99base/dracut-lib.sh" "/lib/dracut-lib.sh" \ + -i "${PKGLIBDIR}/modules.d/99base/dracut-dev-lib.sh" "/lib/dracut-dev-lib.sh" \ + --no-hostonly --no-hostonly-cmdline --nomdadmconf --nohardlink \ + -f "$TESTDIR"/initramfs.root "$KVERSION" || return 1 + + mkdir -p "$TESTDIR"/overlay/source && cp -a "$TESTDIR"/dracut.*/initramfs/* "$TESTDIR"/overlay/source && rm -rf "$TESTDIR"/dracut.* && export initdir=$TESTDIR/overlay/source + + if type -P rpm &> /dev/null; then + rpm -ql systemd | xargs -r "$PKGLIBDIR"/dracut-install ${initdir:+-D "$initdir"} -o -a -l + elif type -P dpkg &> /dev/null; then + dpkg -L systemd | xargs -r "$PKGLIBDIR"/dracut-install ${initdir:+-D "$initdir"} -o -a -l + elif type -P pacman &> /dev/null; then + pacman -Q -l systemd | while read -r _ a; do printf -- "%s\0" "$a"; done | xargs -0 -r "$PKGLIBDIR"/dracut-install ${initdir:+-D "$initdir"} -o -a -l + else + echo "Can't install systemd base" + return 1 + fi + + # softlink mtab + ln -fs /proc/self/mounts "$initdir"/etc/mtab + + # install any Execs from the service files + grep -Eho '^Exec[^ ]*=[^ ]+' "$initdir"{,/usr}/lib/systemd/system/*.service \ + | while read -r i || [ -n "$i" ]; do + i=${i##Exec*=} + i=${i##-} + "$PKGLIBDIR"/dracut-install ${initdir:+-D "$initdir"} -o -a -l "$i" + done + + # setup the testsuite target + mkdir -p "$initdir"/etc/systemd/system + cat > "$initdir"/etc/systemd/system/testsuite.target << EOF +[Unit] +Description=Testsuite target +Requires=basic.target +After=basic.target +Conflicts=rescue.target +AllowIsolate=yes +EOF + + # setup the testsuite service + cat > "$initdir"/etc/systemd/system/testsuite.service << EOF +[Unit] +Description=Testsuite service +After=basic.target + +[Service] +ExecStart=/sbin/test-init +Type=oneshot +StandardInput=tty +StandardOutput=tty +EOF + + mkdir -p "$initdir"/etc/systemd/system/testsuite.target.wants + ln -fs ../testsuite.service "$initdir"/etc/systemd/system/testsuite.target.wants/testsuite.service + + # second, install the files needed to make the root filesystem + # create an initramfs that will create the target root filesystem. + # We do it this way so that we do not risk trashing the host mdraid + # devices, volume groups, encrypted partitions, etc. + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -m "test-makeroot bash btrfs" \ + -I "mkfs.btrfs" \ + -i ./create-root.sh /lib/dracut/hooks/initqueue/01-create-root.sh \ + --nomdadmconf \ + --nohardlink \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.makeroot "$KVERSION" || return 1 + rm -rf -- "$TESTDIR"/overlay/* + + # Create the blank file to use as a root filesystem + declare -a disk_args=() + # shellcheck disable=SC2034 + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker 1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/root.btrfs root 160 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/usr.btrfs usr 160 + + # Invoke KVM and/or QEMU to actually create the target filesystem. + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "root=/dev/fakeroot rw rootfstype=btrfs quiet console=ttyS0,115200n81 selinux=0" \ + -initrd "$TESTDIR"/initramfs.makeroot || return 1 + + if ! test_marker_check dracut-root-block-created; then + echo "Could not create root filesystem" + return 1 + fi + + [ -e /etc/machine-id ] && EXTRA_MACHINE="/etc/machine-id" + [ -e /etc/machine-info ] && EXTRA_MACHINE+=" /etc/machine-info" + + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -a "test systemd i18n qemu" \ + ${EXTRA_MACHINE:+-I "$EXTRA_MACHINE"} \ + -o "network plymouth lvm mdraid resume crypt caps dm terminfo usrmount kernel-network-modules rngd" \ + -d "piix ide-gd_mod ata_piix btrfs sd_mod i6300esb ib700wdt" \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.testing "$KVERSION" || return 1 + + rm -rf -- "$TESTDIR"/overlay +} + +# shellcheck disable=SC1090 +. "$testdir"/test-functions diff --git a/test/TEST-10-RAID/Makefile b/test/TEST-10-RAID/Makefile new file mode 100644 index 0000000..2dcab81 --- /dev/null +++ b/test/TEST-10-RAID/Makefile @@ -0,0 +1 @@ +-include ../Makefile.testdir diff --git a/test/TEST-10-RAID/create-root.sh b/test/TEST-10-RAID/create-root.sh new file mode 100755 index 0000000..05dec0f --- /dev/null +++ b/test/TEST-10-RAID/create-root.sh @@ -0,0 +1,47 @@ +#!/bin/sh + +trap 'poweroff -f' EXIT + +# don't let udev and this script step on eachother's toes +for x in 64-lvm.rules 70-mdadm.rules 99-mount-rules; do + : > "/etc/udev/rules.d/$x" +done +rm -f -- /etc/lvm/lvm.conf +udevadm control --reload +udevadm settle +set -ex +mdadm --create /dev/md0 --run --auto=yes --level=5 --raid-devices=3 /dev/disk/by-id/ata-disk_raid[123] +# wait for the array to finish initializing, otherwise this sometimes fails +# randomly. +mdadm -W /dev/md0 || : +printf test > keyfile +cryptsetup -q luksFormat /dev/md0 /keyfile +echo "The passphrase is test" +cryptsetup luksOpen /dev/md0 dracut_crypt_test < /keyfile +lvm pvcreate -ff -y /dev/mapper/dracut_crypt_test +lvm vgcreate dracut /dev/mapper/dracut_crypt_test +lvm lvcreate -l 100%FREE -n root dracut +lvm vgchange -ay +mkfs.ext4 -L root /dev/dracut/root +mkdir -p /sysroot +mount -t ext4 /dev/dracut/root /sysroot +cp -a -t /sysroot /source/* +mkdir -p /sysroot/run +umount /sysroot +lvm lvchange -a n /dev/dracut/root +udevadm settle +cryptsetup luksClose /dev/mapper/dracut_crypt_test +udevadm settle +mdadm -W /dev/md0 || : +udevadm settle +mdadm --detail --export /dev/md0 | grep -F MD_UUID > /tmp/mduuid +. /tmp/mduuid +udevadm settle +eval "$(udevadm info --query=property --name=/dev/md0 | while read -r line || [ -n "$line" ]; do [ "$line" != "${line#*ID_FS_UUID*}" ] && echo "$line"; done)" +{ + echo "dracut-root-block-created" + echo MD_UUID="$MD_UUID" + echo "ID_FS_UUID=$ID_FS_UUID" +} | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker +sync +poweroff -f diff --git a/test/TEST-10-RAID/cryptroot-ask.sh b/test/TEST-10-RAID/cryptroot-ask.sh new file mode 100755 index 0000000..7e956b3 --- /dev/null +++ b/test/TEST-10-RAID/cryptroot-ask.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +[ -b "/dev/mapper/$2" ] && exit 0 +printf test > /keyfile +/sbin/cryptsetup luksOpen "$1" "$2" < /keyfile diff --git a/test/TEST-10-RAID/finished-false.sh b/test/TEST-10-RAID/finished-false.sh new file mode 100755 index 0000000..ecdbef9 --- /dev/null +++ b/test/TEST-10-RAID/finished-false.sh @@ -0,0 +1,2 @@ +#!/bin/sh +exit 1 diff --git a/test/TEST-10-RAID/hard-off.sh b/test/TEST-10-RAID/hard-off.sh new file mode 100755 index 0000000..01acb19 --- /dev/null +++ b/test/TEST-10-RAID/hard-off.sh @@ -0,0 +1,3 @@ +#!/bin/sh +getargbool 0 rd.shell || poweroff -f +getargbool 0 failme && poweroff -f diff --git a/test/TEST-10-RAID/test-init.sh b/test/TEST-10-RAID/test-init.sh new file mode 100755 index 0000000..108e626 --- /dev/null +++ b/test/TEST-10-RAID/test-init.sh @@ -0,0 +1,24 @@ +#!/bin/sh +: > /dev/watchdog + +. /lib/dracut-lib.sh + +export PATH=/usr/sbin:/usr/bin:/sbin:/bin +command -v plymouth > /dev/null 2>&1 && plymouth --quit +exec > /dev/console 2>&1 + +echo "dracut-root-block-success" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker + +export TERM=linux +export PS1='initramfs-test:\w\$ ' +[ -f /etc/mtab ] || ln -sfn /proc/mounts /etc/mtab +[ -f /etc/fstab ] || ln -sfn /proc/mounts /etc/fstab +stty sane +echo "made it to the rootfs!" +if getargbool 0 rd.shell; then + strstr "$(setsid --help)" "control" && CTTY="-c" + setsid $CTTY sh -i +fi +echo "Powering down." +mount -n -o remount,ro / +poweroff -f diff --git a/test/TEST-10-RAID/test.sh b/test/TEST-10-RAID/test.sh new file mode 100755 index 0000000..15cbf56 --- /dev/null +++ b/test/TEST-10-RAID/test.sh @@ -0,0 +1,124 @@ +#!/bin/bash +# shellcheck disable=SC2034 +TEST_DESCRIPTION="root filesystem on an encrypted LVM PV on a RAID-5" + +# Uncomment this to debug failures +#DEBUGFAIL="rd.shell rd.udev.log-priority=debug loglevel=70 systemd.log_target=kmsg" +#DEBUGFAIL="rd.break rd.shell rd.debug debug" +test_run() { + declare -a disk_args=() + # shellcheck disable=SC2034 + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid-1.img raid1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid-2.img raid2 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid-3.img raid3 + + test_marker_reset + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "panic=1 oops=panic softlockup_panic=1 systemd.crash_reboot root=/dev/dracut/root rd.auto rw rd.retry=10 console=ttyS0,115200n81 selinux=0 rd.shell=0 $DEBUGFAIL" \ + -initrd "$TESTDIR"/initramfs.testing || return 1 + + test_marker_check || return 1 +} + +test_setup() { + kernel=$KVERSION + # Create what will eventually be our root filesystem onto an overlay + ( + # shellcheck disable=SC2030 + export initdir=$TESTDIR/overlay/source + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + ( + cd "$initdir" || exit + mkdir -p -- dev sys proc etc var/run tmp + mkdir -p root usr/bin usr/lib usr/lib64 usr/sbin + ) + inst_multiple sh df free ls shutdown poweroff stty cat ps ln \ + mount dmesg mkdir cp dd sync + for _terminfodir in /lib/terminfo /etc/terminfo /usr/share/terminfo; do + [ -f ${_terminfodir}/l/linux ] && break + done + inst_multiple -o ${_terminfodir}/l/linux + + inst_simple "${PKGLIBDIR}/modules.d/99base/dracut-lib.sh" "/lib/dracut-lib.sh" + inst_simple "${PKGLIBDIR}/modules.d/99base/dracut-dev-lib.sh" "/lib/dracut-dev-lib.sh" + inst_binary "${PKGLIBDIR}/dracut-util" "/usr/bin/dracut-util" + ln -s dracut-util "${initdir}/usr/bin/dracut-getarg" + ln -s dracut-util "${initdir}/usr/bin/dracut-getargs" + + inst_simple /etc/os-release + inst ./test-init.sh /sbin/init + inst_multiple grep + inst_multiple -o /lib/systemd/systemd-shutdown + find_binary plymouth > /dev/null && inst_multiple plymouth + cp -a /etc/ld.so.conf* "$initdir"/etc + ldconfig -r "$initdir" + ) + + # second, install the files needed to make the root filesystem + ( + # shellcheck disable=SC2031 + # shellcheck disable=SC2030 + export initdir=$TESTDIR/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + inst_multiple sfdisk mkfs.ext4 poweroff cp umount dd sync grep + inst_hook initqueue 01 ./create-root.sh + inst_hook initqueue/finished 01 ./finished-false.sh + ) + + # create an initramfs that will create the target root filesystem. + # We do it this way so that we do not risk trashing the host mdraid + # devices, volume groups, encrypted partitions, etc. + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -m "bash crypt lvm mdraid kernel-modules qemu" \ + -d "piix ide-gd_mod ata_piix ext4 sd_mod" \ + --nomdadmconf \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.makeroot "$KVERSION" || return 1 + rm -rf -- "$TESTDIR"/overlay + + # Create the blank files to use as a root filesystem + declare -a disk_args=() + # shellcheck disable=SC2034 + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker 1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid-1.img raid1 40 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid-2.img raid2 40 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid-3.img raid3 40 + + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "root=/dev/cannotreach rw rootfstype=ext4 console=ttyS0,115200n81 selinux=0" \ + -initrd "$TESTDIR"/initramfs.makeroot || return 1 + test_marker_check dracut-root-block-created || return 1 + eval "$(grep -F -a -m 1 ID_FS_UUID "$TESTDIR"/marker.img)" + + ( + # shellcheck disable=SC2031 + export initdir=$TESTDIR/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + inst_multiple poweroff shutdown dd + inst_hook shutdown-emergency 000 ./hard-off.sh + inst_hook emergency 000 ./hard-off.sh + inst ./cryptroot-ask.sh /sbin/cryptroot-ask + mkdir -p "$initdir"/etc + echo "testluks UUID=$ID_FS_UUID /etc/key" > "$initdir"/etc/crypttab + #echo "luks-$ID_FS_UUID /dev/md0 none" > $initdir/etc/crypttab + echo -n "test" > "$initdir"/etc/key + ) + + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -o "plymouth network kernel-network-modules" \ + -a "debug" \ + -d "piix ide-gd_mod ata_piix ext4 sd_mod" \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.testing "$KVERSION" || return 1 +} + +# shellcheck disable=SC1090 +. "$testdir"/test-functions diff --git a/test/TEST-11-LVM/Makefile b/test/TEST-11-LVM/Makefile new file mode 100644 index 0000000..2dcab81 --- /dev/null +++ b/test/TEST-11-LVM/Makefile @@ -0,0 +1 @@ +-include ../Makefile.testdir diff --git a/test/TEST-11-LVM/create-root.sh b/test/TEST-11-LVM/create-root.sh new file mode 100755 index 0000000..015bfe7 --- /dev/null +++ b/test/TEST-11-LVM/create-root.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +trap 'poweroff -f' EXIT + +# don't let udev and this script step on eachother's toes +for x in 64-lvm.rules 70-mdadm.rules 99-mount-rules; do + : > "/etc/udev/rules.d/$x" +done +rm -f -- /etc/lvm/lvm.conf +udevadm control --reload +udevadm settle + +set -ex +for dev in /dev/disk/by-id/ata-disk_disk[123]; do + lvm pvcreate -ff -y "$dev" +done + +lvm vgcreate dracut /dev/disk/by-id/ata-disk_disk[123] +lvm lvcreate -l 100%FREE -n root dracut +lvm vgchange -ay +mkfs.ext4 /dev/dracut/root +mkdir -p /sysroot +mount -t ext4 /dev/dracut/root /sysroot +cp -a -t /sysroot /source/* +umount /sysroot +lvm lvchange -a n /dev/dracut/root +echo "dracut-root-block-created" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker +poweroff -f diff --git a/test/TEST-11-LVM/finished-false.sh b/test/TEST-11-LVM/finished-false.sh new file mode 100755 index 0000000..ecdbef9 --- /dev/null +++ b/test/TEST-11-LVM/finished-false.sh @@ -0,0 +1,2 @@ +#!/bin/sh +exit 1 diff --git a/test/TEST-11-LVM/hard-off.sh b/test/TEST-11-LVM/hard-off.sh new file mode 100755 index 0000000..01acb19 --- /dev/null +++ b/test/TEST-11-LVM/hard-off.sh @@ -0,0 +1,3 @@ +#!/bin/sh +getargbool 0 rd.shell || poweroff -f +getargbool 0 failme && poweroff -f diff --git a/test/TEST-11-LVM/test-init.sh b/test/TEST-11-LVM/test-init.sh new file mode 100755 index 0000000..108e626 --- /dev/null +++ b/test/TEST-11-LVM/test-init.sh @@ -0,0 +1,24 @@ +#!/bin/sh +: > /dev/watchdog + +. /lib/dracut-lib.sh + +export PATH=/usr/sbin:/usr/bin:/sbin:/bin +command -v plymouth > /dev/null 2>&1 && plymouth --quit +exec > /dev/console 2>&1 + +echo "dracut-root-block-success" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker + +export TERM=linux +export PS1='initramfs-test:\w\$ ' +[ -f /etc/mtab ] || ln -sfn /proc/mounts /etc/mtab +[ -f /etc/fstab ] || ln -sfn /proc/mounts /etc/fstab +stty sane +echo "made it to the rootfs!" +if getargbool 0 rd.shell; then + strstr "$(setsid --help)" "control" && CTTY="-c" + setsid $CTTY sh -i +fi +echo "Powering down." +mount -n -o remount,ro / +poweroff -f diff --git a/test/TEST-11-LVM/test.sh b/test/TEST-11-LVM/test.sh new file mode 100755 index 0000000..2782810 --- /dev/null +++ b/test/TEST-11-LVM/test.sh @@ -0,0 +1,117 @@ +#!/bin/bash + +# shellcheck disable=SC2034 +TEST_DESCRIPTION="root filesystem on LVM PV" + +# Uncomment this to debug failures +#DEBUGFAIL="rd.break rd.shell" + +test_run() { + declare -a disk_args=() + # shellcheck disable=SC2034 + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker + qemu_add_drive_args disk_index disk_args "$TESTDIR"/disk-1.img disk1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/disk-2.img disk2 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/disk-3.img disk3 + + test_marker_reset + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "panic=1 oops=panic softlockup_panic=1 systemd.crash_reboot root=/dev/dracut/root rw rd.auto=1 quiet rd.retry=3 rd.info console=ttyS0,115200n81 selinux=0 rd.debug rd.shell=0 $DEBUGFAIL" \ + -initrd "$TESTDIR"/initramfs.testing || return 1 + + test_marker_check || return 1 +} + +test_setup() { + kernel=$KVERSION + # Create what will eventually be our root filesystem onto an overlay + ( + # shellcheck disable=SC2030 + export initdir=$TESTDIR/overlay/source + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + ( + cd "$initdir" || exit + mkdir -p -- dev sys proc etc var/run tmp + mkdir -p root usr/bin usr/lib usr/lib64 usr/sbin + ) + inst_multiple sh df free ls shutdown poweroff stty cat ps ln \ + mount dmesg mkdir cp dd sync + for _terminfodir in /lib/terminfo /etc/terminfo /usr/share/terminfo; do + [ -f ${_terminfodir}/l/linux ] && break + done + inst_multiple -o ${_terminfodir}/l/linux + + inst_simple "${PKGLIBDIR}/modules.d/99base/dracut-lib.sh" "/lib/dracut-lib.sh" + inst_simple "${PKGLIBDIR}/modules.d/99base/dracut-dev-lib.sh" "/lib/dracut-dev-lib.sh" + inst_binary "${PKGLIBDIR}/dracut-util" "/usr/bin/dracut-util" + ln -s dracut-util "${initdir}/usr/bin/dracut-getarg" + ln -s dracut-util "${initdir}/usr/bin/dracut-getargs" + + inst_multiple grep + inst_simple /etc/os-release + inst ./test-init.sh /sbin/init + find_binary plymouth > /dev/null && inst_multiple plymouth + cp -a /etc/ld.so.conf* "$initdir"/etc + mkdir -p "$initdir"/run + ldconfig -r "$initdir" + ) + + # second, install the files needed to make the root filesystem + ( + # shellcheck disable=SC2031 + # shellcheck disable=SC2030 + export initdir=$TESTDIR/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + inst_multiple sfdisk mkfs.ext4 poweroff cp umount dd sync + inst_hook initqueue 01 ./create-root.sh + inst_hook initqueue/finished 01 ./finished-false.sh + ) + + # create an initramfs that will create the target root filesystem. + # We do it this way so that we do not risk trashing the host mdraid + # devices, volume groups, encrypted partitions, etc. + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -m "bash lvm mdraid kernel-modules qemu" \ + -d "piix ide-gd_mod ata_piix ext4 sd_mod" \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.makeroot "$KVERSION" || return 1 + rm -rf -- "$TESTDIR"/overlay + + # Create the blank files to use as a root filesystem + declare -a disk_args=() + # shellcheck disable=SC2034 + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker 1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/disk-1.img disk1 40 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/disk-2.img disk2 40 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/disk-3.img disk3 40 + + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "root=/dev/fakeroot rw rootfstype=ext4 quiet console=ttyS0,115200n81 selinux=0" \ + -initrd "$TESTDIR"/initramfs.makeroot || return 1 + test_marker_check dracut-root-block-created || return 1 + + ( + # shellcheck disable=SC2031 + export initdir=$TESTDIR/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + inst_multiple poweroff shutdown dd + inst_hook shutdown-emergency 000 ./hard-off.sh + inst_hook emergency 000 ./hard-off.sh + ) + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -o "plymouth network kernel-network-modules" \ + -a "debug" \ + -d "piix ide-gd_mod ata_piix ext4 sd_mod" \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.testing "$KVERSION" || return 1 +} + +# shellcheck disable=SC1090 +. "$testdir"/test-functions diff --git a/test/TEST-12-RAID-DEG/Makefile b/test/TEST-12-RAID-DEG/Makefile new file mode 100644 index 0000000..2dcab81 --- /dev/null +++ b/test/TEST-12-RAID-DEG/Makefile @@ -0,0 +1 @@ +-include ../Makefile.testdir diff --git a/test/TEST-12-RAID-DEG/create-root.sh b/test/TEST-12-RAID-DEG/create-root.sh new file mode 100755 index 0000000..05dec0f --- /dev/null +++ b/test/TEST-12-RAID-DEG/create-root.sh @@ -0,0 +1,47 @@ +#!/bin/sh + +trap 'poweroff -f' EXIT + +# don't let udev and this script step on eachother's toes +for x in 64-lvm.rules 70-mdadm.rules 99-mount-rules; do + : > "/etc/udev/rules.d/$x" +done +rm -f -- /etc/lvm/lvm.conf +udevadm control --reload +udevadm settle +set -ex +mdadm --create /dev/md0 --run --auto=yes --level=5 --raid-devices=3 /dev/disk/by-id/ata-disk_raid[123] +# wait for the array to finish initializing, otherwise this sometimes fails +# randomly. +mdadm -W /dev/md0 || : +printf test > keyfile +cryptsetup -q luksFormat /dev/md0 /keyfile +echo "The passphrase is test" +cryptsetup luksOpen /dev/md0 dracut_crypt_test < /keyfile +lvm pvcreate -ff -y /dev/mapper/dracut_crypt_test +lvm vgcreate dracut /dev/mapper/dracut_crypt_test +lvm lvcreate -l 100%FREE -n root dracut +lvm vgchange -ay +mkfs.ext4 -L root /dev/dracut/root +mkdir -p /sysroot +mount -t ext4 /dev/dracut/root /sysroot +cp -a -t /sysroot /source/* +mkdir -p /sysroot/run +umount /sysroot +lvm lvchange -a n /dev/dracut/root +udevadm settle +cryptsetup luksClose /dev/mapper/dracut_crypt_test +udevadm settle +mdadm -W /dev/md0 || : +udevadm settle +mdadm --detail --export /dev/md0 | grep -F MD_UUID > /tmp/mduuid +. /tmp/mduuid +udevadm settle +eval "$(udevadm info --query=property --name=/dev/md0 | while read -r line || [ -n "$line" ]; do [ "$line" != "${line#*ID_FS_UUID*}" ] && echo "$line"; done)" +{ + echo "dracut-root-block-created" + echo MD_UUID="$MD_UUID" + echo "ID_FS_UUID=$ID_FS_UUID" +} | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker +sync +poweroff -f diff --git a/test/TEST-12-RAID-DEG/cryptroot-ask.sh b/test/TEST-12-RAID-DEG/cryptroot-ask.sh new file mode 100755 index 0000000..a6b7ac7 --- /dev/null +++ b/test/TEST-12-RAID-DEG/cryptroot-ask.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +[ -b /dev/mapper/"$2" ] && exit 0 +printf test > /keyfile +/sbin/cryptsetup luksOpen "$1" "$2" < /keyfile diff --git a/test/TEST-12-RAID-DEG/finished-false.sh b/test/TEST-12-RAID-DEG/finished-false.sh new file mode 100755 index 0000000..ecdbef9 --- /dev/null +++ b/test/TEST-12-RAID-DEG/finished-false.sh @@ -0,0 +1,2 @@ +#!/bin/sh +exit 1 diff --git a/test/TEST-12-RAID-DEG/hard-off.sh b/test/TEST-12-RAID-DEG/hard-off.sh new file mode 100755 index 0000000..8179d57 --- /dev/null +++ b/test/TEST-12-RAID-DEG/hard-off.sh @@ -0,0 +1,4 @@ +#!/bin/sh +sleep 5 +getargbool 0 rd.shell || poweroff -f +! getargbool 0 rd.break && getargbool 0 failme && poweroff -f diff --git a/test/TEST-12-RAID-DEG/test-init.sh b/test/TEST-12-RAID-DEG/test-init.sh new file mode 100755 index 0000000..a5360ef --- /dev/null +++ b/test/TEST-12-RAID-DEG/test-init.sh @@ -0,0 +1,27 @@ +#!/bin/sh +: > /dev/watchdog + +. /lib/dracut-lib.sh + +export PATH=/usr/sbin:/usr/bin:/sbin:/bin +command -v plymouth > /dev/null 2>&1 && plymouth --quit +exec > /dev/console 2>&1 + +echo "dracut-root-block-success" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker + +export TERM=linux +export PS1='initramfs-test:\w\$ ' +[ -f /etc/mtab ] || ln -sfn /proc/mounts /etc/mtab +[ -f /etc/fstab ] || ln -sfn /proc/mounts /etc/fstab +stty sane +echo "made it to the rootfs!" +if getargbool 0 rd.shell; then + strstr "$(setsid --help)" "control" && CTTY="-c" + setsid $CTTY sh -i +fi +echo "Powering down." +mount -n -o remount,ro / +if [ -d /run/initramfs/etc ]; then + echo " rd.debug=0 " >> /run/initramfs/etc/cmdline +fi +poweroff -f diff --git a/test/TEST-12-RAID-DEG/test.sh b/test/TEST-12-RAID-DEG/test.sh new file mode 100755 index 0000000..da5177b --- /dev/null +++ b/test/TEST-12-RAID-DEG/test.sh @@ -0,0 +1,160 @@ +#!/bin/bash +# shellcheck disable=SC2034 +TEST_DESCRIPTION="root filesystem on an encrypted LVM PV on a degraded RAID-5" + +# Uncomment this to debug failures +#DEBUGFAIL="rd.shell rd.break rd.debug" +#DEBUGFAIL="rd.shell rd.break=pre-mount udev.log-priority=debug" +#DEBUGFAIL="rd.shell rd.udev.log-priority=debug loglevel=70 systemd.log_target=kmsg" +#DEBUGFAIL="rd.shell loglevel=70 systemd.log_target=kmsg" + +client_run() { + echo "CLIENT TEST START: $*" + declare -a disk_args=() + # shellcheck disable=SC2034 + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker + # degrade the RAID + # qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid-1.img raid1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid-2.img raid2 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid-3.img raid3 + + test_marker_reset + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "panic=1 oops=panic softlockup_panic=1 systemd.crash_reboot $* systemd.log_target=kmsg root=LABEL=root rw rd.retry=10 rd.info console=ttyS0,115200n81 log_buf_len=2M selinux=0 rd.shell=0 $DEBUGFAIL " \ + -initrd "$TESTDIR"/initramfs.testing + + if ! test_marker_check; then + echo "CLIENT TEST END: $* [FAIL]" + return 1 + fi + + echo "CLIENT TEST END: $* [OK]" + return 0 +} + +test_run() { + read -r LUKS_UUID < "$TESTDIR"/luksuuid + read -r MD_UUID < "$TESTDIR"/mduuid + + client_run failme && return 1 + client_run rd.auto || return 1 + + client_run rd.luks.uuid="$LUKS_UUID" rd.md.uuid="$MD_UUID" rd.md.conf=0 rd.lvm.vg=dracut || return 1 + + client_run rd.luks.uuid="$LUKS_UUID" rd.md.uuid=failme rd.md.conf=0 rd.lvm.vg=dracut failme && return 1 + + client_run rd.luks.uuid="$LUKS_UUID" rd.md.uuid="$MD_UUID" rd.lvm=0 failme && return 1 + client_run rd.luks.uuid="$LUKS_UUID" rd.md.uuid="$MD_UUID" rd.lvm=0 rd.auto=1 failme && return 1 + client_run rd.luks.uuid="$LUKS_UUID" rd.md.uuid="$MD_UUID" rd.lvm.vg=failme failme && return 1 + client_run rd.luks.uuid="$LUKS_UUID" rd.md.uuid="$MD_UUID" rd.lvm.vg=dracut || return 1 + client_run rd.luks.uuid="$LUKS_UUID" rd.md.uuid="$MD_UUID" rd.lvm.lv=dracut/failme failme && return 1 + client_run rd.luks.uuid="$LUKS_UUID" rd.md.uuid="$MD_UUID" rd.lvm.lv=dracut/root || return 1 + + return 0 +} + +test_setup() { + kernel=$KVERSION + # Create what will eventually be our root filesystem onto an overlay + ( + # shellcheck disable=SC2030 + export initdir=$TESTDIR/overlay/source + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + ( + cd "$initdir" || exit + mkdir -p -- dev sys proc etc var/run tmp + mkdir -p root usr/bin usr/lib usr/lib64 usr/sbin + ) + inst_multiple sh df free ls shutdown poweroff stty cat ps ln \ + mount dmesg mkdir cp dd sync + for _terminfodir in /lib/terminfo /etc/terminfo /usr/share/terminfo; do + [ -f ${_terminfodir}/l/linux ] && break + done + inst_multiple -o ${_terminfodir}/l/linux + + inst_simple "${PKGLIBDIR}/modules.d/99base/dracut-lib.sh" "/lib/dracut-lib.sh" + inst_simple "${PKGLIBDIR}/modules.d/99base/dracut-dev-lib.sh" "/lib/dracut-dev-lib.sh" + inst_binary "${PKGLIBDIR}/dracut-util" "/usr/bin/dracut-util" + ln -s dracut-util "${initdir}/usr/bin/dracut-getarg" + ln -s dracut-util "${initdir}/usr/bin/dracut-getargs" + + inst_multiple grep + inst_simple /etc/os-release + inst ./test-init.sh /sbin/init + find_binary plymouth > /dev/null && inst_multiple plymouth + cp -a /etc/ld.so.conf* "$initdir"/etc + ldconfig -r "$initdir" + ) + + # second, install the files needed to make the root filesystem + ( + # shellcheck disable=SC2030 + # shellcheck disable=SC2031 + export initdir=$TESTDIR/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + inst_multiple sfdisk mkfs.ext4 poweroff cp umount dd grep sync + inst_hook initqueue 01 ./create-root.sh + inst_hook initqueue/finished 01 ./finished-false.sh + ) + + # create an initramfs that will create the target root filesystem. + # We do it this way so that we do not risk trashing the host mdraid + # devices, volume groups, encrypted partitions, etc. + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -m "bash crypt lvm mdraid kernel-modules qemu" \ + -d "piix ide-gd_mod ata_piix ext4 sd_mod" \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.makeroot "$KVERSION" || return 1 + rm -rf -- "$TESTDIR"/overlay + + # Create the blank files to use as a root filesystem + declare -a disk_args=() + # shellcheck disable=SC2034 + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker 1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid-1.img raid1 40 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid-2.img raid2 40 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid-3.img raid3 40 + + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "root=/dev/fakeroot rw rootfstype=ext4 quiet console=ttyS0,115200n81 selinux=0" \ + -initrd "$TESTDIR"/initramfs.makeroot || return 1 + + test_marker_check dracut-root-block-created || return 1 + eval "$(grep -F --binary-files=text -m 1 MD_UUID "$TESTDIR"/marker.img)" + eval "$(grep -F -a -m 1 ID_FS_UUID "$TESTDIR"/marker.img)" + echo "$ID_FS_UUID" > "$TESTDIR"/luksuuid + eval "$(grep -F --binary-files=text -m 1 MD_UUID "$TESTDIR"/marker.img)" + echo "$MD_UUID" > "$TESTDIR"/mduuid + + ( + # shellcheck disable=SC2031 + export initdir=$TESTDIR/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + inst_multiple poweroff shutdown dd + inst_hook shutdown-emergency 000 ./hard-off.sh + inst_hook emergency 000 ./hard-off.sh + inst ./cryptroot-ask.sh /sbin/cryptroot-ask + mkdir -p "$initdir"/etc + echo "ARRAY /dev/md0 level=raid5 num-devices=3 UUID=$MD_UUID" > "$initdir"/etc/mdadm.conf + echo "luks-$ID_FS_UUID UUID=$ID_FS_UUID /etc/key" > "$initdir"/etc/crypttab + echo -n test > "$initdir"/etc/key + chmod 0600 "$initdir"/etc/key + ) + + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -o "plymouth network kernel-network-modules" \ + -a "debug" \ + -d "piix ide-gd_mod ata_piix ext4 sd_mod" \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.testing "$KVERSION" || return 1 +} + +# shellcheck disable=SC1090 +. "$testdir"/test-functions diff --git a/test/TEST-13-ENC-RAID-LVM/Makefile b/test/TEST-13-ENC-RAID-LVM/Makefile new file mode 100644 index 0000000..2dcab81 --- /dev/null +++ b/test/TEST-13-ENC-RAID-LVM/Makefile @@ -0,0 +1 @@ +-include ../Makefile.testdir diff --git a/test/TEST-13-ENC-RAID-LVM/create-root.sh b/test/TEST-13-ENC-RAID-LVM/create-root.sh new file mode 100755 index 0000000..b681e6b --- /dev/null +++ b/test/TEST-13-ENC-RAID-LVM/create-root.sh @@ -0,0 +1,50 @@ +#!/bin/sh + +trap 'poweroff -f' EXIT + +# don't let udev and this script step on eachother's toes +set -x +for x in 64-lvm.rules 70-mdadm.rules 99-mount-rules; do + : > "/etc/udev/rules.d/$x" +done +rm -f -- /etc/lvm/lvm.conf +udevadm control --reload +udevadm settle + +set -ex +printf test > keyfile +cryptsetup -q luksFormat /dev/disk/by-id/ata-disk_disk1 /keyfile +cryptsetup -q luksFormat /dev/disk/by-id/ata-disk_disk2 /keyfile +cryptsetup -q luksFormat /dev/disk/by-id/ata-disk_disk3 /keyfile +cryptsetup luksOpen /dev/disk/by-id/ata-disk_disk1 dracut_disk1 < /keyfile +cryptsetup luksOpen /dev/disk/by-id/ata-disk_disk2 dracut_disk2 < /keyfile +cryptsetup luksOpen /dev/disk/by-id/ata-disk_disk3 dracut_disk3 < /keyfile +mdadm --create /dev/md0 --run --auto=yes --level=5 --raid-devices=3 /dev/mapper/dracut_disk1 /dev/mapper/dracut_disk2 /dev/mapper/dracut_disk3 +# wait for the array to finish initializing, otherwise this sometimes fails +# randomly. +mdadm -W /dev/md0 +lvm pvcreate -ff -y /dev/md0 +lvm vgcreate dracut /dev/md0 + +lvm lvcreate -l 100%FREE -n root dracut +lvm vgchange -ay +mkfs.ext4 /dev/dracut/root +mkdir -p /sysroot +mount -t ext4 /dev/dracut/root /sysroot +cp -a -t /sysroot /source/* +umount /sysroot +lvm lvchange -a n /dev/dracut/root +mdadm -W /dev/md0 || : +mdadm --stop /dev/md0 +cryptsetup luksClose /dev/mapper/dracut_disk1 +cryptsetup luksClose /dev/mapper/dracut_disk2 +cryptsetup luksClose /dev/mapper/dracut_disk3 + +{ + echo "dracut-root-block-created" + for i in /dev/disk/by-id/ata-disk_disk[123]; do + udevadm info --query=property --name="$i" | grep -F 'ID_FS_UUID=' + done +} | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker +sync +poweroff -f diff --git a/test/TEST-13-ENC-RAID-LVM/cryptroot-ask.sh b/test/TEST-13-ENC-RAID-LVM/cryptroot-ask.sh new file mode 100755 index 0000000..a6b7ac7 --- /dev/null +++ b/test/TEST-13-ENC-RAID-LVM/cryptroot-ask.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +[ -b /dev/mapper/"$2" ] && exit 0 +printf test > /keyfile +/sbin/cryptsetup luksOpen "$1" "$2" < /keyfile diff --git a/test/TEST-13-ENC-RAID-LVM/finished-false.sh b/test/TEST-13-ENC-RAID-LVM/finished-false.sh new file mode 100755 index 0000000..ecdbef9 --- /dev/null +++ b/test/TEST-13-ENC-RAID-LVM/finished-false.sh @@ -0,0 +1,2 @@ +#!/bin/sh +exit 1 diff --git a/test/TEST-13-ENC-RAID-LVM/hard-off.sh b/test/TEST-13-ENC-RAID-LVM/hard-off.sh new file mode 100755 index 0000000..01acb19 --- /dev/null +++ b/test/TEST-13-ENC-RAID-LVM/hard-off.sh @@ -0,0 +1,3 @@ +#!/bin/sh +getargbool 0 rd.shell || poweroff -f +getargbool 0 failme && poweroff -f diff --git a/test/TEST-13-ENC-RAID-LVM/test-init.sh b/test/TEST-13-ENC-RAID-LVM/test-init.sh new file mode 100755 index 0000000..a5360ef --- /dev/null +++ b/test/TEST-13-ENC-RAID-LVM/test-init.sh @@ -0,0 +1,27 @@ +#!/bin/sh +: > /dev/watchdog + +. /lib/dracut-lib.sh + +export PATH=/usr/sbin:/usr/bin:/sbin:/bin +command -v plymouth > /dev/null 2>&1 && plymouth --quit +exec > /dev/console 2>&1 + +echo "dracut-root-block-success" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker + +export TERM=linux +export PS1='initramfs-test:\w\$ ' +[ -f /etc/mtab ] || ln -sfn /proc/mounts /etc/mtab +[ -f /etc/fstab ] || ln -sfn /proc/mounts /etc/fstab +stty sane +echo "made it to the rootfs!" +if getargbool 0 rd.shell; then + strstr "$(setsid --help)" "control" && CTTY="-c" + setsid $CTTY sh -i +fi +echo "Powering down." +mount -n -o remount,ro / +if [ -d /run/initramfs/etc ]; then + echo " rd.debug=0 " >> /run/initramfs/etc/cmdline +fi +poweroff -f diff --git a/test/TEST-13-ENC-RAID-LVM/test.sh b/test/TEST-13-ENC-RAID-LVM/test.sh new file mode 100755 index 0000000..fe79223 --- /dev/null +++ b/test/TEST-13-ENC-RAID-LVM/test.sh @@ -0,0 +1,158 @@ +#!/bin/bash +# shellcheck disable=SC2034 +TEST_DESCRIPTION="root filesystem on LVM on encrypted partitions of a RAID-5" + +# Uncomment this to debug failures +#DEBUGFAIL="rd.shell rd.break" # udev.log-priority=debug +#DEBUGFAIL="rd.shell rd.udev.log-priority=debug loglevel=70 systemd.log_target=kmsg systemd.log_target=debug" +#DEBUGFAIL="rd.shell loglevel=70 systemd.log_target=kmsg systemd.log_target=debug" + +test_run() { + LUKSARGS=$(cat "$TESTDIR"/luks.txt) + + echo "CLIENT TEST START: $LUKSARGS" + + declare -a disk_args=() + # shellcheck disable=SC2034 + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker + qemu_add_drive_args disk_index disk_args "$TESTDIR"/disk-1.img disk1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/disk-2.img disk2 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/disk-3.img disk3 + + test_marker_reset + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "panic=1 oops=panic softlockup_panic=1 systemd.crash_reboot root=/dev/dracut/root rw rd.auto rd.retry=20 console=ttyS0,115200n81 selinux=0 rd.debug rootwait $LUKSARGS rd.shell=0 $DEBUGFAIL" \ + -initrd "$TESTDIR"/initramfs.testing + test_marker_check || return 1 + echo "CLIENT TEST END: [OK]" + + test_marker_reset + + echo "CLIENT TEST START: Any LUKS" + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "panic=1 oops=panic softlockup_panic=1 systemd.crash_reboot root=/dev/dracut/root rw quiet rd.auto rd.retry=20 rd.info console=ttyS0,115200n81 selinux=0 rd.debug $DEBUGFAIL" \ + -initrd "$TESTDIR"/initramfs.testing + test_marker_check || return 1 + echo "CLIENT TEST END: [OK]" + + test_marker_reset + + echo "CLIENT TEST START: Wrong LUKS UUID" + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "panic=1 oops=panic softlockup_panic=1 systemd.crash_reboot root=/dev/dracut/root rw quiet rd.auto rd.retry=10 rd.info console=ttyS0,115200n81 selinux=0 rd.debug $DEBUGFAIL rd.luks.uuid=failme" \ + -initrd "$TESTDIR"/initramfs.testing + test_marker_check && return 1 + echo "CLIENT TEST END: [OK]" + + return 0 +} + +test_setup() { + kernel=$KVERSION + # Create what will eventually be our root filesystem onto an overlay + ( + # shellcheck disable=SC2030 + export initdir=$TESTDIR/overlay/source + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + ( + cd "$initdir" || exit + mkdir -p -- dev sys proc etc var/run tmp + mkdir -p root usr/bin usr/lib usr/lib64 usr/sbin + ) + inst_multiple sh df free ls shutdown poweroff stty cat ps ln \ + mount dmesg mkdir cp dd + for _terminfodir in /lib/terminfo /etc/terminfo /usr/share/terminfo; do + [ -f ${_terminfodir}/l/linux ] && break + done + inst_multiple -o ${_terminfodir}/l/linux + + inst_simple "${PKGLIBDIR}/modules.d/99base/dracut-lib.sh" "/lib/dracut-lib.sh" + inst_simple "${PKGLIBDIR}/modules.d/99base/dracut-dev-lib.sh" "/lib/dracut-dev-lib.sh" + inst_binary "${PKGLIBDIR}/dracut-util" "/usr/bin/dracut-util" + ln -s dracut-util "${initdir}/usr/bin/dracut-getarg" + ln -s dracut-util "${initdir}/usr/bin/dracut-getargs" + + inst_multiple grep + inst_simple /etc/os-release + inst ./test-init.sh /sbin/init + find_binary plymouth > /dev/null && inst_multiple plymouth + cp -a /etc/ld.so.conf* "$initdir"/etc + ldconfig -r "$initdir" + ) + + # second, install the files needed to make the root filesystem + ( + # shellcheck disable=SC2031 + # shellcheck disable=SC2030 + export initdir=$TESTDIR/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + inst_multiple sfdisk mkfs.ext4 poweroff cp umount grep dd sync + inst_hook initqueue 01 ./create-root.sh + inst_hook initqueue/finished 01 ./finished-false.sh + ) + + # create an initramfs that will create the target root filesystem. + # We do it this way so that we do not risk trashing the host mdraid + # devices, volume groups, encrypted partitions, etc. + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -m "bash crypt lvm mdraid kernel-modules qemu" \ + -d "piix ide-gd_mod ata_piix ext4 sd_mod" \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.makeroot "$KVERSION" || return 1 + rm -rf -- "$TESTDIR"/overlay + + # Create the blank files to use as a root filesystem + declare -a disk_args=() + # shellcheck disable=SC2034 + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker 1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/disk-1.img disk1 40 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/disk-2.img disk2 40 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/disk-3.img disk3 40 + + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "root=/dev/fakeroot rw rootfstype=ext4 quiet console=ttyS0,115200n81 selinux=0" \ + -initrd "$TESTDIR"/initramfs.makeroot || return 1 + test_marker_check dracut-root-block-created || return 1 + cryptoUUIDS=$(grep -F --binary-files=text -m 3 ID_FS_UUID "$TESTDIR"/marker.img) + for uuid in $cryptoUUIDS; do + eval "$uuid" + printf ' rd.luks.uuid=luks-%s ' "$ID_FS_UUID" + done > "$TESTDIR"/luks.txt + + ( + # shellcheck disable=SC2031 + export initdir=$TESTDIR/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + inst_multiple poweroff shutdown dd + inst_hook shutdown-emergency 000 ./hard-off.sh + inst_hook emergency 000 ./hard-off.sh + inst ./cryptroot-ask.sh /sbin/cryptroot-ask + mkdir -p "$initdir"/etc + i=1 + for uuid in $cryptoUUIDS; do + eval "$uuid" + printf 'luks-%s /dev/disk/by-id/ata-disk_disk%s /etc/key timeout=0\n' "$ID_FS_UUID" $i + ((i += 1)) + done > "$initdir"/etc/crypttab + echo -n test > "$initdir"/etc/key + chmod 0600 "$initdir"/etc/key + ) + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -o "plymouth network kernel-network-modules" \ + -a "debug" \ + -d "piix ide-gd_mod ata_piix ext4 sd_mod" \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.testing "$KVERSION" || return 1 +} + +# shellcheck disable=SC1090 +. "$testdir"/test-functions diff --git a/test/TEST-14-IMSM/Makefile b/test/TEST-14-IMSM/Makefile new file mode 100644 index 0000000..2dcab81 --- /dev/null +++ b/test/TEST-14-IMSM/Makefile @@ -0,0 +1 @@ +-include ../Makefile.testdir diff --git a/test/TEST-14-IMSM/create-root.sh b/test/TEST-14-IMSM/create-root.sh new file mode 100755 index 0000000..97d29d9 --- /dev/null +++ b/test/TEST-14-IMSM/create-root.sh @@ -0,0 +1,78 @@ +#!/bin/sh + +trap 'poweroff -f' EXIT + +# don't let udev and this script step on eachother's toes +for x in 61-dmraid-imsm.rules 64-md-raid.rules 65-md-incremental-imsm.rules 65-md-incremental.rules 64-lvm.rules 70-mdadm.rules 99-mount-rules; do + rm -f -- "/etc/udev/rules.d/$x" +done +rm -f -- /etc/lvm/lvm.conf + +udevadm control --reload +udevadm settle + +# dmraid does not want symlinks in --disk "..." +echo y | dmraid -f isw -C Test0 --type 1 --disk "$(realpath /dev/disk/by-id/ata-disk_disk1) $(realpath /dev/disk/by-id/ata-disk_disk2)" +udevadm settle + +SETS=$(dmraid -c -s) +# scan and activate all DM RAIDS +for s in $SETS; do + dmraid -ay -i -p --rm_partitions "$s" + [ -e "/dev/mapper/$s" ] && kpartx -a -p p "/dev/mapper/$s" +done + +udevadm settle +sleep 1 +udevadm settle + +sfdisk -g /dev/mapper/isw*Test0 +sfdisk --no-reread /dev/mapper/isw*Test0 << EOF +,4M +,28M +,28M +,28M +EOF + +set -x + +udevadm settle +dmraid -a n +udevadm settle + +SETS=$(dmraid -c -s -i) +# scan and activate all DM RAIDS +for s in $SETS; do + dmraid -ay -i -p --rm_partitions "$s" + [ -e "/dev/mapper/$s" ] && kpartx -a -p p "/dev/mapper/$s" +done + +udevadm settle + +mdadm --create /dev/md0 --run --auto=yes --level=5 --raid-devices=3 \ + /dev/mapper/isw*p*[234] +# wait for the array to finish initializing, otherwise this sometimes fails +# randomly. +mdadm -W /dev/md0 +set -e +lvm pvcreate -ff -y /dev/md0 +lvm vgcreate dracut /dev/md0 +lvm lvcreate -l 100%FREE -n root dracut +lvm vgchange -ay +mkfs.ext4 -L root /dev/dracut/root +mkdir -p /sysroot +mount -t ext4 /dev/dracut/root /sysroot +cp -a -t /sysroot /source/* +umount /sysroot +lvm lvchange -a n /dev/dracut/root +udevadm settle +mdadm --detail --export /dev/md0 | grep -F MD_UUID > /tmp/mduuid +. /tmp/mduuid +echo "MD_UUID=$MD_UUID" +{ + echo "dracut-root-block-created" + echo MD_UUID="$MD_UUID" +} | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker +mdadm --wait-clean /dev/md0 +sync +poweroff -f diff --git a/test/TEST-14-IMSM/cryptroot-ask.sh b/test/TEST-14-IMSM/cryptroot-ask.sh new file mode 100755 index 0000000..a6b7ac7 --- /dev/null +++ b/test/TEST-14-IMSM/cryptroot-ask.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +[ -b /dev/mapper/"$2" ] && exit 0 +printf test > /keyfile +/sbin/cryptsetup luksOpen "$1" "$2" < /keyfile diff --git a/test/TEST-14-IMSM/hard-off.sh b/test/TEST-14-IMSM/hard-off.sh new file mode 100755 index 0000000..01acb19 --- /dev/null +++ b/test/TEST-14-IMSM/hard-off.sh @@ -0,0 +1,3 @@ +#!/bin/sh +getargbool 0 rd.shell || poweroff -f +getargbool 0 failme && poweroff -f diff --git a/test/TEST-14-IMSM/test-init.sh b/test/TEST-14-IMSM/test-init.sh new file mode 100755 index 0000000..a5360ef --- /dev/null +++ b/test/TEST-14-IMSM/test-init.sh @@ -0,0 +1,27 @@ +#!/bin/sh +: > /dev/watchdog + +. /lib/dracut-lib.sh + +export PATH=/usr/sbin:/usr/bin:/sbin:/bin +command -v plymouth > /dev/null 2>&1 && plymouth --quit +exec > /dev/console 2>&1 + +echo "dracut-root-block-success" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker + +export TERM=linux +export PS1='initramfs-test:\w\$ ' +[ -f /etc/mtab ] || ln -sfn /proc/mounts /etc/mtab +[ -f /etc/fstab ] || ln -sfn /proc/mounts /etc/fstab +stty sane +echo "made it to the rootfs!" +if getargbool 0 rd.shell; then + strstr "$(setsid --help)" "control" && CTTY="-c" + setsid $CTTY sh -i +fi +echo "Powering down." +mount -n -o remount,ro / +if [ -d /run/initramfs/etc ]; then + echo " rd.debug=0 " >> /run/initramfs/etc/cmdline +fi +poweroff -f diff --git a/test/TEST-14-IMSM/test.sh b/test/TEST-14-IMSM/test.sh new file mode 100755 index 0000000..06959cd --- /dev/null +++ b/test/TEST-14-IMSM/test.sh @@ -0,0 +1,148 @@ +#!/bin/bash +# shellcheck disable=SC2034 +TEST_DESCRIPTION="root filesystem on LVM PV on a isw dmraid" + +# Uncomment this to debug failures +#DEBUGFAIL="rd.shell" +#DEBUGFAIL="$DEBUGFAIL udev.log-priority=debug" + +client_run() { + echo "CLIENT TEST START: $*" + + declare -a disk_args=() + # shellcheck disable=SC2034 + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker + qemu_add_drive_args disk_index disk_args "$TESTDIR"/disk-1.img disk1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/disk-2.img disk2 + + test_marker_reset + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "panic=1 oops=panic softlockup_panic=1 systemd.crash_reboot $* root=LABEL=root rw debug rd.retry=5 rd.debug console=ttyS0,115200n81 selinux=0 rd.info rd.shell=0 $DEBUGFAIL" \ + -initrd "$TESTDIR"/initramfs.testing || return 1 + + if ! test_marker_check; then + echo "CLIENT TEST END: $* [FAIL]" + return 1 + fi + + echo "CLIENT TEST END: $* [OK]" + return 0 +} + +test_run() { + read -r MD_UUID < "$TESTDIR"/mduuid + if [[ -z $MD_UUID ]]; then + echo "Setup failed" + return 1 + fi + + client_run rd.auto rd.md.imsm=0 || return 1 + client_run rd.md.uuid="$MD_UUID" rd.dm=0 || return 1 + # This test succeeds, because the mirror parts are found without + # assembling the mirror itself, which is what we want + client_run rd.md.uuid="$MD_UUID" rd.md=0 rd.md.imsm failme && return 1 + client_run rd.md.uuid="$MD_UUID" rd.md=0 failme && return 1 + # the following test hangs on newer md + client_run rd.md.uuid="$MD_UUID" rd.dm=0 rd.md.imsm rd.md.conf=0 || return 1 + return 0 +} + +test_setup() { + kernel=$KVERSION + # Create what will eventually be our root filesystem onto an overlay + ( + # shellcheck disable=SC2030 + export initdir=$TESTDIR/overlay/source + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + ( + cd "$initdir" || exit + mkdir -p -- dev sys proc etc var/run tmp + mkdir -p root usr/bin usr/lib usr/lib64 usr/sbin + ) + inst_multiple sh df free ls shutdown poweroff stty cat ps ln \ + mount dmesg mkdir cp dd sync + for _terminfodir in /lib/terminfo /etc/terminfo /usr/share/terminfo; do + [ -f ${_terminfodir}/l/linux ] && break + done + inst_multiple -o ${_terminfodir}/l/linux + inst_simple /etc/os-release + + inst_simple "${PKGLIBDIR}/modules.d/99base/dracut-lib.sh" "/lib/dracut-lib.sh" + inst_simple "${PKGLIBDIR}/modules.d/99base/dracut-dev-lib.sh" "/lib/dracut-dev-lib.sh" + inst_binary "${PKGLIBDIR}/dracut-util" "/usr/bin/dracut-util" + ln -s dracut-util "${initdir}/usr/bin/dracut-getarg" + ln -s dracut-util "${initdir}/usr/bin/dracut-getargs" + + inst_multiple grep + inst ./test-init.sh /sbin/init + find_binary plymouth > /dev/null && inst_multiple plymouth + cp -a /etc/ld.so.conf* "$initdir"/etc + mkdir -p "$initdir"/run + ldconfig -r "$initdir" + ) + + # second, install the files needed to make the root filesystem + ( + # shellcheck disable=SC2030 + # shellcheck disable=SC2031 + export initdir=$TESTDIR/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + inst_multiple sfdisk mkfs.ext4 poweroff cp umount grep dd sync realpath + inst_hook initqueue 01 ./create-root.sh + ) + + # create an initramfs that will create the target root filesystem. + # We do it this way so that we do not risk trashing the host mdraid + # devices, volume groups, encrypted partitions, etc. + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -m "bash lvm mdraid dmraid kernel-modules qemu" \ + -d "piix ide-gd_mod ata_piix ext4 sd_mod dm-multipath dm-crypt dm-round-robin faulty linear multipath raid0 raid10 raid1 raid456" \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.makeroot "$KVERSION" || return 1 + rm -rf -- "$TESTDIR"/overlay + + # Create the blank files to use as a root filesystem + declare -a disk_args=() + # shellcheck disable=SC2034 + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker 1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/disk-1.img disk1 100 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/disk-2.img disk2 100 + + # Invoke KVM and/or QEMU to actually create the target filesystem. + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "root=/dev/dracut/root rw rootfstype=ext4 quiet console=ttyS0,115200n81 selinux=0" \ + -initrd "$TESTDIR"/initramfs.makeroot || return 1 + test_marker_check dracut-root-block-created || return 1 + eval "$(grep -F --binary-files=text -m 1 MD_UUID "$TESTDIR"/marker.img)" + + if [[ -z $MD_UUID ]]; then + echo "Setup failed" + return 1 + fi + + echo "$MD_UUID" > "$TESTDIR"/mduuid + ( + # shellcheck disable=SC2031 + export initdir=$TESTDIR/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + inst_multiple poweroff shutdown + inst_hook shutdown-emergency 000 ./hard-off.sh + inst_hook emergency 000 ./hard-off.sh + ) + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -o "plymouth network kernel-network-modules" \ + -a "debug" \ + -d "piix ide-gd_mod ata_piix ext4 sd_mod" \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.testing "$KVERSION" || return 1 +} + +# shellcheck disable=SC1090 +. "$testdir"/test-functions diff --git a/test/TEST-15-BTRFSRAID/Makefile b/test/TEST-15-BTRFSRAID/Makefile new file mode 100644 index 0000000..2dcab81 --- /dev/null +++ b/test/TEST-15-BTRFSRAID/Makefile @@ -0,0 +1 @@ +-include ../Makefile.testdir diff --git a/test/TEST-15-BTRFSRAID/create-root.sh b/test/TEST-15-BTRFSRAID/create-root.sh new file mode 100755 index 0000000..075deac --- /dev/null +++ b/test/TEST-15-BTRFSRAID/create-root.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +trap 'poweroff -f' EXIT + +# don't let udev and this script step on eachother's toes +for x in 64-lvm.rules 70-mdadm.rules 99-mount-rules; do + : > "/etc/udev/rules.d/$x" +done +modprobe btrfs || : +udevadm control --reload +udevadm settle + +set -e + +mkfs.btrfs -draid10 -mraid10 -L root /dev/disk/by-id/ata-disk_raid[1234] +udevadm settle + +btrfs device scan +udevadm settle + +mkdir -p /sysroot +mount -t btrfs /dev/disk/by-id/ata-disk_raid4 /sysroot +cp -a -t /sysroot /source/* +umount /sysroot + +echo "dracut-root-block-created" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker +sync +poweroff -f diff --git a/test/TEST-15-BTRFSRAID/finished-false.sh b/test/TEST-15-BTRFSRAID/finished-false.sh new file mode 100755 index 0000000..ecdbef9 --- /dev/null +++ b/test/TEST-15-BTRFSRAID/finished-false.sh @@ -0,0 +1,2 @@ +#!/bin/sh +exit 1 diff --git a/test/TEST-15-BTRFSRAID/hard-off.sh b/test/TEST-15-BTRFSRAID/hard-off.sh new file mode 100755 index 0000000..01acb19 --- /dev/null +++ b/test/TEST-15-BTRFSRAID/hard-off.sh @@ -0,0 +1,3 @@ +#!/bin/sh +getargbool 0 rd.shell || poweroff -f +getargbool 0 failme && poweroff -f diff --git a/test/TEST-15-BTRFSRAID/test-init.sh b/test/TEST-15-BTRFSRAID/test-init.sh new file mode 100755 index 0000000..068e8f3 --- /dev/null +++ b/test/TEST-15-BTRFSRAID/test-init.sh @@ -0,0 +1,25 @@ +#!/bin/sh +: > /dev/watchdog + +. /lib/dracut-lib.sh + +export PATH=/usr/sbin:/usr/bin:/sbin:/bin +command -v plymouth > /dev/null 2>&1 && plymouth --quit +exec > /dev/console 2>&1 + +echo "dracut-root-block-success" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker + +export TERM=linux +export PS1='initramfs-test:\w\$ ' +[ -f /etc/mtab ] || ln -sfn /proc/mounts /etc/mtab +[ -f /etc/fstab ] || ln -sfn /proc/mounts /etc/fstab +stty sane +echo "made it to the rootfs!" +if getargbool 0 rd.shell; then + strstr "$(setsid --help)" "control" && CTTY="-c" + setsid $CTTY sh -i +fi +echo "Powering down." +mount -n -o remount,ro / + +poweroff -f diff --git a/test/TEST-15-BTRFSRAID/test.sh b/test/TEST-15-BTRFSRAID/test.sh new file mode 100755 index 0000000..068146e --- /dev/null +++ b/test/TEST-15-BTRFSRAID/test.sh @@ -0,0 +1,123 @@ +#!/bin/bash +# shellcheck disable=SC2034 +TEST_DESCRIPTION="root filesystem on multiple device btrfs" + +# Uncomment this to debug failures +#DEBUGFAIL="rd.shell" +test_run() { + declare -a disk_args=() + # shellcheck disable=SC2034 + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid-1.img raid1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid-2.img raid2 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid-3.img raid3 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid-4.img raid4 + + test_marker_reset + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "panic=1 oops=panic softlockup_panic=1 systemd.crash_reboot root=LABEL=root rw rd.retry=3 rd.info console=ttyS0,115200n81 selinux=0 rd.shell=0 $DEBUGFAIL" \ + -initrd "$TESTDIR"/initramfs.testing + test_marker_check || return 1 +} + +test_setup() { + # Create the blank file to use as a root filesystem + DISKIMAGE=$TESTDIR/TEST-15-BTRFSRAID-root.img + rm -f -- "$DISKIMAGE" + dd if=/dev/zero of="$DISKIMAGE" bs=1M count=1024 + + kernel=$KVERSION + # Create what will eventually be our root filesystem onto an overlay + ( + # shellcheck disable=SC2030 + export initdir=$TESTDIR/overlay/source + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + ( + cd "$initdir" || exit + mkdir -p -- dev sys proc etc var/run tmp + mkdir -p root usr/bin usr/lib usr/lib64 usr/sbin + ) + inst_multiple sh df free ls shutdown poweroff stty cat ps ln \ + mount dmesg mkdir cp sync dd + for _terminfodir in /lib/terminfo /etc/terminfo /usr/share/terminfo; do + [ -f ${_terminfodir}/l/linux ] && break + done + inst_multiple -o ${_terminfodir}/l/linux + + inst_simple "${PKGLIBDIR}/modules.d/99base/dracut-lib.sh" "/lib/dracut-lib.sh" + inst_simple "${PKGLIBDIR}/modules.d/99base/dracut-dev-lib.sh" "/lib/dracut-dev-lib.sh" + inst_binary "${PKGLIBDIR}/dracut-util" "/usr/bin/dracut-util" + ln -s dracut-util "${initdir}/usr/bin/dracut-getarg" + ln -s dracut-util "${initdir}/usr/bin/dracut-getargs" + + inst_multiple grep + inst ./test-init.sh /sbin/init + inst_simple /etc/os-release + find_binary plymouth > /dev/null && inst_multiple plymouth + cp -a /etc/ld.so.conf* "$initdir"/etc + ldconfig -r "$initdir" + ) + + # second, install the files needed to make the root filesystem + ( + # shellcheck disable=SC2031 + # shellcheck disable=SC2030 + export initdir=$TESTDIR/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + inst_multiple sfdisk mkfs.btrfs poweroff cp umount dd sync + inst_hook initqueue 01 ./create-root.sh + inst_hook initqueue/finished 01 ./finished-false.sh + ) + + # create an initramfs that will create the target root filesystem. + # We do it this way so that we do not risk trashing the host mdraid + # devices, volume groups, encrypted partitions, etc. + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -m "bash btrfs rootfs-block kernel-modules qemu" \ + -d "piix ide-gd_mod ata_piix btrfs sd_mod" \ + --nomdadmconf \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.makeroot "$KVERSION" || return 1 + + rm -rf -- "$TESTDIR"/overlay + + # Create the blank files to use as a root filesystem + declare -a disk_args=() + # shellcheck disable=SC2034 + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker 1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid-1.img raid1 150 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid-2.img raid2 150 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid-3.img raid3 150 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid-4.img raid4 150 + + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "root=/dev/fakeroot rw quiet console=ttyS0,115200n81 selinux=0" \ + -initrd "$TESTDIR"/initramfs.makeroot || return 1 + + test_marker_check dracut-root-block-created || return 1 + + ( + # shellcheck disable=SC2031 + export initdir=$TESTDIR/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + inst_multiple poweroff shutdown + inst_hook shutdown-emergency 000 ./hard-off.sh + inst_hook emergency 000 ./hard-off.sh + ) + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -o "plymouth network kernel-network-modules" \ + -a "debug" \ + -d "piix ide-gd_mod ata_piix btrfs sd_mod" \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.testing "$KVERSION" || return 1 +} + +# shellcheck disable=SC1090 +. "$testdir"/test-functions diff --git a/test/TEST-16-DMSQUASH/Makefile b/test/TEST-16-DMSQUASH/Makefile new file mode 100644 index 0000000..2dcab81 --- /dev/null +++ b/test/TEST-16-DMSQUASH/Makefile @@ -0,0 +1 @@ +-include ../Makefile.testdir diff --git a/test/TEST-16-DMSQUASH/create-root.sh b/test/TEST-16-DMSQUASH/create-root.sh new file mode 100755 index 0000000..f17b22f --- /dev/null +++ b/test/TEST-16-DMSQUASH/create-root.sh @@ -0,0 +1,41 @@ +#!/bin/sh + +trap 'poweroff -f' EXIT + +# don't let udev and this script step on eachother's toes +for x in 64-lvm.rules 70-mdadm.rules 99-mount-rules; do + : > "/etc/udev/rules.d/$x" +done +rm -f -- /etc/lvm/lvm.conf +udevadm control --reload +set -e + +udevadm settle + +# create a single partition using 50% of the capacity of the image file created by test_setup() in test.sh +sfdisk /dev/disk/by-id/ata-disk_root << EOF +2048,161792 +EOF + +udevadm settle + +mkfs.ext4 -q -L dracut /dev/disk/by-id/ata-disk_root-part1 +mkdir -p /root +mount -t ext4 /dev/disk/by-id/ata-disk_root-part1 /root +mkdir -p /root/run /root/testdir +cp -a -t /root /source/* +echo "Creating squashfs" +mksquashfs /source /root/testdir/rootfs.img -quiet + +# Copy rootfs.img to the NTFS drive if exists +if [ -e "/dev/disk/by-id/ata-disk_root_ntfs" ]; then + mkfs.ntfs -F -L dracut_ntfs /dev/disk/by-id/ata-disk_root_ntfs + mkdir -p /root_ntfs + mount -t ntfs3 /dev/disk/by-id/ata-disk_root_ntfs /root_ntfs + mkdir -p /root_ntfs/run /root_ntfs/testdir + cp /root/testdir/rootfs.img /root_ntfs/testdir/rootfs.img +fi + +umount /root +echo "dracut-root-block-created" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker +poweroff -f diff --git a/test/TEST-16-DMSQUASH/test-init.sh b/test/TEST-16-DMSQUASH/test-init.sh new file mode 100755 index 0000000..959fa25 --- /dev/null +++ b/test/TEST-16-DMSQUASH/test-init.sh @@ -0,0 +1,31 @@ +#!/bin/sh +: > /dev/watchdog + +. /lib/dracut-lib.sh + +export PATH=/usr/sbin:/usr/bin:/sbin:/bin +command -v plymouth > /dev/null 2>&1 && plymouth --quit +exec > /dev/console 2>&1 + +echo "dracut-root-block-success" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker + +if grep -qF ' rd.live.overlay=LABEL=persist ' /proc/cmdline; then + # Writing to a file in the root filesystem lets test_run() verify that the autooverlay module successfully created + # and formatted the overlay partition and that the dmsquash-live module used it when setting up the rootfs overlay. + echo "dracut-autooverlay-success" > /overlay-marker +fi + +export TERM=linux +export PS1='initramfs-test:\w\$ ' +[ -f /etc/mtab ] || ln -sfn /proc/mounts /etc/mtab +[ -f /etc/fstab ] || ln -sfn /proc/mounts /etc/fstab +stty sane +echo "made it to the rootfs!" +if getargbool 0 rd.shell; then + strstr "$(setsid --help)" "control" && CTTY="-c" + setsid $CTTY sh -i +fi +echo "Powering down." +mount -n -o remount,ro / + +poweroff -f diff --git a/test/TEST-16-DMSQUASH/test.sh b/test/TEST-16-DMSQUASH/test.sh new file mode 100755 index 0000000..3fecc92 --- /dev/null +++ b/test/TEST-16-DMSQUASH/test.sh @@ -0,0 +1,155 @@ +#!/bin/bash + +# shellcheck disable=SC2034 +TEST_DESCRIPTION="live root on a squash filesystem" + +# Uncomment these to debug failures +#DEBUGFAIL="rd.shell rd.debug rd.live.debug loglevel=7" + +test_run() { + declare -a disk_args=() + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker + qemu_add_drive_args disk_index disk_args "$TESTDIR"/root.img root + + # NTFS drive + if modprobe --dry-run ntfs3 &> /dev/null && command -v mkfs.ntfs &> /dev/null; then + qemu_add_drive_args disk_index disk_args "$TESTDIR"/root_ntfs.img root_ntfs + fi + + test_marker_reset + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -boot order=d \ + -append "rd.live.overlay.overlayfs=1 root=live:/dev/disk/by-label/dracut console=ttyS0,115200n81 quiet selinux=0 rd.info rd.shell=0 panic=1 oops=panic softlockup_panic=1 $DEBUGFAIL" \ + -initrd "$TESTDIR"/initramfs.testing + + test_marker_check || return 1 + + test_marker_reset + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -boot order=d \ + -append "rd.live.image rd.live.overlay.overlayfs=1 root=LABEL=dracut console=ttyS0,115200n81 quiet selinux=0 rd.info rd.shell=0 panic=1 oops=panic softlockup_panic=1 $DEBUGFAIL" \ + -initrd "$TESTDIR"/initramfs.testing + + test_marker_check || return 1 + + test_marker_reset + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -boot order=d \ + -append "rd.live.image rd.live.overlay.overlayfs=1 rd.live.dir=testdir root=LABEL=dracut console=ttyS0,115200n81 quiet selinux=0 rd.info rd.shell=0 panic=1 oops=panic softlockup_panic=1 $DEBUGFAIL" \ + -initrd "$TESTDIR"/initramfs.testing + + test_marker_check || return 1 + + # Run the NTFS test only if mkfs.ntfs is available + if modprobe --dry-run ntfs3 &> /dev/null && command -v mkfs.ntfs &> /dev/null; then + dd if=/dev/zero of="$TESTDIR"/marker.img bs=1MiB count=1 + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -boot order=d \ + -append "rd.live.image rd.live.overlay.overlayfs=1 rd.live.dir=testdir root=LABEL=dracut_ntfs console=ttyS0,115200n81 quiet selinux=0 rd.info rd.shell=0 panic=1 oops=panic softlockup_panic=1 $DEBUGFAIL" \ + -initrd "$TESTDIR"/initramfs.testing + + test_marker_check || return 1 + fi + + test_marker_reset + rootPartitions=$(sfdisk -d "$TESTDIR"/root.img | grep -c 'root\.img[0-9]') + [ "$rootPartitions" -eq 1 ] || return 1 + + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -boot order=d \ + -append "rd.live.image rd.live.overlay.overlayfs=1 rd.live.overlay=LABEL=persist rd.live.dir=testdir root=LABEL=dracut console=ttyS0,115200n81 quiet selinux=0 rd.info rd.shell=0 panic=1 oops=panic softlockup_panic=1 $DEBUGFAIL" \ + -initrd "$TESTDIR"/initramfs.testing-autooverlay + + rootPartitions=$(sfdisk -d "$TESTDIR"/root.img | grep -c 'root\.img[0-9]') + [ "$rootPartitions" -eq 2 ] || return 1 + + ( + # Ensure that this test works when run with the `V=1` parameter, which runs the script with `set -o pipefail`. + set +o pipefail + + # Verify that the string "dracut-autooverlay-success" occurs in the second partition in the image file. + dd if="$TESTDIR"/root.img bs=1MiB skip=80 status=none \ + | grep -U --binary-files=binary -F -m 1 -q dracut-autooverlay-success + ) || return 1 +} + +test_setup() { + # Create what will eventually be our root filesystem onto an overlay + "$DRACUT" -l --keep --tmpdir "$TESTDIR" \ + -m "test-root" \ + -i ./test-init.sh /sbin/init \ + -i "${PKGLIBDIR}/modules.d/99base/dracut-lib.sh" "/lib/dracut-lib.sh" \ + -i "${PKGLIBDIR}/modules.d/99base/dracut-dev-lib.sh" "/lib/dracut-dev-lib.sh" \ + --no-hostonly --no-hostonly-cmdline --nomdadmconf --nohardlink \ + -f "$TESTDIR"/initramfs.root "$KVERSION" || return 1 + mkdir -p "$TESTDIR"/overlay/source && mv "$TESTDIR"/dracut.*/initramfs/* "$TESTDIR"/overlay/source && rm -rf "$TESTDIR"/dracut.* + + # second, install the files needed to make the root filesystem + # create an initramfs that will create the target root filesystem. + # We do it this way so that we do not risk trashing the host mdraid + # devices, volume groups, encrypted partitions, etc. + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + --modules "test-makeroot" \ + --install "sfdisk mkfs.ext4 mkfs.ntfs mksquashfs" \ + --drivers "ntfs3" \ + --include ./create-root.sh /lib/dracut/hooks/initqueue/01-create-root.sh \ + --no-hostonly --no-hostonly-cmdline --no-early-microcode --nofscks --nomdadmconf --nohardlink --nostrip \ + --force "$TESTDIR"/initramfs.makeroot "$KVERSION" || return 1 + rm -rf -- "$TESTDIR"/overlay + + # Create the blank file to use as a root filesystem + declare -a disk_args=() + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker 1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/root.img root 160 + + # NTFS drive + if modprobe --dry-run ntfs3 &> /dev/null && command -v mkfs.ntfs &> /dev/null; then + dd if=/dev/zero of="$TESTDIR"/root_ntfs.img bs=1MiB count=160 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/root_ntfs.img root_ntfs + fi + + # Invoke KVM and/or QEMU to actually create the target filesystem. + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "root=/dev/dracut/root rw rootfstype=ext4 quiet console=ttyS0,115200n81 selinux=0" \ + -initrd "$TESTDIR"/initramfs.makeroot || return 1 + + if ! test_marker_check dracut-root-block-created; then + echo "Could not create root filesystem" + return 1 + fi + + # mount NTFS with ntfs3 driver inside the generated initramfs + cat > /tmp/ntfs3.rules << 'EOF' +SUBSYSTEM=="block", ENV{ID_FS_TYPE}=="ntfs", ENV{ID_FS_TYPE}="ntfs3" +EOF + + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + --modules "test dash dmsquash-live qemu" \ + --omit "rngd" \ + --drivers "ext4 ntfs3 sd_mod" \ + --install "mkfs.ext4" \ + --include /tmp/ntfs3.rules /lib/udev/rules.d/ntfs3.rules \ + --no-hostonly --no-hostonly-cmdline \ + --force "$TESTDIR"/initramfs.testing "$KVERSION" || return 1 + + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + --modules "test dmsquash-live-autooverlay qemu" \ + --omit "rngd" \ + --drivers "ext4 sd_mod" \ + --install "mkfs.ext4" \ + --no-hostonly --no-hostonly-cmdline \ + --force "$TESTDIR"/initramfs.testing-autooverlay "$KVERSION" || return 1 + + rm -rf -- "$TESTDIR"/overlay +} + +# shellcheck disable=SC1090 +. "$testdir"/test-functions diff --git a/test/TEST-17-LVM-THIN/Makefile b/test/TEST-17-LVM-THIN/Makefile new file mode 100644 index 0000000..2dcab81 --- /dev/null +++ b/test/TEST-17-LVM-THIN/Makefile @@ -0,0 +1 @@ +-include ../Makefile.testdir diff --git a/test/TEST-17-LVM-THIN/create-root.sh b/test/TEST-17-LVM-THIN/create-root.sh new file mode 100755 index 0000000..2547d1c --- /dev/null +++ b/test/TEST-17-LVM-THIN/create-root.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +trap 'poweroff -f' EXIT + +# don't let udev and this script step on eachother's toes +for x in 64-lvm.rules 70-mdadm.rules 99-mount-rules; do + : > "/etc/udev/rules.d/$x" +done +rm -f -- /etc/lvm/lvm.conf +udevadm control --reload +udevadm settle + +set -ex +for dev in /dev/disk/by-id/ata-disk_disk[123]; do + lvm pvcreate -ff -y "$dev" +done + +lvm vgcreate dracut /dev/disk/by-id/ata-disk_disk[123] +lvm lvcreate --ignoremonitoring -l 100%FREE -T dracut/mythinpool +lvm lvcreate --ignoremonitoring -V100M -T dracut/mythinpool -n root +lvm vgchange --ignoremonitoring -ay +mkfs.ext4 /dev/dracut/root +mkdir -p /sysroot +mount -t ext4 /dev/dracut/root /sysroot +cp -a -t /sysroot /source/* +umount /sysroot +lvm lvchange -a n /dev/dracut/root + +if ! dmsetup status | grep -q out_of_data_space; then + echo "dracut-root-block-created" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker +fi + +sync +poweroff -f diff --git a/test/TEST-17-LVM-THIN/finished-false.sh b/test/TEST-17-LVM-THIN/finished-false.sh new file mode 100755 index 0000000..ecdbef9 --- /dev/null +++ b/test/TEST-17-LVM-THIN/finished-false.sh @@ -0,0 +1,2 @@ +#!/bin/sh +exit 1 diff --git a/test/TEST-17-LVM-THIN/hard-off.sh b/test/TEST-17-LVM-THIN/hard-off.sh new file mode 100755 index 0000000..f4d19dc --- /dev/null +++ b/test/TEST-17-LVM-THIN/hard-off.sh @@ -0,0 +1,3 @@ +#!/bin/sh +getargbool 0 rd.shell || poweroff -f +getarg failme && poweroff -f diff --git a/test/TEST-17-LVM-THIN/test-init.sh b/test/TEST-17-LVM-THIN/test-init.sh new file mode 100755 index 0000000..108e626 --- /dev/null +++ b/test/TEST-17-LVM-THIN/test-init.sh @@ -0,0 +1,24 @@ +#!/bin/sh +: > /dev/watchdog + +. /lib/dracut-lib.sh + +export PATH=/usr/sbin:/usr/bin:/sbin:/bin +command -v plymouth > /dev/null 2>&1 && plymouth --quit +exec > /dev/console 2>&1 + +echo "dracut-root-block-success" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker + +export TERM=linux +export PS1='initramfs-test:\w\$ ' +[ -f /etc/mtab ] || ln -sfn /proc/mounts /etc/mtab +[ -f /etc/fstab ] || ln -sfn /proc/mounts /etc/fstab +stty sane +echo "made it to the rootfs!" +if getargbool 0 rd.shell; then + strstr "$(setsid --help)" "control" && CTTY="-c" + setsid $CTTY sh -i +fi +echo "Powering down." +mount -n -o remount,ro / +poweroff -f diff --git a/test/TEST-17-LVM-THIN/test.sh b/test/TEST-17-LVM-THIN/test.sh new file mode 100755 index 0000000..5010e48 --- /dev/null +++ b/test/TEST-17-LVM-THIN/test.sh @@ -0,0 +1,115 @@ +#!/bin/bash +# shellcheck disable=SC2034 +TEST_DESCRIPTION="root filesystem on LVM PV with thin pool" + +# Uncomment this to debug failures +#DEBUGFAIL="rd.break rd.shell" + +test_run() { + declare -a disk_args=() + # shellcheck disable=SC2034 + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker + qemu_add_drive_args disk_index disk_args "$TESTDIR"/disk-1.img disk1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/disk-2.img disk2 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/disk-3.img disk3 + + test_marker_reset + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "panic=1 oops=panic softlockup_panic=1 systemd.crash_reboot root=/dev/dracut/root rw rd.auto=1 quiet rd.retry=3 rd.info console=ttyS0,115200n81 selinux=0 rd.debug rd.shell=0 $DEBUGFAIL" \ + -initrd "$TESTDIR"/initramfs.testing || return 1 + test_marker_check || return 1 +} + +test_setup() { + kernel=$KVERSION + # Create what will eventually be our root filesystem onto an overlay + ( + # shellcheck disable=SC2030 + export initdir=$TESTDIR/overlay/source + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + ( + cd "$initdir" || exit + mkdir -p -- dev sys proc etc var/run tmp + mkdir -p root usr/bin usr/lib usr/lib64 usr/sbin + ) + inst_multiple sh df free ls shutdown poweroff stty cat ps ln \ + mount dmesg mkdir cp dd sync + for _terminfodir in /lib/terminfo /etc/terminfo /usr/share/terminfo; do + [ -f ${_terminfodir}/l/linux ] && break + done + inst_multiple -o ${_terminfodir}/l/linux + + inst_simple "${PKGLIBDIR}/modules.d/99base/dracut-lib.sh" "/lib/dracut-lib.sh" + inst_simple "${PKGLIBDIR}/modules.d/99base/dracut-dev-lib.sh" "/lib/dracut-dev-lib.sh" + inst_binary "${PKGLIBDIR}/dracut-util" "/usr/bin/dracut-util" + ln -s dracut-util "${initdir}/usr/bin/dracut-getarg" + ln -s dracut-util "${initdir}/usr/bin/dracut-getargs" + + inst_multiple grep + inst_simple /etc/os-release + inst ./test-init.sh /sbin/init + find_binary plymouth > /dev/null && inst_multiple plymouth + cp -a /etc/ld.so.conf* "$initdir"/etc + mkdir -p "$initdir"/run + ldconfig -r "$initdir" + ) + + # second, install the files needed to make the root filesystem + ( + # shellcheck disable=SC2030 + # shellcheck disable=SC2031 + export initdir=$TESTDIR/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + inst_multiple sfdisk mkfs.ext4 poweroff cp umount grep dmsetup dd sync + inst_hook initqueue 01 ./create-root.sh + inst_hook initqueue/finished 01 ./finished-false.sh + ) + + # create an initramfs that will create the target root filesystem. + # We do it this way so that we do not risk trashing the host mdraid + # devices, volume groups, encrypted partitions, etc. + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -m "bash lvm mdraid kernel-modules qemu" \ + -d "piix ide-gd_mod ata_piix ext4 sd_mod" \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.makeroot "$KVERSION" || return 1 + rm -rf -- "$TESTDIR"/overlay + + # Create the blank files to use as a root filesystem + declare -a disk_args=() + # shellcheck disable=SC2034 + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker 1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/disk-1.img disk1 40 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/disk-2.img disk2 40 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/disk-3.img disk3 40 + + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "root=/dev/fakeroot rw rootfstype=ext4 quiet console=ttyS0,115200n81 selinux=0" \ + -initrd "$TESTDIR"/initramfs.makeroot || return 1 + test_marker_check dracut-root-block-created || return 1 + + ( + # shellcheck disable=SC2031 + export initdir=$TESTDIR/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + inst_multiple poweroff shutdown + inst_hook shutdown-emergency 000 ./hard-off.sh + inst_hook emergency 000 ./hard-off.sh + ) + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -o "plymouth network kernel-network-modules" \ + -a "debug" -I lvs \ + -d "piix ide-gd_mod ata_piix ext4 sd_mod" \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.testing "$KVERSION" || return 1 +} + +# shellcheck disable=SC1090 +. "$testdir"/test-functions diff --git a/test/TEST-18-UEFI/Makefile b/test/TEST-18-UEFI/Makefile new file mode 100644 index 0000000..2dcab81 --- /dev/null +++ b/test/TEST-18-UEFI/Makefile @@ -0,0 +1 @@ +-include ../Makefile.testdir diff --git a/test/TEST-18-UEFI/test-init.sh b/test/TEST-18-UEFI/test-init.sh new file mode 100755 index 0000000..03966d2 --- /dev/null +++ b/test/TEST-18-UEFI/test-init.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +export PATH=/usr/sbin:/usr/bin:/sbin:/bin + +[ -e /proc/self/mounts ] \ + || (mkdir -p /proc && mount -t proc -o nosuid,noexec,nodev proc /proc) + +grep -q '^sysfs /sys sysfs' /proc/self/mounts \ + || (mkdir -p /sys && mount -t sysfs -o nosuid,noexec,nodev sysfs /sys) + +grep -q '^devtmpfs /dev devtmpfs' /proc/self/mounts \ + || (mkdir -p /dev && mount -t devtmpfs -o mode=755,noexec,nosuid,strictatime devtmpfs /dev) + +grep -q '^tmpfs /run tmpfs' /proc/self/mounts \ + || (mkdir -p /run && mount -t tmpfs -o mode=755,noexec,nosuid,strictatime tmpfs /run) + +: > /dev/watchdog + +exec > /dev/console 2>&1 + +echo "made it to the rootfs! Powering down." +echo "dracut-root-block-success" | dd oflag=direct,dsync of=/dev/sdb +poweroff -f diff --git a/test/TEST-18-UEFI/test.sh b/test/TEST-18-UEFI/test.sh new file mode 100755 index 0000000..4191fed --- /dev/null +++ b/test/TEST-18-UEFI/test.sh @@ -0,0 +1,92 @@ +#!/bin/bash + +# shellcheck disable=SC2034 +TEST_DESCRIPTION="UEFI boot" + +# Linux kernel requirements +# CONFIG_BLK_DEV_INITRD for initramfs +# CONFIG_EFI_HANDOVER_PROTOCOL for ovmf (Open Virtual Machine Firmware) +# CONFIG_SATA_AHCI for ahci.ko +# CONFIG_BLK_DEV_SD for sd_mod.ko +# CONFIG_SQUASHFS_ZLIB for squashfs.ko + +ovmf_code() { + for path in \ + "/usr/share/OVMF/OVMF_CODE.fd" \ + "/usr/share/edk2/x64/OVMF_CODE.fd" \ + "/usr/share/edk2-ovmf/OVMF_CODE.fd" \ + "/usr/share/qemu/ovmf-x86_64-4m.bin"; do + [[ -s $path ]] && echo -n "$path" && return + done +} + +test_check() { + [[ -n "$(ovmf_code)" ]] +} + +KVERSION="${KVERSION-$(uname -r)}" + +test_marker_reset() { + dd if=/dev/zero of="$TESTDIR"/marker.img bs=1MiB count=1 +} + +test_marker_check() { + grep -U --binary-files=binary -F -m 1 -q dracut-root-block-success -- "$TESTDIR"/marker.img + return $? +} + +test_dracut() { + TEST_DRACUT_ARGS+=" --local --no-hostonly --no-early-microcode --add test --kver $KVERSION" + + # shellcheck disable=SC2162 + IFS=' ' read -a TEST_DRACUT_ARGS_ARRAY <<< "$TEST_DRACUT_ARGS" + + "$DRACUT" "$@" \ + --kernel-cmdline "panic=1 oops=panic softlockup_panic=1 systemd.crash_reboot selinux=0 console=ttyS0,115200n81 $DEBUGFAIL" \ + "${TEST_DRACUT_ARGS_ARRAY[@]}" || return 1 +} + +test_run() { + declare -a disk_args=() + declare -i disk_index=1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker + qemu_add_drive_args disk_index disk_args "$TESTDIR"/squashfs.img root + + test_marker_reset + "$testdir"/run-qemu "${disk_args[@]}" -net none \ + -drive file=fat:rw:"$TESTDIR"/ESP,format=vvfat,label=EFI \ + -global driver=cfi.pflash01,property=secure,value=on \ + -drive if=pflash,format=raw,unit=0,file="$(ovmf_code)",readonly=on + test_marker_check || return 1 +} + +test_setup() { + # Create what will eventually be our root filesystem + "$DRACUT" --local --no-hostonly --no-early-microcode --nofscks \ + --tmpdir "$TESTDIR" --keep --modules "test-root" --include ./test-init.sh /sbin/init \ + "$TESTDIR"/tmp-initramfs.root "$KVERSION" || return 1 + + mkdir -p "$TESTDIR"/dracut.*/initramfs/proc + mksquashfs "$TESTDIR"/dracut.*/initramfs/ "$TESTDIR"/squashfs.img -quiet -no-progress + + mkdir -p "$TESTDIR"/ESP/EFI/BOOT + + if [ -f "/usr/lib/gummiboot/linuxx64.efi.stub" ]; then + TEST_DRACUT_ARGS+=" --uefi-stub /usr/lib/gummiboot/linuxx64.efi.stub " + fi + + mkdir -p "$TESTDIR"/ESP/EFI/BOOT + test_dracut \ + --modules 'rootfs-block test' \ + --kernel-cmdline 'root=/dev/sdc ro rd.skipfsck rootfstype=squashfs' \ + --drivers 'ahci sd_mod squashfs' \ + --uefi \ + "$TESTDIR"/ESP/EFI/BOOT/BOOTX64.efi +} + +test_cleanup() { + return 0 +} + +# shellcheck disable=SC1090 +. "$testdir"/test-functions diff --git a/test/TEST-20-NFS/Makefile b/test/TEST-20-NFS/Makefile new file mode 100644 index 0000000..2dcab81 --- /dev/null +++ b/test/TEST-20-NFS/Makefile @@ -0,0 +1 @@ +-include ../Makefile.testdir diff --git a/test/TEST-20-NFS/client-init.sh b/test/TEST-20-NFS/client-init.sh new file mode 100755 index 0000000..061a2b1 --- /dev/null +++ b/test/TEST-20-NFS/client-init.sh @@ -0,0 +1,49 @@ +#!/bin/sh +: > /dev/watchdog +. /lib/dracut-lib.sh +. /lib/url-lib.sh + +export PATH=/usr/sbin:/usr/bin:/sbin:/bin +command -v plymouth > /dev/null 2>&1 && plymouth --quit +exec > /dev/console 2>&1 + +export TERM=linux +export PS1='initramfs-test:\w\$ ' +stty sane +if getargbool 0 rd.shell; then + [ -c /dev/watchdog ] && printf 'V' > /dev/watchdog + strstr "$(setsid --help)" "control" && CTTY="-c" + setsid $CTTY sh -i +fi + +echo "made it to the rootfs! Powering down." + +while read -r dev _ fstype opts rest || [ -n "$dev" ]; do + [ "$fstype" != "nfs" -a "$fstype" != "nfs4" ] && continue + echo "nfs-OK $dev $fstype $opts" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker + break +done < /proc/mounts + +if [ "$fstype" = "nfs" -o "$fstype" = "nfs4" ]; then + + serverip=${dev%:*} + path=${dev#*:} + echo serverip="${serverip}" + echo path="${path}" + echo /proc/mounts status + cat /proc/mounts + + echo test:nfs_fetch_url nfs::"${serverip}":"${path}"/root/fetchfile + if nfs_fetch_url nfs::"${serverip}":"${path}"/root/fetchfile /run/nfsfetch.out; then + echo nfsfetch-OK + echo "nfsfetch-OK" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker2 + fi +else + echo nfsfetch-BYPASS fstype="${fstype}" + echo "nfsfetch-OK" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker2 +fi + +: > /dev/watchdog + +sync +poweroff -f diff --git a/test/TEST-20-NFS/client.link b/test/TEST-20-NFS/client.link new file mode 100644 index 0000000..b992bfd --- /dev/null +++ b/test/TEST-20-NFS/client.link @@ -0,0 +1,6 @@ +[Match] +OriginalName=* + +[Link] +NamePolicy=keep kernel database onboard slot path +MACAddressPolicy=keep diff --git a/test/TEST-20-NFS/create-root.sh b/test/TEST-20-NFS/create-root.sh new file mode 100755 index 0000000..8060b00 --- /dev/null +++ b/test/TEST-20-NFS/create-root.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +trap 'poweroff -f' EXIT + +# don't let udev and this script step on eachother's toes +for x in 64-lvm.rules 70-mdadm.rules 99-mount-rules; do + : > "/etc/udev/rules.d/$x" +done +rm -f -- /etc/lvm/lvm.conf +udevadm control --reload +udevadm settle + +set -ex + +mkfs.ext4 -L dracut /dev/disk/by-id/ata-disk_root +mkdir -p /root +mount -t ext4 /dev/disk/by-id/ata-disk_root /root +cp -a -t /root /source/* +mkdir -p /root/run +umount /root +echo "dracut-root-block-created" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker +sync +poweroff -f diff --git a/test/TEST-20-NFS/dhcpd.conf b/test/TEST-20-NFS/dhcpd.conf new file mode 100644 index 0000000..02fcc4d --- /dev/null +++ b/test/TEST-20-NFS/dhcpd.conf @@ -0,0 +1,177 @@ +ddns-update-style none; + +use-host-decl-names true; + +subnet 192.168.50.0 netmask 255.255.255.0 { +option subnet-mask 255.255.255.0; +option routers 192.168.50.1; +next-server 192.168.50.1; +server-identifier 192.168.50.1; +option domain-name-servers 192.168.50.1; +option domain-search "example.com"; +option domain-name "other.com"; + +# MAC numbering scheme: +# NFSv3: last octet starts at 0x00 and works up + + group { + # NFSv3 root=dhcp or root={/dev/,}nfs, use server-id + option root-path "/nfs/client"; + + host nfs3-1 { + hardware ethernet 52:54:00:12:34:00; + fixed-address 192.168.50.101; + } + } + + group { + # NFSv3 root=dhcp or root={/dev/,}nfs, use given IP + option root-path "192.168.50.2:/nfs/client"; + + host nfs3-2 { + hardware ethernet 52:54:00:12:34:01; + fixed-address 192.168.50.101; + } + } + + group { + # NFSv3 root=dhcp, use protocol from root-path + option root-path "nfs:192.168.50.3:/nfs/client"; + + host nfs3-3 { + hardware ethernet 52:54:00:12:34:02; + fixed-address 192.168.50.101; + } + } + + group { + # NFSv3 root=dhcp, use protocol, options from root-path + option root-path "nfs:192.168.50.3:/nfs/client:wsize=4096"; + + host nfs3-4 { + hardware ethernet 52:54:00:12:34:03; + fixed-address 192.168.50.101; + } + } + + group { + # NFSv3 root=dhcp, nfsroot=/path and nfsroot=IP:/path testing + + host nfs3-5 { + hardware ethernet 52:54:00:12:34:04; + fixed-address 192.168.50.101; + } + } + + group { + # NFSv3 root=dhcp, use path, comma-separated options + option root-path "/nfs/client,wsize=4096"; + + host nfs3-6 { + hardware ethernet 52:54:00:12:34:05; + fixed-address 192.168.50.101; + } + } + + group { + # NFSv3 root=dhcp, use IP, path, comma-separated options + option root-path "192.168.50.2:/nfs/client,wsize=4096"; + + host nfs3-7 { + hardware ethernet 52:54:00:12:34:06; + fixed-address 192.168.50.101; + } + } + + group { + # NFSv3 root=dhcp, use proto, IP, path, comma-separated options + option root-path "nfs:192.168.50.3:/nfs/client,wsize=4096"; + + host nfs3-8 { + hardware ethernet 52:54:00:12:34:07; + fixed-address 192.168.50.101; + } + } + + # MAC numbering scheme: + # NFSv4: last octet starts at 0x80 and works up + + group { + # NFSv4 root={/dev/,}nfs4, use server-id + option root-path "/client"; + + host nfs4-1 { + hardware ethernet 52:54:00:12:34:80; + fixed-address 192.168.50.101; + } + } + + group { + # NFSv4 root={/dev/,}nfs4, use given IP + option root-path "192.168.50.2:/client"; + + host nfs4-2 { + hardware ethernet 52:54:00:12:34:81; + fixed-address 192.168.50.101; + } + } + + group { + # NFSv4 root=dhcp, use profocol from root-path + option root-path "nfs4:192.168.50.3:/client"; + + host nfs4-3 { + hardware ethernet 52:54:00:12:34:82; + fixed-address 192.168.50.101; + } + } + + group { + # NFSv4 root=dhcp, use profocol, options from root-path + option root-path "nfs4:192.168.50.3:/client:wsize=4096"; + + host nfs4-4 { + hardware ethernet 52:54:00:12:34:83; + fixed-address 192.168.50.101; + } + } + + group { + # NFSv3 root=nfs4, nfsroot=/path and nfsroot=IP:/path testing + host nfs4-5 { + hardware ethernet 52:54:00:12:34:84; + fixed-address 192.168.50.101; + } + } + + group { + # NFSv4 root={/dev/,}nfs4, use server-id, comma-separated opts + option root-path "/client,wsize=4096"; + + host nfs4-6 { + hardware ethernet 52:54:00:12:34:85; + fixed-address 192.168.50.101; + } + } + + group { + # NFSv4 root={/dev/,}nfs4, use given IP, comma-separated opts + option root-path "192.168.50.2:/client,wsize=4096"; + + host nfs4-7 { + hardware ethernet 52:54:00:12:34:86; + fixed-address 192.168.50.101; + } + } + + group { + # NFSv4 root=dhcp, use comma-separated opts + option root-path "nfs4:192.168.50.3:/client,wsize=4096"; + + host nfs4-8 { + hardware ethernet 52:54:00:12:34:87; + fixed-address 192.168.50.101; + } + } + +} diff --git a/test/TEST-20-NFS/exports b/test/TEST-20-NFS/exports new file mode 100644 index 0000000..95619e7 --- /dev/null +++ b/test/TEST-20-NFS/exports @@ -0,0 +1,5 @@ +/nfs 192.168.50.0/24(ro,fsid=0,insecure,no_subtree_check,no_root_squash) +/nfs/client 192.168.50.0/24(ro,insecure,no_subtree_check,no_root_squash) +/nfs/nfs3-5 192.168.50.0/24(ro,insecure,no_subtree_check,no_root_squash,nohide) +/nfs/ip/192.168.50.101 192.168.50.0/24(ro,insecure,no_subtree_check,no_root_squash,nohide) +/nfs/tftpboot/nfs4-5 192.168.50.0/24(ro,insecure,no_subtree_check,no_root_squash,nohide) diff --git a/test/TEST-20-NFS/finished-false.sh b/test/TEST-20-NFS/finished-false.sh new file mode 100755 index 0000000..ecdbef9 --- /dev/null +++ b/test/TEST-20-NFS/finished-false.sh @@ -0,0 +1,2 @@ +#!/bin/sh +exit 1 diff --git a/test/TEST-20-NFS/hard-off.sh b/test/TEST-20-NFS/hard-off.sh new file mode 100755 index 0000000..01acb19 --- /dev/null +++ b/test/TEST-20-NFS/hard-off.sh @@ -0,0 +1,3 @@ +#!/bin/sh +getargbool 0 rd.shell || poweroff -f +getargbool 0 failme && poweroff -f diff --git a/test/TEST-20-NFS/hosts b/test/TEST-20-NFS/hosts new file mode 100644 index 0000000..36be908 --- /dev/null +++ b/test/TEST-20-NFS/hosts @@ -0,0 +1,5 @@ +127.0.0.1 localhost +192.168.50.1 server +192.168.50.2 server-ip +192.168.50.3 server-proto-ip +192.168.50.101 workstation2 diff --git a/test/TEST-20-NFS/server-init.sh b/test/TEST-20-NFS/server-init.sh new file mode 100755 index 0000000..0c06eea --- /dev/null +++ b/test/TEST-20-NFS/server-init.sh @@ -0,0 +1,109 @@ +#!/bin/bash +exec < /dev/console > /dev/console 2>&1 +set -x +export PATH=/usr/sbin:/usr/bin:/sbin:/bin +export TERM=linux +export PS1='nfstest-server:\w\$ ' +: > /dev/watchdog +stty sane +echo "made it to the rootfs!" +echo server > /proc/sys/kernel/hostname + +wait_for_if_link() { + local cnt=0 + local li + while [ $cnt -lt 600 ]; do + li=$(ip -o link show dev "$1" 2> /dev/null) + [ -n "$li" ] && return 0 + sleep 0.1 + cnt=$((cnt + 1)) + done + return 1 +} + +wait_for_if_up() { + local cnt=0 + local li + while [ $cnt -lt 200 ]; do + li=$(ip -o link show up dev "$1") + [ -n "$li" ] && return 0 + sleep 0.1 + cnt=$((cnt + 1)) + done + return 1 +} + +wait_for_route_ok() { + local cnt=0 + while [ $cnt -lt 200 ]; do + li=$(ip route show) + [ -n "$li" ] && [ -z "${li##*"$1"*}" ] && return 0 + sleep 0.1 + cnt=$((cnt + 1)) + done + return 1 +} + +linkup() { + wait_for_if_link "$1" 2> /dev/null && ip link set "$1" up 2> /dev/null && wait_for_if_up "$1" 2> /dev/null +} + +wait_for_if_link enx525400123456 + +ip addr add 127.0.0.1/8 dev lo +ip link set lo up +ip addr add 192.168.50.1/24 dev enx525400123456 +ip addr add 192.168.50.2/24 dev enx525400123456 +ip addr add 192.168.50.3/24 dev enx525400123456 +linkup enx525400123456 + +: > /dev/watchdog +modprobe af_packet +: > /dev/watchdog +mkdir /nfs/nfs3-5 +mount --bind /nfs/client /nfs/nfs3-5 +: > /dev/watchdog +mkdir -p /nfs/ip/192.168.50.101 +mount --bind /nfs/client /nfs/ip/192.168.50.101 +: > /dev/watchdog +mkdir -p /nfs/tftpboot/nfs4-5 +mount --bind /nfs/client /nfs/tftpboot/nfs4-5 +: > /dev/watchdog +modprobe sunrpc +: > /dev/watchdog +mount -t rpc_pipefs sunrpc /var/lib/nfs/rpc_pipefs +: > /dev/watchdog +[ -x /sbin/portmap ] && portmap +: > /dev/watchdog +mkdir -p /run/rpcbind +[ -x /sbin/rpcbind ] && rpcbind +: > /dev/watchdog +modprobe nfsd +: > /dev/watchdog +mount -t nfsd nfsd /proc/fs/nfsd +: > /dev/watchdog +exportfs -r +: > /dev/watchdog +rpc.nfsd +: > /dev/watchdog +rpc.mountd +: > /dev/watchdog +command -v rpc.idmapd > /dev/null && [ -z "$(pidof rpc.idmapd)" ] && rpc.idmapd +: > /dev/watchdog +exportfs -r +: > /dev/watchdog +mkdir -p /var/lib/dhcpd +: > /var/lib/dhcpd/dhcpd.leases +: > /dev/watchdog +chmod 777 /var/lib/dhcpd/dhcpd.leases +: > /dev/watchdog +rm -f /var/run/dhcpd.pid +dhcpd -d -cf /etc/dhcpd.conf -lf /var/lib/dhcpd/dhcpd.leases & +exportfs -s +echo "Serving NFS mounts" +while :; do + [ -n "$(jobs -rp)" ] && : > /dev/watchdog + sleep 10 +done +mount -n -o remount,ro / +poweroff -f diff --git a/test/TEST-20-NFS/server.link b/test/TEST-20-NFS/server.link new file mode 100644 index 0000000..1d21856 --- /dev/null +++ b/test/TEST-20-NFS/server.link @@ -0,0 +1,6 @@ +[Match] +OriginalName=* + +[Link] +NamePolicy=mac +MACAddressPolicy=keep diff --git a/test/TEST-20-NFS/test.sh b/test/TEST-20-NFS/test.sh new file mode 100755 index 0000000..b7cca75 --- /dev/null +++ b/test/TEST-20-NFS/test.sh @@ -0,0 +1,434 @@ +#!/bin/bash + +# shellcheck disable=SC2034 +TEST_DESCRIPTION="root filesystem on NFS with $USE_NETWORK" + +# Uncomment this to debug failures +#DEBUGFAIL="rd.debug loglevel=7 rd.break=initqueue rd.shell" +SERVER_DEBUG="rd.debug loglevel=7" +#SERIAL="unix:/tmp/server.sock" + +run_server() { + # Start server first + echo "NFS TEST SETUP: Starting DHCP/NFS server" + declare -a disk_args=() + # shellcheck disable=SC2034 + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/server.img root 0 1 + + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -net socket,listen=127.0.0.1:12320 \ + -net nic,macaddr=52:54:00:12:34:56,model=e1000 \ + -serial "${SERIAL:-"file:$TESTDIR/server.log"}" \ + -device i6300esb -watchdog-action poweroff \ + -append "panic=1 oops=panic softlockup_panic=1 root=LABEL=dracut rootfstype=ext4 rw console=ttyS0,115200n81 selinux=0 $SERVER_DEBUG" \ + -initrd "$TESTDIR"/initramfs.server \ + -pidfile "$TESTDIR"/server.pid -daemonize || return 1 + chmod 644 "$TESTDIR"/server.pid || return 1 + + # Cleanup the terminal if we have one + tty -s && stty sane + + if ! [[ $SERIAL ]]; then + while ! grep -q Serving "$TESTDIR"/server.log; do + echo "Waiting for the server to startup" + sleep 1 + done + else + echo Sleeping 10 seconds to give the server a head start + sleep 10 + fi +} + +client_test() { + local test_name="$1" + local mac=$2 + local cmdline="$3" + local server="$4" + local check_opt="$5" + local nfsinfo opts found expected + + echo "CLIENT TEST START: $test_name" + + # Need this so kvm-qemu will boot (needs non-/dev/zero local disk) + declare -a disk_args=() + # shellcheck disable=SC2034 + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker 1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker2.img marker2 1 + cmdline="$cmdline rd.net.timeout.dhcp=30" + + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -net nic,macaddr="$mac",model=e1000 \ + -net socket,connect=127.0.0.1:12320 \ + -device i6300esb -watchdog-action poweroff \ + -append "panic=1 oops=panic softlockup_panic=1 systemd.crash_reboot rd.shell=0 $cmdline $DEBUGFAIL rd.retry=10 quiet ro console=ttyS0,115200n81 selinux=0" \ + -initrd "$TESTDIR"/initramfs.testing + + # shellcheck disable=SC2181 + if [[ $? -ne 0 ]] || ! test_marker_check nfs-OK; then + echo "CLIENT TEST END: $test_name [FAILED - BAD EXIT]" + return 1 + fi + + # nfsinfo=( server:/path nfs{,4} options ) + read -r -a nfsinfo < <(awk '{print $2, $3, $4; exit}' "$TESTDIR"/marker.img) + + if [[ ${nfsinfo[0]%%:*} != "$server" ]]; then + echo "CLIENT TEST INFO: got server: ${nfsinfo[0]%%:*}" + echo "CLIENT TEST INFO: expected server: $server" + echo "CLIENT TEST END: $test_name [FAILED - WRONG SERVER]" + return 1 + fi + + found=0 + expected=1 + if [[ ${check_opt:0:1} == '-' ]]; then + expected=0 + check_opt=${check_opt:1} + fi + + opts=${nfsinfo[2]}, + while [[ $opts ]]; do + if [[ ${opts%%,*} == "$check_opt" ]]; then + found=1 + break + fi + opts=${opts#*,} + done + + if [[ $found -ne $expected ]]; then + echo "CLIENT TEST INFO: got options: ${nfsinfo[2]%%:*}" + if [[ $expected -eq 0 ]]; then + echo "CLIENT TEST INFO: did not expect: $check_opt" + echo "CLIENT TEST END: $test_name [FAILED - UNEXPECTED OPTION]" + else + echo "CLIENT TEST INFO: missing: $check_opt" + echo "CLIENT TEST END: $test_name [FAILED - MISSING OPTION]" + fi + return 1 + fi + + if ! test_marker_check nfsfetch-OK marker2.img; then + echo "CLIENT TEST END: $test_name [FAILED - NFS FETCH FAILED]" + return 1 + fi + + echo "CLIENT TEST END: $test_name [OK]" + return 0 +} + +test_nfsv3() { + # MAC numbering scheme: + # NFSv3: last octet starts at 0x00 and works up + # NFSv4: last octet starts at 0x80 and works up + + client_test "NFSv3 root=dhcp DHCP path only" 52:54:00:12:34:00 \ + "root=dhcp" 192.168.50.1 -wsize=4096 || return 1 + + client_test "NFSv3 Legacy root=/dev/nfs nfsroot=IP:path" 52:54:00:12:34:01 \ + "root=/dev/nfs nfsroot=192.168.50.1:/nfs/client" 192.168.50.1 -wsize=4096 || return 1 + + client_test "NFSv3 Legacy root=/dev/nfs DHCP path only" 52:54:00:12:34:00 \ + "root=/dev/nfs" 192.168.50.1 -wsize=4096 || return 1 + + client_test "NFSv3 Legacy root=/dev/nfs DHCP IP:path" 52:54:00:12:34:01 \ + "root=/dev/nfs" 192.168.50.2 -wsize=4096 || return 1 + + client_test "NFSv3 root=dhcp DHCP IP:path" 52:54:00:12:34:01 \ + "root=dhcp" 192.168.50.2 -wsize=4096 || return 1 + + client_test "NFSv3 root=dhcp DHCP proto:IP:path" 52:54:00:12:34:02 \ + "root=dhcp" 192.168.50.3 -wsize=4096 || return 1 + + client_test "NFSv3 root=dhcp DHCP proto:IP:path:options" 52:54:00:12:34:03 \ + "root=dhcp" 192.168.50.3 wsize=4096 || return 1 + + client_test "NFSv3 root=nfs:..." 52:54:00:12:34:04 \ + "root=nfs:192.168.50.1:/nfs/client" 192.168.50.1 -wsize=4096 || return 1 + + client_test "NFSv3 Bridge root=nfs:..." 52:54:00:12:34:04 \ + "root=nfs:192.168.50.1:/nfs/client bridge net.ifnames=0" 192.168.50.1 -wsize=4096 || return 1 + + client_test "NFSv3 Legacy root=IP:path" 52:54:00:12:34:04 \ + "root=192.168.50.1:/nfs/client" 192.168.50.1 -wsize=4096 || return 1 + + # This test must fail: nfsroot= requires root=/dev/nfs + client_test "NFSv3 Invalid root=dhcp nfsroot=/nfs/client" 52:54:00:12:34:04 \ + "root=dhcp nfsroot=/nfs/client failme" 192.168.50.1 -wsize=4096 && return 1 + + client_test "NFSv3 root=dhcp DHCP path,options" 52:54:00:12:34:05 \ + "root=dhcp" 192.168.50.1 wsize=4096 || return 1 + + client_test "NFSv3 Bridge Customized root=dhcp DHCP path,options" 52:54:00:12:34:05 \ + "root=dhcp bridge=foobr0:enp0s1" 192.168.50.1 wsize=4096 || return 1 + + client_test "NFSv3 root=dhcp DHCP IP:path,options" 52:54:00:12:34:06 \ + "root=dhcp" 192.168.50.2 wsize=4096 || return 1 + + client_test "NFSv3 root=dhcp DHCP proto:IP:path,options" 52:54:00:12:34:07 \ + "root=dhcp" 192.168.50.3 wsize=4096 || return 1 + + client_test "NFSv3 Overlayfs root=nfs:..." 52:54:00:12:34:04 \ + "root=nfs:192.168.50.1:/nfs/client rd.live.overlay.overlayfs=1" \ + 192.168.50.1 -wsize=4096 || return 1 + + client_test "NFSv3 Live Overlayfs root=nfs:..." 52:54:00:12:34:04 \ + "root=nfs:192.168.50.1:/nfs/client rd.live.image rd.live.overlay.overlayfs=1" \ + 192.168.50.1 -wsize=4096 || return 1 + + return 0 +} + +test_nfsv4() { + # There is a mandatory 90 second recovery when starting the NFSv4 + # server, so put these later in the list to avoid a pause when doing + # switch_root + + client_test "NFSv4 root=dhcp DHCP proto:IP:path" 52:54:00:12:34:82 \ + "root=dhcp" 192.168.50.3 -wsize=4096 || return 1 + + client_test "NFSv4 root=dhcp DHCP proto:IP:path:options" 52:54:00:12:34:83 \ + "root=dhcp" 192.168.50.3 wsize=4096 || return 1 + + client_test "NFSv4 root=nfs4:..." 52:54:00:12:34:84 \ + "root=nfs4:192.168.50.1:/client" 192.168.50.1 -wsize=4096 || return 1 + + client_test "NFSv4 root=dhcp DHCP proto:IP:path,options" 52:54:00:12:34:87 \ + "root=dhcp" 192.168.50.3 wsize=4096 || return 1 + + return 0 +} + +test_run() { + if [[ -s server.pid ]]; then + kill -TERM "$(cat "$TESTDIR"/server.pid)" + rm -f -- "$TESTDIR"/server.pid + fi + + if ! run_server; then + echo "Failed to start server" 1>&2 + return 1 + fi + + test_nfsv3 \ + && test_nfsv4 + + ret=$? + + if [[ -s $TESTDIR/server.pid ]]; then + kill -TERM "$(cat "$TESTDIR"/server.pid)" + rm -f -- "$TESTDIR"/server.pid + fi + + return $ret +} + +test_setup() { + export kernel=$KVERSION + export srcmods="/lib/modules/$kernel/" + # Detect lib paths + + rm -rf -- "$TESTDIR"/overlay + ( + mkdir -p "$TESTDIR"/server/overlay/source + # shellcheck disable=SC2030 + export initdir=$TESTDIR/server/overlay/source + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + + ( + cd "$initdir" || exit + mkdir -p dev sys proc run etc var/run tmp var/lib/{dhcpd,rpcbind} + mkdir -p var/lib/nfs/{v4recovery,rpc_pipefs} + chmod 777 var/lib/rpcbind var/lib/nfs + ) + + inst_multiple sh ls shutdown poweroff stty cat ps ln ip \ + dmesg mkdir cp ping exportfs \ + modprobe rpc.nfsd rpc.mountd showmount tcpdump \ + sleep mount chmod rm + for _terminfodir in /lib/terminfo /etc/terminfo /usr/share/terminfo; do + if [ -f "${_terminfodir}"/l/linux ]; then + inst_multiple -o "${_terminfodir}"/l/linux + break + fi + done + type -P portmap > /dev/null && inst_multiple portmap + type -P rpcbind > /dev/null && inst_multiple rpcbind + + [ -f /etc/netconfig ] && inst_multiple /etc/netconfig + type -P dhcpd > /dev/null && inst_multiple dhcpd + instmods nfsd sunrpc ipv6 lockd af_packet + inst ./server-init.sh /sbin/init + inst_simple /etc/os-release + inst ./hosts /etc/hosts + inst ./exports /etc/exports + inst ./dhcpd.conf /etc/dhcpd.conf + inst_multiple -o {,/usr}/etc/nsswitch.conf {,/usr}/etc/rpc \ + {,/usr}/etc/protocols {,/usr}/etc/services + inst_multiple -o rpc.idmapd /etc/idmapd.conf + + inst_libdir_file 'libnfsidmap_nsswitch.so*' + inst_libdir_file 'libnfsidmap/*.so*' + inst_libdir_file 'libnfsidmap*.so*' + + _nsslibs=$( + cat "$dracutsysrootdir"/{,usr/}etc/nsswitch.conf 2> /dev/null \ + | sed -e '/^#/d' -e 's/^.*://' -e 's/\[NOTFOUND=return\]//' \ + | tr -s '[:space:]' '\n' | sort -u | tr -s '[:space:]' '|' + ) + _nsslibs=${_nsslibs#|} + _nsslibs=${_nsslibs%|} + inst_libdir_file -n "$_nsslibs" 'libnss_*.so*' + + inst /etc/passwd /etc/passwd + inst /etc/group /etc/group + + cp -a /etc/ld.so.conf* "$initdir"/etc + ldconfig -r "$initdir" + dracut_kernel_post + ) + + # Make client root inside server root + ( + # shellcheck disable=SC2030 + # shellcheck disable=SC2031 + export initdir=$TESTDIR/server/overlay/source/nfs/client + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + + ( + cd "$initdir" || exit + mkdir -p dev sys proc etc run root usr var/lib/nfs/rpc_pipefs + echo "TEST FETCH FILE" > root/fetchfile + ) + + inst_multiple sh shutdown poweroff stty cat ps ln ip dd \ + mount dmesg mkdir cp ping grep setsid ls vi less cat sync + for _terminfodir in /lib/terminfo /etc/terminfo /usr/share/terminfo; do + if [ -f "${_terminfodir}"/l/linux ]; then + inst_multiple -o "${_terminfodir}"/l/linux + break + fi + done + + inst_simple "${PKGLIBDIR}/modules.d/99base/dracut-lib.sh" "/lib/dracut-lib.sh" + inst_simple "${PKGLIBDIR}/modules.d/99base/dracut-dev-lib.sh" "/lib/dracut-dev-lib.sh" + inst_simple "${PKGLIBDIR}/modules.d/45url-lib/url-lib.sh" "/lib/url-lib.sh" + inst_simple "${PKGLIBDIR}/modules.d/40network/net-lib.sh" "/lib/net-lib.sh" + inst_simple "${PKGLIBDIR}/modules.d/95nfs/nfs-lib.sh" "/lib/nfs-lib.sh" + inst_binary "${PKGLIBDIR}/dracut-util" "/usr/bin/dracut-util" + ln -s dracut-util "${initdir}/usr/bin/dracut-getarg" + ln -s dracut-util "${initdir}/usr/bin/dracut-getargs" + + inst ./client-init.sh /sbin/init + inst_simple /etc/os-release + inst_multiple -o {,/usr}/etc/nsswitch.conf + inst /etc/passwd /etc/passwd + inst /etc/group /etc/group + + inst_libdir_file 'libnfsidmap_nsswitch.so*' + inst_libdir_file 'libnfsidmap/*.so*' + inst_libdir_file 'libnfsidmap*.so*' + + _nsslibs=$( + cat "$dracutsysrootdir"/{,usr/}etc/nsswitch.conf 2> /dev/null \ + | sed -e '/^#/d' -e 's/^.*://' -e 's/\[NOTFOUND=return\]//' \ + | tr -s '[:space:]' '\n' | sort -u | tr -s '[:space:]' '|' + ) + _nsslibs=${_nsslibs#|} + _nsslibs=${_nsslibs%|} + inst_libdir_file -n "$_nsslibs" 'libnss_*.so*' + + cp -a /etc/ld.so.conf* "$initdir"/etc + ldconfig -r "$initdir" + ) + + # second, install the files needed to make the root filesystem + ( + # shellcheck disable=SC2030 + # shellcheck disable=SC2031 + export initdir=$TESTDIR/server/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + inst_multiple sfdisk mkfs.ext4 poweroff cp umount sync dd + inst_hook initqueue 01 ./create-root.sh + inst_hook initqueue/finished 01 ./finished-false.sh + ) + + # create an initramfs that will create the target root filesystem. + # We do it this way so that we do not risk trashing the host mdraid + # devices, volume groups, encrypted partitions, etc. + "$DRACUT" -l -i "$TESTDIR"/server/overlay / \ + -m "bash rootfs-block kernel-modules qemu" \ + -d "piix ide-gd_mod ata_piix ext4 sd_mod" \ + --nomdadmconf \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.makeroot "$KVERSION" || return 1 + rm -rf -- "$TESTDIR"/server + + declare -a disk_args=() + # shellcheck disable=SC2034 + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker 1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/server.img root 80 + + # Invoke KVM and/or QEMU to actually create the target filesystem. + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "root=/dev/dracut/root rw rootfstype=ext4 quiet console=ttyS0,115200n81 selinux=0" \ + -initrd "$TESTDIR"/initramfs.makeroot || return 1 + test_marker_check dracut-root-block-created || return 1 + + # Make an overlay with needed tools for the test harness + ( + # shellcheck disable=SC2031 + # shellcheck disable=SC2030 + export initdir="$TESTDIR"/overlay + mkdir -p "$TESTDIR"/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + inst_multiple poweroff shutdown + inst_hook shutdown-emergency 000 ./hard-off.sh + inst_hook emergency 000 ./hard-off.sh + inst_simple ./client.link /etc/systemd/network/01-client.link + ) + + # Make client's dracut image + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -o "plymouth" \ + -a "dmsquash-live debug watchdog ${USE_NETWORK}" \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.testing "$KVERSION" || return 1 + + ( + # shellcheck disable=SC2031 + export initdir="$TESTDIR"/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + rm "$initdir"/etc/systemd/network/01-client.link + inst_simple ./server.link /etc/systemd/network/01-server.link + inst_hook pre-mount 99 ./wait-if-server.sh + ) + # Make server's dracut image + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -m "bash rootfs-block debug kernel-modules watchdog qemu network network-legacy" \ + -d "af_packet piix ide-gd_mod ata_piix ext4 sd_mod e1000 i6300esb" \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.server "$KVERSION" || return 1 + + rm -rf -- "$TESTDIR"/overlay +} + +test_cleanup() { + if [[ -s $TESTDIR/server.pid ]]; then + kill -TERM "$(cat "$TESTDIR"/server.pid)" + rm -f -- "$TESTDIR"/server.pid + fi +} + +# shellcheck disable=SC1090 +. "$testdir"/test-functions diff --git a/test/TEST-20-NFS/wait-if-server.sh b/test/TEST-20-NFS/wait-if-server.sh new file mode 100755 index 0000000..8ae21f8 --- /dev/null +++ b/test/TEST-20-NFS/wait-if-server.sh @@ -0,0 +1,3 @@ +#!/bin/sh +. /lib/net-lib.sh +wait_for_if_link enx525400123456 diff --git a/test/TEST-30-ISCSI/Makefile b/test/TEST-30-ISCSI/Makefile new file mode 100644 index 0000000..88db701 --- /dev/null +++ b/test/TEST-30-ISCSI/Makefile @@ -0,0 +1,7 @@ +-include ../Makefile.testdir + +ibft.table: Makefile ibft.pl + perl ibft.pl \ + --initiator iqn=iqn.1994-05.com.redhat:633114aacf2 \ + --nic ip=192.168.50.101,prefix=24,gw=192.168.50.1,dns1=192.168.50.1,dhcp=192.168.50.1,mac=52:54:00:12:34:00,pci=00:03.0 \ + --target nic=0,ip=192.168.50.1,port=3260,lun=1,name=iqn.2009-06.dracut:target0 >$@ diff --git a/test/TEST-30-ISCSI/client-init.sh b/test/TEST-30-ISCSI/client-init.sh new file mode 100755 index 0000000..46a5e3f --- /dev/null +++ b/test/TEST-30-ISCSI/client-init.sh @@ -0,0 +1,24 @@ +#!/bin/sh +. /lib/dracut-lib.sh + +export PATH=/usr/sbin:/usr/bin:/sbin:/bin +command -v plymouth > /dev/null 2>&1 && plymouth --quit +exec > /dev/console 2>&1 + +export TERM=linux +export PS1='initramfs-test:\w\$ ' +stty sane +echo "made it to the rootfs! Powering down." +while read -r dev _ fstype opts rest || [ -n "$dev" ]; do + [ "$fstype" != "ext4" ] && continue + echo "iscsi-OK $dev $fstype $opts" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker + break +done < /proc/mounts + +if getargbool 0 rd.shell; then + strstr "$(setsid --help)" "control" && CTTY="-c" + setsid $CTTY sh -i +fi + +sync +poweroff -f diff --git a/test/TEST-30-ISCSI/client.link b/test/TEST-30-ISCSI/client.link new file mode 100644 index 0000000..b992bfd --- /dev/null +++ b/test/TEST-30-ISCSI/client.link @@ -0,0 +1,6 @@ +[Match] +OriginalName=* + +[Link] +NamePolicy=keep kernel database onboard slot path +MACAddressPolicy=keep diff --git a/test/TEST-30-ISCSI/create-client-root.sh b/test/TEST-30-ISCSI/create-client-root.sh new file mode 100755 index 0000000..267c93a --- /dev/null +++ b/test/TEST-30-ISCSI/create-client-root.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +trap 'poweroff -f' EXIT + +# don't let udev and this script step on eachother's toes +for x in 64-lvm.rules 70-mdadm.rules 99-mount-rules; do + : > "/etc/udev/rules.d/$x" +done +rm -f -- /etc/lvm/lvm.conf +udevadm control --reload +udevadm settle + +set -ex + +mkfs.ext4 -j -L singleroot -F /dev/disk/by-id/ata-disk_singleroot +mkdir -p /sysroot +mount -t ext4 /dev/disk/by-id/ata-disk_singleroot /sysroot +cp -a -t /sysroot /source/* +umount /sysroot +mdadm --create /dev/md0 --run --auto=yes --level=stripe --raid-devices=2 /dev/disk/by-id/ata-disk_raid0-1 /dev/disk/by-id/ata-disk_raid0-2 +mdadm -W /dev/md0 || : +lvm pvcreate -ff -y /dev/md0 +lvm vgcreate dracut /dev/md0 +lvm lvcreate -l 100%FREE -n root dracut +lvm vgchange -ay +mkfs.ext4 -j -L sysroot /dev/dracut/root +mount -t ext4 /dev/dracut/root /sysroot +cp -a -t /sysroot /source/* +umount /sysroot +lvm lvchange -a n /dev/dracut/root +echo "dracut-root-block-created" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker +sync +poweroff -f diff --git a/test/TEST-30-ISCSI/create-server-root.sh b/test/TEST-30-ISCSI/create-server-root.sh new file mode 100755 index 0000000..2dbc2da --- /dev/null +++ b/test/TEST-30-ISCSI/create-server-root.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +trap 'poweroff -f' EXIT + +# don't let udev and this script step on eachother's toes +for x in 64-lvm.rules 70-mdadm.rules 99-mount-rules; do + : > "/etc/udev/rules.d/$x" +done +rm -f -- /etc/lvm/lvm.conf +udevadm control --reload +udevadm settle + +mkfs.ext4 -L dracut /dev/disk/by-id/ata-disk_root +mkdir -p /root +mount -t ext4 /dev/disk/by-id/ata-disk_root /root +cp -a -t /root /source/* +mkdir -p /root/run +umount /root +echo "dracut-root-block-created" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker +poweroff -f diff --git a/test/TEST-30-ISCSI/dhcpd.conf b/test/TEST-30-ISCSI/dhcpd.conf new file mode 100644 index 0000000..fd306ea --- /dev/null +++ b/test/TEST-30-ISCSI/dhcpd.conf @@ -0,0 +1,48 @@ +ddns-update-style none; + +use-host-decl-names true; + +subnet 192.168.50.0 netmask 255.255.255.0 { + option subnet-mask 255.255.255.0; + option routers 192.168.50.1; + next-server 192.168.50.1; + server-identifier 192.168.50.1; + option domain-name-servers 192.168.50.1; + option domain-search "example.com"; + option domain-name "other.com"; + + # MAC numbering scheme: + # NFSv3: last octet starts at 0x00 and works up + + group { + option root-path "iscsi:192.168.50.1:::1:iqn.2009-06.dracut:target0"; + + host iscsi-1 { + hardware ethernet 52:54:00:12:34:00; + fixed-address 192.168.50.101; + } + } +} + +subnet 192.168.51.0 netmask 255.255.255.0 { + option subnet-mask 255.255.255.0; + option routers 192.168.51.1; + next-server 192.168.51.1; + server-identifier 192.168.51.1; + option domain-name-servers 192.168.51.1; + option domain-search "example.com"; + option domain-name "other.com"; + + # MAC numbering scheme: + # NFSv3: last octet starts at 0x00 and works up + + group { + #option root-path "iscsi:192.168.51.1:::1:iqn.2009-06.dracut:target1"; + + host iscsi-2 { + hardware ethernet 52:54:00:12:34:01; + fixed-address 192.168.51.101; + } + + } +} diff --git a/test/TEST-30-ISCSI/hosts b/test/TEST-30-ISCSI/hosts new file mode 100644 index 0000000..f8c18b6 --- /dev/null +++ b/test/TEST-30-ISCSI/hosts @@ -0,0 +1,8 @@ +127.0.0.1 localhost +192.168.50.1 server +192.168.50.2 server-ip +192.168.50.3 server-proto-ip +192.168.50.100 workstation1 +192.168.50.101 workstation2 +192.168.50.102 workstation3 +192.168.50.103 workstation4 diff --git a/test/TEST-30-ISCSI/ibft.pl b/test/TEST-30-ISCSI/ibft.pl new file mode 100644 index 0000000..c612951 --- /dev/null +++ b/test/TEST-30-ISCSI/ibft.pl @@ -0,0 +1,458 @@ +#!/usr/bin/perl +# SPDX-License-Identifier: GPL-2.0+ +# +# iBFT ACPI table generator +# $ perldoc ibft.pl if you'd like to read the manual, poor you: + +=head1 NAME + +ibft.pl - Generate iBFT ACPI table + +=head1 SYNOPSIS + +ibft.pl +[--oemid <oemid>] +[--tableid <tableid> +[--initiator isns=<ip>,slp=<ip>,radius1=<ip>,radius2=<ip>,iqn=<iqn>] +[--nic ip=<ip>[,prefix=<prefix>][,gw=<ip>][,dns1=<ip>][,dns2=<ip>][,dhcp=<ip>][,vlan=<id>][,mac=<mac>][,pci=<pci>][,hostname=<hostname>] ...] +[--target ip=<ip>[,port=<port>][,lun=<lun>][,name=<iqn> ...] + +=head1 DESCRIPTION + +B<ibft.pl> creates an image of iBFT ACPI table similar to what a real network +boot firmware would do. This is mainly useful for testing. + +=head1 OPTIONS + +=over 4 + +=item B<< --oemid <oemid> >> + +Create a table with a particular OEM ID, limited to 6 characters. +It generally doesn't matter. + +Defaults to I<DRACUT>. + +=item B<< --tableid <tableid> >> + +Create a table with a particular OEM Table ID. + +Defaults to I<TEST>, but any four-letter word would do. Any. + +=item B<< --initiator >> + +Configure the Initiator Structure. +Following parameters are supported: + +=over 4 + +=item B<< isns=<ip> >> + +iSNS server address. + +=item B<< slp=<ip> >> + +SLP server address. + +=item B<< radius1=<ip> >>, B<< radius2=<ip> >> + +Primary and secondary Radius server addresses. + +=item B<< iqn=<iqn> >> + +Override the IQN, which defaults to I<iqn.2009-06.dracut:initiator0>. + +=back + +=item B<< --nic >> + +Configure a NIC Structure. This option can be used up multiple times. + +Following parameters are supported: + +=over 4 + +=item B<< ip=<ip> >> + +Set the IP address. Both I<AF_INET> and I<AF_INET6> families are supported. +This parameter is mandatory. + +=item B<< prefix=<prefix> >> + +Set the IP address prefix. You generally also want to set this in order to +get a sensible iBFT. + +=item B<< gw=<ip> >> + +Set the gateway IP address. + +=item B<< dns1=<ip> >>, B<< dns2=<ip> >> + +Set the domain service server addresses. + +=item B<< dhcp=<ip> >> + +Specify the address of the DHCP server in case dynamic configuration is used. + +=item B<< vlan=<id> >> + +The VLAN Id. Duh. + +=item B<< mac=<mac> >> + +Specify the ethernet hardware address, in form of six colon-delimited +hexadecimal octets. + +=item B<< pci=<pci> >> + +Specify the ethernet hardware's PCI bus location, in form of +B<< <bus> >>:B<< <device> >>.B<< <function> >> where the numbers are in +hexadecimal. + +=item B<< hostname=<hostname> >> + +The host name. Defaults to B<client>. + +=back + +=item B<< --target >> + +Configure a Target Structure. This option can be used multiple times. + +Following parameters are supported: + +=over 4 + +=item B<< ip=<ip> >> + +The iSCSI target IP address. + +=item B<< port=<port> >> + +The iSCSI TCP port, in case the default of I<3260> is not good enough for +you. + +=item B<< lun=<1> >> + +The LUN number. Defaults to I<1> no less. + +=item B<< name=<iqn> >> + +The iSCSI volume name. Defaults to I<iqn.2009-06.dracut:target0> for the first +target, I<iqn.2009-06.dracut:target1> for the second one. + +=back + +=back + +=cut + +use strict; +use warnings; + +sub ip4 { + shift =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/ + or die 'not an INET address'; + return (map { 0x00 } 0..9), 0xff, 0xff, $1, $2, $3, $4; +} + +sub ip6 +{ + my ($beg, $end) = map { [ map { /^([0-9a-fA-F]{0,2}?)([0-9a-fA-F]{1,2})$/ + ? (hex $1, hex $2) + : die "'$_' not valid in a INET6 address" + } split /:/ ] } split /::/, shift; + + $beg ||= []; + $end ||= []; + + my $fill = 16 - scalar @$beg + scalar@$end; + die 'INET6 address too long' if $fill < 0; + + @$beg, (map { 0 } 1..$fill), @$end; +} + +sub ip +{ + my @val; + @val = eval { @val = ip6 ($_[0]) }; + @val = eval { @val = ip4 ($_[0]) } unless @val; + die "Saatana: $_[0] is not an INET or INET6 address" unless @val; + + return pack 'C16', @val; +} + +sub mac +{ + return pack 'C8', map { hex $_ } split /:/, shift; +} + +sub pci +{ + shift =~ /^([0-9a-fA-F]{1,2}?):([0-9a-fA-F]{1,2})\.([0-9a-fA-F]+)$/ + or die 'Not a PCI address'; + return (hex $1) << 8 | (hex $2) << 3 | (hex $3); +} + +sub lun +{ + return pack 'C8', 0, shift, 0, 0, 0, 0, 0, 0; +} + +# signature, length, revision, checksum, oem_id, oem_table_id, reserved +sub pack_table_hdr { pack 'a4 V C C a6 a8 a24 x![C8]', @_ } + +# id, version, length, index, flags +# extensions, initiator_off, nic0_off, tgt0_off, nic1_off, tgt1_off, ext* +sub pack_control { pack 'C C S C C S S S S S S S* x![C8]', @_ } + +# id, version, length, index, flags +# isns_adr, slp_adr, radius1_adr, radius2_adr, iqn_len, iqn_off +sub pack_initiator { pack 'C C S C C a16 a16 a16 a16 SS x![C8]', @_ } + +# id, version, length, index, flags +# adr, prefix, origin, gw, dns1, dns2, dhcp, vlan_id, mac, pci_bdf, hostname_len, hostname_off +sub pack_nic { $_[5] ? pack 'C C S C C a16 C C a16 a16 a16 a16 S a6 S SS x![C8]', @_ : '' } + +# id, version, length, index, flags +# tgt_adr, tgt_port, tgt_lun, chap_type, nic_id, tgt_len, tgt_off, +# chap_name_len, chap_name_off, chap_secret_len, chap_secret_off +# rchap_name_len, rchap_name_off, rchap_secret_len, rchap_secret_off +sub pack_tgt { $_[5] ? pack 'C C S C C a16 S a8 C C SS SS SS SS SS x![C8]', @_ : '' }; + +# str +sub pack_str { pack 'Z*', @_ } + +# Initialize some defaults +my @table_hdr = ('iBFT', 0000, 1, 0000, 'DRACUT', 'TEST', ''); +my @control = (1, 1, 18, 0, 0, 0000, 0000, 0000, 0000, 0000, 0000); +my @initiator = (2, 1, 74, 0, 0x03, '', '', '', '', (0000, 0000)); +my @nics; +my @tgts; +my $iqn = 'iqn.2009-06.dracut:initiator0'; +my @hostnames; +my @tgt_names; + +while (@ARGV) { + my $arg = shift @ARGV; + die "Saatana: $arg is missing an argument" unless @ARGV; + + if ($arg eq '--oemid') { + $table_hdr[4] = shift @ARGV; + } elsif ($arg eq '--tableid') { + $table_hdr[5] = shift @ARGV; + } elsif ($arg eq '--initiator') { + my %val = split /[,=]/, shift @ARGV; + $initiator[5] = ip (delete $val{isns}) if exists $val{isns}; + $initiator[6] = ip (delete $val{slp}) if exists $val{slp}; + $initiator[7] = ip (delete $val{radius1}) if exists $val{radius1}; + $initiator[8] = ip (delete $val{radius2}) if exists $val{radius2}; + $iqn = delete $val{iqn} if exists $val{iqn}; + die "Saatana: Extra arguments to --initiator: ".join (', ', %val) if %val; + } elsif ($arg eq '--nic') { + my @nic = (3, 1, 102, 0, 0x03, + undef, 0, 0x01, '', '', '', '', 0, '', 0, (0000, 0000)); + push @nics, \@nic; + + my %val = split /[,=]/, shift @ARGV; + die 'Saatana: --nic needs an ip' unless exists $val{ip}; + $nic[3] = $#nics; + $nic[5] = ip (delete $val{ip}); + $nic[6] = delete $val{prefix} if exists $val{prefix}; + $nic[7] = 0x03 if exists $val{dhcp}; + $nic[8] = ip (delete $val{gw}) if exists $val{gw}; + $nic[9] = ip (delete $val{dns1}) if exists $val{dns1}; + $nic[10] = ip (delete $val{dns2}) if exists $val{dns2}; + $nic[11] = ip (delete $val{dhcp}) if exists $val{dhcp}; + $nic[12] = delete $val{vlan} if exists $val{vlan}; + $nic[13] = mac (delete $val{mac}) if exists $val{mac}; + $nic[14] = pci (delete $val{pci}) if exists $val{pci}; + $hostnames[$#nics] = exists $val{hostname} ? delete $val{hostname} : 'client'; + $hostnames[$#nics] = pack_str $hostnames[$#nics]; + die "Saatana: Extra arguments to --nic: ".join (', ', %val) if %val; + + # Allocate an control expansion entry + if ($#nics > 1) { + $control[2] += 2; + push @control, (0x4444); + } + } elsif ($arg eq '--target') { + my @tgt = (4, 1, 54, 0, 0x03, + undef, 3260, lun (1), 0, 0, + (0000, 0000), + (0000, 0000), + (0000, 0000), + (0000, 0000), + (0000, 0000)); + push @tgts, \@tgt; + + my %val = split /[,=]/, shift @ARGV; + die 'Saatana: --target needs an ip' unless exists $val{ip}; + $tgt[3] = $#tgts; + $tgt[5] = ip (delete $val{ip}) if exists $val{ip}; + $tgt[6] = delete $val{port} if exists $val{port}; + $tgt[7] = lun (delete $val{lun}) if exists $val{lun}; + $tgt[9] = delete $val{nic} if exists $val{nic}; + $tgt_names[$#tgts] = exists $val{name} ? delete $val{name} + : 'iqn.2009-06.dracut:target'.$#tgts; + $tgt_names[$#tgts] = pack_str $tgt_names[$#tgts]; + die "Saatana: Extra arguments to --target: ".join (', ', %val) if %val; + + # Allocate an control expansion entry if necessary + if ($#tgts > 1) { + $control[2] += 2; + push @control, (0x1111); + } + } else { + die "Saatana: Unknown argument: $arg"; + } +} + +# Pass 1 +my $table_hdr = pack_table_hdr @table_hdr; +my $control = pack_control @control; +my $initiator = pack_initiator @initiator; +my @packed_nics = map { pack_nic @$_ } @nics; +my @packed_tgts = map { pack_tgt @$_ } @tgts; +$iqn = pack_str $iqn; + + +# Resolve the offsets +my $len = 0; +$len += length $table_hdr; +$len += length $control; +$control[6] = $len; +$len += length $initiator; + +for my $i (0..$#packed_nics) { + if ($i == 0) { + # NIC 0 + $control[7] = $len; + } elsif ($i == 1) { + # NIC 1 + $control[9] = $len; + } else { + # Expansion + $control[11 + $i - 2] = $len; + } + $len += length $packed_nics[$i]; +} + +for my $i (0..$#packed_tgts) { + if ($i == 0) { + # Target 0 + $control[8] = $len; + } elsif ($i == 1) { + # Target 1 + $control[10] = $len; + } else { + # Expansion + $control[11 + scalar @packed_nics - 2 + $i - 2] = $len; + } + $len += length $packed_tgts[$i]; +} + +$initiator[9] = -1 + length $iqn; +$initiator[10] = $len; +$len += length $iqn; + +for my $i (0..$#hostnames) { + $nics[$i]->[15] = -1 + length $hostnames[$i]; + $nics[$i]->[16] = $len; + $len += length $hostnames[$i]; +} + +for my $i (0..$#tgt_names) { + $tgts[$i]->[10] = -1 + length $tgt_names[$i]; + $tgts[$i]->[11] = $len; + $len += length $tgt_names[$i]; +} + +@table_hdr[1] = $len; + +# Pass 2, with the offsets resolved +$table_hdr = pack_table_hdr @table_hdr; +$control = pack_control @control; +$initiator = pack_initiator @initiator; +@packed_nics = map { pack_nic @$_ } @nics; +@packed_tgts = map { pack_tgt @$_ } @tgts; + +# Pass 3, calculate checksum +my $cksum = 0xff; +$cksum += ord $_ foreach split //, join '', $table_hdr, $control, $initiator, + @packed_nics, @packed_tgts, $iqn, @hostnames, @tgt_names; +$cksum = ~$cksum & 0xff; +$table_hdr[3] = $cksum; +$table_hdr = pack_table_hdr @table_hdr; + +# Puke stuff out +print $table_hdr; +print $control; +print $initiator; +print @packed_nics; +print @packed_tgts; +print $iqn; +print @hostnames; +print @tgt_names; + +=head1 EXAMPLES + +=over + +=item B<< perl ibft.pl --oemid FENSYS --tableid iPXE --nic ip=192.168.50.101,prefix=24,gw=192.168.50.1,dns1=192.168.50.1,dhcp=192.168.50.1,vlan=0,mac=52:54:00:12:34:00,pci=00:02.0,hostname=iscsi-1 --target ip=192.168.50.1 >ibft.img >> + +Generate an iBFT image with a single NIC while pretending we're iPXE for +no good reason. + +=item B<<perl ibft.pl --initiator iqn=iqn.1994-05.com.redhat:633114aacf2 --nic ip=192.168.50.101,prefix=24,gw=192.168.50.1,dns1=192.168.50.1,dhcp=192.168.50.1,mac=52:54:00:12:34:00,pci=00:03.0 --nic ip=192.168.51.101,prefix=24,gw=192.168.51.1,dns1=192.168.51.1,dhcp=192.168.51.1,mac=52:54:00:12:34:01,pci=00:04.0 --target ip=192.168.50.1,port=3260,lun=1,name=iqn.2009-06.dracut:target0 --target ip=192.168.51.1,port=3260,lun=2,name=iqn.2009-06.dracut:target1 >ibft.img >> + +Generate an iBFT image for two NICs while being slightly more expressive +than necessary. + +=item B<qemy-system-x86_64 -acpitable file=ibft.img> + +Use the image with QEMU. + +=back + +=head1 BUGS + +No support for CHAP secrets. + +=head1 SEE ALSO + +=over 4 + +=item L<qemu(1)>, + +=item L<iSCSI Boot Firmware Table (iBFT)|ftp://ftp.software.ibm.com/systems/support/bladecenter/iscsi_boot_firmware_table_v1.03.pdf>, + +=item L<NL_PREFIX_ORIGIN Enumeration|https://docs.microsoft.com/en-us/windows/win32/api/nldef/ne-nldef-nl_prefix_origin> + +=back + +=head1 COPYRIGHT + +Copyright (C) 2019 Lubomir Rintel + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +=head1 AUTHOR + +Lubomir Rintel C<lkundrak@v3.sk> + +=cut + +# Forgive me. +# This would have been much easier with FORTH. diff --git a/test/TEST-30-ISCSI/ibft.table b/test/TEST-30-ISCSI/ibft.table Binary files differnew file mode 100644 index 0000000..0837940 --- /dev/null +++ b/test/TEST-30-ISCSI/ibft.table diff --git a/test/TEST-30-ISCSI/server-init.sh b/test/TEST-30-ISCSI/server-init.sh new file mode 100755 index 0000000..a1c3b7e --- /dev/null +++ b/test/TEST-30-ISCSI/server-init.sh @@ -0,0 +1,88 @@ +#!/bin/sh +exec < /dev/console > /dev/console 2>&1 +set -x +export PATH=/usr/sbin:/usr/bin:/sbin:/bin +export TERM=linux +export PS1='server:\w\$ ' +stty sane +echo "made it to the rootfs!" +echo server > /proc/sys/kernel/hostname + +wait_for_if_link() { + local cnt=0 + local li + while [ $cnt -lt 600 ]; do + li=$(ip -o link show dev "$1" 2> /dev/null) + [ -n "$li" ] && return 0 + sleep 0.1 + cnt=$((cnt + 1)) + done + return 1 +} + +wait_for_if_up() { + local cnt=0 + local li + while [ $cnt -lt 200 ]; do + li=$(ip -o link show up dev "$1") + [ -n "$li" ] && return 0 + sleep 0.1 + cnt=$((cnt + 1)) + done + return 1 +} + +wait_for_route_ok() { + local cnt=0 + while [ $cnt -lt 200 ]; do + li=$(ip route show) + [ -n "$li" ] && [ -z "${li##*"$1"*}" ] && return 0 + sleep 0.1 + cnt=$((cnt + 1)) + done + return 1 +} + +linkup() { + wait_for_if_link "$1" 2> /dev/null && ip link set "$1" up 2> /dev/null && wait_for_if_up "$1" 2> /dev/null +} + +wait_for_if_link enx525400123456 +wait_for_if_link enx525400123457 + +ip addr add 127.0.0.1/8 dev lo +ip link set lo up + +ip addr add 192.168.50.1/24 dev enx525400123456 +linkup enx525400123456 + +ip addr add 192.168.51.1/24 dev enx525400123457 +linkup enx525400123457 + +modprobe af_packet + +: > /var/lib/dhcpd/dhcpd.leases +chmod 777 /var/lib/dhcpd/dhcpd.leases +dhcpd -d -cf /etc/dhcpd.conf -lf /var/lib/dhcpd/dhcpd.leases & + +tgtd +tgtadm --lld iscsi --mode target --op new --tid 1 --targetname iqn.2009-06.dracut:target0 +tgtadm --lld iscsi --mode target --op new --tid 2 --targetname iqn.2009-06.dracut:target1 +tgtadm --lld iscsi --mode target --op new --tid 3 --targetname iqn.2009-06.dracut:target2 +tgtadm --lld iscsi --mode logicalunit --op new --tid 1 --lun 1 -b /dev/disk/by-id/ata-disk_singleroot +tgtadm --lld iscsi --mode logicalunit --op new --tid 2 --lun 2 -b /dev/disk/by-id/ata-disk_raid0-1 +tgtadm --lld iscsi --mode logicalunit --op new --tid 3 --lun 3 -b /dev/disk/by-id/ata-disk_raid0-2 +tgtadm --lld iscsi --mode target --op bind --tid 1 -I 192.168.50.101 +tgtadm --lld iscsi --mode target --op bind --tid 2 -I 192.168.51.101 +tgtadm --lld iscsi --mode target --op bind --tid 3 -I 192.168.50.101 + +# Wait forever for the VM to die +echo "Serving iSCSI" +while pidof tgtd > /dev/null; do + : > /dev/watchdog + dmesg -c + sleep 1 +done +dmesg -c +mount -n -o remount,ro / +poweroff -f diff --git a/test/TEST-30-ISCSI/server.link b/test/TEST-30-ISCSI/server.link new file mode 100644 index 0000000..1d21856 --- /dev/null +++ b/test/TEST-30-ISCSI/server.link @@ -0,0 +1,6 @@ +[Match] +OriginalName=* + +[Link] +NamePolicy=mac +MACAddressPolicy=keep diff --git a/test/TEST-30-ISCSI/test.sh b/test/TEST-30-ISCSI/test.sh new file mode 100755 index 0000000..ac9f096 --- /dev/null +++ b/test/TEST-30-ISCSI/test.sh @@ -0,0 +1,240 @@ +#!/bin/bash + +# shellcheck disable=SC2034 +TEST_DESCRIPTION="root filesystem over iSCSI with $USE_NETWORK" + +#DEBUGFAIL="rd.shell rd.break rd.debug loglevel=7 " +#SERVER_DEBUG="rd.debug loglevel=7" +#SERIAL="tcp:127.0.0.1:9999" + +run_server() { + # Start server first + echo "iSCSI TEST SETUP: Starting DHCP/iSCSI server" + + declare -a disk_args=() + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/server.img serverroot 0 1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/singleroot.img singleroot + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid0-1.img raid0-1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid0-2.img raid0-2 + + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -serial "${SERIAL:-"file:$TESTDIR/server.log"}" \ + -net nic,macaddr=52:54:00:12:34:56,model=e1000 \ + -net nic,macaddr=52:54:00:12:34:57,model=e1000 \ + -net socket,listen=127.0.0.1:12330 \ + -append "panic=1 oops=panic softlockup_panic=1 quiet root=/dev/disk/by-id/ata-disk_serverroot rootfstype=ext4 rw console=ttyS0,115200n81 selinux=0 $SERVER_DEBUG" \ + -initrd "$TESTDIR"/initramfs.server \ + -pidfile "$TESTDIR"/server.pid -daemonize || return 1 + chmod 644 "$TESTDIR"/server.pid || return 1 + + # Cleanup the terminal if we have one + tty -s && stty sane + + if ! [[ $SERIAL ]]; then + while :; do + grep Serving "$TESTDIR"/server.log && break + echo "Waiting for the server to startup" + tail "$TESTDIR"/server.log + sleep 1 + done + else + echo Sleeping 10 seconds to give the server a head start + sleep 10 + fi + +} + +run_client() { + local test_name=$1 + shift + echo "CLIENT TEST START: $test_name" + + declare -a disk_args=() + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker + + test_marker_reset + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -net nic,macaddr=52:54:00:12:34:00,model=e1000 \ + -net nic,macaddr=52:54:00:12:34:01,model=e1000 \ + -net socket,connect=127.0.0.1:12330 \ + -acpitable file=ibft.table \ + -append "$*" \ + -initrd "$TESTDIR"/initramfs.testing + + # shellcheck disable=SC2181 + if [[ $? -ne 0 ]] || ! test_marker_check iscsi-OK; then + echo "CLIENT TEST END: $test_name [FAILED - BAD EXIT]" + return 1 + fi + + echo "CLIENT TEST END: $test_name [OK]" + return 0 +} + +do_test_run() { + initiator=$(iscsi-iname) + + run_client "root=dhcp" \ + "root=/dev/root netroot=dhcp ip=enp0s1:dhcp" \ + "rd.iscsi.initiator=$initiator" \ + || return 1 + + run_client "netroot=iscsi target0" \ + "root=LABEL=singleroot netroot=iscsi:192.168.50.1::::iqn.2009-06.dracut:target0" \ + "ip=192.168.50.101::192.168.50.1:255.255.255.0:iscsi-1:enp0s1:off" \ + "rd.iscsi.initiator=$initiator" \ + || return 1 + + run_client "netroot=iscsi target1 target2" \ + "root=LABEL=sysroot" \ + "ip=dhcp" \ + "netroot=iscsi:192.168.51.1::::iqn.2009-06.dracut:target1" \ + "netroot=iscsi:192.168.50.1::::iqn.2009-06.dracut:target2" \ + "rd.iscsi.initiator=$initiator" \ + || return 1 + + run_client "root=ibft" \ + "root=LABEL=singleroot" \ + "rd.iscsi.ibft=1" \ + "rd.iscsi.firmware=1" \ + || return 1 + + echo "All tests passed [OK]" + return 0 +} + +test_run() { + if ! run_server; then + echo "Failed to start server" 1>&2 + return 1 + fi + do_test_run + ret=$? + if [[ -s $TESTDIR/server.pid ]]; then + kill -TERM "$(cat "$TESTDIR"/server.pid)" + rm -f -- "$TESTDIR"/server.pid + fi + return $ret +} + +test_check() { + if ! command -v tgtd &> /dev/null || ! command -v tgtadm &> /dev/null; then + echo "Need tgtd and tgtadm from scsi-target-utils" + return 1 + fi +} + +test_setup() { + # Create what will eventually be the client root filesystem onto an overlay + "$DRACUT" -l --keep --tmpdir "$TESTDIR" \ + -m "test-root" \ + -i ./client-init.sh /sbin/init \ + -I "ip ping grep setsid" \ + -i "${PKGLIBDIR}/modules.d/99base/dracut-lib.sh" "/lib/dracut-lib.sh" \ + -i "${PKGLIBDIR}/modules.d/99base/dracut-dev-lib.sh" "/lib/dracut-dev-lib.sh" \ + --no-hostonly --no-hostonly-cmdline --nohardlink \ + -f "$TESTDIR"/initramfs.root "$KVERSION" || return 1 + mkdir -p "$TESTDIR"/overlay/source && mv "$TESTDIR"/dracut.*/initramfs/* "$TESTDIR"/overlay/source && rm -rf "$TESTDIR"/dracut.* + + mkdir -p -- "$TESTDIR"/overlay/source/var/lib/nfs/rpc_pipefs + + # create an initramfs that will create the target root filesystem. + # We do it this way so that we do not risk trashing the host mdraid + # devices, volume groups, encrypted partitions, etc. + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -m "test-makeroot crypt lvm mdraid" \ + -I "mkfs.ext4 setsid blockdev" \ + -i ./create-client-root.sh /lib/dracut/hooks/initqueue/01-create-client-root.sh \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.makeroot "$KVERSION" || return 1 + rm -rf -- "$TESTDIR"/overlay + + declare -a disk_args=() + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker 1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/singleroot.img singleroot 200 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid0-1.img raid0-1 100 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid0-2.img raid0-2 100 + + # Invoke KVM and/or QEMU to actually create the target filesystem. + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "root=/dev/fakeroot rw rootfstype=ext4 quiet console=ttyS0,115200n81 selinux=0" \ + -initrd "$TESTDIR"/initramfs.makeroot || return 1 + test_marker_check dracut-root-block-created || return 1 + rm -- "$TESTDIR"/marker.img + + # Create what will eventually be the server root filesystem onto an overlay + "$DRACUT" -l --keep --tmpdir "$TESTDIR" \ + -m "test-root network network-legacy" \ + -d "iscsi_tcp crc32c ipv6" \ + -i ./server-init.sh /sbin/init \ + -i "${PKGLIBDIR}/modules.d/99base/dracut-lib.sh" "/lib/dracut-lib.sh" \ + -i "${PKGLIBDIR}/modules.d/99base/dracut-dev-lib.sh" "/lib/dracut-dev-lib.sh" \ + -I "modprobe chmod ip ping tcpdump setsid pidof tgtd tgtadm /etc/passwd" \ + --install-optional "/etc/netconfig dhcpd /etc/group /etc/nsswitch.conf /etc/rpc /etc/protocols /etc/services /usr/etc/nsswitch.conf /usr/etc/rpc /usr/etc/protocols /usr/etc/services" \ + -i "./hosts" "/etc/hosts" \ + -i "./dhcpd.conf" "/etc/dhcpd.conf" \ + --no-hostonly --no-hostonly-cmdline --nohardlink \ + -f "$TESTDIR"/initramfs.root "$KVERSION" || return 1 + mkdir -p "$TESTDIR"/overlay/source && mv "$TESTDIR"/dracut.*/initramfs/* "$TESTDIR"/overlay/source && rm -rf "$TESTDIR"/dracut.* + + mkdir -p "$TESTDIR"/overlay/source/var/lib/dhcpd + + # second, install the files needed to make the root filesystem + # create an initramfs that will create the target root filesystem. + # We do it this way so that we do not risk trashing the host mdraid + # devices, volume groups, encrypted partitions, etc. + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -m "test-makeroot" \ + -I "mkfs.ext4" \ + -i ./create-server-root.sh /lib/dracut/hooks/initqueue/01-create-server-root.sh \ + --nomdadmconf \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.makeroot "$KVERSION" || return 1 + rm -rf -- "$TESTDIR"/overlay + + declare -a disk_args=() + # shellcheck disable=SC2034 + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker 1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/server.img root 240 + + # Invoke KVM and/or QEMU to actually create the target filesystem. + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "root=/dev/dracut/root rw rootfstype=ext4 quiet console=ttyS0,115200n81 selinux=0" \ + -initrd "$TESTDIR"/initramfs.makeroot || return 1 + test_marker_check dracut-root-block-created || return 1 + rm -- "$TESTDIR"/marker.img + + # Make server's dracut image + "$DRACUT" -l \ + -a "dash rootfs-block test kernel-modules network network-legacy" \ + -d "piix ide-gd_mod ata_piix ext4 sd_mod e1000 drbg" \ + -i "./server.link" "/etc/systemd/network/01-server.link" \ + -i ./wait-if-server.sh /lib/dracut/hooks/pre-mount/99-wait-if-server.sh \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.server "$KVERSION" || return 1 + + # Make client's dracut image + test_dracut \ + --add "$USE_NETWORK" \ + --include "./client.link" "/etc/systemd/network/01-client.link" \ + --kernel-cmdline "rw rd.auto rd.retry=50" \ + "$TESTDIR"/initramfs.testing +} + +test_cleanup() { + if [[ -s $TESTDIR/server.pid ]]; then + kill -TERM "$(cat "$TESTDIR"/server.pid)" + rm -f -- "$TESTDIR"/server.pid + fi +} + +# shellcheck disable=SC1090 +. "$testdir"/test-functions diff --git a/test/TEST-30-ISCSI/wait-if-server.sh b/test/TEST-30-ISCSI/wait-if-server.sh new file mode 100755 index 0000000..b53e41f --- /dev/null +++ b/test/TEST-30-ISCSI/wait-if-server.sh @@ -0,0 +1,4 @@ +#!/bin/sh +. /lib/net-lib.sh +wait_for_if_link enx525400123456 +wait_for_if_link enx525400123457 diff --git a/test/TEST-35-ISCSI-MULTI/Makefile b/test/TEST-35-ISCSI-MULTI/Makefile new file mode 100644 index 0000000..2dcab81 --- /dev/null +++ b/test/TEST-35-ISCSI-MULTI/Makefile @@ -0,0 +1 @@ +-include ../Makefile.testdir diff --git a/test/TEST-35-ISCSI-MULTI/client-init.sh b/test/TEST-35-ISCSI-MULTI/client-init.sh new file mode 100755 index 0000000..46a5e3f --- /dev/null +++ b/test/TEST-35-ISCSI-MULTI/client-init.sh @@ -0,0 +1,24 @@ +#!/bin/sh +. /lib/dracut-lib.sh + +export PATH=/usr/sbin:/usr/bin:/sbin:/bin +command -v plymouth > /dev/null 2>&1 && plymouth --quit +exec > /dev/console 2>&1 + +export TERM=linux +export PS1='initramfs-test:\w\$ ' +stty sane +echo "made it to the rootfs! Powering down." +while read -r dev _ fstype opts rest || [ -n "$dev" ]; do + [ "$fstype" != "ext4" ] && continue + echo "iscsi-OK $dev $fstype $opts" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker + break +done < /proc/mounts + +if getargbool 0 rd.shell; then + strstr "$(setsid --help)" "control" && CTTY="-c" + setsid $CTTY sh -i +fi + +sync +poweroff -f diff --git a/test/TEST-35-ISCSI-MULTI/client.link b/test/TEST-35-ISCSI-MULTI/client.link new file mode 100644 index 0000000..b992bfd --- /dev/null +++ b/test/TEST-35-ISCSI-MULTI/client.link @@ -0,0 +1,6 @@ +[Match] +OriginalName=* + +[Link] +NamePolicy=keep kernel database onboard slot path +MACAddressPolicy=keep diff --git a/test/TEST-35-ISCSI-MULTI/create-client-root.sh b/test/TEST-35-ISCSI-MULTI/create-client-root.sh new file mode 100755 index 0000000..267c93a --- /dev/null +++ b/test/TEST-35-ISCSI-MULTI/create-client-root.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +trap 'poweroff -f' EXIT + +# don't let udev and this script step on eachother's toes +for x in 64-lvm.rules 70-mdadm.rules 99-mount-rules; do + : > "/etc/udev/rules.d/$x" +done +rm -f -- /etc/lvm/lvm.conf +udevadm control --reload +udevadm settle + +set -ex + +mkfs.ext4 -j -L singleroot -F /dev/disk/by-id/ata-disk_singleroot +mkdir -p /sysroot +mount -t ext4 /dev/disk/by-id/ata-disk_singleroot /sysroot +cp -a -t /sysroot /source/* +umount /sysroot +mdadm --create /dev/md0 --run --auto=yes --level=stripe --raid-devices=2 /dev/disk/by-id/ata-disk_raid0-1 /dev/disk/by-id/ata-disk_raid0-2 +mdadm -W /dev/md0 || : +lvm pvcreate -ff -y /dev/md0 +lvm vgcreate dracut /dev/md0 +lvm lvcreate -l 100%FREE -n root dracut +lvm vgchange -ay +mkfs.ext4 -j -L sysroot /dev/dracut/root +mount -t ext4 /dev/dracut/root /sysroot +cp -a -t /sysroot /source/* +umount /sysroot +lvm lvchange -a n /dev/dracut/root +echo "dracut-root-block-created" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker +sync +poweroff -f diff --git a/test/TEST-35-ISCSI-MULTI/create-server-root.sh b/test/TEST-35-ISCSI-MULTI/create-server-root.sh new file mode 100755 index 0000000..2dbc2da --- /dev/null +++ b/test/TEST-35-ISCSI-MULTI/create-server-root.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +trap 'poweroff -f' EXIT + +# don't let udev and this script step on eachother's toes +for x in 64-lvm.rules 70-mdadm.rules 99-mount-rules; do + : > "/etc/udev/rules.d/$x" +done +rm -f -- /etc/lvm/lvm.conf +udevadm control --reload +udevadm settle + +mkfs.ext4 -L dracut /dev/disk/by-id/ata-disk_root +mkdir -p /root +mount -t ext4 /dev/disk/by-id/ata-disk_root /root +cp -a -t /root /source/* +mkdir -p /root/run +umount /root +echo "dracut-root-block-created" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker +poweroff -f diff --git a/test/TEST-35-ISCSI-MULTI/dhcpd.conf b/test/TEST-35-ISCSI-MULTI/dhcpd.conf new file mode 100644 index 0000000..fd306ea --- /dev/null +++ b/test/TEST-35-ISCSI-MULTI/dhcpd.conf @@ -0,0 +1,48 @@ +ddns-update-style none; + +use-host-decl-names true; + +subnet 192.168.50.0 netmask 255.255.255.0 { + option subnet-mask 255.255.255.0; + option routers 192.168.50.1; + next-server 192.168.50.1; + server-identifier 192.168.50.1; + option domain-name-servers 192.168.50.1; + option domain-search "example.com"; + option domain-name "other.com"; + + # MAC numbering scheme: + # NFSv3: last octet starts at 0x00 and works up + + group { + option root-path "iscsi:192.168.50.1:::1:iqn.2009-06.dracut:target0"; + + host iscsi-1 { + hardware ethernet 52:54:00:12:34:00; + fixed-address 192.168.50.101; + } + } +} + +subnet 192.168.51.0 netmask 255.255.255.0 { + option subnet-mask 255.255.255.0; + option routers 192.168.51.1; + next-server 192.168.51.1; + server-identifier 192.168.51.1; + option domain-name-servers 192.168.51.1; + option domain-search "example.com"; + option domain-name "other.com"; + + # MAC numbering scheme: + # NFSv3: last octet starts at 0x00 and works up + + group { + #option root-path "iscsi:192.168.51.1:::1:iqn.2009-06.dracut:target1"; + + host iscsi-2 { + hardware ethernet 52:54:00:12:34:01; + fixed-address 192.168.51.101; + } + + } +} diff --git a/test/TEST-35-ISCSI-MULTI/finished-false.sh b/test/TEST-35-ISCSI-MULTI/finished-false.sh new file mode 100755 index 0000000..ecdbef9 --- /dev/null +++ b/test/TEST-35-ISCSI-MULTI/finished-false.sh @@ -0,0 +1,2 @@ +#!/bin/sh +exit 1 diff --git a/test/TEST-35-ISCSI-MULTI/hard-off.sh b/test/TEST-35-ISCSI-MULTI/hard-off.sh new file mode 100755 index 0000000..01acb19 --- /dev/null +++ b/test/TEST-35-ISCSI-MULTI/hard-off.sh @@ -0,0 +1,3 @@ +#!/bin/sh +getargbool 0 rd.shell || poweroff -f +getargbool 0 failme && poweroff -f diff --git a/test/TEST-35-ISCSI-MULTI/hosts b/test/TEST-35-ISCSI-MULTI/hosts new file mode 100644 index 0000000..f8c18b6 --- /dev/null +++ b/test/TEST-35-ISCSI-MULTI/hosts @@ -0,0 +1,8 @@ +127.0.0.1 localhost +192.168.50.1 server +192.168.50.2 server-ip +192.168.50.3 server-proto-ip +192.168.50.100 workstation1 +192.168.50.101 workstation2 +192.168.50.102 workstation3 +192.168.50.103 workstation4 diff --git a/test/TEST-35-ISCSI-MULTI/server-init.sh b/test/TEST-35-ISCSI-MULTI/server-init.sh new file mode 100755 index 0000000..a1c3b7e --- /dev/null +++ b/test/TEST-35-ISCSI-MULTI/server-init.sh @@ -0,0 +1,88 @@ +#!/bin/sh +exec < /dev/console > /dev/console 2>&1 +set -x +export PATH=/usr/sbin:/usr/bin:/sbin:/bin +export TERM=linux +export PS1='server:\w\$ ' +stty sane +echo "made it to the rootfs!" +echo server > /proc/sys/kernel/hostname + +wait_for_if_link() { + local cnt=0 + local li + while [ $cnt -lt 600 ]; do + li=$(ip -o link show dev "$1" 2> /dev/null) + [ -n "$li" ] && return 0 + sleep 0.1 + cnt=$((cnt + 1)) + done + return 1 +} + +wait_for_if_up() { + local cnt=0 + local li + while [ $cnt -lt 200 ]; do + li=$(ip -o link show up dev "$1") + [ -n "$li" ] && return 0 + sleep 0.1 + cnt=$((cnt + 1)) + done + return 1 +} + +wait_for_route_ok() { + local cnt=0 + while [ $cnt -lt 200 ]; do + li=$(ip route show) + [ -n "$li" ] && [ -z "${li##*"$1"*}" ] && return 0 + sleep 0.1 + cnt=$((cnt + 1)) + done + return 1 +} + +linkup() { + wait_for_if_link "$1" 2> /dev/null && ip link set "$1" up 2> /dev/null && wait_for_if_up "$1" 2> /dev/null +} + +wait_for_if_link enx525400123456 +wait_for_if_link enx525400123457 + +ip addr add 127.0.0.1/8 dev lo +ip link set lo up + +ip addr add 192.168.50.1/24 dev enx525400123456 +linkup enx525400123456 + +ip addr add 192.168.51.1/24 dev enx525400123457 +linkup enx525400123457 + +modprobe af_packet + +: > /var/lib/dhcpd/dhcpd.leases +chmod 777 /var/lib/dhcpd/dhcpd.leases +dhcpd -d -cf /etc/dhcpd.conf -lf /var/lib/dhcpd/dhcpd.leases & + +tgtd +tgtadm --lld iscsi --mode target --op new --tid 1 --targetname iqn.2009-06.dracut:target0 +tgtadm --lld iscsi --mode target --op new --tid 2 --targetname iqn.2009-06.dracut:target1 +tgtadm --lld iscsi --mode target --op new --tid 3 --targetname iqn.2009-06.dracut:target2 +tgtadm --lld iscsi --mode logicalunit --op new --tid 1 --lun 1 -b /dev/disk/by-id/ata-disk_singleroot +tgtadm --lld iscsi --mode logicalunit --op new --tid 2 --lun 2 -b /dev/disk/by-id/ata-disk_raid0-1 +tgtadm --lld iscsi --mode logicalunit --op new --tid 3 --lun 3 -b /dev/disk/by-id/ata-disk_raid0-2 +tgtadm --lld iscsi --mode target --op bind --tid 1 -I 192.168.50.101 +tgtadm --lld iscsi --mode target --op bind --tid 2 -I 192.168.51.101 +tgtadm --lld iscsi --mode target --op bind --tid 3 -I 192.168.50.101 + +# Wait forever for the VM to die +echo "Serving iSCSI" +while pidof tgtd > /dev/null; do + : > /dev/watchdog + dmesg -c + sleep 1 +done +dmesg -c +mount -n -o remount,ro / +poweroff -f diff --git a/test/TEST-35-ISCSI-MULTI/server.link b/test/TEST-35-ISCSI-MULTI/server.link new file mode 100644 index 0000000..1d21856 --- /dev/null +++ b/test/TEST-35-ISCSI-MULTI/server.link @@ -0,0 +1,6 @@ +[Match] +OriginalName=* + +[Link] +NamePolicy=mac +MACAddressPolicy=keep diff --git a/test/TEST-35-ISCSI-MULTI/test.sh b/test/TEST-35-ISCSI-MULTI/test.sh new file mode 100755 index 0000000..3e649a8 --- /dev/null +++ b/test/TEST-35-ISCSI-MULTI/test.sh @@ -0,0 +1,345 @@ +#!/bin/bash + +# shellcheck disable=SC2034 +TEST_DESCRIPTION="root filesystem over multiple iSCSI with $USE_NETWORK" + +#DEBUGFAIL="rd.shell rd.break rd.debug loglevel=7 " +#SERVER_DEBUG="rd.debug loglevel=7" +#SERIAL="tcp:127.0.0.1:9999" + +run_server() { + # Start server first + echo "iSCSI TEST SETUP: Starting DHCP/iSCSI server" + + declare -a disk_args=() + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/server.img serverroot 0 1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/singleroot.img singleroot + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid0-1.img raid0-1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid0-2.img raid0-2 + + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -serial "${SERIAL:-"file:$TESTDIR/server.log"}" \ + -net nic,macaddr=52:54:00:12:34:56,model=e1000 \ + -net nic,macaddr=52:54:00:12:34:57,model=e1000 \ + -net socket,listen=127.0.0.1:12331 \ + -append "panic=1 oops=panic softlockup_panic=1 systemd.crash_reboot root=/dev/disk/by-id/ata-disk_serverroot rootfstype=ext4 rw console=ttyS0,115200n81 selinux=0 $SERVER_DEBUG" \ + -initrd "$TESTDIR"/initramfs.server \ + -pidfile "$TESTDIR"/server.pid -daemonize || return 1 + chmod 644 "$TESTDIR"/server.pid || return 1 + + # Cleanup the terminal if we have one + tty -s && stty sane + + if ! [[ $SERIAL ]]; then + while :; do + grep Serving "$TESTDIR"/server.log && break + echo "Waiting for the server to startup" + tail "$TESTDIR"/server.log + sleep 1 + done + else + echo Sleeping 10 seconds to give the server a head start + sleep 10 + fi +} + +run_client() { + local test_name=$1 + shift + echo "CLIENT TEST START: $test_name" + + declare -a disk_args=() + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker + + test_marker_reset + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -net nic,macaddr=52:54:00:12:34:00,model=e1000 \ + -net nic,macaddr=52:54:00:12:34:01,model=e1000 \ + -net socket,connect=127.0.0.1:12331 \ + -append "panic=1 oops=panic softlockup_panic=1 systemd.crash_reboot rw rd.auto rd.retry=50 console=ttyS0,115200n81 selinux=0 rd.debug=0 rd.shell=0 $DEBUGFAIL $*" \ + -initrd "$TESTDIR"/initramfs.testing + if ! test_marker_check iscsi-OK; then + echo "CLIENT TEST END: $test_name [FAILED - BAD EXIT]" + return 1 + fi + + echo "CLIENT TEST END: $test_name [OK]" + return 0 +} + +do_test_run() { + initiator=$(iscsi-iname) + run_client "netroot=iscsi target1 target2" \ + "root=LABEL=sysroot" \ + "ip=192.168.50.101:::255.255.255.0::enp0s1:off" \ + "ip=192.168.51.101:::255.255.255.0::enp0s2:off" \ + "netroot=iscsi:192.168.51.1::::iqn.2009-06.dracut:target1" \ + "netroot=iscsi:192.168.50.1::::iqn.2009-06.dracut:target2" \ + "rd.iscsi.initiator=$initiator" \ + || return 1 + + run_client "netroot=iscsi target1 target2 rd.iscsi.waitnet=0" \ + "root=LABEL=sysroot" \ + "ip=192.168.50.101:::255.255.255.0::enp0s1:off" \ + "ip=192.168.51.101:::255.255.255.0::enp0s2:off" \ + "netroot=iscsi:192.168.51.1::::iqn.2009-06.dracut:target1" \ + "netroot=iscsi:192.168.50.1::::iqn.2009-06.dracut:target2" \ + "rd.iscsi.firmware" \ + "rd.iscsi.initiator=$initiator" \ + "rd.iscsi.waitnet=0" \ + || return 1 + + run_client "netroot=iscsi target1 target2 rd.iscsi.waitnet=0 rd.iscsi.testroute=0" \ + "root=LABEL=sysroot" \ + "ip=192.168.50.101:::255.255.255.0::enp0s1:off" \ + "ip=192.168.51.101:::255.255.255.0::enp0s2:off" \ + "netroot=iscsi:192.168.51.1::::iqn.2009-06.dracut:target1" \ + "netroot=iscsi:192.168.50.1::::iqn.2009-06.dracut:target2" \ + "rd.iscsi.firmware" \ + "rd.iscsi.initiator=$initiator" \ + "rd.iscsi.waitnet=0 rd.iscsi.testroute=0" \ + || return 1 + + run_client "netroot=iscsi target1 target2 rd.iscsi.waitnet=0 rd.iscsi.testroute=0 default GW" \ + "root=LABEL=sysroot" \ + "ip=192.168.50.101::192.168.50.1:255.255.255.0::enp0s1:off" \ + "ip=192.168.51.101::192.168.51.1:255.255.255.0::enp0s2:off" \ + "netroot=iscsi:192.168.51.1::::iqn.2009-06.dracut:target1" \ + "netroot=iscsi:192.168.50.1::::iqn.2009-06.dracut:target2" \ + "rd.iscsi.firmware" \ + "rd.iscsi.initiator=$initiator" \ + "rd.iscsi.waitnet=0 rd.iscsi.testroute=0" \ + || return 1 + + echo "All tests passed [OK]" + return 0 +} + +test_run() { + if ! run_server; then + echo "Failed to start server" 1>&2 + return 1 + fi + do_test_run + ret=$? + if [[ -s $TESTDIR/server.pid ]]; then + kill -TERM "$(cat "$TESTDIR"/server.pid)" + rm -f -- "$TESTDIR"/server.pid + fi + return $ret +} + +test_check() { + if ! command -v tgtd &> /dev/null || ! command -v tgtadm &> /dev/null; then + echo "Need tgtd and tgtadm from scsi-target-utils" + return 1 + fi +} + +test_setup() { + kernel=$KVERSION + # Create what will eventually be our root filesystem onto an overlay + rm -rf -- "$TESTDIR"/overlay + ( + # shellcheck disable=SC2030 + export initdir=$TESTDIR/overlay/source + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + ( + cd "$initdir" || exit + mkdir -p -- dev sys proc etc var/run tmp + mkdir -p root usr/bin usr/lib usr/lib64 usr/sbin + mkdir -p -- var/lib/nfs/rpc_pipefs + ) + inst_multiple sh shutdown poweroff stty cat ps ln ip \ + mount dmesg mkdir cp ping grep setsid dd sync + for _terminfodir in /lib/terminfo /etc/terminfo /usr/share/terminfo; do + [ -f ${_terminfodir}/l/linux ] && break + done + inst_multiple -o ${_terminfodir}/l/linux + inst_simple /etc/os-release + + inst_simple "${PKGLIBDIR}/modules.d/99base/dracut-lib.sh" "/lib/dracut-lib.sh" + inst_simple "${PKGLIBDIR}/modules.d/99base/dracut-dev-lib.sh" "/lib/dracut-dev-lib.sh" + inst_binary "${PKGLIBDIR}/dracut-util" "/usr/bin/dracut-util" + ln -s dracut-util "${initdir}/usr/bin/dracut-getarg" + ln -s dracut-util "${initdir}/usr/bin/dracut-getargs" + + inst ./client-init.sh /sbin/init + cp -a /etc/ld.so.conf* "$initdir"/etc + ldconfig -r "$initdir" + ) + + # second, install the files needed to make the root filesystem + ( + # shellcheck disable=SC2031 + # shellcheck disable=SC2030 + export initdir=$TESTDIR/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + inst_multiple sfdisk mkfs.ext4 poweroff cp umount setsid dd sync blockdev + inst_hook initqueue 01 ./create-client-root.sh + inst_hook initqueue/finished 01 ./finished-false.sh + ) + + # create an initramfs that will create the target root filesystem. + # We do it this way so that we do not risk trashing the host mdraid + # devices, volume groups, encrypted partitions, etc. + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -m "dash crypt lvm mdraid kernel-modules qemu" \ + -d "piix ide-gd_mod ata_piix ext4 sd_mod" \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.makeroot "$KVERSION" || return 1 + rm -rf -- "$TESTDIR"/overlay + + declare -a disk_args=() + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker 1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/singleroot.img singleroot 200 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid0-1.img raid0-1 100 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/raid0-2.img raid0-2 100 + + # Invoke KVM and/or QEMU to actually create the target filesystem. + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "root=/dev/fakeroot rw rootfstype=ext4 quiet console=ttyS0,115200n81 selinux=0" \ + -initrd "$TESTDIR"/initramfs.makeroot || return 1 + test_marker_check dracut-root-block-created || return 1 + rm -- "$TESTDIR"/marker.img + + # shellcheck disable=SC2031 + export kernel=$KVERSION + rm -rf -- "$TESTDIR"/overlay + ( + mkdir -p "$TESTDIR"/overlay/source + # shellcheck disable=SC2031 + # shellcheck disable=SC2030 + export initdir=$TESTDIR/overlay/source + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + ( + cd "$initdir" || exit + mkdir -p dev sys proc etc var/run tmp var/lib/dhcpd /etc/iscsi + ) + inst /etc/passwd /etc/passwd + inst_multiple sh ls shutdown poweroff stty cat ps ln ip \ + dmesg mkdir cp ping modprobe tcpdump setsid \ + sleep mount chmod pidof + inst_multiple tgtd tgtadm + for _terminfodir in /lib/terminfo /etc/terminfo /usr/share/terminfo; do + [ -f ${_terminfodir}/l/linux ] && break + done + inst_multiple -o ${_terminfodir}/l/linux + instmods iscsi_tcp crc32c ipv6 af_packet + [ -f /etc/netconfig ] && inst_multiple /etc/netconfig + type -P dhcpd > /dev/null && inst_multiple dhcpd + inst ./server-init.sh /sbin/init + inst ./hosts /etc/hosts + inst ./dhcpd.conf /etc/dhcpd.conf + inst_multiple -o {,/usr}/etc/nsswitch.conf {,/usr}/etc/rpc \ + {,/usr}/etc/protocols {,/usr}/etc/services \ + /etc/group /etc/os-release + + _nsslibs=$( + cat "$dracutsysrootdir"/{,usr/}etc/nsswitch.conf 2> /dev/null \ + | sed -e '/^#/d' -e 's/^.*://' -e 's/\[NOTFOUND=return\]//' \ + | tr -s '[:space:]' '\n' | sort -u | tr -s '[:space:]' '|' + ) + _nsslibs=${_nsslibs#|} + _nsslibs=${_nsslibs%|} + + inst_libdir_file -n "$_nsslibs" 'libnss_*.so*' + + cp -a /etc/ld.so.conf* "$initdir"/etc + ldconfig -r "$initdir" + dracut_kernel_post + ) + + # second, install the files needed to make the root filesystem + ( + # shellcheck disable=SC2031 + # shellcheck disable=SC2030 + export initdir=$TESTDIR/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + inst_multiple sfdisk mkfs.ext4 poweroff cp umount sync dd + inst_hook initqueue 01 ./create-server-root.sh + inst_hook initqueue/finished 01 ./finished-false.sh + ) + + # create an initramfs that will create the target root filesystem. + # We do it this way so that we do not risk trashing the host mdraid + # devices, volume groups, encrypted partitions, etc. + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -m "dash rootfs-block kernel-modules qemu" \ + -d "piix ide-gd_mod ata_piix ext4 sd_mod" \ + --nomdadmconf \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.makeroot "$KVERSION" || return 1 + rm -rf -- "$TESTDIR"/overlay + + declare -a disk_args=() + # shellcheck disable=SC2034 + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker 1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/server.img root 60 + + # Invoke KVM and/or QEMU to actually create the target filesystem. + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "root=/dev/dracut/root rw rootfstype=ext4 quiet console=ttyS0,115200n81 selinux=0" \ + -initrd "$TESTDIR"/initramfs.makeroot || return 1 + test_marker_check dracut-root-block-created || return 1 + rm -- "$TESTDIR"/marker.img + + # Make an overlay with needed tools for the test harness + ( + # shellcheck disable=SC2031 + # shellcheck disable=SC2030 + export initdir=$TESTDIR/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + inst_multiple poweroff shutdown + inst_hook shutdown-emergency 000 ./hard-off.sh + inst_hook emergency 000 ./hard-off.sh + inst_simple ./client.link /etc/systemd/network/01-client.link + ) + # Make client's dracut image + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -o "plymouth dmraid nfs" \ + -a "debug ${USE_NETWORK}" \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.testing "$KVERSION" || return 1 + + ( + # shellcheck disable=SC2031 + export initdir="$TESTDIR"/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + rm "$initdir"/etc/systemd/network/01-client.link + inst_simple ./server.link /etc/systemd/network/01-server.link + inst_hook pre-mount 99 ./wait-if-server.sh + ) + # Make server's dracut image + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -a "dash rootfs-block debug kernel-modules network network-legacy" \ + -d "af_packet piix ide-gd_mod ata_piix ext4 sd_mod e1000 drbg" \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.server "$KVERSION" || return 1 + + rm -rf -- "$TESTDIR"/overlay +} + +test_cleanup() { + if [[ -s $TESTDIR/server.pid ]]; then + kill -TERM "$(cat "$TESTDIR"/server.pid)" + rm -f -- "$TESTDIR"/server.pid + fi +} + +# shellcheck disable=SC1090 +. "$testdir"/test-functions diff --git a/test/TEST-35-ISCSI-MULTI/wait-if-server.sh b/test/TEST-35-ISCSI-MULTI/wait-if-server.sh new file mode 100755 index 0000000..b53e41f --- /dev/null +++ b/test/TEST-35-ISCSI-MULTI/wait-if-server.sh @@ -0,0 +1,4 @@ +#!/bin/sh +. /lib/net-lib.sh +wait_for_if_link enx525400123456 +wait_for_if_link enx525400123457 diff --git a/test/TEST-40-NBD/Makefile b/test/TEST-40-NBD/Makefile new file mode 100644 index 0000000..2dcab81 --- /dev/null +++ b/test/TEST-40-NBD/Makefile @@ -0,0 +1 @@ +-include ../Makefile.testdir diff --git a/test/TEST-40-NBD/client-init.sh b/test/TEST-40-NBD/client-init.sh new file mode 100755 index 0000000..c5c57a2 --- /dev/null +++ b/test/TEST-40-NBD/client-init.sh @@ -0,0 +1,29 @@ +#!/bin/sh +: > /dev/watchdog +. /lib/dracut-lib.sh + +export PATH=/usr/sbin:/usr/bin:/sbin:/bin +command -v plymouth > /dev/null 2>&1 && plymouth --quit +exec > /dev/console 2>&1 + +while read -r dev fs fstype opts rest || [ -n "$dev" ]; do + [ "$dev" = "rootfs" ] && continue + [ "$fs" != "/" ] && continue + echo "nbd-OK $fstype $opts" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker + echo "nbd-OK $fstype $opts" + break +done < /proc/mounts +export TERM=linux +export PS1='nbdclient-test:\w\$ ' +stty sane +echo "made it to the rootfs! Powering down." + +if getargbool 0 rd.shell; then + strstr "$(setsid --help)" "control" && CTTY="-c" + setsid $CTTY sh -i +fi + +mount -n -o remount,ro / + +sync +poweroff -f diff --git a/test/TEST-40-NBD/client.link b/test/TEST-40-NBD/client.link new file mode 100644 index 0000000..b992bfd --- /dev/null +++ b/test/TEST-40-NBD/client.link @@ -0,0 +1,6 @@ +[Match] +OriginalName=* + +[Link] +NamePolicy=keep kernel database onboard slot path +MACAddressPolicy=keep diff --git a/test/TEST-40-NBD/create-client-root.sh b/test/TEST-40-NBD/create-client-root.sh new file mode 100755 index 0000000..a214f38 --- /dev/null +++ b/test/TEST-40-NBD/create-client-root.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +trap 'poweroff -f' EXIT + +# don't let udev and this script step on eachother's toes +for x in 64-lvm.rules 70-mdadm.rules 99-mount-rules; do + : > "/etc/udev/rules.d/$x" +done +rm -f -- /etc/lvm/lvm.conf +udevadm control --reload +set -e + +udevadm settle +mkfs.ext4 -L dracut /dev/disk/by-id/ata-disk_root +mkdir -p /root +mount -t ext4 /dev/disk/by-id/ata-disk_root /root +cp -a -t /root /source/* +mkdir -p /root/run +umount /root +{ + echo "dracut-root-block-created" + echo "ID_FS_UUID=$ID_FS_UUID" +} | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker +poweroff -f diff --git a/test/TEST-40-NBD/create-encrypted-root.sh b/test/TEST-40-NBD/create-encrypted-root.sh new file mode 100755 index 0000000..0ea90e3 --- /dev/null +++ b/test/TEST-40-NBD/create-encrypted-root.sh @@ -0,0 +1,41 @@ +#!/bin/sh + +trap 'poweroff -f' EXIT + +# don't let udev and this script step on eachother's toes +for x in 64-lvm.rules 70-mdadm.rules 99-mount-rules; do + : > "/etc/udev/rules.d/$x" +done +rm -f -- /etc/lvm/lvm.conf +udevadm control --reload +udevadm settle + +set -ex + +printf test > keyfile +cryptsetup -q luksFormat /dev/disk/by-id/ata-disk_root /keyfile +echo "The passphrase is test" +cryptsetup luksOpen /dev/disk/by-id/ata-disk_root dracut_crypt_test < /keyfile +lvm pvcreate -ff -y /dev/mapper/dracut_crypt_test +lvm vgcreate dracut /dev/mapper/dracut_crypt_test +lvm lvcreate -l 100%FREE -n root dracut +lvm vgchange -ay +udevadm settle +mkfs.ext4 -L dracut -j /dev/dracut/root +mkdir -p /sysroot +mount -t ext4 /dev/dracut/root /sysroot +cp -a -t /sysroot /source/* +umount /sysroot +sleep 1 +lvm lvchange -a n /dev/dracut/root +udevadm settle +cryptsetup luksClose /dev/mapper/dracut_crypt_test +udevadm settle +sleep 1 +eval "$(udevadm info --query=property --name=/dev/disk/by-id/ata-disk_root | while read -r line || [ -n "$line" ]; do [ "$line" != "${line#*ID_FS_UUID*}" ] && echo "$line"; done)" +{ + echo "dracut-root-block-created" + echo "ID_FS_UUID=$ID_FS_UUID" +} | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker +sync +poweroff -f diff --git a/test/TEST-40-NBD/create-server-root.sh b/test/TEST-40-NBD/create-server-root.sh new file mode 100755 index 0000000..de4d670 --- /dev/null +++ b/test/TEST-40-NBD/create-server-root.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +trap 'poweroff -f' EXIT + +# don't let udev and this script step on eachother's toes +for x in 64-lvm.rules 70-mdadm.rules 99-mount-rules; do + : > "/etc/udev/rules.d/$x" +done +rm -f -- /etc/lvm/lvm.conf +udevadm control --reload +udevadm settle +set -e + +udevadm settle +mkfs.ext4 -L dracut /dev/disk/by-id/ata-disk_root +mkdir -p /root +mount -t ext4 /dev/disk/by-id/ata-disk_root /root +cp -a -t /root /source/* +mkdir -p /root/run +umount /root +{ + echo "dracut-root-block-created" + echo "ID_FS_UUID=$ID_FS_UUID" +} | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker +sync +poweroff -f diff --git a/test/TEST-40-NBD/cryptroot-ask.sh b/test/TEST-40-NBD/cryptroot-ask.sh new file mode 100755 index 0000000..a6b7ac7 --- /dev/null +++ b/test/TEST-40-NBD/cryptroot-ask.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +[ -b /dev/mapper/"$2" ] && exit 0 +printf test > /keyfile +/sbin/cryptsetup luksOpen "$1" "$2" < /keyfile diff --git a/test/TEST-40-NBD/dhcpd.conf b/test/TEST-40-NBD/dhcpd.conf new file mode 100644 index 0000000..08461f9 --- /dev/null +++ b/test/TEST-40-NBD/dhcpd.conf @@ -0,0 +1,66 @@ +ddns-update-style none; + +use-host-decl-names true; + +subnet 192.168.50.0 netmask 255.255.255.0 { + option subnet-mask 255.255.255.0; + option routers 192.168.50.1; + next-server 192.168.50.1; + server-identifier 192.168.50.1; + option domain-name-servers 192.168.50.1; + option domain-search "example.com"; + option domain-name "other.com"; + + group { + host nbd-1 { + hardware ethernet 52:54:00:12:34:00; + fixed-address 192.168.50.101; + } + } + + group { + host nbd-2 { + option root-path "nbd:192.168.50.1:raw"; + + hardware ethernet 52:54:00:12:34:01; + fixed-address 192.168.50.101; + } + } + + group { + host nbd-3 { + option root-path "nbd:192.168.50.1:raw:ext2"; + + hardware ethernet 52:54:00:12:34:02; + fixed-address 192.168.50.101; + } + } + + group { + host nbd-4 { + option root-path "nbd:192.168.50.1:raw::errors=panic"; + + hardware ethernet 52:54:00:12:34:03; + fixed-address 192.168.50.101; + } + } + + group { + host nbd-5 { + option root-path "nbd:192.168.50.1:raw:ext2:errors=panic"; + + hardware ethernet 52:54:00:12:34:04; + fixed-address 192.168.50.101; + } + } + + group { + host nbd-6 { + # Use the encrypted image + option root-path "nbd:192.168.50.1:encrypted:ext2:errors=panic"; + + hardware ethernet 52:54:00:12:34:05; + fixed-address 192.168.50.101; + } + } +} diff --git a/test/TEST-40-NBD/finished-false.sh b/test/TEST-40-NBD/finished-false.sh new file mode 100755 index 0000000..ecdbef9 --- /dev/null +++ b/test/TEST-40-NBD/finished-false.sh @@ -0,0 +1,2 @@ +#!/bin/sh +exit 1 diff --git a/test/TEST-40-NBD/hard-off.sh b/test/TEST-40-NBD/hard-off.sh new file mode 100755 index 0000000..01acb19 --- /dev/null +++ b/test/TEST-40-NBD/hard-off.sh @@ -0,0 +1,3 @@ +#!/bin/sh +getargbool 0 rd.shell || poweroff -f +getargbool 0 failme && poweroff -f diff --git a/test/TEST-40-NBD/hosts b/test/TEST-40-NBD/hosts new file mode 100644 index 0000000..f8c18b6 --- /dev/null +++ b/test/TEST-40-NBD/hosts @@ -0,0 +1,8 @@ +127.0.0.1 localhost +192.168.50.1 server +192.168.50.2 server-ip +192.168.50.3 server-proto-ip +192.168.50.100 workstation1 +192.168.50.101 workstation2 +192.168.50.102 workstation3 +192.168.50.103 workstation4 diff --git a/test/TEST-40-NBD/server-init.sh b/test/TEST-40-NBD/server-init.sh new file mode 100755 index 0000000..bc52b2e --- /dev/null +++ b/test/TEST-40-NBD/server-init.sh @@ -0,0 +1,68 @@ +#!/bin/sh +exec < /dev/console > /dev/console 2>&1 +set -x +export PATH=/usr/sbin:/usr/bin:/sbin:/bin +export TERM=linux +export PS1='nbdtest-server:\w\$ ' +stty sane +echo "made it to the rootfs!" +echo server > /proc/sys/kernel/hostname + +wait_for_if_link() { + local cnt=0 + local li + while [ $cnt -lt 600 ]; do + li=$(ip -o link show dev "$1" 2> /dev/null) + [ -n "$li" ] && return 0 + sleep 0.1 + cnt=$((cnt + 1)) + done + return 1 +} + +wait_for_if_up() { + local cnt=0 + local li + while [ $cnt -lt 200 ]; do + li=$(ip -o link show up dev "$1") + [ -n "$li" ] && return 0 + sleep 0.1 + cnt=$((cnt + 1)) + done + return 1 +} + +wait_for_route_ok() { + local cnt=0 + while [ $cnt -lt 200 ]; do + li=$(ip route show) + [ -n "$li" ] && [ -z "${li##*"$1"*}" ] && return 0 + sleep 0.1 + cnt=$((cnt + 1)) + done + return 1 +} + +linkup() { + wait_for_if_link "$1" 2> /dev/null && ip link set "$1" up 2> /dev/null && wait_for_if_up "$1" 2> /dev/null +} + +ip addr add 127.0.0.1/8 dev lo +ip link set lo up + +wait_for_if_link enx525400123456 +ip addr add 192.168.50.1/24 dev enx525400123456 +linkup enx525400123456 + +modprobe af_packet +nbd-server +: > /var/lib/dhcpd/dhcpd.leases +chmod 777 /var/lib/dhcpd/dhcpd.leases +dhcpd -d -cf /etc/dhcpd.conf -lf /var/lib/dhcpd/dhcpd.leases & +echo "Serving NBD disks" +while pidof nbd-server && pidof dhcpd; do + echo > /dev/watchdog + sleep 1 +done +mount -n -o remount,ro / +poweroff -f diff --git a/test/TEST-40-NBD/server.link b/test/TEST-40-NBD/server.link new file mode 100644 index 0000000..1d21856 --- /dev/null +++ b/test/TEST-40-NBD/server.link @@ -0,0 +1,6 @@ +[Match] +OriginalName=* + +[Link] +NamePolicy=mac +MACAddressPolicy=keep diff --git a/test/TEST-40-NBD/test.sh b/test/TEST-40-NBD/test.sh new file mode 100755 index 0000000..7fd1efc --- /dev/null +++ b/test/TEST-40-NBD/test.sh @@ -0,0 +1,507 @@ +#!/bin/bash + +# shellcheck disable=SC2034 +TEST_DESCRIPTION="root filesystem on NBD with $USE_NETWORK" + +# Uncomment this to debug failures +# DEBUGFAIL="rd.debug systemd.log_target=console loglevel=7" +#DEBUGFAIL="rd.shell rd.break rd.debug systemd.log_target=console loglevel=7 systemd.log_level=debug" +#SERIAL="tcp:127.0.0.1:9999" + +test_check() { + if ! type -p nbd-server &> /dev/null; then + echo "Test needs nbd-server... Skipping" + return 1 + fi + + if ! modinfo -k "$KVERSION" nbd &> /dev/null; then + echo "Kernel module nbd does not exist" + return 1 + fi + + return 0 +} + +run_server() { + # Start server first + echo "NBD TEST SETUP: Starting DHCP/NBD server" + + declare -a disk_args=() + # shellcheck disable=SC2034 + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/unencrypted.img unencrypted + qemu_add_drive_args disk_index disk_args "$TESTDIR"/encrypted.img encrypted + qemu_add_drive_args disk_index disk_args "$TESTDIR"/server.img serverroot + + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -serial "${SERIAL:-"file:$TESTDIR/server.log"}" \ + -net nic,macaddr=52:54:00:12:34:56,model=e1000 \ + -net socket,listen=127.0.0.1:12340 \ + -append "panic=1 oops=panic softlockup_panic=1 rd.luks=0 systemd.crash_reboot quiet root=/dev/disk/by-id/ata-disk_serverroot rootfstype=ext4 rw console=ttyS0,115200n81 selinux=0 $SERVER_DEBUG" \ + -initrd "$TESTDIR"/initramfs.server \ + -pidfile "$TESTDIR"/server.pid -daemonize || return 1 + chmod 644 "$TESTDIR"/server.pid || return 1 + + # Cleanup the terminal if we have one + tty -s && stty sane + + if ! [[ $SERIAL ]]; then + echo "Waiting for the server to startup" + while :; do + grep Serving "$TESTDIR"/server.log && break + tail "$TESTDIR"/server.log + sleep 1 + done + else + echo Sleeping 10 seconds to give the server a head start + sleep 10 + fi +} + +client_test() { + local test_name="$1" + local mac=$2 + local cmdline="$3" + local fstype=$4 + local fsopt=$5 + local found opts nbdinfo + + [[ $fstype ]] || fstype=ext4 + [[ $fsopt ]] || fsopt="ro" + + echo "CLIENT TEST START: $test_name" + + declare -a disk_args=() + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker + + test_marker_reset + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -net nic,macaddr="$mac",model=e1000 \ + -net socket,connect=127.0.0.1:12340 \ + -append "panic=1 oops=panic softlockup_panic=1 systemd.crash_reboot rd.shell=0 $cmdline $DEBUGFAIL rd.auto rd.info rd.retry=10 ro console=ttyS0,115200n81 selinux=0 " \ + -initrd "$TESTDIR"/initramfs.testing + + # shellcheck disable=SC2181 + if [[ $? -ne 0 ]] || ! test_marker_check nbd-OK "$TESTDIR"/marker.img; then + echo "CLIENT TEST END: $test_name [FAILED - BAD EXIT]" + return 1 + fi + + # nbdinfo=( fstype fsoptions ) + read -r -a nbdinfo < <(awk '{print $2, $3; exit}' "$TESTDIR"/marker.img) + + if [[ ${nbdinfo[0]} != "$fstype" ]]; then + echo "CLIENT TEST END: $test_name [FAILED - WRONG FS TYPE] \"${nbdinfo[0]}\" != \"$fstype\"" + return 1 + fi + + opts=${nbdinfo[1]}, + while [[ $opts ]]; do + if [[ ${opts%%,*} == "$fsopt" ]]; then + found=1 + break + fi + opts=${opts#*,} + done + + if [[ ! $found ]]; then + echo "CLIENT TEST END: $test_name [FAILED - BAD FS OPTS] \"${nbdinfo[1]}\" != \"$fsopt\"" + return 1 + fi + + echo "CLIENT TEST END: $test_name [OK]" +} + +test_run() { + if ! run_server; then + echo "Failed to start server" 1>&2 + return 1 + fi + client_run + kill_server +} + +client_run() { + # The default is ext4,errors=continue so use that to determine + # if our options were parsed and used + client_test "NBD root=nbd:IP:port" 52:54:00:12:34:00 \ + "root=nbd:192.168.50.1:raw rd.luks=0" || return 1 + + client_test "NBD root=nbd:IP:port::fsopts" 52:54:00:12:34:00 \ + "root=nbd:192.168.50.1:raw::errors=panic rd.luks=0" \ + ext4 errors=panic || return 1 + + client_test "NBD root=nbd:IP:port:fstype" 52:54:00:12:34:00 \ + "root=nbd:192.168.50.1:raw:ext4 rd.luks=0" ext4 || return 1 + + client_test "NBD root=nbd:IP:port:fstype:fsopts" 52:54:00:12:34:00 \ + "root=nbd:192.168.50.1:raw:ext4:errors=panic rd.luks=0" \ + ext4 errors=panic || return 1 + + # DHCP root-path parsing + + client_test "NBD root=/dev/root netroot=dhcp DHCP root-path nbd:srv:port" 52:54:00:12:34:01 \ + "root=/dev/root netroot=dhcp ip=dhcp rd.luks=0" || return 1 + + client_test "NBD root=/dev/root netroot=dhcp DHCP root-path nbd:srv:port:fstype" \ + 52:54:00:12:34:02 "root=/dev/root netroot=dhcp ip=dhcp rd.luks=0" ext2 || return 1 + + client_test "NBD root=/dev/root netroot=dhcp DHCP root-path nbd:srv:port::fsopts" \ + 52:54:00:12:34:03 "root=/dev/root netroot=dhcp ip=dhcp rd.luks=0" ext4 errors=panic || return 1 + + client_test "NBD root=/dev/root netroot=dhcp DHCP root-path nbd:srv:port:fstype:fsopts" \ + 52:54:00:12:34:04 "root=/dev/root netroot=dhcp ip=dhcp rd.luks=0" ext2 errors=panic || return 1 + + # netroot handling + + client_test "NBD netroot=nbd:IP:port" 52:54:00:12:34:00 \ + "root=LABEL=dracut netroot=nbd:192.168.50.1:raw ip=dhcp rd.luks=0" || return 1 + + client_test "NBD root=/dev/root netroot=dhcp DHCP root-path nbd:srv:port:fstype:fsopts" \ + 52:54:00:12:34:04 "root=/dev/root netroot=dhcp ip=dhcp rd.luks=0" ext2 errors=panic || return 1 + + # Encrypted root handling via LVM/LUKS over NBD + + # shellcheck disable=SC1090 + . "$TESTDIR"/luks.uuid + + client_test "NBD root=LABEL=dracut netroot=nbd:IP:port" \ + 52:54:00:12:34:00 \ + "root=LABEL=dracut rd.luks.uuid=$ID_FS_UUID rd.lv.vg=dracut ip=dhcp netroot=nbd:192.168.50.1:encrypted" || return 1 + + # XXX This should be ext4,errors=panic but that doesn't currently + # XXX work when you have a real root= line in addition to netroot= + # XXX How we should work here needs clarification + # client_test "NBD root=LABEL=dracut netroot=dhcp (w/ fstype and opts)" \ + # 52:54:00:12:34:05 \ + # "root=LABEL=dracut rd.luks.uuid=$ID_FS_UUID rd.lv.vg=dracut netroot=dhcp" || return 1 + + if [[ -s server.pid ]]; then + kill -TERM "$(cat "$TESTDIR"/server.pid)" + rm -f -- "$TESTDIR"/server.pid + fi + +} + +make_encrypted_root() { + rm -fr "$TESTDIR"/overlay + kernel=$KVERSION + # Create what will eventually be our root filesystem onto an overlay + ( + # shellcheck disable=SC2030 + export initdir=$TESTDIR/overlay/source + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + mkdir -p "$initdir" + ( + cd "$initdir" || exit + mkdir -p dev sys proc etc run var/run tmp + ) + + inst_multiple sh df free ls shutdown poweroff stty cat ps ln ip \ + mount dmesg mkdir cp ping dd sync + for _terminfodir in /lib/terminfo /etc/terminfo /usr/share/terminfo; do + [ -f ${_terminfodir}/l/linux ] && break + done + inst_multiple -o ${_terminfodir}/l/linux + + inst_simple "${PKGLIBDIR}/modules.d/99base/dracut-lib.sh" "/lib/dracut-lib.sh" + inst_simple "${PKGLIBDIR}/modules.d/99base/dracut-dev-lib.sh" "/lib/dracut-dev-lib.sh" + inst_binary "${PKGLIBDIR}/dracut-util" "/usr/bin/dracut-util" + ln -s dracut-util "${initdir}/usr/bin/dracut-getarg" + ln -s dracut-util "${initdir}/usr/bin/dracut-getargs" + + inst ./client-init.sh /sbin/init + inst_simple /etc/os-release + find_binary plymouth > /dev/null && inst_multiple plymouth + cp -a /etc/ld.so.conf* "$initdir"/etc + ldconfig -r "$initdir" + ) + + # second, install the files needed to make the root filesystem + ( + # shellcheck disable=SC2030 + # shellcheck disable=SC2031 + export initdir=$TESTDIR/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + ( + cd "$initdir" || exit + mkdir -p dev sys proc etc tmp var run root + ln -s ../run var/run + ) + inst_multiple mkfs.ext4 poweroff cp umount dd sync + inst_hook shutdown-emergency 000 ./hard-off.sh + inst_hook emergency 000 ./hard-off.sh + inst_hook initqueue 01 ./create-encrypted-root.sh + inst_hook initqueue/finished 01 ./finished-false.sh + ) + + # create an initramfs that will create the target root filesystem. + # We do it this way so that we do not risk trashing the host mdraid + # devices, volume groups, encrypted partitions, etc. + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -m "dash crypt lvm mdraid kernel-modules qemu" \ + -d "piix ide-gd_mod ata_piix ext4 sd_mod" \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.makeroot "$KVERSION" || return 1 + rm -rf -- "$TESTDIR"/overlay + + declare -a disk_args=() + # shellcheck disable=SC2034 + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker 1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/encrypted.img root 120 + + # Invoke KVM and/or QEMU to actually create the target filesystem. + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "root=/dev/fakeroot rw quiet console=ttyS0,115200n81 selinux=0" \ + -initrd "$TESTDIR"/initramfs.makeroot || return 1 + test_marker_check dracut-root-block-created || return 1 + grep -F -a -m 1 ID_FS_UUID "$TESTDIR"/marker.img > "$TESTDIR"/luks.uuid +} + +make_client_root() { + rm -fr "$TESTDIR"/overlay + kernel=$KVERSION + ( + mkdir -p "$TESTDIR"/overlay/source + # shellcheck disable=SC2030 + # shellcheck disable=SC2031 + export initdir=$TESTDIR/overlay/source + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + mkdir -p "$initdir" + ( + cd "$initdir" || exit + mkdir -p dev sys proc etc run var/run tmp + ) + inst_multiple sh ls shutdown poweroff stty cat ps ln ip \ + dmesg mkdir cp ping dd mount sync + for _terminfodir in /lib/terminfo /etc/terminfo /usr/share/terminfo; do + [ -f ${_terminfodir}/l/linux ] && break + done + inst_multiple -o ${_terminfodir}/l/linux + + inst_simple "${PKGLIBDIR}/modules.d/99base/dracut-lib.sh" "/lib/dracut-lib.sh" + inst_simple "${PKGLIBDIR}/modules.d/99base/dracut-dev-lib.sh" "/lib/dracut-dev-lib.sh" + inst_binary "${PKGLIBDIR}/dracut-util" "/usr/bin/dracut-util" + ln -s dracut-util "${initdir}/usr/bin/dracut-getarg" + ln -s dracut-util "${initdir}/usr/bin/dracut-getargs" + + inst ./client-init.sh /sbin/init + inst_simple /etc/os-release + inst_multiple -o {,/usr}/etc/nsswitch.conf + inst /etc/passwd /etc/passwd + inst /etc/group /etc/group + for i in /usr/lib*/libnss_files* /lib*/libnss_files*; do + [ -e "$i" ] || continue + inst "$i" + done + cp -a /etc/ld.so.conf* "$initdir"/etc + ldconfig -r "$initdir" + ) + + # second, install the files needed to make the root filesystem + ( + # shellcheck disable=SC2030 + # shellcheck disable=SC2031 + export initdir=$TESTDIR/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + inst_multiple sfdisk mkfs.ext4 poweroff cp umount sync dd + inst_hook initqueue 01 ./create-client-root.sh + inst_hook initqueue/finished 01 ./finished-false.sh + ) + + # create an initramfs that will create the target root filesystem. + # We do it this way so that we do not risk trashing the host mdraid + # devices, volume groups, encrypted partitions, etc. + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -m "dash rootfs-block kernel-modules qemu" \ + -d "piix ide-gd_mod ata_piix ext4 sd_mod" \ + --nomdadmconf \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.makeroot "$KVERSION" || return 1 + + declare -a disk_args=() + # shellcheck disable=SC2034 + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker 1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/unencrypted.img root 120 + + # Invoke KVM and/or QEMU to actually create the target filesystem. + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "root=/dev/dracut/root rw rootfstype=ext4 quiet console=ttyS0,115200n81 selinux=0" \ + -initrd "$TESTDIR"/initramfs.makeroot || return 1 + test_marker_check dracut-root-block-created || return 1 + rm -fr "$TESTDIR"/overlay +} + +make_server_root() { + rm -fr "$TESTDIR"/overlay + # shellcheck disable=SC2031 + export kernel=$KVERSION + ( + mkdir -p "$TESTDIR"/overlay/source + # shellcheck disable=SC2030 + # shellcheck disable=SC2031 + export initdir=$TESTDIR/overlay/source + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + mkdir -p "$initdir" + ( + cd "$initdir" || exit + mkdir -p run dev sys proc etc var var/lib/dhcpd tmp etc/nbd-server + ln -s ../run var/run + ) + cat > "$initdir/etc/nbd-server/config" << EOF +[generic] +[raw] +exportname = /dev/disk/by-id/ata-disk_unencrypted +port = 2000 +bs = 4096 +[encrypted] +exportname = /dev/disk/by-id/ata-disk_encrypted +port = 2001 +bs = 4096 +EOF + inst_multiple sh ls shutdown poweroff stty cat ps ln ip \ + dmesg mkdir cp ping grep \ + sleep nbd-server chmod modprobe vi pidof + for _terminfodir in /lib/terminfo /etc/terminfo /usr/share/terminfo; do + [ -f ${_terminfodir}/l/linux ] && break + done + inst_multiple -o ${_terminfodir}/l/linux + instmods nfsd sunrpc ipv6 lockd af_packet 8021q ipvlan macvlan + type -P dhcpd > /dev/null && inst_multiple dhcpd + inst ./server-init.sh /sbin/init + inst_simple /etc/os-release + inst ./hosts /etc/hosts + inst ./dhcpd.conf /etc/dhcpd.conf + inst_multiple -o {,/usr}/etc/nsswitch.conf + inst /etc/passwd /etc/passwd + inst /etc/group /etc/group + _nsslibs=$( + cat "$dracutsysrootdir"/{,usr/}etc/nsswitch.conf 2> /dev/null \ + | sed -e '/^#/d' -e 's/^.*://' -e 's/\[NOTFOUND=return\]//' \ + | tr -s '[:space:]' '\n' | sort -u | tr -s '[:space:]' '|' + ) + _nsslibs=${_nsslibs#|} + _nsslibs=${_nsslibs%|} + + inst_libdir_file -n "$_nsslibs" 'libnss_*.so*' + + cp -a /etc/ld.so.conf* "$initdir"/etc + ldconfig -r "$initdir" + dracut_kernel_post + ) + + # second, install the files needed to make the root filesystem + ( + # shellcheck disable=SC2030 + # shellcheck disable=SC2031 + export initdir=$TESTDIR/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + inst_multiple sfdisk mkfs.ext4 poweroff cp umount sync dd sync + inst_hook initqueue 01 ./create-server-root.sh + inst_hook initqueue/finished 01 ./finished-false.sh + ) + + # create an initramfs that will create the target root filesystem. + # We do it this way so that we do not risk trashing the host mdraid + # devices, volume groups, encrypted partitions, etc. + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -m "dash rootfs-block kernel-modules qemu" \ + -d "piix ide-gd_mod ata_piix ext4 sd_mod" \ + --nomdadmconf \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.makeroot "$KVERSION" || return 1 + + declare -a disk_args=() + # shellcheck disable=SC2034 + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker 1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/server.img root 120 + + # Invoke KVM and/or QEMU to actually create the target filesystem. + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "root=/dev/dracut/root rw rootfstype=ext4 quiet console=ttyS0,115200n81 selinux=0" \ + -initrd "$TESTDIR"/initramfs.makeroot || return 1 + test_marker_check dracut-root-block-created || return 1 + rm -fr "$TESTDIR"/overlay +} + +test_setup() { + make_encrypted_root || return 1 + make_client_root || return 1 + make_server_root || return 1 + + rm -fr "$TESTDIR"/overlay + # Make the test image + ( + # shellcheck disable=SC2031 + # shellcheck disable=SC2030 + export initdir=$TESTDIR/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + inst_multiple poweroff shutdown dd + inst_hook shutdown-emergency 000 ./hard-off.sh + inst ./cryptroot-ask.sh /sbin/cryptroot-ask + + # inst ./debug-shell.service /lib/systemd/system/debug-shell.service + # mkdir -p "${initdir}/lib/systemd/system/sysinit.target.wants" + # ln -fs ../debug-shell.service "${initdir}/lib/systemd/system/sysinit.target.wants/debug-shell.service" + + # shellcheck disable=SC1090 + . "$TESTDIR"/luks.uuid + mkdir -p "$initdir"/etc + echo "luks-$ID_FS_UUID /dev/nbd0 /etc/key" > "$initdir"/etc/crypttab + echo -n test > "$initdir"/etc/key + inst_simple ./client.link /etc/systemd/network/01-client.link + ) + + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -o "plymouth iscsi nfs" \ + -a "debug watchdog ${USE_NETWORK}" \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.testing "$KVERSION" || return 1 + + ( + # shellcheck disable=SC2031 + export initdir="$TESTDIR"/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + rm "$initdir"/etc/systemd/network/01-client.link + inst_simple ./server.link /etc/systemd/network/01-server.link + inst_hook pre-mount 99 ./wait-if-server.sh + ) + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -a "rootfs-block debug kernel-modules network network-legacy" \ + -d "af_packet piix ide-gd_mod ata_piix ext4 sd_mod e1000 drbg" \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.server "$KVERSION" || return 1 + + rm -rf -- "$TESTDIR"/overlay +} + +kill_server() { + if [[ -s $TESTDIR/server.pid ]]; then + kill -TERM "$(cat "$TESTDIR"/server.pid)" + rm -f -- "$TESTDIR"/server.pid + fi +} + +test_cleanup() { + kill_server +} + +# shellcheck disable=SC1090 +. "$testdir"/test-functions diff --git a/test/TEST-40-NBD/wait-if-server.sh b/test/TEST-40-NBD/wait-if-server.sh new file mode 100755 index 0000000..8ae21f8 --- /dev/null +++ b/test/TEST-40-NBD/wait-if-server.sh @@ -0,0 +1,3 @@ +#!/bin/sh +. /lib/net-lib.sh +wait_for_if_link enx525400123456 diff --git a/test/TEST-50-MULTINIC/Makefile b/test/TEST-50-MULTINIC/Makefile new file mode 100644 index 0000000..2dcab81 --- /dev/null +++ b/test/TEST-50-MULTINIC/Makefile @@ -0,0 +1 @@ +-include ../Makefile.testdir diff --git a/test/TEST-50-MULTINIC/client-init.sh b/test/TEST-50-MULTINIC/client-init.sh new file mode 100755 index 0000000..4c51e27 --- /dev/null +++ b/test/TEST-50-MULTINIC/client-init.sh @@ -0,0 +1,40 @@ +#!/bin/sh +. /lib/dracut-lib.sh + +export PATH=/usr/sbin:/usr/bin:/sbin:/bin +command -v plymouth > /dev/null 2>&1 && plymouth --quit +exec > /dev/console 2>&1 + +export TERM=linux +export PS1='initramfs-test:\w\$ ' +stty sane +echo "made it to the rootfs! Powering down." + +set -x + +for i in /sys/class/net/*; do + # booting with network-manager module + state=/run/NetworkManager/devices/$(cat "$i"/ifindex) + grep -q connection-uuid= "$state" 2> /dev/null || continue + i=${i##*/} + [ "$i" = lo ] && continue + ip link show "$i" | grep -q master && continue + IFACES="${IFACES}${i} " +done + +for i in /run/initramfs/net.*.did-setup; do + # booting with network-legacy module + [ -f "$i" ] || continue + strglobin "$i" ":*:*:*:*:" && continue + i=${i%.did-setup} + IFACES="${IFACES}${i##*/net.} " +done +{ + echo "OK" + echo "$IFACES" +} | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker + +getargbool 0 rd.shell && sh -i + +sync +poweroff -f diff --git a/test/TEST-50-MULTINIC/client.link b/test/TEST-50-MULTINIC/client.link new file mode 100644 index 0000000..b992bfd --- /dev/null +++ b/test/TEST-50-MULTINIC/client.link @@ -0,0 +1,6 @@ +[Match] +OriginalName=* + +[Link] +NamePolicy=keep kernel database onboard slot path +MACAddressPolicy=keep diff --git a/test/TEST-50-MULTINIC/create-root.sh b/test/TEST-50-MULTINIC/create-root.sh new file mode 100755 index 0000000..8060b00 --- /dev/null +++ b/test/TEST-50-MULTINIC/create-root.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +trap 'poweroff -f' EXIT + +# don't let udev and this script step on eachother's toes +for x in 64-lvm.rules 70-mdadm.rules 99-mount-rules; do + : > "/etc/udev/rules.d/$x" +done +rm -f -- /etc/lvm/lvm.conf +udevadm control --reload +udevadm settle + +set -ex + +mkfs.ext4 -L dracut /dev/disk/by-id/ata-disk_root +mkdir -p /root +mount -t ext4 /dev/disk/by-id/ata-disk_root /root +cp -a -t /root /source/* +mkdir -p /root/run +umount /root +echo "dracut-root-block-created" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker +sync +poweroff -f diff --git a/test/TEST-50-MULTINIC/dhcpd.conf b/test/TEST-50-MULTINIC/dhcpd.conf new file mode 100644 index 0000000..be8dee7 --- /dev/null +++ b/test/TEST-50-MULTINIC/dhcpd.conf @@ -0,0 +1,36 @@ +ddns-update-style none; + +use-host-decl-names true; + +subnet 192.168.50.0 netmask 255.255.255.0 { + option subnet-mask 255.255.255.0; + option routers 192.168.50.1; + next-server 192.168.50.1; + server-identifier 192.168.50.1; + option domain-name-servers 192.168.50.1; + option domain-search "example.com"; + option domain-name "other.com"; + + group { + host client-if1 { + hardware ethernet 52:54:00:12:34:00; + fixed-address 192.168.50.100; + } + } + + group { + host client-if2 { + hardware ethernet 52:54:00:12:34:01; + fixed-address 192.168.50.101; + } + } + + group { + option root-path "nfs:192.168.50.1:/nfs/client"; + + host client-if3 { + hardware ethernet 52:54:00:12:34:02; + fixed-address 192.168.50.102; + } + } +} diff --git a/test/TEST-50-MULTINIC/exports b/test/TEST-50-MULTINIC/exports new file mode 100644 index 0000000..ff5f29b --- /dev/null +++ b/test/TEST-50-MULTINIC/exports @@ -0,0 +1 @@ +/nfs/client 192.168.50.0/24(rw,insecure,no_subtree_check,no_root_squash) diff --git a/test/TEST-50-MULTINIC/finished-false.sh b/test/TEST-50-MULTINIC/finished-false.sh new file mode 100755 index 0000000..ecdbef9 --- /dev/null +++ b/test/TEST-50-MULTINIC/finished-false.sh @@ -0,0 +1,2 @@ +#!/bin/sh +exit 1 diff --git a/test/TEST-50-MULTINIC/hard-off.sh b/test/TEST-50-MULTINIC/hard-off.sh new file mode 100755 index 0000000..01acb19 --- /dev/null +++ b/test/TEST-50-MULTINIC/hard-off.sh @@ -0,0 +1,3 @@ +#!/bin/sh +getargbool 0 rd.shell || poweroff -f +getargbool 0 failme && poweroff -f diff --git a/test/TEST-50-MULTINIC/hosts b/test/TEST-50-MULTINIC/hosts new file mode 100644 index 0000000..d02a4e9 --- /dev/null +++ b/test/TEST-50-MULTINIC/hosts @@ -0,0 +1,5 @@ +127.0.0.1 localhost +192.168.50.1 server +192.168.50.100 client-if1 +192.168.50.101 client-if2 +192.168.50.102 client-if3 diff --git a/test/TEST-50-MULTINIC/server-init.sh b/test/TEST-50-MULTINIC/server-init.sh new file mode 100755 index 0000000..997b1d1 --- /dev/null +++ b/test/TEST-50-MULTINIC/server-init.sh @@ -0,0 +1,98 @@ +#!/bin/bash +exec < /dev/console > /dev/console 2>&1 +set -x +export PATH=/usr/sbin:/usr/bin:/sbin:/bin +export TERM=linux +export PS1='nfstest-server:\w\$ ' +: > /dev/watchdog +stty sane +echo "made it to the rootfs!" +echo server > /proc/sys/kernel/hostname + +wait_for_if_link() { + local cnt=0 + local li + while [ $cnt -lt 600 ]; do + li=$(ip -o link show dev "$1" 2> /dev/null) + [ -n "$li" ] && return 0 + sleep 0.1 + cnt=$((cnt + 1)) + done + return 1 +} + +wait_for_if_up() { + local cnt=0 + local li + while [ $cnt -lt 200 ]; do + li=$(ip -o link show up dev "$1") + [ -n "$li" ] && return 0 + sleep 0.1 + cnt=$((cnt + 1)) + done + return 1 +} + +wait_for_route_ok() { + local cnt=0 + while [ $cnt -lt 200 ]; do + li=$(ip route show) + [ -n "$li" ] && [ -z "${li##*"$1"*}" ] && return 0 + sleep 0.1 + cnt=$((cnt + 1)) + done + return 1 +} + +linkup() { + wait_for_if_link "$1" 2> /dev/null && ip link set "$1" up 2> /dev/null && wait_for_if_up "$1" 2> /dev/null +} + +wait_for_if_link enx525401123456 + +ip addr add 127.0.0.1/8 dev lo +ip link set lo up +ip addr add 192.168.50.1/24 dev enx525401123456 +linkup enx525401123456 + +: > /dev/watchdog +modprobe af_packet +: > /dev/watchdog +modprobe sunrpc +: > /dev/watchdog +mount -t rpc_pipefs sunrpc /var/lib/nfs/rpc_pipefs +: > /dev/watchdog +[ -x /sbin/portmap ] && portmap +: > /dev/watchdog +mkdir -p /run/rpcbind +[ -x /sbin/rpcbind ] && rpcbind +: > /dev/watchdog +modprobe nfsd +: > /dev/watchdog +mount -t nfsd nfsd /proc/fs/nfsd +: > /dev/watchdog +exportfs -r +: > /dev/watchdog +rpc.nfsd +: > /dev/watchdog +rpc.mountd +: > /dev/watchdog +command -v rpc.idmapd > /dev/null && [ -z "$(pidof rpc.idmapd)" ] && rpc.idmapd +: > /dev/watchdog +exportfs -r +: > /dev/watchdog +mkdir -p /var/lib/dhcpd +: > /var/lib/dhcpd/dhcpd.leases +: > /dev/watchdog +chmod 777 /var/lib/dhcpd/dhcpd.leases +: > /dev/watchdog +rm -f /var/run/dhcpd.pid +dhcpd -d -cf /etc/dhcpd.conf -lf /var/lib/dhcpd/dhcpd.leases & +exportfs -s +echo "Serving NFS mounts" +while :; do + [ -n "$(jobs -rp)" ] && : > /dev/watchdog + sleep 10 +done +mount -n -o remount,ro / +poweroff -f diff --git a/test/TEST-50-MULTINIC/server.link b/test/TEST-50-MULTINIC/server.link new file mode 100644 index 0000000..1d21856 --- /dev/null +++ b/test/TEST-50-MULTINIC/server.link @@ -0,0 +1,6 @@ +[Match] +OriginalName=* + +[Link] +NamePolicy=mac +MACAddressPolicy=keep diff --git a/test/TEST-50-MULTINIC/test.sh b/test/TEST-50-MULTINIC/test.sh new file mode 100755 index 0000000..4f81235 --- /dev/null +++ b/test/TEST-50-MULTINIC/test.sh @@ -0,0 +1,376 @@ +#!/bin/bash + +# shellcheck disable=SC2034 +TEST_DESCRIPTION="root filesystem on NFS with multiple nics with $USE_NETWORK" + +# Uncomment this to debug failures +#DEBUGFAIL="loglevel=7 rd.shell rd.break" +#SERIAL="tcp:127.0.0.1:9999" + +run_server() { + # Start server first + echo "MULTINIC TEST SETUP: Starting DHCP/NFS server" + + declare -a disk_args=() + # shellcheck disable=SC2034 + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/server.img root + + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -net socket,listen=127.0.0.1:12350 \ + -net nic,macaddr=52:54:01:12:34:56,model=e1000 \ + -serial "${SERIAL:-"file:$TESTDIR/server.log"}" \ + -device i6300esb -watchdog-action poweroff \ + -append "panic=1 oops=panic softlockup_panic=1 systemd.crash_reboot root=LABEL=dracut rootfstype=ext4 rw console=ttyS0,115200n81 selinux=0" \ + -initrd "$TESTDIR"/initramfs.server \ + -pidfile "$TESTDIR"/server.pid -daemonize || return 1 + + chmod 644 -- "$TESTDIR"/server.pid || return 1 + + # Cleanup the terminal if we have one + tty -s && stty sane + + if ! [[ $SERIAL ]]; then + while :; do + grep Serving "$TESTDIR"/server.log && break + echo "Waiting for the server to startup" + tail "$TESTDIR"/server.log + sleep 1 + done + else + echo Sleeping 10 seconds to give the server a head start + sleep 10 + fi +} + +client_test() { + local test_name="$1" + local mac1="$2" + local mac2="$3" + local mac3="$4" + local cmdline="$5" + local check="$6" + + echo "CLIENT TEST START: $test_name" + + declare -a disk_args=() + # shellcheck disable=SC2034 + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker + cmdline="$cmdline rd.net.timeout.dhcp=30" + + # Invoke KVM and/or QEMU to actually create the target filesystem. + test_marker_reset + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -net socket,connect=127.0.0.1:12350 \ + -net nic,macaddr=52:54:00:12:34:"$mac1",model=e1000 \ + -net nic,macaddr=52:54:00:12:34:"$mac2",model=e1000 \ + -net nic,macaddr=52:54:00:12:34:"$mac3",model=e1000 \ + -netdev hubport,id=n1,hubid=1 \ + -netdev hubport,id=n2,hubid=2 \ + -device e1000,netdev=n1,mac=52:54:00:12:34:98 \ + -device e1000,netdev=n2,mac=52:54:00:12:34:99 \ + -device i6300esb -watchdog-action poweroff \ + -append "quiet panic=1 oops=panic softlockup_panic=1 systemd.crash_reboot rd.shell=0 $cmdline $DEBUGFAIL rd.retry=5 ro console=ttyS0,115200n81 selinux=0 init=/sbin/init rd.debug systemd.log_target=console" \ + -initrd "$TESTDIR"/initramfs.testing || return 1 + + { + read -r OK + read -r IFACES + } < "$TESTDIR"/marker.img + + if [[ $OK != "OK" ]]; then + echo "CLIENT TEST END: $test_name [FAILED - BAD EXIT]" + return 1 + fi + + for i in $check; do + if [[ " $IFACES " != *\ $i\ * ]]; then + echo "$i not in '$IFACES'" + echo "CLIENT TEST END: $test_name [FAILED - BAD IF]" + return 1 + fi + done + + for i in $IFACES; do + if [[ " $check " != *\ $i\ * ]]; then + echo "$i in '$IFACES', but should not be" + echo "CLIENT TEST END: $test_name [FAILED - BAD IF]" + return 1 + fi + done + + echo "CLIENT TEST END: $test_name [OK]" + return 0 +} + +test_run() { + if ! run_server; then + echo "Failed to start server" 1>&2 + return 1 + fi + test_client + ret=$? + kill_server + return $ret +} + +test_client() { + # Mac Numbering Scheme + # ...:00-02 receive IP addresses all others don't + # ...:02 receives a dhcp root-path + + # PXE Style BOOTIF= + client_test "MULTINIC root=nfs BOOTIF=" \ + 00 01 02 \ + "root=nfs:192.168.50.1:/nfs/client BOOTIF=52-54-00-12-34-00" \ + "enp0s1" || return 1 + + client_test "MULTINIC root=nfs BOOTIF= ip=enp0s3:dhcp" \ + 00 01 02 \ + "root=nfs:192.168.50.1:/nfs/client BOOTIF=52-54-00-12-34-00 ip=enp0s2:dhcp" \ + "enp0s1 enp0s2" || return 1 + + # PXE Style BOOTIF= with dhcp root-path + client_test "MULTINIC root=dhcp BOOTIF=" \ + 00 01 02 \ + "root=dhcp BOOTIF=52-54-00-12-34-02" \ + "enp0s3" || return 1 + + # Multinic case, where only one nic works + client_test "MULTINIC root=nfs ip=dhcp" \ + FF 00 FE \ + "root=nfs:192.168.50.1:/nfs/client ip=dhcp" \ + "enp0s2" || return 1 + + # Require two interfaces + client_test "MULTINIC root=nfs ip=enp0s2:dhcp ip=enp0s3:dhcp bootdev=enp0s2" \ + 00 01 02 \ + "root=nfs:192.168.50.1:/nfs/client ip=enp0s2:dhcp ip=enp0s3:dhcp bootdev=enp0s2" \ + "enp0s2 enp0s3" || return 1 + + # Require three interfaces with dhcp root-path + client_test "MULTINIC root=dhcp ip=enp0s1:dhcp ip=enp0s2:dhcp ip=enp0s3:dhcp bootdev=enp0s3" \ + 00 01 02 \ + "root=dhcp ip=enp0s1:dhcp ip=enp0s2:dhcp ip=enp0s3:dhcp bootdev=enp0s3" \ + "enp0s1 enp0s2 enp0s3" || return 1 + + client_test "MULTINIC bonding" \ + 00 01 02 \ + "root=nfs:192.168.50.1:/nfs/client ip=bond0:dhcp bond=bond0:enp0s1,enp0s2,enp0s3:mode=balance-rr" \ + "bond0" || return 1 + + # bridge, where only one interface is actually connected + client_test "MULTINIC bridging" \ + 00 01 02 \ + "root=nfs:192.168.50.1:/nfs/client ip=bridge0:dhcp::52:54:00:12:34:00 bridge=bridge0:enp0s1,enp0s5,enp0s6" \ + "bridge0" || return 1 + return 0 +} + +test_setup() { + export kernel=$KVERSION + export srcmods="/lib/modules/$kernel/" + rm -rf -- "$TESTDIR"/overlay + ( + mkdir -p "$TESTDIR"/overlay/source + # shellcheck disable=SC2030 + export initdir=$TESTDIR/overlay/source + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + + ( + cd "$initdir" || exit + mkdir -p dev sys proc run etc var/run tmp var/lib/{dhcpd,rpcbind} + mkdir -p var/lib/nfs/{v4recovery,rpc_pipefs} + chmod 777 var/lib/rpcbind var/lib/nfs + ) + + inst_multiple sh ls shutdown poweroff stty cat ps ln ip \ + dmesg mkdir cp ping exportfs \ + modprobe rpc.nfsd rpc.mountd showmount tcpdump \ + sleep mount chmod rm + for _terminfodir in /lib/terminfo /etc/terminfo /usr/share/terminfo; do + if [ -f "${_terminfodir}"/l/linux ]; then + inst_multiple -o "${_terminfodir}"/l/linux + break + fi + done + type -P portmap > /dev/null && inst_multiple portmap + type -P rpcbind > /dev/null && inst_multiple rpcbind + [ -f /etc/netconfig ] && inst_multiple /etc/netconfig + type -P dhcpd > /dev/null && inst_multiple dhcpd + instmods nfsd sunrpc ipv6 lockd af_packet + inst ./server-init.sh /sbin/init + inst_simple /etc/os-release + inst ./hosts /etc/hosts + inst ./exports /etc/exports + inst ./dhcpd.conf /etc/dhcpd.conf + inst_multiple -o {,/usr}/etc/nsswitch.conf {,/usr}/etc/rpc \ + {,/usr}/etc/protocols {,/usr}/etc/services + inst_multiple -o rpc.idmapd /etc/idmapd.conf + + inst_libdir_file 'libnfsidmap_nsswitch.so*' + inst_libdir_file 'libnfsidmap/*.so*' + inst_libdir_file 'libnfsidmap*.so*' + + _nsslibs=$( + cat "$dracutsysrootdir"/{,usr/}etc/nsswitch.conf 2> /dev/null \ + | sed -e '/^#/d' -e 's/^.*://' -e 's/\[NOTFOUND=return\]//' \ + | tr -s '[:space:]' '\n' | sort -u | tr -s '[:space:]' '|' + ) + _nsslibs=${_nsslibs#|} + _nsslibs=${_nsslibs%|} + inst_libdir_file -n "$_nsslibs" 'libnss_*.so*' + + inst /etc/passwd /etc/passwd + inst /etc/group /etc/group + + cp -a /etc/ld.so.conf* "$initdir"/etc + ldconfig -r "$initdir" + dracut_kernel_post + ) + + # Make client root inside server root + ( + # shellcheck disable=SC2030 + # shellcheck disable=SC2031 + export initdir=$TESTDIR/overlay/source/nfs/client + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + + ( + cd "$initdir" || exit + mkdir -p dev sys proc etc run root usr var/lib/nfs/rpc_pipefs + ) + + inst_multiple sh shutdown poweroff stty cat ps ln ip dd \ + mount dmesg mkdir cp ping grep setsid ls vi less cat sync + for _terminfodir in /lib/terminfo /etc/terminfo /usr/share/terminfo; do + if [ -f "${_terminfodir}"/l/linux ]; then + inst_multiple -o "${_terminfodir}"/l/linux + break + fi + done + + inst_simple "${PKGLIBDIR}/modules.d/99base/dracut-lib.sh" "/lib/dracut-lib.sh" + inst_simple "${PKGLIBDIR}/modules.d/99base/dracut-dev-lib.sh" "/lib/dracut-dev-lib.sh" + inst_binary "${PKGLIBDIR}/dracut-util" "/usr/bin/dracut-util" + ln -s dracut-util "${initdir}/usr/bin/dracut-getarg" + ln -s dracut-util "${initdir}/usr/bin/dracut-getargs" + + inst ./client-init.sh /sbin/init + inst_simple /etc/os-release + inst_multiple -o {,/usr}/etc/nsswitch.conf + inst /etc/passwd /etc/passwd + inst /etc/group /etc/group + + inst_libdir_file 'libnfsidmap_nsswitch.so*' + inst_libdir_file 'libnfsidmap/*.so*' + inst_libdir_file 'libnfsidmap*.so*' + + _nsslibs=$( + cat "$dracutsysrootdir"/{,usr/}etc/nsswitch.conf 2> /dev/null \ + | sed -e '/^#/d' -e 's/^.*://' -e 's/\[NOTFOUND=return\]//' \ + | tr -s '[:space:]' '\n' | sort -u | tr -s '[:space:]' '|' + ) + _nsslibs=${_nsslibs#|} + _nsslibs=${_nsslibs%|} + inst_libdir_file -n "$_nsslibs" 'libnss_*.so*' + + cp -a /etc/ld.so.conf* "$initdir"/etc + ldconfig -r "$initdir" + ) + + # second, install the files needed to make the root filesystem + ( + # shellcheck disable=SC2030 + # shellcheck disable=SC2031 + export initdir=$TESTDIR/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + inst_multiple sfdisk mkfs.ext4 poweroff cp umount sync dd + inst_hook initqueue 01 ./create-root.sh + inst_hook initqueue/finished 01 ./finished-false.sh + ) + + # create an initramfs that will create the target root filesystem. + # We do it this way so that we do not risk trashing the host mdraid + # devices, volume groups, encrypted partitions, etc. + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -m "bash rootfs-block kernel-modules qemu" \ + -d "piix ide-gd_mod ata_piix ext4 sd_mod" \ + --nomdadmconf \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.makeroot "$KVERSION" || return 1 + rm -rf -- "$TESTDIR"/overlay + + declare -a disk_args=() + # shellcheck disable=SC2034 + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker 1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/server.img root 120 + + # Invoke KVM and/or QEMU to actually create the target filesystem. + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "root=/dev/dracut/root rw rootfstype=ext4 quiet console=ttyS0,115200n81 selinux=0" \ + -initrd "$TESTDIR"/initramfs.makeroot || return 1 + test_marker_check dracut-root-block-created || return 1 + + # Make an overlay with needed tools for the test harness + ( + # shellcheck disable=SC2031 + # shellcheck disable=SC2030 + export initdir="$TESTDIR"/overlay + mkdir -p "$TESTDIR"/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + inst_multiple poweroff shutdown + inst_hook shutdown-emergency 000 ./hard-off.sh + inst_hook emergency 000 ./hard-off.sh + inst_simple ./client.link /etc/systemd/network/01-client.link + + inst_binary awk + inst_hook pre-pivot 85 "$PKGLIBDIR/modules.d/45ifcfg/write-ifcfg.sh" + ) + # Make client's dracut image + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -o "ifcfg plymouth" \ + -a "debug watchdog ${USE_NETWORK}" \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.testing "$KVERSION" || return 1 + + ( + # shellcheck disable=SC2031 + export initdir="$TESTDIR"/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + rm "$initdir"/etc/systemd/network/01-client.link + inst_simple ./server.link /etc/systemd/network/01-server.link + inst_hook pre-mount 99 ./wait-if-server.sh + ) + # Make server's dracut image + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -m "bash rootfs-block debug kernel-modules watchdog qemu network network-legacy" \ + -d "af_packet piix ide-gd_mod ata_piix ext4 sd_mod nfsv2 nfsv3 nfsv4 nfs_acl nfs_layout_nfsv41_files nfsd e1000 i6300esb ib700wdt" \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.server "$KVERSION" || return 1 + +} + +kill_server() { + if [[ -s "$TESTDIR"/server.pid ]]; then + kill -TERM -- "$(cat "$TESTDIR"/server.pid)" + rm -f -- "$TESTDIR"/server.pid + fi +} + +test_cleanup() { + kill_server +} + +# shellcheck disable=SC1090 +. "$testdir"/test-functions diff --git a/test/TEST-50-MULTINIC/wait-if-server.sh b/test/TEST-50-MULTINIC/wait-if-server.sh new file mode 100755 index 0000000..cea7259 --- /dev/null +++ b/test/TEST-50-MULTINIC/wait-if-server.sh @@ -0,0 +1,3 @@ +#!/bin/sh +. /lib/net-lib.sh +wait_for_if_link enx525401123456 diff --git a/test/TEST-60-BONDBRIDGEVLAN/Makefile b/test/TEST-60-BONDBRIDGEVLAN/Makefile new file mode 100644 index 0000000..2dcab81 --- /dev/null +++ b/test/TEST-60-BONDBRIDGEVLAN/Makefile @@ -0,0 +1 @@ +-include ../Makefile.testdir diff --git a/test/TEST-60-BONDBRIDGEVLAN/client-init.sh b/test/TEST-60-BONDBRIDGEVLAN/client-init.sh new file mode 100755 index 0000000..b1d1db4 --- /dev/null +++ b/test/TEST-60-BONDBRIDGEVLAN/client-init.sh @@ -0,0 +1,64 @@ +#!/bin/sh +exec > /dev/console 2>&1 +export PATH=/usr/sbin:/usr/bin:/sbin:/bin +strstr() { [ "${1#*"$2"*}" != "$1" ]; } +CMDLINE=$(while read -r line; do echo "$line"; done < /proc/cmdline) +export TERM=linux +export PS1='initramfs-test:\w\$ ' +stty sane +echo "made it to the rootfs! Powering down." + +testnum=$(grep -Eo "rd.dracut.test.num=[^[:space:]]+" /proc/cmdline | sed -nr 's/.*=(.*)/\1/p') +netmodule=$(grep -Eo "rd.dracut.test.net-module=[^[:space:]]+" /proc/cmdline | sed -nr 's/.*=(.*)/\1/p') + +( + echo OK + + ip -o -4 address show scope global | while read -r _ if rest; do echo "$if"; done | sort + + case "$testnum" in + 1) + ping -c 2 192.168.50.1 > /dev/null + echo PING1=$? + ping -c 2 192.168.54.1 > /dev/null + echo PING2=$? + ping -c 2 192.168.55.1 > /dev/null + echo PING3=$? + ping -c 2 192.168.56.1 > /dev/null + echo PING4=$? + ping -c 2 192.168.57.1 > /dev/null + echo PING5=$? + ;; + 2) + ping -c 2 192.168.51.1 > /dev/null + echo PING1=$? + ip link show net3 | grep "master bond0" > /dev/null + echo NET3=$? + ip link show net4 | grep "master bond0" > /dev/null + echo NET4=$? + ;; + 3) + ping -c 2 192.168.51.1 > /dev/null + echo PING1=$? + ip link show net1 | grep "master br0" > /dev/null + echo NET1=$? + ip link show net5 | grep "master br0" > /dev/null + echo NET5=$? + + ;; + esac + + case "$netmodule" in + network-legacy) + for i in /run/initramfs/state/etc/sysconfig/network-scripts/ifcfg-*; do + basename "$i" + grep -v 'UUID=' "$i" + done + ;; + esac + + echo EOF +) | dd oflag=direct,dsync of=/dev/sda + +strstr "$CMDLINE" "rd.shell" && sh -i +poweroff -f diff --git a/test/TEST-60-BONDBRIDGEVLAN/client.link b/test/TEST-60-BONDBRIDGEVLAN/client.link new file mode 100644 index 0000000..b992bfd --- /dev/null +++ b/test/TEST-60-BONDBRIDGEVLAN/client.link @@ -0,0 +1,6 @@ +[Match] +OriginalName=* + +[Link] +NamePolicy=keep kernel database onboard slot path +MACAddressPolicy=keep diff --git a/test/TEST-60-BONDBRIDGEVLAN/create-root.sh b/test/TEST-60-BONDBRIDGEVLAN/create-root.sh new file mode 100755 index 0000000..fe7b515 --- /dev/null +++ b/test/TEST-60-BONDBRIDGEVLAN/create-root.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +trap 'poweroff -f' EXIT + +# don't let udev and this script step on eachother's toes +for x in 64-lvm.rules 70-mdadm.rules 99-mount-rules; do + : > "/etc/udev/rules.d/$x" +done +rm -f -- /etc/lvm/lvm.conf +udevadm control --reload +udevadm settle +set -e + +mkfs.ext4 -L dracut /dev/disk/by-id/ata-disk_root +mkdir -p /root +mount -t ext4 /dev/disk/by-id/ata-disk_root /root +cp -a -t /root /source/* +mkdir -p /root/run +umount /root +echo "dracut-root-block-created" | dd oflag=direct,dsync of=/dev/disk/by-id/ata-disk_marker +sync +poweroff -f diff --git a/test/TEST-60-BONDBRIDGEVLAN/dhcpd.conf b/test/TEST-60-BONDBRIDGEVLAN/dhcpd.conf new file mode 100644 index 0000000..e26bd60 --- /dev/null +++ b/test/TEST-60-BONDBRIDGEVLAN/dhcpd.conf @@ -0,0 +1,27 @@ +ddns-update-style none; + +use-host-decl-names true; + +subnet 192.168.50.0 netmask 255.255.255.0 { + option subnet-mask 255.255.255.0; + option routers 192.168.50.1; + next-server 192.168.50.1; + server-identifier 192.168.50.1; + option domain-name-servers 192.168.50.1; + option domain-search "example.com"; + option domain-name "other.com"; + option root-path "nfs:192.168.50.1:/nfs/client"; + range 192.168.50.10 192.168.50.100; +} + +subnet 192.168.51.0 netmask 255.255.255.0 { + option subnet-mask 255.255.255.0; + option routers 192.168.51.1; + next-server 192.168.51.1; + server-identifier 192.168.51.1; + option domain-name-servers 192.168.51.1; + option domain-search "example.com"; + option domain-name "other.com"; + option root-path "nfs:192.168.51.1:/nfs/client"; + range 192.168.51.10 192.168.51.100; +} diff --git a/test/TEST-60-BONDBRIDGEVLAN/exports b/test/TEST-60-BONDBRIDGEVLAN/exports new file mode 100644 index 0000000..9c07923 --- /dev/null +++ b/test/TEST-60-BONDBRIDGEVLAN/exports @@ -0,0 +1 @@ +/nfs/client 192.168.50.0/24(rw,insecure,no_subtree_check,no_root_squash) 192.168.51.0/24(rw,insecure,no_subtree_check,no_root_squash) diff --git a/test/TEST-60-BONDBRIDGEVLAN/finished-false.sh b/test/TEST-60-BONDBRIDGEVLAN/finished-false.sh new file mode 100755 index 0000000..ecdbef9 --- /dev/null +++ b/test/TEST-60-BONDBRIDGEVLAN/finished-false.sh @@ -0,0 +1,2 @@ +#!/bin/sh +exit 1 diff --git a/test/TEST-60-BONDBRIDGEVLAN/hard-off.sh b/test/TEST-60-BONDBRIDGEVLAN/hard-off.sh new file mode 100755 index 0000000..12c3d5a --- /dev/null +++ b/test/TEST-60-BONDBRIDGEVLAN/hard-off.sh @@ -0,0 +1,3 @@ +#!/bin/sh +getarg rd.shell || poweroff -f +getarg failme && poweroff -f diff --git a/test/TEST-60-BONDBRIDGEVLAN/hosts b/test/TEST-60-BONDBRIDGEVLAN/hosts new file mode 100644 index 0000000..d02a4e9 --- /dev/null +++ b/test/TEST-60-BONDBRIDGEVLAN/hosts @@ -0,0 +1,5 @@ +127.0.0.1 localhost +192.168.50.1 server +192.168.50.100 client-if1 +192.168.50.101 client-if2 +192.168.50.102 client-if3 diff --git a/test/TEST-60-BONDBRIDGEVLAN/server-init.sh b/test/TEST-60-BONDBRIDGEVLAN/server-init.sh new file mode 100755 index 0000000..3b0f55e --- /dev/null +++ b/test/TEST-60-BONDBRIDGEVLAN/server-init.sh @@ -0,0 +1,140 @@ +#!/bin/sh +exec < /dev/console > /dev/console 2>&1 +set -x +export PATH=/usr/sbin:/usr/bin:/sbin:/bin +export TERM=linux +export PS1='nfstest-server:\w\$ ' +stty sane +echo "made it to the rootfs!" +echo server > /proc/sys/kernel/hostname + +wait_for_if_link() { + local cnt=0 + local li + + while [ $cnt -lt 600 ]; do + ip link show + + li=$(ip -o link show dev "$1" 2> /dev/null) + [ -n "$li" ] && return 0 + sleep 0.1 + cnt=$((cnt + 1)) + done + return 1 +} + +wait_for_if_up() { + local cnt=0 + local li + while [ $cnt -lt 200 ]; do + li=$(ip -o link show up dev "$1") + [ -n "$li" ] && return 0 + sleep 0.1 + cnt=$((cnt + 1)) + done + return 1 +} + +wait_for_route_ok() { + local cnt=0 + while [ $cnt -lt 200 ]; do + li=$(ip route show) + [ -n "$li" ] && [ -z "${li##*"$1"*}" ] && return 0 + sleep 0.1 + cnt=$((cnt + 1)) + done + return 1 +} + +linkup() { + wait_for_if_link "$1" 2> /dev/null && ip link set "$1" up 2> /dev/null && wait_for_if_up "$1" 2> /dev/null +} + +udevadm settle + +ip link show + +wait_for_if_link enx525401123456 +wait_for_if_link enx525401123457 +wait_for_if_link enx525401123458 +wait_for_if_link enx525401123459 + +ip link set dev enx525401123456 name net1 +ip link set dev enx525401123457 name net2 +ip link set dev enx525401123458 name net3 +ip link set dev enx525401123459 name net4 + +modprobe --all -b -q 8021q bonding +: > /dev/watchdog + +ip addr add 127.0.0.1/8 dev lo +linkup lo + +ip addr add 192.168.50.1/24 dev net1 +linkup net1 +: > /dev/watchdog + +ip link add dev net2.1 link net2 type vlan id 1 +ip link add dev net2.2 link net2 type vlan id 2 +ip link add dev net2.3 link net2 type vlan id 3 +ip link add dev net2.4 link net2 type vlan id 4 +ip addr add 192.168.54.1/24 dev net2.1 +ip addr add 192.168.55.1/24 dev net2.2 +ip addr add 192.168.56.1/24 dev net2.3 +ip addr add 192.168.57.1/24 dev net2.4 +linkup net2 +ip link set dev net2.1 up +ip link set dev net2.2 up +ip link set dev net2.3 up +ip link set dev net2.4 up + +ip link add bond0 type bond +ip link set net3 master bond0 +ip link set net4 master bond0 +ip link set net3 up +ip link set net4 up +ip link set bond0 up +ip addr add 192.168.51.1/24 dev bond0 + +: > /dev/watchdog +modprobe af_packet +: > /dev/watchdog +modprobe sunrpc +: > /dev/watchdog +mount -t rpc_pipefs sunrpc /var/lib/nfs/rpc_pipefs +: > /dev/watchdog +[ -x /sbin/portmap ] && portmap +: > /dev/watchdog +mkdir -p /run/rpcbind +[ -x /sbin/rpcbind ] && rpcbind +: > /dev/watchdog +modprobe nfsd +: > /dev/watchdog +mount -t nfsd nfsd /proc/fs/nfsd +: > /dev/watchdog +exportfs -r +: > /dev/watchdog +rpc.nfsd +: > /dev/watchdog +rpc.mountd +: > /dev/watchdog +command -v rpc.idmapd > /dev/null && [ -z "$(pidof rpc.idmapd)" ] && rpc.idmapd -S +: > /dev/watchdog +exportfs -r +: > /dev/watchdog +: > /var/lib/dhcpd/dhcpd.leases +: > /dev/watchdog +chmod 777 /var/lib/dhcpd/dhcpd.leases +: > /dev/watchdog +dhcpd -cf /etc/dhcpd.conf -lf /var/lib/dhcpd/dhcpd.leases net1 bond0 +#echo -n 'V' : > /dev/watchdog +#sh -i +#tcpdump -i net1 +# Wait forever for the VM to die +echo "Serving" +while :; do + sleep 10 + : > /dev/watchdog +done +mount -n -o remount,ro / +poweroff -f diff --git a/test/TEST-60-BONDBRIDGEVLAN/server.link b/test/TEST-60-BONDBRIDGEVLAN/server.link new file mode 100644 index 0000000..1d21856 --- /dev/null +++ b/test/TEST-60-BONDBRIDGEVLAN/server.link @@ -0,0 +1,6 @@ +[Match] +OriginalName=* + +[Link] +NamePolicy=mac +MACAddressPolicy=keep diff --git a/test/TEST-60-BONDBRIDGEVLAN/test.sh b/test/TEST-60-BONDBRIDGEVLAN/test.sh new file mode 100755 index 0000000..5110ddb --- /dev/null +++ b/test/TEST-60-BONDBRIDGEVLAN/test.sh @@ -0,0 +1,404 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh + +# shellcheck disable=SC2034 +TEST_DESCRIPTION="root filesystem on NFS with bridging/bonding/vlan with $USE_NETWORK" + +# Uncomment this to debug failures +#DEBUGFAIL="rd.shell rd.break" +#SERIAL="tcp:127.0.0.1:9999" + +# Network topology: +# +# .---------------------. .---------------. +# | SERVER-VM | | CLIENT-VM | +# | | | | +# | (DHCP) net1 <------------> net1 | +# | | | | +# | net2 <------------> net2 | +# | vlan 1 <-| | | | +# | vlan 2 <-| | | | +# | vlan 3 <-| | | | +# | vlan 4 <-. | | | +# | | | | +# | / net3 <------------> net3 | +# | bond0 | | | | +# | (DHCP) \ net4 <------------> net4 | +# | | | | +# | | X-----> net5 | +# .---------------------. .---------------. + +run_server() { + # Start server first + echo "MULTINIC TEST SETUP: Starting DHCP/NFS server" + + "$testdir"/run-qemu \ + -netdev socket,id=n0,listen=127.0.0.1:12370 \ + -netdev socket,id=n1,listen=127.0.0.1:12371 \ + -netdev socket,id=n2,listen=127.0.0.1:12372 \ + -netdev socket,id=n3,listen=127.0.0.1:12373 \ + -device virtio-net-pci,netdev=n0,mac=52:54:01:12:34:56 \ + -device virtio-net-pci,netdev=n1,mac=52:54:01:12:34:57 \ + -device virtio-net-pci,netdev=n2,mac=52:54:01:12:34:58 \ + -device virtio-net-pci,netdev=n3,mac=52:54:01:12:34:59 \ + -hda "$TESTDIR"/server.ext4 \ + -serial "${SERIAL:-"file:$TESTDIR/server.log"}" \ + -device i6300esb -watchdog-action poweroff \ + -append "panic=1 oops=panic softlockup_panic=1 loglevel=7 root=LABEL=dracut rootfstype=ext4 rw console=ttyS0,115200n81 selinux=0 rd.debug" \ + -initrd "$TESTDIR"/initramfs.server \ + -pidfile "$TESTDIR"/server.pid -daemonize || return 1 + chmod 644 -- "$TESTDIR"/server.pid || return 1 + + # Cleanup the terminal if we have one + tty -s && stty sane + + if ! [[ $SERIAL ]]; then + echo "Waiting for the server to startup" + while :; do + grep Serving "$TESTDIR"/server.log && break + tail "$TESTDIR"/server.log + sleep 1 + done + else + echo Sleeping 10 seconds to give the server a head start + sleep 10 + fi +} + +client_test() { + local test_name="$1" + local cmdline="$2" + local check="$3" + local CONF + + echo "CLIENT TEST START: $test_name" + + # Need this so kvm-qemu will boot (needs non-/dev/zero local disk) + if ! dd if=/dev/zero of="$TESTDIR"/client.img bs=1M count=1; then + echo "Unable to make client sda image" 1>&2 + return 1 + fi + + "$testdir"/run-qemu \ + -netdev socket,connect=127.0.0.1:12370,id=n1 -device virtio-net-pci,mac=52:54:00:12:34:01,netdev=n1 \ + -netdev socket,connect=127.0.0.1:12371,id=n2 -device virtio-net-pci,mac=52:54:00:12:34:02,netdev=n2 \ + -netdev socket,connect=127.0.0.1:12372,id=n3 -device virtio-net-pci,mac=52:54:00:12:34:03,netdev=n3 \ + -netdev socket,connect=127.0.0.1:12373,id=n4 -device virtio-net-pci,mac=52:54:00:12:34:04,netdev=n4 \ + -netdev hubport,id=n5,hubid=1 -device virtio-net-pci,mac=52:54:00:12:34:05,netdev=n5 \ + -hda "$TESTDIR"/client.img \ + -device i6300esb -watchdog-action poweroff \ + -append " + panic=1 oops=panic softlockup_panic=1 + ifname=net1:52:54:00:12:34:01 + ifname=net2:52:54:00:12:34:02 + ifname=net3:52:54:00:12:34:03 + ifname=net4:52:54:00:12:34:04 + ifname=net5:52:54:00:12:34:05 + $cmdline rd.net.timeout.dhcp=30 systemd.crash_reboot + $DEBUGFAIL rd.retry=5 rw console=ttyS0,115200n81 selinux=0 init=/sbin/init" \ + -initrd "$TESTDIR"/initramfs.testing || return 1 + + { + read -r OK _ + if [[ $OK != "OK" ]]; then + echo "CLIENT TEST END: $test_name [FAILED - BAD EXIT]" + return 1 + fi + + while read -r line; do + [[ $line == END ]] && break + CONF+="$line " + done + } < "$TESTDIR"/client.img || return 1 + + if [[ $check != "$CONF" ]]; then + echo "Expected: '$check'" + echo + echo + echo "Got: '$CONF'" + echo "CLIENT TEST END: $test_name [FAILED - BAD CONF]" + return 1 + fi + + echo "CLIENT TEST END: $test_name [OK]" + return 0 +} + +test_run() { + if ! run_server; then + echo "Failed to start server" 1>&2 + return 1 + fi + test_client || { + kill_server + return 1 + } +} + +test_client() { + + ### TEST 1: VLANs + if [ "$USE_NETWORK" = network-legacy ]; then + NETCONF='ifcfg-net1 # Generated by dracut initrd NAME="net1" HWADDR="52:54:00:12:34:01" DEVICE="net1" ONBOOT=yes NETBOOT=yes IPV6INIT=yes BOOTPROTO=dhcp TYPE=Ethernet ifcfg-net2.0004 # Generated by dracut initrd NAME="net2.0004" ONBOOT=yes NETBOOT=yes BOOTPROTO=none IPADDR="192.168.57.104" PREFIX="24" GATEWAY="192.168.57.1" TYPE=Vlan DEVICE="net2.0004" VLAN=yes PHYSDEV="net2" ifcfg-net2.3 # Generated by dracut initrd NAME="net2.3" ONBOOT=yes NETBOOT=yes BOOTPROTO=none IPADDR="192.168.56.103" PREFIX="24" GATEWAY="192.168.56.1" TYPE=Vlan DEVICE="net2.3" VLAN=yes PHYSDEV="net2" ifcfg-vlan0001 # Generated by dracut initrd NAME="vlan0001" ONBOOT=yes NETBOOT=yes BOOTPROTO=none IPADDR="192.168.54.101" PREFIX="24" GATEWAY="192.168.54.1" TYPE=Vlan DEVICE="vlan0001" VLAN=yes PHYSDEV="net2" ifcfg-vlan2 # Generated by dracut initrd NAME="vlan2" ONBOOT=yes NETBOOT=yes BOOTPROTO=none IPADDR="192.168.55.102" PREFIX="24" GATEWAY="192.168.55.1" TYPE=Vlan DEVICE="vlan2" VLAN=yes PHYSDEV="net2" ' + fi + + client_test "VLANs" \ + " +rd.dracut.test.num=1 +rd.dracut.test.net-module=$USE_NETWORK +vlan=vlan0001:net2 +vlan=vlan2:net2 +vlan=net2.3:net2 +vlan=net2.0004:net2 +ip=net1:dhcp +ip=192.168.54.101::192.168.54.1:24:test:vlan0001:none +ip=192.168.55.102::192.168.55.1:24:test:vlan2:none +ip=192.168.56.103::192.168.56.1:24:test:net2.3:none +ip=192.168.57.104::192.168.57.1:24:test:net2.0004:none +rd.neednet=1 +root=nfs:192.168.50.1:/nfs/client +bootdev=net1 +" \ + "net1 net2.0004 net2.3 vlan0001 vlan2 PING1=0 PING2=0 PING3=0 PING4=0 PING5=0 ${NETCONF}EOF " \ + || return 1 + + ### TEST 2: bond + if [ "$USE_NETWORK" = network-legacy ]; then + NETCONF='ifcfg-bond0 # Generated by dracut initrd NAME="bond0" DEVICE="bond0" ONBOOT=yes NETBOOT=yes IPV6INIT=yes BOOTPROTO=dhcp BONDING_OPTS="miimon=100" NAME="bond0" TYPE=Bond ifcfg-net3 # Generated by dracut initrd NAME="net3" TYPE=Ethernet ONBOOT=yes NETBOOT=yes SLAVE=yes MASTER="bond0" DEVICE="net3" ifcfg-net4 # Generated by dracut initrd NAME="net4" TYPE=Ethernet ONBOOT=yes NETBOOT=yes SLAVE=yes MASTER="bond0" DEVICE="net4" ' + fi + client_test "Bond" \ + " +rd.dracut.test.num=2 +rd.dracut.test.net-module=$USE_NETWORK +bond=bond0:net3,net4:miimon=100 +ip=bond0:dhcp +rd.neednet=1 +root=nfs:192.168.51.1:/nfs/client +bootdev=bond0 +" \ + "bond0 PING1=0 NET3=0 NET4=0 ${NETCONF}EOF " \ + || return 1 + + ### TEST 3: bridge + if [ "$USE_NETWORK" = network-legacy ]; then + NETCONF='ifcfg-br0 # Generated by dracut initrd NAME="br0" DEVICE="br0" ONBOOT=yes NETBOOT=yes IPV6INIT=yes BOOTPROTO=dhcp TYPE=Bridge NAME="br0" ifcfg-net1 # Generated by dracut initrd NAME="net1" TYPE=Ethernet ONBOOT=yes NETBOOT=yes BRIDGE="br0" HWADDR="52:54:00:12:34:01" DEVICE="net1" ifcfg-net5 # Generated by dracut initrd NAME="net5" TYPE=Ethernet ONBOOT=yes NETBOOT=yes BRIDGE="br0" HWADDR="52:54:00:12:34:05" DEVICE="net5" ' + fi + client_test "Bridge" \ + " +rd.dracut.test.num=3 +rd.dracut.test.net-module=$USE_NETWORK +bridge=br0:net1,net5 +ip=br0:dhcp +rd.neednet=1 +root=nfs:192.168.50.1:/nfs/client +bootdev=br0 +" \ + "br0 PING1=0 NET1=0 NET5=0 ${NETCONF}EOF " \ + || return 1 + + kill_server + return 0 +} + +test_setup() { + kernel=$KVERSION + rm -rf -- "$TESTDIR"/overlay + ( + mkdir -p "$TESTDIR"/overlay/source + # shellcheck disable=SC2030 + export initdir=$TESTDIR/overlay/source + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + + ( + cd "$initdir" || exit + mkdir -p -- dev sys proc run etc var/run tmp var/lib/{dhcpd,rpcbind} + mkdir -p -- var/lib/nfs/{v4recovery,rpc_pipefs} + chmod 777 -- var/lib/rpcbind var/lib/nfs + ) + + for _f in modules.builtin.bin modules.builtin; do + [[ -f $srcmods/$_f ]] && break + done || { + dfatal "No modules.builtin.bin and modules.builtin found!" + return 1 + } + + for _f in modules.builtin.bin modules.builtin modules.order; do + [[ -f $srcmods/$_f ]] && inst_simple "$srcmods/$_f" "/lib/modules/$kernel/$_f" + done + + inst_multiple sh ls shutdown poweroff stty cat ps ln ip \ + dmesg mkdir cp ping exportfs \ + modprobe rpc.nfsd rpc.mountd showmount tcpdump \ + /etc/services sleep mount chmod + for _terminfodir in /lib/terminfo /etc/terminfo /usr/share/terminfo; do + [ -f "${_terminfodir}"/l/linux ] && break + done + inst_multiple -o "${_terminfodir}"/l/linux + type -P portmap > /dev/null && inst_multiple portmap + type -P rpcbind > /dev/null && inst_multiple rpcbind + [ -f /etc/netconfig ] && inst_multiple /etc/netconfig + type -P dhcpd > /dev/null && inst_multiple dhcpd + instmods nfsd sunrpc ipv6 lockd af_packet 8021q bonding + inst_simple /etc/os-release + inst ./server-init.sh /sbin/init + inst ./hosts /etc/hosts + inst ./exports /etc/exports + inst ./dhcpd.conf /etc/dhcpd.conf + inst_multiple -o {,/usr}/etc/nsswitch.conf {,/usr}/etc/rpc {,/usr}/etc/protocols + + inst_multiple -o rpc.idmapd /etc/idmapd.conf + + inst_libdir_file 'libnfsidmap_nsswitch.so*' + inst_libdir_file 'libnfsidmap/*.so*' + inst_libdir_file 'libnfsidmap*.so*' + + _nsslibs=$( + cat "$dracutsysrootdir"/{,usr/}etc/nsswitch.conf 2> /dev/null \ + | sed -e '/^#/d' -e 's/^.*://' -e 's/\[NOTFOUND=return\]//' \ + | tr -s '[:space:]' '\n' | sort -u | tr -s '[:space:]' '|' + ) + _nsslibs=${_nsslibs#|} + _nsslibs=${_nsslibs%|} + + inst_libdir_file -n "$_nsslibs" 'libnss_*.so*' + + inst /etc/passwd /etc/passwd + inst /etc/group /etc/group + + cp -a -- /etc/ld.so.conf* "$initdir"/etc + ldconfig -r "$initdir" + dracut_kernel_post + ) + + # Make client root inside server root + ( + # shellcheck disable=SC2030 + # shellcheck disable=SC2031 + export initdir=$TESTDIR/overlay/source/nfs/client + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + inst_multiple sh shutdown poweroff stty cat ps ln ip \ + mount dmesg mkdir cp ping grep ls sort dd sed basename + for _terminfodir in /lib/terminfo /etc/terminfo /usr/share/terminfo; do + [[ -f ${_terminfodir}/l/linux ]] && break + done + inst_multiple -o "${_terminfodir}"/l/linux + inst_simple /etc/os-release + inst ./client-init.sh /sbin/init + ( + cd "$initdir" || exit + mkdir -p -- dev sys proc etc run + mkdir -p -- var/lib/nfs/rpc_pipefs + ) + inst_multiple -o {,/usr}/etc/nsswitch.conf {,/usr}/etc/rpc {,/usr}/etc/protocols + inst /etc/passwd /etc/passwd + inst /etc/group /etc/group + + inst_multiple -o rpc.idmapd /etc/idmapd.conf + inst_libdir_file 'libnfsidmap_nsswitch.so*' + inst_libdir_file 'libnfsidmap/*.so*' + inst_libdir_file 'libnfsidmap*.so*' + + _nsslibs=$( + cat "$dracutsysrootdir"/{,usr/}etc/nsswitch.conf 2> /dev/null \ + | sed -e '/^#/d' -e 's/^.*://' -e 's/\[NOTFOUND=return\]//' \ + | tr -s '[:space:]' '\n' | sort -u | tr -s '[:space:]' '|' + ) + _nsslibs=${_nsslibs#|} + _nsslibs=${_nsslibs%|} + + inst_libdir_file -n "$_nsslibs" 'libnss_*.so*' + + cp -a -- /etc/ld.so.conf* "$initdir"/etc + ldconfig -r "$initdir" + ) + + # second, install the files needed to make the root filesystem + ( + # shellcheck disable=SC2030 + # shellcheck disable=SC2031 + export initdir=$TESTDIR/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + inst_multiple sfdisk mkfs.ext4 poweroff cp umount sync dd + inst_hook initqueue 01 ./create-root.sh + inst_hook initqueue/finished 01 ./finished-false.sh + ) + + # create an initramfs that will create the target root filesystem. + # We do it this way so that we do not risk trashing the host mdraid + # devices, volume groups, encrypted partitions, etc. + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + -m "bash rootfs-block kernel-modules qemu" \ + -d "piix ide-gd_mod ata_piix ext4 sd_mod" \ + --nomdadmconf \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.makeroot "$KVERSION" || return 1 + + declare -a disk_args=() + declare -i disk_index=0 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/marker.img marker 1 + qemu_add_drive_args disk_index disk_args "$TESTDIR"/server.ext4 root 120 + + # Invoke KVM and/or QEMU to actually create the target filesystem. + "$testdir"/run-qemu \ + "${disk_args[@]}" \ + -append "root=/dev/dracut/root rw rootfstype=ext4 quiet console=ttyS0,115200n81 selinux=0" \ + -initrd "$TESTDIR"/initramfs.makeroot || return 1 + test_marker_check dracut-root-block-created || return 1 + rm -- "$TESTDIR"/marker.img + rm -fr "$TESTDIR"/overlay + + # Make an overlay with needed tools for the test harness + ( + # shellcheck disable=SC2031 + # shellcheck disable=SC2030 + export initdir="$TESTDIR"/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + inst_multiple poweroff shutdown + inst_hook emergency 000 ./hard-off.sh + inst_simple ./client.link /etc/systemd/network/01-client.link + ) + # Make client's dracut image + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + --no-early-microcode \ + -o "plymouth" \ + -a "debug ${USE_NETWORK}" \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.testing "$KVERSION" || return 1 + + ( + # shellcheck disable=SC2031 + export initdir="$TESTDIR"/overlay + # shellcheck disable=SC1090 + . "$PKGLIBDIR"/dracut-init.sh + rm "$initdir"/etc/systemd/network/01-client.link + inst_simple ./server.link /etc/systemd/network/01-server.link + inst_hook pre-mount 99 ./wait-if-server.sh + ) + # Make server's dracut image + "$DRACUT" -l -i "$TESTDIR"/overlay / \ + --no-early-microcode \ + -m "rootfs-block debug kernel-modules watchdog qemu network network-legacy" \ + -d "ipvlan macvlan af_packet piix ide-gd_mod ata_piix ext4 sd_mod nfsv2 nfsv3 nfsv4 nfs_acl nfs_layout_nfsv41_files nfsd virtio-net i6300esb ib700wdt" \ + --no-hostonly-cmdline -N \ + -f "$TESTDIR"/initramfs.server "$KVERSION" || return 1 +} + +kill_server() { + if [[ -s "$TESTDIR"/server.pid ]]; then + kill -TERM -- "$(cat "$TESTDIR"/server.pid)" + rm -f -- "$TESTDIR"/server.pid + fi +} + +test_cleanup() { + kill_server +} + +# shellcheck disable=SC1090 +. "$testdir"/test-functions diff --git a/test/TEST-60-BONDBRIDGEVLAN/wait-if-server.sh b/test/TEST-60-BONDBRIDGEVLAN/wait-if-server.sh new file mode 100755 index 0000000..7cdb941 --- /dev/null +++ b/test/TEST-60-BONDBRIDGEVLAN/wait-if-server.sh @@ -0,0 +1,6 @@ +#!/bin/sh +. /lib/net-lib.sh +wait_for_if_link enx525401123456 +wait_for_if_link enx525401123457 +wait_for_if_link enx525401123458 +wait_for_if_link enx525401123459 diff --git a/test/TEST-62-SKIPCPIO/Makefile b/test/TEST-62-SKIPCPIO/Makefile new file mode 100644 index 0000000..2dcab81 --- /dev/null +++ b/test/TEST-62-SKIPCPIO/Makefile @@ -0,0 +1 @@ +-include ../Makefile.testdir diff --git a/test/TEST-62-SKIPCPIO/test.sh b/test/TEST-62-SKIPCPIO/test.sh new file mode 100755 index 0000000..2311da3 --- /dev/null +++ b/test/TEST-62-SKIPCPIO/test.sh @@ -0,0 +1,80 @@ +#!/bin/bash +# This file is part of dracut. +# SPDX-License-Identifier: GPL-2.0-or-later + +# shellcheck disable=SC2034 +TEST_DESCRIPTION="test skipcpio" + +test_check() { + cpio dd truncate find sort diff &> /dev/null +} + +skipcpio_simple() { + mkdir -p "$CPIO_TESTDIR/skipcpio_simple/first_archive" + pushd "$CPIO_TESTDIR/skipcpio_simple/first_archive" + + for ((i = 0; i < 3; i++)); do + echo "first archive file $i" >> ./"$i" + done + find . -print0 | sort -z \ + | cpio -o --null -H newc --file "$CPIO_TESTDIR/skipcpio_simple.cpio" + popd + + mkdir -p "$CPIO_TESTDIR/skipcpio_simple/second_archive" + pushd "$CPIO_TESTDIR/skipcpio_simple/second_archive" + + for ((i = 10; i < 13; i++)); do + echo "second archive file $i" >> ./"$i" + done + + find . -print0 | sort -z \ + | cpio -o --null -H newc >> "$CPIO_TESTDIR/skipcpio_simple.cpio" + popd + + cpio -i --list < "$CPIO_TESTDIR/skipcpio_simple.cpio" \ + > "$CPIO_TESTDIR/skipcpio_simple.list" + cat << EOF | diff - "$CPIO_TESTDIR/skipcpio_simple.list" +. +0 +1 +2 +EOF + + if [ "$PKGLIBDIR" = "$basedir" ]; then + skipcpio_path="${PKGLIBDIR}/src/skipcpio" + else + skipcpio_path="${PKGLIBDIR}" + fi + "$skipcpio_path"/skipcpio "$CPIO_TESTDIR/skipcpio_simple.cpio" \ + | cpio -i --list > "$CPIO_TESTDIR/skipcpio_simple.list" + cat << EOF | diff - "$CPIO_TESTDIR/skipcpio_simple.list" +. +10 +11 +12 +EOF +} + +test_run() { + set -x + set -e + + skipcpio_simple + + return 0 +} + +test_setup() { + CPIO_TESTDIR=$(mktemp --directory -p "$TESTDIR" cpio-test.XXXXXXXXXX) \ + || return 1 + export CPIO_TESTDIR + return 0 +} + +test_cleanup() { + [ -d "$CPIO_TESTDIR" ] && rm -rf "$CPIO_TESTDIR" + return 0 +} + +# shellcheck disable=SC1090 +. "$testdir"/test-functions diff --git a/test/TEST-63-DRACUT-CPIO/Makefile b/test/TEST-63-DRACUT-CPIO/Makefile new file mode 100644 index 0000000..2dcab81 --- /dev/null +++ b/test/TEST-63-DRACUT-CPIO/Makefile @@ -0,0 +1 @@ +-include ../Makefile.testdir diff --git a/test/TEST-63-DRACUT-CPIO/test.sh b/test/TEST-63-DRACUT-CPIO/test.sh new file mode 100755 index 0000000..f9dff10 --- /dev/null +++ b/test/TEST-63-DRACUT-CPIO/test.sh @@ -0,0 +1,85 @@ +#!/bin/bash +# This file is part of dracut. +# SPDX-License-Identifier: GPL-2.0-or-later + +# shellcheck disable=SC2034 +TEST_DESCRIPTION="kernel cpio extraction tests for dracut-cpio" +# see dracut-cpio source for unit tests + +test_check() { + if ! [[ -x "$PKGLIBDIR/dracut-cpio" ]]; then + echo "Test needs dracut-cpio... Skipping" + return 1 + fi +} + +test_dracut_cpio() { + local tdir="${CPIO_TESTDIR}/${1}" + shift + # --enhanced-cpio tells dracut to use dracut-cpio instead of GNU cpio + local dracut_cpio_params=("--enhanced-cpio" "$@") + + mkdir -p "$tdir" + + # VM script to print sentinel on boot + # write to kmsg so that sysrq messages don't race with console output + cat > "$tdir/init.sh" << EOF +echo "Image with ${dracut_cpio_params[*]} booted successfully" > /dev/kmsg +echo 1 > /proc/sys/kernel/sysrq +echo o > /proc/sysrq-trigger +sleep 20 +EOF + + "$DRACUT" -l --drivers "" \ + "${dracut_cpio_params[@]}" \ + --modules "bash base" \ + --include "$tdir/init.sh" /lib/dracut/hooks/emergency/00-init.sh \ + --no-hostonly --no-hostonly-cmdline \ + "$tdir/initramfs" \ + || return 1 + + "$testdir"/run-qemu \ + -device i6300esb -watchdog-action poweroff \ + -daemonize -pidfile "$tdir/vm.pid" \ + -serial "file:$tdir/console.out" \ + -append "panic=1 oops=panic softlockup_panic=1 loglevel=7 console=ttyS0 rd.shell=1" \ + -initrd "$tdir/initramfs" || return 1 + + timeout=120 + while [[ -f $tdir/vm.pid ]] \ + && ps -p "$(head -n1 "$tdir/vm.pid")" > /dev/null; do + echo "$timeout - awaiting VM shutdown" + sleep 1 + [[ $((timeout--)) -le 0 ]] && return 1 + done + + cat "$tdir/console.out" + grep -q "Image with ${dracut_cpio_params[*]} booted successfully" \ + "$tdir/console.out" +} + +test_run() { + set -x + + # dracut-cpio is typically used with compression and strip disabled, to + # increase the chance of (reflink) extent sharing. + test_dracut_cpio "simple" "--no-compress" "--nostrip" || return 1 + # dracut-cpio should still work fine with compression and stripping enabled + test_dracut_cpio "compress" "--gzip" "--nostrip" || return 1 + test_dracut_cpio "strip" "--gzip" "--strip" || return 1 +} + +test_setup() { + CPIO_TESTDIR=$(mktemp --directory -p "$TESTDIR" cpio-test.XXXXXXXXXX) \ + || return 1 + export CPIO_TESTDIR + return 0 +} + +test_cleanup() { + [ -d "$CPIO_TESTDIR" ] && rm -rf "$CPIO_TESTDIR" + return 0 +} + +# shellcheck disable=SC1090 +. "$testdir"/test-functions diff --git a/test/TEST-98-GETARG/Makefile b/test/TEST-98-GETARG/Makefile new file mode 100644 index 0000000..2dcab81 --- /dev/null +++ b/test/TEST-98-GETARG/Makefile @@ -0,0 +1 @@ +-include ../Makefile.testdir diff --git a/test/TEST-98-GETARG/test.sh b/test/TEST-98-GETARG/test.sh new file mode 100755 index 0000000..8f628a2 --- /dev/null +++ b/test/TEST-98-GETARG/test.sh @@ -0,0 +1,159 @@ +#!/bin/bash + +# This file is part of dracut. +# SPDX-License-Identifier: GPL-2.0-or-later + +# shellcheck disable=SC2034 +TEST_DESCRIPTION="dracut getarg command" + +test_check() { + if ! [[ -x "$PKGLIBDIR/dracut-util" ]]; then + echo "Test needs dracut-util... Skipping" + return 1 + fi +} + +test_setup() { + ln -sfnr "$PKGLIBDIR"/dracut-util "$TESTDIR"/dracut-getarg + ln -sfnr "$PKGLIBDIR"/dracut-util "$TESTDIR"/dracut-getargs + ln -sfnr "$PKGLIBDIR"/modules.d/99base/dracut-lib.sh "$TESTDIR"/dracut-lib.sh + ln -sfnr "$PKGLIBDIR"/modules.d/99base/dracut-dev-lib.sh "$TESTDIR"/dracut-dev-lib.sh + return 0 +} + +test_run() { + set -x + ( + cd "$TESTDIR" || exit 1 + export CMDLINE='key1=0 key2=val key2=val2 key3=" val 3 " " key 4 ="val4 "key 5=val 5" "key 6=""val 6" key7="foo"bar" baz="end " key8 = val 8 " +"key 9"="val 9"' + + ret=0 + + unset TEST + declare -A TEST + TEST=( + ["key1"]="0" + ["key2"]="val2" + ["key3"]=" val 3 " + [" key 4 "]="val4" + ["key 5"]="val 5" + ["key 6"]='"val 6' + ["key7"]='foo"bar" baz="end' + [" key8 "]=" val 8 " + ['key 9"']="val 9" + ) + for key in "${!TEST[@]}"; do + if ! val=$(./dracut-getarg "${key}="); then + echo "'$key' == '${TEST[$key]}', but not found" >&2 + ret=$((ret + 1)) + else + if [[ $val != "${TEST[$key]}" ]]; then + echo "'$key' != '${TEST[$key]}' but '$val'" >&2 + ret=$((ret + 1)) + fi + fi + done + + declare -a INVALIDKEYS + + INVALIDKEYS=("key" "4" "5" "6" "key8" "9" '"' "baz") + for key in "${INVALIDKEYS[@]}"; do + val=$(./dracut-getarg "$key") + # shellcheck disable=SC2181 + if (($? == 0)); then + echo "key '$key' should not be found" + ret=$((ret + 1)) + fi + # must have no output + [[ $val ]] && ret=$((ret + 1)) + done + + RESULT=("val" "val2") + readarray -t args < <(./dracut-getargs "key2=") + ((${#RESULT[@]} == ${#args[@]})) || ret=$((ret + 1)) + for ((i = 0; i < ${#RESULT[@]}; i++)); do + [[ ${args[$i]} == "${RESULT[$i]}" ]] || ret=$((ret + 1)) + done + + val=$(./dracut-getarg "key1") || ret=$((ret + 1)) + [[ $val == "0" ]] || ret=$((ret + 1)) + + val=$(./dracut-getarg "key2=val") && ret=$((ret + 1)) + # must have no output + [[ $val ]] && ret=$((ret + 1)) + val=$(./dracut-getarg "key2=val2") || ret=$((ret + 1)) + # must have no output + [[ $val ]] && ret=$((ret + 1)) + + export PATH=".:$PATH" + + . dracut-dev-lib.sh + . dracut-lib.sh + + debug_off() { + : + } + + debug_on() { + : + } + + getcmdline() { + echo "rdbreak=cmdline rd.lvm rd.auto=0 rd.auto rd.retry=10" + } + RDRETRY=$(getarg rd.retry -d 'rd_retry=') + [[ $RDRETRY == "10" ]] || ret=$((ret + 1)) + getarg rd.break=cmdline -d rdbreak=cmdline || ret=$((ret + 1)) + getargbool 1 rd.lvm -d -n rd_NO_LVM || ret=$((ret + 1)) + getargbool 0 rd.auto || ret=$((ret + 1)) + + getcmdline() { + echo "rd.break=cmdlined rd.lvm=0 rd.auto rd.auto=1 rd.auto=0" + } + getarg rd.break=cmdline -d rdbreak=cmdline && ret=$((ret + 1)) + getargbool 1 rd.lvm -d -n rd_NO_LVM && ret=$((ret + 1)) + getargbool 0 rd.auto && ret=$((ret + 1)) + + getcmdline() { + echo "ip=a ip=b ip=dhcp6" + } + getargs "ip=dhcp6" &> /dev/null || ret=$((ret + 1)) + readarray -t args < <(getargs "ip=") + RESULT=("a" "b" "dhcp6") + ((${#RESULT[@]} || ${#args[@]})) || ret=$((ret + 1)) + for ((i = 0; i < ${#RESULT[@]}; i++)); do + [[ ${args[$i]} == "${RESULT[$i]}" ]] || ret=$((ret + 1)) + done + + getcmdline() { + echo "bridge bridge=val" + } + readarray -t args < <(getargs bridge=) + RESULT=("bridge" "val") + ((${#RESULT[@]} == ${#args[@]})) || ret=$((ret + 1)) + for ((i = 0; i < ${#RESULT[@]}; i++)); do + [[ ${args[$i]} == "${RESULT[$i]}" ]] || ret=$((ret + 1)) + done + + getcmdline() { + echo "rd.break rd.md.uuid=bf96e457:230c9ad4:1f3e59d6:745cf942 rd.md.uuid=bf96e457:230c9ad4:1f3e59d6:745cf943 rd.shell" + } + readarray -t args < <(getargs rd.md.uuid -d rd_MD_UUID=) + RESULT=("bf96e457:230c9ad4:1f3e59d6:745cf942" "bf96e457:230c9ad4:1f3e59d6:745cf943") + ((${#RESULT[@]} == ${#args[@]})) || ret=$((ret + 1)) + for ((i = 0; i < ${#RESULT[@]}; i++)); do + [[ ${args[$i]} == "${RESULT[$i]}" ]] || ret=$((ret + 1)) + done + + return $ret + ) +} + +test_cleanup() { + rm -fr -- "$TESTDIR"/*.rpm + return 0 +} + +# shellcheck disable=SC1090 +. "$testdir"/test-functions diff --git a/test/container/Dockerfile-Arch b/test/container/Dockerfile-Arch new file mode 100644 index 0000000..f05ce8f --- /dev/null +++ b/test/container/Dockerfile-Arch @@ -0,0 +1,17 @@ +FROM docker.io/archlinux + +MAINTAINER https://github.com/dracutdevs/dracut + +# Install needed packages for the dracut CI container +RUN pacman --noconfirm -Syu \ + linux dash strace dhclient asciidoc cpio pigz squashfs-tools \ + qemu btrfs-progs mdadm dmraid nfs-utils nfsidmap lvm2 nbd \ + dhcp networkmanager multipath-tools vi tcpdump open-iscsi connman \ + git shfmt shellcheck astyle which base-devel glibc parted ntfs-3g && yes | pacman -Scc + +RUN useradd -m build +RUN su build -c 'cd && git clone https://aur.archlinux.org/perl-config-general.git && cd perl-config-general && makepkg -s --noconfirm' +RUN pacman -U --noconfirm ~build/perl-config-general/*.pkg.tar.* +RUN su build -c 'cd && git clone https://aur.archlinux.org/tgt.git && cd tgt && makepkg -s --noconfirm' +RUN pacman -U --noconfirm ~build/tgt/*.pkg.tar.* +RUN rm -fr ~build diff --git a/test/container/Dockerfile-Debian b/test/container/Dockerfile-Debian new file mode 100644 index 0000000..9ba3a1f --- /dev/null +++ b/test/container/Dockerfile-Debian @@ -0,0 +1,67 @@ +FROM docker.io/debian:latest + +MAINTAINER https://github.com/dracutdevs/dracut + +# Install needed packages for the dracut CI container +# Install dracut as a linux-initramfs-tool provider so that the default initramfs-tool package does not get installed +# Uninstall initramfs-tools-core as a workaround for https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=994492 +RUN apt-get update -y -qq && apt-get upgrade -y -qq && apt-get install -y -qq --no-install-recommends dracut && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends -o Dpkg::Use-Pty=0 \ + asciidoc \ + astyle \ + btrfs-progs \ + busybox-static \ + bzip2 \ + ca-certificates \ + console-setup \ + cpio \ + cryptsetup \ + curl \ + dash \ + debhelper \ + debhelper-compat \ + dmraid \ + docbook \ + docbook-xml \ + docbook-xsl \ + fdisk \ + g++ \ + gawk \ + git \ + iputils-arping \ + iputils-ping \ + isc-dhcp-client \ + isc-dhcp-server \ + kmod \ + less \ + libdmraid-dev \ + libkmod-dev \ + linux-image-generic \ + lvm2 \ + make \ + mdadm \ + multipath-tools \ + nbd-client \ + nbd-server \ + network-manager \ + nfs-kernel-server \ + ntfs-3g \ + open-iscsi \ + ovmf \ + parted \ + pigz \ + pkg-config \ + procps \ + qemu-system-x86 \ + quilt \ + shellcheck \ + squashfs-tools \ + strace \ + sudo \ + systemd-boot-efi \ + tcpdump \ + tgt \ + thin-provisioning-tools \ + vim \ + wget \ + && apt-get clean && dpkg -P --force-depends dracut dracut-core initramfs-tools-core diff --git a/test/container/Dockerfile-Fedora-latest b/test/container/Dockerfile-Fedora-latest new file mode 100644 index 0000000..2ce3975 --- /dev/null +++ b/test/container/Dockerfile-Fedora-latest @@ -0,0 +1,71 @@ +FROM registry.fedoraproject.org/fedora:latest + +MAINTAINER https://github.com/dracutdevs/dracut + +# Install needed packages for the dracut CI container +RUN dnf -y install --setopt=install_weak_deps=False \ + asciidoc \ + bash-completion \ + biosdevname \ + bluez \ + btrfs-progs \ + busybox \ + bzip2 \ + cifs-utils \ + cryptsetup \ + dash \ + dbus-daemon \ + device-mapper-multipath \ + dhcp-client \ + dhcp-server \ + dmraid \ + e2fsprogs \ + f2fs-tools \ + fcoe-utils \ + fuse3 \ + gcc \ + git \ + iproute \ + iputils \ + iscsi-initiator-utils \ + kbd \ + kernel \ + kmod-devel \ + libkcapi-hmaccalc \ + libselinux-utils \ + lvm2 \ + lzop \ + make \ + mdadm \ + memstrack \ + mksh \ + nbd \ + ndctl \ + NetworkManager \ + nfs-utils \ + ntfs-3g \ + ntfsprogs \ + nvme-cli \ + parted \ + pcsc-lite \ + pigz \ + qemu-system-x86-core \ + rng-tools \ + rpm-build \ + sbsigntools \ + scsi-target-utils \ + ShellCheck \ + shfmt \ + squashfs-tools \ + strace \ + sudo \ + systemd-boot-unsigned \ + systemd-networkd \ + systemd-resolved \ + tar \ + tcpdump \ + tpm2-tools \ + wget \ + which \ + xz \ + && dnf -y remove dracut --noautoremove && dnf -y update && dnf clean all diff --git a/test/container/Dockerfile-Gentoo b/test/container/Dockerfile-Gentoo new file mode 100644 index 0000000..f2bb555 --- /dev/null +++ b/test/container/Dockerfile-Gentoo @@ -0,0 +1,57 @@ +ARG TAG=musl +FROM docker.io/gentoo/portage:latest as portage + +# uefi stub in a separate builder +FROM docker.io/gentoo/stage3 as efistub +COPY --from=portage /var/db/repos/gentoo /var/db/repos/gentoo + +# systemd-boot +RUN echo 'sys-apps/systemd-utils boot' > /etc/portage/package.use/systemd-utils && \ + emerge -qv sys-apps/systemd-utils + +# kernel and its dependencies in a separate builder +FROM docker.io/gentoo/stage3:$TAG as kernel +COPY --from=portage /var/db/repos/gentoo /var/db/repos/gentoo +# disable initramfs generation, only need the kernel image itself +RUN echo 'sys-kernel/gentoo-kernel-bin -initramfs' > /etc/portage/package.use/kernel +RUN emerge -qv sys-kernel/gentoo-kernel-bin + +FROM docker.io/gentoo/stage3:$TAG +COPY --from=portage /var/db/repos/gentoo /var/db/repos/gentoo +COPY --from=kernel /boot /boot +COPY --from=kernel /lib/modules /lib/modules +COPY --from=efistub /usr/lib/systemd/boot/efi /usr/lib/systemd/boot/efi +ARG TAG + +MAINTAINER https://github.com/dracutdevs/dracut + +# required by sys-fs/dmraid +RUN echo 'sys-fs/lvm2 lvm thin' > /etc/portage/package.use/lvm2 + +# workaround for https://bugs.gentoo.org/734022 whereby Gentoo does not support NFS4 with musl +RUN if [[ "$TAG" == 'musl' ]]; then echo 'net-fs/nfs-utils -nfsv4' > /etc/portage/package.use/nfs-utils ; fi + +# workaround for packages do not compile on musl +# https://bugs.gentoo.org/713490 for tgt +# https://bugs.gentoo.org/908587 for open-iscsi +RUN if [[ "$TAG" != 'musl' ]]; then emerge -qv sys-block/tgt sys-block/open-iscsi ; fi + +# Install needed packages for the dracut CI container +RUN emerge -qv \ + app-arch/cpio \ + app-emulation/qemu \ + app-shells/dash \ + net-fs/nfs-utils \ + net-misc/dhcp \ + sys-apps/busybox \ + sys-block/nbd \ + sys-block/parted \ + sys-fs/btrfs-progs \ + sys-fs/cryptsetup \ + sys-fs/dmraid \ + sys-fs/lvm2 \ + sys-fs/mdadm \ + sys-fs/multipath-tools \ + sys-fs/ntfs3g \ + sys-fs/squashfs-tools \ + && rm -rf /var/cache/* /usr/share/doc/* /usr/share/man/* diff --git a/test/container/Dockerfile-OpenSuse-latest b/test/container/Dockerfile-OpenSuse-latest new file mode 100644 index 0000000..3e7cefc --- /dev/null +++ b/test/container/Dockerfile-OpenSuse-latest @@ -0,0 +1,13 @@ +FROM registry.opensuse.org/opensuse/tumbleweed-dnf:latest + +MAINTAINER https://github.com/dracutdevs/dracut + +# Install needed packages for the dracut CI container +RUN dnf -y install --setopt=install_weak_deps=False \ + dash asciidoc mdadm lvm2 dmraid cryptsetup nfs-utils nbd dhcp-server \ + strace libkmod-devel gcc bzip2 xz tar wget rpm-build make git bash-completion \ + sudo kernel dhcp-client qemu-kvm /usr/bin/qemu-system-$(uname -m) e2fsprogs \ + tcpdump iproute iputils kbd NetworkManager btrfsprogs tgt dbus-broker \ + iscsiuio open-iscsi which ShellCheck shfmt procps pigz parted squashfs ntfsprogs \ + multipath-tools util-linux-systemd systemd-boot \ + && dnf -y remove dracut && dnf -y update && dnf clean all diff --git a/test/container/Dockerfile-Ubuntu b/test/container/Dockerfile-Ubuntu new file mode 100644 index 0000000..0fb7f20 --- /dev/null +++ b/test/container/Dockerfile-Ubuntu @@ -0,0 +1,63 @@ +FROM docker.io/ubuntu:latest + +MAINTAINER https://github.com/dracutdevs/dracut + +# Install needed packages for the dracut CI container +# The Linux kernel is only readable by root. See https://launchpad.net/bugs/759725 +RUN apt-get update -y -qq && apt-get upgrade -y -qq && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends -o Dpkg::Use-Pty=0 \ + asciidoc \ + astyle \ + btrfs-progs \ + busybox-static \ + bzip2 \ + ca-certificates \ + console-setup \ + cpio \ + cryptsetup \ + curl \ + dmraid \ + docbook \ + docbook-xml \ + docbook-xsl \ + fdisk \ + g++ \ + gawk \ + git \ + iputils-arping \ + iputils-ping \ + isc-dhcp-client \ + isc-dhcp-server \ + kmod \ + less \ + libdmraid-dev \ + libkmod-dev \ + linux-image-generic \ + lvm2 \ + make \ + mdadm \ + multipath-tools \ + nbd-client \ + nbd-server \ + network-manager \ + nfs-kernel-server \ + ntfs-3g \ + open-iscsi \ + ovmf \ + parted \ + pigz \ + pkg-config \ + procps \ + qemu-kvm \ + shellcheck \ + squashfs-tools \ + strace \ + sudo \ + systemd \ + tcpdump \ + tgt \ + thin-provisioning-tools \ + vim \ + wget \ + && apt-get clean \ + && chmod a+r /boot/vmlinu* diff --git a/test/run-qemu b/test/run-qemu new file mode 100755 index 0000000..41d458a --- /dev/null +++ b/test/run-qemu @@ -0,0 +1,74 @@ +#!/bin/bash +# Check which virtualization technology to use +# We prefer kvm, kqemu, userspace in that order. + +export PATH=/usr/sbin:/usr/bin:/sbin:/bin +ARCH="${ARCH-$(uname -m)}" +QEMU_CPU="${QEMU_CPU:-max}" + +[[ -x /usr/bin/qemu ]] && BIN=/usr/bin/qemu && ARGS=(-cpu "$QEMU_CPU") +(lsmod | grep -q '^kqemu ') && BIN=/usr/bin/qemu && ARGS=(-kernel-kqemu -cpu host) +[[ -z ${NO_KVM-} && -c /dev/kvm && -x /usr/bin/kvm ]] && BIN=/usr/bin/kvm && ARGS=(-cpu host) +[[ -z ${NO_KVM-} && -c /dev/kvm && -x /usr/bin/qemu-kvm ]] && BIN=/usr/bin/qemu-kvm && ARGS=(-cpu host) +[[ -z ${NO_KVM-} && -c /dev/kvm && -x /usr/libexec/qemu-kvm ]] && BIN=/usr/libexec/qemu-kvm && ARGS=(-cpu host) +[[ -x "/usr/bin/qemu-system-${ARCH}" ]] && BIN="/usr/bin/qemu-system-${ARCH}" && ARGS=(-cpu "$QEMU_CPU") +[[ -z ${NO_KVM-} && -c /dev/kvm && -x "/usr/bin/qemu-system-${ARCH}" ]] && BIN="/usr/bin/qemu-system-${ARCH}" && ARGS=(-enable-kvm -cpu host) + +[[ $BIN ]] || { + echo "Could not find a working KVM or QEMU to test with!" >&2 + echo "Please install kvm or qemu." >&2 + exit 1 +} + +case "$ARCH" in + aarch64 | arm64) + ARGS+=(-M "virt,gic-version=max") + ;; + amd64 | i?86 | x86_64) + ARGS+=(-M q35) + ;; + arm | armhf | armv7l) + ARGS+=(-M virt) + ;; + ppc64el | ppc64le) + ARGS+=(-M "cap-ccf-assist=off,cap-cfpc=broken,cap-ibs=broken,cap-sbbc=broken") + ;; +esac + +# Provide rng device sourcing the hosts /dev/urandom and other standard parameters +ARGS+=(-smp 2 -m 1024 -nodefaults -vga none -display none -no-reboot -device virtio-rng-pci) + +if ! [[ $* == *-daemonize* ]] && ! [[ $* == *-daemonize* ]]; then + ARGS+=(-serial stdio) +fi + +KVERSION=${KVERSION-$(uname -r)} + +VMLINUZ="/lib/modules/${KVERSION}/vmlinuz" +if ! [ -f "$VMLINUZ" ]; then + VMLINUZ="/lib/modules/${KVERSION}/vmlinux" +fi + +if ! [ -f "$VMLINUZ" ]; then + [[ -f /etc/machine-id ]] && read -r MACHINE_ID < /etc/machine-id + + if [[ $MACHINE_ID ]] && { [[ -d /boot/${MACHINE_ID} ]] || [[ -L /boot/${MACHINE_ID} ]]; }; then + VMLINUZ="/boot/${MACHINE_ID}/$KVERSION/linux" + elif [ -f "/boot/vmlinuz-${KVERSION}" ]; then + VMLINUZ="/boot/vmlinuz-${KVERSION}" + elif [ -f "/boot/vmlinux-${KVERSION}" ]; then + VMLINUZ="/boot/vmlinux-${KVERSION}" + else + echo "Could not find a Linux kernel version $KVERSION to test with!" >&2 + echo "Please install linux." >&2 + exit 1 + fi +fi + +# only set -kernel if -initrd is specified +if [[ $* == *-initrd* ]]; then + ARGS+=(-kernel "$VMLINUZ") +fi + +echo "${0##*/}: $BIN ${ARGS[*]@Q} ${*@Q}" +exec "$BIN" "${ARGS[@]}" "$@" diff --git a/test/test-functions b/test/test-functions new file mode 100644 index 0000000..f76d930 --- /dev/null +++ b/test/test-functions @@ -0,0 +1,206 @@ +#!/bin/bash +PATH=/usr/sbin:/usr/bin:/sbin:/bin +export PATH + +# shellcheck disable=SC1090 +[[ -e .testdir${TEST_RUN_ID:+-$TEST_RUN_ID} ]] && . .testdir${TEST_RUN_ID:+-$TEST_RUN_ID} +if [[ -z $TESTDIR ]] || [[ ! -d $TESTDIR ]]; then + TESTDIR=$(mktemp -d -p "/var/tmp" -t dracut-test.XXXXXX) +fi +echo "TESTDIR=\"$TESTDIR\"" > .testdir${TEST_RUN_ID:+-$TEST_RUN_ID} +export TESTDIR + +KVERSION=${KVERSION-$(uname -r)} + +[ -z "$USE_NETWORK" ] && USE_NETWORK="network-legacy" + +if [[ -z $basedir ]]; then basedir="$(realpath ../..)"; fi + +DRACUT=${DRACUT-${basedir}/dracut.sh} +PKGLIBDIR=${PKGLIBDIR-$basedir} + +test_dracut() { + TEST_DRACUT_ARGS+=" --local --no-hostonly --no-early-microcode --add test --kver $KVERSION" + + # shellcheck disable=SC2162 + IFS=' ' read -a TEST_DRACUT_ARGS_ARRAY <<< "$TEST_DRACUT_ARGS" + + "$DRACUT" "$@" \ + --kernel-cmdline "panic=1 oops=panic softlockup_panic=1 systemd.crash_reboot selinux=0 console=ttyS0,115200n81 $DEBUGFAIL" \ + "${TEST_DRACUT_ARGS_ARRAY[@]}" || return 1 +} + +command -v test_check &> /dev/null || test_check() { + : +} + +command -v test_cleanup &> /dev/null || test_cleanup() { + : +} + +# terminal sequence to set color to a 'success' color (currently: green) +function SETCOLOR_SUCCESS() { echo -en '\033[0;32m'; } +# terminal sequence to set color to a 'failure' color (currently: red) +function SETCOLOR_FAILURE() { echo -en '\033[0;31m'; } +# terminal sequence to set color to a 'warning' color (currently: yellow) +function SETCOLOR_WARNING() { echo -en '\033[0;33m'; } +# terminal sequence to reset to the default color. +function SETCOLOR_NORMAL() { echo -en '\033[0;39m'; } + +COLOR_SUCCESS='\033[0;32m' +COLOR_FAILURE='\033[0;31m' +COLOR_WARNING='\033[0;33m' +COLOR_NORMAL='\033[0;39m' + +check_root() { + if ((EUID != 0)); then + SETCOLOR_FAILURE + echo "Tests must be run as root! Please use 'sudo'." + SETCOLOR_NORMAL + exit 1 + fi +} + +# generate qemu arguments for named raw disks +# +# qemu_add_drive_args <index> <args> <filename> <id-name> [<bootindex>] +# +# index: name of the index variable (set to 0 at start) +# args: name of the argument array variable (set to () at start) +# filename: filename of the raw disk image +# id-name: name of the disk in /dev/disk/by-id -> /dev/disk/by-id/ata-disk_$name +# size: optional file size in MiB (0 implies size is not set) +# bootindex: optional bootindex number +# +# to be used later with `qemu … "${args[@]}" …` +# The <index> variable will be incremented each time the function is called. +# +# can't be easier than this :-/ +# +# # EXAMPLES +# ``` +# declare -a disk_args=() +# declare -i disk_index=0 +# qemu_add_drive_args disk_index disk_args "$TESTDIR"/root.ext3 root 0 1 +# qemu_add_drive_args disk_index disk_args "$TESTDIR"/client.img client +# qemu_add_drive_args disk_index disk_args "$TESTDIR"/iscsidisk2.img iscsidisk2 +# qemu_add_drive_args disk_index disk_args "$TESTDIR"/iscsidisk3.img iscsidisk3 +# qemu "${disk_args[@]}" +# ``` +qemu_add_drive_args() { + local index=${!1} + local file=$3 + local name=${4:-$index} + local size=${5:-0} + local bootindex=$6 + + if [ "${size}" -ne 0 ]; then + dd if=/dev/zero of="${file}" bs=1MiB count="${size}" + fi + + eval "${2}"'+=(' \ + -drive "if=none,format=raw,file=${file},id=drive-sata${index}" \ + -device "ide-hd,bus=ide.${index},drive=drive-sata${index},id=sata${index},${bootindex:+bootindex=$bootindex,}model=disk,serial=${name}" \ + ')' + + # shellcheck disable=SC2219 + let "${1}++" +} + +test_marker_reset() { + dd if=/dev/zero of="$TESTDIR"/marker.img bs=1MiB count=1 +} + +test_marker_check() { + local marker=${1:-dracut-root-block-success} + local file=${2:-marker.img} + + grep -U --binary-files=binary -F -m 1 -q "$marker" "$TESTDIR/$file" + return $? +} + +while (($# > 0)); do + case $1 in + --run) + check_root + echo "TEST RUN: $TEST_DESCRIPTION" + test_check && test_run + exit $? + ;; + --setup) + check_root + echo "TEST SETUP: $TEST_DESCRIPTION" + test_check && test_setup + exit $? + ;; + --clean) + echo "TEST CLEANUP: $TEST_DESCRIPTION" + test_cleanup + rm -fr -- "$TESTDIR" + rm -f -- .testdir${TEST_RUN_ID:+-$TEST_RUN_ID} + exit $? + ;; + --all) + check_root + if ! test_check 2 &> test${TEST_RUN_ID:+-$TEST_RUN_ID}.log; then + echo -e "TEST: $TEST_DESCRIPTION " "$COLOR_WARNING" "[SKIPPED]" "$COLOR_NORMAL" + exit 0 + else + echo -e "TEST: $TEST_DESCRIPTION " "$COLOR_SUCCESS" "[STARTED]" "$COLOR_NORMAL" + fi + if [[ $V == "1" ]]; then + set -o pipefail + ( + test_setup && test_run + ret=$? + test_cleanup + if ((ret != 0)) && [[ -f "$TESTDIR"/server.log ]]; then + mv "$TESTDIR"/server.log ./server${TEST_RUN_ID:+-$TEST_RUN_ID}.log + fi + rm -fr -- "$TESTDIR" + rm -f -- .testdir${TEST_RUN_ID:+-$TEST_RUN_ID} + exit $ret + ) < /dev/null 2>&1 | tee "test${TEST_RUN_ID:+-$TEST_RUN_ID}.log" + elif [[ $V == "2" ]]; then + set -o pipefail + ( + test_setup && test_run + ret=$? + test_cleanup + if ((ret != 0)) && [[ -f "$TESTDIR"/server.log ]]; then + mv "$TESTDIR"/server.log ./server${TEST_RUN_ID:+-$TEST_RUN_ID}.log + fi + rm -fr -- "$TESTDIR" + rm -f -- .testdir${TEST_RUN_ID:+-$TEST_RUN_ID} + exit $ret + ) < /dev/null 2>&1 | "$basedir/logtee" "test${TEST_RUN_ID:+-$TEST_RUN_ID}.log" + else + ( + test_setup && test_run + ret=$? + test_cleanup + rm -fr -- "$TESTDIR" + rm -f -- .testdir${TEST_RUN_ID:+-$TEST_RUN_ID} + exit $ret + ) < /dev/null > test${TEST_RUN_ID:+-$TEST_RUN_ID}.log 2>&1 + fi + ret=$? + set +o pipefail + if [ $ret -eq 0 ]; then + rm -- test${TEST_RUN_ID:+-$TEST_RUN_ID}.log + echo -e "TEST: $TEST_DESCRIPTION " "$COLOR_SUCCESS" "[OK]" "$COLOR_NORMAL" + else + echo -e "TEST: $TEST_DESCRIPTION " "$COLOR_FAILURE" "[FAILED]" "$COLOR_NORMAL" + if [ "$V" == "2" ]; then + tail -c 1048576 "$(pwd)/server${TEST_RUN_ID:+-$TEST_RUN_ID}.log" "$(pwd)/test${TEST_RUN_ID:+-$TEST_RUN_ID}.log" + echo -e "TEST: $TEST_DESCRIPTION " "$COLOR_FAILURE" "[FAILED]" "$COLOR_NORMAL" + else + echo "see $(pwd)/test${TEST_RUN_ID:+-$TEST_RUN_ID}.log" + fi + fi + exit $ret + ;; + *) break ;; + esac + shift +done |