81 lines
4.9 KiB
Markdown
81 lines
4.9 KiB
Markdown
# zfs-pacman-hook
|
|
|
|
Arch Linux pacman hook for automatic ZFS snapshots
|
|
|
|
# Setup
|
|
|
|
Get started like so:
|
|
|
|
1. Install dependency `jq`
|
|
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
|
|
```
|
|
sudo ln -s <repo>/pacman-zfs-snapshot.sh /usr/local/bin/pacman-zfs-snapshot
|
|
sudo ln -s <repo>/pacman-zfs-snapshot-install.hook /usr/share/libalpm/hooks/pacman-zfs-snapshot-install.hook
|
|
sudo ln -s <repo>/pacman-zfs-snapshot-remove.hook /usr/share/libalpm/hooks/pacman-zfs-snapshot-remove.hook
|
|
sudo ln -s <repo>/pacman-zfs-snapshot-upgrade.hook /usr/share/libalpm/hooks/pacman-zfs-snapshot-upgrade.hook
|
|
sudo 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` files reference `/usr/local/bin/pacman-zfs-snapshot`. Change that accordingly if you need to.
|
|
1. For datasets you want auto-snapshotted add property `space.quico:auto-snapshot=true`
|
|
```
|
|
zfs set space.quico:auto-snapshot=true zpool/root/archlinux
|
|
```
|
|
With any other property and any other value datasets will not be auto-snapshotted.
|
|
1. Adjust `pacman-zfs-snapshot.conf` to your liking. You may want to set `do_dry_run='true'` for a start and just reinstall a benign package to get a feel for what this hook would do.
|
|
|
|
# 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|systemd|zfs-(dkms|utils))$` 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.
|
|
|
|
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.
|
|
|
|
Snapshots may look like so:
|
|
```
|
|
$ zfs list -o name -t all
|
|
NAME ┌─── Important because systemd
|
|
zpool snap_date_format='%F-%H%M' | is on our list of
|
|
zpool/root ▼ | important packages
|
|
zpool/root/archlinux ┌─────────────┐ ▼▼▼
|
|
zpool/root/archlinux@pacman_2023-03-07-0113_op:upgr_sev:imp_pkgs:systemd:bind:enchant:grep
|
|
zpool/root/archlinux@pacman_2023-03-07-0113_op:upgr_sev:trv_pkgs:jdk17-temurin
|
|
zpool/root/archlinux@pacman_2023-03-07-0115_op:upgr_sev:trv_pkgs:proton-ge-custom-bin
|
|
▲▲▲▲ ▲▲▲ └────────────────────────────┘
|
|
| | Max. 30 characters per our
|
|
Pacman operation that triggered this snapshot ───┘ | pacman-zfs-snapshot.conf
|
|
| setting 'pkgs_list_max_length'
|
|
Severity based on affected packages, here trivial ───────┘
|
|
```
|
|
|
|
Have a look at `pacman-zfs-snapshot.conf` as well, 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:
|
|
|
|
- `conf`: How we deal with script config
|
|
- `script`: Any other script work that doesn't specifically fall into the above scopes
|
|
- `hook`: Configuring the hook(s)
|
|
- `meta`: Affects the project's repo layout, readme content, file names etc.
|