NBD root: add support for LVM/LUKS
authorDavid Dillow <dave@thedillows.org>
Thu, 11 Jun 2009 05:36:10 +0000 (01:36 -0400)
committerDavid Dillow <dave@thedillows.org>
Thu, 11 Jun 2009 05:47:11 +0000 (01:47 -0400)
With this change, we can now use LUKS and LVM over NBD. There are
some decisions to be made regarding where we should get the fstype
and fsoptions from (DHCP root vs rootfstype= etc), but the basic
functionality is there.

modules.d/95nbd/nbdroot
test/TEST-40-NBD/client-init
test/TEST-40-NBD/create-root.sh [new file with mode: 0755]
test/TEST-40-NBD/cryptroot-ask [new file with mode: 0755]
test/TEST-40-NBD/dhcpd.conf
test/TEST-40-NBD/server-init
test/TEST-40-NBD/test.sh

index 3475239..b7f4cc4 100755 (executable)
@@ -81,16 +81,16 @@ while [ ! -b /dev/nbd0 ]; do
     i=$(( $i + 1))
 done
 
-# XXX netroot expects to have the handler mount things, but we should
-# XXX allow LVM, LUKS, etc over nbd
+# If we didn't get a root= on the command line, then we need to
+# add the udev rules for mounting the nbd0 device
+if [ ! -e /etc/udev/rules.d/99-mount.rules ]; then
+    printf 'KERNEL=="%s", RUN+="/bin/mount -t %s -o %s %s %s"\n' \
+       nbd0 "$nbdfstype" "$fsopts" /dev/nbd0 "$NEWROOT" \
+               > /etc/udev/rules.d/99-mount.rules
+fi
 
 nbd-client $preopts "$nbdserver" "$nbdport" /dev/nbd0 $opts || exit 1
 
-if ! mount -t $nbdfstype -o$fsopts /dev/nbd0 $NEWROOT; then
-    # Mount failed, clean up after ourselves so if we try a different
-    # interface it can succeed
-    nbd-client -d /dev/nbd0
-    exit 1
-fi
-
+# NBD doesn't emit uevents when it gets connected, so kick it
+echo change > /sys/block/nbd0/uevent
 exit 0
index 88b3d65..b0af521 100755 (executable)
@@ -1,7 +1,8 @@
 #!/bin/sh
 exec >/dev/console 2>&1
 while read dev fs fstype opts rest; do
-    [ "$dev" != "/dev/nbd0" ] && continue
+    [ "$dev" == "rootfs" ] && continue
+    [ "$fs" != "/" ] && continue
     echo "nbd-OK $fstype $opts" >/dev/sda
     break
 done < /proc/mounts
