From b3312f86061a0d887233f5068cbc335aa2612bed Mon Sep 17 00:00:00 2001 From: Jonathan Bauer Date: Wed, 6 May 2015 18:13:52 +0200 Subject: current state: udev disk detection still not done! also improved module structure and code commentary --- testModule/hooks/cmdline/enable-sysrq.sh | 2 + testModule/hooks/cmdline/expand-kcl-ip.sh | 20 +++++ testModule/hooks/cmdline/mark-root-device.sh | 9 ++ testModule/hooks/mount/mount-root-device.sh | 4 + testModule/hooks/pre-mount/mount-qcow.sh | 49 +++++++++++ testModule/hooks/pre-pivot/mount-tmp.sh | 38 +++++++++ .../hooks/pre-udev/load-dnbd3-nbd-modules.sh | 32 +++++++ testModule/module-setup.sh | 63 ++++++++++---- testModule/scripts/prepare-disks | 98 ++++++++++++++++++++++ testModule/scripts/setup-qcow2 | 41 +++++---- testModule/udev/70-openslx-disk.rules | 8 ++ 11 files changed, 335 insertions(+), 29 deletions(-) create mode 100755 testModule/hooks/cmdline/enable-sysrq.sh create mode 100755 testModule/hooks/cmdline/expand-kcl-ip.sh create mode 100755 testModule/hooks/cmdline/mark-root-device.sh create mode 100755 testModule/hooks/mount/mount-root-device.sh create mode 100755 testModule/hooks/pre-mount/mount-qcow.sh create mode 100755 testModule/hooks/pre-pivot/mount-tmp.sh create mode 100755 testModule/hooks/pre-udev/load-dnbd3-nbd-modules.sh create mode 100755 testModule/scripts/prepare-disks create mode 100644 testModule/udev/70-openslx-disk.rules (limited to 'testModule') diff --git a/testModule/hooks/cmdline/enable-sysrq.sh b/testModule/hooks/cmdline/enable-sysrq.sh new file mode 100755 index 00000000..f779aa7a --- /dev/null +++ b/testModule/hooks/cmdline/enable-sysrq.sh @@ -0,0 +1,2 @@ +# enables magic sysrq keys +echo 1 > /proc/sys/kernel/sysrq diff --git a/testModule/hooks/cmdline/expand-kcl-ip.sh b/testModule/hooks/cmdline/expand-kcl-ip.sh new file mode 100755 index 00000000..8be1c718 --- /dev/null +++ b/testModule/hooks/cmdline/expand-kcl-ip.sh @@ -0,0 +1,20 @@ +# fakes the cmdline to fix the ip parsing when using +# syslinux's IPAPPEND 1 mask +[ -d /fake ] || mkdir /fake + +# need to be a tmpfs for the hack to work +mount -t tmpfs tmpfs /fake + +# append ':hiwi:eth0:none' to the 'ip=' parameter we got +# from syslinux's IPAPPEND 1 +sed 's/\(ip=\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}:\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}:\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}:\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}\)/\1:hiwi:eno1:none/' /proc/cmdline > /fake/cmdline + +# bind mount it. Can we trust mount return codes here? +# # if so, we should check what we get in $? +mount -o bind /fake/cmdline /proc/cmdline + +# check if it worked +if ! grep 'hiwi:eth0:none' /proc/cmdline; then + command -v warn >/dev/null || . /lib/dracut-lib.sh + warn 'Haxing cmdline did not work :( sad pandaz...' +fi diff --git a/testModule/hooks/cmdline/mark-root-device.sh b/testModule/hooks/cmdline/mark-root-device.sh new file mode 100755 index 00000000..b7282521 --- /dev/null +++ b/testModule/hooks/cmdline/mark-root-device.sh @@ -0,0 +1,9 @@ +# set rootok and root as dracut expects them to be set by +# the module preparing the root filesystem. +# +# Once the root filesystem is mounted per dnbd3 and +# exported as qcow2 per nbd, /dev/root will be a symlink +# to /dev/nbd0 as this is then our rootfs-device +rootok=1 +root=block:/dev/root + diff --git a/testModule/hooks/mount/mount-root-device.sh b/testModule/hooks/mount/mount-root-device.sh new file mode 100755 index 00000000..d02f9002 --- /dev/null +++ b/testModule/hooks/mount/mount-root-device.sh @@ -0,0 +1,4 @@ +# this rudimentary script just mounts the rootfs device that was symlinked to +# /dev/root to dracut's $NEWROOT (usually /sysroot). + +mount /dev/root $NEWROOT diff --git a/testModule/hooks/pre-mount/mount-qcow.sh b/testModule/hooks/pre-mount/mount-qcow.sh new file mode 100755 index 00000000..d70492bf --- /dev/null +++ b/testModule/hooks/pre-mount/mount-qcow.sh @@ -0,0 +1,49 @@ +############################################################################### +# CHECKS +# + +SETUP_ROOTFS_SCRIPT="/sbin/setup-qcow2" + +if [ ! -e "${SETUP_ROOTFS_SCRIPT}" ]; then + warn "No such file of directory: ${SETUP_ROOTFS_SCRIPT}" + emergency_shell -n "Error in $0" + return 1 +fi + +if [ ! -x "${SETUP_ROOTFS_SCRIPT}" ]; then + warn "Cannot execute: ${SETUP_ROOTFS_SCRIPT}" + emergency_shell -n "Error in $0" + return 1 +fi + +# +# END CHECKS +############################################################################### + +############################################################################### +# MAIN CODE +# + +# ok, let's source the setup script +if ! . ${SETUP_ROOTFS_SCRIPT} ; then + warn "Could not source: ${SETUP_ROOTFS_SCRIPT}" + emergency_shell -n "Error in $0" + return 1 +fi + +# just go over the functions in the right order ;-) +for fun in connect_dnbd3 create_qcow export_qcow connect_qcow; do + if ! $fun; then + # something failed, drop a shell for debugging + warn "'$fun' failed with: $?" + emergency_shell -n "Error in $fun" + return 1 + fi +done + +# all good, we are done +return 0 + +# +# END MAIN CODE +############################################################################### diff --git a/testModule/hooks/pre-pivot/mount-tmp.sh b/testModule/hooks/pre-pivot/mount-tmp.sh new file mode 100755 index 00000000..152c844e --- /dev/null +++ b/testModule/hooks/pre-pivot/mount-tmp.sh @@ -0,0 +1,38 @@ +# This script only checks if we found a usable partition for the +# future /tmp. The discovery of that partition is done by udev during +# the initqueue. If a valid partition is found (either GPT with the label +# OPENSLX_TMP or MBR with the type 0x44) its path will be written to +# /tmp/openslx.tmpdisk +OPENSLX_TMP_DISK_FLAG="/tmp/openslx.tmpdisk" + +if [ ! -e "$OPENSLX_TMP_DISK_FLAG" ]; then + warn "'$OPENSLX_TMP_DISK_FLAG' not found!" + warn "Systemd will manage $NEWROOT/tmp on its own." + # no partition for the future /tmp found, just + # let systemd manage it then (probably a tmpfs) + return 1 +fi + +# in /tmp/openslx.disk.tmp is the name of the device +# to mount as /tmp in the real system +# meaning we need to mount it to /sysroot/tmp here. + +OPENSLX_TMP_DISK_DEV="$(cat $OPENSLX_TMP_DISK_FLAG)" + +# sanity check: is the content a block device? +if [ ! -b "$OPENSLX_TMP_DISK_DEV" ]; then + warn "'$OPENSLX_TMP_DISK_DEV' appears not to be a block device!" + warn "Systemd will manage $NEWROOT/tmp on its own." + return 1 +fi + +# all good, keep on +if ! mount -t auto "$OPENSLX_TMP_DISK_DEV" /sysroot/tmp; then + # something else went wrong :( + warn "Mounting '$OPENSLX_TMP_DISK_DEV' to '/sysroot/tmp' failed with: $!" + warn "Systemd will manage $NEWROOT/tmp on its own." + return 1 +fi + +# still here? mount worked wohoo +return 0 diff --git a/testModule/hooks/pre-udev/load-dnbd3-nbd-modules.sh b/testModule/hooks/pre-udev/load-dnbd3-nbd-modules.sh new file mode 100755 index 00000000..29f9f210 --- /dev/null +++ b/testModule/hooks/pre-udev/load-dnbd3-nbd-modules.sh @@ -0,0 +1,32 @@ +# include dracut-lib.sh to use 'warn' +command -v warn >/dev/null || . /lib/dracut-lib.sh + +NBD_MOD_PATH="/usr/lib/modules/current/extra/nbd.ko" +DNBD3_MOD_PATH="/usr/lib/modules/current/extra/dnbd3.ko" + +# do we actually have our modules? +if [ ! -e "${NBD_MOD_PATH}" ]; then + warn "No such file of directory: ${NBD_MOD_PATH}" + emergency_shell -n "Error in $0" + return 1 +fi +if [ ! -e "${DNBD3_MOD_PATH}" ]; then + warn "No such file of directory: ${DNBD3_MOD_PATH}" + emergency_shell -n "Error in $0" + return 1 +fi + +# load the kernel modules for dnbd3 and nbd +if ! insmod "${DNBD3_MOD_PATH}"; then + warn "Failed to load DNBD3 kernel module..." + emergency_shell -n "Error in $0" + return 1 +fi + +if ! insmod "${NBD_MOD_PATH}"; then + warn "Failed to load NBD kernel module..." + emergency_shell -n "Error in $0" + return 1 +fi + +return 0 diff --git a/testModule/module-setup.sh b/testModule/module-setup.sh index 839e5deb..efd79cf1 100644 --- a/testModule/module-setup.sh +++ b/testModule/module-setup.sh @@ -42,32 +42,67 @@ installkernel() { } install() { - # cause we need reboots - inst "$moddir/scripts/r" /usr/bin/r - # Needed to mount remote dnbd3 filesystem. - inst "$moddir/binaries/dnbd3-client" /usr/bin/dnbd3-client + ### BINARIES + # + # busybox: cause we want lightweight tools inst "$moddir/binaries/busybox" /usr/bin/busybox - # A generic wrapper program to prepend a "@" to each process spawned by - # given nested programs. + # dnbd3-client: needed to mount remote dnbd3 filesystem. + inst "$moddir/binaries/dnbd3-client" /usr/bin/dnbd3-client + # A generic wrapper program to prepend a "@" to each process + # spawned by given nested programs. inst "$moddir/binaries/systemd-preserve-process-marker" \ /usr/bin/systemd-preserve-process-marker # NOTE: These modules are build again Kernel: 3.10.0-229.1.2.el7.x86_64 + # TODO: build these in check() ! inst "$moddir/kernel_modules/dnbd3.ko" \ /usr/lib/modules/current/extra/dnbd3.ko inst "$moddir/kernel_modules/nbd.ko" \ /usr/lib/modules/current/extra/nbd.ko - # NOTE: Priority has to be lower than the network cmdline parsing hooks - # since we have to modify the some kernel parameter before. - inst_hook cmdline 00 "$moddir/hooks/cmdline.sh" - inst_hook cmdline 90 "$moddir/hooks/nbd-cmdline.sh" - inst_hook pre-udev 00 "$moddir/hooks/pre-udev.sh" - inst_hook pre-mount 10 "$moddir/hooks/pre-mount.sh" - inst_hook mount 10 "$moddir/hooks/mount.sh" + ### HOOKS + ## HOOK cmdline + # enables sysrq-shortcuts + inst_hook cmdline 00 "$moddir/hooks/cmdline/enable-sysrq.sh" + + # expands the ip parameter in the kernel command line to + # make it dracut-compatible + # TODO: dracut still parses this incorrectly... + inst_hook cmdline 10 "$moddir/hooks/cmdline/expand-kcl-ip.sh" + + # sets environment variables to tell dracut which device + # holds the future root filesystem + inst_hook cmdline 90 "$moddir/hooks/cmdline/mark-root-device.sh" + + ## HOOK pre-udev + # loads the dnbd3/nbd kernel modules + inst_hook pre-udev 00 "$moddir/hooks/pre-udev/load-dnbd3-nbd-modules.sh" + + ## HOOK pre-mount + # this is the main hook where all the magic is triggered + inst_hook pre-mount 10 "$moddir/hooks/pre-mount/mount-qcow.sh" + + ## HOOK mount + # this simply mounts the prepared /dev/root to $NEWROOT + # aka "the dracut way" + inst_hook mount 10 "$moddir/hooks/mount/mount-root-device.sh" + + ## HOOK pre-pivot + # this checks whether we found a partition suitable for + # the future /tmp and if so, mounts it + inst_hook pre-pivot 00 "$moddir/hooks/pre-pivot/mount-tmp.sh" + + ### SCRIPTS + # the main magic script containing all the functions needed + # to prepare the qcow2-based root filesystem inst "$moddir/scripts/setup-qcow2" /sbin/setup-qcow2 - inst "$moddir/scripts/setup-nbdroot" /sbin/setup-nbdroot + # the script triggered by udev upon finding the right partitions + inst "$moddir/scripts/prepare-disks" /sbin/prepare-disks + + # udev rules detecting 44, 45, 46 partitions and running + # 'prepare-disks' to do then format/mount/use them + inst "$moddir/udev/70-openslx-disk.rules" /etc/udev/rules.d/70-openslx-disk.rules # Debugging Uncomment this version if you need some useful debugging tools # in your iniramfs. diff --git a/testModule/scripts/prepare-disks b/testModule/scripts/prepare-disks new file mode 100755 index 00000000..28113cc7 --- /dev/null +++ b/testModule/scripts/prepare-disks @@ -0,0 +1,98 @@ +#!/bin/bash +############################################################################### +# GLOBALS +# + +declare -rg FLAG="/tmp/openslx.disks" +declare -rg OPENSLX_SYS_MOUNT="/opt/openslx/system" + +# +# END GLOBALS +############################################################################### + +############################################################################### +# FUNCTION DEFINITIONS +# +# helper to mount the OPENSLX_SYS partition to /opt/openslx/system +# Usage: mount_sys_part +mount_sys_part() { + if [ ! -b "$1" ]; then + warn "'$1' is not a block device?" + echo "!block: $1" >> /tmp/openslx.disks.log + return 1 + fi + + local OPENSLX_SYS_DEVICE="$1" + mkdir -p ${OPENSLX_SYS_MOUNT} + if ! mount -t auto "${OPENSLX_SYS_DEVICE}" "${OPENSLX_SYS_MOUNT}"; then + warn "Mounting '${OPENSLX_SYS_DEVICE}' to '${OPENSLX_SYS_MOUNT}' failed." + echo "mount phail" >> /tmp/openslx.disks.log + return 1 + fi + echo "ZOMG" >> /tmp/openslx.disks.log + return 0 + +} +# +# END FUNCTION DEFINITIONS +############################################################################### + +############################################################################### +# MAIN CODE +# + +command -v warn >/dev/null || . /lib/dracut-lib.sh + +# let check the arguments +if [ "$#" -ne 2 ]; then + warn "'$0' need 2 arguments: '$0 [OPENSLX_SYS|OPENSLX_TMP] '" + echo "Not enough args!" >> /tmp/openslx.disks.log + exit 1 +fi +# $1 sane? +if [ "x$1" != "xOPENSLX_SYS" ] && [ "x$1" != "xOPENSLX_TMP" ]; then + warn "First arg needs to be either 'OPENSLX_SYS' or 'OPENSLX_TMP'." + warn "Given: $1" + echo "OPENSLX? $1" >> /tmp/openslx.disks.log + exit 1 +fi +# $2 sane? +if [ ! -b "/dev/$2" ]; then + warn "Second arg appears not to be a block device!" + echo "block? $2" >> /tmp/openslx.disks.log + exit 1 +fi + +# ok all seems well +PART_TYPE="$1" +PART_DEV="/dev/$2" + +# lets check if we are already running +INSTANCES="$(grep "$PART_TYPE" "$FLAG" | busybox wc -l)" +if [ "$INSTANCES" -ge 1 ]; then + # uhoh we are not alone! + warn "'$0' already running for $PART_TYPE ... ignoring." + echo "already running for $PART_TYPE" >> /tmp/openslx.disks.log + exit 1 +fi + +# now comes the funny part. We write our pid to $FLAG in order to make sure +# we are the only instance of this script running. +echo "$PART_TYPE.$$" >> "$FLAG" + +# if we are still here, then we can go on and process the partition +echo "Processing: $PART_TYPE -> $PART_DEV" >> /tmp/openslx.disks.log + +if [ "$PART_TYPE" = "OPENSLX_TMP" ]; then + # mark it for later mounting! + echo "$PART_DEV" > /tmp/openslx.disk.tmp + exit 0 +fi +if [ "$PART_TYPE" = "OPENSLX_SYS" ]; then + # mount it now, since qemu-nbd needs it asap! + exit $(mount_sys_part "$PART_DEV") +fi + +# +# END MAIN CODE +############################################################################### diff --git a/testModule/scripts/setup-qcow2 b/testModule/scripts/setup-qcow2 index ba1ef6b1..b14ccd87 100755 --- a/testModule/scripts/setup-qcow2 +++ b/testModule/scripts/setup-qcow2 @@ -2,6 +2,7 @@ # dracut-lib to use debugging functions command -v warn >/dev/null || . /lib/dracut-lib.sh +command -v emergency_shell >/dev/null || . /lib/dracut-lib.sh ############################################################################### # GLOBALS @@ -12,6 +13,7 @@ declare -rg DNBD3_DEVICE="/dev/dnbd0" declare -rg DNBD3_SERVER="132.230.4.1" declare -rg DNBD3_IMAGE="stage4/joe/centos7" declare -rg DNBD3_RID="4" +declare -rg QCOW_CONTAINER="/opt/openslx/system/system.qcow2" # # END GLOBALS ############################################################################### @@ -49,18 +51,18 @@ connect_dnbd3() { # helper to create the qcow2 container file using # DNBD3_DEVICE as the base of the filesystem -# /run/test.qcow2 as the writable file +# QCOW_CONTAINER as the writable file # (our future rootfs) create_qcow() { # check if we already created the qcow2-container - [ -e /run/test.qcow2 ] && return 0 + [ -e "$QCOW_CONTAINER" ] && return 0 # we did not, let's create it if ! qemu-img create -f qcow2 -o \ - backing_file="$DNBD3_DEVICE",backing_fmt=qcow2 /run/test.qcow2; then + backing_file="$DNBD3_DEVICE",backing_fmt=qcow2 "$QCOW_CONTAINER"; then warn "Failed to create qcow2-Container from $DNBD3_DEVICE" emergency_shell -n "Error in $0" - rm -f -- /run/test.qcow2 + rm -f -- "$QCOW_CONTAINER" return 1 fi return 0 @@ -75,7 +77,7 @@ export_qcow() { fi # since we use the wrapper, we need a little more logic to see if it runs /usr/bin/systemd-preserve-process-marker \ - /usr/bin/qemu-nbd -t -p 2000 /run/test.qcow2 & + /usr/bin/qemu-nbd -t -p 2000 "$QCOW_CONTAINER" & # the wrapper returns 255 if the qemu-nbd binary is missing local qemu_nbd_pid="$!" for i in 0.5 1 2; do @@ -102,17 +104,26 @@ export_qcow() { # fallback return 1 } +# helper to mount the qcow2-container per nbd +connect_qcow() { + # try to mount the locally exported qcow2-container using nbd-client + if nbd-client --systemd-mark --persist 127.0.0.1 2000 /dev/nbd0; then + # it worked, lets set the symlink to /dev/root as dracut needs it + # later on to mount that device to the future root (/sysroot) + ln -sf /dev/nbd0 /dev/root + return 0 + else + # this is pretty bad, dracut would spawn an emergency later on + # since there is no /dev/root to mount. + # For debugging purposes, we drop an emergency shell ourselves + # if the mount fails. + warn "Could not mount /dev/nbd0 from 127.0.0.1:2000." + emergency_shell -n "Error in $0" + return 1 + fi +} # # END FUNCTION DEFINITIONS ############################################################################### -############################################################################### -# MAIN CODE -# -#check_dnbd3 || return 1 -connect_dnbd3 || exit 1 -create_qcow || exit 1 -export_qcow || exit 1 - -# all good, we are done :) -exit 0 +# No main, use functions! diff --git a/testModule/udev/70-openslx-disk.rules b/testModule/udev/70-openslx-disk.rules new file mode 100644 index 00000000..3f5e382f --- /dev/null +++ b/testModule/udev/70-openslx-disk.rules @@ -0,0 +1,8 @@ +# GPT rules +KERNEL=="sd?[0-9]" SUBSYSTEM=="block" ENV{ID_PART_TABLE_TYPE}=="gpt" ENV{ID_PART_ENTRY_NAME}=="OPENSLX_TMP" RUN+="/sbin/prepare-disks %E{ID_PART_ENTRY_NAME} %k" +KERNEL=="sd?[0-9]" SUBSYSTEM=="block" ENV{ID_PART_TABLE_TYPE}=="gpt" ENV{ID_PART_ENTRY_NAME}=="OPENSLX_SYS" RUN+="/sbin/prepare-disks %E{ID_PART_ENTRY_NAME} %k" + +# MBR rules +KERNEL=="sd?[0-9]" SUBSYSTEM=="block" ENV{ID_PART_TABLE_TYPE}=="dos" ENV{ID_PART_ENTRY_TYPE}=="0x44" RUN+="/sbin/prepare-disks OPENSLX_TMP %k" +KERNEL=="sd?[0-9]" SUBSYSTEM=="block" ENV{ID_PART_TABLE_TYPE}=="dos" ENV{ID_PART_ENTRY_TYPE}=="0x46" RUN+="/sbin/prepare-disks OPENSLX_SYS %k" + -- cgit v1.2.3-55-g7522