forked from borgmatic-collective/borgmatic
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
b63c854509 | |||
aa013af25e | |||
cc32f0018b | |||
dfc4db1860 | |||
35706604ea | |||
6d76e8e5cb | |||
aecb6fcd74 | |||
ea45f6c4c8 | |||
97b5cd089d | |||
f2c2f3139e | |||
dc4e7093e5 |
5
NEWS
5
NEWS
|
@ -1,3 +1,8 @@
|
||||||
|
1.6.4.dev0
|
||||||
|
* #546, #382: Keep your repository passphrases and database passwords outside of borgmatic's
|
||||||
|
configuration file with environment variable interpolation. See the documentation for more
|
||||||
|
information: https://torsion.org/borgmatic/docs/how-to/provide-your-passwords/
|
||||||
|
|
||||||
1.6.3
|
1.6.3
|
||||||
* #541: Add "borgmatic list --find" flag for searching for files across multiple archives, useful
|
* #541: Add "borgmatic list --find" flag for searching for files across multiple archives, useful
|
||||||
for hunting down that file you accidentally deleted so you can extract it. See the documentation
|
for hunting down that file you accidentally deleted so you can extract it. See the documentation
|
||||||
|
|
|
@ -188,6 +188,12 @@ def make_parsers():
|
||||||
action='extend',
|
action='extend',
|
||||||
help='One or more configuration file options to override with specified values',
|
help='One or more configuration file options to override with specified values',
|
||||||
)
|
)
|
||||||
|
global_group.add_argument(
|
||||||
|
'--no-environment-interpolation',
|
||||||
|
dest='resolve_env',
|
||||||
|
action='store_false',
|
||||||
|
help='Do not resolve environment variables in configuration file',
|
||||||
|
)
|
||||||
global_group.add_argument(
|
global_group.add_argument(
|
||||||
'--bash-completion',
|
'--bash-completion',
|
||||||
default=False,
|
default=False,
|
||||||
|
|
|
@ -650,7 +650,7 @@ def run_actions(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def load_configurations(config_filenames, overrides=None):
|
def load_configurations(config_filenames, overrides=None, resolve_env=True):
|
||||||
'''
|
'''
|
||||||
Given a sequence of configuration filenames, load and validate each configuration file. Return
|
Given a sequence of configuration filenames, load and validate each configuration file. Return
|
||||||
the results as a tuple of: dict of configuration filename to corresponding parsed configuration,
|
the results as a tuple of: dict of configuration filename to corresponding parsed configuration,
|
||||||
|
@ -664,7 +664,7 @@ def load_configurations(config_filenames, overrides=None):
|
||||||
for config_filename in config_filenames:
|
for config_filename in config_filenames:
|
||||||
try:
|
try:
|
||||||
configs[config_filename] = validate.parse_configuration(
|
configs[config_filename] = validate.parse_configuration(
|
||||||
config_filename, validate.schema_filename(), overrides
|
config_filename, validate.schema_filename(), overrides, resolve_env
|
||||||
)
|
)
|
||||||
except PermissionError:
|
except PermissionError:
|
||||||
logs.extend(
|
logs.extend(
|
||||||
|
@ -892,7 +892,9 @@ def main(): # pragma: no cover
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
config_filenames = tuple(collect.collect_config_filenames(global_arguments.config_paths))
|
config_filenames = tuple(collect.collect_config_filenames(global_arguments.config_paths))
|
||||||
configs, parse_logs = load_configurations(config_filenames, global_arguments.overrides)
|
configs, parse_logs = load_configurations(
|
||||||
|
config_filenames, global_arguments.overrides, global_arguments.resolve_env
|
||||||
|
)
|
||||||
|
|
||||||
any_json_flags = any(
|
any_json_flags = any(
|
||||||
getattr(sub_arguments, 'json', False) for sub_arguments in arguments.values()
|
getattr(sub_arguments, 'json', False) for sub_arguments in arguments.values()
|
||||||
|
|
40
borgmatic/config/environment.py
Normal file
40
borgmatic/config/environment.py
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
_VARIABLE_PATTERN = re.compile(r'(?P<escape>\\)?(?P<variable>\$\{(?P<name>[A-Za-z0-9_]+)((:?-)(?P<default>[^}]+))?\})')
|
||||||
|
|
||||||
|
|
||||||
|
def _resolve_string(matcher):
|
||||||
|
'''
|
||||||
|
Get the value from environment given a matcher containing a name and an optional default value.
|
||||||
|
If the variable is not defined in environment and no default value is provided, an Error is raised.
|
||||||
|
'''
|
||||||
|
if matcher.group('escape') is not None:
|
||||||
|
# in case of escaped envvar, unescape it
|
||||||
|
return matcher.group('variable')
|
||||||
|
# resolve the env var
|
||||||
|
name, default = matcher.group('name'), matcher.group('default')
|
||||||
|
out = os.getenv(name, default=default)
|
||||||
|
if out is None:
|
||||||
|
raise ValueError('Cannot find variable ${name} in environment'.format(name=name))
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_env_variables(item):
|
||||||
|
'''
|
||||||
|
Resolves variables like or ${FOO} from given configuration with values from process environment
|
||||||
|
Supported formats:
|
||||||
|
- ${FOO} will return FOO env variable
|
||||||
|
- ${FOO-bar} or ${FOO:-bar} will return FOO env variable if it exists, else "bar"
|
||||||
|
|
||||||
|
If any variable is missing in environment and no default value is provided, an Error is raised.
|
||||||
|
'''
|
||||||
|
if isinstance(item, str):
|
||||||
|
return _VARIABLE_PATTERN.sub(_resolve_string, item)
|
||||||
|
if isinstance(item, list):
|
||||||
|
for i, subitem in enumerate(item):
|
||||||
|
item[i] = resolve_env_variables(subitem)
|
||||||
|
if isinstance(item, dict):
|
||||||
|
for key, value in item.items():
|
||||||
|
item[key] = resolve_env_variables(value)
|
||||||
|
return item
|
|
@ -908,13 +908,13 @@ properties:
|
||||||
topic:
|
topic:
|
||||||
type: string
|
type: string
|
||||||
description: |
|
description: |
|
||||||
The topic to publish to
|
The topic to publish to.
|
||||||
(https://ntfy.sh/docs/publish/)
|
(https://ntfy.sh/docs/publish/)
|
||||||
example: topic
|
example: topic
|
||||||
server:
|
server:
|
||||||
type: string
|
type: string
|
||||||
description: |
|
description: |
|
||||||
The address of your self-hosted ntfy.sh installation
|
The address of your self-hosted ntfy.sh instance.
|
||||||
example: https://ntfy.your-domain.com
|
example: https://ntfy.your-domain.com
|
||||||
start:
|
start:
|
||||||
type: object
|
type: object
|
||||||
|
@ -927,17 +927,17 @@ properties:
|
||||||
message:
|
message:
|
||||||
type: string
|
type: string
|
||||||
description: |
|
description: |
|
||||||
The message body to publish
|
The message body to publish.
|
||||||
example: Your backups have failed.
|
example: Your backups have failed.
|
||||||
priority:
|
priority:
|
||||||
type: string
|
type: string
|
||||||
description: |
|
description: |
|
||||||
The priority to set
|
The priority to set.
|
||||||
example: urgent
|
example: urgent
|
||||||
tags:
|
tags:
|
||||||
type: string
|
type: string
|
||||||
description: |
|
description: |
|
||||||
Tags to attach to the message
|
Tags to attach to the message.
|
||||||
example: incoming_envelope
|
example: incoming_envelope
|
||||||
finish:
|
finish:
|
||||||
type: object
|
type: object
|
||||||
|
@ -945,22 +945,22 @@ properties:
|
||||||
title:
|
title:
|
||||||
type: string
|
type: string
|
||||||
description: |
|
description: |
|
||||||
The title of the message
|
The title of the message.
|
||||||
example: Ping!
|
example: Ping!
|
||||||
message:
|
message:
|
||||||
type: string
|
type: string
|
||||||
description: |
|
description: |
|
||||||
The message body to publish
|
The message body to publish.
|
||||||
example: Your backups have failed.
|
example: Your backups have failed.
|
||||||
priority:
|
priority:
|
||||||
type: string
|
type: string
|
||||||
description: |
|
description: |
|
||||||
The priority to set
|
The priority to set.
|
||||||
example: urgent
|
example: urgent
|
||||||
tags:
|
tags:
|
||||||
type: string
|
type: string
|
||||||
description: |
|
description: |
|
||||||
Tags to attach to the message
|
Tags to attach to the message.
|
||||||
example: incoming_envelope
|
example: incoming_envelope
|
||||||
fail:
|
fail:
|
||||||
type: object
|
type: object
|
||||||
|
@ -968,22 +968,22 @@ properties:
|
||||||
title:
|
title:
|
||||||
type: string
|
type: string
|
||||||
description: |
|
description: |
|
||||||
The title of the message
|
The title of the message.
|
||||||
example: Ping!
|
example: Ping!
|
||||||
message:
|
message:
|
||||||
type: string
|
type: string
|
||||||
description: |
|
description: |
|
||||||
The message body to publish
|
The message body to publish.
|
||||||
example: Your backups have failed.
|
example: Your backups have failed.
|
||||||
priority:
|
priority:
|
||||||
type: string
|
type: string
|
||||||
description: |
|
description: |
|
||||||
The priority to set
|
The priority to set.
|
||||||
example: urgent
|
example: urgent
|
||||||
tags:
|
tags:
|
||||||
type: string
|
type: string
|
||||||
description: |
|
description: |
|
||||||
Tags to attach to the message
|
Tags to attach to the message.
|
||||||
example: incoming_envelope
|
example: incoming_envelope
|
||||||
states:
|
states:
|
||||||
type: array
|
type: array
|
||||||
|
|
|
@ -4,7 +4,7 @@ import jsonschema
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
import ruamel.yaml
|
import ruamel.yaml
|
||||||
|
|
||||||
from borgmatic.config import load, normalize, override
|
from borgmatic.config import environment, load, normalize, override
|
||||||
|
|
||||||
|
|
||||||
def schema_filename():
|
def schema_filename():
|
||||||
|
@ -79,7 +79,7 @@ def apply_logical_validation(config_filename, parsed_configuration):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def parse_configuration(config_filename, schema_filename, overrides=None):
|
def parse_configuration(config_filename, schema_filename, overrides=None, resolve_env=True):
|
||||||
'''
|
'''
|
||||||
Given the path to a config filename in YAML format, the path to a schema filename in a YAML
|
Given the path to a config filename in YAML format, the path to a schema filename in a YAML
|
||||||
rendition of JSON Schema format, a sequence of configuration file override strings in the form
|
rendition of JSON Schema format, a sequence of configuration file override strings in the form
|
||||||
|
@ -98,8 +98,10 @@ def parse_configuration(config_filename, schema_filename, overrides=None):
|
||||||
except (ruamel.yaml.error.YAMLError, RecursionError) as error:
|
except (ruamel.yaml.error.YAMLError, RecursionError) as error:
|
||||||
raise Validation_error(config_filename, (str(error),))
|
raise Validation_error(config_filename, (str(error),))
|
||||||
|
|
||||||
override.apply_overrides(config, overrides)
|
|
||||||
normalize.normalize(config)
|
normalize.normalize(config)
|
||||||
|
override.apply_overrides(config, overrides)
|
||||||
|
if resolve_env:
|
||||||
|
environment.resolve_env_variables(config)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
validator = jsonschema.Draft7Validator(schema)
|
validator = jsonschema.Draft7Validator(schema)
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
FROM python:3.8-alpine3.13 as borgmatic
|
FROM alpine:3.16.0 as borgmatic
|
||||||
|
|
||||||
COPY . /app
|
COPY . /app
|
||||||
RUN apk add --no-cache py3-ruamel.yaml py3-ruamel.yaml.clib
|
RUN apk add --no-cache py3-pip py3-ruamel.yaml py3-ruamel.yaml.clib
|
||||||
RUN pip install --no-cache /app && generate-borgmatic-config && chmod +r /etc/borgmatic/config.yaml
|
RUN pip install --no-cache /app && generate-borgmatic-config && chmod +r /etc/borgmatic/config.yaml
|
||||||
RUN borgmatic --help > /command-line.txt \
|
RUN borgmatic --help > /command-line.txt \
|
||||||
&& for action in init prune compact create check extract export-tar mount umount restore list info borg; do \
|
&& for action in init prune compact create check extract export-tar mount umount restore list info borg; do \
|
||||||
echo -e "\n--------------------------------------------------------------------------------\n" >> /command-line.txt \
|
echo -e "\n--------------------------------------------------------------------------------\n" >> /command-line.txt \
|
||||||
&& borgmatic "$action" --help >> /command-line.txt; done
|
&& borgmatic "$action" --help >> /command-line.txt; done
|
||||||
|
|
||||||
FROM node:15.2.1-alpine as html
|
FROM node:18.4.0-alpine as html
|
||||||
|
|
||||||
ARG ENVIRONMENT=production
|
ARG ENVIRONMENT=production
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ COPY . /source
|
||||||
RUN NODE_ENV=${ENVIRONMENT} npx eleventy --input=/source/docs --output=/output/docs \
|
RUN NODE_ENV=${ENVIRONMENT} npx eleventy --input=/source/docs --output=/output/docs \
|
||||||
&& mv /output/docs/index.html /output/index.html
|
&& mv /output/docs/index.html /output/index.html
|
||||||
|
|
||||||
FROM nginx:1.19.4-alpine
|
FROM nginx:1.22.0-alpine
|
||||||
|
|
||||||
COPY --from=html /output /usr/share/nginx/html
|
COPY --from=html /output /usr/share/nginx/html
|
||||||
COPY --from=borgmatic /etc/borgmatic/config.yaml /usr/share/nginx/html/docs/reference/config.yaml
|
COPY --from=borgmatic /etc/borgmatic/config.yaml /usr/share/nginx/html/docs/reference/config.yaml
|
||||||
|
|
|
@ -3,7 +3,7 @@ title: How to add preparation and cleanup steps to backups
|
||||||
eleventyNavigation:
|
eleventyNavigation:
|
||||||
key: 🧹 Add preparation and cleanup steps
|
key: 🧹 Add preparation and cleanup steps
|
||||||
parent: How-to guides
|
parent: How-to guides
|
||||||
order: 8
|
order: 9
|
||||||
---
|
---
|
||||||
## Preparation and cleanup hooks
|
## Preparation and cleanup hooks
|
||||||
|
|
||||||
|
@ -28,7 +28,8 @@ hooks:
|
||||||
- umount /some/filesystem
|
- umount /some/filesystem
|
||||||
```
|
```
|
||||||
|
|
||||||
The `before_backup` and `after_backup` hooks each run once per repository in a
|
<span class="minilink minilink-addedin">New in version 1.6.0</span> The
|
||||||
|
`before_backup` and `after_backup` hooks each run once per repository in a
|
||||||
configuration file. `before_backup` hooks runs right before the `create`
|
configuration file. `before_backup` hooks runs right before the `create`
|
||||||
action for a particular repository, and `after_backup` hooks run afterwards,
|
action for a particular repository, and `after_backup` hooks run afterwards,
|
||||||
but not if an error occurs in a previous hook or in the backups themselves.
|
but not if an error occurs in a previous hook or in the backups themselves.
|
||||||
|
@ -61,6 +62,10 @@ variables you can use here:
|
||||||
* `repository`: path of the current repository as configured in the current
|
* `repository`: path of the current repository as configured in the current
|
||||||
borgmatic configuration file
|
borgmatic configuration file
|
||||||
|
|
||||||
|
Note that you can also interpolate in [arbitrary environment
|
||||||
|
variables](https://torsion.org/borgmatic/docs/how-to/provide-your-passwords/).
|
||||||
|
|
||||||
|
|
||||||
## Global hooks
|
## Global hooks
|
||||||
|
|
||||||
You can also use `before_everything` and `after_everything` hooks to perform
|
You can also use `before_everything` and `after_everything` hooks to perform
|
||||||
|
|
|
@ -3,7 +3,7 @@ title: How to backup to a removable drive or an intermittent server
|
||||||
eleventyNavigation:
|
eleventyNavigation:
|
||||||
key: 💾 Backup to a removable drive/server
|
key: 💾 Backup to a removable drive/server
|
||||||
parent: How-to guides
|
parent: How-to guides
|
||||||
order: 9
|
order: 10
|
||||||
---
|
---
|
||||||
## Occasional backups
|
## Occasional backups
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ title: How to backup your databases
|
||||||
eleventyNavigation:
|
eleventyNavigation:
|
||||||
key: 🗄️ Backup your databases
|
key: 🗄️ Backup your databases
|
||||||
parent: How-to guides
|
parent: How-to guides
|
||||||
order: 7
|
order: 8
|
||||||
---
|
---
|
||||||
## Database dump hooks
|
## Database dump hooks
|
||||||
|
|
||||||
|
@ -100,6 +100,14 @@ hooks:
|
||||||
- name: all
|
- name: all
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### External passwords
|
||||||
|
|
||||||
|
If you don't want to keep your database passwords in your borgmatic
|
||||||
|
configuration file, you can instead pass them in via [environment
|
||||||
|
variables](https://torsion.org/borgmatic/docs/how-to/provide-your-passwords/)
|
||||||
|
or command-line [configuration
|
||||||
|
overrides](https://torsion.org/borgmatic/docs/how-to/make-per-application-backups/#configuration-overrides).
|
||||||
|
|
||||||
|
|
||||||
### Configuration backups
|
### Configuration backups
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ title: How to deal with very large backups
|
||||||
eleventyNavigation:
|
eleventyNavigation:
|
||||||
key: 📏 Deal with very large backups
|
key: 📏 Deal with very large backups
|
||||||
parent: How-to guides
|
parent: How-to guides
|
||||||
order: 3
|
order: 4
|
||||||
---
|
---
|
||||||
## Biggish data
|
## Biggish data
|
||||||
|
|
||||||
|
@ -74,8 +74,9 @@ See [Borg's check documentation](https://borgbackup.readthedocs.io/en/stable/usa
|
||||||
|
|
||||||
### Check frequency
|
### Check frequency
|
||||||
|
|
||||||
As of borgmatic 1.6.2, you can optionally configure checks to run on a
|
<span class="minilink minilink-addedin">New in version 1.6.2</span> You can
|
||||||
periodic basis rather than every time borgmatic runs checks. For instance:
|
optionally configure checks to run on a periodic basis rather than every time
|
||||||
|
borgmatic runs checks. For instance:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
consistency:
|
consistency:
|
||||||
|
|
|
@ -3,7 +3,7 @@ title: How to develop on borgmatic
|
||||||
eleventyNavigation:
|
eleventyNavigation:
|
||||||
key: 🏗️ Develop on borgmatic
|
key: 🏗️ Develop on borgmatic
|
||||||
parent: How-to guides
|
parent: How-to guides
|
||||||
order: 12
|
order: 13
|
||||||
---
|
---
|
||||||
## Source code
|
## Source code
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ title: How to extract a backup
|
||||||
eleventyNavigation:
|
eleventyNavigation:
|
||||||
key: 📤 Extract a backup
|
key: 📤 Extract a backup
|
||||||
parent: How-to guides
|
parent: How-to guides
|
||||||
order: 6
|
order: 7
|
||||||
---
|
---
|
||||||
## Extract
|
## Extract
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ title: How to inspect your backups
|
||||||
eleventyNavigation:
|
eleventyNavigation:
|
||||||
key: 🔎 Inspect your backups
|
key: 🔎 Inspect your backups
|
||||||
parent: How-to guides
|
parent: How-to guides
|
||||||
order: 4
|
order: 5
|
||||||
---
|
---
|
||||||
## Backup progress
|
## Backup progress
|
||||||
|
|
||||||
|
@ -53,10 +53,10 @@ borgmatic info
|
||||||
|
|
||||||
### Searching for a file
|
### Searching for a file
|
||||||
|
|
||||||
Let's say you've accidentally deleted a file and want to find the backup
|
<span class="minilink minilink-addedin">New in version 1.6.3</span> Let's say
|
||||||
archive(s) containing it. `borgmatic list` provides a `--find` flag for
|
you've accidentally deleted a file and want to find the backup archive(s)
|
||||||
exactly this purpose (as of borgmatic 1.6.3). For instance, if you're looking
|
containing it. `borgmatic list` provides a `--find` flag for exactly this
|
||||||
for a `foo.txt`:
|
purpose. For instance, if you're looking for a `foo.txt`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
borgmatic list --find foo.txt
|
borgmatic list --find foo.txt
|
||||||
|
|
|
@ -3,7 +3,7 @@ title: How to make backups redundant
|
||||||
eleventyNavigation:
|
eleventyNavigation:
|
||||||
key: ☁️ Make backups redundant
|
key: ☁️ Make backups redundant
|
||||||
parent: How-to guides
|
parent: How-to guides
|
||||||
order: 2
|
order: 3
|
||||||
---
|
---
|
||||||
## Multiple repositories
|
## Multiple repositories
|
||||||
|
|
||||||
|
|
|
@ -123,11 +123,7 @@ Once this include gets merged in, the resulting configuration would have a
|
||||||
`keep_hourly` value of `24` and an overridden `keep_daily` value of `5`.
|
`keep_hourly` value of `24` and an overridden `keep_daily` value of `5`.
|
||||||
|
|
||||||
When there's an option collision between the local file and the merged
|
When there's an option collision between the local file and the merged
|
||||||
include, the local file's option takes precedence. And as of borgmatic 1.6.0,
|
include, the local file's option takes precedence.
|
||||||
this feature performs a deep merge, meaning that values are merged at all
|
|
||||||
levels in the two configuration files. Colliding list values are appended
|
|
||||||
together. This allows you to include common configuration—up to full borgmatic
|
|
||||||
configuration files—while overriding only the parts you want to customize.
|
|
||||||
|
|
||||||
Note that this `<<` include merging syntax is only for merging in mappings
|
Note that this `<<` include merging syntax is only for merging in mappings
|
||||||
(configuration options and their values). But if you'd like to include a
|
(configuration options and their values). But if you'd like to include a
|
||||||
|
@ -139,6 +135,16 @@ global level, another `<<` within each configuration section, etc. (This is a
|
||||||
YAML limitation.)
|
YAML limitation.)
|
||||||
|
|
||||||
|
|
||||||
|
### Deep merge
|
||||||
|
|
||||||
|
<span class="minilink minilink-addedin">New in version 1.6.0</span> borgmatic
|
||||||
|
performs a deep merge of merged include files, meaning that values are merged
|
||||||
|
at all levels in the two configuration files. Colliding list values are
|
||||||
|
appended together. This allows you to include common configuration—up to full
|
||||||
|
borgmatic configuration files—while overriding only the parts you want to
|
||||||
|
customize.
|
||||||
|
|
||||||
|
|
||||||
## Configuration overrides
|
## Configuration overrides
|
||||||
|
|
||||||
In more complex multi-application setups, you may want to override particular
|
In more complex multi-application setups, you may want to override particular
|
||||||
|
@ -203,3 +209,5 @@ indentation and a leading dash.)
|
||||||
|
|
||||||
Be sure to quote your overrides if they contain spaces or other characters
|
Be sure to quote your overrides if they contain spaces or other characters
|
||||||
that your shell may interpret.
|
that your shell may interpret.
|
||||||
|
|
||||||
|
An alternate to command-line overrides is passing in your values via [environment variables](https://torsion.org/borgmatic/docs/how-to/provide-your-passwords/).
|
||||||
|
|
|
@ -3,7 +3,7 @@ title: How to monitor your backups
|
||||||
eleventyNavigation:
|
eleventyNavigation:
|
||||||
key: 🚨 Monitor your backups
|
key: 🚨 Monitor your backups
|
||||||
parent: How-to guides
|
parent: How-to guides
|
||||||
order: 5
|
order: 6
|
||||||
---
|
---
|
||||||
|
|
||||||
## Monitoring and alerting
|
## Monitoring and alerting
|
||||||
|
@ -61,8 +61,6 @@ one of them at most.
|
||||||
You can use traditional monitoring software to consume borgmatic JSON output
|
You can use traditional monitoring software to consume borgmatic JSON output
|
||||||
and track when the last successful backup occurred. See [scripting
|
and track when the last successful backup occurred. See [scripting
|
||||||
borgmatic](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#scripting-borgmatic)
|
borgmatic](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#scripting-borgmatic)
|
||||||
and [related
|
|
||||||
software](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#related-software)
|
|
||||||
below for how to configure this.
|
below for how to configure this.
|
||||||
|
|
||||||
### Borg hosting providers
|
### Borg hosting providers
|
||||||
|
@ -329,11 +327,6 @@ suppressed so as not to interfere with the captured JSON. Also note that JSON
|
||||||
output only shows up at the console, and not in syslog.
|
output only shows up at the console, and not in syslog.
|
||||||
|
|
||||||
|
|
||||||
## Related software
|
|
||||||
|
|
||||||
* [Borgmacator GNOME AppIndicator](https://github.com/N-Coder/borgmacator/)
|
|
||||||
|
|
||||||
|
|
||||||
### Latest backups
|
### Latest backups
|
||||||
|
|
||||||
All borgmatic actions that accept an "--archive" flag allow you to specify an
|
All borgmatic actions that accept an "--archive" flag allow you to specify an
|
||||||
|
|
82
docs/how-to/provide-your-passwords.md
Normal file
82
docs/how-to/provide-your-passwords.md
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
---
|
||||||
|
title: How to provide your passwords
|
||||||
|
eleventyNavigation:
|
||||||
|
key: 🔒 Provide your passwords
|
||||||
|
parent: How-to guides
|
||||||
|
order: 2
|
||||||
|
---
|
||||||
|
## Environment variable interpolation
|
||||||
|
|
||||||
|
If you want to use a Borg repository passphrase or database passwords with
|
||||||
|
borgmatic, you can set them directly in your borgmatic configuration file,
|
||||||
|
treating those secrets like any other option value. But if you'd rather store
|
||||||
|
them outside of borgmatic, whether for convenience or security reasons, read
|
||||||
|
on.
|
||||||
|
|
||||||
|
<span class="minilink minilink-addedin">New in version 1.6.4</span> borgmatic
|
||||||
|
supports interpolating arbitrary environment variables directly into option
|
||||||
|
values in your configuration file. That means you can instruct borgmatic to
|
||||||
|
pull your repository passphrase, your database passwords, or any other option
|
||||||
|
values from environment variables. For instance:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
storage:
|
||||||
|
encryption_passphrase: ${MY_PASSPHRASE}
|
||||||
|
```
|
||||||
|
|
||||||
|
This uses the `MY_PASSPHRASE` environment variable as your encryption
|
||||||
|
passphrase. Note that the `{` `}` brackets are required. Just `$MY_PASSPHRASE`
|
||||||
|
will not work.
|
||||||
|
|
||||||
|
In the case of `encryption_passphrase` in particular, an alternate approach
|
||||||
|
is to use Borg's `BORG_PASSPHRASE` environment variable, which doesn't even
|
||||||
|
require setting an explicit `encryption_passphrase` value in borgmatic's
|
||||||
|
configuration file.
|
||||||
|
|
||||||
|
For [database
|
||||||
|
configuration](https://torsion.org/borgmatic/docs/how-to/backup-your-databases/),
|
||||||
|
the same approach applies. For example:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
hooks:
|
||||||
|
postgresql_databases:
|
||||||
|
- name: users
|
||||||
|
password: ${MY_DATABASE_PASSWORD}
|
||||||
|
```
|
||||||
|
|
||||||
|
This uses the `MY_DATABASE_PASSWORD` environment variable as your database
|
||||||
|
password.
|
||||||
|
|
||||||
|
|
||||||
|
### Interpolation defaults
|
||||||
|
|
||||||
|
If you'd like to set a default for your environment variables, you can do so with the following syntax:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
storage:
|
||||||
|
encryption_passphrase: ${MY_PASSPHRASE:-defaultpass}
|
||||||
|
```
|
||||||
|
|
||||||
|
Here, "`defaultpass`" is the default passphrase if the `MY_PASSPHRASE`
|
||||||
|
environment variable is not set. Without a default, if the environment
|
||||||
|
variable doesn't exist, borgmatic will error.
|
||||||
|
|
||||||
|
|
||||||
|
### Disabling interpolation
|
||||||
|
|
||||||
|
To disable this environment variable interpolation feature entirely, you can
|
||||||
|
pass the `--no-environment-interpolation` flag on the command-line.
|
||||||
|
|
||||||
|
|
||||||
|
### Related features
|
||||||
|
|
||||||
|
Another way to override particular options within a borgmatic configuration
|
||||||
|
file is to use a [configuration
|
||||||
|
override](https://torsion.org/borgmatic/docs/how-to/make-per-application-backups/#configuration-overrides)
|
||||||
|
on the command-line. But please be aware of the security implications of
|
||||||
|
specifying secrets on the command-line.
|
||||||
|
|
||||||
|
Additionally, borgmatic action hooks support their own [variable
|
||||||
|
interpolation](https://torsion.org/borgmatic/docs/how-to/add-preparation-and-cleanup-steps-to-backups/#variable-interpolation),
|
||||||
|
although in that case it's for particular borgmatic runtime values rather than
|
||||||
|
(only) environment variables.
|
|
@ -3,7 +3,7 @@ title: How to run arbitrary Borg commands
|
||||||
eleventyNavigation:
|
eleventyNavigation:
|
||||||
key: 🔧 Run arbitrary Borg commands
|
key: 🔧 Run arbitrary Borg commands
|
||||||
parent: How-to guides
|
parent: How-to guides
|
||||||
order: 10
|
order: 11
|
||||||
---
|
---
|
||||||
## Running Borg with borgmatic
|
## Running Borg with borgmatic
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ title: How to upgrade borgmatic
|
||||||
eleventyNavigation:
|
eleventyNavigation:
|
||||||
key: 📦 Upgrade borgmatic
|
key: 📦 Upgrade borgmatic
|
||||||
parent: How-to guides
|
parent: How-to guides
|
||||||
order: 11
|
order: 12
|
||||||
---
|
---
|
||||||
## Upgrading
|
## Upgrading
|
||||||
|
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -1,6 +1,6 @@
|
||||||
from setuptools import find_packages, setup
|
from setuptools import find_packages, setup
|
||||||
|
|
||||||
VERSION = '1.6.3'
|
VERSION = '1.6.4.dev0'
|
||||||
|
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
|
|
85
tests/unit/config/test_environment.py
Normal file
85
tests/unit/config/test_environment.py
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from borgmatic.config import environment as module
|
||||||
|
|
||||||
|
|
||||||
|
def test_env(monkeypatch):
|
||||||
|
monkeypatch.setenv('MY_CUSTOM_VALUE', 'foo')
|
||||||
|
config = {'key': 'Hello $MY_CUSTOM_VALUE'}
|
||||||
|
module.resolve_env_variables(config)
|
||||||
|
assert config == {'key': 'Hello $MY_CUSTOM_VALUE'}
|
||||||
|
|
||||||
|
|
||||||
|
def test_env_braces(monkeypatch):
|
||||||
|
monkeypatch.setenv('MY_CUSTOM_VALUE', 'foo')
|
||||||
|
config = {'key': 'Hello ${MY_CUSTOM_VALUE}'}
|
||||||
|
module.resolve_env_variables(config)
|
||||||
|
assert config == {'key': 'Hello foo'}
|
||||||
|
|
||||||
|
def test_env_multi(monkeypatch):
|
||||||
|
monkeypatch.setenv('MY_CUSTOM_VALUE', 'foo')
|
||||||
|
monkeypatch.setenv('MY_CUSTOM_VALUE2', 'bar')
|
||||||
|
config = {'key': 'Hello ${MY_CUSTOM_VALUE}${MY_CUSTOM_VALUE2}'}
|
||||||
|
module.resolve_env_variables(config)
|
||||||
|
assert config == {'key': 'Hello foobar'}
|
||||||
|
|
||||||
|
def test_env_escape(monkeypatch):
|
||||||
|
monkeypatch.setenv('MY_CUSTOM_VALUE', 'foo')
|
||||||
|
monkeypatch.setenv('MY_CUSTOM_VALUE2', 'bar')
|
||||||
|
config = {'key': r'Hello ${MY_CUSTOM_VALUE} \${MY_CUSTOM_VALUE}'}
|
||||||
|
module.resolve_env_variables(config)
|
||||||
|
assert config == {'key': r'Hello foo ${MY_CUSTOM_VALUE}'}
|
||||||
|
|
||||||
|
|
||||||
|
def test_env_default_value(monkeypatch):
|
||||||
|
monkeypatch.delenv('MY_CUSTOM_VALUE', raising=False)
|
||||||
|
config = {'key': 'Hello ${MY_CUSTOM_VALUE:-bar}'}
|
||||||
|
module.resolve_env_variables(config)
|
||||||
|
assert config == {'key': 'Hello bar'}
|
||||||
|
|
||||||
|
|
||||||
|
def test_env_unknown(monkeypatch):
|
||||||
|
monkeypatch.delenv('MY_CUSTOM_VALUE', raising=False)
|
||||||
|
config = {'key': 'Hello ${MY_CUSTOM_VALUE}'}
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
module.resolve_env_variables(config)
|
||||||
|
|
||||||
|
|
||||||
|
def test_env_full(monkeypatch):
|
||||||
|
monkeypatch.setenv('MY_CUSTOM_VALUE', 'foo')
|
||||||
|
monkeypatch.delenv('MY_CUSTOM_VALUE2', raising=False)
|
||||||
|
config = {
|
||||||
|
'key': 'Hello $MY_CUSTOM_VALUE is not resolved',
|
||||||
|
'dict': {
|
||||||
|
'key': 'value',
|
||||||
|
'anotherdict': {
|
||||||
|
'key': 'My ${MY_CUSTOM_VALUE} here',
|
||||||
|
'other': '${MY_CUSTOM_VALUE}',
|
||||||
|
'escaped': r'\${MY_CUSTOM_VALUE}',
|
||||||
|
'list': [
|
||||||
|
'/home/${MY_CUSTOM_VALUE}/.local',
|
||||||
|
'/var/log/',
|
||||||
|
'/home/${MY_CUSTOM_VALUE2:-bar}/.config',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'list': [
|
||||||
|
'/home/${MY_CUSTOM_VALUE}/.local',
|
||||||
|
'/var/log/',
|
||||||
|
'/home/${MY_CUSTOM_VALUE2-bar}/.config',
|
||||||
|
],
|
||||||
|
}
|
||||||
|
module.resolve_env_variables(config)
|
||||||
|
assert config == {
|
||||||
|
'key': 'Hello $MY_CUSTOM_VALUE is not resolved',
|
||||||
|
'dict': {
|
||||||
|
'key': 'value',
|
||||||
|
'anotherdict': {
|
||||||
|
'key': 'My foo here',
|
||||||
|
'other': 'foo',
|
||||||
|
'escaped': '${MY_CUSTOM_VALUE}',
|
||||||
|
'list': ['/home/foo/.local', '/var/log/', '/home/bar/.config'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'list': ['/home/foo/.local', '/var/log/', '/home/bar/.config'],
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user