From e16cc72ab2505f53098789fd02cfcf01dff89b79 Mon Sep 17 00:00:00 2001 From: Sergey Malyuk Date: Fri, 12 Dec 2025 17:22:02 +0300 Subject: [PATCH 01/10] add borgmatic role --- roles/borgmatic/.ansible-lint | 16 +++++ roles/borgmatic/.gitignore | 3 + roles/borgmatic/.yamllint | 8 +++ roles/borgmatic/README.md | 40 +++++++++++ roles/borgmatic/conda.dev.yml | 11 ++++ roles/borgmatic/conda.prod.yml | 9 +++ roles/borgmatic/defaults/main.yml | 17 +++++ roles/borgmatic/handlers/main.yml | 1 + roles/borgmatic/meta/main.yml | 17 +++++ roles/borgmatic/molecule/default/converge.yml | 48 ++++++++++++++ roles/borgmatic/molecule/default/molecule.yml | 31 +++++++++ roles/borgmatic/molecule/default/verify.yml | 48 ++++++++++++++ roles/borgmatic/renovate.json | 6 ++ roles/borgmatic/requirements.ci.txt | 6 ++ roles/borgmatic/requirements.txt | 1 + roles/borgmatic/requirements.yml | 6 ++ roles/borgmatic/tasks/config.yml | 34 ++++++++++ roles/borgmatic/tasks/handle-ssh-keys.yml | 25 +++++++ roles/borgmatic/tasks/install.yml | 66 +++++++++++++++++++ roles/borgmatic/tasks/integrations.yml | 1 + roles/borgmatic/tasks/main.yml | 15 +++++ roles/borgmatic/tasks/run.yml | 22 +++++++ roles/borgmatic/vars/main.yml | 1 + 23 files changed, 432 insertions(+) create mode 100644 roles/borgmatic/.ansible-lint create mode 100644 roles/borgmatic/.gitignore create mode 100644 roles/borgmatic/.yamllint create mode 100644 roles/borgmatic/README.md create mode 100644 roles/borgmatic/conda.dev.yml create mode 100644 roles/borgmatic/conda.prod.yml create mode 100644 roles/borgmatic/defaults/main.yml create mode 100644 roles/borgmatic/handlers/main.yml create mode 100644 roles/borgmatic/meta/main.yml create mode 100644 roles/borgmatic/molecule/default/converge.yml create mode 100644 roles/borgmatic/molecule/default/molecule.yml create mode 100644 roles/borgmatic/molecule/default/verify.yml create mode 100644 roles/borgmatic/renovate.json create mode 100644 roles/borgmatic/requirements.ci.txt create mode 100644 roles/borgmatic/requirements.txt create mode 100644 roles/borgmatic/requirements.yml create mode 100644 roles/borgmatic/tasks/config.yml create mode 100644 roles/borgmatic/tasks/handle-ssh-keys.yml create mode 100644 roles/borgmatic/tasks/install.yml create mode 100644 roles/borgmatic/tasks/integrations.yml create mode 100644 roles/borgmatic/tasks/main.yml create mode 100644 roles/borgmatic/tasks/run.yml create mode 100644 roles/borgmatic/vars/main.yml diff --git a/roles/borgmatic/.ansible-lint b/roles/borgmatic/.ansible-lint new file mode 100644 index 0000000..f865478 --- /dev/null +++ b/roles/borgmatic/.ansible-lint @@ -0,0 +1,16 @@ +--- +profile: production +strict: true + +# Enable checking of loop variable prefixes in roles +loop_var_prefix: "^(__|{role}_)" + +skip_list: + - var-naming[no-role-prefix] + +warn_list: + - role-name[path] + - var-naming[no-role-prefix] + +exclude_paths: + - .github/ diff --git a/roles/borgmatic/.gitignore b/roles/borgmatic/.gitignore new file mode 100644 index 0000000..9451651 --- /dev/null +++ b/roles/borgmatic/.gitignore @@ -0,0 +1,3 @@ +.vscode +.idea +.lock diff --git a/roles/borgmatic/.yamllint b/roles/borgmatic/.yamllint new file mode 100644 index 0000000..611db54 --- /dev/null +++ b/roles/borgmatic/.yamllint @@ -0,0 +1,8 @@ +--- +rules: + brackets: + forbid: false + min-spaces-inside: 0 + max-spaces-inside: 2 + min-spaces-inside-empty: -1 + max-spaces-inside-empty: 2 diff --git a/roles/borgmatic/README.md b/roles/borgmatic/README.md new file mode 100644 index 0000000..ce5f940 --- /dev/null +++ b/roles/borgmatic/README.md @@ -0,0 +1,40 @@ +ansible-borgmatic +========= + +This is a wrapper around the `borgmatic` role from the `maxhoesel.borgbackup` collection. + +The wrapper solve the most outstading issue with the current implementation of the original role: inability to install latest (or arbitrary) versions of `borgmatic` and `borg`. + +In the case of Borg we are fetching a release from Github. + +In the case of Borgmatic we are installing it via `pipx`, as recommended by their official documentation found here: https://torsion.org/borgmatic/docs/how-to/set-up-backups/. + +Requirements +------------ + +- `maxhoesel.borgbackup` collection installed (see `requirements.yml`); + +Role Variables +-------------- + +None + +Dependencies +------------ + +None + +Example Playbook +---------------- + +See `molecule/default/converge.yml` + +License +------- + +BSD + +Author Information +------------------ + +corvus-migratorius@proton.me diff --git a/roles/borgmatic/conda.dev.yml b/roles/borgmatic/conda.dev.yml new file mode 100644 index 0000000..f8272ac --- /dev/null +++ b/roles/borgmatic/conda.dev.yml @@ -0,0 +1,11 @@ +--- +name: ansible-borgmatic +channels: + - conda-forge +dependencies: + - python~=3.12.0 + - pip>=24.2 + - actionlint + - pip: + - -r requirements.txt + - -r requirements.ci.txt diff --git a/roles/borgmatic/conda.prod.yml b/roles/borgmatic/conda.prod.yml new file mode 100644 index 0000000..2e7d5bd --- /dev/null +++ b/roles/borgmatic/conda.prod.yml @@ -0,0 +1,9 @@ +--- +name: ansible-borgmatic +channels: + - conda-forge +dependencies: + - python~=3.12.0 + - pip>=24.2 + - pip: + - -r requirements.txt diff --git a/roles/borgmatic/defaults/main.yml b/roles/borgmatic/defaults/main.yml new file mode 100644 index 0000000..6ae71ef --- /dev/null +++ b/roles/borgmatic/defaults/main.yml @@ -0,0 +1,17 @@ +--- +borg_version: "1.4.0" +glibc_version: "2.36" +pipx_version: "1.7.1" +borg_binary_url: "https://github.com/borgbackup/borg/releases/download/{{ borg_version }}/borg-linux-glibc{{ glibc_version | replace('.', '') }}.tgz" +borgmatic_pipx_bin_dir: "/opt/borgmatic/bin" +borgmatic_schedule_oncalendar: "daily" +push_pubkey: true +ssh_key_path: "/root/borgmatic/id_ed25519" +borg_compression: "lz4" +borg_keep_hourly: 0 +borg_keep_daily: 3 +borg_keep_weekly: 3 +borg_keep_monthly: 1 +borg_keep_yearly: 0 +borg_uptime_kuma: +borg_loki: diff --git a/roles/borgmatic/handlers/main.yml b/roles/borgmatic/handlers/main.yml new file mode 100644 index 0000000..ed97d53 --- /dev/null +++ b/roles/borgmatic/handlers/main.yml @@ -0,0 +1 @@ +--- diff --git a/roles/borgmatic/meta/main.yml b/roles/borgmatic/meta/main.yml new file mode 100644 index 0000000..c99f58c --- /dev/null +++ b/roles/borgmatic/meta/main.yml @@ -0,0 +1,17 @@ +--- +galaxy_info: + role_name: "borgmatic" + namespace: genlab + author: "Alexander Gorelyshev" + company: "Genlab, LLC" + description: "" + license: "MIT" + min_ansible_version: "2.1" + + platforms: + - name: "Ubuntu" + versions: [ "focal", "jammy", "noble" ] + + galaxy_tags: [ ] + +dependencies: [] diff --git a/roles/borgmatic/molecule/default/converge.yml b/roles/borgmatic/molecule/default/converge.yml new file mode 100644 index 0000000..eabe4f7 --- /dev/null +++ b/roles/borgmatic/molecule/default/converge.yml @@ -0,0 +1,48 @@ +--- +- name: Converge + hosts: all + vars: + repo_path: "/home/borg/test-repo" + + pre_tasks: + - name: "Create a user for borg" + ansible.builtin.user: + name: borg + shell: /bin/bash + create_home: true + + - name: "Generate test data file" + ansible.builtin.copy: + dest: "/tmp/data" + content: "This is a test file!" + owner: "{{ ansible_user_id }}" + group: "{{ ansible_user_id }}" + mode: "0644" + + - name: "Ensure the repo path exists" + ansible.builtin.file: + path: "{{ repo_path }}" + state: directory + owner: "borg" + mode: "0700" + + - name: "Install openssh-server" + ansible.builtin.apt: + name: openssh-server + state: present + update_cache: true + + - name: "Start an SSH openssh-server" + ansible.builtin.systemd: + name: ssh + state: started + + roles: + - role: genlab.borgmatic + borg_source_directories: + - "/tmp/data" + borg_repo_path: "ssh://borg@localhost/./test-repo" + borg_repo_label: "test-repo" + borg_encryption_passphrase: "secret" + repo_server_inventory_hostname: ubuntu # in production this should be an Ansible inventory hostname + repo_server_user: borg diff --git a/roles/borgmatic/molecule/default/molecule.yml b/roles/borgmatic/molecule/default/molecule.yml new file mode 100644 index 0000000..2910ca3 --- /dev/null +++ b/roles/borgmatic/molecule/default/molecule.yml @@ -0,0 +1,31 @@ +--- +dependency: + name: galaxy + +driver: + name: docker + +platforms: + - name: ubuntu + image: geerlingguy/docker-${MOLECULE_DISTRO:-ubuntu2404}-ansible:latest + pre_build_image: true + command: ${MOLECULE_DOCKER_COMMAND:-""} + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:rw + cgroupns_mode: host + privileged: true + +provisioner: + name: ansible + +verifier: + name: ansible + +scenario: + name: default + test_sequence: + - destroy + - create + - converge + # - idempotence + - verify diff --git a/roles/borgmatic/molecule/default/verify.yml b/roles/borgmatic/molecule/default/verify.yml new file mode 100644 index 0000000..67cdad1 --- /dev/null +++ b/roles/borgmatic/molecule/default/verify.yml @@ -0,0 +1,48 @@ +--- +- name: Verify + hosts: all + gather_facts: false + any_errors_fatal: true + + vars: + repo_path: "/home/borg/test-repo" + + tasks: + - name: "Include default vars" + ansible.builtin.include_vars: + dir: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') }}/defaults/" + extensions: [ 'yml' ] + + - name: "Check if Borg is installed" + changed_when: false + register: borg_installed_version + ansible.builtin.command: "/usr/bin/borg --version" + + - name: "Check Borg version" + ansible.builtin.assert: + that: borg_installed_version.stdout.find(borg_version) + success_msg: "borg version {{ borg_version }} is installed and working" + fail_msg: "borg version {{ borg_version }} is not installed or not working correctly" + + - name: "Check if Borgmatic is installed" + changed_when: false + register: borgmatic_installed_version + ansible.builtin.command: + cmd: "/usr/bin/borgmatic --version" + + - name: "Check that the test repo was created" + register: test_repo_readme + failed_when: test_repo_readme.stat.exists is false + ansible.builtin.stat: + path: "{{ repo_path }}" + + - name: "Check that the systemd timer for Borgmatic is up and running" + register: timer + ansible.builtin.systemd: + name: borgmatic.timer + + - name: "Assert that the timer is running" + ansible.builtin.assert: + that: timer.status.ActiveState == "active" + success_msg: "Timer is running" + fail_msg: "Unexpected timer state: '{{ timer.status.ActiveState }}'" diff --git a/roles/borgmatic/renovate.json b/roles/borgmatic/renovate.json new file mode 100644 index 0000000..5db72dd --- /dev/null +++ b/roles/borgmatic/renovate.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:recommended" + ] +} diff --git a/roles/borgmatic/requirements.ci.txt b/roles/borgmatic/requirements.ci.txt new file mode 100644 index 0000000..f99c76a --- /dev/null +++ b/roles/borgmatic/requirements.ci.txt @@ -0,0 +1,6 @@ +ansible-lint +molecule==24.12.0 +molecule-plugins[docker] +docker~=7.1.0 +requests==2.31.0 # pinned to the latest version not breaking Docker SDK +yamllint diff --git a/roles/borgmatic/requirements.txt b/roles/borgmatic/requirements.txt new file mode 100644 index 0000000..92f8677 --- /dev/null +++ b/roles/borgmatic/requirements.txt @@ -0,0 +1 @@ +ansible~=11.3.0 diff --git a/roles/borgmatic/requirements.yml b/roles/borgmatic/requirements.yml new file mode 100644 index 0000000..e2cdc9f --- /dev/null +++ b/roles/borgmatic/requirements.yml @@ -0,0 +1,6 @@ +# requirements file +--- +collections: + - name: https://github.com/maxhoesel/ansible-collection-borgbackup + type: git + version: "v2.0.1" diff --git a/roles/borgmatic/tasks/config.yml b/roles/borgmatic/tasks/config.yml new file mode 100644 index 0000000..f030017 --- /dev/null +++ b/roles/borgmatic/tasks/config.yml @@ -0,0 +1,34 @@ +--- +- name: "Compose basic configuration for Borgmatic" + ansible.builtin.set_fact: + borgmatic_composite_config: + source_directories: "{{ borg_source_directories }}" + repositories: + - path: "{{ borg_repo_path }}" + label: "{{ borg_repo_label }}" + encryption_passphrase: "{{ borg_encryption_passphrase }}" + compression: "{{ borg_compression }}" + # CLI output configuration + list_details: true + statistics: true + exclude_caches: true + # logging verbosity: + verbosity: 1 + syslog_verbosity: 1 + monitoring_verbosity: 1 + # backup depth + keep_hourly: "{{ borg_keep_hourly }}" + keep_daily: "{{ borg_keep_daily }}" + keep_weekly: "{{ borg_keep_weekly }}" + keep_monthly: "{{ borg_keep_monthly }}" + keep_yearly: "{{ borg_keep_yearly }}" + +- name: "Add Uptime Kuma configuration" + when: borg_uptime_kuma + ansible.builtin.set_fact: + borgmatic_composite_config: "{{ borgmatic_composite_config | combine({'uptime_kuma': borg_uptime_kuma}) }}" + +- name: "Add Loki configuration" + when: borg_loki + ansible.builtin.set_fact: + borgmatic_composite_config: "{{ borgmatic_composite_config | combine({'loki': borg_loki}) }}" diff --git a/roles/borgmatic/tasks/handle-ssh-keys.yml b/roles/borgmatic/tasks/handle-ssh-keys.yml new file mode 100644 index 0000000..126349b --- /dev/null +++ b/roles/borgmatic/tasks/handle-ssh-keys.yml @@ -0,0 +1,25 @@ +--- +- name: "Ensure the path for SSH keys exists" + ansible.builtin.file: + path: "{{ ssh_key_path | dirname }}" + state: directory + owner: root + group: root + mode: "0700" + +- name: "Generate an ed25519 SSH key pair with 100 KDF rounds" + register: ssh_key_pair + community.crypto.openssh_keypair: + type: ed25519 + path: "{{ ssh_key_path }}" + comment: "Generated by Ansible for Borgmatic" + force: false + mode: '0600' + +- name: "Push the SSH key pair to the Borg repo host" + when: push_pubkey + delegate_to: "{{ repo_server_inventory_hostname }}" + ansible.posix.authorized_key: + user: "{{ repo_server_user }}" + key: "{{ ssh_key_pair.public_key }}" + state: present diff --git a/roles/borgmatic/tasks/install.yml b/roles/borgmatic/tasks/install.yml new file mode 100644 index 0000000..98cf198 --- /dev/null +++ b/roles/borgmatic/tasks/install.yml @@ -0,0 +1,66 @@ +--- +- name: "Ensure that system dependencies are installed" + ansible.builtin.apt: + name: + - openssh-client + - python3-pip + - python3-venv + state: present + update_cache: true + cache_valid_time: 3600 + +- name: "Install pipx" + retries: 3 + delay: 1 + ansible.builtin.pip: + name: "pipx=={{ pipx_version }}" + executable: pip3 + break_system_packages: true + +- name: "Ensure pipx binary is available in PATH" + changed_when: false + ansible.builtin.command: + cmd: pipx ensurepath + +- name: "Install borgmatic via pipx" + retries: 3 + delay: 1 + environment: + PIPX_BIN_DIR: "{{ borgmatic_pipx_bin_dir }}" + community.general.pipx: + name: borgmatic + state: present + install_deps: true + +- name: "Install Borg if the correct version is not available" + block: + # we are looking for Borg installed in a directory that Max Hoesel's role exects to find it + - name: "Get the currently installed version of Borg" + changed_when: false + register: borg_version_installed + ansible.builtin.command: + cmd: /usr/bin/borg --version + + - name: "Check that the correct version of Borg is installed" + ansible.builtin.assert: + that: borg_version_installed.stdout.find(borg_version) + fail_msg: "The expected Borg version was not found: {{ borg_version_installed }}" + success_msg: "Found the expected Borg version ({{ borg_version }})" + + rescue: + - name: "Download Borg from a custom URL: '{{ borg_binary_url }}'" + retries: 3 + delay: 1 + ansible.builtin.unarchive: + src: "{{ borg_binary_url }}" + dest: "/opt/" + remote_src: true + owner: root + group: root + mode: "0755" + + - name: "Create a symbolic link for Borg" + ansible.builtin.file: + state: link + src: "/opt/borg-dir/borg.exe" + dest: "/usr/bin/borg" diff --git a/roles/borgmatic/tasks/integrations.yml b/roles/borgmatic/tasks/integrations.yml new file mode 100644 index 0000000..ed97d53 --- /dev/null +++ b/roles/borgmatic/tasks/integrations.yml @@ -0,0 +1 @@ +--- diff --git a/roles/borgmatic/tasks/main.yml b/roles/borgmatic/tasks/main.yml new file mode 100644 index 0000000..0207ec6 --- /dev/null +++ b/roles/borgmatic/tasks/main.yml @@ -0,0 +1,15 @@ +--- +- name: "Include tool installation tasks" + ansible.builtin.include_tasks: "install.yml" + +- name: "Include SSH key handling tasks" + ansible.builtin.include_tasks: "handle-ssh-keys.yml" + +- name: "Include configuration tasks" + ansible.builtin.include_tasks: "config.yml" + +- name: "Include tasks for third-party integrations" + ansible.builtin.include_tasks: "integrations.yml" + +- name: "Include tasks for running borgmatic" + ansible.builtin.include_tasks: "run.yml" diff --git a/roles/borgmatic/tasks/run.yml b/roles/borgmatic/tasks/run.yml new file mode 100644 index 0000000..182aa05 --- /dev/null +++ b/roles/borgmatic/tasks/run.yml @@ -0,0 +1,22 @@ +--- +# A workaround for maxhoesel.borgbackup.borgmatic that does not support custom paths +- name: "Create symbolic links for Borgmatic executables" + loop: + - borgmatic + - generate-borgmatic-config + - validate-borgmatic-config + ansible.builtin.file: + state: link + src: "{{ borgmatic_pipx_bin_dir }}/{{ item }}" + dest: /usr/bin/{{ item }} + +- name: "Configure and run Borgmatic" + ansible.builtin.include_role: + name: maxhoesel.borgbackup.borgmatic + vars: + borgmatic_install: false # we handle installation separately to get the recent version + # borgmatic_ssh_key_gen_options: "-t ed25519 -a 100" + borgmatic_ssh_key_path: "{{ ssh_key_path }}" + borgmatic_schedule_on: "{{ borgmatic_schedule_oncalendar }}" + borgmatic_schedule_max_random_delay: 600 + borgmatic_config: "{{ borgmatic_composite_config }}" diff --git a/roles/borgmatic/vars/main.yml b/roles/borgmatic/vars/main.yml new file mode 100644 index 0000000..ed97d53 --- /dev/null +++ b/roles/borgmatic/vars/main.yml @@ -0,0 +1 @@ +--- From c40b4928f71fed417f7e69494dee8a48c33c477e Mon Sep 17 00:00:00 2001 From: Sergey Malyuk Date: Fri, 12 Dec 2025 17:22:12 +0300 Subject: [PATCH 02/10] update meta --- README.md | 1 + galaxy.yml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5bd9d0d..e9151cd 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ ## Roles - [alertmanager](roles/alertmanager/README.md) +- [borgmatic](roles/borgmatic/README.md) - [dnsmasq](roles/dnsmasq/README.md) - [grafana](roles/grafana/README.md) - [ipmi_exporter](roles/ipmi_exporter/README.md) diff --git a/galaxy.yml b/galaxy.yml index c68bddb..409ec6a 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: genlab name: common -version: 0.9.0 +version: 0.10.0 readme: README.md authors: - Alexander Gorelyshev (corvus-migratorius@proton.me) From 3f4556f3b2932e9a4448d6dcd960b9c472a897ba Mon Sep 17 00:00:00 2001 From: Sergey Malyuk Date: Fri, 12 Dec 2025 18:35:37 +0300 Subject: [PATCH 03/10] fix some ansible-lint errors --- roles/borgmatic/defaults/main.yml | 21 +++++++------- roles/borgmatic/meta/main.yml | 4 +-- roles/borgmatic/molecule/default/converge.yml | 10 +++---- roles/borgmatic/molecule/default/verify.yml | 20 ++++++------- roles/borgmatic/tasks/config.yml | 28 +++++++++---------- roles/borgmatic/tasks/handle-ssh-keys.yml | 4 +-- roles/borgmatic/tasks/install.yml | 12 ++++---- 7 files changed, 50 insertions(+), 49 deletions(-) diff --git a/roles/borgmatic/defaults/main.yml b/roles/borgmatic/defaults/main.yml index 6ae71ef..4cfd1c1 100644 --- a/roles/borgmatic/defaults/main.yml +++ b/roles/borgmatic/defaults/main.yml @@ -1,17 +1,18 @@ --- -borg_version: "1.4.0" +borgmatic_version: "1.4.0" glibc_version: "2.36" pipx_version: "1.7.1" -borg_binary_url: "https://github.com/borgbackup/borg/releases/download/{{ borg_version }}/borg-linux-glibc{{ glibc_version | replace('.', '') }}.tgz" +borgmatic_binary_url: "https://github.com/borgbackup/borg/releases/download/{{ borgmatic_version }}/borg-linux-glibc{{ glibc_version | replace('.', '') }}.tgz" borgmatic_pipx_bin_dir: "/opt/borgmatic/bin" borgmatic_schedule_oncalendar: "daily" push_pubkey: true ssh_key_path: "/root/borgmatic/id_ed25519" -borg_compression: "lz4" -borg_keep_hourly: 0 -borg_keep_daily: 3 -borg_keep_weekly: 3 -borg_keep_monthly: 1 -borg_keep_yearly: 0 -borg_uptime_kuma: -borg_loki: +borgmatic_compression: "lz4" +borgmatic_keep_hourly: 0 +borgmatic_keep_daily: 3 +borgmatic_keep_weekly: 3 +borgmatic_keep_monthly: 1 +borgmatic_keep_yearly: 0 +borgmatic_uptime_kuma: +borgmatic_loki: +# todo: ansible-lint errors \ No newline at end of file diff --git a/roles/borgmatic/meta/main.yml b/roles/borgmatic/meta/main.yml index c99f58c..868031b 100644 --- a/roles/borgmatic/meta/main.yml +++ b/roles/borgmatic/meta/main.yml @@ -10,8 +10,8 @@ galaxy_info: platforms: - name: "Ubuntu" - versions: [ "focal", "jammy", "noble" ] + versions: ["focal", "jammy", "noble"] - galaxy_tags: [ ] + galaxy_tags: [] dependencies: [] diff --git a/roles/borgmatic/molecule/default/converge.yml b/roles/borgmatic/molecule/default/converge.yml index eabe4f7..cb3fdb1 100644 --- a/roles/borgmatic/molecule/default/converge.yml +++ b/roles/borgmatic/molecule/default/converge.yml @@ -38,11 +38,11 @@ state: started roles: - - role: genlab.borgmatic - borg_source_directories: + - role: genlab.common.borgmatic + borgmatic_source_directories: - "/tmp/data" - borg_repo_path: "ssh://borg@localhost/./test-repo" - borg_repo_label: "test-repo" - borg_encryption_passphrase: "secret" + borgmatic_repo_path: "ssh://borg@localhost/./test-repo" + borgmatic_repo_label: "test-repo" + borgmatic_encryption_passphrase: "secret" repo_server_inventory_hostname: ubuntu # in production this should be an Ansible inventory hostname repo_server_user: borg diff --git a/roles/borgmatic/molecule/default/verify.yml b/roles/borgmatic/molecule/default/verify.yml index 67cdad1..6edcb47 100644 --- a/roles/borgmatic/molecule/default/verify.yml +++ b/roles/borgmatic/molecule/default/verify.yml @@ -11,18 +11,18 @@ - name: "Include default vars" ansible.builtin.include_vars: dir: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') }}/defaults/" - extensions: [ 'yml' ] + extensions: ['yml'] - name: "Check if Borg is installed" changed_when: false - register: borg_installed_version + register: borgmatic_installed_version ansible.builtin.command: "/usr/bin/borg --version" - name: "Check Borg version" ansible.builtin.assert: - that: borg_installed_version.stdout.find(borg_version) - success_msg: "borg version {{ borg_version }} is installed and working" - fail_msg: "borg version {{ borg_version }} is not installed or not working correctly" + that: borgmatic_installed_version.stdout.find(borgmatic_version) + success_msg: "borg version {{ borgmatic_version }} is installed and working" + fail_msg: "borg version {{ borgmatic_version }} is not installed or not working correctly" - name: "Check if Borgmatic is installed" changed_when: false @@ -31,18 +31,18 @@ cmd: "/usr/bin/borgmatic --version" - name: "Check that the test repo was created" - register: test_repo_readme - failed_when: test_repo_readme.stat.exists is false + register: borgmatic_test_repo_readme + failed_when: borgmatic_test_repo_readme.stat.exists is false ansible.builtin.stat: path: "{{ repo_path }}" - name: "Check that the systemd timer for Borgmatic is up and running" - register: timer + register: borgmatic_timer ansible.builtin.systemd: name: borgmatic.timer - name: "Assert that the timer is running" ansible.builtin.assert: - that: timer.status.ActiveState == "active" + that: borgmatic_timer.status.ActiveState == "active" success_msg: "Timer is running" - fail_msg: "Unexpected timer state: '{{ timer.status.ActiveState }}'" + fail_msg: "Unexpected timer state: '{{ borgmatic_timer.status.ActiveState }}'" diff --git a/roles/borgmatic/tasks/config.yml b/roles/borgmatic/tasks/config.yml index f030017..78dc67d 100644 --- a/roles/borgmatic/tasks/config.yml +++ b/roles/borgmatic/tasks/config.yml @@ -2,12 +2,12 @@ - name: "Compose basic configuration for Borgmatic" ansible.builtin.set_fact: borgmatic_composite_config: - source_directories: "{{ borg_source_directories }}" + source_directories: "{{ borgmatic_source_directories }}" repositories: - - path: "{{ borg_repo_path }}" - label: "{{ borg_repo_label }}" - encryption_passphrase: "{{ borg_encryption_passphrase }}" - compression: "{{ borg_compression }}" + - path: "{{ borgmatic_repo_path }}" + label: "{{ borgmatic_repo_label }}" + encryption_passphrase: "{{ borgmatic_encryption_passphrase }}" + compression: "{{ borgmatic_compression }}" # CLI output configuration list_details: true statistics: true @@ -17,18 +17,18 @@ syslog_verbosity: 1 monitoring_verbosity: 1 # backup depth - keep_hourly: "{{ borg_keep_hourly }}" - keep_daily: "{{ borg_keep_daily }}" - keep_weekly: "{{ borg_keep_weekly }}" - keep_monthly: "{{ borg_keep_monthly }}" - keep_yearly: "{{ borg_keep_yearly }}" + keep_hourly: "{{ borgmatic_keep_hourly }}" + keep_daily: "{{ borgmatic_keep_daily }}" + keep_weekly: "{{ borgmatic_keep_weekly }}" + keep_monthly: "{{ borgmatic_keep_monthly }}" + keep_yearly: "{{ borgmatic_keep_yearly }}" - name: "Add Uptime Kuma configuration" - when: borg_uptime_kuma + when: borgmatic_uptime_kuma ansible.builtin.set_fact: - borgmatic_composite_config: "{{ borgmatic_composite_config | combine({'uptime_kuma': borg_uptime_kuma}) }}" + borgmatic_composite_config: "{{ borgmatic_composite_config | combine({'uptime_kuma': borgmatic_uptime_kuma}) }}" - name: "Add Loki configuration" - when: borg_loki + when: borgmatic_loki ansible.builtin.set_fact: - borgmatic_composite_config: "{{ borgmatic_composite_config | combine({'loki': borg_loki}) }}" + borgmatic_composite_config: "{{ borgmatic_composite_config | combine({'loki': borgmatic_loki}) }}" diff --git a/roles/borgmatic/tasks/handle-ssh-keys.yml b/roles/borgmatic/tasks/handle-ssh-keys.yml index 126349b..37db382 100644 --- a/roles/borgmatic/tasks/handle-ssh-keys.yml +++ b/roles/borgmatic/tasks/handle-ssh-keys.yml @@ -8,7 +8,7 @@ mode: "0700" - name: "Generate an ed25519 SSH key pair with 100 KDF rounds" - register: ssh_key_pair + register: borgmatic_ssh_key_pair community.crypto.openssh_keypair: type: ed25519 path: "{{ ssh_key_path }}" @@ -21,5 +21,5 @@ delegate_to: "{{ repo_server_inventory_hostname }}" ansible.posix.authorized_key: user: "{{ repo_server_user }}" - key: "{{ ssh_key_pair.public_key }}" + key: "{{ borgmatic_ssh_key_pair.public_key }}" state: present diff --git a/roles/borgmatic/tasks/install.yml b/roles/borgmatic/tasks/install.yml index 98cf198..0e6d718 100644 --- a/roles/borgmatic/tasks/install.yml +++ b/roles/borgmatic/tasks/install.yml @@ -37,22 +37,22 @@ # we are looking for Borg installed in a directory that Max Hoesel's role exects to find it - name: "Get the currently installed version of Borg" changed_when: false - register: borg_version_installed + register: borgmatic_version_installed ansible.builtin.command: cmd: /usr/bin/borg --version - name: "Check that the correct version of Borg is installed" ansible.builtin.assert: - that: borg_version_installed.stdout.find(borg_version) - fail_msg: "The expected Borg version was not found: {{ borg_version_installed }}" - success_msg: "Found the expected Borg version ({{ borg_version }})" + that: borgmatic_version_installed.stdout.find(borgmatic_version) + fail_msg: "The expected Borg version was not found: {{ borgmatic_version_installed }}" + success_msg: "Found the expected Borg version ({{ borgmatic_version }})" rescue: - - name: "Download Borg from a custom URL: '{{ borg_binary_url }}'" + - name: "Download Borg from a custom URL: '{{ borgmatic_binary_url }}'" retries: 3 delay: 1 ansible.builtin.unarchive: - src: "{{ borg_binary_url }}" + src: "{{ borgmatic_binary_url }}" dest: "/opt/" remote_src: true owner: root From 246905a2ee489fd6202276e3146a5fc35abe0660 Mon Sep 17 00:00:00 2001 From: Sergey Malyuk Date: Mon, 15 Dec 2025 12:20:12 +0300 Subject: [PATCH 04/10] fix ansible-lint errors --- roles/borgmatic/defaults/main.yml | 12 ++++++------ roles/borgmatic/tasks/handle-ssh-keys.yml | 6 +++--- roles/borgmatic/tasks/install.yml | 2 +- roles/borgmatic/tasks/run.yml | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/roles/borgmatic/defaults/main.yml b/roles/borgmatic/defaults/main.yml index 4cfd1c1..c96f1e8 100644 --- a/roles/borgmatic/defaults/main.yml +++ b/roles/borgmatic/defaults/main.yml @@ -1,12 +1,13 @@ --- borgmatic_version: "1.4.0" -glibc_version: "2.36" -pipx_version: "1.7.1" -borgmatic_binary_url: "https://github.com/borgbackup/borg/releases/download/{{ borgmatic_version }}/borg-linux-glibc{{ glibc_version | replace('.', '') }}.tgz" +borgmatic_glibc_version: "2.36" +borgmatic_pipx_version: "1.7.1" +borgmatic_binary_url: "\ + https://github.com/borgbackup/borg/releases/download/{{ borgmatic_version }}/borg-linux-glibc{{ borgmatic_glibc_version | replace('.', '') }}.tgz" borgmatic_pipx_bin_dir: "/opt/borgmatic/bin" borgmatic_schedule_oncalendar: "daily" -push_pubkey: true -ssh_key_path: "/root/borgmatic/id_ed25519" +borgmatic_push_pubkey: true +borgmatic_sshkey_path: "/root/borgmatic/id_ed25519" borgmatic_compression: "lz4" borgmatic_keep_hourly: 0 borgmatic_keep_daily: 3 @@ -15,4 +16,3 @@ borgmatic_keep_monthly: 1 borgmatic_keep_yearly: 0 borgmatic_uptime_kuma: borgmatic_loki: -# todo: ansible-lint errors \ No newline at end of file diff --git a/roles/borgmatic/tasks/handle-ssh-keys.yml b/roles/borgmatic/tasks/handle-ssh-keys.yml index 37db382..07e9c07 100644 --- a/roles/borgmatic/tasks/handle-ssh-keys.yml +++ b/roles/borgmatic/tasks/handle-ssh-keys.yml @@ -1,7 +1,7 @@ --- - name: "Ensure the path for SSH keys exists" ansible.builtin.file: - path: "{{ ssh_key_path | dirname }}" + path: "{{ borgmatic_sshkey_path | dirname }}" state: directory owner: root group: root @@ -11,13 +11,13 @@ register: borgmatic_ssh_key_pair community.crypto.openssh_keypair: type: ed25519 - path: "{{ ssh_key_path }}" + path: "{{ borgmatic_sshkey_path }}" comment: "Generated by Ansible for Borgmatic" force: false mode: '0600' - name: "Push the SSH key pair to the Borg repo host" - when: push_pubkey + when: borgmatic_push_pubkey delegate_to: "{{ repo_server_inventory_hostname }}" ansible.posix.authorized_key: user: "{{ repo_server_user }}" diff --git a/roles/borgmatic/tasks/install.yml b/roles/borgmatic/tasks/install.yml index 0e6d718..46f5203 100644 --- a/roles/borgmatic/tasks/install.yml +++ b/roles/borgmatic/tasks/install.yml @@ -13,7 +13,7 @@ retries: 3 delay: 1 ansible.builtin.pip: - name: "pipx=={{ pipx_version }}" + name: "pipx=={{ borgmatic_pipx_version }}" executable: pip3 break_system_packages: true diff --git a/roles/borgmatic/tasks/run.yml b/roles/borgmatic/tasks/run.yml index 182aa05..28051f5 100644 --- a/roles/borgmatic/tasks/run.yml +++ b/roles/borgmatic/tasks/run.yml @@ -16,7 +16,7 @@ vars: borgmatic_install: false # we handle installation separately to get the recent version # borgmatic_ssh_key_gen_options: "-t ed25519 -a 100" - borgmatic_ssh_key_path: "{{ ssh_key_path }}" + borgmatic_ssh_key_path: "{{ borgmatic_sshkey_path }}" borgmatic_schedule_on: "{{ borgmatic_schedule_oncalendar }}" borgmatic_schedule_max_random_delay: 600 borgmatic_config: "{{ borgmatic_composite_config }}" From b2277e43ba489305f2682f0959a2728261382ed6 Mon Sep 17 00:00:00 2001 From: Sergey Malyuk Date: Mon, 15 Dec 2025 12:34:19 +0300 Subject: [PATCH 05/10] remove garbage --- roles/borgmatic/.ansible-lint | 16 ---------------- roles/borgmatic/.gitignore | 3 --- roles/borgmatic/.yamllint | 8 -------- roles/borgmatic/conda.dev.yml | 11 ----------- roles/borgmatic/conda.prod.yml | 9 --------- roles/borgmatic/renovate.json | 6 ------ roles/borgmatic/requirements.ci.txt | 6 ------ roles/borgmatic/requirements.txt | 1 - roles/borgmatic/requirements.yml | 6 ------ 9 files changed, 66 deletions(-) delete mode 100644 roles/borgmatic/.ansible-lint delete mode 100644 roles/borgmatic/.gitignore delete mode 100644 roles/borgmatic/.yamllint delete mode 100644 roles/borgmatic/conda.dev.yml delete mode 100644 roles/borgmatic/conda.prod.yml delete mode 100644 roles/borgmatic/renovate.json delete mode 100644 roles/borgmatic/requirements.ci.txt delete mode 100644 roles/borgmatic/requirements.txt delete mode 100644 roles/borgmatic/requirements.yml diff --git a/roles/borgmatic/.ansible-lint b/roles/borgmatic/.ansible-lint deleted file mode 100644 index f865478..0000000 --- a/roles/borgmatic/.ansible-lint +++ /dev/null @@ -1,16 +0,0 @@ ---- -profile: production -strict: true - -# Enable checking of loop variable prefixes in roles -loop_var_prefix: "^(__|{role}_)" - -skip_list: - - var-naming[no-role-prefix] - -warn_list: - - role-name[path] - - var-naming[no-role-prefix] - -exclude_paths: - - .github/ diff --git a/roles/borgmatic/.gitignore b/roles/borgmatic/.gitignore deleted file mode 100644 index 9451651..0000000 --- a/roles/borgmatic/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.vscode -.idea -.lock diff --git a/roles/borgmatic/.yamllint b/roles/borgmatic/.yamllint deleted file mode 100644 index 611db54..0000000 --- a/roles/borgmatic/.yamllint +++ /dev/null @@ -1,8 +0,0 @@ ---- -rules: - brackets: - forbid: false - min-spaces-inside: 0 - max-spaces-inside: 2 - min-spaces-inside-empty: -1 - max-spaces-inside-empty: 2 diff --git a/roles/borgmatic/conda.dev.yml b/roles/borgmatic/conda.dev.yml deleted file mode 100644 index f8272ac..0000000 --- a/roles/borgmatic/conda.dev.yml +++ /dev/null @@ -1,11 +0,0 @@ ---- -name: ansible-borgmatic -channels: - - conda-forge -dependencies: - - python~=3.12.0 - - pip>=24.2 - - actionlint - - pip: - - -r requirements.txt - - -r requirements.ci.txt diff --git a/roles/borgmatic/conda.prod.yml b/roles/borgmatic/conda.prod.yml deleted file mode 100644 index 2e7d5bd..0000000 --- a/roles/borgmatic/conda.prod.yml +++ /dev/null @@ -1,9 +0,0 @@ ---- -name: ansible-borgmatic -channels: - - conda-forge -dependencies: - - python~=3.12.0 - - pip>=24.2 - - pip: - - -r requirements.txt diff --git a/roles/borgmatic/renovate.json b/roles/borgmatic/renovate.json deleted file mode 100644 index 5db72dd..0000000 --- a/roles/borgmatic/renovate.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": [ - "config:recommended" - ] -} diff --git a/roles/borgmatic/requirements.ci.txt b/roles/borgmatic/requirements.ci.txt deleted file mode 100644 index f99c76a..0000000 --- a/roles/borgmatic/requirements.ci.txt +++ /dev/null @@ -1,6 +0,0 @@ -ansible-lint -molecule==24.12.0 -molecule-plugins[docker] -docker~=7.1.0 -requests==2.31.0 # pinned to the latest version not breaking Docker SDK -yamllint diff --git a/roles/borgmatic/requirements.txt b/roles/borgmatic/requirements.txt deleted file mode 100644 index 92f8677..0000000 --- a/roles/borgmatic/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -ansible~=11.3.0 diff --git a/roles/borgmatic/requirements.yml b/roles/borgmatic/requirements.yml deleted file mode 100644 index e2cdc9f..0000000 --- a/roles/borgmatic/requirements.yml +++ /dev/null @@ -1,6 +0,0 @@ -# requirements file ---- -collections: - - name: https://github.com/maxhoesel/ansible-collection-borgbackup - type: git - version: "v2.0.1" From 57d9c0d3cbce922d05f26c4ce0b9190be4080a71 Mon Sep 17 00:00:00 2001 From: Sergey Malyuk Date: Mon, 15 Dec 2025 12:37:18 +0300 Subject: [PATCH 06/10] update dependencies --- .github/workflows/molecule.yml | 8 -------- requirements.yml | 3 +++ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/.github/workflows/molecule.yml b/.github/workflows/molecule.yml index 5fcb13d..2fde508 100644 --- a/.github/workflows/molecule.yml +++ b/.github/workflows/molecule.yml @@ -78,14 +78,6 @@ jobs: run: ansible-galaxy install -r requirements.yml shell: micromamba-shell {0} - - name: "Install community.general collection" - run: ansible-galaxy collection install community.general - shell: micromamba-shell {0} - - - name: "Install community.grafana collection" - run: ansible-galaxy collection install community.grafana - shell: micromamba-shell {0} - - name: "Run Molecule tests" if: ${{ matrix.role != '__no_role__' }} working-directory: ${{ matrix.role }} diff --git a/requirements.yml b/requirements.yml index a0cd255..493187f 100644 --- a/requirements.yml +++ b/requirements.yml @@ -1,3 +1,6 @@ --- collections: - name: ansible.posix + - name: community.general + - name: community.grafana + - name: community.docker From 8bf9916739fef07b52131a46e0b30445a4934b13 Mon Sep 17 00:00:00 2001 From: Sergey Malyuk Date: Mon, 15 Dec 2025 12:39:41 +0300 Subject: [PATCH 07/10] update dependencies --- requirements.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.yml b/requirements.yml index 493187f..b5c13cc 100644 --- a/requirements.yml +++ b/requirements.yml @@ -4,3 +4,4 @@ collections: - name: community.general - name: community.grafana - name: community.docker + - name: community.crypto From b142cb1bcaa89f2695b9c0b40a6875226219ea9a Mon Sep 17 00:00:00 2001 From: Sergey Malyuk Date: Mon, 15 Dec 2025 12:43:19 +0300 Subject: [PATCH 08/10] update dependencies --- requirements.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/requirements.yml b/requirements.yml index b5c13cc..9fbcca8 100644 --- a/requirements.yml +++ b/requirements.yml @@ -5,3 +5,5 @@ collections: - name: community.grafana - name: community.docker - name: community.crypto +roles: + - name: maxhoesel.borgbackup.borgmatic From 2b1f2497149b8ac50967bfff05a19706f9a6b81d Mon Sep 17 00:00:00 2001 From: Sergey Malyuk Date: Mon, 15 Dec 2025 12:49:15 +0300 Subject: [PATCH 09/10] update dependencies --- requirements.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.yml b/requirements.yml index 9fbcca8..e558ead 100644 --- a/requirements.yml +++ b/requirements.yml @@ -6,4 +6,4 @@ collections: - name: community.docker - name: community.crypto roles: - - name: maxhoesel.borgbackup.borgmatic + - name: maxhoesel.borgmatic From 85333e5455a0379668274578dee8a7fd84d8a4f3 Mon Sep 17 00:00:00 2001 From: Sergey Malyuk Date: Mon, 15 Dec 2025 12:51:17 +0300 Subject: [PATCH 10/10] update dependencies --- requirements.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/requirements.yml b/requirements.yml index e558ead..093988a 100644 --- a/requirements.yml +++ b/requirements.yml @@ -5,5 +5,4 @@ collections: - name: community.grafana - name: community.docker - name: community.crypto -roles: - - name: maxhoesel.borgmatic + - name: maxhoesel.borgbackup