{ povSelf, hostConfig, config, lib, pkgs, ... }: let inherit (lib) types; cfg = lib.getAttrFromPath povSelf config; users = ( config.modules.users |> lib.mapAttrsToList (name: value: if value.enable then name else null) |> lib.filter (element: !builtins.isNull element) ); part = name: content: if cfg.encrypt then { type = "luks"; inherit name content; } else content; in { options = { enable = { type = types.bool; default = false; }; type = { type = types.enum [ "zfs" "btrfs" "ext4" ]; }; path = { type = types.path; }; encrypt = { type = types.bool; default = false; }; parts = { home = { type = types.bool; default = false; }; homePerUser = { type = types.bool; default = cfg.parts.home; }; nix = { type = types.bool; default = true; }; tmp = { type = types.bool; default = false; }; system = { type = types.bool; default = false; }; }; reservedSpace = { type = types.str; default = "8G"; }; swap = { enable = { type = types.bool; default = false; }; size = { type = types.strMatching "[0-9]+[KMGTP]"; }; }; }; config = lib.mkIf cfg.enable ( lib.mkMerge [ (lib.mkIf (cfg.type == "zfs") { assertions = [ { assertion = cfg.parts.homePerUser -> cfg.parts.home; message = "Option ${cfg}.parts.homePerUser requires ${cfg}.parts.home to be true."; } ]; services.zfs.autoScrub.enable = true; boot = lib.mkMerge [ (lib.mkIf cfg.encrypt { initrd = { luks.forceLuksSupportInInitrd = true; supportedFilesystems = { ext4 = true; }; systemd.services.decrypt-root = { description = "Decrypt ZFS root pool"; wantedBy = [ "initrd.target" ]; after = [ "zfs-import.target" ]; before = [ "create-needed-for-boot-dirs.service" "defenestrate.service" "sysroot.mount" ]; onFailure = [ "emergency.target" ]; unitConfig.DefaultDependencies = "no"; serviceConfig = { Type = "oneshot"; RemainAfterExit = "yes"; }; script = '' systemd-cryptsetup attach key /dev/zvol/${hostConfig.hostName}/key || exit 1 mount /dev/mapper/key /key --mkdir || exit 1 zfs load-key -a || exit 1 umount /key || exit 1 systemd-cryptsetup detach key || exit 1 ''; }; }; zfs.requestEncryptionCredentials = false; }) (lib.mkIf hostConfig.hardware.allowHibernation { zfs = { forceImportRoot = false; allowHibernation = true; }; }) ]; fileSystems."/nix/persist" = lib.mkIf cfg.parts.system { neededForBoot = true; }; disko.devices = { zpool = { "${hostConfig.hostName}" = { type = "zpool"; options.ashift = "12"; rootFsOptions = lib.mkMerge [ { acltype = "posixacl"; devices = "off"; canmount = "off"; compression = "zstd-6"; exec = "off"; mountpoint = "none"; setuid = "off"; xattr = "sa"; } (lib.mkIf cfg.encrypt { encryption = "on"; keyformat = "hex"; keylocation = "file:///key/${hostConfig.hostName}.key"; }) ]; datasets = lib.mkMerge [ { "reserved" = { type = "zfs_volume"; size = cfg.reservedSpace; options.readonly = "on"; }; "os" = { type = "zfs_fs"; options.canmount = "off"; }; "os/nixos" = { type = "zfs_fs"; options.canmount = "off"; }; "os/nixos/root-1" = { type = "zfs_fs"; options.mountpoint = "legacy"; mountpoint = "/"; }; } (lib.mkIf cfg.parts.nix { nix = { type = "zfs_fs"; options = { atime = "off"; devices = "off"; exec = "on"; mountpoint = "legacy"; }; mountpoint = "/nix"; }; }) (lib.mkIf (cfg.parts.system || cfg.parts.home) { data = { type = "zfs_fs"; options.canmount = "off"; }; }) (lib.mkIf (cfg.parts.home && !cfg.parts.homePerUser) { "data/home" = { type = "zfs_fs"; options.mountpoint = "legacy"; mountpoint = "/home"; mountOptions = [ "nofail" ]; }; }) (lib.mkIf (cfg.parts.home && cfg.parts.homePerUser) { "data/home" = { type = "zfs_fs"; options.canmount = "off"; }; }) (lib.mkIf cfg.parts.homePerUser ( lib.listToAttrs ( lib.map (user: { name = "data/home/${user}"; value = { type = "zfs_fs"; options = { devices = "off"; mountpoint = "legacy"; setuid = "off"; }; mountOptions = [ "nofail" ]; mountpoint = if config.modules.filesystem.impermanence.home.enable then "/nix/persist/home/${user}" else "/home/${user}"; }; }) users ) )) (lib.mkIf cfg.parts.system { "data/system" = { type = "zfs_fs"; options = { devices = "off"; mountpoint = "legacy"; setuid = "off"; }; mountpoint = "/nix/persist"; }; }) (lib.mkIf cfg.encrypt { key = { type = "zfs_volume"; size = "50M"; options.encryption = "off"; # TODO: luksFormat, add key and make readonly # cryptsetup luksFormat /dev/zvol//key # cryptsetup open /dev/zvol//key key # mkfs.ext4 -O ^has_journal /dev/mapper/key # mount /dev/mapper/key /key }; }) ]; }; }; }; }) { disko.devices = { nodev = lib.mkIf cfg.parts.tmp { "/tmp" = { fsType = "tmpfs"; mountOptions = [ "nosuid" "nodev" ]; }; }; disk = { # TODO: Add multidisk support "${hostConfig.hostName}" = { type = "disk"; device = "${cfg.path}"; content = { type = "gpt"; partitions = lib.mkMerge [ (lib.mkIf (config.modules.boot.type == "legacy") { grub-mbr = { size = "1M"; type = "EF02"; priority = 1; }; }) { boot = { size = "700M"; content = { type = "filesystem"; format = "vfat"; mountOptions = [ "nofail" "umask=0077" "dmask=0077" ]; mountpoint = "/boot"; }; }; } (lib.mkIf (config.modules.boot.type == "uefi") { boot.type = "EF00"; }) { root.content = ( lib.mkMerge [ (lib.mkIf (cfg.type == "ext4") ( part "root" { type = "filesystem"; format = "ext4"; mountpoint = "/"; } )) (lib.mkIf (cfg.type == "btrfs") ( part "root" { type = "btrfs"; subvolumes = { "/nixos/@" = { mountpoint = "/"; }; "/nixos/@home" = { mountOptions = [ "compress=zstd" ]; mountpoint = "/home"; }; "/nixos/@nix" = { mountOptions = [ "compress=zstd" "noatime" ]; mountpoint = "/nix"; }; }; } )) (lib.mkIf (cfg.type == "zfs") { type = "zfs"; pool = hostConfig.hostName; }) ] ); } ( if cfg.swap.enable then { root.end = "-${cfg.swap.size}"; swap = { size = "100%"; content = part "swap" { type = "swap"; }; }; } else { root.size = "100%"; } ) ]; }; }; }; }; } ] ); }