# 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 = []; }; device = mkOption { description = "Device to be wiped"; type = types.str; }; archiveLimit = mkOption { type = types.ints.positive; description = "The number of previous roots to preserve."; default = 3; }; }; }; config = mkIf cfg.enable { # Create a group called `cfg.persistGroupName` users.groups.${cfg.persistGroupName} = { name = cfg.persistGroupName; }; systemd.tmpfiles.settings = { "10-persist" = { # Permit members of `cfg.persistGroupName` to read, write, and execute # /persist. "/persist" = { z = { group = cfg.persistGroupName; mode = "2775"; }; }; }; }; # TODO: Move this somewhere else. programs.fuse.userAllowOther = true; # sudo mount -o ro -t virtiofs mount-dots /persist/dots boot.initrd.systemd = { # `pkgs.babashka` calls `pkgs.babashka-unwrapped`, and will explode if it # cannot find it. storePaths = [ pkgs.babashka-unwrapped ]; initrdBin = with pkgs; [ babashka util-linux ]; }; boot.initrd.systemd.services.erase-darlings = let service = { description = "Rollback filesystem to a blank state on boot"; wantedBy = [ "initrd.target" ]; before = [ "sysroot.mount" ]; path = with pkgs; [ util-linux babashka ]; unitConfig.DefaultDependencies = "no"; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; }; script = let bb-script = "/sysroot" + ./impermanence/erase-darlings.clj; in ''${pkgs.babashka}/bin/bb "${bb-script}" -n "${toString cfg.archiveLimit}" --device "${cfg.device}"''; }; in if config.boot.initrd.systemd.enable then service else throw "sydnix.impermanence currently requires config.boot.initrd.systemd.enable'!"; # TODO: Remove this. # boot.initrd.systemd.services.erase-darlings-old = # 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; }; }; }