summary refs log tree commit diff
diff options
context:
space:
mode:
authorWill Fancher <elvishjerricco@gmail.com>2022-12-29 00:00:29 -0500
committerGitHub <noreply@github.com>2022-12-29 00:00:29 -0500
commit3d7270abd5b28bc8ef6c64a7eb15f41bdc9717f0 (patch)
tree1bbf4db316112ef6e28aa2077d260d2a1e70f7f3
parent61345687940092e1cfda9aae7aec152a5a716063 (diff)
parent51809df3028ad65ff81b2badf7fef04bd9ed5921 (diff)
downloadnixpkgs-3d7270abd5b28bc8ef6c64a7eb15f41bdc9717f0.tar
nixpkgs-3d7270abd5b28bc8ef6c64a7eb15f41bdc9717f0.tar.gz
nixpkgs-3d7270abd5b28bc8ef6c64a7eb15f41bdc9717f0.tar.bz2
nixpkgs-3d7270abd5b28bc8ef6c64a7eb15f41bdc9717f0.tar.lz
nixpkgs-3d7270abd5b28bc8ef6c64a7eb15f41bdc9717f0.tar.xz
nixpkgs-3d7270abd5b28bc8ef6c64a7eb15f41bdc9717f0.tar.zst
nixpkgs-3d7270abd5b28bc8ef6c64a7eb15f41bdc9717f0.zip
Merge pull request #203171 from ElvishJerricco/zfs-fix-requested-credentials
nixos/zfs: Ensure pool has datasets to decrypt
-rw-r--r--nixos/modules/tasks/filesystems/zfs.nix25
-rw-r--r--nixos/tests/zfs.nix174
2 files changed, 126 insertions, 73 deletions
diff --git a/nixos/modules/tasks/filesystems/zfs.nix b/nixos/modules/tasks/filesystems/zfs.nix
index 0f14f2b501c..6c775964751 100644
--- a/nixos/modules/tasks/filesystems/zfs.nix
+++ b/nixos/modules/tasks/filesystems/zfs.nix
@@ -97,10 +97,15 @@ let
     in
       map (x: "${mountPoint x}.mount") (getPoolFilesystems pool);
 
-  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)}";
+  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}";
+  };
 
   createImportService = { pool, systemd, force, prefix ? "" }:
     nameValuePair "zfs-import-${pool}" {
@@ -124,7 +129,9 @@ let
         RemainAfterExit = true;
       };
       environment.ZFS_FORCE = optionalString force "-f";
-      script = (importLib {
+      script = let
+        keyLocations = getKeyLocations pool;
+      in (importLib {
         # See comments at importLib definition.
         zpoolCmd = "${cfgZfs.package}/sbin/zpool";
         awkCmd = "${pkgs.gawk}/bin/awk";
@@ -139,10 +146,8 @@ let
         done
         poolImported "${pool}" || poolImport "${pool}"  # Try one last time, e.g. to import a degraded pool.
         if poolImported "${pool}"; then
-          ${optionalString (if isBool cfgZfs.requestEncryptionCredentials
-                            then cfgZfs.requestEncryptionCredentials
-                            else cfgZfs.requestEncryptionCredentials != []) ''
-            ${getKeyLocations pool} | while IFS=$'\t' read ds kl ks; do
+          ${optionalString keyLocations.hasKeys ''
+            ${keyLocations.command} | while IFS=$'\t' read ds kl ks; do
               {
               if [[ "$ks" != unavailable ]]; then
                 continue
@@ -565,7 +570,7 @@ in
               ''
               else concatMapStrings (fs: ''
                 zfs load-key -- ${escapeShellArg fs}
-              '') cfgZfs.requestEncryptionCredentials}
+              '') (filter (x: datasetToPool x == pool) cfgZfs.requestEncryptionCredentials)}
         '') rootPools));
 
         # Systemd in stage 1
diff --git a/nixos/tests/zfs.nix b/nixos/tests/zfs.nix
index 29df691cecb..3e55369daa0 100644
--- a/nixos/tests/zfs.nix
+++ b/nixos/tests/zfs.nix
@@ -17,103 +17,151 @@ let
     makeTest {
       name = "zfs-" + name;
       meta = with pkgs.lib.maintainers; {
-        maintainers = [ adisbladis ];
+        maintainers = [ adisbladis elvishjerricco ];
       };
 
       nodes.machine = { pkgs, lib, ... }:
         let
           usersharePath = "/var/lib/samba/usershares";
         in {
-        virtualisation.emptyDiskImages = [ 4096 ];
+        virtualisation = {
+          emptyDiskImages = [ 4096 4096 ];
+          useBootLoader = true;
+          useEFIBoot = true;
+        };
+        boot.loader.systemd-boot.enable = true;
+        boot.loader.timeout = 0;
+        boot.loader.efi.canTouchEfiVariables = true;
         networking.hostId = "deadbeef";
         boot.kernelPackages = kernelPackage;
         boot.supportedFilesystems = [ "zfs" ];
         boot.zfs.enableUnstable = enableUnstable;
 
-        services.samba = {
-          enable = true;
-          extraConfig = ''
-            registry shares = yes
-            usershare path = ${usersharePath}
-            usershare allow guests = yes
-            usershare max shares = 100
-            usershare owner only = no
-          '';
+        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";
+            };
+          };
         };
-        systemd.services.samba-smbd.serviceConfig.ExecStartPre =
-          "${pkgs.coreutils}/bin/mkdir -m +t -p ${usersharePath}";
 
-        environment.systemPackages = [ pkgs.parted ];
+        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" ];
+          };
+        };
 
-        # Setup regular fileSystems machinery to ensure forceImportAll can be
-        # tested via the regular service units.
-        virtualisation.fileSystems = {
-          "/forcepool" = {
+        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" = {
             device = "forcepool";
             fsType = "zfs";
             options = [ "noauto" ];
           };
         };
-
-        # 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";
       };
 
       testScript = ''
+        machine.wait_for_unit("multi-user.target")
         machine.succeed(
-            "modprobe zfs",
             "zpool status",
-            "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",
+            "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",
         )
 
-        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",
-        )
+        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("password\n")
+            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",
+            )
 
         with subtest("boot.zfs.forceImportAll works"):
             machine.succeed(
                 "rm /etc/hostid",
                 "zgenhostid deadcafe",
-                "zpool create forcepool /dev/vdb1 -O mountpoint=legacy",
+                "zpool create forcepool /dev/vdc1 -O mountpoint=legacy",
+                "bootctl set-default nixos-generation-1-specialisation-forcepool.conf",
+                "rm /etc/hostid",
+                "sync",
             )
-            machine.shutdown()
-            machine.start()
-            machine.succeed("udevadm settle")
+            machine.crash()
+            machine.wait_for_unit("multi-user.target")
             machine.fail("zpool import forcepool")
             machine.succeed(
-                "systemctl start zfs-import-forcepool.service",
-                "mount -t zfs forcepool /tmp/mnt",
+                "systemctl start forcepool.mount",
+                "mount | grep forcepool",
             )
       '' + extraTest;