Change:
Steps to reproduce the behavior: to a list. (in my case, these are backup pools to which I raw-send encrypted datasets, none of their content is expected to be mounted under normal circumstances). boot process still requests the keys for datasets that are not in the list from step 1. I should only ever see decryption prompts for datasets that I want decrypted. system: host os: multi-user?: sandbox: version: channels(novenary): channels(root): nixpkgs:

Discussion:
in map (x: "${mountPoint x}.mount") (getPoolFilesystems pool); <del> getKeyLocations = pool: if isBool cfgZfs.requestEncryptionCredentials then "${cfgZfs.package}/sbin/zfs list -rHo name,keylocation,keystatus ${pool}" else "${cfgZfs.package}/sbin/zfs list -Ho name,keylocation,keystatus ${toString (filter (x: datasetToPool x == pool) cfgZfs.requestEncryptionCredentials)}"; </del> <ins> getKeyLocations = pool: if isBool cfgZfs.requestEncryptionCredentials then { hasKeys = cfgZfs.requestEncryptionCredentials; command = "${cfgZfs.package}/sbin/zfs list -rHo name,keylocation,keystatus ${pool}"; } else let keys = filter (x: datasetToPool x == pool) cfgZfs.requestEncryptionCredentials; in { hasKeys = keys != []; command = "${cfgZfs.package}/sbin/zfs list -Ho name,keylocation,keystatus ${toString keys}"; }; </ins> createImportService = { pool, systemd, force, prefix ? "" }: nameValuePair "zfs-import-${pool}" {

RemainAfterExit = true; }; environment.ZFS_FORCE = optionalString force "-f"; <del> script = (importLib { </del> <ins> script = let keyLocations = getKeyLocations pool; in (importLib { </ins> # See comments at importLib definition. zpoolCmd = "${cfgZfs.package}/sbin/zpool"; awkCmd = "${pkgs.gawk}/bin/awk";

done poolImported "${pool}" || poolImport "${pool}"  # Try one last time, e.g. to import a degraded pool. if poolImported "${pool}"; then <del> ${optionalString (if isBool cfgZfs.requestEncryptionCredentials then cfgZfs.requestEncryptionCredentials else cfgZfs.requestEncryptionCredentials != []) '' ${getKeyLocations pool} | while IFS=$'t' read ds kl ks; do </del> <ins> ${optionalString keyLocations.hasKeys '' ${keyLocations.command} | while IFS=$'t' read ds kl ks; do </ins> { if [[ "$ks" != unavailable ]]; then continue

'' else concatMapStrings (fs: '' zfs load-key -- ${escapeShellArg fs} <del> '') cfgZfs.requestEncryptionCredentials} </del> <ins> '') (filter (x: datasetToPool x == pool) cfgZfs.requestEncryptionCredentials)} </ins> '') rootPools)); # Systemd in stage 1

