mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-07-13 21:50:33 +03:00
nixos/zfs: remove top-level with
s
As it is generally considered an anti-pattern. Removing them here in fact exposed one bug (see previous commit).
This commit is contained in:
parent
06ed2c46fb
commit
33bd85a6c8
1 changed files with 111 additions and 114 deletions
|
@ -2,9 +2,6 @@
|
||||||
#
|
#
|
||||||
# TODO: zfs tunables
|
# TODO: zfs tunables
|
||||||
|
|
||||||
with utils;
|
|
||||||
with lib;
|
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
cfgZfs = config.boot.zfs;
|
cfgZfs = config.boot.zfs;
|
||||||
|
@ -17,7 +14,7 @@ let
|
||||||
cfgZED = config.services.zfs.zed;
|
cfgZED = config.services.zfs.zed;
|
||||||
|
|
||||||
selectModulePackage = package: config.boot.kernelPackages.${package.kernelModuleAttribute};
|
selectModulePackage = package: config.boot.kernelPackages.${package.kernelModuleAttribute};
|
||||||
clevisDatasets = attrNames (filterAttrs (device: _: any (e: e.fsType == "zfs" && (fsNeededForBoot e) && (e.device == device || hasPrefix "${device}/" e.device)) config.system.build.fileSystems) config.boot.initrd.clevis.devices);
|
clevisDatasets = lib.attrNames (lib.filterAttrs (device: _: lib.any (e: e.fsType == "zfs" && (utils.fsNeededForBoot e) && (e.device == device || lib.hasPrefix "${device}/" e.device)) config.system.build.fileSystems) config.boot.initrd.clevis.devices);
|
||||||
|
|
||||||
inInitrd = config.boot.initrd.supportedFilesystems.zfs or false;
|
inInitrd = config.boot.initrd.supportedFilesystems.zfs or false;
|
||||||
inSystem = config.boot.supportedFilesystems.zfs or false;
|
inSystem = config.boot.supportedFilesystems.zfs or false;
|
||||||
|
@ -28,17 +25,17 @@ let
|
||||||
|
|
||||||
zfsAutoSnap = "${autosnapPkg}/bin/zfs-auto-snapshot";
|
zfsAutoSnap = "${autosnapPkg}/bin/zfs-auto-snapshot";
|
||||||
|
|
||||||
datasetToPool = x: elemAt (splitString "/" x) 0;
|
datasetToPool = x: lib.elemAt (lib.splitString "/" x) 0;
|
||||||
|
|
||||||
fsToPool = fs: datasetToPool fs.device;
|
fsToPool = fs: datasetToPool fs.device;
|
||||||
|
|
||||||
zfsFilesystems = filter (x: x.fsType == "zfs") config.system.build.fileSystems;
|
zfsFilesystems = lib.filter (x: x.fsType == "zfs") config.system.build.fileSystems;
|
||||||
|
|
||||||
allPools = unique ((map fsToPool zfsFilesystems) ++ cfgZfs.extraPools);
|
allPools = lib.unique ((map fsToPool zfsFilesystems) ++ cfgZfs.extraPools);
|
||||||
|
|
||||||
rootPools = unique (map fsToPool (filter fsNeededForBoot zfsFilesystems));
|
rootPools = lib.unique (map fsToPool (lib.filter utils.fsNeededForBoot zfsFilesystems));
|
||||||
|
|
||||||
dataPools = unique (filter (pool: !(elem pool rootPools)) allPools);
|
dataPools = lib.unique (lib.filter (pool: !(lib.elem pool rootPools)) allPools);
|
||||||
|
|
||||||
snapshotNames = [ "frequent" "hourly" "daily" "weekly" "monthly" ];
|
snapshotNames = [ "frequent" "hourly" "daily" "weekly" "monthly" ];
|
||||||
|
|
||||||
|
@ -89,7 +86,7 @@ let
|
||||||
'';
|
'';
|
||||||
|
|
||||||
getPoolFilesystems = pool:
|
getPoolFilesystems = pool:
|
||||||
filter (x: x.fsType == "zfs" && (fsToPool x) == pool) config.system.build.fileSystems;
|
lib.filter (x: x.fsType == "zfs" && (fsToPool x) == pool) config.system.build.fileSystems;
|
||||||
|
|
||||||
getPoolMounts = prefix: pool:
|
getPoolMounts = prefix: pool:
|
||||||
let
|
let
|
||||||
|
@ -98,36 +95,36 @@ let
|
||||||
# Remove the "/" suffix because even though most mountpoints
|
# Remove the "/" suffix because even though most mountpoints
|
||||||
# won't have it, the "/" mountpoint will, and we can't have the
|
# won't have it, the "/" mountpoint will, and we can't have the
|
||||||
# trailing slash in "/sysroot/" in stage 1.
|
# trailing slash in "/sysroot/" in stage 1.
|
||||||
mountPoint = fs: escapeSystemdPath (prefix + (lib.removeSuffix "/" fs.mountPoint));
|
mountPoint = fs: utils.escapeSystemdPath (prefix + (lib.removeSuffix "/" fs.mountPoint));
|
||||||
|
|
||||||
hasUsr = lib.any (fs: fs.mountPoint == "/usr") poolFSes;
|
hasUsr = lib.any (fs: fs.mountPoint == "/usr") poolFSes;
|
||||||
in
|
in
|
||||||
map (x: "${mountPoint x}.mount") poolFSes
|
map (x: "${mountPoint x}.mount") poolFSes
|
||||||
++ lib.optional hasUsr "sysusr-usr.mount";
|
++ lib.optional hasUsr "sysusr-usr.mount";
|
||||||
|
|
||||||
getKeyLocations = pool: if isBool cfgZfs.requestEncryptionCredentials then {
|
getKeyLocations = pool: if lib.isBool cfgZfs.requestEncryptionCredentials then {
|
||||||
hasKeys = cfgZfs.requestEncryptionCredentials;
|
hasKeys = cfgZfs.requestEncryptionCredentials;
|
||||||
command = "${cfgZfs.package}/sbin/zfs list -rHo name,keylocation,keystatus -t volume,filesystem ${pool}";
|
command = "${cfgZfs.package}/sbin/zfs list -rHo name,keylocation,keystatus -t volume,filesystem ${pool}";
|
||||||
} else let
|
} else let
|
||||||
keys = filter (x: datasetToPool x == pool) cfgZfs.requestEncryptionCredentials;
|
keys = lib.filter (x: datasetToPool x == pool) cfgZfs.requestEncryptionCredentials;
|
||||||
in {
|
in {
|
||||||
hasKeys = keys != [];
|
hasKeys = keys != [];
|
||||||
command = "${cfgZfs.package}/sbin/zfs list -Ho name,keylocation,keystatus -t volume,filesystem ${toString keys}";
|
command = "${cfgZfs.package}/sbin/zfs list -Ho name,keylocation,keystatus -t volume,filesystem ${toString keys}";
|
||||||
};
|
};
|
||||||
|
|
||||||
createImportService = { pool, systemd, force, prefix ? "" }:
|
createImportService = { pool, systemd, force, prefix ? "" }:
|
||||||
nameValuePair "zfs-import-${pool}" {
|
lib.nameValuePair "zfs-import-${pool}" {
|
||||||
description = "Import ZFS pool \"${pool}\"";
|
description = "Import ZFS pool \"${pool}\"";
|
||||||
# We wait for systemd-udev-settle to ensure devices are available,
|
# We wait for systemd-udev-settle to ensure devices are available,
|
||||||
# but don't *require* it, because mounts shouldn't be killed if it's stopped.
|
# but don't *require* it, because mounts shouldn't be killed if it's stopped.
|
||||||
# In the future, hopefully someone will complete this:
|
# In the future, hopefully someone will complete this:
|
||||||
# https://github.com/zfsonlinux/zfs/pull/4943
|
# https://github.com/zfsonlinux/zfs/pull/4943
|
||||||
wants = [ "systemd-udev-settle.service" ] ++ optional (config.boot.initrd.clevis.useTang) "network-online.target";
|
wants = [ "systemd-udev-settle.service" ] ++ lib.optional (config.boot.initrd.clevis.useTang) "network-online.target";
|
||||||
after = [
|
after = [
|
||||||
"systemd-udev-settle.service"
|
"systemd-udev-settle.service"
|
||||||
"systemd-modules-load.service"
|
"systemd-modules-load.service"
|
||||||
"systemd-ask-password-console.service"
|
"systemd-ask-password-console.service"
|
||||||
] ++ optional (config.boot.initrd.clevis.useTang) "network-online.target";
|
] ++ lib.optional (config.boot.initrd.clevis.useTang) "network-online.target";
|
||||||
requiredBy = getPoolMounts prefix pool ++ [ "zfs-import.target" ];
|
requiredBy = getPoolMounts prefix pool ++ [ "zfs-import.target" ];
|
||||||
before = getPoolMounts prefix pool ++ [ "shutdown.target" "zfs-import.target" ];
|
before = getPoolMounts prefix pool ++ [ "shutdown.target" "zfs-import.target" ];
|
||||||
conflicts = [ "shutdown.target" ];
|
conflicts = [ "shutdown.target" ];
|
||||||
|
@ -138,7 +135,7 @@ let
|
||||||
Type = "oneshot";
|
Type = "oneshot";
|
||||||
RemainAfterExit = true;
|
RemainAfterExit = true;
|
||||||
};
|
};
|
||||||
environment.ZFS_FORCE = optionalString force "-f";
|
environment.ZFS_FORCE = lib.optionalString force "-f";
|
||||||
script = let
|
script = let
|
||||||
keyLocations = getKeyLocations pool;
|
keyLocations = getKeyLocations pool;
|
||||||
in (importLib {
|
in (importLib {
|
||||||
|
@ -157,10 +154,10 @@ let
|
||||||
poolImported "${pool}" || poolImport "${pool}" # Try one last time, e.g. to import a degraded pool.
|
poolImported "${pool}" || poolImport "${pool}" # Try one last time, e.g. to import a degraded pool.
|
||||||
fi
|
fi
|
||||||
if poolImported "${pool}"; then
|
if poolImported "${pool}"; then
|
||||||
${optionalString config.boot.initrd.clevis.enable (concatMapStringsSep "\n" (elem: "clevis decrypt < /etc/clevis/${elem}.jwe | zfs load-key ${elem} || true ") (filter (p: (elemAt (splitString "/" p) 0) == pool) clevisDatasets))}
|
${lib.optionalString config.boot.initrd.clevis.enable (lib.concatMapStringsSep "\n" (elem: "clevis decrypt < /etc/clevis/${elem}.jwe | zfs load-key ${elem} || true ") (lib.filter (p: (lib.elemAt (lib.splitString "/" p) 0) == pool) clevisDatasets))}
|
||||||
|
|
||||||
|
|
||||||
${optionalString keyLocations.hasKeys ''
|
${lib.optionalString keyLocations.hasKeys ''
|
||||||
${keyLocations.command} | while IFS=$'\t' read ds kl ks; do
|
${keyLocations.command} | while IFS=$'\t' read ds kl ks; do
|
||||||
{
|
{
|
||||||
if [[ "$ks" != unavailable ]]; then
|
if [[ "$ks" != unavailable ]]; then
|
||||||
|
@ -193,15 +190,15 @@ let
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
zedConf = generators.toKeyValue {
|
zedConf = lib.generators.toKeyValue {
|
||||||
mkKeyValue = generators.mkKeyValueDefault {
|
mkKeyValue = lib.generators.mkKeyValueDefault {
|
||||||
mkValueString = v:
|
mkValueString = v:
|
||||||
if isInt v then toString v
|
if lib.isInt v then toString v
|
||||||
else if isString v then "\"${v}\""
|
else if lib.isString v then "\"${v}\""
|
||||||
else if true == v then "1"
|
else if true == v then "1"
|
||||||
else if false == v then "0"
|
else if false == v then "0"
|
||||||
else if isList v then "\"" + (concatStringsSep " " v) + "\""
|
else if lib.isList v then "\"" + (lib.concatStringsSep " " v) + "\""
|
||||||
else err "this value is" (toString v);
|
else lib.err "this value is" (toString v);
|
||||||
} "=";
|
} "=";
|
||||||
} cfgZED.settings;
|
} cfgZED.settings;
|
||||||
in
|
in
|
||||||
|
@ -209,38 +206,38 @@ in
|
||||||
{
|
{
|
||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
(mkRemovedOptionModule [ "boot" "zfs" "enableLegacyCrypto" ] "The corresponding package was removed from nixpkgs.")
|
(lib.mkRemovedOptionModule [ "boot" "zfs" "enableLegacyCrypto" ] "The corresponding package was removed from nixpkgs.")
|
||||||
(mkRemovedOptionModule [ "boot" "zfs" "enableUnstable" ] "Instead set `boot.zfs.package = pkgs.zfs_unstable;`")
|
(lib.mkRemovedOptionModule [ "boot" "zfs" "enableUnstable" ] "Instead set `boot.zfs.package = pkgs.zfs_unstable;`")
|
||||||
];
|
];
|
||||||
|
|
||||||
###### interface
|
###### interface
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
boot.zfs = {
|
boot.zfs = {
|
||||||
package = mkOption {
|
package = lib.mkOption {
|
||||||
type = types.package;
|
type = lib.types.package;
|
||||||
default = pkgs.zfs;
|
default = pkgs.zfs;
|
||||||
defaultText = literalExpression "pkgs.zfs";
|
defaultText = lib.literalExpression "pkgs.zfs";
|
||||||
description = "Configured ZFS userland tools package, use `pkgs.zfs_unstable` if you want to track the latest staging ZFS branch.";
|
description = "Configured ZFS userland tools package, use `pkgs.zfs_unstable` if you want to track the latest staging ZFS branch.";
|
||||||
};
|
};
|
||||||
|
|
||||||
modulePackage = mkOption {
|
modulePackage = lib.mkOption {
|
||||||
internal = true; # It is supposed to be selected automatically, but can be overridden by expert users.
|
internal = true; # It is supposed to be selected automatically, but can be overridden by expert users.
|
||||||
default = selectModulePackage cfgZfs.package;
|
default = selectModulePackage cfgZfs.package;
|
||||||
type = types.package;
|
type = lib.types.package;
|
||||||
description = "Configured ZFS kernel module package.";
|
description = "Configured ZFS kernel module package.";
|
||||||
};
|
};
|
||||||
|
|
||||||
enabled = mkOption {
|
enabled = lib.mkOption {
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
type = types.bool;
|
type = lib.types.bool;
|
||||||
default = inInitrd || inSystem;
|
default = inInitrd || inSystem;
|
||||||
defaultText = literalMD "`true` if ZFS filesystem support is enabled";
|
defaultText = lib.literalMD "`true` if ZFS filesystem support is enabled";
|
||||||
description = "True if ZFS filesystem support is enabled";
|
description = "True if ZFS filesystem support is enabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
allowHibernation = mkOption {
|
allowHibernation = lib.mkOption {
|
||||||
type = types.bool;
|
type = lib.types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
description = ''
|
description = ''
|
||||||
Allow hibernation support, this may be a unsafe option depending on your
|
Allow hibernation support, this may be a unsafe option depending on your
|
||||||
|
@ -248,8 +245,8 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
extraPools = mkOption {
|
extraPools = lib.mkOption {
|
||||||
type = types.listOf types.str;
|
type = lib.types.listOf lib.types.str;
|
||||||
default = [];
|
default = [];
|
||||||
example = [ "tank" "data" ];
|
example = [ "tank" "data" ];
|
||||||
description = ''
|
description = ''
|
||||||
|
@ -267,8 +264,8 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
devNodes = mkOption {
|
devNodes = lib.mkOption {
|
||||||
type = types.path;
|
type = lib.types.path;
|
||||||
default = "/dev/disk/by-id";
|
default = "/dev/disk/by-id";
|
||||||
description = ''
|
description = ''
|
||||||
Name of directory from which to import ZFS devices.
|
Name of directory from which to import ZFS devices.
|
||||||
|
@ -278,8 +275,8 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
forceImportRoot = mkOption {
|
forceImportRoot = lib.mkOption {
|
||||||
type = types.bool;
|
type = lib.types.bool;
|
||||||
default = true;
|
default = true;
|
||||||
description = ''
|
description = ''
|
||||||
Forcibly import the ZFS root pool(s) during early boot.
|
Forcibly import the ZFS root pool(s) during early boot.
|
||||||
|
@ -296,8 +293,8 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
forceImportAll = mkOption {
|
forceImportAll = lib.mkOption {
|
||||||
type = types.bool;
|
type = lib.types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
description = ''
|
description = ''
|
||||||
Forcibly import all ZFS pool(s).
|
Forcibly import all ZFS pool(s).
|
||||||
|
@ -309,8 +306,8 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
requestEncryptionCredentials = mkOption {
|
requestEncryptionCredentials = lib.mkOption {
|
||||||
type = types.either types.bool (types.listOf types.str);
|
type = lib.types.either lib.types.bool (lib.types.listOf lib.types.str);
|
||||||
default = true;
|
default = true;
|
||||||
example = [ "tank" "data" ];
|
example = [ "tank" "data" ];
|
||||||
description = ''
|
description = ''
|
||||||
|
@ -321,8 +318,8 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
passwordTimeout = mkOption {
|
passwordTimeout = lib.mkOption {
|
||||||
type = types.int;
|
type = lib.types.int;
|
||||||
default = 0;
|
default = 0;
|
||||||
description = ''
|
description = ''
|
||||||
Timeout in seconds to wait for password entry for decrypt at boot.
|
Timeout in seconds to wait for password entry for decrypt at boot.
|
||||||
|
@ -332,7 +329,7 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
removeLinuxDRM = lib.mkOption {
|
removeLinuxDRM = lib.mkOption {
|
||||||
type = types.bool;
|
type = lib.types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
description = ''
|
description = ''
|
||||||
Patch the kernel to change symbols needed by ZFS from
|
Patch the kernel to change symbols needed by ZFS from
|
||||||
|
@ -345,9 +342,9 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
services.zfs.autoSnapshot = {
|
services.zfs.autoSnapshot = {
|
||||||
enable = mkOption {
|
enable = lib.mkOption {
|
||||||
default = false;
|
default = false;
|
||||||
type = types.bool;
|
type = lib.types.bool;
|
||||||
description = ''
|
description = ''
|
||||||
Enable the (OpenSolaris-compatible) ZFS auto-snapshotting service.
|
Enable the (OpenSolaris-compatible) ZFS auto-snapshotting service.
|
||||||
Note that you must set the `com.sun:auto-snapshot`
|
Note that you must set the `com.sun:auto-snapshot`
|
||||||
|
@ -360,10 +357,10 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
flags = mkOption {
|
flags = lib.mkOption {
|
||||||
default = "-k -p";
|
default = "-k -p";
|
||||||
example = "-k -p --utc";
|
example = "-k -p --utc";
|
||||||
type = types.str;
|
type = lib.types.str;
|
||||||
description = ''
|
description = ''
|
||||||
Flags to pass to the zfs-auto-snapshot command.
|
Flags to pass to the zfs-auto-snapshot command.
|
||||||
|
|
||||||
|
@ -379,41 +376,41 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
frequent = mkOption {
|
frequent = lib.mkOption {
|
||||||
default = 4;
|
default = 4;
|
||||||
type = types.int;
|
type = lib.types.int;
|
||||||
description = ''
|
description = ''
|
||||||
Number of frequent (15-minute) auto-snapshots that you wish to keep.
|
Number of frequent (15-minute) auto-snapshots that you wish to keep.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
hourly = mkOption {
|
hourly = lib.mkOption {
|
||||||
default = 24;
|
default = 24;
|
||||||
type = types.int;
|
type = lib.types.int;
|
||||||
description = ''
|
description = ''
|
||||||
Number of hourly auto-snapshots that you wish to keep.
|
Number of hourly auto-snapshots that you wish to keep.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
daily = mkOption {
|
daily = lib.mkOption {
|
||||||
default = 7;
|
default = 7;
|
||||||
type = types.int;
|
type = lib.types.int;
|
||||||
description = ''
|
description = ''
|
||||||
Number of daily auto-snapshots that you wish to keep.
|
Number of daily auto-snapshots that you wish to keep.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
weekly = mkOption {
|
weekly = lib.mkOption {
|
||||||
default = 4;
|
default = 4;
|
||||||
type = types.int;
|
type = lib.types.int;
|
||||||
description = ''
|
description = ''
|
||||||
Number of weekly auto-snapshots that you wish to keep.
|
Number of weekly auto-snapshots that you wish to keep.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
monthly = mkOption {
|
monthly = lib.mkOption {
|
||||||
default = 12;
|
default = 12;
|
||||||
type = types.int;
|
type = lib.types.int;
|
||||||
description = ''
|
description = ''
|
||||||
Number of monthly auto-snapshots that you wish to keep.
|
Number of monthly auto-snapshots that you wish to keep.
|
||||||
'';
|
'';
|
||||||
|
@ -421,16 +418,16 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
services.zfs.trim = {
|
services.zfs.trim = {
|
||||||
enable = mkOption {
|
enable = lib.mkOption {
|
||||||
description = "Whether to enable periodic TRIM on all ZFS pools.";
|
description = "Whether to enable periodic TRIM on all ZFS pools.";
|
||||||
default = true;
|
default = true;
|
||||||
example = false;
|
example = false;
|
||||||
type = types.bool;
|
type = lib.types.bool;
|
||||||
};
|
};
|
||||||
|
|
||||||
interval = mkOption {
|
interval = lib.mkOption {
|
||||||
default = "weekly";
|
default = "weekly";
|
||||||
type = types.str;
|
type = lib.types.str;
|
||||||
example = "daily";
|
example = "daily";
|
||||||
description = ''
|
description = ''
|
||||||
How often we run trim. For most desktop and server systems
|
How often we run trim. For most desktop and server systems
|
||||||
|
@ -441,9 +438,9 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
randomizedDelaySec = mkOption {
|
randomizedDelaySec = lib.mkOption {
|
||||||
default = "6h";
|
default = "6h";
|
||||||
type = types.str;
|
type = lib.types.str;
|
||||||
example = "12h";
|
example = "12h";
|
||||||
description = ''
|
description = ''
|
||||||
Add a randomized delay before each ZFS trim.
|
Add a randomized delay before each ZFS trim.
|
||||||
|
@ -455,11 +452,11 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
services.zfs.autoScrub = {
|
services.zfs.autoScrub = {
|
||||||
enable = mkEnableOption "periodic scrubbing of ZFS pools";
|
enable = lib.mkEnableOption "periodic scrubbing of ZFS pools";
|
||||||
|
|
||||||
interval = mkOption {
|
interval = lib.mkOption {
|
||||||
default = "monthly";
|
default = "monthly";
|
||||||
type = types.str;
|
type = lib.types.str;
|
||||||
example = "quarterly";
|
example = "quarterly";
|
||||||
description = ''
|
description = ''
|
||||||
Systemd calendar expression when to scrub ZFS pools. See
|
Systemd calendar expression when to scrub ZFS pools. See
|
||||||
|
@ -467,9 +464,9 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
randomizedDelaySec = mkOption {
|
randomizedDelaySec = lib.mkOption {
|
||||||
default = "6h";
|
default = "6h";
|
||||||
type = types.str;
|
type = lib.types.str;
|
||||||
example = "12h";
|
example = "12h";
|
||||||
description = ''
|
description = ''
|
||||||
Add a randomized delay before each ZFS autoscrub.
|
Add a randomized delay before each ZFS autoscrub.
|
||||||
|
@ -479,9 +476,9 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
pools = mkOption {
|
pools = lib.mkOption {
|
||||||
default = [];
|
default = [];
|
||||||
type = types.listOf types.str;
|
type = lib.types.listOf lib.types.str;
|
||||||
example = [ "tank" ];
|
example = [ "tank" ];
|
||||||
description = ''
|
description = ''
|
||||||
List of ZFS pools to periodically scrub. If empty, all pools
|
List of ZFS pools to periodically scrub. If empty, all pools
|
||||||
|
@ -490,8 +487,8 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
services.zfs.expandOnBoot = mkOption {
|
services.zfs.expandOnBoot = lib.mkOption {
|
||||||
type = types.either (types.enum [ "disabled" "all" ]) (types.listOf types.str);
|
type = lib.types.either (lib.types.enum [ "disabled" "all" ]) (lib.types.listOf lib.types.str);
|
||||||
default = "disabled";
|
default = "disabled";
|
||||||
example = [ "tank" "dozer" ];
|
example = [ "tank" "dozer" ];
|
||||||
description = ''
|
description = ''
|
||||||
|
@ -508,10 +505,10 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
services.zfs.zed = {
|
services.zfs.zed = {
|
||||||
enableMail = mkOption {
|
enableMail = lib.mkOption {
|
||||||
type = types.bool;
|
type = lib.types.bool;
|
||||||
default = config.services.mail.sendmailSetuidWrapper != null;
|
default = config.services.mail.sendmailSetuidWrapper != null;
|
||||||
defaultText = literalExpression ''
|
defaultText = lib.literalExpression ''
|
||||||
config.services.mail.sendmailSetuidWrapper != null
|
config.services.mail.sendmailSetuidWrapper != null
|
||||||
'';
|
'';
|
||||||
description = ''
|
description = ''
|
||||||
|
@ -519,9 +516,9 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
settings = mkOption {
|
settings = lib.mkOption {
|
||||||
type = with types; attrsOf (oneOf [ str int bool (listOf str) ]);
|
type = with lib.types; attrsOf (oneOf [ str int bool (listOf str) ]);
|
||||||
example = literalExpression ''
|
example = lib.literalExpression ''
|
||||||
{
|
{
|
||||||
ZED_DEBUG_LOG = "/tmp/zed.debug.log";
|
ZED_DEBUG_LOG = "/tmp/zed.debug.log";
|
||||||
|
|
||||||
|
@ -549,8 +546,8 @@ in
|
||||||
|
|
||||||
###### implementation
|
###### implementation
|
||||||
|
|
||||||
config = mkMerge [
|
config = lib.mkMerge [
|
||||||
(mkIf cfgZfs.enabled {
|
(lib.mkIf cfgZfs.enabled {
|
||||||
assertions = [
|
assertions = [
|
||||||
{
|
{
|
||||||
assertion = cfgZfs.modulePackage.version == cfgZfs.package.version;
|
assertion = cfgZfs.modulePackage.version == cfgZfs.package.version;
|
||||||
|
@ -569,7 +566,7 @@ in
|
||||||
message = "boot.zfs.allowHibernation while force importing is enabled will cause data corruption";
|
message = "boot.zfs.allowHibernation while force importing is enabled will cause data corruption";
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
assertion = !(elem "" allPools);
|
assertion = !(lib.elem "" allPools);
|
||||||
message = ''
|
message = ''
|
||||||
Automatic pool detection found an empty pool name, which can't be used.
|
Automatic pool detection found an empty pool name, which can't be used.
|
||||||
Hint: for `fileSystems` entries with `fsType = zfs`, the `device` attribute
|
Hint: for `fileSystems` entries with `fsType = zfs`, the `device` attribute
|
||||||
|
@ -591,10 +588,10 @@ in
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
boot.initrd = mkIf inInitrd {
|
boot.initrd = lib.mkIf inInitrd {
|
||||||
kernelModules = [ "zfs" ];
|
kernelModules = [ "zfs" ];
|
||||||
extraUtilsCommands =
|
extraUtilsCommands =
|
||||||
mkIf (!config.boot.initrd.systemd.enable) ''
|
lib.mkIf (!config.boot.initrd.systemd.enable) ''
|
||||||
copy_bin_and_libs ${cfgZfs.package}/sbin/zfs
|
copy_bin_and_libs ${cfgZfs.package}/sbin/zfs
|
||||||
copy_bin_and_libs ${cfgZfs.package}/sbin/zdb
|
copy_bin_and_libs ${cfgZfs.package}/sbin/zdb
|
||||||
copy_bin_and_libs ${cfgZfs.package}/sbin/zpool
|
copy_bin_and_libs ${cfgZfs.package}/sbin/zpool
|
||||||
|
@ -602,12 +599,12 @@ in
|
||||||
copy_bin_and_libs ${cfgZfs.package}/lib/udev/zvol_id
|
copy_bin_and_libs ${cfgZfs.package}/lib/udev/zvol_id
|
||||||
'';
|
'';
|
||||||
extraUtilsCommandsTest =
|
extraUtilsCommandsTest =
|
||||||
mkIf (!config.boot.initrd.systemd.enable) ''
|
lib.mkIf (!config.boot.initrd.systemd.enable) ''
|
||||||
$out/bin/zfs --help >/dev/null 2>&1
|
$out/bin/zfs --help >/dev/null 2>&1
|
||||||
$out/bin/zpool --help >/dev/null 2>&1
|
$out/bin/zpool --help >/dev/null 2>&1
|
||||||
'';
|
'';
|
||||||
postResumeCommands = mkIf (!config.boot.initrd.systemd.enable) (concatStringsSep "\n" ([''
|
postResumeCommands = lib.mkIf (!config.boot.initrd.systemd.enable) (lib.concatStringsSep "\n" ([''
|
||||||
ZFS_FORCE="${optionalString cfgZfs.forceImportRoot "-f"}"
|
ZFS_FORCE="${lib.optionalString cfgZfs.forceImportRoot "-f"}"
|
||||||
''] ++ [(importLib {
|
''] ++ [(importLib {
|
||||||
# See comments at importLib definition.
|
# See comments at importLib definition.
|
||||||
zpoolCmd = "zpool";
|
zpoolCmd = "zpool";
|
||||||
|
@ -629,21 +626,21 @@ in
|
||||||
poolImported "${pool}" || poolImport "${pool}" # Try one last time, e.g. to import a degraded pool.
|
poolImported "${pool}" || poolImport "${pool}" # Try one last time, e.g. to import a degraded pool.
|
||||||
fi
|
fi
|
||||||
|
|
||||||
${optionalString config.boot.initrd.clevis.enable (concatMapStringsSep "\n" (elem: "clevis decrypt < /etc/clevis/${elem}.jwe | zfs load-key ${elem}") (filter (p: (elemAt (splitString "/" p) 0) == pool) clevisDatasets))}
|
${lib.optionalString config.boot.initrd.clevis.enable (lib.concatMapStringsSep "\n" (elem: "clevis decrypt < /etc/clevis/${elem}.jwe | zfs load-key ${elem}") (lib.filter (p: (lib.elemAt (lib.splitString "/" p) 0) == pool) clevisDatasets))}
|
||||||
|
|
||||||
${if isBool cfgZfs.requestEncryptionCredentials
|
${if lib.isBool cfgZfs.requestEncryptionCredentials
|
||||||
then optionalString cfgZfs.requestEncryptionCredentials ''
|
then lib.optionalString cfgZfs.requestEncryptionCredentials ''
|
||||||
zfs load-key -a
|
zfs load-key -a
|
||||||
''
|
''
|
||||||
else concatMapStrings (fs: ''
|
else lib.concatMapStrings (fs: ''
|
||||||
zfs load-key -- ${escapeShellArg fs}
|
zfs load-key -- ${lib.escapeShellArg fs}
|
||||||
'') (filter (x: datasetToPool x == pool) cfgZfs.requestEncryptionCredentials)}
|
'') (lib.filter (x: datasetToPool x == pool) cfgZfs.requestEncryptionCredentials)}
|
||||||
'') rootPools)));
|
'') rootPools)));
|
||||||
|
|
||||||
# Systemd in stage 1
|
# Systemd in stage 1
|
||||||
systemd = mkIf config.boot.initrd.systemd.enable {
|
systemd = lib.mkIf config.boot.initrd.systemd.enable {
|
||||||
packages = [cfgZfs.package];
|
packages = [cfgZfs.package];
|
||||||
services = listToAttrs (map (pool: createImportService {
|
services = lib.listToAttrs (map (pool: createImportService {
|
||||||
inherit pool;
|
inherit pool;
|
||||||
systemd = config.boot.initrd.systemd.package;
|
systemd = config.boot.initrd.systemd.package;
|
||||||
force = cfgZfs.forceImportRoot;
|
force = cfgZfs.forceImportRoot;
|
||||||
|
@ -670,18 +667,18 @@ in
|
||||||
systemd.shutdownRamfs.storePaths = ["${cfgZfs.package}/bin/zpool"];
|
systemd.shutdownRamfs.storePaths = ["${cfgZfs.package}/bin/zpool"];
|
||||||
|
|
||||||
# TODO FIXME See https://github.com/NixOS/nixpkgs/pull/99386#issuecomment-798813567. To not break people's bootloader and as probably not everybody would read release notes that thoroughly add inSystem.
|
# TODO FIXME See https://github.com/NixOS/nixpkgs/pull/99386#issuecomment-798813567. To not break people's bootloader and as probably not everybody would read release notes that thoroughly add inSystem.
|
||||||
boot.loader.grub = mkIf (inInitrd || inSystem) {
|
boot.loader.grub = lib.mkIf (inInitrd || inSystem) {
|
||||||
zfsSupport = true;
|
zfsSupport = true;
|
||||||
zfsPackage = cfgZfs.package;
|
zfsPackage = cfgZfs.package;
|
||||||
};
|
};
|
||||||
|
|
||||||
services.zfs.zed.settings = {
|
services.zfs.zed.settings = {
|
||||||
ZED_EMAIL_PROG = mkIf cfgZED.enableMail (mkDefault (
|
ZED_EMAIL_PROG = lib.mkIf cfgZED.enableMail (lib.mkDefault (
|
||||||
config.security.wrapperDir + "/" +
|
config.security.wrapperDir + "/" +
|
||||||
config.services.mail.sendmailSetuidWrapper.program
|
config.services.mail.sendmailSetuidWrapper.program
|
||||||
));
|
));
|
||||||
# subject in header for sendmail
|
# subject in header for sendmail
|
||||||
ZED_EMAIL_OPTS = mkIf cfgZED.enableMail (mkDefault "@ADDRESS@");
|
ZED_EMAIL_OPTS = lib.mkIf cfgZED.enableMail (lib.mkDefault "@ADDRESS@");
|
||||||
|
|
||||||
PATH = lib.makeBinPath [
|
PATH = lib.makeBinPath [
|
||||||
cfgZfs.package
|
cfgZfs.package
|
||||||
|
@ -700,7 +697,7 @@ in
|
||||||
ACTION=="add|change", KERNEL=="sd[a-z]*[0-9]*|mmcblk[0-9]*p[0-9]*|nvme[0-9]*n[0-9]*p[0-9]*", ENV{ID_FS_TYPE}=="zfs_member", ATTR{../queue/scheduler}="none"
|
ACTION=="add|change", KERNEL=="sd[a-z]*[0-9]*|mmcblk[0-9]*p[0-9]*|nvme[0-9]*n[0-9]*p[0-9]*", ENV{ID_FS_TYPE}=="zfs_member", ATTR{../queue/scheduler}="none"
|
||||||
'';
|
'';
|
||||||
|
|
||||||
environment.etc = genAttrs
|
environment.etc = lib.genAttrs
|
||||||
(map
|
(map
|
||||||
(file: "zfs/zed.d/${file}")
|
(file: "zfs/zed.d/${file}")
|
||||||
[
|
[
|
||||||
|
@ -725,7 +722,7 @@ in
|
||||||
|
|
||||||
system.fsPackages = [ cfgZfs.package ]; # XXX: needed? zfs doesn't have (need) a fsck
|
system.fsPackages = [ cfgZfs.package ]; # XXX: needed? zfs doesn't have (need) a fsck
|
||||||
environment.systemPackages = [ cfgZfs.package ]
|
environment.systemPackages = [ cfgZfs.package ]
|
||||||
++ optional cfgSnapshots.enable autosnapPkg; # so the user can run the command to see flags
|
++ lib.optional cfgSnapshots.enable autosnapPkg; # so the user can run the command to see flags
|
||||||
|
|
||||||
services.udev.packages = [ cfgZfs.package ]; # to hook zvol naming, etc.
|
services.udev.packages = [ cfgZfs.package ]; # to hook zvol naming, etc.
|
||||||
systemd.packages = [ cfgZfs.package ];
|
systemd.packages = [ cfgZfs.package ];
|
||||||
|
@ -740,7 +737,7 @@ in
|
||||||
# This forces a sync of any ZFS pools prior to poweroff, even if they're set
|
# This forces a sync of any ZFS pools prior to poweroff, even if they're set
|
||||||
# to sync=disabled.
|
# to sync=disabled.
|
||||||
createSyncService = pool:
|
createSyncService = pool:
|
||||||
nameValuePair "zfs-sync-${pool}" {
|
lib.nameValuePair "zfs-sync-${pool}" {
|
||||||
description = "Sync ZFS pool \"${pool}\"";
|
description = "Sync ZFS pool \"${pool}\"";
|
||||||
wantedBy = [ "shutdown.target" ];
|
wantedBy = [ "shutdown.target" ];
|
||||||
unitConfig = {
|
unitConfig = {
|
||||||
|
@ -756,12 +753,12 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
createZfsService = serv:
|
createZfsService = serv:
|
||||||
nameValuePair serv {
|
lib.nameValuePair serv {
|
||||||
after = [ "systemd-modules-load.service" ];
|
after = [ "systemd-modules-load.service" ];
|
||||||
wantedBy = [ "zfs.target" ];
|
wantedBy = [ "zfs.target" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
in listToAttrs (map createImportService' dataPools ++
|
in lib.listToAttrs (map createImportService' dataPools ++
|
||||||
map createSyncService allPools ++
|
map createSyncService allPools ++
|
||||||
map createZfsService [ "zfs-mount" "zfs-share" "zfs-zed" ]);
|
map createZfsService [ "zfs-mount" "zfs-share" "zfs-zed" ]);
|
||||||
|
|
||||||
|
@ -770,7 +767,7 @@ in
|
||||||
systemd.targets.zfs.wantedBy = [ "multi-user.target" ];
|
systemd.targets.zfs.wantedBy = [ "multi-user.target" ];
|
||||||
})
|
})
|
||||||
|
|
||||||
(mkIf (cfgZfs.enabled && cfgExpandOnBoot != "disabled") {
|
(lib.mkIf (cfgZfs.enabled && cfgExpandOnBoot != "disabled") {
|
||||||
systemd.services."zpool-expand@" = {
|
systemd.services."zpool-expand@" = {
|
||||||
description = "Expand ZFS pools";
|
description = "Expand ZFS pools";
|
||||||
after = [ "zfs.target" ];
|
after = [ "zfs.target" ];
|
||||||
|
@ -823,7 +820,7 @@ in
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
||||||
(mkIf (cfgZfs.enabled && cfgSnapshots.enable) {
|
(lib.mkIf (cfgZfs.enabled && cfgSnapshots.enable) {
|
||||||
systemd.services = let
|
systemd.services = let
|
||||||
descr = name: if name == "frequent" then "15 mins"
|
descr = name: if name == "frequent" then "15 mins"
|
||||||
else if name == "hourly" then "hour"
|
else if name == "hourly" then "hour"
|
||||||
|
@ -861,7 +858,7 @@ in
|
||||||
}) snapshotNames);
|
}) snapshotNames);
|
||||||
})
|
})
|
||||||
|
|
||||||
(mkIf (cfgZfs.enabled && cfgScrub.enable) {
|
(lib.mkIf (cfgZfs.enabled && cfgScrub.enable) {
|
||||||
systemd.services.zfs-scrub = {
|
systemd.services.zfs-scrub = {
|
||||||
description = "ZFS pools scrubbing";
|
description = "ZFS pools scrubbing";
|
||||||
after = [ "zfs-import.target" ];
|
after = [ "zfs-import.target" ];
|
||||||
|
@ -871,7 +868,7 @@ in
|
||||||
script = ''
|
script = ''
|
||||||
${cfgZfs.package}/bin/zpool scrub -w ${
|
${cfgZfs.package}/bin/zpool scrub -w ${
|
||||||
if cfgScrub.pools != [] then
|
if cfgScrub.pools != [] then
|
||||||
(concatStringsSep " " cfgScrub.pools)
|
(lib.concatStringsSep " " cfgScrub.pools)
|
||||||
else
|
else
|
||||||
"$(${cfgZfs.package}/bin/zpool list -H -o name)"
|
"$(${cfgZfs.package}/bin/zpool list -H -o name)"
|
||||||
}
|
}
|
||||||
|
@ -889,7 +886,7 @@ in
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
||||||
(mkIf (cfgZfs.enabled && cfgTrim.enable) {
|
(lib.mkIf (cfgZfs.enabled && cfgTrim.enable) {
|
||||||
systemd.services.zpool-trim = {
|
systemd.services.zpool-trim = {
|
||||||
description = "ZFS pools trim";
|
description = "ZFS pools trim";
|
||||||
after = [ "zfs-import.target" ];
|
after = [ "zfs-import.target" ];
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue