Skip to content
Snippets Groups Projects
Commit 8358f4aa authored by MyIgel's avatar MyIgel :fire:
Browse files

restic: Init

parent 975620bd
No related branches found
No related tags found
1 merge request!613Restic
{% set restic = pillar.get('restic', {}) -%}
{% if accumulator is not defined -%}
{% set accumulator = {} -%}
{% endif -%}
{% set cmds = accumulator.get('restic.cmd', []) | json_query('[][]') -%}
{% set paths = accumulator.get('restic.path', []) | json_query('[][]') -%}
{% set excludes = accumulator.get('restic.exclude', []) | json_query('[][]') -%}
[Unit]
Description=Create a backup
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
Environment="RESTIC_REPOSITORY=rest:https://{{ restic.get('http_user') }}:{{ restic.get('http_password') }}@{{ restic.get('http_host') }}/{{ restic.get('http_user') }}"
Environment="RESTIC_PASSWORD_FILE=/etc/restic.password"
Environment="RESTIC_CACHE_DIR=/tmp/restic"
{% for cmd in cmds | sort -%}
{% if cmd[0] != '/' -%}
{% set cmd = cmd.split(' ') -%}
{% do cmd.insert(0, cmd[0] | which) -%}
{% do cmd.pop(1) -%}
{% set cmd = cmd|join(' ') -%}
{% endif -%}
ExecStartPre={{ cmd }}
{% endfor -%}
ExecStart={{ 'restic' | which }} backup \
{% for path in paths | sort -%}
"{{ path }}"{% if not loop.last or excludes %} \{%endif %}
{% else -%}
/dev/null{% if excludes %} \{%endif %}
{% endfor -%}
{% for path in excludes | sort -%}
--exclude "{{ path }}"{% if not loop.last %} \{%endif %}
{% endfor -%}
{% set restic = pillar.get('restic', {}) -%}
[Unit]
Description=Create a backup
Wants=network-online.target
After=network-online.target
[Timer]
OnCalendar={{ restic.get('time', '02:00') }}
RandomizedDelaySec={{ restic.get('delay', '7200') }}
Persistent=true
[Install]
WantedBy=timers.target
{% set restic = pillar.get('restic', {}) -%}
{% set backup = restic.get('backup', {}) %}
restic:
pkg.installed: []
restic password:
file.managed:
- name: /etc/restic.password
- user: root
- group: root
- mode: '0600'
- contents: {{ restic.get('password') }}
{% set repository = ['rest:https://', restic.get('http_user'), ':', restic.get('http_password'), '@', restic.get('http_host'), '/', restic.get('http_user')] | join %}
restic init:
cmd.run:
- env:
- RESTIC_REPOSITORY: {{ repository }}
- RESTIC_PASSWORD_FILE: /etc/restic.password
- unless: restic snapshots -r '{{ repository }}' -p /etc/restic.password
- require:
- file: restic password
- pkg: restic
/etc/systemd/system/restic.service:
file.managed:
- source: salt://restic/files/restic.service.j2
- template: jinja
service.enabled:
- name: restic
- require:
- file: /etc/systemd/system/restic.service
/etc/systemd/system/restic.timer:
file.managed:
- source: salt://restic/files/restic.timer.j2
- template: jinja
service.running:
- name: restic.timer
- enable: True
- require:
- service: restic
- file: restic password
- cmd: restic init
{% macro cmd(name) %}
restic run {{ name }}:
file.accumulated:
- name: restic.cmd
- text: {{ varargs | list | tojson }}
- filename: /etc/systemd/system/restic.service
- require_in:
- file: /etc/systemd/system/restic.service
{% endmacro %}
{% macro path(name) %}
restic backup {{ name }}:
file.accumulated:
- name: restic.path
- filename: /etc/systemd/system/restic.service
- text: {{ varargs | list | tojson }}
- require_in:
- file: /etc/systemd/system/restic.service
{% endmacro %}
{% macro exclude(name) %}
restic exclude {{ name }}:
file.accumulated:
- name: restic.exclude
- filename: /etc/systemd/system/restic.service
- text: {{ varargs | list | tojson }}
- require_in:
- file: /etc/systemd/system/restic.service
{% endmacro %}
{% if backup.get('cmd', []) %}
{{ cmd('defaults', *backup.get('cmd', [])) }}
{% endif %}
{% if backup.get('path', []) %}
{{ path('defaults', *backup.get('path', [])) }}
{% endif %}
{% if backup.get('exclude', []) %}
{{ exclude('defaults', *backup.get('exclude', [])) }}
{% endif %}
# Restic
This module backups the provided data to a [Restic](https://restic.readthedocs.io/en/latest/)
[REST Server](https://restic.readthedocs.io/en/latest/030_preparing_a_new_repo.html#rest-server) over https.
When no backup paths are specified, `/dev/null` is added to allow for the same rollout on every system.
## Requirements
* Python
* `jmespath`
* Parameters
* The `cmd` command must start with a command which has to be an absolute path to a binary or exist in `$PATH`.
## Pillar
Pillar configuration to configure the backup target
```yaml
restic:
http_user: {{ grains['id'] }}
http_password: 1anDoMpAs5Wo1D
http_host: restic.host.tld
password: rAnD0MpA5SWoRd # The repository password
backup:
cmd: # Optional, commands to run before starting the backup
- echo 'I should be in the backup' > /tmp/note
path: # Paths to include in the backup
- /tmp/note
- /etc/
exclude: # Paths to exclude from backup
- /etc/foo/
time: 5:42 # Optional, time to start the backup, default 02:00
delay: 300 # Optional, in seconds, defaults 2h
```
## States
Include backups by other states
```jinja
{% import 'restic/init.sls' as restic %}
[...]
{{ restic.cmd('cmd name', '/usr/local/bin/dump-data > /some/file') }}
{{ restic.path('path name', '/some/file') }}
{{ restic.exclude('exclude name', '/another/path') }}
```
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment