Merge branch 'borgbase:master' into add_compression_possibility

This commit is contained in:
kaufe 2023-07-26 09:03:15 +02:00 committed by GitHub
commit fbe31b567a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 831 additions and 246 deletions

View File

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

129
EXAMPLES.md Normal file
View File

@ -0,0 +1,129 @@
# Additional Examples
## Custom SSH key for backups only
```
- hosts: webservers
roles:
- role: borgbase.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"
```

103
README.md
View File

@ -1,35 +1,35 @@
# Ansible Role: BorgBackup Client # Ansible Role: BorgBackup Client
[![Test](https://github.com/borgbase/ansible-role-borgbackup/actions/workflows/main.yml/badge.svg)](https://github.com/borgbase/ansible-role-borgbackup/actions/workflows/main.yml) [![Ansible Galaxy](https://img.shields.io/ansible/role/48519)](https://galaxy.ansible.com/m3nu/ansible_role_borgbackup) [![Test](https://github.com/borgbase/ansible-role-borgbackup/actions/workflows/main.yml/badge.svg)](https://github.com/borgbase/ansible-role-borgbackup/actions/workflows/main.yml) [![Ansible Galaxy](https://img.shields.io/ansible/role/48519)](https://galaxy.ansible.com/borgbase/ansible_role_borgbackup)
Set up encrypted, compressed and deduplicated backups using [BorgBackup](https://borgbackup.readthedocs.io/en/stable/) and [Borgmatic](https://github.com/witten/borgmatic). Currently supports Debian/Ubuntu, CentOS/Red Hat/Fedora, Archlinux and Manjaro. Set up encrypted, compressed and deduplicated backups using [BorgBackup](https://borgbackup.readthedocs.io/en/stable/) and [Borgmatic](https://github.com/witten/borgmatic). Currently supports Debian/Ubuntu, CentOS/Red Hat/Fedora, Archlinux and Manjaro.
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). 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: **Main features**
- Set up Borg and Borgmatic - Install Borg and Borgmatic from PyPi or distro packages
- Add cron job at random time - Set up Borgmatic config
- Provision new remote [BorgBase.com](https://www.borgbase.com) repo for storing backups (optional) - 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: roles:
- role: m3nu.ansible_role_borgbackup - role: borgbase.ansible_role_borgbackup
borg_encryption_passphrase: CHANGEME borg_encryption_passphrase: CHANGEME
borg_repository: m5vz9gp4@m5vz9gp4.repo.borgbase.com:repo borg_repository:
- ssh://xxxxxx@xxxxxx.repo.borgbase.com/./repo
borg_source_directories: borg_source_directories:
- /srv/www - /var/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: borgmatic_hooks:
before_backup: before_backup:
- echo "`date` - Starting backup." - echo "`date` - Starting backup."
@ -37,15 +37,35 @@ Main features:
- name: users - name: users
hostname: database1.example.org hostname: database1.example.org
port: 5433 port: 5433
```
## Example playbook with service user and Systemd timer
``` ```
- hosts: all
roles:
- role: borgbase.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 ## Installation
Download from Ansible Galaxy Download from Ansible Galaxy
``` ```
$ ansible-galaxy install m3nu.ansible_role_borgbackup $ ansible-galaxy install borgbase.ansible_role_borgbackup
``` ```
Clone latest version from Github Clone latest version from Github
@ -56,39 +76,48 @@ $ git clone https://github.com/borgbase/ansible-role-borgbackup.git roles/ansibl
## Role Variables ## Role Variables
### Required Arguments ### Required Variables
- `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_repository`: Full path to repository. Your own server or [BorgBase.com](https://www.borgbase.com) repo.
- `borg_source_directories`: List of local folders to back up. 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_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_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_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_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_require_epel`: When using `borg_install_method: package` on RHEL-based distributions, the EPEL repo is required. To disable the check (e.g. when using a custom mirror instead of the `epel-release` package), set this to `false`. Defaults to `{{ ansible_os_family == 'RedHat' and ansible_distribution != 'Fedora' }}` (i.e. `true` on Enterprise Linux-based distros).
- `borg_lock_wait_time`: Config maximum seconds to wait for acquiring a repository/cache lock. Defaults to 5 seconds. - `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_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_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_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_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_check_last`: Number of archives to check. Defaults to `3`
- `borgmatic_checks`: List of consistency checks. Defaults to `['repository']` - `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_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_timer_hour`: Hour when regular create and prune cron/systemd-timer job will run. Defaults to `{{ 6 | random }}`
- `borgmatic_cron_checks_hour`: Hour when cron job for infrequent checks will run. Defaults to `{{ range(7, 24) | random }}` - `borgmatic_timer_minute`: Minute when regular create and prune cron/systemd-timer job will run. Defaults to `{{ 59 | 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_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_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_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_atime`: Store atime into archive. Defaults to `true`
- `borgmatic_store_ctime`: Store ctime 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 - `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 ## Contributing
@ -105,4 +134,4 @@ MIT/BSD
## Author ## Author
© 2018-2020 Manuel Riel and contributors. © 2018-2023 Manuel Riel and contributors.

View File

@ -1,25 +1,13 @@
--- ---
borg_encryption_passphrase: '' borg_encryption_passphrase: ''
borg_exclude_patterns: [] 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_one_file_system: true
borg_exclude_from: [] borg_exclude_from: []
borg_encryption_passcommand: false borg_encryption_passcommand: false
borg_lock_wait_time: 5 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_ssh_command: false
borg_remote_path: false borg_remote_path: false
borg_remote_rate_limit: 0 borg_remote_rate_limit: 0
@ -28,13 +16,34 @@ borg_retention_policy:
keep_daily: 7 keep_daily: 7
keep_weekly: 4 keep_weekly: 4
keep_monthly: 6 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 borg_version: false
borgmatic_version: false borgmatic_timer_cron_name: "borgmatic"
borg_install_method: pip 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"
borg_require_epel: "{{ ansible_os_family == 'RedHat' and ansible_distribution != 'Fedora' }}"
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: ">=1.7.11"
borg_venv_path: "/opt/borgmatic"
borg_user: "root"
borg_group: "root"
...

182
meta/arguments_specs.yml Normal file
View File

@ -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

View File

@ -4,11 +4,11 @@ dependencies: []
galaxy_info: galaxy_info:
author: Manuel Riel author: Manuel Riel
role_name: ansible_role_borgbackup role_name: ansible_role_borgbackup
namespace: m3nu namespace: borgbase
description: Set up backup to remote machine using Borg and Borgmatic. description: Set up backup to remote machine using Borg and Borgmatic.
company: "BorgBase.com" company: "BorgBase.com"
license: license (BSD, MIT) license: license (BSD, MIT)
min_ansible_version: 2.0 min_ansible_version: "2.0"
platforms: platforms:
- name: Debian - name: Debian
versions: versions:

View File

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

View File

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

View File

@ -1,3 +1,4 @@
ansible ansible
ansible-lint ansible-lint
molecule[lint,docker] molecule
molecule-plugins[docker]

29
tasks/01_install.yml Normal file
View File

@ -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
...

View File

@ -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
...

28
tasks/03_create_key.yml Normal file
View File

@ -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 }}"
...

19
tasks/05_configure.yml Executable file
View File

@ -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 }}"
...

View File

@ -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

View File

@ -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 }}"

View File

@ -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"

101
tasks/main.yml Executable file → Normal file
View File

@ -1,96 +1,7 @@
--- ---
- name: Ensure legacy hooks aren't used - name: Add and run all plays
assert: include_tasks: "{{ bak_element }}"
that: with_items: "{{ lookup('ansible.builtin.fileglob', '*.yml').split(',') | reject('search', 'main.yml') | reject('search', 'noauto_*') | sort }}"
- borgmatic_failure_command is undefined loop_control:
- borgmatic_before_backup_command is undefined loop_var: bak_element
- 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

View File

@ -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 }}"
...

View File

@ -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
...

View File

@ -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."
...

View File

@ -0,0 +1,21 @@
---
- name: Install borgbackup by distro
block:
- name: Check if EPEL repo is enabled, if installation from distro is requested
when: borg_require_epel
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 }}"
...

View File

@ -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"
...

View File

@ -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

View File

@ -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

View File

@ -1,11 +1,18 @@
#jinja2: lstrip_blocks: "True", trim_blocks: "True" #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 # Full config: https://torsion.org/borgmatic/docs/reference/config.yaml
location: location:
{% if borg_source_directories is not defined or borg_source_directories | length == 0 %}
source_directories:
- /etc/hostname # prevent empty backupconfig
{% else %}
source_directories: source_directories:
{% for dir in borg_source_directories %} {% for dir in borg_source_directories %}
- {{ dir }} - {{ dir }}
{% endfor %} {% endfor %}
{% endif %}
# Stay in same file system (do not cross mount points). # Stay in same file system (do not cross mount points).
one_file_system: {{ borg_one_file_system }} one_file_system: {{ borg_one_file_system }}
@ -142,11 +149,6 @@ retention:
keep_yearly: {{ borg_retention_policy.keep_yearly }} keep_yearly: {{ borg_retention_policy.keep_yearly }}
{% endif %} {% endif %}
# When pruning, only consider archive names starting with this prefix.
# Borg placeholders can be used. See the output of "borg help placeholders" for
# details. Default is "{hostname}-".
prefix: '{hostname}-'
# Consistency checks to run after backups. See # Consistency checks to run after backups. See
# https://borgbackup.readthedocs.org/en/stable/usage.html#borg-check and # https://borgbackup.readthedocs.org/en/stable/usage.html#borg-check and
# https://borgbackup.readthedocs.org/en/stable/usage.html#borg-extract for details. # https://borgbackup.readthedocs.org/en/stable/usage.html#borg-extract for details.
@ -167,11 +169,6 @@ consistency:
# Restrict the number of checked archives to the last n. Applies only to the "archives" check. # Restrict the number of checked archives to the last n. Applies only to the "archives" check.
check_last: {{ borgmatic_check_last }} check_last: {{ borgmatic_check_last }}
# When performing the "archives" check, only consider archive names starting with
# this prefix. Borg placeholders can be used. See the output of
# "borg help placeholders" for details. Default is "{hostname}-".
prefix: '{hostname}-'
# Shell commands or scripts to execute before and after a backup or if an error has occurred. # Shell commands or scripts to execute before and after a backup or if an error has occurred.
# IMPORTANT: All provided commands and scripts are executed with user permissions of borgmatic. # IMPORTANT: All provided commands and scripts are executed with user permissions of borgmatic.
# Do not forget to set secure permissions on this file as well as on any script listed (chmod 0700) to # Do not forget to set secure permissions on this file as well as on any script listed (chmod 0700) to

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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