# Requires boot.initrd.enable = true and boot.initrd.systemd.enable = true! { config, lib, pkgs, ... }: with lib; let cfg = config.sydnix.impermanence; in { options = { sydnix.impermanence = { enable = mkOption { description = "Enable Impermanence"; type = types.bool; default = false; }; directories = mkOption { description = ""; type = with types; listOf anything; default = []; }; persistGroupName = mkOption { default = "persist"; type = types.str; }; files = mkOption { description = ""; type = with types; listOf anything; default = []; }; rollbackTo = mkOption { type = types.str; }; archiveTo = mkOption { type = types.str; default = "/persist/previous/home"; }; dataset = mkOption { type = types.str; }; archiveLimit = mkOption { type = types.ints.positive; default = 3; }; }; }; config = mkIf cfg.enable { users.groups.${cfg.persistGroupName} = { name = cfg.persistGroupName; }; systemd.tmpfiles.settings = { "10-persist" = { "/persist" = { z = { group = cfg.persistGroupName; mode = "2775"; }; }; }; }; boot.initrd.systemd.initrdBin = with pkgs; [ zfs ]; # TODO: Move this somewhere else. programs.fuse.userAllowOther = true; boot.initrd.systemd.services.erase-darlings = let service = { description = "Rollback filesystem to a blank state on boot"; wantedBy = [ "initrd.target" ]; after = [ # "zfs-import.service" "zfs-import-rpool.service" ]; before = [ "sysroot.mount" ]; path = [ pkgs.zfs ]; unitConfig.DefaultDependencies = "no"; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; }; script = /* bash */ '' zfs rollback -r rpool/local/root@blank \ && echo ">> >> rollback complete << <<" ''; }; in if config.boot.initrd.systemd.enable then service else throw "sydnix.impermanence currently requires config.boot.initrd.systemd.enable'!"; systemd.services = let erase-home-darlings = { description = "Rollback home to a blank state on boot"; wantedBy = [ "local-fs-pre.target" "zfs-mount.service" ]; before = [ "local-fs.target" "local-fs-pre.target" "zfs-mount.service" ]; path = [ pkgs.zfs pkgs.babashka pkgs.util-linux ]; unitConfig.DefaultDependencies = "no"; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; ExecStart = let script = ./erase-home-darlings.clj; in ''${pkgs.babashka}/bin/bb "${script}" -n "${toString cfg.archiveLimit}" --dataset "${cfg.dataset}" --rollback-to "${cfg.rollbackTo}"''; }; stopIfChanged = false; restartIfChanged = false; }; in { # inherit erase-home-darlings; }; environment.persistence."/persist/root" = { directories = cfg.directories; files = cfg.files; }; }; }