feat(storage): erase rootfs on boot
We want impermanence so that it's easier to keep track of what state we
have on our system, and what we should be rigrously backing up
This is the first step towards setting that up
Change-Id: I399a7035237f02172180be559c9340faba40af47
Reviewed-on: https://git.clicks.codes/c/Infra/NixFiles/+/722
Reviewed-by: Samuel Shuert <coded@clicks.codes>
Tested-by: Samuel Shuert <coded@clicks.codes>
diff --git a/modules/nixos/clicks/storage/impermanence/default.nix b/modules/nixos/clicks/storage/impermanence/default.nix
new file mode 100644
index 0000000..ac797a6
--- /dev/null
+++ b/modules/nixos/clicks/storage/impermanence/default.nix
@@ -0,0 +1,70 @@
+# SPDX-FileCopyrightText: 2024 Clicks Codes
+# SPDX-FileCopyrightText: 2020 Nix Community Projects
+#
+# SPDX-License-Identifier: MIT
+# postDeviceCommands based of code from https://github.com/nix-community/impermanence/tree/d5f1ed7141fa407880ff5956ded2c88a307ca940?tab=readme-ov-file#btrfs-subvolumes
+
+{ lib, config, ... }:
+let
+ cfg = config.clicks.storage.impermanence;
+in
+{
+ options.clicks.storage.impermanence = {
+ enable = lib.mkEnableOption "Enable impermanent rootfs with btrfs subvolumes";
+ device = lib.mkOption {
+ type = lib.types.str;
+ description = "Device Path";
+ };
+ volumes = {
+ mount = lib.mkOption {
+ type = lib.types.str;
+ description = "Path on 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";
+ default = "old_roots";
+ };
+ };
+ delete_days = lib.mkOption {
+ type = lib.types.int;
+ description = "How many days to wait before deleting an old root from cfg.old_roots";
+ default = 7;
+ };
+ };
+
+ config = lib.mkIf cfg.enable {
+ boot.initrd.postDeviceCommands = lib.mkAfter ''
+ mkdir /impermanent_fs
+ mount ${cfg.device} /impermanent_fs
+
+ if [[ -e /impermanent_fs/${cfg.volumes.mount} ]]; then
+ mkdir -p /impermanent_fs/${cfg.volumes.old_roots}
+ timestamp=$(date --date="@$(stat -c %Y /impermanent_fs/${cfg.volumes.mount})" "+%Y-%m-%-d_%H:%M:%S")
+ mv /impermanent_fs/${cfg.volumes.mount} "/impermanent_fs/${cfg.volumes.old_roots}/$timestamp"
+ fi
+
+ delete_subvolume_recursively() {
+ IFS=$'\n'
+ for i in $(btrfs subvolume list -o "$1" | cut -f 9- -d ' '); do
+ delete_subvolume_recursively "/impermanent_fs/$i"
+ done
+ btrfs subvolume delete "$1"
+ }
+
+ for i in $(find /impermanent_fs/${cfg.volumes.old_roots}/ -maxdepth 1 -mtime +${builtins.toString cfg.delete_days}); do
+ delete_subvolume_recursively "$i"
+ done
+
+ btrfs subvolume create /impermanent_fs/${cfg.volumes.mount}
+ umount /impermanent_fs
+ '';
+
+ fileSystems."/" = {
+ device = cfg.device;
+ fsType = "btrfs";
+ options = [ "subvol=${cfg.volumes.mount}" ];
+ };
+ };
+}
diff --git a/systems/x86_64-linux/a1d1/default.nix b/systems/x86_64-linux/a1d1/default.nix
index 1bca337..3add29d 100644
--- a/systems/x86_64-linux/a1d1/default.nix
+++ b/systems/x86_64-linux/a1d1/default.nix
@@ -27,6 +27,13 @@
services = {
ssh.enable = true;
};
+
+ storage = {
+ impermanence = {
+ enable = true;
+ device = "/dev/disk/by-uuid/ab5c2f52-a737-4b29-a505-e3d0b9d0714c";
+ };
+ };
};
boot.initrd.availableKernelModules = [
@@ -42,10 +49,10 @@
boot.kernelModules = [ "kvm-amd" ];
boot.extraModulePackages = [ ];
- fileSystems."/" = {
+ fileSystems."/nix" = {
device = "/dev/disk/by-uuid/ab5c2f52-a737-4b29-a505-e3d0b9d0714c";
fsType = "btrfs";
- options = [ "subvol=@" ];
+ options = [ "subvol=@nix" ];
};
fileSystems."/boot" = {