Compare commits

...

34 Commits

Author SHA1 Message Date
Nish_
4faab60075 add option borgmatic_unknown_unencrypted_repo_access_is_ok
Signed-off-by: Nish_ <120EE0980@nitrkl.ac.in>
2025-07-09 18:38:43 +01:00
AJ Jordan
0dd2f88033 Add none installation method 2025-07-09 18:37:42 +01:00
Bert-Jan Fikse
e3397c62f7 fix: use path as key for repositories config 2025-07-09 18:37:16 +01:00
Manu
9ab81e461e Support for RHEL10 2025-07-09 18:33:43 +01:00
hydrandt
b12f97a11f #180 config.yaml.j2 jinja2 trim_blocks string -> boolean 2025-05-14 01:04:54 +01:00
Max Fuxjäger
e2f8e75155 Fix linting messages
- fix truthy values to proper booleans
- fix too long lines: wrapped
- fix indentation
- fix amount of preceding whitespace
- fix argument_spec syntax: borg_retention_policy as type dict with specific options
2025-04-28 19:59:35 +01:00
Matthias Stegmann
320975170d Add option to add flags to borgmatic in cron/systemd-timer job 2025-04-07 16:03:00 +01:00
Matthias Stegmann
4c7f8d86bf Add option to set ssh key comment 2025-04-04 23:29:03 +01:00
AJ Jordan
c91bf0e9b4 Remove unneeded execute bit on YAML file 2025-03-31 10:44:25 +01:00
AJ Jordan
e179627077 Extract asserts into their own file
These don't really belong in the "install" file.
2025-03-30 12:38:01 +01:00
Aaron
781f1226e7
Fix hook indention. By @Jaffr0 (#168)
Co-authored-by: Aaron Paterson <81300255+Jaff-ro@users.noreply.github.com>
2024-12-16 21:47:45 +00:00
Manu
ed8fe0d345
Indent hook name (#159) 2024-12-09 15:32:39 +00:00
Manu
efa8e5ec7f
fix borgmatic_hooks indention (#155) 2024-10-25 16:32:15 +01:00
Manu
2f4966fff3 Add missing arg_spec: borgmatic_version 2024-10-22 10:37:28 +01:00
berumuron
e9161f596e
Add borgmatic_timer_hour and borgmatic_timer_minute to argument_specs.yml (#154) 2024-10-18 14:17:33 +01:00
Manu
c8a295aa26
Test and dependency fixes (#153) 2024-10-18 11:35:39 +01:00
kaufe
ad163fec68
Add possibility to overwrite compression (#116)
Co-authored-by: Alexander Kaufmann <akaufman@DESKTOP-K5ID02T.localdomain>
2024-10-18 09:01:21 +01:00
jerome.gagnon
ab8dd529b8 fixes tests 2024-10-18 08:57:07 +01:00
Jerome Gagnon
8f52fbe8e5 Rename argument_spec.yml to argument_specs.yml
ok, got it this time.
2024-10-18 08:55:54 +01:00
Jerome Gagnon
637a951e21 Rename arguments_spec.yml to argument_spec.yml 2024-10-18 08:55:54 +01:00
Jerome Gagnon
d511f30e04 Rename arguments_specs.yml to arguments_spec.yml
Closes #141
2024-10-18 08:55:54 +01:00
AJ Jordan
0e5e876626 Fix Debian install failures due to missing libs 2024-08-14 08:26:11 +01:00
AJ Jordan
84b0030581
Fix malformed config if no passphrase set (#148) 2024-03-12 08:44:43 +00:00
Woomy
702299f861
Don't fail if cron isn't installed when setting up systemd timer (#147)
* `cron` isn't always installed and is not required when using a systemd
  timer, so make sure setup doesn't fail when we check if there's
  already an installed cron timer

Signed-off-by: Woomymy <woomy@woomy.be>
2024-03-07 21:11:02 +00:00
Kamil Essekkat
cbe280e7ff
docs: Repositories can be a list (#134) 2023-06-18 15:02:05 +01:00
Manu
f5d7a0afb6
Update namespace (#129) 2023-05-16 08:07:46 +02:00
Manu
07c853663c
Set default minimum borgmatic version to match config format (#127) 2023-04-26 20:34:53 +01:00
Sam Hartsfield
7efeb1be5e
Fix failing on EPEL check in Fedora (#111)
* Fix failing on EPEL check in Fedora

Only applies when using the "package" install method.
Added a separate variable "borg_require_epel" to make it easy to disable
the check in any other situations (e.g. using a custom mirror instead of
the epel-release package).

* Explain default value of borg_require_epel
2023-04-19 11:07:29 +01:00
Manu
2f57fce727 Remove deprecated Borgmatic option. 2023-04-05 21:12:32 +01:00
Frank Dornheim
dd960dcf4e
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>
2023-03-28 18:01:12 +01:00
Stefan Morgenthaler
981d4f9072
Allow to installation via OS package manager or pip (#106)
* allow to installation via os package manager or pip

* Run a second time to install via package manager

* Check for EPEL if distro package requested.

* Split dep lists to avoid installing build deps when using distro pkg

Co-authored-by: Stefan Morgenthaler <dev@morgenthaler.at>
Co-authored-by: Manu <manu@snapdragon.cc>
2022-12-15 17:40:53 +01:00
Sébastien Clément
e34f9311d8
Allow setting borg/borgmatic version (#107) 2022-11-22 20:54:31 +01:00
Manu
e1ba1d1364
Adjust Borgmatic arguments for v1.7.0 (#102) 2022-09-03 11:07:50 +02:00
Manuel Riel
1def545c86
Remove borgbase module, now separate (#100) 2022-05-13 11:17:47 +04:00
41 changed files with 1049 additions and 571 deletions

3
.ansible-lint Normal file
View File

@ -0,0 +1,3 @@
---
skip_list:
- fqcn-builtins

View File

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

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.cache

130
EXAMPLES.md Normal file
View File

@ -0,0 +1,130 @@
# 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_key_comment: backup key
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"
```

152
README.md
View File

@ -1,35 +1,36 @@
# 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/d/borgbase/ansible_role_borgbackup?logo=ansible&color=5cbec1&label=Ansible%20Galaxy)](https://galaxy.ansible.com/ui/standalone/roles/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 and CentOS/Red Hat.
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.
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, using the distro package and Cron timer
```
- hosts: webservers
- hosts: all
roles:
- role: m3nu.ansible_role_borgbackup
- role: borgbase.ansible_role_borgbackup
borg_install_method: package
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,20 +38,38 @@ Main features:
- name: users
hostname: database1.example.org
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
Download from Ansible Galaxy
```
$ ansible-galaxy install m3nu.ansible_role_borgbackup
$ ansible-galaxy install borgbase.ansible_role_borgbackup
```
Clone to local folder
Clone latest version from Github
```
$ git clone https://github.com/borgbase/ansible-role-borgbackup.git roles/ansible_role_borgbackup
```
@ -58,77 +77,50 @@ $ 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. `none` completely disables installation management.
- `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_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_key_comment`: Comment added to the SSH public key.
- `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_timer_flags`: Flags to pass to borgmatic cron/systemd-timer job, like "--log-file /path/to/file.log --log-file-verbosity 2"
- `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_unknown_unencrypted_repo_access_is_ok`: Bypass Borg error about a previously unknown unencrypted repository. 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.
- `borgmatic_version`: Force a specific borgmatic version to be installed
### Optional Arguments for [BorgBase.com](https://www.borgbase.com) repository auto creation
This role can also set up a new repository on BorgBase, using the arguments below. Thanks to [Philipp Rintz](https://github.com/p-rintz) for contribution of this feature.
- `create_repo`: Whether to let the role create the repository for the server. Default: False
- `bb_token`: Your [BorgBase.com](https://www.borgbase.com) API-Token. Should be Create Only for security reasons.
- `bb_region`: Which region the backups should be saved in. Choice: "eu" or "us".
- `bb_new_sshkey`: Whether to use the automatically created SSH_key. Default: True
- `bb_sshkey`: If there is a key already available on [BorgBase.com](https://www.borgbase.com) that should be used, it can be set with this variable. The key needs to be exactly the same, including key-comment.
- `bb_append`: Should the permission of the newly created repository be append only? Default: True
- `bb_quota`: To use a quota for the Server. Default: False
- `bb_quota_size`: Will need to be set if `bb_quota` is set to True. In Gigabyte.
- `bb_alertdays`: After how many days of no backup activity should alerts be sent out? Defaults to off.
- `bb_repo_name`: What name the created repository should have. Defaults to the inventory_hostname.
### Use BorgBase Module Standalone
You can also use the BorgBase-Ansible module directly if needed:
```
- name: Create new repository for server in EU with new SSH_key and quota
borgbase:
repository_name: "{{ inventory_hostname }}"
token: "Your Borgbase API Token"
new_ssh_key: True
ssh_key: "{{ some_variable }}"
append_only: True
quota_enable: True
quota: 1000 #in GB
region: eu
alertdays: 2
delegate_to: localhost
```
## Planned features
- [x] Testing
- [ ] Multiple repos in one role-call instead of callng this role multiple times.
- [ ] Support more OSs, like Red Hat/Fedora/CentOS, SuSE, Gentoo, Slackware, Arch, BSD
- `borg_user`: Name of the User to create Backups (service account)
- `borg_group`: Name of the Group to create Backups (service account)
## Contributing
@ -146,4 +138,4 @@ MIT/BSD
## Author
© 2018-2020 Manuel Riel and contributors.
© 2018-2023 Manuel Riel and contributors.

View File

@ -1,25 +1,14 @@
---
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_comment: ''
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,18 +17,38 @@ borg_retention_policy:
keep_daily: 7
keep_weekly: 4
keep_monthly: 6
create_repo: False
ssh_key_file: .ssh/id_ed25519
bb_new_sshkey: True
bb_append: True
bb_quota: False
bb_quota_size: 0
bb_alertdays: 0
bb_repo_name: "{{ inventory_hostname }}"
bb_sshkey: "{{ root_user['ssh_public_key'] }}"
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) }}"
borgmatic_timer_flags: ""
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_unknown_unencrypted_repo_access_is_ok: false
borgmatic_version: ">=1.7.11"
borg_venv_path: "/opt/borgmatic"
borg_user: "root"
borg_group: "root"
backup_user_info:
home: "/home/{{ borg_user }}"
...

View File

@ -1,215 +0,0 @@
#!/usr/bin/python
DOCUMENTATION = '''
---
module: borgbase
author: "Philipp Rintz (https://github.com/p-rintz)"
short_description: Ansible module for creating new repositories with borgbase.com
description:
- Ansible Module for creating new repositories with borgbase.com including adding new ssh keys
version_added: "2.6"
'''
EXAMPLES = '''
- name: Create new repository for server in EU with new SSH_key and quota
borgbase:
repository_name: "{{ inventory_hostname }}"
token: "Your Borgbase API Token"
new_ssh_key: True
ssh_key: "{{ some_variable }}"
append_only: True
quota_enable: True
quota: 1000 #in GB
region: eu
alertdays: 2
delegate_to: localhost
- name: Create new repository without new key and no quota/alerting in US region
borgbase:
repository_name: "{{ inventory_hostname }}"
token: "Your Borgbase API Token"
new_ssh_key: False
ssh_key: "ssh-ed25519 AAAAC3Nz......aLqRJw+dl/E+2BJ xxx@yyy"
region: us
delegate_to: localhost
'''
from ansible.module_utils.basic import *
from ansible.module_utils.borgbase_api_client.client import GraphQLClient
from ansible.module_utils.borgbase_api_client.mutations import *
from ansible.module_utils.borgbase_api_client.queries import *
def get_key_id(ssh_key):
res = client.execute(KEY_DETAILS)
for i in res['data']['sshList']:
if i['keyData'] == ssh_key:
key_id = i['id']
return key_id
def add_ssh_key():
key_name = 'Key for %s' % (module.params['repository_name'],)
new_key_vars = {
'name': key_name,
'keyData': module.params['ssh_key']
}
res = client.execute(SSH_ADD, new_key_vars)
new_key_id = res['data']['sshAdd']['keyAdded']['id']
return new_key_id
def add_repo(key_id):
if module.params['append_only']:
access_level = 'appendOnlyKeys'
else:
access_level = 'fullAccessKeys'
if not module.params['quota_enable']:
new_repo_vars = {
'name': module.params['repository_name'],
'quotaEnabled': module.params['quota_enable'],
access_level: [key_id],
'alertDays': module.params['alertdays'],
'region': module.params['region']
}
else:
new_repo_vars = {
'name': module.params['repository_name'],
'quotaEnabled': module.params['quota_enable'],
'quota': 1000*module.params['quota'],
access_level: [key_id],
'alertDays': module.params['alertdays'],
'region': module.params['region']
}
res = client.execute(REPO_ADD, new_repo_vars)
return res
def get_repo_id(name):
res = client.execute(REPO_DETAILS)
for repo in res['data']['repoList']:
if repo['name'] == name:
repo_id = repo['id']
return repo_id
return None
def edit_repo(repo_id, key_id):
if module.params['append_only']:
access_level = 'appendOnlyKeys'
else:
access_level = 'fullAccessKeys'
if not module.params['quota_enable']:
repo_vars = {
'id': repo_id,
'name': module.params['repository_name'],
access_level: [key_id],
'alertDays': module.params['alertdays'],
'region': module.params['region']
}
else:
repo_vars = {
'id': repo_id,
'name': module.params['repository_name'],
'quotaEnabled': module.params['quota_enable'],
'quota': 1000*module.params['quota'],
access_level: [key_id],
'alertDays': module.params['alertdays'],
'region': module.params['region']
}
res = client.execute(REPO_EDIT, repo_vars)
return res
def main():
global module
module = AnsibleModule(
argument_spec = dict(
repository_name = dict(
type='str',
required=True,
),
token = dict(
required=True,
type='str',
no_log=True
),
new_ssh_key = dict(
required=False,
default='True',
type='bool'
),
ssh_key = dict(
required=True,
type='str'
),
append_only = dict(
required=False,
default='True',
type='bool'
),
quota_enable = dict(
required=False,
default='False',
type='bool'
),
quota = dict(
required=False,
type='int'
),
region = dict(
required=True,
type='str',
choice=["eu", "us"]
),
alertdays = dict(
required=False,
default=0,
type='int'
)
)
)
global client
client = GraphQLClient(module.params['token'])
# Add new SSH key or get ID of old key
if module.params['new_ssh_key']:
key_id = add_ssh_key()
else:
key_id = get_key_id(module.params['ssh_key'])
# Check if repo with given name exists
repo_id = get_repo_id(module.params['repository_name'])
if repo_id is None:
# Add new repo using the key
res = add_repo(key_id)
repo_exist = False
else:
# Edit the repo
res = edit_repo(repo_id, key_id)
repo_exist = True
# Setup information for Ansible
result = dict(
changed = False,
data = '',
type = '',
key_id = ''
)
# Test for success and change info
if type(res) == dict:
result['changed'] = True
if repo_exist:
result['data'] = res["data"]["repoEdit"]["repoEdited"]
else:
result['data'] = res['data']['repoAdd']['repoAdded']
result['key_id'] = key_id
module.exit_json(**result)
else:
result['data'] = res
result['type'] = type(res)
result['key_id'] = key_id
module.fail_json(msg="Failed creating new respository.", **result)
if __name__ == '__main__':
main()

209
meta/argument_specs.yml Normal file
View File

@ -0,0 +1,209 @@
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.
Set to none to disable installation management.
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: str
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.
borgmatic_unknown_unencrypted_repo_access_is_ok:
type: bool
description: Bypass Borg error about a previously unknown unencrypted repository.
borg_retention_policy:
type: dict
description: Define the pruning policy
options:
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".
borgmatic_timer_hour:
type: str
required: false
description: Hour when regular create and prune cron/systemd-timer job will run.
borgmatic_timer_minute:
type: str
required: false
description: Minute when regular create and prune cron/systemd-timer job will run.
borgmatic_timer_flags:
type: str
required: false
description: Flags to pass to borgmatic cron/systemd-timer job, like "--log-file /path/to/file.log --log-file-verbosity 2"
borgmatic_version:
type: str
required: false
description: Borgmatic version to install. Defaults to 'latest'
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
borg_ssh_key_comment:
type: str
required: false
description: Comment added to the SSH public key.

View File

@ -4,21 +4,19 @@ dependencies: []
galaxy_info:
author: Manuel Riel
role_name: ansible_role_borgbackup
namespace: m3nu
namespace: borgbase
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:
- all
- name: Ubuntu
versions:
- trusty
- xenial
- bionic
- name: Archlinux
- all
- name: ArchLinux
versions:
- all
galaxy_tags:

View File

@ -1,6 +0,0 @@
The "borgbase_api_client" folder of the API client repository will need to be put into this folder.
Folder structure:
ansible-role-borgbackup/
|---------------------+ module_utils/
|-------- borgbase_api_client/

View File

@ -14,10 +14,10 @@ ENV {{ var }} {{ value }}
{% endfor %}
{% endif %}
RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates iproute2 python3-apt aptitude && apt-get clean; \
RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python3 python3-pip sudo bash ca-certificates iproute2 python3-apt aptitude && apt-get clean; \
elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install /usr/bin/python3 /usr/bin/python3-config /usr/bin/dnf-3 sudo bash iproute && dnf clean all; \
elif [ $(command -v yum) ]; then yum makecache fast && yum install -y /usr/bin/python /usr/bin/python2-config sudo yum-plugin-ovl bash iproute && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \
elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml iproute2 && zypper clean -a; \
elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; \
elif [ $(command -v pacman) ]; then pacman --noconfirm -Suy python sudo openssh; \
elif [ $(command -v pacman) ]; then pacman --noconfirm -Suy python python-pip sudo openssh; \
elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates iproute2 && xbps-remove -O; fi

View File

@ -5,11 +5,13 @@
- name: Set ssh server package name for non-Archlinux ansible_os_family
set_fact:
openssh_package: "openssh-server"
pip3_extra_args: ""
when: ansible_os_family != "Archlinux"
- name: Set ssh server package name for Archlinux ansible_os_family
- name: Set ssh server package name and pip3 argument for Archlinux ansible_os_family
set_fact:
openssh_package: "openssh"
pip3_extra_args: "--break-system-packages"
when: ansible_os_family == "Archlinux"
- name: Install openssh
@ -17,10 +19,23 @@
name: "{{ openssh_package }}"
state: present
- name: Enable EPEL for yamllint
package:
name: epel-release
state: present
when: ansible_os_family == 'RedHat' and ansible_distribution != 'Fedora'
- name: Install yamllint
package:
name: yamllint
state: present
roles:
- role: m3nu.ansible_role_borgbackup
borg_encryption_passphrase: CHANGEME
- role: borgbase.ansible_role_borgbackup
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,9 +53,3 @@
- name: users
hostname: database1.example.org
port: 5433
post_tasks:
- name: Install yamllint for checking config file
pip:
name: yamllint
executable: pip3

View File

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

View File

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

9
tasks/00_assert.yml Normal file
View File

@ -0,0 +1,9 @@
---
- 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.
...

22
tasks/01_install.yml Normal file
View File

@ -0,0 +1,22 @@
---
- name: Install borgbackup
when: borg_install_method != "none"
block:
- 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
...

29
tasks/03_create_key.yml Normal file
View File

@ -0,0 +1,29 @@
---
- 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 }}"
comment: "{{ borg_ssh_key_comment }}"
- 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 Normal 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 +0,0 @@
---

View File

@ -1 +0,0 @@
---

View File

@ -1 +0,0 @@
---

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

@ -1,158 +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: Run OS-specific tasks
include: "{{ item }}"
with_first_found:
- "{{ ansible_os_family }}-{{ ansible_distribution_major_version }}.yml"
- "{{ ansible_os_family }}.yml"
- name: Install required System Packages
package:
name: "{{ borg_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: "{{ borg_python_packages }}"
virtualenv: /opt/borgmatic
when: borg_python_packages is defined
- 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"
- 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: Create new repository for server
borgbase:
repository_name: "{{ bb_repo_name }}"
token: "{{ bb_token }}"
new_ssh_key: "{{ bb_new_sshkey }}"
ssh_key: "{{ bb_sshkey }}"
append_only: "{{ bb_append }}"
quota_enable: "{{ bb_quota }}"
quota: "{{ bb_quota_size }}"
region: "{{ bb_region }}"
alertdays: "{{ bb_alertdays }}"
delegate_to: localhost
become: no
register: repo_creation
when: create_repo
- name: Set Repository Fact
set_fact:
borg_repository: |-
{% if borg_repository is defined and borg_repository is string %}
{{ [borg_repository] + [ repo_creation['data']['repoPath'] ] }}
{% elif borg_repository is defined %}
{{ borg_repository + [ repo_creation['data']['repoPath'] ] }}
{% else %}
{{ repo_creation['data']['repoPath'] }}
{% endif %}
when: create_repo
- 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 }} --create --prune"
- 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 }} --check"
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
...

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 }} {{ borgmatic_timer_flags }}"
- 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: true
value: /usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
...

View File

@ -0,0 +1,67 @@
---
- 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
ignore_errors: true
- name: Ensure no Borgmatic Cron file exists.
ansible.builtin.assert:
that:
- not cron_file_exists.changed
- not cron_file_exists.failed or "Failed to find" in cron_file_exists.msg
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,57 @@
---
- name: Install Borg and Borgmatic via pip
block:
- name: Ensure the crb repository is enabled for RedHat (needed for xxhash)
community.general.dnf_config_manager:
name: crb
state: enabled
when: ansible_os_family == 'RedHat' and ansible_distribution != 'Fedora'
- 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 }} {{ borgmatic_timer_flags }}
# 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,21 +1,28 @@
#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
location:
{% if borg_source_directories is not defined or borg_source_directories | length == 0 %}
source_directories:
{% for dir in borg_source_directories %}
- /etc/hostname # prevent empty backupconfig
{% else %}
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 }}
repositories:
{% if borg_repository is iterable and (borg_repository is not string and borg_repository is not mapping) %}
{% for repo in borg_repository %}
- {{ repo }}
- path: {{ repo }}
{% endfor %}
{% elif borg_repository is defined and borg_repository is string %}
- {{ borg_repository }}
- path: {{ borg_repository }}
{% endif %}
# Store atime into archive.
@ -59,8 +66,10 @@ location:
# https://borgbackup.readthedocs.io/en/stable/usage/general.html#environment-variables for
# details.
storage:
{% if borg_encryption_passphrase %}
encryption_passphrase: {{ borg_encryption_passphrase }}
{% endif %}
# 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,
@ -73,7 +82,7 @@ storage:
# Type of compression to use when creating archives. See
# https://borgbackup.readthedocs.org/en/stable/usage.html#borg-create for details.
# Defaults to no compression.
compression: auto,zstd
compression: {{ borg_compression|default('auto,zstd') }}
# Remote network upload rate limit in kiBytes/second.
{% if borg_remote_rate_limit %}
@ -103,6 +112,9 @@ storage:
# Bypass Borg error about a repository that has been moved.
relocated_repo_access_is_ok: {{ borgmatic_relocated_repo_access_is_ok }}
# Bypass Borg error about a previously unknown unencrypted repository.
unknown_unencrypted_repo_access_is_ok: {{ borgmatic_unknown_unencrypted_repo_access_is_ok }}
# Retention policy for how many backups to keep in each category. See
# https://borgbackup.readthedocs.org/en/stable/usage.html#borg-prune for details.
# At least one of the "keep" options is required for pruning to work.
@ -142,11 +154,6 @@ retention:
keep_yearly: {{ borg_retention_policy.keep_yearly }}
{% 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
# https://borgbackup.readthedocs.org/en/stable/usage.html#borg-check and
# https://borgbackup.readthedocs.org/en/stable/usage.html#borg-extract for details.
@ -167,11 +174,6 @@ consistency:
# Restrict the number of checked archives to the last n. Applies only to the "archives" check.
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.
# 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
@ -179,5 +181,5 @@ consistency:
hooks:
{% for hook in borgmatic_hooks %}
{{ hook }}:
{{ borgmatic_hooks[hook] | to_nice_yaml(indent=2) | trim | indent(8) }}
{{ borgmatic_hooks[hook] | to_nice_yaml(indent=4) | indent(8, first=true) }}
{% endfor %}

View File

@ -1,10 +1,24 @@
---
borg_packages:
- cronie
- gcc
borg_dep_packages:
- openssh
borg_cron_package: cronie
borg_pip_packages:
- acl
- gcc
- lz4
- openssl
- pkgconfig
- python-pip
- python-setuptools
- xxhash
- xz
- zstd
borg_distro_packages:
- borg
- borgmatic
python_bin: python3
pip_bin: pip3

View File

@ -1,8 +1,16 @@
---
borg_packages:
borg_dep_packages:
- openssh-client
borg_cron_package: cron
borg_pip_packages:
- libssl-dev
- libacl1-dev
- libacl1
- liblz4-dev
- libzstd-dev
- libxxhash-dev
- build-essential
- python3-setuptools
- python3-dev
@ -10,8 +18,10 @@ borg_packages:
- python3-pkgconfig
- python3-msgpack
- python3-venv
- openssh-client
- cron
borg_distro_packages:
- borgbackup
- borgmatic
python_bin: python3
pip_bin: pip3

View File

@ -1,17 +1,29 @@
---
borg_packages:
- libacl-devel
- libacl
borg_dep_packages:
- openssh-clients
borg_cron_package: cronie
borg_pip_packages:
- gcc
- gcc-c++
- libacl
- libacl-devel
- libzstd-devel
- lz4-devel
- openssl-devel
- openssl-devel
- python3-cython
# - python3-devel
- python3-pip
- python3-wheel
- python3-devel
- python3-setuptools
- python3-Cython
- openssh-clients
- cronie
- python3-wheel
- xxhash
- xxhash-devel
borg_distro_packages:
- borgbackup
- borgmatic
python_bin: python3
pip_bin: pip3

View File

@ -1,8 +1,24 @@
---
borg_packages:
- borgmatic
borg_dep_packages:
- openssh
- cronie
borg_cron_package: cronie
borg_pip_packages: # untested
- libssl-dev
- libacl1-dev
- libacl1
- build-essential
- python3-setuptools
- python3-dev
- python3-pip
- python3-pkgconfig
- python3-msgpack
- python3-venv
borg_distro_packages:
- borg
- borgmatic
python_bin: python3
pip_bin: pip3

28
vars/RedHat-10.yml Normal file
View File

@ -0,0 +1,28 @@
---
borg_dep_packages:
- openssh-clients
borg_cron_package: cronie
borg_pip_packages:
- gcc
- gcc-c++
- libacl
- libacl-devel
- libzstd-devel
- lz4-devel
- openssl-devel
# - python3-devel
- python3-pip
- python3-setuptools
- xxhash
- xxhash-devel
# - python3-virtualenv
# - python3-wheel
borg_distro_packages:
- borgbackup
- borgmatic
python_bin: python3
pip_bin: pip3

View File

@ -1,5 +1,10 @@
---
borg_packages:
borg_dep_packages:
- openssh-clients
borg_cron_package: cronie
borg_pip_packages:
- libacl-devel
- libacl
- gcc
@ -10,8 +15,10 @@ borg_packages:
- python3-devel
- python3-setuptools
- python3-virtualenv
- openssh-clients
- cronie
borg_distro_packages:
- borgbackup
- borgmatic
python_bin: python3
pip_bin: pip3

View File

@ -1,17 +1,28 @@
---
borg_packages:
- libacl-devel
- libacl
borg_dep_packages:
- openssh-clients
borg_cron_package: cronie
borg_pip_packages:
- gcc
- gcc-c++
- libacl
- libacl-devel
- libzstd-devel
- lz4-devel
- openssl-devel
# - python3-devel
- python3-pip
- python3-wheel
- python3-devel
- python3-setuptools
- python3-virtualenv
- openssh-clients
- cronie
- xxhash
- xxhash-devel
# - python3-virtualenv
# - python3-wheel
borg_distro_packages:
- borgbackup
- borgmatic
python_bin: python3
pip_bin: pip3

View File

@ -1,5 +1,10 @@
---
borg_packages:
borg_dep_packages:
- openssh-clients
borg_cron_package: cronie
borg_pip_packages:
- libacl-devel
- libacl
- gcc
@ -9,8 +14,10 @@ borg_packages:
- python36-wheel
- python36-devel
- python-setuptools
- openssh-clients
- cronie
borg_distro_packages:
- borgbackup
- borgmatic
python_bin: python3
pip_bin: pip3

View File

@ -2,6 +2,9 @@
borg_dependent_python_packages:
- cython
- pkgconfig
borg_python_packages:
- borgbackup
- borgmatic
- name: borgbackup
version: "{{ borg_version }}"
- name: borgmatic
version: "{{ borgmatic_version }}"