diff --git a/ci.nix b/ci.nix index cdb3198..3c49ab1 100644 --- a/ci.nix +++ b/ci.nix @@ -3,6 +3,6 @@ let in { test = pkgs.writeScript "test" '' #!/bin/sh - nix-build "${toString ./tests/test.nix}"; + nix-build "${toString ./tests}"; ''; } diff --git a/default.nix b/default.nix index d20b67e..51b70f5 100644 --- a/default.nix +++ b/default.nix @@ -4,12 +4,13 @@ with builtins; let - helper.find-device = device: let - environment = helper.device-id device; - in + helper.find-device = device: + let + environment = helper.device-id device; + in # DEVICE points already to /dev/disk, so we don't handle it via /dev/disk/by-path if hasPrefix "/dev/disk" device then - "${environment}='${device}'" + "${environment}='${device}'" else '' ${environment}=$(for x in $(find /dev/disk/{by-path,by-id}/); do dev=$x @@ -38,42 +39,65 @@ let }; }; + config.zfs_filesystem = q: x: { + fileSystems.${x.mountpoint} = { + device = q.device; + fsType = "zfs"; + }; + }; + config.devices = q: x: - foldl' recursiveUpdate {} (mapAttrsToList (name: config-f { device = "/dev/${name}"; }) x.content); + foldl' recursiveUpdate { } (mapAttrsToList (name: config-f { device = "/dev/${name}"; }) x.content); config.luks = q: x: { boot.initrd.luks.devices.${x.name}.device = q.device; } // config-f { device = "/dev/mapper/${x.name}"; } x.content; - config.lv = q: x: - config-f { device = "/dev/mapper/${q.vgname}-${q.name}"; } x.content; + config.lvm_lv = q: x: + config-f { device = "/dev/${q.vgname}/${q.name}"; } x.content; - config.lvm = q: x: - foldl' recursiveUpdate {} (mapAttrsToList (name: config-f { inherit name; vgname = x.name; }) x.lvs); + config.lvm_vg = q: x: + foldl' recursiveUpdate { } (mapAttrsToList (name: config-f { inherit name; vgname = x.name; }) x.lvs); - config.noop = q: x: {}; + config.noop = q: x: { }; config.partition = q: x: config-f { device = q.device + toString q.index; } x.content; config.table = q: x: - foldl' recursiveUpdate {} (imap (index: config-f (q // { inherit index; })) x.partitions); + foldl' recursiveUpdate { } (imap (index: config-f (q // { inherit index; })) x.partitions); create-f = q: x: create.${x.type} q x; - create.filesystem = q: x: '' - mkfs.${x.format} ${q.device} + create.btrfs = q: x: '' + mkfs.btrfs ${q.device} + ${lib.optionalString (!isNull x.subvolumes or null) '' + MNTPOINT=$(mktemp -d) + ( + mount ${q.device} "$MNTPOINT" + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + ${concatMapStringsSep "\n" (subvolume: "btrfs subvolume create \"$MNTPOINT\"/${subvolume}") x.subvolumes} + ) + ''} ''; - create.devices = q: x: let - raid-devices = lib.filterAttrs (_: dev: dev.type == "mdadm") x.content; - other-devices = lib.filterAttrs (_: dev: dev.type != "mdadm") x.content; - in '' - ${concatStrings (mapAttrsToList (name: create-f { device = "/dev/${name}"; }) other-devices)} - ${concatStrings (mapAttrsToList (name: create-f { device = "/dev/${name}"; name = name; }) raid-devices)} + create.filesystem = q: x: '' + mkfs.${x.format} \ + ${lib.optionalString (!isNull x.extraArgs or null) x.extraArgs} \ + ${q.device} ''; + create.devices = q: x: + let + raid-devices = lib.filterAttrs (_: dev: dev.type == "mdadm" || dev.type == "zpool" || dev.type == "lvm_vg") x.content; + other-devices = lib.filterAttrs (_: dev: dev.type != "mdadm" && dev.type != "zpool" && dev.type != "lvm_vg") x.content; + in + '' + ${concatStrings (mapAttrsToList (name: create-f { device = "/dev/${name}"; }) other-devices)} + ${concatStrings (mapAttrsToList (name: create-f { device = "/dev/${name}"; name = name; }) raid-devices)} + ''; + create.mdraid = q: x: '' RAIDDEVICES_N_${x.name}=$((''${RAIDDEVICES_N_${x.name}:-0}+1)) RAIDDEVICES_${x.name}="''${RAIDDEVICES_${x.name}:-}${q.device} " @@ -91,33 +115,44 @@ let ${create-f { device = "/dev/mapper/${x.name}"; } x.content} ''; - create.lv = q: x: '' - lvcreate ${if hasInfix "%" x.size then "-l" else "-L"} ${x.size} -n ${q.name} ${q.vgname} - ${create-f { device = "/dev/mapper/${q.vgname}-${q.name}"; } x.content} + create.lvm_pv = q: x: '' + pvcreate ${q.device} + LVMDEVICES_${x.vg}="''${LVMDEVICES_${x.vg}:-}${q.device} " ''; - create.lvm = q: x: '' - pvcreate ${q.device} - vgcreate ${x.name} ${q.device} - ${concatStrings (mapAttrsToList (name: create-f { inherit name; vgname = x.name; }) x.lvs)} + create.lvm_lv = q: x: '' + lvcreate \ + ${if hasInfix "%" x.size then "-l" else "-L"} ${x.size} \ + -n ${q.name} \ + ${lib.optionalString (!isNull x.lvm_type or null) "--type=${x.lvm_type}"} \ + ${lib.optionalString (!isNull x.extraArgs or null) x.extraArgs} \ + ${q.vgname} + ${create-f { device = "/dev/${q.vgname}/${q.name}"; } x.content} + ''; + + create.lvm_vg = q: x: '' + vgcreate ${q.name} $LVMDEVICES_${q.name} + ${concatStrings (mapAttrsToList (name: create-f { inherit name; vgname = q.name; }) x.lvs)} ''; create.noop = q: x: ""; - create.partition = q: x: let - env = helper.device-id q.device; - in '' - parted -s "''${${env}}" mkpart ${x.part-type} ${x.fs-type or ""} ${x.start} ${x.end} - # ensure /dev/disk/by-path/..-partN exists before continuing - udevadm trigger --subsystem-match=block; udevadm settle - ${optionalString (x.bootable or false) '' - parted -s "''${${env}}" set ${toString q.index} boot on - ''} - ${concatMapStringsSep "" (flag: '' - parted -s "''${${env}}" set ${toString q.index} ${flag} on - '') (x.flags or [])} - ${create-f { device = "\"\${${env}}\"-part" + toString q.index; } x.content} - ''; + create.partition = q: x: + let + env = helper.device-id q.device; + in + '' + parted -s "''${${env}}" mkpart ${x.part-type} ${x.fs-type or ""} ${x.start} ${x.end} + # ensure /dev/disk/by-path/..-partN exists before continuing + udevadm trigger --subsystem-match=block; udevadm settle + ${optionalString (x.bootable or false) '' + parted -s "''${${env}}" set ${toString q.index} boot on + ''} + ${concatMapStringsSep "" (flag: '' + parted -s "''${${env}}" set ${toString q.index} ${flag} on + '') (x.flags or [])} + ${create-f { device = "\"\${${env}}\"-part" + toString q.index; } x.content} + ''; create.table = q: x: '' ${helper.find-device q.device} @@ -125,51 +160,98 @@ let ${concatStrings (imap (index: create-f (q // { inherit index; })) x.partitions)} ''; + create.zfs = q: x: '' + ZFSDEVICES_${x.pool}="''${ZFSDEVICES_${x.pool}:-}${q.device} " + ''; + + create.zfs_filesystem = q: x: '' + zfs create ${q.pool}/${x.name} \ + ${lib.optionalString (isAttrs x.options or null) (concatStringsSep " " (mapAttrsToList (n: v: "-o ${n}=${v}") x.options))} + ''; + + create.zfs_volume = q: x: '' + zfs create ${q.pool}/${x.name} \ + -V ${x.size} \ + ${lib.optionalString (isAttrs x.options or null) (concatStringsSep " " (mapAttrsToList (n: v: "-o ${n}=${v}") x.options))} + udevadm trigger --subsystem-match=block; udevadm settle + ${create-f { device = "/dev/zvol/${q.pool}/${x.name}"; } x.content} + ''; + + create.zpool = q: x: '' + zpool create ${q.name} \ + ${lib.optionalString (!isNull (x.mode or null) && x.mode != "stripe") x.mode} \ + ${lib.optionalString (isAttrs x.options or null) (concatStringsSep " " (mapAttrsToList (n: v: "-o ${n}=${v}") x.options))} \ + ${lib.optionalString (isAttrs x.rootFsOptions or null) (concatStringsSep " " (mapAttrsToList (n: v: "-O ${n}=${v}") x.rootFsOptions))} \ + ''${ZFSDEVICES_${q.name}} + ${concatMapStrings (create-f (q // { pool = q.name; })) x.datasets} + ''; + mount-f = q: x: mount.${x.type} q x; mount.filesystem = q: x: { - fs.${x.mountpoint} = '' - if ! findmnt ${q.device} "/mnt${x.mountpoint}" > /dev/null 2>&1; then - mount ${q.device} "/mnt${x.mountpoint}" -o X-mount.mkdir - fi - ''; - }; + fs.${x.mountpoint} = '' + if ! findmnt ${q.device} "/mnt${x.mountpoint}" > /dev/null 2>&1; then + mount ${q.device} "/mnt${x.mountpoint}" \ + -o X-mount.mkdir \ + ${lib.optionalString (isList x.mountOptions or null) (concatStringsSep " " x.mountOptions)} + fi + ''; + }; - mount.devices = q: x: let - z = foldl' recursiveUpdate {} (mapAttrsToList (name: mount-f { device = "/dev/${name}"; }) x.content); - # attrValues returns values sorted by name. This is important, because it - # ensures that "/" is processed before "/foo" etc. - in '' - ${optionalString (hasAttr "table" z) (concatStringsSep "\n" (attrValues z.table))} - ${optionalString (hasAttr "luks" z) (concatStringsSep "\n" (attrValues z.luks))} - ${optionalString (hasAttr "lvm" z) (concatStringsSep "\n" (attrValues z.lvm))} - ${optionalString (hasAttr "fs" z) (concatStringsSep "\n" (attrValues z.fs))} - ''; + mount.zfs_filesystem = q: x: + optionalAttrs ((x.options.mountpoint or "") != "none") + (mount.filesystem (q // { device = q.dataset; }) (x // { mountOptions = [ + (lib.optionalString ((x.options.mountpoint or "") != "legacy") "-o zfsutil") + "-t zfs" + ]; })); + + mount.btrfs = mount.filesystem; + + mount.devices = q: x: + let + z = foldl' recursiveUpdate { } (mapAttrsToList (name: mount-f { device = "/dev/${name}"; inherit name; }) x.content); + # attrValues returns values sorted by name. This is important, because it + # ensures that "/" is processed before "/foo" etc. + in + '' + ${optionalString (hasAttr "table" z) (concatStringsSep "\n" (attrValues z.table))} + ${optionalString (hasAttr "luks" z) (concatStringsSep "\n" (attrValues z.luks))} + ${optionalString (hasAttr "lvm" z) (concatStringsSep "\n" (attrValues z.lvm))} + ${optionalString (hasAttr "zpool" z) (concatStringsSep "\n" (attrValues z.zpool))} + ${optionalString (hasAttr "zfs" z) (concatStringsSep "\n" (attrValues z.zfs))} + ${optionalString (hasAttr "fs" z) (concatStringsSep "\n" (attrValues z.fs))} + ''; mount.luks = q: x: ( recursiveUpdate - (mount-f { device = "/dev/mapper/${x.name}"; } x.content) - {luks.${q.device} = '' - cryptsetup luksOpen ${q.device} ${x.name} ${if builtins.hasAttr "keyfile" x then "--key-file " + x.keyfile else ""} - '';} + (mount-f { device = "/dev/mapper/${x.name}"; } x.content) + { + luks.${q.device} = '' + cryptsetup status ${x.name} >/dev/null 2>/dev/null || cryptsetup luksOpen ${q.device} ${x.name} ${if builtins.hasAttr "keyfile" x then "--key-file " + x.keyfile else ""} + ''; + } ); - mount.lv = q: x: - mount-f { device = "/dev/mapper/${q.vgname}-${q.name}"; } x.content; + mount.lvm_lv = q: x: + mount-f { device = "/dev/${q.vgname}/${q.name}"; } x.content; - mount.lvm = q: x: ( + mount.lvm_vg = q: x: ( recursiveUpdate - (foldl' recursiveUpdate {} (mapAttrsToList (name: mount-f { inherit name; vgname = x.name; }) x.lvs)) - {lvm.${q.device} = '' - vgchange -a y - '';} + (foldl' recursiveUpdate { } (mapAttrsToList (name: mount-f { inherit name; vgname = q.name; }) x.lvs)) + { + lvm.${q.device} = '' + vgchange -a y + ''; + } ); - mount.noop = q: x: {}; + mount.lvm_pv = mount.noop; - # TODO maybe we need to do something here? - mount.mdadm = mount.noop; + mount.noop = q: x: { }; + + mount.mdadm = q: x: + mount-f { device = "/dev/md/${q.name}"; } x.content; mount.mdraid = mount.noop; mount.partition = q: x: @@ -177,11 +259,47 @@ let mount.table = q: x: ( recursiveUpdate - (foldl' recursiveUpdate {} (imap (index: mount-f (q // { inherit index; device = helper.device-id q.device; })) x.partitions)) - {table.${q.device} = helper.find-device q.device;} + (foldl' recursiveUpdate { } (imap (index: mount-f (q // { inherit index; device = helper.device-id q.device; })) x.partitions)) + { table.${q.device} = helper.find-device q.device; } ); -in { - config = config-f {}; + + mount.zfs = mount.noop; + + mount.zpool = q: x: + let + datasets = [{ + inherit (q) name; + type = "zfs_filesystem"; + dataset = q.name; + mountpoint = x.mountpoint or "/${q.name}"; + options = q.rootFsOptions or { }; + }] ++ x.datasets; + in + recursiveUpdate + (foldl' recursiveUpdate { } + ( + (map + (x: mount-f + ({ + dataset = x.dataset or "${q.name}/${x.name}"; + mountpoint = x.mountpoint or "/${q.name}/${x.name}"; + } // q) + x) + datasets) + ) + ) + { + zpool.${q.device} = '' + zpool list '${q.name}' >/dev/null 2>/dev/null || zpool import '${q.name}' + ''; + }; + + mount.zfs_volume = q: x: + mount-f { device = "/dev/zvol/${q.dataset}"; } x.content; + +in +{ + config = config-f { }; create = cfg: '' set -efux ${create-f {} cfg} diff --git a/example/btrfs-subvolumes.nix b/example/btrfs-subvolumes.nix new file mode 100644 index 0000000..0124c86 --- /dev/null +++ b/example/btrfs-subvolumes.nix @@ -0,0 +1,26 @@ +{ + type = "devices"; + content = { + vdb = { + type = "table"; + format = "gpt"; + partitions = [ + { + type = "partition"; + part-type = "primary"; + start = "0%"; + end = "100%"; + content = { + type = "btrfs"; + mountpoint = "/"; + subvolumes = [ + "/home" + "/test" + ]; + }; + } + ]; + }; + }; +} + diff --git a/example/luks-lvm.nix b/example/luks-lvm.nix new file mode 100644 index 0000000..22c029e --- /dev/null +++ b/example/luks-lvm.nix @@ -0,0 +1,81 @@ +{ + type = "devices"; + content = { + vdb = { + type = "table"; + format = "gpt"; + partitions = [ + { + type = "partition"; + part-type = "ESP"; + start = "1MiB"; + end = "100MiB"; + fs-type = "FAT32"; + bootable = true; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + options = [ + "defaults" + ]; + }; + } + { + type = "partition"; + part-type = "primary"; + start = "100MiB"; + end = "100%"; + content = { + type = "luks"; + algo = "aes-xts..."; + name = "crypted"; + keyfile = "/tmp/secret.key"; + extraArgs = [ + "--hash sha512" + "--iter-time 5000" + ]; + content = { + type = "lvm_pv"; + vg = "pool"; + }; + }; + } + ]; + }; + pool = { + type = "lvm_vg"; + lvs = { + root = { + type = "lvm_lv"; + size = "100M"; + mountpoint = "/"; + content = { + type = "filesystem"; + format = "ext4"; + mountpoint = "/"; + options = [ + "defaults" + ]; + }; + }; + home = { + type = "lvm_lv"; + size = "10M"; + content = { + type = "filesystem"; + format = "ext4"; + mountpoint = "/home"; + }; + }; + raw = { + type = "lvm_lv"; + size = "10M"; + content = { + type = "noop"; + }; + }; + }; + }; + }; +} diff --git a/example/lvm-raid.nix b/example/lvm-raid.nix new file mode 100644 index 0000000..48930ec --- /dev/null +++ b/example/lvm-raid.nix @@ -0,0 +1,66 @@ +{ + type = "devices"; + content = { + vdb = { + type = "table"; + format = "gpt"; + partitions = [ + { + type = "partition"; + part-type = "primary"; + start = "0%"; + end = "100%"; + content = { + type = "lvm_pv"; + vg = "pool"; + }; + } + ]; + }; + vdc = { + type = "table"; + format = "gpt"; + partitions = [ + { + type = "partition"; + part-type = "primary"; + start = "0%"; + end = "100%"; + content = { + type = "lvm_pv"; + vg = "pool"; + }; + } + ]; + }; + pool = { + type = "lvm_vg"; + lvs = { + root = { + type = "lvm_lv"; + size = "100M"; + mountpoint = "/"; + lvm_type = "mirror"; + content = { + type = "filesystem"; + format = "ext4"; + mountpoint = "/"; + options = [ + "defaults" + ]; + }; + }; + home = { + type = "lvm_lv"; + size = "10M"; + lvm_type = "raid0"; + content = { + type = "filesystem"; + format = "ext4"; + mountpoint = "/home"; + }; + }; + }; + }; + }; +} diff --git a/example/raid.nix b/example/mdadm.nix similarity index 99% rename from example/raid.nix rename to example/mdadm.nix index 490ea01..cb0ad91 100644 --- a/example/raid.nix +++ b/example/mdadm.nix @@ -53,7 +53,6 @@ }; } ]; - }; }; }; diff --git a/example/zfs-over-legacy.nix b/example/zfs-over-legacy.nix new file mode 100644 index 0000000..8f5a8bc --- /dev/null +++ b/example/zfs-over-legacy.nix @@ -0,0 +1,42 @@ +{ + type = "devices"; + content = { + vdb = { + type = "table"; + format = "gpt"; + partitions = [ + { + type = "partition"; + # leave space for the grub aka BIOS boot + start = "0%"; + end = "100%"; + part-type = "primary"; + bootable = true; + content = { + type = "filesystem"; + format = "ext4"; + mountpoint = "/"; + }; + } + ]; + }; + vdc = { + type = "zfs"; + pool = "zroot"; + }; + zroot = { + type = "zpool"; + mountpoint = "/"; + + datasets = [ + { + type = "zfs_filesystem"; + name = "zfs_fs"; + mountpoint = "/zfs_fs"; + options."com.sun:auto-snapshot" = "true"; + } + ]; + }; + }; +} + diff --git a/example/zfs.nix b/example/zfs.nix new file mode 100644 index 0000000..60e4700 --- /dev/null +++ b/example/zfs.nix @@ -0,0 +1,53 @@ +{ + type = "devices"; + content = { + vdb = { + type = "zfs"; + pool = "zroot"; + }; + vdc = { + type = "zfs"; + pool = "zroot"; + }; + zroot = { + type = "zpool"; + mode = "mirror"; + rootFsOptions = { + compression = "lz4"; + "com.sun:auto-snapshot" = "false"; + }; + mountpoint = "/"; + + datasets = [ + { + type = "zfs_filesystem"; + name = "zfs_fs"; + mountpoint = "/zfs_fs"; + options."com.sun:auto-snapshot" = "true"; + } + { + type = "zfs_filesystem"; + name = "zfs_unmounted_fs"; + options.mountpoint = "none"; + } + { + type = "zfs_filesystem"; + name = "zfs_legacy_fs"; + options.mountpoint = "legacy"; + mountpoint = "/zfs_legacy_fs"; + } + { + type = "zfs_volume"; + name = "zfs_testvolume"; + size = "10M"; + content = { + type = "filesystem"; + format = "ext4"; + mountpoint = "/ext4onzfs"; + }; + } + ]; + }; + }; +} + diff --git a/flake.nix b/flake.nix index 3e7263a..488933d 100644 --- a/flake.nix +++ b/flake.nix @@ -9,11 +9,11 @@ }; checks.x86_64-linux = let pkgs = nixpkgs.legacyPackages.x86_64-linux; - in { + in # Run tests: nix flake check -L - nixos-test = pkgs.callPackage ./tests/test.nix { + import ./tests { + inherit pkgs; makeTest = import (pkgs.path + "/nixos/tests/make-test-python.nix"); }; - }; }; } diff --git a/tests/btrfs-subvolumes.nix b/tests/btrfs-subvolumes.nix new file mode 100644 index 0000000..3ff4386 --- /dev/null +++ b/tests/btrfs-subvolumes.nix @@ -0,0 +1,11 @@ +{ pkgs ? (import { }) +, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest +}: +makeDiskoTest { + disko-config = import ../example/btrfs-subvolumes.nix; + extraTestScript = '' + machine.succeed("test -e /mnt/test"); + machine.succeed("btrfs subvolume list /mnt | grep -qs 'path test$'"); + ''; +} + diff --git a/tests/default.nix b/tests/default.nix new file mode 100644 index 0000000..525f936 --- /dev/null +++ b/tests/default.nix @@ -0,0 +1,16 @@ +{ makeTest ? import +, pkgs ? (import { }) +}@args: +let + lib = pkgs.lib; + makeDiskoTest = (pkgs.callPackage ./lib.nix { inherit makeTest; }).makeDiskoTest; + allTestFilenames = + builtins.map (lib.removeSuffix ".nix") ( + builtins.filter + (x: lib.hasSuffix ".nix" x && x != "default.nix" && x != "lib.nix") + (lib.attrNames (builtins.readDir ./.)) + ); + + allTests = lib.genAttrs (allTestFilenames) (test: import (./. + "/${test}.nix") { inherit makeDiskoTest; }); +in +allTests diff --git a/tests/lib.nix b/tests/lib.nix new file mode 100644 index 0000000..2ec42e6 --- /dev/null +++ b/tests/lib.nix @@ -0,0 +1,48 @@ +{ pkgs ? (import { }) +, makeTest ? import +, ... +}: +{ + makeDiskoTest = + { disko-config + , extraTestScript + , extraConfig ? { } + }: + let + lib = pkgs.lib; + makeTest' = args: + makeTest args { + inherit pkgs; + inherit (pkgs) system; + }; + tsp-create = pkgs.writeScript "create" ((pkgs.callPackage ../. { }).create disko-config); + tsp-mount = pkgs.writeScript "mount" ((pkgs.callPackage ../. { }).mount disko-config); + num-disks = builtins.length (builtins.filter (x: builtins.match "vd." x == [ ]) (lib.attrNames disko-config.content)); + in + makeTest' { + name = "disko"; + + nodes.machine = + { config, pkgs, modulesPath, ... }: + + { + imports = [ + (modulesPath + "/profiles/installation-device.nix") + (modulesPath + "/profiles/base.nix") + ]; + + # speed-up eval + documentation.enable = false; + + virtualisation.emptyDiskImages = builtins.genList (_: 512) num-disks; + } // extraConfig; + + testScript = '' + machine.succeed("echo 'secret' > /tmp/secret.key"); + machine.succeed("${tsp-create}"); + machine.succeed("${tsp-mount}"); + machine.succeed("${tsp-mount}"); # verify that the command is idempotent + ${extraTestScript} + ''; + }; +} diff --git a/tests/luks-lvm.nix b/tests/luks-lvm.nix new file mode 100644 index 0000000..d59f3f4 --- /dev/null +++ b/tests/luks-lvm.nix @@ -0,0 +1,10 @@ +{ pkgs ? (import { }) +, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest +}: +makeDiskoTest { + disko-config = import ../example/luks-lvm.nix; + extraTestScript = '' + machine.succeed("cryptsetup isLuks /dev/vdb2"); + machine.succeed("mountpoint /mnt/home"); + ''; +} diff --git a/tests/lvm-raid.nix b/tests/lvm-raid.nix new file mode 100644 index 0000000..102dcd7 --- /dev/null +++ b/tests/lvm-raid.nix @@ -0,0 +1,12 @@ +{ pkgs ? (import { }) +, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest +}: +makeDiskoTest { + disko-config = import ../example/lvm-raid.nix; + extraTestScript = '' + machine.succeed("mountpoint /mnt/home"); + ''; + extraConfig = { + boot.kernelModules = [ "dm-raid" "dm-mirror" ]; + }; +} diff --git a/tests/mdadm.nix b/tests/mdadm.nix new file mode 100644 index 0000000..bd57a00 --- /dev/null +++ b/tests/mdadm.nix @@ -0,0 +1,10 @@ +{ pkgs ? (import { }) +, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest +}: +makeDiskoTest { + disko-config = import ../example/mdadm.nix; + extraTestScript = '' + machine.succeed("test -b /dev/md/raid1"); + machine.succeed("mountpoint /mnt/raid"); + ''; +} diff --git a/tests/test.nix b/tests/test.nix deleted file mode 100644 index 1384590..0000000 --- a/tests/test.nix +++ /dev/null @@ -1,38 +0,0 @@ -{ makeTest ? import -, pkgs ? (import {}) -}: -let - makeTest' = args: - makeTest args { - inherit pkgs; - inherit (pkgs) system; - }; - disko-config = import ../example/raid.nix; - tsp-create = pkgs.writeScript "create" ((pkgs.callPackage ../. {}).create disko-config); - tsp-mount = pkgs.writeScript "mount" ((pkgs.callPackage ../. {}).mount disko-config); -in makeTest' { - name = "disko"; - - nodes.machine = - { config, pkgs, modulesPath, ... }: - - { - imports = [ - (modulesPath + "/profiles/installation-device.nix") - (modulesPath + "/profiles/base.nix") - ]; - - # speed-up eval - documentation.enable = false; - - virtualisation.emptyDiskImages = [ 512 512 ]; - }; - - testScript = '' - machine.succeed("echo 'secret' > /tmp/secret.key"); - machine.succeed("${tsp-create}"); - machine.succeed("${tsp-mount}"); - machine.succeed("${tsp-mount}"); # verify that the command is idempotent - machine.succeed("test -b /dev/md/raid1"); - ''; -} diff --git a/tests/zfs-over-legacy.nix b/tests/zfs-over-legacy.nix new file mode 100644 index 0000000..13f86a9 --- /dev/null +++ b/tests/zfs-over-legacy.nix @@ -0,0 +1,12 @@ +{ pkgs ? (import { }) +, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest +}: +makeDiskoTest { + disko-config = import ../example/zfs-over-legacy.nix; + extraTestScript = '' + machine.succeed("test -e /mnt/zfs_fs"); + machine.succeed("mountpoint /mnt"); + machine.succeed("mountpoint /mnt/zfs_fs"); + ''; +} + diff --git a/tests/zfs.nix b/tests/zfs.nix new file mode 100644 index 0000000..5940c4d --- /dev/null +++ b/tests/zfs.nix @@ -0,0 +1,27 @@ +{ pkgs ? (import { }) +, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest +}: +makeDiskoTest { + disko-config = import ../example/zfs.nix; + extraTestScript = '' + machine.succeed("test -b /dev/zvol/zroot/zfs_testvolume"); + + def assert_property(ds, property, expected_value): + out = machine.succeed(f"zfs get -H {property} {ds} -o value").rstrip() + assert ( + out == expected_value + ), f"Expected {property}={expected_value} on {ds}, got: {out}" + + assert_property("zroot", "compression", "lz4") + assert_property("zroot/zfs_fs", "compression", "lz4") + assert_property("zroot", "com.sun:auto-snapshot", "false") + assert_property("zroot/zfs_fs", "com.sun:auto-snapshot", "true") + assert_property("zroot/zfs_testvolume", "volsize", "10M") + assert_property("zroot/zfs_unmounted_fs", "mountpoint", "none") + + machine.succeed("mountpoint /mnt"); + machine.succeed("mountpoint /mnt/zfs_fs"); + machine.succeed("mountpoint /mnt/zfs_legacy_fs"); + machine.succeed("mountpoint /mnt/ext4onzfs"); + ''; +}