31 Commits

Author SHA1 Message Date
Erik Westrup
77b5a2c653 Update CHANGELOG.md 2022-04-11 21:09:18 +02:00
Erik Westrup
489046c603 Modified: README.md 2022-04-11 18:07:03 +02:00
Erik Westrup
6a43b95222 Fix systemd service OnFailure
Fixes #86
2022-04-11 17:48:00 +02:00
Erik Westrup
329fa40c30 Rename master branch to main 2022-04-05 08:28:16 +02:00
Matteo Mardegan
7c64d861ae correct the environtment file name 2022-03-22 09:27:26 +01:00
Erik Westrup
7ebeb00761 chmod a-x bin/*
The source files won't execute util after the build step. Remove
execution bit to not invite users to try to run these files.

Fixes #89
2022-02-27 22:14:21 +01:00
Erik Westrup
041d3374cc Fix service names in README.md
Fixes #88
2022-02-27 22:11:52 +01:00
Erik Westrup
5ed72bb87f Command for copy cron.d to crontab 2022-02-24 11:20:08 +01:00
Erik Westrup
9797543231 Update README.md 2022-02-24 05:50:10 +01:00
Erik Westrup
7e5496d00a Update README.md 2022-02-24 05:49:18 +01:00
Gerard Bosch
22d6af802f Update README: Metered connection check (#87)
* Update README: Metered connection check

Add a single command to copy and paste to install the metered connection
check.

* Reformat to be consistent with DIY style of optionals

Co-authored-by: Erik Westrup <erik.westrup@gmail.com>
2022-02-16 19:31:46 +01:00
Gerard Bosch
38b3243b4c Redirect stderr to systemd journal (#86)
Errors were not written to the journal as systemd-cat was only reading
stdin. Now, errors printed by restic are shown in the journal.
2022-02-16 13:51:28 +01:00
Erik Westrup
d5a141fc9a Modified: CHANGELOG.md 2022-02-16 12:23:59 +01:00
Erik Westrup
f4d1d6f1b2 chmod u+x bin/ to try execute scripts in build dir
before install step
2022-02-16 12:20:54 +01:00
Gerard Bosch
14f9741b82 Add docopt.sh option: DOCOPT_OPTIONS_FIRST=true
This will allow to use `resticw` as a true wrapper, enabling to pass
restic options through it, for example:

```
resticw --profile profileX snapshots --compact
```

will now be suported by the wraper :)
2022-02-16 12:19:44 +01:00
Gerard Bosch
43b718ea86 Fix README/resticw commands (#84)
* Fix README/resticw commands

As per restic 0.12.1, the special snapshot ID `latest` is not supported by `diff` command.

* Update `resticw diff` description
2022-02-16 10:14:01 +01:00
Erik Westrup
ef059ebd68 Update macOS notifier examples URL 2022-02-16 09:39:38 +01:00
Gerard Bosch
de1b851d3d Update README/Metered Connections (#83) 2022-02-15 19:30:08 +01:00
Erik Westrup
b00ae89812 Add desktop notification screenshot 2022-02-15 19:19:46 +01:00
Erik Westrup
2c14351cd4 Document desktop notifications in README 2022-02-15 18:38:14 +01:00
Erik Westrup
cfbc6c6c51 Merge pull request #82 from gerardbosch/patch-1
Minor fix on README
2022-02-15 18:24:14 +01:00
Gerard Bosch
e8a2647cae Minor fix on README 2022-02-15 18:22:45 +01:00
Erik Westrup
4952cc3ee1 Modified: CHANGELOG.md 2022-02-15 17:49:11 +01:00
Erik Westrup
3ecc3c3510 Consistent default values 2022-02-15 17:47:51 +01:00
Erik Westrup
65172e650b Merge pull request #76 from gerardbosch/feature/desktop-notifications
Add optional desktop notifications
2022-02-15 17:45:07 +01:00
Gerard Bosch
705248ee00 Final cleanup 2022-02-15 16:06:19 +01:00
Gerard Bosch
be2c3163a8 Rework notification data fetching: Use stats+diff 2022-02-15 13:50:10 +01:00
Erik Westrup
84e083c62e Modified: README.md 2022-02-15 12:46:27 +01:00
Gerard Bosch
7dde85f25e Reformat 2022-02-12 10:02:03 +01:00
Gerard Bosch
9ebc9ea641 Replace 'here string' syntax with echo + pipe 2022-02-12 08:47:09 +01:00
Gerard Bosch
3f000ce137 Add optional desktop notifications
When backing up a desktop system it is handy to have regular and
immediate feedback about backups. This features a notification of backup
stats summary, including the added size to the repository, so you can
have a quick follow-up about what are you uploading to the repository.

This may be very useful if you upload by accident a big file or directory
which should be in your exclusions, so it warns you and gives the chance
to fix the exclusions and remove the undesired snapshot later.
2022-02-09 18:19:48 +01:00
10 changed files with 117 additions and 32 deletions

View File

@@ -3,13 +3,13 @@ name: Lint Code Base
on:
workflow_dispatch:
push:
branches: master
branches: main
paths:
- '**.sh'
- '.github/workflows/linter.yml'
- 'bin/**'
pull_request:
branches: master
branches: main
paths:
- '**.sh'
- '.github/workflows/linter.yml'
@@ -29,5 +29,5 @@ jobs:
env:
VALIDATE_ALL_CODEBASE: true
VALIDATE_BASH: true
DEFAULT_BRANCH: master
DEFAULT_BRANCH: main
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -6,9 +6,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [7.3.2] - 2022-04-11
### Fixed
- Trying to fix broken Homebrew bottles
## [7.3.1] - 2022-04-11
### Fixed
- `resticw` is now a true wrapper in that it support `--` args to restic.
- OnFailure no longer masked by the stderr redirect to systemd-cat. [#86](https://github.com/erikw/restic-automatic-backup-scheduler/pull/86)
## [7.3.0] - 2022-02-15
### Added
- optional user-controlled notification. See `RESTIC_NOTIFY_BACKUP_STATS` and in `backup.sh`.
## [7.2.0] - 2022-02-15
### Added
- restic-check launchagent.
- restic-check LaunchAgent.
### Changed
- [README.md](README.md) is restructured with easier TL;DR for each OS and a more general detailed section for the interested.

View File

@@ -76,7 +76,7 @@ Many Linux distributions nowadays use [Systemd](https://en.wikipedia.org/wiki/Sy
```
1. Fill out [configuration values](#2-configure-b2-credentials-locally) in `/etc/restic`.
1. [Initialize](#3-initialize-remote-repo) the remote repo.
Source the profile to make all needed configuration available to `restic`. All commands after this assumes the profile is sourced in the current shell.
Source the profile to make all needed configuration available to `restic(1)`. All commands after this assumes the profile is sourced in the current shell.
```console
# source /etc/restic/default.env.sh
# restic init
@@ -126,7 +126,7 @@ Many Linux distributions nowadays use [Systemd](https://en.wikipedia.org/wiki/Sy
```
1. Fill out [configuration values](#2-configure-b2-credentials-locally) in `/usr/local/etc/restic`.
1. [Initialize](#3-initialize-remote-repo) the remote repo.
Source the profile to make all needed configuration available to `restic`. All commands after this assumes the profile is sourced in the current shell.
Source the profile to make all needed configuration available to `restic(1)`. All commands after this assumes the profile is sourced in the current shell.
```console
$ source /usr/local/etc/restic/default.env.sh
$ restic init
@@ -226,7 +226,7 @@ I describe here one of may ways you can get restic and this backup script workin
export RESTIC_BACKUP_PATHS='/c/Users/<username>/My Documents'
```
1. [Initialize](#3-initialize-remote-repo) the remote repo.
Source the profile to make all needed configuration available to `restic`. All commands after this assumes the profile is sourced in the current shell.
Source the profile to make all needed configuration available to `restic(1)`. All commands after this assumes the profile is sourced in the current shell.
```console
git-bash$ source /etc/restic/default.env.sh
git-bash$ restic init
@@ -268,9 +268,12 @@ Any system that has a cron-like system can easily setup restic backups as well.
$ sudo make install-cron
```
* This assumes that your cron supports dropping files into `/etc/cron.d/`. If that is not the case, simply copy the relevant contents of the installed `/etc/cron.d/restic` in to your `/etc/crontab`.
```console
# grep "^@.*restic_" /etc/cron.d/restic >> /etc/crontab
```
1. Fill out [configuration values](#2-configure-b2-credentials-locally) in `/etc/restic`.
1. [Initialize](#3-initialize-remote-repo) the remote repo.
Source the profile to make all needed configuration available to `restic`. All commands after this assumes the profile is sourced in the current shell.
Source the profile to make all needed configuration available to `restic(1)`. All commands after this assumes the profile is sourced in the current shell.
```console
# source /etc/restic/default.env.sh
# restic init
@@ -435,6 +438,33 @@ To create a different backup and use you can do:
# restic_backup.sh
```
### Optional: Desktop Notifications
<img src="img/macos_notification.png" align="right" />
It's a good idea to be on top of your backups to make sure that they don't increase a lot in size and incur high costs. However it's notoriously tricky to make GUI notifications correctly from a non-user process (e.g. root).
Therefore this project provides a lightweight solution for desktop notifications that works like this: Basically `restic_backup.sh` will append a summary line of the last backup to a user-owned file (the user running your OS's desktop environment) in a fire-and-forget fashion. Then the user has a process that reads this and forward each line as a new message to the desktop environment in use.
To set desktop notifications up:
1. Create a special FIFO file as your desktop user:
```console
$ mkfifo /home/user/.cache/notification-queue
```
1. In your profile, e.g. `/etc/restic/default.sh`, set:
```bash
RESTIC_NOTIFY_BACKUP_STATS=true
RESTIC_BACKUP_NOTIFICATION_FILE=/home/user/.cache/notification-queue
```
1. Create a listener on the notification queue file that forwards to desktop notifications
* Linux auto start + cross-platform notifier / notify-send
* [notification-queue-notifier](https://github.com/gerardbosch/dotfiles/blob/ddc1491056822eab45dedd131f1946308ef62135/home/bin/notification-queue-notifier)
* [notification-queue.desktop](https://github.com/gerardbosch/dotfiles-linux/blob/ea0f75bfd7a356945544ecaa42a2fc35c9fab3a1/home/.config/autostart/notification-queue.desktop)
* macOS auto start + [terminal-notifier](https://github.com/julienXX/terminal-notifier)
* [notification-queue-notifier.sh](https://github.com/erikw/dotfiles/blob/8a942defe268292200b614951cdf433ddccf7170/bin/notification-queue-notifier.sh)
* [com.user.notificationqueue.plist](https://github.com/erikw/dotfiles/blob/8a942defe268292200b614951cdf433ddccf7170/.config/LaunchAgents/com.user.notificationqueue.plist)
### Optional: Email Notification on Failure
#### Systemd
We want to be aware when the automatic backup fails, so we can fix it. Since my laptop does not run a mail server, I went for a solution to set up my laptop to be able to send emails with [postfix via my Gmail](https://easyengine.io/tutorials/linux/ubuntu-postfix-gmail-smtp/). Follow the instructions over there.
@@ -445,7 +475,7 @@ Put this file in `/bin`:
Put this files in `/etc/systemd/system/`:
* `status-email-user@.service`: A service that can notify you via email when a systemd service fails. Edit the target email address in this file.
Now edit `restic-backup.service` and `status-email-user.service` to call this service failure.
Now edit `restic-backup@.service` and `status-email-user@.service` to call this service failure.
```
OnFailure=status-email-user@%n.service
```
@@ -459,18 +489,31 @@ To use this, wrap the restic script command with it in your cron file like:
```
### Optional: No Backup on Metered Connections
### Optional: No Backup on Metered Connections (Linux/systemd only)
For a laptop, it can make sense to not do heavy backups when your on a metered connection like a shared connection from you mobile phone. To solve this we can set up a systemd service that is in success state only when a connection is unmetered. Then we can tell our backup service to depend on this service simply! When the unmetered service detects an unmetered connection it will go to failed state. Then our backup service will not run as it requires this other service to be in success state.
Put this file in `/bin`:
* `nm-unmetered-connection.sh`: Detects metered connections and returns will error code if one is detected. This scripts requires the Gnome [NetworkManager](https://wiki.gnome.org/Projects/NetworkManager) to be installed. Modify this script if your system has a different network manager.
1. Edit `restic-backup@.service` and `restic-check@.service` to require the new service to be in success state:
```
Requires=nm-unmetered-connection.service
```
1. Copy and paste the command below, it will install the following files and refresh systemd daemon:
1. Put this file in `/etc/systemd/system/`:
* `nm-unmetered-connection.service`: A service that is in success state only if the connection is unmetered.
1. Install this file in `/bin`:
* `nm-unmetered-connection.sh`: Detects metered connections and returns an error code if one is detected. This scripts requires the Gnome [NetworkManager](https://wiki.gnome.org/Projects/NetworkManager) to be installed (modify this script if your system has a different network manager).
1. Reload systemd with
```console
# systemctl daemon-reload
```
Put this files in `/etc/systemd/system/`:
* `nm-unmetered-connection.service`: A service that is in success state if the connection is unmetered only.
Now edit `restic-backup.service` and `status-email-user.service` to require the new service to be in success state:
```
Requires=nm-unmetered-connection.service
☝ **Tip**: All steps but the first can be done in one go if you use the Makefile. Set `$PREFIX` as needed or leave empty for install to `/`.
```bash
sudo bash -c 'export PREFIX=
make build/usr/lib/systemd/system/nm-unmetered-connection.service
install -m 0644 build/usr/lib/systemd/system/nm-unmetered-connection.service $PREFIX/etc/systemd/system
install -m 0555 bin/nm-unmetered-connection.sh /bin
systemctl daemon-reload
'
```
### Optional: Restic Wrapper Script
@@ -484,8 +527,8 @@ Useful commands:
| Command | Description |
|---------------------------------------------------|-------------------------------------------------------------------|
| `resticw snapshots` | List backup snapshots |
| `resticw diff <snapshot-id> latest` | Show the changes from the latest backup |
| `resticw stats` / `resticw stats snapshot-id ...` | Show the statistics for the whole repo or the specified snapshots |
| `resticw diff <snapshotId-1> <snapshotId-2>` | Show the changes between backup snapshots |
| `resticw stats` / `resticw stats snapshotId ...` | Show the statistics for the whole repo or the specified snapshots |
| `resticw mount /mnt/restic` | Mount your remote repository |
@@ -516,5 +559,7 @@ To make a new release:
$ git tag vX.Y.Z
$ git push && git push --tags
```
1. Update version in the AUR [PKGBUILD](https://aur.archlinux.org/packages/restic-automatic-backup-scheduler/).
1. Update version in the Homebrew [Formula](https://github.com/erikw/homebrew-tap/blob/main/Formula/restic-automatic-backup-scheduler.rb).
1. Update version in the AUR [PKGBUILD](https://aur.archlinux.org/packages/restic-automatic-backup-scheduler/)
1. Update version in the Homebrew Formulas (see the repo README):
* [restic-automatic-backup-scheduler](https://github.com/erikw/homebrew-tap/blob/main/Formula/restic-automatic-backup-scheduler.rb)
* [restic-automatic-backup-scheduler-check](https://github.com/erikw/homebrew-tap/blob/main/Formula/restic-automatic-backup-scheduler-check.rb)

View File

@@ -105,3 +105,23 @@ wait $!
#wait $!
echo "Backup & cleaning is done."
# (optionally) Notify about backup summary stats.
if [ "$RESTIC_NOTIFY_BACKUP_STATS" = true ]; then
if [ -w "$RESTIC_BACKUP_NOTIFICATION_FILE" ]; then
echo 'Notifications are enabled: Silently computing backup summary stats...'
snapshot_size=$(restic stats latest --tag "$RESTIC_BACKUP_TAG" | grep -i 'total size:' | cut -d ':' -f2 | xargs) # xargs acts as trim
latest_snapshot_diff=$(restic snapshots --tag "$RESTIC_BACKUP_TAG" --latest 2 --compact \
| grep -Ei "^[abcdef0-9]{8} " \
| awk '{print $1}' \
| tr '\n' ' ' \
| xargs restic diff)
added=$(echo "$latest_snapshot_diff" | grep -i 'added:' | awk '{print $2 " " $3}')
removed=$(echo "$latest_snapshot_diff" | grep -i 'removed:' | awk '{print $2 " " $3}')
echo "Added: ${added}. Removed: ${removed}. Snap size: ${snapshot_size}" >> "$RESTIC_BACKUP_NOTIFICATION_FILE"
else
echo "[WARN] Couldn't write the backup summary stats. File not found or not writable: ${RESTIC_BACKUP_NOTIFICATION_FILE}"
fi
fi

View File

@@ -116,8 +116,9 @@ else eval "${prefix}"'_restic_arguments_line_=()'; fi; local docopt_i=1
declare -p "${prefix}__profile" "${prefix}_restic_arguments_line_"; done; }
# docopt parser above, complete command for generating this parser is `docopt.sh resticw`
# Parse arguments
eval "$(docopt "$@")" # See https://github.com/andsens/docopt.sh for the magic :)
# Parse arguments - See https://github.com/andsens/docopt.sh for the magic :)
DOCOPT_OPTIONS_FIRST=true # treat everything after the first non-option as commands/arguments
eval "$(docopt "$@")"
# --^^^-- END OF GENERATED COMMAND LINE PARSING STUFF --^^^--
#

View File

@@ -5,9 +5,9 @@ PATH=/etc:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin/:$INSTALL_PREFIX/bin/
# Reference: https://www.freebsd.org/doc/handbook/configtuning-cron.html
# Reference: crontab(5).
@midnight root . $INSTALL_PREFIX/etc/restic/default.sh && restic_backup.sh
@monthly root . $INSTALL_PREFIX/etc/restic/default.sh && restic_check.sh
@midnight root . $INSTALL_PREFIX/etc/restic/default.env.sh && restic_backup.sh
@monthly root . $INSTALL_PREFIX/etc/restic/default.env.sh && restic_check.sh
# Email notification version. Make sure bin/cron_mail is in the above $PATH
#@midnight root . $INSTALL_PREFIX/etc/restic/default.sh && cron_mail restic_backup.sh
#@monthly root . $INSTALL_PREFIX/etc/restic/default.sh && cron_mail restic_check.sh
#@midnight root . $INSTALL_PREFIX/etc/restic/default.env.sh && cron_mail restic_backup.sh
#@monthly root . $INSTALL_PREFIX/etc/restic/default.env.sh && cron_mail restic_check.sh

View File

@@ -29,3 +29,7 @@ export RESTIC_BACKUP_EXTRA_ARGS=
# Verbosity level from 0-3. 0 means no --verbose.
# Override this value in a profile if needed.
export RESTIC_VERBOSITY_LEVEL=0
# (optional) Desktop notifications. See restic_backup.sh for details on how to set this up.
export RESTIC_NOTIFY_BACKUP_STATS=false
export RESTIC_BACKUP_NOTIFICATION_FILE=

BIN
img/macos_notification.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View File

@@ -10,6 +10,7 @@ Type=simple
Nice=10
# $HOME or $XDG_CACHE_HOME must be set for restic to find /root/.cache/restic/
Environment="HOME=/root"
# The random sleep (in seconds) is in the case of multiple backup profiles. Many restic instances started at the same time could case high load or network bandwith usage.
# pipefail: so that redirecting stderr from the script to systemd-cat does not hide the failed command from OnFailure above.
# Random sleep (in seconds): in the case of multiple backup profiles. Many restic instances started at the same time could case high load or network bandwith usage.
# `systemd-cat` allows showing the restic output to the systemd journal
ExecStart=bash -c 'ps cax | grep -q restic && sleep $(shuf -i 0-300 -n 1); source $INSTALL_PREFIX/etc/restic/%I.env.sh && $INSTALL_PREFIX/bin/restic_backup.sh | systemd-cat'
ExecStart=bash -c 'set -o pipefail; ps cax | grep -q restic && sleep $(shuf -i 0-300 -n 1); source $INSTALL_PREFIX/etc/restic/%I.env.sh && $INSTALL_PREFIX/bin/restic_backup.sh 2>&1 | systemd-cat'

View File

@@ -9,5 +9,6 @@ Conflicts=restic-backup.service
[Service]
Type=simple
Nice=10
# `systemd-cat` allows showing the restic output to the systemd journal
ExecStart=bash -c 'source $INSTALL_PREFIX/etc/restic/%I.env.sh && $INSTALL_PREFIX/bin/restic_check.sh | systemd-cat'
# pipefail: so that redirecting stderr from the script to systemd-cat does not hide the failed command from OnFailure above.
# `systemd-cat`: allows showing the restic output to the systemd journal
ExecStart=bash -c 'set -o pipefail; source $INSTALL_PREFIX/etc/restic/%I.env.sh && $INSTALL_PREFIX/bin/restic_check.sh 2>&1 | systemd-cat'