Add btrbk

Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
This commit is contained in:
2025-06-02 11:40:37 +01:00
parent 0481bc2785
commit 1f44a8b6bc
14 changed files with 59 additions and 112 deletions

View File

@@ -1,16 +0,0 @@
_backup_completion() {
local options=(
'-m[Partition to mount for backup]:partition:($(_partitions))'
'-b[Backup directory]:backup directory:_files -/'
)
local curcontext="$curcontext" state line
typeset -A opt_args
_partitions() {
lsblk -rno NAME | sed 's/^/\/dev\//'
}
_arguments -s $options
}
compdef _backup_completion backup

View File

@@ -1,67 +0,0 @@
# shellcheck shell=bash
if [[ "$EUID" -ne 0 ]]; then
echo "Please run the script as root."
exit 1
fi
usage() {
echo "Usage: $0 [-m partition] [-b backup_location]"
exit 1
}
cleanup() {
if [ -d "/persist/user.bak" ]; then btrfs -q subvolume delete "/persist/user.bak"; fi
if [ -n "$backup_location" ]; then rm -f "$backup_location.tmp"; fi
if [ -n "$mount_location" ]; then
if mount | grep -q "$mount_location"; then umount "$mount_location"; fi
if [ -d "$mount_location" ]; then rmdir "$mount_location"; fi
fi
}
partition=""
backup_location=""
mount_location=""
trap cleanup EXIT
while getopts "m:b:" opt; do
case "$opt" in
m) partition="$OPTARG" ;;
b) backup_location="$OPTARG" ;;
*) usage ;;
esac
done
if [ -n "$partition" ]; then
mkdir -p "/mnt"
mount_location=$(mktemp -d /mnt/backup.XXXXXX)
echo "Mounting $partition at $mount_location..."
mount "$partition" "$mount_location"
fi
if [ -z "$mount_location" ]; then
if [[ "$backup_location" != /* ]]; then
backup_location="$(realpath "$backup_location")"
fi
else
if [[ "$backup_location" = /* ]]; then
echo "Error: When a partition is mounted, backup_location must be relative."
exit 1
fi
backup_location="$(realpath "$mount_location/$backup_location")"
fi
backup_location="$backup_location/$(hostname)-$(date +%Y-%m-%d-%H-%M-%S).btrfs.gz"
echo "Creating /persist/user snapshot..."
btrfs -q subvolume snapshot -r "/persist/user" "/persist/user.bak"
echo "Creating backup at $backup_location..."
btrfs -q send "/persist/user.bak" > "$backup_location.tmp"
mv "$backup_location.tmp" "$backup_location"
echo "Backup completed successfully!"

View File

@@ -1,18 +0,0 @@
{ pkgs, ... }:
{
environment.systemPackages = [
(pkgs.writeShellApplication {
name = "backup";
runtimeInputs = with pkgs; [
btrfs-progs
coreutils
util-linux
];
text = builtins.readFile ./backup.sh;
})
];
home-manager.sharedModules = [
{ programs.zsh.initContent = builtins.readFile ./backup.completion.zsh; }
];
}

View File

@@ -0,0 +1,33 @@
{ ... }:
{
systemd.tmpfiles.rules = [
"d /persist/user.bak 0755 root root"
"d /persist/state.bak 0755 root root"
];
services.btrbk = {
ioSchedulingClass = "idle";
niceness = 19;
instances = {
persist-user = {
onCalendar = "hourly";
settings.volume."/persist" = {
subvolume = "user";
snapshot_dir = "user.bak";
snapshot_preserve_min = "latest";
snapshot_preserve = "48h 14d 4w 6m";
};
};
persist-state = {
onCalendar = "daily";
settings.volume."/persist" = {
subvolume = "state";
snapshot_dir = "state.bak";
snapshot_preserve_min = "latest";
snapshot_preserve = "7d 4w 3m";
};
};
};
};
}

View File

@@ -129,7 +129,10 @@ in
"directory"
];
default = "none";
description = "Whether to create the file or directory in persistence if it does not exist.";
description = ''
Whether to create the file or directory
in persistence if it does not exist.
'';
};
};
}

View File

@@ -13,11 +13,22 @@ mount "$DEVICE" /mnt/btrfs
if [[ -e /mnt/btrfs/@ ]]; then
mkdir -p /mnt/btrfs/@.bak
timestamp=$(date --date="@$(stat -c %Y /mnt/btrfs/@)" "+%Y-%m-%d_%H:%M:%S")
mv /mnt/btrfs/@ "/mnt/btrfs/@.bak/$timestamp"
timestamp=$(date --date="@$(stat -c %Y /mnt/btrfs/@)" "+%Y%m%dT%H%M")
base="@.$timestamp"
target="/mnt/btrfs/@.bak/$base"
if [[ -e "$target" ]]; then
i=1
while [[ -e "/mnt/btrfs/@.bak/${base}_$i" ]]; do
(( i++ ))
done
target="/mnt/btrfs/@.bak/${base}_$i"
fi
mv /mnt/btrfs/@ "$target"
fi
find /mnt/btrfs/@.bak/ -maxdepth 1 -mtime +14 | while IFS= read -r i; do
find /mnt/btrfs/@.bak/ -maxdepth 1 -mtime +7 | while IFS= read -r i; do
delete_subvolume_recursively "$i"
done

View File

@@ -8,10 +8,10 @@
./hardware
../common/configs/system/backup
../common/configs/system/bluetooth
../common/configs/system/boot
../common/configs/system/brightnessctl
../common/configs/system/btrbk
../common/configs/system/btrfs
../common/configs/system/cloudflared
../common/configs/system/cpu

View File

@@ -89,7 +89,7 @@ in
(import ./configs/gui/vscode { inherit user home; })
];
# echo "password" | mkpasswd -s
# mkpasswd -s
sops.secrets."${user}-password" = {
sopsFile = ../../../../secrets/sas/secrets.yaml;
key = "password";

View File

@@ -6,10 +6,10 @@
./hardware
../common/configs/system/backup
../common/configs/system/bluetooth
../common/configs/system/boot
../common/configs/system/brightnessctl
../common/configs/system/btrbk
../common/configs/system/btrfs
../common/configs/system/cpu
../common/configs/system/documentation

View File

@@ -89,7 +89,7 @@ in
(import ./configs/gui/vscode { inherit user home; })
];
# echo "password" | mkpasswd -s
# mkpasswd -s
sops.secrets."${user}-password" = {
sopsFile = ../../../../secrets/personal/secrets.yaml;
key = "password";

View File

@@ -37,7 +37,7 @@ in
(import ./configs/console/ssh { inherit user home; })
];
# echo "password" | mkpasswd -s
# mkpasswd -s
sops.secrets."${user}-password" = {
sopsFile = ../../../../secrets/personal/secrets.yaml;
key = "password";

View File

@@ -8,6 +8,7 @@
../common/configs/system/boot
../common/configs/system/brightnessctl
../common/configs/system/btrbk
../common/configs/system/btrfs
../common/configs/system/cpu
../common/configs/system/documentation

View File

@@ -35,7 +35,7 @@ in
(import ./configs/console/podman { inherit user home; })
];
# echo "password" | mkpasswd -s
# mkpasswd -s
sops.secrets."${user}-password" = {
sopsFile = ../../../../secrets/personal/secrets.yaml;
key = "password";

View File

@@ -19,7 +19,7 @@ in
(import ./configs/console/podman { inherit user home; })
];
# echo "password" | mkpasswd -s
# mkpasswd -s
sops.secrets."${user}-password" = {
sopsFile = ../../../../secrets/personal/secrets.yaml;
key = "password";