diff --git a/test/TEST-40-NBD/create-root.sh b/test/TEST-40-NBD/create-root.sh
new file mode 100755 (executable)
index 0000000..b5e45e2
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/sh
+# don't let udev and this script step on eachother's toes
+for x in 63-luks.rules 64-lvm.rules 70-mdadm.rules 99-mount-rules; do
+    > "/etc/udev/rules.d/$x"
+done
+udevadm control --reload-rules
+echo -n test >keyfile
+cryptsetup -q luksFormat /dev/sdb /keyfile
+echo "The passphrase is test"
+cryptsetup luksOpen /dev/sdb 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 && \
+mke2fs -j /dev/dracut/root && \
+mkdir -p /sysroot && \
+mount /dev/dracut/root /sysroot && \
+cp -a -t /sysroot /source/* && \
+umount /sysroot && \
+lvm lvchange -a n /dev/dracut/root && \
+cryptsetup luksClose /dev/mapper/dracut_crypt_test && \
+echo "dracut-root-block-created" >/dev/sda
+poweroff -f
diff --git a/test/TEST-40-NBD/cryptroot-ask b/test/TEST-40-NBD/cryptroot-ask
new file mode 100755 (executable)
index 0000000..db27c5b
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+[ -b /dev/mapper/$2 ] && exit 0
+echo -n test >/keyfile
+/sbin/cryptsetup luksOpen $1 $2 </keyfile
+
index f9eeead..942bc6a 100644 (file)
@@ -53,4 +53,14 @@ subnet 192.168.50.0 netmask 255.255.255.0 {
                        fixed-address 192.168.50.101;
                }
        }
+
+       group {
+               host nbd-6 {
+                       # Use the encrypted image
+                       option root-path "nbd:192.168.50.1:2001:ext2:errors=panic";
+
+                       hardware ethernet 52:54:00:12:34:05;
+                       fixed-address 192.168.50.101;
+               }
+       }
 }
index aa6a17b..6c2db08 100755 (executable)
@@ -9,6 +9,7 @@ ip link set lo up
 ip addr add 192.168.50.1/24 dev eth0
 ip link set eth0 up
 nbd-server 2000 /dev/sdb -C /dev/null
+nbd-server 2001 /dev/sdc -C /dev/null
 >/var/lib/dhcpd/dhcpd.leases
 dhcpd -cf /etc/dhcpd.conf
 sh -i
index 39ec746..a70092d 100755 (executable)
@@ -10,7 +10,8 @@ run_server() {
     # Start server first
     echo "NBD TEST SETUP: Starting DHCP/NBD server"
 
-    $testdir/run-qemu -hda server.ext2 -hdb nbd.ext2 -m 512M -nographic \
+    $testdir/run-qemu -hda server.ext2 -hdb nbd.ext2 -hdc encrypted.ext2 \
+       -m 512M -nographic \
        -net nic,macaddr=52:54:00:12:34:56,model=e1000 \
        -net socket,mcast=230.0.0.1:1234 \
        -serial udp:127.0.0.1:9999 \
@@ -154,6 +155,62 @@ test_run() {
 
     client_test "NBD netroot=dhcp DHCP root-path nbd:srv:port:fstype:fsopts" \
        52:54:00:12:34:04 "netroot=dhcp" ext2 errors=panic || return 1
+
+    # Encrypted root handling via LVM/LUKS over NBD
+
+    client_test "NBD root=/dev/dracut/root netroot=nbd:IP:port" \
+       52:54:00:12:34:00 \
+       "root=/dev/dracut/root netroot=nbd:192.168.50.1:2001" || return 1
+
+    # XXX This should be ext2,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=/dev/dracut/root netroot=dhcp (w/ fstype and opts)" \
+       52:54:00:12:34:05 \
+       "root=/dev/dracut/root netroot=dhcp" || return 1
+}
+
+make_encrypted_root() {
+    # Create the blank file to use as a root filesystem
+    dd if=/dev/zero of=encrypted.ext2 bs=1M count=20
+    dd if=/dev/zero of=flag.img bs=1M count=1
+
+    kernel=$KVERSION
+    # Create what will eventually be our root filesystem onto an overlay
+    (
+       initdir=overlay/source
+       . $basedir/dracut-functions
+       dracut_install sh df free ls shutdown poweroff stty cat ps ln ip \
+           /lib/terminfo/l/linux mount dmesg mkdir cp ping
+       inst ./client-init /sbin/init
+       find_binary plymouth >/dev/null && dracut_install plymouth
+       (cd "$initdir"; mkdir -p dev sys proc etc var/run tmp )
+    )
+
+    # second, install the files needed to make the root filesystem
+    (
+       initdir=overlay
+       . $basedir/dracut-functions
+       dracut_install mke2fs poweroff cp umount
+       inst_simple ./create-root.sh /pre-mount/01create-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.
+    $basedir/dracut -l -i overlay / \
+       -m "dash crypt lvm mdraid udev-rules base rootfs-block" \
+       -d "ata_piix ext2 sd_mod" \
+       -f initramfs.makeroot $KVERSION || return 1
+    rm -rf overlay
+
+    # Invoke KVM and/or QEMU to actually create the target filesystem.
+    $testdir/run-qemu -hda flag.img -hdb encrypted.ext2 -m 512M \
+       -nographic -net none \
+       -kernel "/boot/vmlinuz-$kernel" \
+       -append "root=/dev/dracut/root rw quiet console=ttyS0,115200n81" \
+       -initrd initramfs.makeroot  || return 1
+    grep -m 1 -q dracut-root-block-created flag.img || return 1
 }
 
 make_client_root() {
@@ -222,6 +279,7 @@ make_server_root() {
 }
 
 test_setup() {
+    make_encrypted_root || return 1
     make_client_root || return 1
     make_server_root || return 1
 
@@ -231,6 +289,7 @@ test_setup() {
        . $basedir/dracut-functions
        dracut_install poweroff shutdown
        inst_simple ./hard-off.sh /emergency/01hard-off.sh
+       inst ./cryptroot-ask /sbin/cryptroot-ask
     )
 
     sudo $basedir/dracut -l -i overlay / \
@@ -250,7 +309,8 @@ test_cleanup() {
        rm -f server.pid
     fi
     rm -fr overlay mnt
-    rm -f flag.img server.ext2 nbd.ext2 initramfs.server initramfs.testing
+    rm -f flag.img server.ext2 nbd.ext2 encrypted.ext2
+    rm -f initramfs.server initramfs.testing initramfs.makeroot
 }
 
 . $testdir/test-functions