feat(meta): Initial commit (#1)

This commit is contained in:
hygienic-books 2023-03-05 08:15:16 +01:00
parent 7ea829aacf
commit f7f6d71250
4 changed files with 127 additions and 1 deletions

View File

@ -1,3 +1,56 @@
# zfs-pacman-hook # zfs-pacman-hook
Arch Linux pacman hook for automatic snapshots Arch Linux pacman hook for automatic ZFS snapshots
# Setup
Get started like so:
1. Install dependency `zfs-auto-snapshot`
1. Clone repo into arbitrary path `<repo>`
1. Make `pacman-zfs-snapshot.sh` executable
```
chmod +x <repo>/pacman-zfs-snapshot.sh
```
1. Symlink to files, for example
```
ln -s <repo>/pacman-zfs-snapshot.sh /usr/local/bin/pacman-zfs-snapshot
ln -s <repo>/pacman-zfs-snapshot.hook /usr/share/libalpm/hooks/pacman-zfs-snapshot.hook
ln -s <repo>/pacman-zfs-snapshot.conf /etc/pacman-zfs-snapshot.conf
```
Note that while you may choose arbitrary locations for symlinks the `pacman-zfs-snapshot.hook` file references `/usr/local/bin/pacman-zfs-snapshot`. Change that accordingly if you need to.
1. Adjust `pacman-zfs-snapshot.conf` to your liking
# What's it do?
In `pacman` on every `PreTransaction`, meaning right before any actual operation on a package begins, we trigger a ZFS snapshot. By default we identify the active system dataset by doing `findmnt / --noheadings --output source`. If exactly one source returns that is the exact name of a ZFS dataset in an imported zpool we create a snapshot on it. If no source returns we silently exit. If more than one source returns we raise an error and halt the `pacman` transaction.
We retain two different snapshot chains, one for `pacman` transactions that only affect what we are calling _trivial_ packages and a separate chain for _important_ packages. By default only the exact regular expression package name match `^linux$` is considered important. Whenever an important package is affected by a transaction a snapshot goes into the corresponding chain. In all other cases - when an important package is not affected - snapshots go into the trivial chain
We use `zfs-auto-snapshot` both for snapshot creation and for destroying old snapshots. The _trivial_ snapshot chain by default keeps 15 snapshots, the _important_ chain keeps 5. The thought process here is that you will likely not futz around with a kernel every day whereas you may very well install arbitrary packages multiple times a day. Snapshots should keep you safe for a couple of days hence the defaults of 5 and 15 snapshots, respectively.
You may optionally include more ZFS datasets in this snapshot mechanism. Have a look at `pacman-zfs-snapshot.conf`, its comments should be clear enough to get you going.
# Development
## Conventional commits
This project uses [Conventional Commits](https://www.conventionalcommits.org/) for its commit messages.
### Commit types
Commit _types_ besides `fix` and `feat` are:
- `build`: Project structure, directory layout, build instructions for roll-out
- `refactor`: Keeping functionality while streamlining or otherwise improving function flow
- `test`: Working on test coverage
- `docs`: Documentation for project or components
### Commit scopes
The following _scopes_ are known for this project. A Conventional Commits commit message may optionally use one of the following scopes or none:
- `auto`: Change how `zfs-auto-snapshot` is run
- `conf`: How we deal with script config
- `script`: Any other script work that doesn't specifically fall into the above scopes
- `meta`: Affects the project's repo layout, readme content, file names etc.

12
pacman-zfs-snapshot.conf Normal file
View File

@ -0,0 +1,12 @@
# Pipe-separated list of kernel names. Will be matched against regular
# expression ^this_var_here$. Snapshots taken before a pacman transaction on
# an important package have a separate retention from snapshots for trivial
# packages. Lends itself to keeping kernel updates separate from everything
# else.
important_names='tmux'
snaps_trivial_keep='15'
snaps_important_keep='5'
snaps_trivial_suffix='trv'
snaps_important_suffix='imp'

14
pacman-zfs-snapshot.hook Normal file
View File

@ -0,0 +1,14 @@
[Trigger]
Operation = Install
Operation = Upgrade
Operation = Remove
Type = Package
Target = *
[Action]
Description = Create ZFS snapshot on active system dataset
When = PreTransaction
Exec = /bin/sh -c 'while read -r f; do echo "$f"; done | /usr/local/bin/pacman-zfs-snapshot'
Depends = zfs-auto-snapshot
AbortOnFail
NeedsTargets

47
pacman-zfs-snapshot.sh Executable file
View File

@ -0,0 +1,47 @@
#!/bin/bash
declare -a pkgs
while read pkg; do
pkgs+=("${pkg}")
done
declare conf_file
conf_file='/etc/pacman-zfs-snapshot.conf'
declare important_names snaps_trivial_keep snaps_important_keep snaps_trivial_suffix snaps_important_suffix
if [[ -r "${conf_file}" ]]; then
source "${conf_file}"
fi
if [[ ! "${important_names}" ]]; then important_names='linux'; fi
if [[ ! "${snaps_trivial_keep}" ]]; then snaps_trivial_keep='5'; fi
if [[ ! "${snaps_important_keep}" ]]; then snaps_important_keep='5'; fi
if [[ ! "${snaps_trivial_suffix}" ]]; then snaps_trivial_suffix='trv'; fi
if [[ ! "${snaps_important_suffix}" ]]; then snaps_important_suffix='imp'; fi
function split_pkgs_by_importance () {
local pkgs_in_transaction
pkgs_in_transaction=("${@}")
for pkg in "${pkgs_in_transaction[@]}"; do
if grep -Piq -- '^'"${important_names}"'$' <<<"${pkg}"; then
important_pkgs_in_transaction+=("${pkg}")
else
unimportant_pkgs_in_transaction+=("${pkg}")
fi
done
}
function main () {
local pkgs_in_transaction
pkgs_in_transaction=("${@}")
declare -a important_pkgs_in_transaction unimportant_pkgs_in_transaction
split_pkgs_by_importance "${pkgs_in_transaction[@]}"
#for pkg in "${!important_pkgs_in_transaction[@]}"; do
# printf -- 'Array item '"'"'%s'"'"' equals '"'"'%s'"'"'\n' "${pkg}" "${important_pkgs_in_transaction[${pkg}]}"
#done
}
main "${pkgs[@]}"