diff --git a/nixos/modules/tasks/filesystems/zfs.nix b/nixos/modules/tasks/filesystems/zfs.nix index 853cd833fd04..32e3da6a273c 100644 --- a/nixos/modules/tasks/filesystems/zfs.nix +++ b/nixos/modules/tasks/filesystems/zfs.nix @@ -11,18 +11,30 @@ with pkgs.lib; let cfgSpl = config.boot.spl; + cfgSnapshots = config.services.zfs.autoSnapshot; + inInitrd = any (fs: fs == "zfs") config.boot.initrd.supportedFilesystems; inSystem = any (fs: fs == "zfs") config.boot.supportedFilesystems; + + enableAutoSnapshots = cfgSnapshots.enable; + enableZfs = inInitrd || inSystem || enableAutoSnapshots; + kernel = config.boot.kernelPackages; + autosnapPkg = pkgs.zfstools.override { + zfs = config.boot.kernelPackages.zfs; + }; + + zfsAutoSnap = "${autosnapPkg}/bin/zfs-auto-snapshot"; + in { ###### interface - - options = { - boot.spl.hostid = mkOption { + + options = { + boot.spl.hostid = mkOption { default = ""; example = "0xdeadbeef"; description = '' @@ -34,62 +46,177 @@ in manually import pools. ''; }; + + services.zfs.autoSnapshot = { + enable = mkOption { + default = false; + type = types.bool; + description = '' + Enable the (OpenSolaris-compatible) ZFS auto-snapshotting service. + Note that you must set the com.sun:auto-snapshot + property to true on all datasets which you wish + to auto-snapshot. + + You can override a child dataset to use, or not use auto-snapshotting + by setting its flag with the given interval: + zfs set com.sun:auto-snapshot:weekly=false DATASET + ''; + }; + + frequent = mkOption { + default = 4; + type = types.int; + description = '' + Number of frequent (15-minute) auto-snapshots that you wish to keep. + ''; + }; + + hourly = mkOption { + default = 24; + type = types.int; + description = '' + Number of hourly auto-snapshots that you wish to keep. + ''; + }; + + daily = mkOption { + default = 7; + type = types.int; + description = '' + Number of daily auto-snapshots that you wish to keep. + ''; + }; + + weekly = mkOption { + default = 4; + type = types.int; + description = '' + Number of weekly auto-snapshots that you wish to keep. + ''; + }; + + monthly = mkOption { + default = 12; + type = types.int; + description = '' + Number of monthly auto-snapshots that you wish to keep. + ''; + }; + }; }; ###### implementation - config = mkIf ( inInitrd || inSystem ) { - - boot = { - kernelModules = [ "spl" "zfs" ] ; - extraModulePackages = [ kernel.zfs kernel.spl ]; - extraModprobeConfig = mkIf (cfgSpl.hostid != "") '' - options spl spl_hostid=${cfgSpl.hostid} - ''; - }; - - boot.initrd = mkIf inInitrd { - kernelModules = [ "spl" "zfs" ] ; - extraUtilsCommands = - '' - cp -v ${kernel.zfs}/sbin/zfs $out/bin - cp -v ${kernel.zfs}/sbin/zdb $out/bin - cp -v ${kernel.zfs}/sbin/zpool $out/bin - cp -pdv ${kernel.zfs}/lib/lib*.so* $out/lib - cp -pdv ${pkgs.zlib}/lib/lib*.so* $out/lib + config = mkMerge [ + (mkIf enableZfs { + boot = { + kernelModules = [ "spl" "zfs" ] ; + extraModulePackages = [ kernel.zfs kernel.spl ]; + extraModprobeConfig = mkIf (cfgSpl.hostid != "") '' + options spl spl_hostid=${cfgSpl.hostid} ''; - postDeviceCommands = - '' - zpool import -f -a - ''; - }; - - systemd.services."zpool-import" = { - description = "Import zpools"; - after = [ "systemd-udev-settle.service" ]; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - restartIfChanged = false; - ExecStart = "${kernel.zfs}/sbin/zpool import -f -a"; }; - }; - systemd.services."zfs-mount" = { - description = "Mount ZFS Volumes"; - after = [ "zpool-import.service" ]; - wantedBy = [ "local-fs.target" ]; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - restartIfChanged = false; - ExecStart = "${kernel.zfs}/sbin/zfs mount -a"; - ExecStop = "${kernel.zfs}/sbin/zfs umount -a"; + boot.initrd = mkIf inInitrd { + kernelModules = [ "spl" "zfs" ] ; + extraUtilsCommands = + '' + cp -v ${kernel.zfs}/sbin/zfs $out/bin + cp -v ${kernel.zfs}/sbin/zdb $out/bin + cp -v ${kernel.zfs}/sbin/zpool $out/bin + cp -pdv ${kernel.zfs}/lib/lib*.so* $out/lib + cp -pdv ${pkgs.zlib}/lib/lib*.so* $out/lib + ''; + postDeviceCommands = + '' + zpool import -f -a + ''; }; - }; - system.fsPackages = [ kernel.zfs ]; # XXX: needed? zfs doesn't have (need) a fsck - environment.systemPackages = [ kernel.zfs ]; - services.udev.packages = [ kernel.zfs ]; # to hook zvol naming, etc. - }; + systemd.services."zpool-import" = { + description = "Import zpools"; + after = [ "systemd-udev-settle.service" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = "${kernel.zfs}/sbin/zpool import -f -a"; + }; + restartIfChanged = false; + }; + + systemd.services."zfs-mount" = { + description = "Mount ZFS Volumes"; + after = [ "zpool-import.service" ]; + wantedBy = [ "local-fs.target" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = "${kernel.zfs}/sbin/zfs mount -a"; + ExecStop = "${kernel.zfs}/sbin/zfs umount -a"; + }; + restartIfChanged = false; + }; + + system.fsPackages = [ kernel.zfs ]; # XXX: needed? zfs doesn't have (need) a fsck + environment.systemPackages = [ kernel.zfs ]; + services.udev.packages = [ kernel.zfs ]; # to hook zvol naming, etc. + }) + + (mkIf enableAutoSnapshots { + systemd.services."zfs-snapshot-frequent" = { + description = "ZFS auto-snapshotting every 15 mins"; + after = [ "zpool-import.service" ]; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${zfsAutoSnap} frequent ${toString cfgSnapshots.frequent}"; + }; + restartIfChanged = false; + startAt = "*:15,30,45"; + }; + + systemd.services."zfs-snapshot-hourly" = { + description = "ZFS auto-snapshotting every hour"; + after = [ "zpool-import.service" ]; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${zfsAutoSnap} hourly ${toString cfgSnapshots.hourly}"; + }; + restartIfChanged = false; + startAt = "hourly"; + }; + + systemd.services."zfs-snapshot-daily" = { + description = "ZFS auto-snapshotting every day"; + after = [ "zpool-import.service" ]; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${zfsAutoSnap} daily ${toString cfgSnapshots.daily}"; + }; + restartIfChanged = false; + startAt = "daily"; + }; + + systemd.services."zfs-snapshot-weekly" = { + description = "ZFS auto-snapshotting every week"; + after = [ "zpool-import.service" ]; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${zfsAutoSnap} weekly ${toString cfgSnapshots.weekly}"; + }; + restartIfChanged = false; + startAt = "weekly"; + }; + + systemd.services."zfs-snapshot-monthly" = { + description = "ZFS auto-snapshotting every month"; + after = [ "zpool-import.service" ]; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${zfsAutoSnap} monthly ${toString cfgSnapshots.monthly}"; + }; + restartIfChanged = false; + startAt = "monthly"; + }; + }) + ]; }