feat: add rollback service for btrfs
This commit is contained in:
parent
6d85bb5bdb
commit
2c03698a2f
@ -1,16 +1,122 @@
|
|||||||
{
|
{
|
||||||
config,
|
config,
|
||||||
lib,
|
lib,
|
||||||
|
pkgs,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
inherit (lib) mkIf mkEnableOption;
|
inherit (builtins) map;
|
||||||
|
inherit (lib)
|
||||||
|
concatStringsSep
|
||||||
|
mkIf
|
||||||
|
mkEnableOption
|
||||||
|
mkOption
|
||||||
|
mkBefore
|
||||||
|
;
|
||||||
|
inherit (lib.types)
|
||||||
|
bool
|
||||||
|
str
|
||||||
|
listOf
|
||||||
|
submodule
|
||||||
|
;
|
||||||
cfg = config.ataraxia.filesystems.btrfs;
|
cfg = config.ataraxia.filesystems.btrfs;
|
||||||
|
|
||||||
|
eraseVolumesOpts =
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
vol = mkOption {
|
||||||
|
type = str;
|
||||||
|
example = "rootfs";
|
||||||
|
description = "Name of submodule to erase";
|
||||||
|
};
|
||||||
|
blank = mkOption {
|
||||||
|
type = str;
|
||||||
|
example = "rootfs-blank";
|
||||||
|
description = "Name of submodule to clone into `vol`";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.ataraxia.filesystems.btrfs = {
|
options.ataraxia.filesystems.btrfs = {
|
||||||
enable = mkEnableOption "Root on btrfs";
|
enable = mkEnableOption "Root on btrfs";
|
||||||
|
# Btrfs clean root
|
||||||
|
eraseOnBoot = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = bool;
|
||||||
|
default = config.persist.enable;
|
||||||
|
description = "Clean btrfs subvolumes on boot";
|
||||||
|
};
|
||||||
|
device = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Device on which is btrfs partititon";
|
||||||
|
};
|
||||||
|
systemdDevice = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Escaped string with name of .device service";
|
||||||
|
example = "dev-disk-by\\x2did-ata\\x2dPhison_SATA_SSD_2165.device";
|
||||||
|
};
|
||||||
|
eraseVolumes = mkOption {
|
||||||
|
type = listOf (submodule eraseVolumesOpts);
|
||||||
|
default = [ ];
|
||||||
|
example = [
|
||||||
|
{
|
||||||
|
vol = "rootfs";
|
||||||
|
blank = "rootfs-blank";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
description = ''
|
||||||
|
A list of subvolumes to erase on boot.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable { };
|
config =
|
||||||
|
let
|
||||||
|
script = ''
|
||||||
|
mkdir -p /mnt
|
||||||
|
mount -t btrfs -o subvol=/ ${cfg.eraseOnBoot.device} /mnt
|
||||||
|
|
||||||
|
${concatStringsSep "\n" (
|
||||||
|
map (x: ''
|
||||||
|
btrfs subvolume list -o /mnt/${x.vol} |
|
||||||
|
cut -f9 -d' ' |
|
||||||
|
while read subvolume; do
|
||||||
|
echo "deleting /$subvolume subvolume..."
|
||||||
|
btrfs subvolume delete "/mnt/$subvolume"
|
||||||
|
done &&
|
||||||
|
|
||||||
|
echo "deleting /${x.vol} subvolume..."
|
||||||
|
btrfs subvolume delete /mnt/${x.vol}
|
||||||
|
echo "restoring blank ${x.blank} subvolume..."
|
||||||
|
btrfs subvolume snapshot /mnt/snapshots/${x.blank} /mnt/${x.vol}
|
||||||
|
'') cfg.eraseOnBoot.eraseVolumes
|
||||||
|
)}
|
||||||
|
|
||||||
|
umount /mnt
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
mkIf cfg.enable {
|
||||||
|
boot.initrd = mkIf cfg.eraseOnBoot.enable {
|
||||||
|
postDeviceCommands = mkIf (!config.boot.initrd.systemd.enable) (mkBefore script);
|
||||||
|
|
||||||
|
systemd.services.rollback = mkIf config.boot.initrd.systemd.enable {
|
||||||
|
description = "Rollback btrfs root subvolume to a pristine state on boot";
|
||||||
|
wantedBy = [ "initrd.target" ];
|
||||||
|
requires = [ cfg.eraseOnBoot.systemdDevice ];
|
||||||
|
after = [ cfg.eraseOnBoot.systemdDevice ];
|
||||||
|
before = [ "sysroot.mount" ];
|
||||||
|
path = [
|
||||||
|
pkgs.btrfs-progs
|
||||||
|
pkgs.coreutils
|
||||||
|
pkgs.util-linuxMinimal.mount
|
||||||
|
];
|
||||||
|
unitConfig.DefaultDependencies = "no";
|
||||||
|
serviceConfig.Type = "oneshot";
|
||||||
|
script = script;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user