Compare commits
2 Commits
0deed89c3f
...
3d4f2773a8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d4f2773a8 | ||
|
|
0db60e2d60 |
22
roles/borgmatic/meta/argument_specs.yaml
Normal file
22
roles/borgmatic/meta/argument_specs.yaml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
---
|
||||||
|
argument_specs:
|
||||||
|
main:
|
||||||
|
short_description: Borgmatic
|
||||||
|
description:
|
||||||
|
- Installs borgmatic
|
||||||
|
options:
|
||||||
|
borgmatic_targets:
|
||||||
|
description: List of backup targets
|
||||||
|
type: list
|
||||||
|
required: true
|
||||||
|
elements: dict
|
||||||
|
options:
|
||||||
|
host:
|
||||||
|
description: Target hostname
|
||||||
|
type: str
|
||||||
|
required: true
|
||||||
|
directories:
|
||||||
|
description: Directories on the host where backup repos will be created under
|
||||||
|
type: list
|
||||||
|
required: true
|
||||||
|
elements: str
|
||||||
55
roles/borgmatic/tasks/main.yaml
Normal file
55
roles/borgmatic/tasks/main.yaml
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
---
|
||||||
|
- name: Ensure host distribution is supported
|
||||||
|
ansible.builtin.import_role:
|
||||||
|
name: compatcheck
|
||||||
|
vars:
|
||||||
|
compatcheck_supported_distributions:
|
||||||
|
- name: debian
|
||||||
|
version_min: 11
|
||||||
|
- name: ubuntu
|
||||||
|
version_min: 22
|
||||||
|
|
||||||
|
- name: Install borgmatic
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: borgmatic
|
||||||
|
|
||||||
|
- name: Disable borgmatic global timer
|
||||||
|
ansible.builtin.systemd_service:
|
||||||
|
name: borgmatic.timer
|
||||||
|
state: stopped
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
- name: Add systemd drop-in service for borgmatic
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: borgmatic@.service.j2
|
||||||
|
dest: /etc/systemd/system/borgmatic@.service
|
||||||
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Create borgmatic configurations directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /etc/borgmatic.d
|
||||||
|
state: directory
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Generate ssh key for borg
|
||||||
|
community.crypto.openssh_keypair:
|
||||||
|
type: ed25519
|
||||||
|
path: "{{ ansible_user_dir }}/.ssh/id_ed25519_borg"
|
||||||
|
comment: "{{ ansible_user_id }}@{{ ansible_fqdn }} borg"
|
||||||
|
register: _borgmatic_key
|
||||||
|
|
||||||
|
- name: Setup backup targets
|
||||||
|
ansible.builtin.include_tasks:
|
||||||
|
file: target.yaml
|
||||||
|
apply:
|
||||||
|
delegate_to: "{{ target.host }}"
|
||||||
|
become: false
|
||||||
|
loop: "{{ borgmatic_targets }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: target
|
||||||
|
|
||||||
|
- name: Add borg target ssh host keys to known hosts
|
||||||
|
ansible.builtin.known_hosts:
|
||||||
|
name: "{{ item }}"
|
||||||
|
key: "{{ item }} ssh-ed25519 {{ hostvars[item].ansible_ssh_host_key_ed25519_public }}"
|
||||||
|
loop: "{{ borgmatic_targets | map(attribute='host') }}"
|
||||||
26
roles/borgmatic/tasks/target.yaml
Normal file
26
roles/borgmatic/tasks/target.yaml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
- name: Gather facts
|
||||||
|
ansible.builtin.setup:
|
||||||
|
delegate_facts: true
|
||||||
|
|
||||||
|
- name: Add ssh key to authorized_keys
|
||||||
|
ansible.posix.authorized_key:
|
||||||
|
user: "{{ hostvars[target.host].ansible_user_id }}"
|
||||||
|
key: >-
|
||||||
|
{{
|
||||||
|
_borgmatic_key.public_key + ' ' + _borgmatic_key.comment
|
||||||
|
if not (ansible_check_mode and _borgmatic_key.changed)
|
||||||
|
else 'ssh-ed25519 AAAA'
|
||||||
|
}}
|
||||||
|
key_options: >-
|
||||||
|
command="borg
|
||||||
|
serve{% for directory in target.directories %}
|
||||||
|
--restrict-to-path
|
||||||
|
{{ hostvars[target.host].ansible_user_dir }}/{{ directory }}/{{ ansible_fqdn }}{%- endfor -%}",restrict
|
||||||
|
|
||||||
|
- name: Create backup directories
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ hostvars[target.host].ansible_user_dir }}/{{ item }}/{{ ansible_fqdn }}"
|
||||||
|
state: directory
|
||||||
|
mode: "0700"
|
||||||
|
loop: "{{ target.directories }}"
|
||||||
63
roles/borgmatic/templates/borgmatic@.service.j2
Normal file
63
roles/borgmatic/templates/borgmatic@.service.j2
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# {{ ansible_managed }}
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Description=borgmatic backup %i
|
||||||
|
Wants=network-online.target
|
||||||
|
After=network-online.target
|
||||||
|
Documentation=https://torsion.org/borgmatic/
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
RuntimeDirectory=borgmatic
|
||||||
|
StateDirectory=borgmatic
|
||||||
|
|
||||||
|
# Security settings for systemd running as root, optional but recommended to improve security. You
|
||||||
|
# can disable individual settings if they cause problems for your use case. For more details, see
|
||||||
|
# the systemd manual: https://www.freedesktop.org/software/systemd/man/systemd.exec.html
|
||||||
|
LockPersonality=true
|
||||||
|
# Certain borgmatic features like Healthchecks integration need MemoryDenyWriteExecute to be off.
|
||||||
|
# But you can try setting it to "yes" for improved security if you don't use those features.
|
||||||
|
MemoryDenyWriteExecute=no
|
||||||
|
NoNewPrivileges=yes
|
||||||
|
PrivateDevices=yes
|
||||||
|
PrivateTmp=yes
|
||||||
|
ProtectClock=yes
|
||||||
|
ProtectControlGroups=yes
|
||||||
|
ProtectHostname=yes
|
||||||
|
ProtectKernelLogs=yes
|
||||||
|
ProtectKernelModules=yes
|
||||||
|
ProtectKernelTunables=yes
|
||||||
|
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK
|
||||||
|
RestrictNamespaces=yes
|
||||||
|
RestrictRealtime=yes
|
||||||
|
RestrictSUIDSGID=yes
|
||||||
|
SystemCallArchitectures=native
|
||||||
|
SystemCallFilter=@system-service
|
||||||
|
SystemCallErrorNumber=EPERM
|
||||||
|
# To restrict write access further, change "ProtectSystem" to "strict" and
|
||||||
|
# uncomment "ReadWritePaths", "TemporaryFileSystem", "BindPaths" and
|
||||||
|
# "BindReadOnlyPaths". Then add any local repository paths to the list of
|
||||||
|
# "ReadWritePaths". This leaves most of the filesystem read-only to borgmatic.
|
||||||
|
ProtectSystem=full
|
||||||
|
# ReadWritePaths=-/mnt/my_backup_drive
|
||||||
|
# This will mount a tmpfs on top of /root and pass through needed paths
|
||||||
|
# TemporaryFileSystem=/root:ro
|
||||||
|
# BindPaths=-/root/.cache/borg -/root/.config/borg -/root/.borgmatic
|
||||||
|
# BindReadOnlyPaths=-/root/.ssh
|
||||||
|
|
||||||
|
# May interfere with running external programs within borgmatic hooks.
|
||||||
|
CapabilityBoundingSet=CAP_DAC_READ_SEARCH CAP_NET_RAW
|
||||||
|
|
||||||
|
# Lower CPU and I/O priority.
|
||||||
|
Nice=19
|
||||||
|
CPUSchedulingPolicy=batch
|
||||||
|
IOSchedulingClass=best-effort
|
||||||
|
IOSchedulingPriority=7
|
||||||
|
IOWeight=100
|
||||||
|
|
||||||
|
Restart=no
|
||||||
|
# Prevent rate limiting of borgmatic log events. If you are using an older version of systemd that
|
||||||
|
# doesn't support this (pre-240 or so), you may have to remove this option.
|
||||||
|
LogRateLimitIntervalSec=0
|
||||||
|
|
||||||
|
ExecStart=systemd-inhibit --who="borgmatic" --what="sleep:shutdown" --why="Prevent interrupting scheduled backup" /usr/bin/borgmatic -c "/etc/borgmatic.d/%I.yaml" --verbosity -2 --syslog-verbosity 1
|
||||||
8
roles/borgmatic_config/defaults/main.yaml
Normal file
8
roles/borgmatic_config/defaults/main.yaml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
borgmatic_config_backup_frequency:
|
||||||
|
unit: h
|
||||||
|
amount: 1
|
||||||
|
|
||||||
|
borgmatic_config_keep_backups_months: 6
|
||||||
|
|
||||||
|
borgmatic_config_targets: "{{ borgmatic_targets }}"
|
||||||
6
roles/borgmatic_config/handlers/main.yaml
Normal file
6
roles/borgmatic_config/handlers/main.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
- name: Restart borgmatic timer {{ borgmatic_config_name }}
|
||||||
|
ansible.builtin.systemd_service:
|
||||||
|
name: "borgmatic@{{ borgmatic_config_name }}.timer"
|
||||||
|
state: restarted
|
||||||
|
daemon_reload: true
|
||||||
65
roles/borgmatic_config/meta/argument_specs.yaml
Normal file
65
roles/borgmatic_config/meta/argument_specs.yaml
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
---
|
||||||
|
argument_specs:
|
||||||
|
main:
|
||||||
|
short_description: Borgmatic config
|
||||||
|
description:
|
||||||
|
- Creates a bormatic configuration in /etc/borgmatic.d/ and creates the repos
|
||||||
|
options:
|
||||||
|
borgmatic_config_name:
|
||||||
|
description:
|
||||||
|
- Name of the borgmatic config.
|
||||||
|
- Must be unique within the (source) host.
|
||||||
|
type: str
|
||||||
|
required: true
|
||||||
|
borgmatic_config_directories:
|
||||||
|
description: Directories to backup
|
||||||
|
type: list
|
||||||
|
required: true
|
||||||
|
elements: str
|
||||||
|
borgmatic_config_encryption_passphrase:
|
||||||
|
description: Passphrase for borg repo encryption
|
||||||
|
type: str
|
||||||
|
required: true
|
||||||
|
borgmatic_config_targets:
|
||||||
|
description:
|
||||||
|
- List of backup targets for this config.
|
||||||
|
- All backup targets and directories must be listed in borgmatic_targets.
|
||||||
|
- Defaults to all defined in borgmatic_targets.
|
||||||
|
type: list
|
||||||
|
required: false
|
||||||
|
elements: dict
|
||||||
|
options:
|
||||||
|
host:
|
||||||
|
description: Target hostname
|
||||||
|
type: str
|
||||||
|
required: true
|
||||||
|
directories:
|
||||||
|
description: Directories on the host where backup repos will be created under
|
||||||
|
type: list
|
||||||
|
required: true
|
||||||
|
elements: str
|
||||||
|
borgmatic_config_backup_frequency:
|
||||||
|
description: How often to take backups. Defaults to once per hour.
|
||||||
|
type: dict
|
||||||
|
required: false
|
||||||
|
default:
|
||||||
|
unit: h
|
||||||
|
amount: 1
|
||||||
|
options:
|
||||||
|
unit:
|
||||||
|
description: Time unit
|
||||||
|
type: str
|
||||||
|
required: true
|
||||||
|
choices:
|
||||||
|
- min
|
||||||
|
- h
|
||||||
|
- d
|
||||||
|
amount:
|
||||||
|
description: Every how many time units to take backpus
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
borgmatic_config_keep_backups_months:
|
||||||
|
description: How many months to keep backups for
|
||||||
|
type: int
|
||||||
|
required: false
|
||||||
|
default: 6
|
||||||
3
roles/borgmatic_config/meta/main.yaml
Normal file
3
roles/borgmatic_config/meta/main.yaml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
dependencies:
|
||||||
|
- borgmatic
|
||||||
35
roles/borgmatic_config/tasks/main.yaml
Normal file
35
roles/borgmatic_config/tasks/main.yaml
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
- name: Fail if hosts or directories listed in borgmatic_config_targets not in borgmatic_targets.
|
||||||
|
ansible.builtin.fail:
|
||||||
|
msg: All backup targets and directories must be listed in borgmatic_targets.
|
||||||
|
when: >-
|
||||||
|
borgmatic_config_targets
|
||||||
|
| items2dict(key_name='host', value_name='directories')
|
||||||
|
| ansible.builtin.combine(
|
||||||
|
borgmatic_targets | items2dict(key_name='host', value_name='directories'), list_merge='prepend_rp'
|
||||||
|
)
|
||||||
|
| dict2items(key_name='host', value_name='directories')
|
||||||
|
| difference(borgmatic_targets)
|
||||||
|
| length != 0
|
||||||
|
|
||||||
|
- name: Add borgmatic configuration for {{ borgmatic_config_name }}
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: borgmatic.yaml.j2
|
||||||
|
dest: /etc/borgmatic.d/{{ borgmatic_config_name }}.yaml
|
||||||
|
mode: "0600"
|
||||||
|
no_log: true
|
||||||
|
|
||||||
|
- name: Add systemd timer for borgmatic {{ borgmatic_config_name }}
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: borgmatic@.timer.j2
|
||||||
|
dest: /etc/systemd/system/borgmatic@{{ borgmatic_config_name }}.timer
|
||||||
|
mode: "0644"
|
||||||
|
register: _borgmatic_config_systemd_timer
|
||||||
|
notify: Restart borgmatic timer {{ borgmatic_config_name }}
|
||||||
|
|
||||||
|
- name: Enable systemd timer for borgmatic {{ borgmatic_config_name }}
|
||||||
|
ansible.builtin.systemd_service:
|
||||||
|
name: borgmatic@{{ borgmatic_config_name }}.timer
|
||||||
|
state: started
|
||||||
|
enabled: true
|
||||||
|
when: "not (ansible_check_mode and _borgmatic_config_systemd_timer.changed and _borgmatic_config_systemd_timer.diff.before == '')"
|
||||||
35
roles/borgmatic_config/templates/borgmatic.yaml.j2
Normal file
35
roles/borgmatic_config/templates/borgmatic.yaml.j2
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# {{ ansible_managed }}
|
||||||
|
# vim:ft=yaml
|
||||||
|
|
||||||
|
source_directories:
|
||||||
|
{{ borgmatic_config_directories | to_nice_yaml }}
|
||||||
|
repositories:
|
||||||
|
{% for target in borgmatic_config_targets %}
|
||||||
|
{% for directory in target.directories %}
|
||||||
|
- path: "ssh://{{ hostvars[target.host].ansible_user_id }}@{{ target.host }}/{{ directory }}/{{ ansible_fqdn }}/{{ borgmatic_config_name }}"
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
working_directory: "~"
|
||||||
|
|
||||||
|
one_file_system: true
|
||||||
|
exclude_patterns:
|
||||||
|
- /var/cache
|
||||||
|
exclude_caches: true
|
||||||
|
exclude_if_present:
|
||||||
|
- .nobackup
|
||||||
|
keep_exclude_tags: true
|
||||||
|
|
||||||
|
source_directories_must_exist: true
|
||||||
|
|
||||||
|
compression: zstd
|
||||||
|
|
||||||
|
encryption_passphrase: "{{ borgmatic_config_encryption_passphrase }}"
|
||||||
|
ssh_command: ssh -i ~/.ssh/id_ed25519_borg
|
||||||
|
|
||||||
|
|
||||||
|
keep_within: 48H
|
||||||
|
keep_hourly: 168
|
||||||
|
keep_daily: 30
|
||||||
|
keep_weekly: 26
|
||||||
|
keep_monthly: {{ (borgmatic_config_keep_backups_months / 2) | round(0, 'ceil') | int }}
|
||||||
|
keep_yearly: {{ (borgmatic_config_keep_backups_months / 12) | round(0, 'ceil') | int }}
|
||||||
21
roles/borgmatic_config/templates/borgmatic@.timer.j2
Normal file
21
roles/borgmatic_config/templates/borgmatic@.timer.j2
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# {{ ansible_managed }}
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Description=Run borgmatic backup
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
{% if borgmatic_config_backup_frequency.unit == "min" %}
|
||||||
|
OnCalendar=*:0/{{ borgmatic_config_backup_frequency.amount }}
|
||||||
|
{% elif borgmatic_config_backup_frequency.unit == "h" %}
|
||||||
|
OnCalendar=0/{{ borgmatic_config_backup_frequency.amount }}:30
|
||||||
|
{% elif borgmatic_config_backup_frequency.unit == "d" %}
|
||||||
|
OnCalendar=*-1/{{ borgmatic_config_backup_frequency.amount }} 22:00
|
||||||
|
{% else %}
|
||||||
|
{{ dafuq }}
|
||||||
|
{% endif %}
|
||||||
|
Persistent=true
|
||||||
|
RandomizedDelaySec={{ 10 * borgmatic_config_backup_frequency.amount }}{{ _borgmatic_config_previous_time_unit[borgmatic_config_backup_frequency.unit] }}
|
||||||
|
FixedRandomDelay=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
5
roles/borgmatic_config/vars/main.yaml
Normal file
5
roles/borgmatic_config/vars/main.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
_borgmatic_config_previous_time_unit:
|
||||||
|
min: s
|
||||||
|
h: min
|
||||||
|
d: h
|
||||||
Reference in New Issue
Block a user