Initial commit

This commit is contained in:
Manuel 2022-10-15 21:05:53 +02:00
commit 104a8b8cfb
Signed by: Manuel
GPG key ID: 4085037435E1F07A
6 changed files with 162 additions and 0 deletions

21
LICENSE.txt Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 SunRed
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

39
README.md Normal file
View file

@ -0,0 +1,39 @@
# Incremental sync-snap with cleanup
These are simple scripts I use for incrementally backuping my system running on btrfs whenever I connect my USB drive to my computer(s).
One could of course also simply use other tools like [btrbk](https://github.com/digint/btrbk) to automatically backup/replicate btrfs snapshots. One would just have to change the commands used to `btrbk run` and let btrbk itself handle the cleanup locally and on the external drive.
For a desktop system I still like to be able to manually snapshot or cleanup using [snapper-gui](https://github.com/ricardomv/snapper-gui) and since snap-sync does not automatically prune old snapshots, we need [a simple cleanup script](https://gist.github.com/alanorth/fdaa3f3be16b58822a4a876afbd62604/) that runs after the snap-sync replication.
Based on this it's also possible to use a network target to simply replicate snapshots onto a NAS or similar.
## Config
You should have a subvolume present already on your backup drive using something like `snap-sync -c "root home" -d "latest incremental backup"` pointing to `snapshot_root` configured in [clean-snap-sync-external.sh](scripts/clean-snap-sync-external.sh). After first replication snap-sync automatically uses the same subvolume again so that you just have to set the UUID of your external drive you placed your initial snapshot on in the bash scripts in the [scripts](scripts) folder.
If you are going to enable `snap-sync-cleanup.service`, edit the snapshot root and the amount of snapshots to keep on the external drive in `clean-snap-sync-external.sh` as well.
Edit both services in the [services](services) folder and edit the path to the scripts. In my case I just keep them on the external drive my replicated snapshots reside on.
You _also_ have to edit the `.mount` target in all service files to point to your usb drive.
You can get the correct mount target by running `systemctl list-units -t mount`.
## Install
Place the services in the [services](services) folder in `/etc/systemd/system/`, run `systemctl daemon-reload` and enable each of them:
`snap-sync.service` for backuping a new snapshot onto your disk
`snap-sync-cleanup.service` for deleting any snapshots older than the amount you've configured (only runs if `snap-sync.service` succeeded)
The next time you connect your external drive a snap-sync notification should pop up, starting the replication process.
<br>
***
### TODO
* Proper config file
* setup script
* AUR package?

View file

@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -e
readonly backup_uuid="b8f49636-2681-4c28-911e-63c63f16dbc8"
snap-sync --UUID $backup_uuid -c "root home" -d "latest incremental backup" -n

View file

@ -0,0 +1,72 @@
#!/usr/bin/env bash
#
# clean-snap-sync-external.sh v1.0.1 (2021-07-09)
#
# Changes
# -------
# 2021-07-09:
# - adjust logic to keep latest x, instead of delete oldest x
# - make output cleaner (hide btrfs subvolume delete output)
#
# Inspired by FraYoshi's original
# See: https://github.com/wesbarnett/snap-sync/issues/16
# Change these for your environment
readonly backup_uuid="b8f49636-2681-4c28-911e-63c63f16dbc8"
readonly snapshot_root="$(findmnt -rn -S UUID=$backup_uuid -o TARGET)/snapshots/$(hostname)"
readonly keep_latest=3
# Don't change these
readonly ansi_default="\e[39m"
readonly ansi_green="\e[32m"
readonly ansi_yellow="\e[33m"
echo -e "$ansi_green[DEBUG] Keeping the latest $keep_latest snapshots on $snapshot_root.$ansi_default"
# Use printf to get the filename without the path
find /etc/snapper/configs -mindepth 1 -maxdepth 1 -printf "%f\n" | while read config; do
echo -e " $ansi_green[DEBUG] Checking $snapshot_root/$config$ansi_default"
# Make sure the total number of snapshots is more than $keep_latest
if [ $(find "$snapshot_root/$config" -mindepth 1 -maxdepth 1 -type d | wc -l) -gt $keep_latest ]; then
# Find all snapshots for the current config, sort by snapshot number, and
# get the oldest. Note that I would prefer to do this:
#
# for snapshot in $(ls -1td /mnt/backup/root/*); do
#
# ... but parsing ls is apparently frowned upon. I will settle on using find
# and sorting numerically, since snapshot numbers should be integers.
#
# See: http://mywiki.wooledge.org/ParsingLs
#
# Again, we rely on printf to get the snapshot number without the path,
# then we sort the snapshot numbers in reverse numerical order, ie:
#
# 6601 (snapshot 1)
# 6600 (snapshot 2)
# 6599 (snapshot 3)
#
# Then we use `tail -n +` with $keep_latest + 1 to skip that many snap-
# shots, as tail's `-n +` syntax starts at line 1.
find "$snapshot_root/$config" -mindepth 1 -maxdepth 1 -type d -printf "%f\n" | sort -nr | tail -n +$(expr $keep_latest + 1) | while read snapnum; do
echo -e " $ansi_green[DEBUG] Found $snapshot_root/$config/$snapnum$ansi_default"
# Make sure this is not the latest incremental backup. grep will return
# with a non-zero exit status if there is *no match*, so we continue to
# delete matching snapshots if this command fails.
if ! snapper -c "$config" list --columns number,description | grep -E "^$snapnum" | grep 'latest incremental backup' >/dev/null; then
# Delete the snapshot itself
echo -e " $ansi_yellow[INFO] Deleting $snapshot_root/$config/$snapnum$ansi_default"
btrfs subvolume delete "$snapshot_root/$config/$snapnum/snapshot" >/dev/null
# Delete the snapper snapshot root (ie, where info.xml lives)
# SC2115: Use "${var:?}" to ensure this never expands to / .
rm -r "${snapshot_root:?}/$config/$snapnum"
else
echo -e " $ansi_green[DEBUG] Not deleting $snapshot_root/$config/$snapnum because it is the latest incremental backup.$ansi_default"
fi
done
else
echo -e " $ansi_green[DEBUG] Number of snapshots in $snapshot_root/$config should be more than $keep_latest.$ansi_default"
fi
done

View file

@ -0,0 +1,12 @@
[Unit]
Description=Run snap-sync cleanup
Requires=run-media-usbdrive.mount
After=run-media-usbdrive.mount snap-sync.service
[Service]
Environment=TZ=UTC
Type=oneshot
ExecStart=/run/media/manuel/T7/snapshots/scripts/clean-snap-sync-external.sh
[Install]
WantedBy=snap-sync.service

View file

@ -0,0 +1,12 @@
[Unit]
Description=Run snap-sync backup
Requires=run-media-usbdrive.mount
After=run-media-usbdrive.mount
[Service]
Environment=TZ=UTC
Type=oneshot
ExecStart=/run/media/manuel/T7/snapshots/scripts/backup-snap-sync-incremental.sh
[Install]
WantedBy=run-media-usbdrive.mount