From dd960dcf4e16f3bd6eb418ea58bfa1870a63a0cc Mon Sep 17 00:00:00 2001 From: Frank Dornheim <524257+conloos@users.noreply.github.com> Date: Tue, 28 Mar 2023 19:01:12 +0200 Subject: [PATCH] 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 --- .github/workflows/main.yml | 4 +- EXAMPLES.md | 129 +++++++++++++ README.md | 95 +++++---- defaults/main.yml | 54 +++--- meta/arguments_specs.yml | 182 ++++++++++++++++++ meta/main.yml | 2 +- molecule/default/converge.yml | 5 +- molecule/default/molecule.yml | 6 - tasks/01_install.yml | 29 +++ tasks/02_user_management.yml | 25 +++ tasks/03_create_key.yml | 28 +++ tasks/05_configure.yml | 19 ++ tasks/07_install_timer.yml | 8 + tasks/install_package.yml | 18 -- tasks/install_pip.yml | 39 ---- tasks/main.yml | 101 +--------- tasks/noauto_create_backup_user_and_group.yml | 34 ++++ tasks/noauto_create_timer_cron.yml | 31 +++ tasks/noauto_create_timer_systemd.yml | 63 ++++++ tasks/noauto_install_package.yml | 21 ++ tasks/noauto_install_pip.yml | 51 +++++ templates/borgmatic.service.j2 | 60 ++++++ templates/borgmatic.timer.j2 | 13 ++ templates/config.yaml.j2 | 11 +- vars/Archlinux.yml | 3 +- vars/Debian.yml | 3 +- vars/Fedora.yml | 3 +- vars/ManjaroLinux.yml | 3 +- vars/RedHat-8.yml | 3 +- vars/RedHat-9.yml | 3 +- vars/RedHat.yml | 3 +- 31 files changed, 820 insertions(+), 229 deletions(-) create mode 100644 EXAMPLES.md create mode 100644 meta/arguments_specs.yml create mode 100644 tasks/01_install.yml create mode 100644 tasks/02_user_management.yml create mode 100644 tasks/03_create_key.yml create mode 100755 tasks/05_configure.yml create mode 100644 tasks/07_install_timer.yml delete mode 100644 tasks/install_package.yml delete mode 100644 tasks/install_pip.yml mode change 100755 => 100644 tasks/main.yml create mode 100644 tasks/noauto_create_backup_user_and_group.yml create mode 100644 tasks/noauto_create_timer_cron.yml create mode 100644 tasks/noauto_create_timer_systemd.yml create mode 100644 tasks/noauto_install_package.yml create mode 100644 tasks/noauto_install_pip.yml create mode 100644 templates/borgmatic.service.j2 create mode 100644 templates/borgmatic.timer.j2 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 501bfe9..ef664fc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,9 +8,9 @@ jobs: steps: - uses: actions/checkout@v2 - name: Set up Python - uses: actions/setup-python@v1 + uses: actions/setup-python@v4 with: - python-version: 3.8 + python-version: "3.10" - name: Install Molecule run: | pip install -U pip setuptools wheel diff --git a/EXAMPLES.md b/EXAMPLES.md new file mode 100644 index 0000000..8597bde --- /dev/null +++ b/EXAMPLES.md @@ -0,0 +1,129 @@ +# Additional Examples + +## Custom SSH key for backups only + +``` +- hosts: webservers + roles: + - role: m3nu.ansible_role_borgbackup + borg_encryption_passphrase: CHANGEME + borg_repository: ssh://m5vz9gp4@m5vz9gp4.repo.borgbase.com/./repo + borgmatic_timer: systemd + borg_ssh_key_name: id_backup + borg_ssh_command: "ssh -i {{ borg_ssh_key_file_path }} -o StrictHostKeyChecking=accept-new" + borg_user: backupuser + borg_group: backupuser +``` + +## Use service user and copy SSH key to target server + +Installs and configures the Borgmatic client and also initializes the repo on the +remote backup server. (not tested) + +``` +- name: Configure backup + hosts: test.lab + pre_tasks: + - name: Get home of {{ borg_user }} + ansible.builtin.user: + name: "{{ borg_user }}" + state: present + register: user_info + changed_when: false + check_mode: true # Important, otherwise user will be created + + - name: Save the user_info, we need them for the home_dir + ansible.builtin.set_fact: + backup_user_info: "{{ user_info }}" + vars_files: [] + vars: + borg_encryption_passphrase: "CHANGEME" + borg_repository: "USER@TARGET_SERVER:/PATH/TO/BACKUP" + borg_user: "srv_backup" + borg_group: "srv_backup" + borg_ssh_key_name: id_backup + borg_ssh_command: "ssh -i {{ borg_ssh_key_file_path }} -o StrictHostKeyChecking=accept-new" + borgmatic_timer: systemd + borg_source_directories: + - /srv/www + - /var/lib/automysqlbackup + borg_exclude_patterns: + - /srv/www/old-sites + borg_retention_policy: + keep_hourly: 3 + keep_daily: 7 + keep_weekly: 4 + keep_monthly: 6 + borgmatic_hooks: + before_backup: + - echo "`date` - Starting backup." + tasks: + - name: Configure Borg Backup and Backupmatic + tags: + - always + - install_backup + ansible.builtin.include_role: + name: ansible_role_borgbackup + apply: + tags: + - always + + + - name: Copy SSH-Key to Target {{ borg_repository }} and Init Repo + tags: + - never + - backup_init_repo + block: + - name: Read ssh key + ansible.builtin.slurp: + src: "{{ borg_ssh_key_file_path }}.pub" + register: backup_local_ssh_key + + - name: Set authorized key taken from file + ansible.posix.authorized_key: + # example: + # borg_repository: m5vz9gp4@m5vz9gp4.repo.borgbase.com:repo + # have three parts: "username"@"FQDN":"path/to/store/backup", specific: + # a) user: m5vz9gp4 + # b) fqdn: m5vz9gp4.repo.borgbase.co + # c) dir: repo + user: "{{ borg_repository | regex_search('(.*)@', '\\1') | first }}" # part a) + state: present + key: "{{ backup_local_ssh_key['content'] | b64decode }}" + delegate_to: "{{ borg_repository | regex_search('@(.*):', '\\1') | first }}" # part b) + + - name: Init repository + ansible.builtin.command: + cmd: "su - {{ borg_user }} -c '/usr/local/bin/borgmatic rcreate --encryption keyfile --append-only'" + + - name: Activate systemd service and timer + when: + - borgmatic_timer is defined and borgmatic_timer == "systemd" + tags: + - never + - backup_init_repo + block: + - name: Populate service facts + ansible.builtin.service_facts: + + - name: Start borgmatic services + ansible.builtin.systemd: + name: "{{ item }}" + state: started + enabled: true + masked: false + daemon_reload: true + when: "item in services" + with_items: + - borgmatic.service + + # bug: Need own section without masked else the timer are skipped + - name: Start borgmatic timers + ansible.builtin.systemd: + name: "{{ item }}" + state: started + enabled: true + daemon_reload: true + with_items: + - "borgmatic.timer" +``` diff --git a/README.md b/README.md index 415c63f..db8f434 100644 --- a/README.md +++ b/README.md @@ -6,30 +6,29 @@ Set up encrypted, compressed and deduplicated backups using [BorgBackup](https:/ Works great with [BorgBase.com](https://www.borgbase.com) - Simple and Secure Hosting for your Borg Repositories. To manage BorgBase repos via Ansible, also see Andy Hawkins' [BorgBase Collection](https://galaxy.ansible.com/adhawkins/borgbase). -Main features: -- Set up Borg and Borgmatic -- Add cron job at random time -- Provision new remote [BorgBase.com](https://www.borgbase.com) repo for storing backups (optional) +**Main features** +- Install Borg and Borgmatic from PyPi or distro packages +- Set up Borgmatic config +- Schedule regular backups using Cron or Systemd timer +## Breaking changes +- Older versions of this role set up a separate Cron job for creating and checking + backups. With recent Borgmatic version, this feature is now managed in Borgmatic. + As a result the extra Cron job will be removed by this role. +- Older versions of this role only supported Cron for scheduling. If you use + Systemd timers, be sure to remove the Cron job in `/etc/cron.d/borgmatic` first. + The role will also alert you when trying to use both timers. -## Example Playbook +## Example playbook with root as backup user and Cron timer ``` -- hosts: webservers +- hosts: all roles: - role: m3nu.ansible_role_borgbackup borg_encryption_passphrase: CHANGEME - borg_repository: m5vz9gp4@m5vz9gp4.repo.borgbase.com:repo + borg_repository: ssh://xxxxxx@xxxxxx.repo.borgbase.com/./repo borg_source_directories: - - /srv/www - - /var/lib/automysqlbackup - borg_exclude_patterns: - - /srv/www/old-sites - borg_retention_policy: - keep_hourly: 3 - keep_daily: 7 - keep_weekly: 4 - keep_monthly: 6 + - /var/www borgmatic_hooks: before_backup: - echo "`date` - Starting backup." @@ -37,8 +36,28 @@ Main features: - name: users hostname: database1.example.org port: 5433 +``` + +## Example playbook with service user and Systemd timer ``` +- hosts: all + roles: + - role: m3nu.ansible_role_borgbackup + borg_encryption_passphrase: CHANGEME + borg_repository: ssh://xxxxxx@xxxxxx.repo.borgbase.com/./repo + borgmatic_timer: systemd + borg_user: "backupuser" + borg_group: "backupuser" + borg_source_directories: + - /var/www + borg_retention_policy: + keep_hourly: 3 + keep_daily: 7 + keep_weekly: 4 + keep_monthly: 6 +``` + ## Installation @@ -56,39 +75,47 @@ $ git clone https://github.com/borgbase/ansible-role-borgbackup.git roles/ansibl ## Role Variables -### Required Arguments -- `borg_repository`: Full path to repository. Your own server or [BorgBase.com](https://www.borgbase.com) repo. Not required when using auto creation of repositories. Can be a list if you want to backup to multiple repositories. -- `borg_source_directories`: List of local folders to back up. +### Required Variables +- `borg_repository`: Full path to repository. Your own server or [BorgBase.com](https://www.borgbase.com) repo. + Can be a list if you want to backup to multiple repositories. -### Optional Arguments +### Optional Variables +- `borg_dep_packages`: Dependency Packages to install `borg(backup)` and `borgmatic`. +- `borg_distro_packages`: contains the names of distributions packages for `borg(backup)` and `borgmatic`, only used if `borg_install_method` is set to `package`. - `borg_encryption_passcommand`: The standard output of this command is used to unlock the encryption key. - `borg_encryption_passphrase`: Password to use for repokey or keyfile. Empty if repo is unencrypted. - `borg_exclude_from`: Read exclude patterns from one or more separate named files, one pattern per line. - `borg_exclude_patterns`: Paths or patterns to exclude from backup. See [official documentation](https://borgbackup.readthedocs.io/en/stable/usage/help.html#borg-help-patterns) for more. +- `borg_install_method`: By default `pip` is used to install borgmatic. To install via your distributions package manager set this to `package` and (if needed) overwrite the `borg_distro_packages` variable to contain your distributions package names required to install borgmatic. Note that many distributions ship outdated versions of borgbackup and borgmatic; use at your own risk. - `borg_lock_wait_time`: Config maximum seconds to wait for acquiring a repository/cache lock. Defaults to 5 seconds. - `borg_one_file_system`: Don't cross file-system boundaries. Defaults to `true` +- `borg_pip_packages`: Dependancy Packages (pip) to install `borg(backup)` and `borgmatic`. - `borg_remote_path`: Path to the borg executable on the remote. It will default to `borg`. - `borg_remote_rate_limit`: Remote network upload rate limit in kiBytes/second. - `borg_retention_policy`: Retention policy for how many backups to keep in each category (daily, weekly, monthly, etc). -- `borg_ssh_command`: Command to use instead of just "ssh". This can be used to specify ssh options. +- `borg_source_directories`: List of local folders to back up. Default is `/etc/hostname` to prevent an empty backup. +- `borg_ssh_key_name`: Name of the SSH public and pivate key. Default `id_ed25519` +- `borg_ssh_key_file_path`: SSH-key to be used. Default `~/.ssh/{{ borg_ssh_key_name }}` +- `borg_ssh_key_type`: The algorithm used to generate the SSH private key. Choose: `rsa`, `dsa`, `rsa1`, `ecdsa`, `ed25519`. Default: `ed25519` +- `borg_ssh_command`: Command to use instead of just "ssh". This can be used to specify SSH options. +- `borg_version`: Force a specific borg version to be installed +- `borg_venv_path`: Path to store the venv for `borg(backup)` and `borgmatic` + - `borgmatic_check_last`: Number of archives to check. Defaults to `3` -- `borgmatic_checks`: List of consistency checks. Defaults to `['repository']` -- `borgmatic_config_name`: Name to use for the borgmatic config file. Defaults to `config.yaml` -- `borgmatic_cron_checks_day`: Day when cron job for infrequent checks will run. Defaults to `{{ 28 | random }}` -- `borgmatic_cron_checks_hour`: Hour when cron job for infrequent checks will run. Defaults to `{{ range(7, 24) | random }}` -- `borgmatic_cron_checks_minute`: Minute when cron job for infrequent checks will run. Defaults to `{{ 59 | random }}` -- `borgmatic_cron_hour`: Hour when regular create and prune cron job will run. Defaults to `{{ 6 | random }}` -- `borgmatic_cron_minute`: Minute when regular create and prune cron job will run. Defaults to `{{ 59 | random }}` +- `borgmatic_checks`: List of consistency checks. Defaults to monthly checks. See [docs](https://torsion.org/borgmatic/docs/how-to/deal-with-very-large-backups/#check-frequency) for all options. +- `borgmatic_config_name`: Name to use for the Borgmatic config file. Defaults to `config.yaml` +- `borgmatic_timer_hour`: Hour when regular create and prune cron/systemd-timer job will run. Defaults to `{{ 6 | random }}` +- `borgmatic_timer_minute`: Minute when regular create and prune cron/systemd-timer job will run. Defaults to `{{ 59 | random }}` - `borgmatic_hooks`: Hooks to monitor your backups e.g. with [Healthchecks](https://healthchecks.io/). See [official documentation](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/) for more. -- `borgmatic_large_repo`: Less frequent, monthly repo checking. Defaults to `true` +- `borgmatic_timer`: If the variable is set, a timer is installed. A choice must be made between `cron` and `systemd`. - `borgmatic_relocated_repo_access_is_ok`: Bypass Borg error about a repository that has been moved. Defaults to `false` - `borgmatic_store_atime`: Store atime into archive. Defaults to `true` - `borgmatic_store_ctime`: Store ctime into archive. Defaults to `true` -- `ssh_key_file`: Path to a private ssh key file (default is `.ssh/id_ed25519`). It generates a ed25519 key if the file doesn't exist yet. -- `borg_version`: Force a specific borg version to be installed - `borgmatic_version`: Force a specific borgmatic version to be installed -- `borg_install_method`: By default `pip` is used to install borgmatic. To install via your distributions package manager set this to `package` and (if needed) overwrite the `borg_distro_packages` variable to contain your distributions package names required to install borgmatic. Note that many distributions ship outdated versions of borgbackup and borgmatic; use at your own risk. -- `borg_distro_packages`: contains the names of distributions packages for `borg(backup)` and `borgmatic`, only used if `borg_install_method` is set to `package`. + +- `borg_user`: Name of the User to create Backups (service account) +- `borg_group`: Name of the Group to create Backups (service account) + ## Contributing @@ -105,4 +132,4 @@ MIT/BSD ## Author -© 2018-2020 Manuel Riel and contributors. +© 2018-2023 Manuel Riel and contributors. diff --git a/defaults/main.yml b/defaults/main.yml index 6918f3f..4dd9630 100755 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -1,25 +1,13 @@ --- borg_encryption_passphrase: '' borg_exclude_patterns: [] -borgmatic_config_name: config.yaml -borgmatic_large_repo: true -borgmatic_hooks: - on_error: - - echo "`date` - Error while creating a backup." - before_backup: - - echo "`date` - Starting backup." - after_backup: - - echo "`date` - Finished backup." -borgmatic_checks: - - repository -borgmatic_check_last: 3 -borgmatic_store_atime: true -borgmatic_store_ctime: true -borgmatic_relocated_repo_access_is_ok: false borg_one_file_system: true borg_exclude_from: [] borg_encryption_passcommand: false borg_lock_wait_time: 5 +borg_ssh_key_type: "ed25519" +borg_ssh_key_name: "id_{{ borg_ssh_key_type }}" +borg_ssh_key_file_path: "{{ backup_user_info.home }}/.ssh/{{ borg_ssh_key_name }}" borg_ssh_command: false borg_remote_path: false borg_remote_rate_limit: 0 @@ -28,13 +16,33 @@ borg_retention_policy: keep_daily: 7 keep_weekly: 4 keep_monthly: 6 -ssh_key_file: .ssh/id_ed25519 -borgmatic_cron_name: borgmatic -borgmatic_cron_hour: "{{ 6 | random(seed=inventory_hostname) }}" -borgmatic_cron_minute: "{{ 59 | random(seed=inventory_hostname) }}" -borgmatic_cron_checks_day: "{{ range(1, 28) | random(seed=inventory_hostname) }}" -borgmatic_cron_checks_hour: "{{ range(9, 24) | random(seed=inventory_hostname) }}" -borgmatic_cron_checks_minute: "{{ 59 | random(seed=inventory_hostname) }}" borg_version: false +borgmatic_timer_cron_name: "borgmatic" +borgmatic_timer: cron +borgmatic_timer_hour: "{{ range(0, 5) | random(seed=inventory_hostname) }}" +borgmatic_timer_minute: "{{ range(0, 59) | random(seed=inventory_hostname) }}" +borg_install_method: "pip" + +borgmatic_config_name: config.yaml +borgmatic_hooks: + on_error: + - echo "`date` - Error while creating a backup." + before_backup: + - echo "`date` - Starting backup." + after_backup: + - echo "`date` - Finished backup." +borgmatic_checks: + - name: repository + frequency: "4 weeks" + - name: archives + frequency: "6 weeks" +borgmatic_check_last: 3 +borgmatic_store_atime: true +borgmatic_store_ctime: true +borgmatic_relocated_repo_access_is_ok: false borgmatic_version: false -borg_install_method: pip + +borg_venv_path: "/opt/borgmatic" +borg_user: "root" +borg_group: "root" +... diff --git a/meta/arguments_specs.yml b/meta/arguments_specs.yml new file mode 100644 index 0000000..2908b4f --- /dev/null +++ b/meta/arguments_specs.yml @@ -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 diff --git a/meta/main.yml b/meta/main.yml index 979fc62..d9fa6c6 100644 --- a/meta/main.yml +++ b/meta/main.yml @@ -8,7 +8,7 @@ galaxy_info: description: Set up backup to remote machine using Borg and Borgmatic. company: "BorgBase.com" license: license (BSD, MIT) - min_ansible_version: 2.0 + min_ansible_version: "2.0" platforms: - name: Debian versions: diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml index e5b47d2..c58023e 100644 --- a/molecule/default/converge.yml +++ b/molecule/default/converge.yml @@ -19,8 +19,10 @@ roles: - role: m3nu.ansible_role_borgbackup - borg_encryption_passphrase: CHANGEME + borg_install_method: pip + borgmatic_timer: cron borg_repository: m5vz9gp4@m5vz9gp4.repo.borgbase.com:repo + borg_encryption_passphrase: CHANGEME borg_source_directories: - /srv/www - /var/lib/automysqlbackup @@ -38,7 +40,6 @@ - name: users hostname: database1.example.org port: 5433 - borg_install_method: pip post_tasks: - name: Install yamllint for checking config file diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml index be2f4f4..9c8fa0e 100644 --- a/molecule/default/molecule.yml +++ b/molecule/default/molecule.yml @@ -6,18 +6,12 @@ driver: platforms: - name: archlinux-latest image: archlinux:latest - - name: centos-7 - image: centos:7 - - name: almalinux-8 - image: almalinux:8 - name: almalinux-9 image: almalinux:9 - name: fedora-latest image: fedora:latest - name: debian-bullseye image: debian:bullseye - - name: ubuntu-bionic - image: ubuntu:bionic - name: ubuntu-latest image: ubuntu:latest provisioner: diff --git a/tasks/01_install.yml b/tasks/01_install.yml new file mode 100644 index 0000000..e4478d9 --- /dev/null +++ b/tasks/01_install.yml @@ -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 +... diff --git a/tasks/02_user_management.yml b/tasks/02_user_management.yml new file mode 100644 index 0000000..fb396d1 --- /dev/null +++ b/tasks/02_user_management.yml @@ -0,0 +1,25 @@ +--- +# So in different positions in that role we need the user home +# Since we cannot be sure that this FSH is compatible we will determine it. +- name: Get home dir + when: + - borg_user == "root" + block: + - name: Get home if borg_user == "root" + ansible.builtin.user: + name: "{{ borg_user }}" + state: present + register: user_info + changed_when: false + check_mode: true # Important, otherwise user will be created + + - name: Save the user_info, we need them for the home_dir + ansible.builtin.set_fact: + backup_user_info: "{{ user_info }}" + +- name: Create user if borg_user != "root" + when: + - borg_user != "root" + ansible.builtin.include_tasks: + file: noauto_create_backup_user_and_group.yml +... diff --git a/tasks/03_create_key.yml b/tasks/03_create_key.yml new file mode 100644 index 0000000..3827d77 --- /dev/null +++ b/tasks/03_create_key.yml @@ -0,0 +1,28 @@ +--- +- name: Create SSH key (if neeeded) for {{ borg_user }} + block: + - name: Ensure directory exist + ansible.builtin.file: + path: "{{ backup_user_info.home }}/.ssh/" + state: directory + mode: "0700" + owner: "{{ borg_user }}" + group: "{{ borg_group }}" + + - name: Generate an OpenSSH keypair + community.crypto.openssh_keypair: + path: "{{ borg_ssh_key_file_path }}" + mode: "0600" + type: "{{ borg_ssh_key_type }}" + owner: "{{ borg_user }}" + group: "{{ borg_group }}" + + - name: Read SSH key + ansible.builtin.slurp: + src: "{{ borg_ssh_key_file_path }}.pub" + register: backup_local_ssh_key + + - name: Print key + ansible.builtin.debug: + msg: "The generated key is: {{ backup_local_ssh_key['content'] | b64decode }}" +... diff --git a/tasks/05_configure.yml b/tasks/05_configure.yml new file mode 100755 index 0000000..e055c20 --- /dev/null +++ b/tasks/05_configure.yml @@ -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 }}" +... diff --git a/tasks/07_install_timer.yml b/tasks/07_install_timer.yml new file mode 100644 index 0000000..4ca6afa --- /dev/null +++ b/tasks/07_install_timer.yml @@ -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 diff --git a/tasks/install_package.yml b/tasks/install_package.yml deleted file mode 100644 index f153ecb..0000000 --- a/tasks/install_package.yml +++ /dev/null @@ -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 }}" diff --git a/tasks/install_pip.yml b/tasks/install_pip.yml deleted file mode 100644 index 1f72f39..0000000 --- a/tasks/install_pip.yml +++ /dev/null @@ -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" diff --git a/tasks/main.yml b/tasks/main.yml old mode 100755 new mode 100644 index 4b67356..d6b56c1 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -1,96 +1,7 @@ --- -- name: Ensure legacy hooks aren't used - assert: - that: - - borgmatic_failure_command is undefined - - borgmatic_before_backup_command is undefined - - borgmatic_after_backup_command is undefined - msg: Please use the new borgmatic_hooks variable instead of individual before/after/failure hooks. - -- name: Include OS-specific variables - include_vars: "{{ item }}" - with_first_found: - - "{{ ansible_distribution }}-{{ ansible_distribution_major_version }}.yml" - - "{{ ansible_os_family }}-{{ ansible_distribution_major_version }}.yml" - - "{{ ansible_distribution }}.yml" - - "{{ ansible_os_family }}.yml" - - "{{ ansible_lsb.id }}.yml" - -- name: Install general dependencies (cron and openssh) - package: - name: "{{ borg_dep_packages }}" - state: present - -- name: Install Borg and Borgmatic - ansible.builtin.include_tasks: - file: install_{{ borg_install_method }}.yml - -- name: Ensure root has SSH key. - user: - name: "root" - generate_ssh_key: yes - ssh_key_file: "{{ ssh_key_file }}" - ssh_key_type: ed25519 - register: root_user - -- name: Print key created for root user (use for remote repo) - debug: - var: root_user['ssh_public_key'] - -- name: Ensure /etc/borgmatic exists - file: - path: /etc/borgmatic - state: directory - mode: 0700 - owner: root - -- name: Add Borgmatic configuration - template: - src: config.yaml.j2 - dest: "/etc/borgmatic/{{ borgmatic_config_name }}" - mode: 0600 - -- name: Add cron-job for borgmatic (large repo, create and check separate) - block: - - name: Add cron job for regular create and prune - cron: - name: "{{ borgmatic_cron_name }}" - hour: "{{ borgmatic_cron_hour }}" - minute: "{{ borgmatic_cron_minute }}" - user: "root" - cron_file: "{{ borgmatic_cron_name }}" - job: "borgmatic -c /etc/borgmatic/{{ borgmatic_config_name }} -C -p" - - name: Add cron job for infrequent checks - cron: - name: "{{ borgmatic_cron_name }}-check" - day: "{{ borgmatic_cron_checks_day }}" - hour: "{{ borgmatic_cron_checks_hour }}" - minute: "{{ borgmatic_cron_checks_minute }}" - user: "root" - cron_file: "{{ borgmatic_cron_name }}" - job: "borgmatic -c /etc/borgmatic/{{ borgmatic_config_name }} -k" - when: borgmatic_large_repo - -- name: Add cron-job for borgmatic (normal-sized repo) - block: - - name: Add cron job for create, check and prune - cron: - name: "{{ borgmatic_cron_name }}" - hour: "{{ borgmatic_cron_hour }}" - minute: "{{ borgmatic_cron_minute }}" - user: "root" - cron_file: "{{ borgmatic_cron_name }}" - job: "borgmatic -c /etc/borgmatic/{{ borgmatic_config_name }}" - - name: Ensure separate check cron job is absent - cron: - name: "{{ borgmatic_cron_name }}-check" - state: absent - when: not borgmatic_large_repo - -- name: Set PATH for borgmatic cron job. - cron: - user: "root" - cron_file: "{{ borgmatic_cron_name }}" - name: PATH - env: yes - value: /usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +- name: Add and run all plays + include_tasks: "{{ bak_element }}" + with_items: "{{ lookup('ansible.builtin.fileglob', '*.yml').split(',') | reject('search', 'main.yml') | reject('search', 'noauto_*') | sort }}" + loop_control: + loop_var: bak_element +... diff --git a/tasks/noauto_create_backup_user_and_group.yml b/tasks/noauto_create_backup_user_and_group.yml new file mode 100644 index 0000000..d11526e --- /dev/null +++ b/tasks/noauto_create_backup_user_and_group.yml @@ -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 }}" +... diff --git a/tasks/noauto_create_timer_cron.yml b/tasks/noauto_create_timer_cron.yml new file mode 100644 index 0000000..6a557a4 --- /dev/null +++ b/tasks/noauto_create_timer_cron.yml @@ -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 +... diff --git a/tasks/noauto_create_timer_systemd.yml b/tasks/noauto_create_timer_systemd.yml new file mode 100644 index 0000000..53e0b6b --- /dev/null +++ b/tasks/noauto_create_timer_systemd.yml @@ -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." +... diff --git a/tasks/noauto_install_package.yml b/tasks/noauto_install_package.yml new file mode 100644 index 0000000..d07e30b --- /dev/null +++ b/tasks/noauto_install_package.yml @@ -0,0 +1,21 @@ +--- +- name: Install borgbackup by distro + block: + - name: Check if EPEL repo is enabled, if installation from distro is requested + when: ansible_os_family == 'RedHat' + block: + - name: Get list of installed packages + ansible.builtin.package_facts: + manager: auto + - name: Ensure EPEL is enabled + ansible.builtin.assert: + that: + - "'epel-release' in ansible_facts.packages" + fail_msg: Need EPEL repo to install via distro package. + + - name: Install borgmatic and borg via distribution package manager + ansible.builtin.package: + name: "{{ item }}" + state: present + loop: "{{ borg_distro_packages }}" +... diff --git a/tasks/noauto_install_pip.yml b/tasks/noauto_install_pip.yml new file mode 100644 index 0000000..0cf26c1 --- /dev/null +++ b/tasks/noauto_install_pip.yml @@ -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" +... diff --git a/templates/borgmatic.service.j2 b/templates/borgmatic.service.j2 new file mode 100644 index 0000000..4e4406c --- /dev/null +++ b/templates/borgmatic.service.j2 @@ -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 diff --git a/templates/borgmatic.timer.j2 b/templates/borgmatic.timer.j2 new file mode 100644 index 0000000..2ff402c --- /dev/null +++ b/templates/borgmatic.timer.j2 @@ -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 \ No newline at end of file diff --git a/templates/config.yaml.j2 b/templates/config.yaml.j2 index c5148ee..69ddf33 100644 --- a/templates/config.yaml.j2 +++ b/templates/config.yaml.j2 @@ -1,11 +1,18 @@ #jinja2: lstrip_blocks: "True", trim_blocks: "True" --- +# Managed by Ansible, please don't edit manually + # Full config: https://torsion.org/borgmatic/docs/reference/config.yaml location: +{% if borg_source_directories is not defined or borg_source_directories | length == 0 %} source_directories: -{% 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 }} diff --git a/vars/Archlinux.yml b/vars/Archlinux.yml index 0ec7e01..48c3688 100644 --- a/vars/Archlinux.yml +++ b/vars/Archlinux.yml @@ -1,8 +1,9 @@ --- borg_dep_packages: - - cronie - openssh +borg_cron_package: cronie + borg_pip_packages: - gcc - pkgconfig diff --git a/vars/Debian.yml b/vars/Debian.yml index 03d7d87..c5fb44b 100644 --- a/vars/Debian.yml +++ b/vars/Debian.yml @@ -1,7 +1,8 @@ --- borg_dep_packages: - openssh-client - - cron + +borg_cron_package: cron borg_pip_packages: - libssl-dev diff --git a/vars/Fedora.yml b/vars/Fedora.yml index 6a2166b..a5583ec 100644 --- a/vars/Fedora.yml +++ b/vars/Fedora.yml @@ -1,8 +1,9 @@ --- borg_dep_packages: - - cronie - openssh-clients +borg_cron_package: cronie + borg_pip_packages: - libacl-devel - libacl diff --git a/vars/ManjaroLinux.yml b/vars/ManjaroLinux.yml index 52e70f6..fd4a65b 100644 --- a/vars/ManjaroLinux.yml +++ b/vars/ManjaroLinux.yml @@ -1,7 +1,8 @@ --- borg_dep_packages: - openssh - - cronie + +borg_cron_package: cronie borg_pip_packages: # untested - libssl-dev diff --git a/vars/RedHat-8.yml b/vars/RedHat-8.yml index 4673e05..4497b8d 100644 --- a/vars/RedHat-8.yml +++ b/vars/RedHat-8.yml @@ -1,7 +1,8 @@ --- borg_dep_packages: - openssh-clients - - cronie + +borg_cron_package: cronie borg_pip_packages: - libacl-devel diff --git a/vars/RedHat-9.yml b/vars/RedHat-9.yml index 50112d3..2b900f4 100644 --- a/vars/RedHat-9.yml +++ b/vars/RedHat-9.yml @@ -1,8 +1,9 @@ --- borg_dep_packages: - - cronie - openssh-clients +borg_cron_package: cronie + borg_pip_packages: - libacl-devel - libacl diff --git a/vars/RedHat.yml b/vars/RedHat.yml index 7c5f8b6..3115a75 100644 --- a/vars/RedHat.yml +++ b/vars/RedHat.yml @@ -1,8 +1,9 @@ --- borg_dep_packages: - - cronie - openssh-clients +borg_cron_package: cronie + borg_pip_packages: - libacl-devel - libacl