Restructure role, add Systemd timer option. By @conloos (#112)

* add full path

* Update Readme.me: reorder optional Arguments, update cron -> systemd timer

* remove ssh_key_file; change cron to timer

* Removed cronie from package installation because systemd timer is used

* docker.sh - Stops all or selected containers to save the persistent data intact. The containers are started in reverse order

* Created arguments_specs.yml

* Role restructured:
  - if needed creation of a service user incl. creation of the ssh-key,
  - add the ssh key to authorized_keys,
  - auto init of the repos,
  - creation and start of systemd timer and services and
  - installation of the Docker helperscript.

* restructure role add import logic

* cleanup: user backup_user

* - "borg_source_directories" is not longer a required Argument
- add "borg_keys_directory" to load key from Service user during starting borgmatic by sudo

* Add borgmatic_initialization_repo (bool) as option to disable init of repo

* cleanup

* fix ansible-lint errors and warnings

* fix letter turner

* add option: borgmatic_timer

* add:
  - borgmatic_timer_systemd: true
readd:
  - borgmatic_cron_name: "borgmatic"

* - renamed borgmatic_cron_name to borgmatic_timer_cron_name to be more convergent.
- Change recommendations implemented by m3nu so that creation of a timer (systemd or cron) is optional and can be selected via borgmatic_timer.

* Add description to borgmatic_timer_cron_name and borgmatic_timer

* Add variable borg_cron_package to install the cron-packages in case of using timer: cron

* reworked timer install logic

* reworked timer install logic

* Add comments for running backup with service account

* add new parameters for tests

* Switch created to perform the backup as root or service account. If a service account is to be used, it will be created.

* Refactored: Check for ssh-key if not present, genereate them.

* Refactored

* Refactored

* renamed tasks/03_configure.yml to tasks/04_create_links_to_borg_and_borgmatic.yml

* Refactored

* Refactored

* add example for service account

* Update Python version for testing

* No auto init

* Add description to install_backup

* Add description to install_backup

* set coverage back to: m3nu.ansible_role_borgbackup

* The initialization of the repository must be activated and does not take place automatically.

* The initialization of the repository must be activated and does not take place automatically.

* Removed install_backup as var (bool) to prevent that this role run

* Rename backup_ssh_command to borg_ssh_command, tis was a double definition

* Renamed backup_repository to borg_repository and add better explanations

* remove copy ssh-keys and cert parts

* Add comments to borg_ssh_key_file and borg_ssh_key_type

* Set allways the borg_ssh_key_file and borg_ssh_command to load the right ssh-key. Add borg_ssh_key_type to select the key type by user

* Add borg_ssh_key_type

* renamed id_rsa to backup

* generate ssh-keys (backup and backup.pub) and add better explanation

* Print out key if borgmatic_initialization_repo is false

* Remove 'su - {{ borgbackup_user }} -c' to execute the borgmatic by the right user

* Add Check frequency, therefore, we no longer need to distinguish between normal and large repos

* Add link to Article

* renamed backup_ssh_command and backup_ssh_key_file to borg_ssh_command and borg_ssh_key_file

* Removed: borgmatic_initialization_repo

* Removed: borgmatic_initialization_repo

* Removed: borgmatic_initialization_repo

* revert changes

* Add Full Automation

* polishing

* rename backup.timer and bakup.service to borgmatic.timer and borgmatic.service

* remove debug

* Try to find services in ansible_facts

* Forgot to install Cron

* change borg_ssh_key_type to ed25519

* remove conditional checks

* - add hint to using a service user
- renamed: borg_ssh_key_file to borg_ssh_key_file_path
- removed advanced example

* add borg_ssh_key_name, renamed borg_ssh_key_file to borg_ssh_key_file_path

* removed static pointing to ~/.ssh/backup SSH private key

* Add README-Advanced-Examples.md for storing more examples

* Fix test idempotence

* Dont symlink when using distro packages

* Remove old test targets, consistent wording, remove tag

* Remove helper scripts, fix absolute path

* Fix cron job, add assert to prevent duplicate timers

* nit-pick

* Create bin links as root, no borg_ssh_command by default.

* Add breaking changes note to README

---------

Co-authored-by: Manu <manu@snapdragon.cc>
pull/118/head v1.0.0
Frank Dornheim 1 year ago committed by GitHub
parent 981d4f9072
commit dd960dcf4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      .github/workflows/main.yml
  2. 129
      EXAMPLES.md
  3. 95
      README.md
  4. 54
      defaults/main.yml
  5. 182
      meta/arguments_specs.yml
  6. 2
      meta/main.yml
  7. 5
      molecule/default/converge.yml
  8. 6
      molecule/default/molecule.yml
  9. 29
      tasks/01_install.yml
  10. 25
      tasks/02_user_management.yml
  11. 28
      tasks/03_create_key.yml
  12. 19
      tasks/05_configure.yml
  13. 8
      tasks/07_install_timer.yml
  14. 18
      tasks/install_package.yml
  15. 39
      tasks/install_pip.yml
  16. 101
      tasks/main.yml
  17. 34
      tasks/noauto_create_backup_user_and_group.yml
  18. 31
      tasks/noauto_create_timer_cron.yml
  19. 63
      tasks/noauto_create_timer_systemd.yml
  20. 21
      tasks/noauto_install_package.yml
  21. 51
      tasks/noauto_install_pip.yml
  22. 60
      templates/borgmatic.service.j2
  23. 13
      templates/borgmatic.timer.j2
  24. 11
      templates/config.yaml.j2
  25. 3
      vars/Archlinux.yml
  26. 3
      vars/Debian.yml
  27. 3
      vars/Fedora.yml
  28. 3
      vars/ManjaroLinux.yml
  29. 3
      vars/RedHat-8.yml
  30. 3
      vars/RedHat-9.yml
  31. 3
      vars/RedHat.yml

@ -8,9 +8,9 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v1
uses: actions/setup-python@v4
with:
python-version: 3.8
python-version: "3.10"
- name: Install Molecule
run: |
pip install -U pip setuptools wheel

@ -0,0 +1,129 @@
# Additional Examples
## Custom SSH key for backups only
```
- hosts: webservers
roles:
- role: m3nu.ansible_role_borgbackup
borg_encryption_passphrase: CHANGEME
borg_repository: ssh://m5vz9gp4@m5vz9gp4.repo.borgbase.com/./repo
borgmatic_timer: systemd
borg_ssh_key_name: id_backup
borg_ssh_command: "ssh -i {{ borg_ssh_key_file_path }} -o StrictHostKeyChecking=accept-new"
borg_user: backupuser
borg_group: backupuser
```
## Use service user and copy SSH key to target server
Installs and configures the Borgmatic client and also initializes the repo on the
remote backup server. (not tested)
```
- name: Configure backup
hosts: test.lab
pre_tasks:
- name: Get home of {{ borg_user }}
ansible.builtin.user:
name: "{{ borg_user }}"
state: present
register: user_info
changed_when: false
check_mode: true # Important, otherwise user will be created
- name: Save the user_info, we need them for the home_dir
ansible.builtin.set_fact:
backup_user_info: "{{ user_info }}"
vars_files: []
vars:
borg_encryption_passphrase: "CHANGEME"
borg_repository: "USER@TARGET_SERVER:/PATH/TO/BACKUP"
borg_user: "srv_backup"
borg_group: "srv_backup"
borg_ssh_key_name: id_backup
borg_ssh_command: "ssh -i {{ borg_ssh_key_file_path }} -o StrictHostKeyChecking=accept-new"
borgmatic_timer: systemd
borg_source_directories:
- /srv/www
- /var/lib/automysqlbackup
borg_exclude_patterns:
- /srv/www/old-sites
borg_retention_policy:
keep_hourly: 3
keep_daily: 7
keep_weekly: 4
keep_monthly: 6
borgmatic_hooks:
before_backup:
- echo "`date` - Starting backup."
tasks:
- name: Configure Borg Backup and Backupmatic
tags:
- always
- install_backup
ansible.builtin.include_role:
name: ansible_role_borgbackup
apply:
tags:
- always
- name: Copy SSH-Key to Target {{ borg_repository }} and Init Repo
tags:
- never
- backup_init_repo
block:
- name: Read ssh key
ansible.builtin.slurp:
src: "{{ borg_ssh_key_file_path }}.pub"
register: backup_local_ssh_key
- name: Set authorized key taken from file
ansible.posix.authorized_key:
# example:
# borg_repository: m5vz9gp4@m5vz9gp4.repo.borgbase.com:repo
# have three parts: "username"@"FQDN":"path/to/store/backup", specific:
# a) user: m5vz9gp4
# b) fqdn: m5vz9gp4.repo.borgbase.co
# c) dir: repo
user: "{{ borg_repository | regex_search('(.*)@', '\\1') | first }}" # part a)
state: present
key: "{{ backup_local_ssh_key['content'] | b64decode }}"
delegate_to: "{{ borg_repository | regex_search('@(.*):', '\\1') | first }}" # part b)
- name: Init repository
ansible.builtin.command:
cmd: "su - {{ borg_user }} -c '/usr/local/bin/borgmatic rcreate --encryption keyfile --append-only'"
- name: Activate systemd service and timer
when:
- borgmatic_timer is defined and borgmatic_timer == "systemd"
tags:
- never
- backup_init_repo
block:
- name: Populate service facts
ansible.builtin.service_facts:
- name: Start borgmatic services
ansible.builtin.systemd:
name: "{{ item }}"
state: started
enabled: true
masked: false
daemon_reload: true
when: "item in services"
with_items:
- borgmatic.service
# bug: Need own section without masked else the timer are skipped
- name: Start borgmatic timers
ansible.builtin.systemd:
name: "{{ item }}"
state: started
enabled: true
daemon_reload: true
with_items:
- "borgmatic.timer"
```

@ -6,30 +6,29 @@ Set up encrypted, compressed and deduplicated backups using [BorgBackup](https:/
Works great with [BorgBase.com](https://www.borgbase.com) - Simple and Secure Hosting for your Borg Repositories. To manage BorgBase repos via Ansible, also see Andy Hawkins' [BorgBase Collection](https://galaxy.ansible.com/adhawkins/borgbase).
Main features:
- Set up Borg and Borgmatic
- Add cron job at random time
- Provision new remote [BorgBase.com](https://www.borgbase.com) repo for storing backups (optional)
**Main features**
- Install Borg and Borgmatic from PyPi or distro packages
- Set up Borgmatic config
- Schedule regular backups using Cron or Systemd timer
## Breaking changes
- Older versions of this role set up a separate Cron job for creating and checking
backups. With recent Borgmatic version, this feature is now managed in Borgmatic.
As a result the extra Cron job will be removed by this role.
- Older versions of this role only supported Cron for scheduling. If you use
Systemd timers, be sure to remove the Cron job in `/etc/cron.d/borgmatic` first.
The role will also alert you when trying to use both timers.
## Example Playbook
## Example playbook with root as backup user and Cron timer
```
- hosts: webservers
- hosts: all
roles:
- role: m3nu.ansible_role_borgbackup
borg_encryption_passphrase: CHANGEME
borg_repository: m5vz9gp4@m5vz9gp4.repo.borgbase.com:repo
borg_repository: ssh://xxxxxx@xxxxxx.repo.borgbase.com/./repo
borg_source_directories:
- /srv/www
- /var/lib/automysqlbackup
borg_exclude_patterns:
- /srv/www/old-sites
borg_retention_policy:
keep_hourly: 3
keep_daily: 7
keep_weekly: 4
keep_monthly: 6
- /var/www
borgmatic_hooks:
before_backup:
- echo "`date` - Starting backup."
@ -37,8 +36,28 @@ Main features:
- name: users
hostname: database1.example.org
port: 5433
```
## Example playbook with service user and Systemd timer
```
- hosts: all
roles:
- role: m3nu.ansible_role_borgbackup
borg_encryption_passphrase: CHANGEME
borg_repository: ssh://xxxxxx@xxxxxx.repo.borgbase.com/./repo
borgmatic_timer: systemd
borg_user: "backupuser"
borg_group: "backupuser"
borg_source_directories:
- /var/www
borg_retention_policy:
keep_hourly: 3
keep_daily: 7
keep_weekly: 4
keep_monthly: 6
```
## Installation
@ -56,39 +75,47 @@ $ git clone https://github.com/borgbase/ansible-role-borgbackup.git roles/ansibl
## Role Variables
### Required Arguments
- `borg_repository`: Full path to repository. Your own server or [BorgBase.com](https://www.borgbase.com) repo. Not required when using auto creation of repositories. Can be a list if you want to backup to multiple repositories.
- `borg_source_directories`: List of local folders to back up.
### Required Variables
- `borg_repository`: Full path to repository. Your own server or [BorgBase.com](https://www.borgbase.com) repo.
Can be a list if you want to backup to multiple repositories.
### Optional Arguments
### Optional Variables
- `borg_dep_packages`: Dependency Packages to install `borg(backup)` and `borgmatic`.
- `borg_distro_packages`: contains the names of distributions packages for `borg(backup)` and `borgmatic`, only used if `borg_install_method` is set to `package`.
- `borg_encryption_passcommand`: The standard output of this command is used to unlock the encryption key.
- `borg_encryption_passphrase`: Password to use for repokey or keyfile. Empty if repo is unencrypted.
- `borg_exclude_from`: Read exclude patterns from one or more separate named files, one pattern per line.
- `borg_exclude_patterns`: Paths or patterns to exclude from backup. See [official documentation](https://borgbackup.readthedocs.io/en/stable/usage/help.html#borg-help-patterns) for more.
- `borg_install_method`: By default `pip` is used to install borgmatic. To install via your distributions package manager set this to `package` and (if needed) overwrite the `borg_distro_packages` variable to contain your distributions package names required to install borgmatic. Note that many distributions ship outdated versions of borgbackup and borgmatic; use at your own risk.
- `borg_lock_wait_time`: Config maximum seconds to wait for acquiring a repository/cache lock. Defaults to 5 seconds.
- `borg_one_file_system`: Don't cross file-system boundaries. Defaults to `true`
- `borg_pip_packages`: Dependancy Packages (pip) to install `borg(backup)` and `borgmatic`.
- `borg_remote_path`: Path to the borg executable on the remote. It will default to `borg`.
- `borg_remote_rate_limit`: Remote network upload rate limit in kiBytes/second.
- `borg_retention_policy`: Retention policy for how many backups to keep in each category (daily, weekly, monthly, etc).
- `borg_ssh_command`: Command to use instead of just "ssh". This can be used to specify ssh options.
- `borg_source_directories`: List of local folders to back up. Default is `/etc/hostname` to prevent an empty backup.
- `borg_ssh_key_name`: Name of the SSH public and pivate key. Default `id_ed25519`
- `borg_ssh_key_file_path`: SSH-key to be used. Default `~/.ssh/{{ borg_ssh_key_name }}`
- `borg_ssh_key_type`: The algorithm used to generate the SSH private key. Choose: `rsa`, `dsa`, `rsa1`, `ecdsa`, `ed25519`. Default: `ed25519`
- `borg_ssh_command`: Command to use instead of just "ssh". This can be used to specify SSH options.
- `borg_version`: Force a specific borg version to be installed
- `borg_venv_path`: Path to store the venv for `borg(backup)` and `borgmatic`
- `borgmatic_check_last`: Number of archives to check. Defaults to `3`
- `borgmatic_checks`: List of consistency checks. Defaults to `['repository']`
- `borgmatic_config_name`: Name to use for the borgmatic config file. Defaults to `config.yaml`
- `borgmatic_cron_checks_day`: Day when cron job for infrequent checks will run. Defaults to `{{ 28 | random }}`
- `borgmatic_cron_checks_hour`: Hour when cron job for infrequent checks will run. Defaults to `{{ range(7, 24) | random }}`
- `borgmatic_cron_checks_minute`: Minute when cron job for infrequent checks will run. Defaults to `{{ 59 | random }}`
- `borgmatic_cron_hour`: Hour when regular create and prune cron job will run. Defaults to `{{ 6 | random }}`
- `borgmatic_cron_minute`: Minute when regular create and prune cron job will run. Defaults to `{{ 59 | random }}`
- `borgmatic_checks`: List of consistency checks. Defaults to monthly checks. See [docs](https://torsion.org/borgmatic/docs/how-to/deal-with-very-large-backups/#check-frequency) for all options.
- `borgmatic_config_name`: Name to use for the Borgmatic config file. Defaults to `config.yaml`
- `borgmatic_timer_hour`: Hour when regular create and prune cron/systemd-timer job will run. Defaults to `{{ 6 | random }}`
- `borgmatic_timer_minute`: Minute when regular create and prune cron/systemd-timer job will run. Defaults to `{{ 59 | random }}`
- `borgmatic_hooks`: Hooks to monitor your backups e.g. with [Healthchecks](https://healthchecks.io/). See [official documentation](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/) for more.
- `borgmatic_large_repo`: Less frequent, monthly repo checking. Defaults to `true`
- `borgmatic_timer`: If the variable is set, a timer is installed. A choice must be made between `cron` and `systemd`.
- `borgmatic_relocated_repo_access_is_ok`: Bypass Borg error about a repository that has been moved. Defaults to `false`
- `borgmatic_store_atime`: Store atime into archive. Defaults to `true`
- `borgmatic_store_ctime`: Store ctime into archive. Defaults to `true`
- `ssh_key_file`: Path to a private ssh key file (default is `.ssh/id_ed25519`). It generates a ed25519 key if the file doesn't exist yet.
- `borg_version`: Force a specific borg version to be installed
- `borgmatic_version`: Force a specific borgmatic version to be installed
- `borg_install_method`: By default `pip` is used to install borgmatic. To install via your distributions package manager set this to `package` and (if needed) overwrite the `borg_distro_packages` variable to contain your distributions package names required to install borgmatic. Note that many distributions ship outdated versions of borgbackup and borgmatic; use at your own risk.
- `borg_distro_packages`: contains the names of distributions packages for `borg(backup)` and `borgmatic`, only used if `borg_install_method` is set to `package`.
- `borg_user`: Name of the User to create Backups (service account)
- `borg_group`: Name of the Group to create Backups (service account)
## Contributing
@ -105,4 +132,4 @@ MIT/BSD
## Author
© 2018-2020 Manuel Riel and contributors.
© 2018-2023 Manuel Riel and contributors.

@ -1,25 +1,13 @@
---
borg_encryption_passphrase: ''
borg_exclude_patterns: []
borgmatic_config_name: config.yaml
borgmatic_large_repo: true
borgmatic_hooks:
on_error:
- echo "`date` - Error while creating a backup."
before_backup:
- echo "`date` - Starting backup."
after_backup:
- echo "`date` - Finished backup."
borgmatic_checks:
- repository
borgmatic_check_last: 3
borgmatic_store_atime: true
borgmatic_store_ctime: true
borgmatic_relocated_repo_access_is_ok: false
borg_one_file_system: true
borg_exclude_from: []
borg_encryption_passcommand: false
borg_lock_wait_time: 5
borg_ssh_key_type: "ed25519"
borg_ssh_key_name: "id_{{ borg_ssh_key_type }}"
borg_ssh_key_file_path: "{{ backup_user_info.home }}/.ssh/{{ borg_ssh_key_name }}"
borg_ssh_command: false
borg_remote_path: false
borg_remote_rate_limit: 0
@ -28,13 +16,33 @@ borg_retention_policy:
keep_daily: 7
keep_weekly: 4
keep_monthly: 6
ssh_key_file: .ssh/id_ed25519
borgmatic_cron_name: borgmatic
borgmatic_cron_hour: "{{ 6 | random(seed=inventory_hostname) }}"
borgmatic_cron_minute: "{{ 59 | random(seed=inventory_hostname) }}"
borgmatic_cron_checks_day: "{{ range(1, 28) | random(seed=inventory_hostname) }}"
borgmatic_cron_checks_hour: "{{ range(9, 24) | random(seed=inventory_hostname) }}"
borgmatic_cron_checks_minute: "{{ 59 | random(seed=inventory_hostname) }}"
borg_version: false
borgmatic_timer_cron_name: "borgmatic"
borgmatic_timer: cron
borgmatic_timer_hour: "{{ range(0, 5) | random(seed=inventory_hostname) }}"
borgmatic_timer_minute: "{{ range(0, 59) | random(seed=inventory_hostname) }}"
borg_install_method: "pip"
borgmatic_config_name: config.yaml
borgmatic_hooks:
on_error:
- echo "`date` - Error while creating a backup."
before_backup:
- echo "`date` - Starting backup."
after_backup:
- echo "`date` - Finished backup."
borgmatic_checks:
- name: repository
frequency: "4 weeks"
- name: archives
frequency: "6 weeks"
borgmatic_check_last: 3
borgmatic_store_atime: true
borgmatic_store_ctime: true
borgmatic_relocated_repo_access_is_ok: false
borgmatic_version: false
borg_install_method: pip
borg_venv_path: "/opt/borgmatic"
borg_user: "root"
borg_group: "root"
...

@ -0,0 +1,182 @@
argument_specs:
main:
# https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html#role-argument-validation
# https://docs.ansible.com/ansible/latest/dev_guide/developing_program_flow_modules.html#argument-spec
short_description: Role to install borgbackup and borgmatic.
description: Role to install borgbackup and borgmatic
author:
- 2018-2020 Manuel Riel and contributors.
- Frank Dornheim
options:
borg_dep_packages:
type: str
required: false
description: Dependancy Packages to install borg(backup) and borgmatic.
borg_distro_packages:
type: str
required: false
description: |
Contains the names of distributions packages for borg(backup) and borgmatic,
only used if `borg_install_method` is set to package
borg_pip_packages:
type: str
required: false
description: Dependancy Packages (pip) to install borg(backup) and borgmatic.
borg_venv_path:
type: str
required: false
description: Path to store the venv for borg(backup) and borgmatic.
borg_install_method:
type: str
required: false
default: pip
description: |
By default pip is used to install borgmatic.
To install via your distributions package manager set this to package and (if needed)
overwrite the borg_distro_packages variable to contain your distributions package names
required to install borgmatic.
Note that many distributions ship outdated versions of borgbackup and borgmatic; use at your own risk.
borgmatic_config_name:
type: str
required: false
default: config.yaml
description: Name to use for the borgmatic config file.
borg_user:
type: str
default: root
description: Name of the User to create Backups (Service Account)
borg_group:
type: str
default: root
description: Name of the Group to create Backups (Service Account)
borg_source_directories:
type: List
default: "/etc/hostname"
required: false
description: List of local folders to back up.
borg_one_file_system:
type: str
required: false
description: Don't cross file-system boundaries.
borg_repository:
type: List
required: true
description: |
Full path to repository.
Your own server or [BorgBase.com](https://www.borgbase.com) repo.
Not required when using auto creation of repositories.
Can be a list if you want to backup to multiple repositories.
borgmatic_store_atime:
type: bool
required: false
description: Store atime into archive.
borgmatic_store_ctime:
type: bool
required: false
description: Store ctime into archive.
borg_exclude_patterns:
type: List
required: false
description: Any paths matching these patterns are excluded from backups. Globs and tildes are expanded.
borg_exclude_from:
type: List
required: false
description: Read exclude patterns from one or more separate named files, one pattern per line.
borg_remote_path:
type: str
required: false
description: Alternate Borg remote executable. Defaults to "borg"
borg_encryption_passphrase:
type: str
description: |
The standard output of this command is used to unlock the encryption key.
Only use on repositories that were initialized with passcommand/repokey encryption.
Note that if both encryption_passcommand and encryption_passphrase are set,
then encryption_passphrase takes precedence.
borg_encryption_passcommand:
type: str
required: false
description: secret-tool lookup borg-repository repo-name
borg_remote_rate_limit:
type: int
required: false
description: Remote network upload rate limit in kiBytes/second.
borg_ssh_key_file_path:
type: str
required: false
description: Path to ssh-key
borg_ssh_command:
type: str
description: Command to use instead of just ssh. This can be used to specify ssh options.
borg_lock_wait_time:
type: int
description: Maximum seconds to wait for acquiring a repository/cache lock.
borgmatic_relocated_repo_access_is_ok:
type: bool
description: Bypass Borg error about a repository that has been moved.
borg_retention_policy:
keep_secondly:
type: int
required: false
description: Number of secondly archives to keep.
keep_minutely:
type: int
required: false
description: Number of minutely archives to keep.
keep_hourly:
type: int
required: false
description: Number of hourly archives to keep.
keep_daily:
type: int
required: false
description: Number of daily archives to keep.
keep_weekly:
type: int
required: false
description: Number of weekly archives to keep.
keep_monthly:
type: int
required: false
description: Number of monthly archives to keep.
keep_yearly:
type: int
required: false
description: Number of yearly archives to keep.
borgmatic_checks:
type: List
required: false
description: |
List of one or more consistency checks to run
"repository", "archives", "data", and/or "extract".
Defaults to "repository" and "archives".
Set to "disabled" to disable all consistency checks.
"repository" checks the consistency of the repository,
"archives" checks all of the archives, "data" verifies
the integrity of the data within the archives, and
"extract" does an extraction dry-run of the most recent archive.
Note that "data" implies "archives".
borgmatic_check_last:
type: int
required: false
description: Restrict the number of checked archives to the last n. Applies only to the "archives" check.
borgmatic_hooks:
type: dict
required: false
description: Shell commands or scripts to execute before and after a backup or if an error has occurred.
borgmatic_timer_cron_name:
type: str
required: false
description: Name of the cron Job
borgmatic_timer:
type: str
required: false
description: If the variable is set, a timer is installed. A choice must be made between "cron" and "systemd".
borg_ssh_key_type:
type: str
required: false
description: The algorithm used to generate the SSH private key
borg_ssh_key_name:
type: str
required: false
description: Name of the SSH public and private key

@ -8,7 +8,7 @@ galaxy_info:
description: Set up backup to remote machine using Borg and Borgmatic.
company: "BorgBase.com"
license: license (BSD, MIT)
min_ansible_version: 2.0
min_ansible_version: "2.0"
platforms:
- name: Debian
versions:

@ -19,8 +19,10 @@
roles:
- role: m3nu.ansible_role_borgbackup
borg_encryption_passphrase: CHANGEME
borg_install_method: pip
borgmatic_timer: cron
borg_repository: m5vz9gp4@m5vz9gp4.repo.borgbase.com:repo
borg_encryption_passphrase: CHANGEME
borg_source_directories:
- /srv/www
- /var/lib/automysqlbackup
@ -38,7 +40,6 @@
- name: users
hostname: database1.example.org
port: 5433
borg_install_method: pip
post_tasks:
- name: Install yamllint for checking config file

@ -6,18 +6,12 @@ driver:
platforms:
- name: archlinux-latest
image: archlinux:latest
- name: centos-7
image: centos:7
- name: almalinux-8
image: almalinux:8
- name: almalinux-9
image: almalinux:9
- name: fedora-latest
image: fedora:latest
- name: debian-bullseye
image: debian:bullseye
- name: ubuntu-bionic
image: ubuntu:bionic
- name: ubuntu-latest
image: ubuntu:latest
provisioner:

@ -0,0 +1,29 @@
---
- name: Install borgbackup
block:
- name: Ensure legacy hooks aren't used
ansible.builtin.assert:
that:
- borgmatic_failure_command is undefined
- borgmatic_before_backup_command is undefined
- borgmatic_after_backup_command is undefined
msg: Please use the new borgmatic_hooks variable instead of individual before/after/failure hooks.
- name: Include OS-specific variables
include_vars: "{{ item }}"
with_first_found:
- "{{ ansible_distribution }}-{{ ansible_distribution_major_version }}.yml"
- "{{ ansible_os_family }}-{{ ansible_distribution_major_version }}.yml"
- "{{ ansible_distribution }}.yml"
- "{{ ansible_os_family }}.yml"
- "{{ ansible_lsb.id }}.yml"
- name: Install general dependencies (openssh)
ansible.builtin.package:
name: "{{ borg_dep_packages }}"
state: present
- name: Install Borg and Borgmatic
ansible.builtin.include_tasks:
file: noauto_install_{{ borg_install_method }}.yml
...

@ -0,0 +1,25 @@
---
# So in different positions in that role we need the user home
# Since we cannot be sure that this FSH is compatible we will determine it.
- name: Get home dir
when:
- borg_user == "root"
block:
- name: Get home if borg_user == "root"
ansible.builtin.user:
name: "{{ borg_user }}"
state: present
register: user_info
changed_when: false
check_mode: true # Important, otherwise user will be created
- name: Save the user_info, we need them for the home_dir
ansible.builtin.set_fact:
backup_user_info: "{{ user_info }}"
- name: Create user if borg_user != "root"
when:
- borg_user != "root"
ansible.builtin.include_tasks:
file: noauto_create_backup_user_and_group.yml
...

@ -0,0 +1,28 @@
---
- name: Create SSH key (if neeeded) for {{ borg_user }}
block:
- name: Ensure directory exist
ansible.builtin.file:
path: "{{ backup_user_info.home }}/.ssh/"
state: directory
mode: "0700"
owner: "{{ borg_user }}"
group: "{{ borg_group }}"
- name: Generate an OpenSSH keypair
community.crypto.openssh_keypair:
path: "{{ borg_ssh_key_file_path }}"
mode: "0600"
type: "{{ borg_ssh_key_type }}"
owner: "{{ borg_user }}"
group: "{{ borg_group }}"
- name: Read SSH key
ansible.builtin.slurp:
src: "{{ borg_ssh_key_file_path }}.pub"
register: backup_local_ssh_key
- name: Print key
ansible.builtin.debug:
msg: "The generated key is: {{ backup_local_ssh_key['content'] | b64decode }}"
...

@ -0,0 +1,19 @@
---
- name: Add Borgmatic config file
block:
- name: Ensure /etc/borgmatic exists
ansible.builtin.file:
path: /etc/borgmatic
state: directory
mode: "0700"
owner: "{{ borg_user }}"
group: "{{ borg_group }}"
- name: Add Borgmatic configuration
ansible.builtin.template:
src: config.yaml.j2
dest: "/etc/borgmatic/{{ borgmatic_config_name }}"
mode: "0600"
owner: "{{ borg_user }}"
group: "{{ borg_group }}"
...

@ -0,0 +1,8 @@
---
- name: Install timer to run Borgmatic
when:
- borgmatic_timer is defined and borgmatic_timer | length > 0
block:
- name: Start timer install script
ansible.builtin.include_tasks:
file: noauto_create_timer_{{ borgmatic_timer }}.yml

@ -1,18 +0,0 @@
---
- name: Check if EPEL repo is enabled, if installation from distro is requested
when: ansible_os_family == 'RedHat'
block:
- name: Get list of installed packages
ansible.builtin.package_facts:
manager: auto
- name: Ensure EPEL is enabled
ansible.builtin.assert:
that:
- "'epel-release' in ansible_facts.packages"
fail_msg: Need EPEL repo to install via distro package.
- name: Install borgmatic and borg via distribution package manager
package:
name: "{{ item }}"
state: present
loop: "{{ borg_distro_packages }}"

@ -1,39 +0,0 @@
---
- name: Install build dependencies
package:
name: "{{ borg_pip_packages }}"
state: present
- name: Create virtualenv for borg # noqa package-latest
pip:
name:
- pip
- setuptools
state: latest
virtualenv: /opt/borgmatic
virtualenv_command: "{{ python_bin }} -m venv"
- name: Install dependent Python Packages
pip:
name: "{{ borg_dependent_python_packages }}"
virtualenv: /opt/borgmatic
when: borg_dependent_python_packages is defined
- name: Install main Python Packages
pip:
name: "{{ item.name }}"
version: "{{ item.version | default(omit, true) }}"
virtualenv: /opt/borgmatic
when: borg_python_packages is defined
loop: "{{ borg_python_packages }}"
- name: Create borgmatic command in /usr/local/bin
copy:
content: |
#!/bin/bash
. /opt/borgmatic/bin/activate
borgmatic "$@"
dest: /usr/local/bin/borgmatic
owner: root
group: root
mode: "0755"

@ -1,96 +1,7 @@
---
- name: Ensure legacy hooks aren't used
assert:
that:
- borgmatic_failure_command is undefined
- borgmatic_before_backup_command is undefined
- borgmatic_after_backup_command is undefined
msg: Please use the new borgmatic_hooks variable instead of individual before/after/failure hooks.
- name: Include OS-specific variables
include_vars: "{{ item }}"
with_first_found:
- "{{ ansible_distribution }}-{{ ansible_distribution_major_version }}.yml"
- "{{ ansible_os_family }}-{{ ansible_distribution_major_version }}.yml"
- "{{ ansible_distribution }}.yml"
- "{{ ansible_os_family }}.yml"
- "{{ ansible_lsb.id }}.yml"
- name: Install general dependencies (cron and openssh)
package:
name: "{{ borg_dep_packages }}"
state: present
- name: Install Borg and Borgmatic
ansible.builtin.include_tasks:
file: install_{{ borg_install_method }}.yml
- name: Ensure root has SSH key.
user:
name: "root"
generate_ssh_key: yes
ssh_key_file: "{{ ssh_key_file }}"
ssh_key_type: ed25519
register: root_user
- name: Print key created for root user (use for remote repo)
debug:
var: root_user['ssh_public_key']
- name: Ensure /etc/borgmatic exists
file:
path: /etc/borgmatic
state: directory
mode: 0700
owner: root
- name: Add Borgmatic configuration
template:
src: config.yaml.j2
dest: "/etc/borgmatic/{{ borgmatic_config_name }}"
mode: 0600
- name: Add cron-job for borgmatic (large repo, create and check separate)
block:
- name: Add cron job for regular create and prune
cron:
name: "{{ borgmatic_cron_name }}"
hour: "{{ borgmatic_cron_hour }}"
minute: "{{ borgmatic_cron_minute }}"
user: "root"
cron_file: "{{ borgmatic_cron_name }}"
job: "borgmatic -c /etc/borgmatic/{{ borgmatic_config_name }} -C -p"
- name: Add cron job for infrequent checks
cron:
name: "{{ borgmatic_cron_name }}-check"
day: "{{ borgmatic_cron_checks_day }}"
hour: "{{ borgmatic_cron_checks_hour }}"
minute: "{{ borgmatic_cron_checks_minute }}"
user: "root"
cron_file: "{{ borgmatic_cron_name }}"
job: "borgmatic -c /etc/borgmatic/{{ borgmatic_config_name }} -k"
when: borgmatic_large_repo
- name: Add cron-job for borgmatic (normal-sized repo)
block:
- name: Add cron job for create, check and prune
cron:
name: "{{ borgmatic_cron_name }}"
hour: "{{ borgmatic_cron_hour }}"
minute: "{{ borgmatic_cron_minute }}"
user: "root"
cron_file: "{{ borgmatic_cron_name }}"
job: "borgmatic -c /etc/borgmatic/{{ borgmatic_config_name }}"
- name: Ensure separate check cron job is absent
cron:
name: "{{ borgmatic_cron_name }}-check"
state: absent
when: not borgmatic_large_repo
- name: Set PATH for borgmatic cron job.
cron:
user: "root"
cron_file: "{{ borgmatic_cron_name }}"
name: PATH
env: yes
value: /usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
- name: Add and run all plays
include_tasks: "{{ bak_element }}"
with_items: "{{ lookup('ansible.builtin.fileglob', '*.yml').split(',') | reject('search', 'main.yml') | reject('search', 'noauto_*') | sort }}"
loop_control:
loop_var: bak_element
...

@ -0,0 +1,34 @@
---
- name: Setup backup environment
when:
- backup_create_local_user is not defined or backup_create_local_user
- borg_user != "root"
block:
- name: Add local backup group
ansible.builtin.group:
name: "{{ borg_group }}"
state: present
- name: Add local backup user
ansible.builtin.user:
name: "{{ borg_user }}"
shell: "/bin/bash"
groups: "{{ borg_group }}"
comment: "Backup User Account"
append: true
register: user_info
- name: Save the user_info, we need them for the home_dir
ansible.builtin.set_fact:
backup_user_info: "{{ user_info }}"
- name: Add sudo users
community.general.sudoers:
name: "backup"
state: present
user: "{{ borg_user }}"
nopassword: true
commands:
- "/opt/borgmatic/bin/borg"
- "/usr/local/bin/borgmatic -c /etc/borgmatic/{{ borgmatic_config_name }}"
...

@ -0,0 +1,31 @@
---
- name: Ensure Cron is installed
ansible.builtin.package:
name: "{{ borg_cron_package }}"
state: present
- name: Add Cron job for borgmatic
block:
- name: Add single Cron job for borgmatic
cron:
name: "{{ borgmatic_timer_cron_name }}"
hour: "{{ borgmatic_timer_hour }}"
minute: "{{ borgmatic_timer_minute }}"
user: "{{ borg_user }}"
cron_file: "{{ borgmatic_timer_cron_name }}"
job: "borgmatic -c /etc/borgmatic/{{ borgmatic_config_name }}"
- name: Ensure separate check cron job is absent
cron:
name: "{{ borgmatic_timer_cron_name }}-check"
cron_file: "{{ borgmatic_timer_cron_name }}"
state: absent
- name: Set PATH for borgmatic cron job.
cron:
user: "{{ borg_user }}"
cron_file: "{{ borgmatic_timer_cron_name }}"
name: PATH
env: yes
value: /usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
...

@ -0,0 +1,63 @@
---
- name: Register existence of Borgmatic cron file.
cron:
name: "{{ borgmatic_timer_cron_name }}"
cron_file: "{{ borgmatic_timer_cron_name }}"
state: absent
check_mode: true
register: cron_file_exists
- name: Ensure no Borgmatic Cron file exists.
ansible.builtin.assert:
that:
- not cron_file_exists.changed
fail_msg: Found an existing Borgmatic Cron job. Please remove before using Systemd timer.
- name: Create borgbackup timer
block:
- name: Copy systemd files
ansible.builtin.template:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
owner: root
group: root
backup: true
mode: "{{ item.mode }}"
with_items:
- { src: "borgmatic.timer.j2", dest: "/usr/lib/systemd/system/borgmatic.timer", mode: "0644" }
- { src: "borgmatic.service.j2", dest: "/usr/lib/systemd/system/borgmatic.service", mode: "0644" }
- name: Populate service facts
ansible.builtin.service_facts:
# If the role is running and the repo is not yet initialized, an error will occur.
# Therefore the service is stopped by default and must be started manually.
- name: Stop fresh installed borgmatic.timer and borgmatic.service
when: "'borgmatic.service' not in ansible_facts.services"
block:
- name: Set borgmatic services to stopped - newly installed
ansible.builtin.systemd:
name: "{{ item }}"
state: stopped
enabled: false
masked: false
daemon_reload: true
when: item in ansible_facts.services
with_items:
- borgmatic.service
# bug: Need own section without masked else the timer are skipped
- name: Set borgmatic timers to stopped - newly installed
ansible.builtin.systemd:
name: "{{ item }}"
state: stopped
enabled: false
daemon_reload: true
with_items:
- "borgmatic.timer"
- name: Show hints
when: "'backup_init_repo' not in ansible_run_tags"
ansible.builtin.debug:
msg: "Attention: Since the repo was not initialized automatically, the systemd service (borgmatic.service) and the timer (borgmatic.timer) are not activated."
...

@ -0,0 +1,21 @@
---
- name: Install borgbackup by distro
block:
- name: Check if EPEL repo is enabled, if installation from distro is requested
when: ansible_os_family == 'RedHat'
block:
- name: Get list of installed packages
ansible.builtin.package_facts:
manager: auto
- name: Ensure EPEL is enabled
ansible.builtin.assert:
that:
- "'epel-release' in ansible_facts.packages"
fail_msg: Need EPEL repo to install via distro package.
- name: Install borgmatic and borg via distribution package manager
ansible.builtin.package:
name: "{{ item }}"
state: present
loop: "{{ borg_distro_packages }}"
...

@ -0,0 +1,51 @@
---
- name: Install Borg and Borgmatic via pip
block:
- name: Install build dependencies
ansible.builtin.package:
name: "{{ borg_pip_packages }}"
state: present
- name: Create virtualenv for borg # noqa package-latest
ansible.builtin.pip:
name:
- pip
- setuptools
state: latest
virtualenv: "{{ borg_venv_path }}"
virtualenv_command: "{{ python_bin }} -m venv"
- name: Install dependent Python packages
ansible.builtin.pip:
name: "{{ borg_dependent_python_packages }}"
virtualenv: "{{ borg_venv_path }}"
when: borg_dependent_python_packages is defined
- name: Install main Python packages
ansible.builtin.pip:
name: "{{ item.name }}"
version: "{{ item.version | default(omit, true) }}"
virtualenv: "{{ borg_venv_path }}"
when: borg_python_packages is defined
loop: "{{ borg_python_packages }}"
- name: Create links to Borgmatic and Borg binaries
block:
- name: Create borgmatic command in /usr/local/bin
ansible.builtin.copy:
content: |
#!/bin/bash
. "{{ borg_venv_path }}"/bin/activate
borgmatic "$@"
dest: /usr/local/bin/borgmatic
mode: "0755"
- name: Create borg command in /usr/local/bin
ansible.builtin.copy:
content: |
#!/bin/bash
. "{{ borg_venv_path }}"/bin/activate
borg "$@"
dest: /usr/local/bin/borg
mode: "0755"
...

@ -0,0 +1,60 @@
# Managed by Ansible, please don't edit manually
[Unit]
Description=borgmatic backup
Wants=backup_normal_repo.timer
Wants=network-online.target
After=network-online.target
# Prevent borgmatic from running unless the machine is plugged into power. Remove this line if you
# want to allow borgmatic to run anytime.
ConditionACPower=true
[Service]
Type=oneshot
User={{ borg_user }}
ExecStart=borgmatic -c /etc/borgmatic/{{ borgmatic_config_name }}
# Source: https://projects.torsion.org/borgmatic-collective/borgmatic/raw/branch/master/sample/systemd/borgmatic.service
# 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", "ReadOnlyPaths", "ProtectHome", and "BindPaths". Then add any local repository
# paths to the list of "ReadWritePaths" and local backup source paths to "ReadOnlyPaths". This
# leaves most of the filesystem read-only to borgmatic.
ProtectSystem=full
# ReadWritePaths=-/mnt/my_backup_drive
# ReadOnlyPaths=-/var/lib/my_backup_source
# This will mount a tmpfs on top of /root and pass through needed paths
# ProtectHome=tmpfs
# BindPaths=-/root/.cache/borg -/root/.config/borg -/root/.borgmatic
# 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

@ -0,0 +1,13 @@
# Managed by Ansible, please don't edit manually
[Unit]
Description=Start creating of Backups - see: https://www.freedesktop.org/software/systemd/man/systemd.time.html#
[Timer]
# Day-of-the-Week Year-Month-Day Hour:Minutes:Seconds
# Persistent -> resume backup after shutdown
OnCalendar= *-*-* {{ borgmatic_timer_hour }}:{{ borgmatic_timer_minute }}:00
Persistent=true
[Install]
WantedBy=timers.target

@ -1,11 +1,18 @@
#jinja2: lstrip_blocks: "True", trim_blocks: "True"
---
# Managed by Ansible, please don't edit manually
# Full config: https://torsion.org/borgmatic/docs/reference/config.yaml
location:
{% if borg_source_directories is not defined or borg_source_directories | length == 0 %}
source_directories:
- /etc/hostname # prevent empty backupconfig
{% else %}
source_directories:
{% for dir in borg_source_directories %}
{% for dir in borg_source_directories %}
- {{ dir }}
{% endfor %}
{% endfor %}
{% endif %}
# Stay in same file system (do not cross mount points).
one_file_system: {{ borg_one_file_system }}

@ -1,8 +1,9 @@
---
borg_dep_packages:
- cronie
- openssh
borg_cron_package: cronie
borg_pip_packages:
- gcc
- pkgconfig

@ -1,7 +1,8 @@
---
borg_dep_packages:
- openssh-client
- cron
borg_cron_package: cron
borg_pip_packages:
- libssl-dev

@ -1,8 +1,9 @@
---
borg_dep_packages:
- cronie
- openssh-clients
borg_cron_package: cronie
borg_pip_packages:
- libacl-devel
- libacl

@ -1,7 +1,8 @@
---
borg_dep_packages:
- openssh
- cronie
borg_cron_package: cronie
borg_pip_packages: # untested
- libssl-dev

@ -1,7 +1,8 @@
---
borg_dep_packages:
- openssh-clients
- cronie
borg_cron_package: cronie
borg_pip_packages:
- libacl-devel

@ -1,8 +1,9 @@
---
borg_dep_packages:
- cronie
- openssh-clients
borg_cron_package: cronie
borg_pip_packages:
- libacl-devel
- libacl

@ -1,8 +1,9 @@
---
borg_dep_packages:
- cronie
- openssh-clients
borg_cron_package: cronie
borg_pip_packages:
- libacl-devel
- libacl

Loading…
Cancel
Save