Files
sydnix/modules/nixos/impermanence/rollback.nix
T
msyds 3ad33b734a
build / build (push) Failing after 53s
chore: bump all
2026-06-25 05:55:08 -06:00

99 lines
3.4 KiB
Nix

{ config, lib, pkgs, ... }:
with lib;
let cfg = config.sydnix.impermanence.rollback;
in {
options = {
sydnix.impermanence.rollback = {
enable = mkEnableOption "rollback of the root filesystem";
device = mkOption {
description = "Device to be wiped";
type = types.str;
};
subvolume = mkOption {
description = ''
The subvolume to be rolled back. Usually, this should be where your
root filesystem resides.
'';
type = types.str;
};
};
};
config = mkIf cfg.enable {
boot.initrd.systemd = {
services.impermance-btrfs-rolling-root = {
description = "Archiving existing BTRFS root subvolume and creating a fresh one";
unitConfig.DefaultDependencies = false;
serviceConfig = {
# The script needs to run to completion before this service
# is done
Type = "oneshot";
# NOTE: to be able to see errors in your script do this
StandardOutput = "journal+console";
StandardError = "journal+console";
};
# This service is required for boot to succeed
requiredBy = ["initrd.target"];
# Should complete before any file systems are mounted
before = ["sysroot.mount"];
# Wait until the root device is available
# If you're altering a different device, specify its device unit explicitly.
# see: systemd-escape(1)
requires = ["initrd-root-device.target"];
after = [
"initrd-root-device.target"
# Allow hibernation to resume before trying to alter any data
"local-fs-pre.target"
];
script = ''
# Mount the btrfs filesystem.
mkdir -p /btrfs-tmp
mount -t btrfs "${cfg.device}" /btrfs-tmp
# If the moribund subvolume exists, send it do 'death row' (old-roots),
# where live for about three days before its eventual deletion.
if [[ -e "/btrfs-tmp/${cfg.subvolume}" ]]; then
mkdir -p /btrfs-tmp/old-roots
timestamp=$(date --date="@$(stat -c %Y "/btrfs-tmp/${cfg.subvolume}")" "+%Y-%m-%-d_%H:%M:%S")
mv "/btrfs-tmp/${cfg.subvolume}" "/btrfs-tmp/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 "/btrfs-tmp/$i"
done
btrfs subvolume delete "$1"
}
# Delete previous roots older than three days.
# TODO: I would prefer archiving the last N previous roots, rather than
# time.
for i in $(find /btrfs-tmp/old-roots/ -maxdepth 1 -mtime +3); do
delete_subvolume_recursively "$i"
done
btrfs subvolume create "/btrfs-tmp/${cfg.subvolume}"
umount /btrfs-tmp
'';
};
# NOTE: path = [...]; doesnt work for initrd, use full paths in
# your script or extraBin
extraBin = {
"mkdir" = "${pkgs.coreutils}/bin/mkdir";
"date" = "${pkgs.coreutils}/bin/date";
"stat" = "${pkgs.coreutils}/bin/stat";
"mv" = "${pkgs.coreutils}/bin/mv";
"find" = "${pkgs.findutils}/bin/find";
"btrfs" = "${pkgs.btrfs-progs}/bin/btrfs";
};
};
};
}