args @ { lib, config, ... }: let datasetSubmodules = (import ./submodules/dataset.nix) args; impermanenceDatasetSubmodule = (import ./submodules/impermanenceDataset.nix) args; permissionsToMode = permissions: let permSetToDigit = permSet: ( if permSet.read then 4 else 0 ) + ( if permSet.write then 2 else 0 ) + ( if permSet.execute then 1 else 0 ); ownerDigit = permSetToDigit permissions.owner.permissions; groupDigit = permSetToDigit permissions.group.permissions; otherDigit = permSetToDigit permissions.other.permissions; in toString ownerDigit + toString groupDigit + toString otherDigit; # Get the option names from both submodules to automatically determine which are impermanence-specific regularDatasetEval = lib.evalModules { modules = [datasetSubmodules]; specialArgs = args; }; impermanenceDatasetEval = lib.evalModules { modules = [impermanenceDatasetSubmodule]; specialArgs = args; }; regularDatasetOptions = builtins.attrNames regularDatasetEval.options; impermanenceDatasetOptions = builtins.attrNames impermanenceDatasetEval.options; # Find options that are only in impermanence datasets (not in regular ZFS datasets) impermanenceOnlyOptions = lib.lists.subtractLists regularDatasetOptions impermanenceDatasetOptions; in { options.storage = { impermanence = { enable = lib.mkEnableOption "should impermanence be enabled for this system"; datasets = lib.mkOption { type = lib.types.attrsOf (lib.types.submodule impermanenceDatasetSubmodule); default = {}; }; }; }; config = lib.mkIf config.storage.impermanence.enable (lib.mkMerge [ { assertions = [ { assertion = config.storage.zfs.enable; message = "storage.impermanence can not be used without storage.zfs."; } ]; # fixes issues with /var/lib/private not having the correct permissions https://github.com/nix-community/impermanence/issues/254 system.activationScripts."createPersistentStorageDirs".deps = ["var-lib-private-permissions" "users" "groups"]; system.activationScripts = { "var-lib-private-permissions" = { deps = ["specialfs"]; text = '' mkdir -p /persist/replicate/system/root/var/lib/private chmod 0700 /persist/replicate/system/root/var/lib/private ''; }; }; programs.fuse.userAllowOther = true; fileSystems = lib.mapAttrs' ( datasetName: dataset: lib.nameValuePair "/${datasetName}" { neededForBoot = true; } ) config.storage.impermanence.datasets; environment.persistence = lib.mapAttrs (datasetName: dataset: { enable = true; hideMounts = true; persistentStoragePath = "/${datasetName}"; directories = lib.mapAttrsToList (path: dirConfig: { directory = path; user = dirConfig.owner.name; group = dirConfig.group.name; mode = permissionsToMode dirConfig; }) (lib.filterAttrs (_: dirConfig: dirConfig.enable) dataset.directories); files = lib.mapAttrsToList (path: fileConfig: { file = path; parentDirectory = { user = fileConfig.owner.name; group = fileConfig.group.name; mode = permissionsToMode fileConfig; }; }) (lib.filterAttrs (_: fileConfig: fileConfig.enable) dataset.files); }) config.storage.impermanence.datasets; } (lib.mkIf config.storage.zfs.enable { storage.zfs.datasets = lib.mapAttrs ( datasetName: dataset: builtins.removeAttrs dataset impermanenceOnlyOptions ) config.storage.impermanence.datasets; }) ]); }