feat(storage): add impermanence

We'll setup impermanence for a1d1 based on some RAIDed together hard
drives we have. In doing so, we'll gain the ability to keep some
important data persistent while losing everything else.

This is also useful when looking for what to backup.

Change-Id: I51a9dfcaea46a4a21e601615ddd7288c91effa9e
Reviewed-on: https://git.clicks.codes/c/Infra/NixFiles/+/724
Tested-by: Samuel Shuert <coded@clicks.codes>
Reviewed-by: Samuel Shuert <coded@clicks.codes>
diff --git a/modules/nixos/clicks/storage/impermanence/default.nix b/modules/nixos/clicks/storage/impermanence/default.nix
index ac797a6..eb8a72e 100644
--- a/modules/nixos/clicks/storage/impermanence/default.nix
+++ b/modules/nixos/clicks/storage/impermanence/default.nix
@@ -11,33 +11,56 @@
 {
   options.clicks.storage.impermanence = {
     enable = lib.mkEnableOption "Enable impermanent rootfs with btrfs subvolumes";
-    device = lib.mkOption {
-      type = lib.types.str;
-      description = "Device Path";
+    devices = {
+      root = lib.mkOption {
+        type = lib.types.str;
+        description = "Rootfs device path";
+      };
+      persist = lib.mkOption {
+        type = lib.types.str;
+        description = "Persistent data device path";
+      };
     };
     volumes = {
       mount = lib.mkOption {
         type = lib.types.str;
-        description = "Path on device to the mounting subvolume, everything on here will be deleted";
+        description = "Path on rootfs device to the mounting subvolume, everything on here will be deleted";
         default = "@";
       };
       old_roots = lib.mkOption {
         type = lib.types.str;
-        description = "Path on device to store old roots on";
+        description = "Path on rootfs device to store old roots on";
         default = "old_roots";
       };
+      persistent_data = lib.mkOption {
+        type = lib.types.str;
+        description = "Path on persist device to store persistent data on";
+        default = "data";
+      };
     };
     delete_days = lib.mkOption {
       type = lib.types.int;
-      description = "How many days to wait before deleting an old root from cfg.old_roots";
+      description = "How many days to wait before deleting an old root from `cfg.volumes.old_roots`";
       default = 7;
     };
+    persist = {
+      directories = lib.mkOption {
+        type = lib.types.listOf lib.types.str;
+        description = "List of directories to store between boots";
+        default = [ ];
+      };
+      files = lib.mkOption {
+        type = lib.types.listOf lib.types.str;
+        description = "List of files to store between boots";
+        default = [ ];
+      };
+    };
   };
 
   config = lib.mkIf cfg.enable {
     boot.initrd.postDeviceCommands = lib.mkAfter ''
       mkdir /impermanent_fs
-      mount ${cfg.device} /impermanent_fs
+      mount ${cfg.devices.root} /impermanent_fs
 
       if [[ -e /impermanent_fs/${cfg.volumes.mount} ]]; then
           mkdir -p /impermanent_fs/${cfg.volumes.old_roots}
@@ -62,9 +85,26 @@
     '';
 
     fileSystems."/" = {
-      device = cfg.device;
+      device = cfg.devices.root;
       fsType = "btrfs";
       options = [ "subvol=${cfg.volumes.mount}" ];
     };
+
+    fileSystems."/persist" = {
+      device = cfg.devices.persist;
+      neededForBoot = true;
+      fsType = "btrfs";
+    };
+
+    environment.persistence."/persist/${cfg.volumes.persistent_data}" = {
+      directories = [ ] ++ cfg.persist.directories;
+      files = [
+        "/etc/machine-id"
+        "/etc/ssh/ssh_host_ed25519_key"
+        "/etc/ssh/ssh_host_ed25519_key.pub"
+        "/etc/ssh/ssh_host_rsa_key"
+        "/etc/ssh/ssh_host_rsa_key.pub"
+      ] ++ cfg.persist.files;
+    };
   };
 }