From 5df5c822ea625da7ef1acadc06fa4cb10133595e Mon Sep 17 00:00:00 2001 From: Daniel Barlow Date: Wed, 3 Apr 2024 23:17:36 +0100 Subject: [PATCH] convert mount service to trigger Good: this means it's not hanging holding the s6 dataase lock. Bad: it's the ugliest implementation and doesn't deserve to be preserved (tbf the ugliness is not new) --- modules/mount/service.nix | 25 ++++++++++---- tests/ci.nix | 1 + tests/inout/configuration.nix | 61 +++++++++++++++++++++++++++++++++++ tests/inout/script.expect | 47 +++++++++++++++++++++++++++ tests/inout/test.nix | 26 +++++++++++++++ 5 files changed, 154 insertions(+), 6 deletions(-) create mode 100644 tests/inout/configuration.nix create mode 100644 tests/inout/script.expect create mode 100644 tests/inout/test.nix diff --git a/modules/mount/service.nix b/modules/mount/service.nix index 67fa768..7491bff 100644 --- a/modules/mount/service.nix +++ b/modules/mount/service.nix @@ -4,15 +4,28 @@ }: { device, mountpoint, options, fstype }: let - inherit (liminix.services) oneshot; -in oneshot { - name = "mount.${lib.escapeURL mountpoint}"; - up = '' + inherit (liminix.services) longrun oneshot; + options_string = + if options == [] then "" else "-o ${lib.concatStringsSep "," options}"; + mount_service = oneshot { + name = "mount.${lib.escapeURL mountpoint}"; + timeout-up = 3600; + up = "mount -t ${fstype} ${options_string} ${device} ${mountpoint}"; + down = "umount ${mountpoint}"; + }; +in longrun { + name = "watch-mount.${lib.strings.sanitizeDerivationName mountpoint}"; + isTrigger = true; + buildInputs = [ mount_service ]; + + # This accommodates bringing the service up when the device appears. + # It doesn't bring it down on unplug because unmount will probably + # fail anyway (so don't do that) + run = '' while ! findfs ${device}; do echo waiting for device ${device} sleep 1 done - mount -t ${fstype} -o ${lib.concatStringsSep "," options} ${device} ${mountpoint} + s6-rc -b -u change ${mount_service.name} ''; - down = "umount ${mountpoint}"; } diff --git a/tests/ci.nix b/tests/ci.nix index 888a2d6..4fbd953 100644 --- a/tests/ci.nix +++ b/tests/ci.nix @@ -9,4 +9,5 @@ fennel = import ./fennel/test.nix; tftpboot = import ./tftpboot/test.nix; updown = import ./updown/test.nix; + inout = import ./inout/test.nix; } diff --git a/tests/inout/configuration.nix b/tests/inout/configuration.nix new file mode 100644 index 0000000..6c984a1 --- /dev/null +++ b/tests/inout/configuration.nix @@ -0,0 +1,61 @@ +{ config, pkgs, lib, modulesPath, ... } : +let + inherit (pkgs.liminix.services) bundle oneshot longrun; + inherit (pkgs.pseudofile) dir symlink; + inherit (pkgs) serviceFns; + + svc = config.system.service; + +in rec { + imports = [ + "${modulesPath}/dhcp6c" + "${modulesPath}/dnsmasq" + "${modulesPath}/firewall" + "${modulesPath}/hostapd" + "${modulesPath}/network" + "${modulesPath}/ssh" + "${modulesPath}/mount" + ]; + + filesystem = dir { srv = dir {}; }; + + kernel = { + config = { + USB = "y"; + USB_EHCI_HCD = "y"; + USB_EHCI_HCD_PLATFORM = "y"; + USB_OHCI_HCD = "y"; + USB_OHCI_HCD_PLATFORM = "y"; + USB_SUPPORT = "y"; + USB_COMMON = "y"; + USB_STORAGE = "y"; + USB_STORAGE_DEBUG = "n"; + USB_UAS = "y"; + USB_ANNOUNCE_NEW_DEVICES = "y"; + SCSI = "y"; + BLK_DEV_SD = "y"; + USB_PRINTER = "y"; + MSDOS_PARTITION = "y"; + EFI_PARTITION = "y"; + EXT4_FS = "y"; + EXT4_USE_FOR_EXT2 = "y"; + FS_ENCRYPTION = "y"; + }; + }; + + rootfsType = "jffs2"; + hostname = "inout"; + + services.mount_external_disk = svc.mount.build { + device = "LABEL=backup-disk"; + mountpoint = "/srv"; + fstype = "ext4"; + }; + + services.sshd = svc.ssh.build { }; + + defaultProfile.packages = with pkgs; [ + min-collect-garbage + tcpdump + ]; +} diff --git a/tests/inout/script.expect b/tests/inout/script.expect new file mode 100644 index 0000000..0ee2919 --- /dev/null +++ b/tests/inout/script.expect @@ -0,0 +1,47 @@ +set timeout 10 + +proc chat {instr outstr} { + expect { + $instr { send $outstr } + timeout { exit 1 } + } +} +spawn socat -,echo=0,icanon=1 unix-connect:vm/monitor +set monitor_id $spawn_id + +# expect "(qemu)" +# send "set_link virtio-net-pci.1 off\n" +# expect "(qemu)" +# send "set_link virtio-net-pci.0 off\n" +# expect "(qemu)" +# send "c\r\n" + +spawn socat unix-connect:vm/console - +set console_id $spawn_id + +expect "BusyBox" +chat "#" "PS1=RE\\ADY_\\ ; stty -echo \r" +chat "READY_" "s6-rc -b -a list\r" + +chat "watch-mount" "\r" + +set spawn_id $monitor_id +chat "QEMU" "device_add usb-storage,bus=xhci.0,drive=usbstick\n" +chat "(qemu)" "version\r" + +set spawn_id $console_id + +expect { + "mounted filesystem" { } + timeout { exit 1 } +} + + +send "\r" +chat "READY_" "s6-rc -b -a list\r" +chat "READY_" "cat /proc/mounts\r" + +expect { + "/srv" { } + timeout { exit 1 } +} diff --git a/tests/inout/test.nix b/tests/inout/test.nix new file mode 100644 index 0000000..9e75f31 --- /dev/null +++ b/tests/inout/test.nix @@ -0,0 +1,26 @@ +{ + liminix +, nixpkgs +}: +let img = (import liminix { + device = import "${liminix}/devices/qemu/"; + liminix-config = ./configuration.nix; + }).outputs.vmroot; + pkgs = import { overlays = [(import ../../overlay.nix)]; }; +in pkgs.runCommand "check" { + nativeBuildInputs = with pkgs; [ + expect + socat + e2fsprogs + util-linux # for sfdisk, fallocate + ] ; +} '' +mkdir vm +dd if=/dev/zero of=./vm/stick.e2fs bs=1M count=32 +mkfs.ext2 -L backup-disk ./vm/stick.e2fs +cat <(dd if=/dev/zero bs=512 count=4) ./vm/stick.e2fs > ./vm/stick.img +echo '4,-,L,*' | sfdisk ./vm/stick.img + +${img}/run.sh --background ./vm --flag -device --flag usb-ehci,id=xhci --flag -drive --flag if=none,id=usbstick,format=raw,file=$(pwd)/vm/stick.img +expect ${./script.expect} | tee $out +''