58 lines
3.5 KiB
Markdown
58 lines
3.5 KiB
Markdown
# Backup helpers
|
||
|
||
With the right tooling (I use `restic` for instance), taking backups is very easy, so is distributing them to multiple locations including cloud storage. It is so easy, that the main challenge for me is keeping track of them. Questions such as _Where can I find the most recent backup of **X**_ or even _Am I taking backups according to the schedule or is anything missing_ are more and more difficult to answer. It is supported by the fact that some storage locations aren't always online.
|
||
|
||
The goal of this project is to provide a collection of simple scripts to keep an offline list of that is backed up where, perform simple queries on the list and evaluate, whether it fulfills simple criteria (such as whether there is a recent enough backup of specified files). It is designed to keep the information in a simple format (actually JSON files scattered across a couple of directories) to be easily queryable and editable directly and so that it can easily be synchronized across multiple devices (Git, Syncthing, …). It deliberately doesn't provide any encryption; your backups should be protected by the actual backup software and the metadata gathered by these scripts are probably gonna be stored on your laptop or similar, so if it is breached, you have a much more urgent problem (like someone replacing you `gpg` binary with their shell script).
|
||
|
||
## Importing backups
|
||
|
||
The only currently implemented import mechanism is for `restic`. If you are brave enough however, you can write the files by hand. Every storage, that can hold some backups, is called a `repo` and has a configuration file in `repos/<repo-name>`. The configuration is needed only for the import, which then creates `backups/<repo-name>/<backup-id>` for each backup in the repository.
|
||
|
||
For `restic` repos, the config looks like
|
||
|
||
```json
|
||
{
|
||
"name": "<repo-name>",
|
||
"type": "restic",
|
||
"restic-path": "<What one passes to `-r` to restic>"
|
||
}
|
||
```
|
||
|
||
and you can import the backups with
|
||
|
||
```sh
|
||
./import.sh <repo-name>
|
||
```
|
||
|
||
**Make sure to always call the script with the root of this repository as your working directory**
|
||
|
||
## Declaring backup targets
|
||
|
||
The files/directories you want to back up are called `targets`. You configure each one of them by creating a file `targets/<target-name>`, where you list the source machine's hostname and the local path to the file/directory. Together it looks like
|
||
|
||
```json
|
||
{
|
||
"name": "<target-name>",
|
||
"hostname": "<hostname>",
|
||
"path": "<path>"
|
||
}
|
||
```
|
||
|
||
The `hostname` and `path` values do not necessarily have to be real, it is just something we match on the backups in repos to recognize what's what.
|
||
|
||
## Checking freshness
|
||
|
||
When we have all the metadata downloaded, we can evaluate whether they match our expectations. This can be done offline without access to the repositories and should be resource non-intensive in general.
|
||
|
||
We can define the rules in `check.sh` by appending them at the bottom of the file (between the markers in comments). If we then execute the checks with
|
||
|
||
```sh
|
||
./check.sh
|
||
```
|
||
|
||
it prints those that didn't pass. The return code is 0 on successful execution and all checks passing, 2 on successful execution but some checks non-passing and other exit codes signify a failure.
|
||
|
||
**Again make sure to always call the script with the root of this repository as your working directory**
|
||
|
||
The only currently implemented check is `isRecentInRepo <repo-name> <target-name> <maxAge>` where the first two arguments are the filenames of the corresponding configuration files and the last one is maximum age in whole seconds to still consider the backup to be fresh.
|