makeTest { name = "zfs-" + name; meta = with pkgs.lib.maintainers; { <del> maintainers = [ adisbladis ]; </del> <ins> maintainers = [ adisbladis elvishjerricco ]; </ins> }; nodes.machine = { pkgs, lib, ... }: let usersharePath = "/var/lib/samba/usershares"; in { <del> virtualisation.emptyDiskImages = [ 4096 ]; </del> <ins> virtualisation = { emptyDiskImages = [ 4096 4096 ]; useBootLoader = true; useEFIBoot = true; }; boot.loader.systemd-boot.enable = true; boot.loader.timeout = 0; boot.loader.efi.canTouchEfiVariables = true; </ins> networking.hostId = "deadbeef"; boot.kernelPackages = kernelPackage; boot.supportedFilesystems = [ "zfs" ]; boot.zfs.enableUnstable = enableUnstable; <del> services.samba = { enable = true; extraConfig = '' registry shares = yes usershare path = ${usersharePath} usershare allow guests = yes usershare max shares = 100 usershare owner only = no ''; </del> <ins> environment.systemPackages = [ pkgs.parted ]; # /dev/disk/by-id doesn't get populated in the NixOS test framework boot.zfs.devNodes = "/dev/disk/by-uuid"; specialisation.samba.configuration = { services.samba = { enable = true; extraConfig = '' registry shares = yes usershare path = ${usersharePath} usershare allow guests = yes usershare max shares = 100 usershare owner only = no ''; }; systemd.services.samba-smbd.serviceConfig.ExecStartPre = "${pkgs.coreutils}/bin/mkdir -m +t -p ${usersharePath}"; virtualisation.fileSystems = { "/tmp/mnt" = { device = "rpool/root"; fsType = "zfs"; }; }; </ins> }; <del> systemd.services.samba-smbd.serviceConfig.ExecStartPre = "${pkgs.coreutils}/bin/mkdir -m +t -p ${usersharePath}"; environment.systemPackages = [ pkgs.parted ]; </del> <ins> specialisation.encryption.configuration = { boot.zfs.requestEncryptionCredentials = [ "automatic" ]; virtualisation.fileSystems."/automatic" = { device = "automatic"; fsType = "zfs"; }; virtualisation.fileSystems."/manual" = { device = "manual"; fsType = "zfs"; }; virtualisation.fileSystems."/manual/encrypted" = { device = "manual/encrypted"; fsType = "zfs"; options = [ "noauto" ]; }; }; </ins> <del> # Setup regular fileSystems machinery to ensure forceImportAll can be # tested via the regular service units. virtualisation.fileSystems = { "/forcepool" = { </del> <ins> specialisation.forcepool.configuration = { systemd.services.zfs-import-forcepool.wantedBy = lib.mkVMOverride [ "forcepool.mount" ]; systemd.targets.zfs.wantedBy = lib.mkVMOverride []; boot.zfs.forceImportAll = true; virtualisation.fileSystems."/forcepool" = { </ins> device = "forcepool"; fsType = "zfs"; options = [ "noauto" ]; }; }; <del> # forcepool doesn't exist at first boot, and we need to manually test # the import after tweaking the hostId. systemd.services.zfs-import-forcepool.wantedBy = lib.mkVMOverride []; systemd.targets.zfs.wantedBy = lib.mkVMOverride []; boot.zfs.forceImportAll = true; # /dev/disk/by-id doesn't get populated in the NixOS test framework boot.zfs.devNodes = "/dev/disk/by-uuid"; </del> }; testScript = '' <ins> machine.wait_for_unit("multi-user.target") </ins> machine.succeed( <del> "modprobe zfs", </del> "zpool status", <del> "ls /dev", "mkdir /tmp/mnt", "udevadm settle", "parted --script /dev/vdb mklabel msdos", "parted --script /dev/vdb -- mkpart primary 1024M -1s", "udevadm settle", "zpool create rpool /dev/vdb1", "zfs create -o mountpoint=legacy rpool/root", # shared datasets cannot have legacy mountpoint "zfs create rpool/shared_smb", "mount -t zfs rpool/root /tmp/mnt", "udevadm settle", # wait for samba services "systemctl is-system-running --wait", "zfs set sharesmb=on rpool/shared_smb", "zfs share rpool/shared_smb", "smbclient -gNL localhost | grep rpool_shared_smb", "umount /tmp/mnt", "zpool destroy rpool", "udevadm settle", </del> <ins> "parted --script /dev/vdc mklabel msdos", "parted --script /dev/vdc -- mkpart primary 1024M -1s", "parted --script /dev/vdd mklabel msdos", "parted --script /dev/vdd -- mkpart primary 1024M -1s", </ins> ) <del> machine.succeed( 'echo password | zpool create -o altroot="/tmp/mnt" ' + "-O encryption=aes-256-gcm -O keyformat=passphrase rpool /dev/vdb1", "zfs create -o mountpoint=legacy rpool/root", "mount -t zfs rpool/root /tmp/mnt", "udevadm settle", "umount /tmp/mnt", "zpool destroy rpool", "udevadm settle", ) </del> <ins> with subtest("sharesmb works"): machine.succeed( "zpool create rpool /dev/vdc1", "zfs create -o mountpoint=legacy rpool/root", # shared datasets cannot have legacy mountpoint "zfs create rpool/shared_smb", "bootctl set-default nixos-generation-1-specialisation-samba.conf", "sync", ) machine.crash() machine.wait_for_unit("multi-user.target") machine.succeed( "zfs set sharesmb=on rpool/shared_smb", "zfs share rpool/shared_smb", "smbclient -gNL localhost | grep rpool_shared_smb", "umount /tmp/mnt", "zpool destroy rpool", ) with subtest("encryption works"): machine.succeed( 'echo password | zpool create -O mountpoint=legacy ' + "-O encryption=aes-256-gcm -O keyformat=passphrase automatic /dev/vdc1", "zpool create -O mountpoint=legacy manual /dev/vdd1", "echo otherpass | zfs create " + "-o encryption=aes-256-gcm -o keyformat=passphrase manual/encrypted", "bootctl set-default nixos-generation-1-specialisation-encryption.conf", "sync", "zpool export automatic", "zpool export manual", ) machine.crash() machine.start() machine.wait_for_console_text("Starting password query on") machine.send_console("passwordn") machine.wait_for_unit("multi-user.target") machine.succeed( "zfs get keystatus manual/encrypted | grep unavailable", "echo otherpass | zfs load-key manual/encrypted", "systemctl start manual-encrypted.mount", "umount /automatic /manual/encrypted /manual", "zpool destroy automatic", "zpool destroy manual", ) </ins> with subtest("boot.zfs.forceImportAll works"): machine.succeed( "rm /etc/hostid", "zgenhostid deadcafe", <del> "zpool create forcepool /dev/vdb1 -O mountpoint=legacy", </del> <ins> "zpool create forcepool /dev/vdc1 -O mountpoint=legacy", "bootctl set-default nixos-generation-1-specialisation-forcepool.conf", "rm /etc/hostid", "sync", </ins> ) <del> machine.shutdown() machine.start() machine.succeed("udevadm settle") </del> <ins> machine.crash() machine.wait_for_unit("multi-user.target") </ins> machine.fail("zpool import forcepool") machine.succeed( <del> "systemctl start zfs-import-forcepool.service", "mount -t zfs forcepool /tmp/mnt", </del> <ins> "systemctl start forcepool.mount", "mount | grep forcepool", </ins> ) '' + extraTest;