Merge branch 'main' into extra-vars-in-backup

Signed-off-by: Sondre Batalden <151748642+nuz014@users.noreply.github.com>
This commit is contained in:
Sondre Batalden 2026-03-06 14:44:00 +01:00 committed by GitHub
commit 9947e791e8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 79 additions and 42 deletions

View file

@ -11,11 +11,11 @@ jobs:
steps:
- name: 'checkout git repo'
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Run ansible-lint
uses: ansible-actions/ansible-lint-action@v1.0.3
uses: ansible-actions/ansible-lint-action@v1.1.0
with:
target: "./"

View file

@ -13,7 +13,7 @@ jobs:
steps:
- name: 'Checkout git repo'
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
submodules: true
fetch-depth: 0

View file

@ -11,7 +11,7 @@ jobs:
steps:
- name: 'checkout git repo'
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
submodules: true
fetch-depth: 0

View file

@ -74,14 +74,17 @@ ansible-galaxy install roles-ansible.restic
| `restic_install_path` | `'/usr/local/bin'` | Install location for the restic binary |
| `restic_script_dir` | `'/opt/restic'` | Location of the generated backup scripts |
| `restic_backup_script_shell` | `sh` | Shell to use for run of backup script |
| `restic_pid_dir` | `'/var/run/restic'` | Location of the PID files that lock each backup script to a single running instance |
| `restic_log_dir` | `'{{ restic_script_dir }}/log'` | Location of the logs of the backup scripts |
| `restic_repos` | `{}` | A dictionary of repositories where snapshots are stored. *(More Info: [Repos](#Repos))* |
| `restic_backups` | `{}` (or `[]`) | A list of dictionaries specifying the files and directories to be backed up *(More Infos: [Backups](#Backups))* |
| `restic_create_schedule` | `false` | Should we schedule each backup? Either via cronjob or via systemd timer. |
| `restic_backup_now` | `false` | Whether or not the backup script should be run immediately |
| `restic_schedule_type` | `systemd` | Here you can define if we create a ``cronjob`` or a ``systemd`` timer. If it fails to create a systemd timer, a cronjob will be created. |
| `restic_dir_owner` | `'{{ansible_user}}'` | The owner of all created dirs |
| `restic_dir_group` | `'{{ansible_user}}'` | The group of all created dirs |
| `restic_user` | `'restic'` | System account that owns the restic files and runs scheduled tasks. |
| `restic_create_user` | `"{{ restic_user != 'root' }}"` | Controls if the role should create `restic_user`. Useful to skip creation when an existing account or `root` is used. |
| `restic_dir_owner` | `'{{ restic_user }}'` | The owner of all created dirs |
| `restic_dir_group` | `'{{ restic_user }}'` | The group of all created dirs |
| `restic_no_log` | `true` | Set to false to see hidden ansible logs |
| `restic_do_not_cleanup_cron ` | `false` | We changed the cron location and clean up the old one. You can skip the cleanup here |
| `restic__cache_config` | `false` | Configure custom cache directory |
@ -177,6 +180,7 @@ Available variables:
| `prune` | no (`false`) | If `true`, the `restic forget` command in the script has the [`--prune` option](https://restic.readthedocs.io/en/stable/060_forget.html#removing-backup-snapshots) appended. |
| `forget_extra_args` | no | Extra arguments to pass to the `restic forget` command. |
| `backup_extra_args` | no | Extra arguments to pass to the `restic backup` command (e.g. `--retry-lock 5m`). |
| `skip_forget` | no | Skip restic forget, eg if you have a separate cleanup script. |
| `scheduled` | no (`false`) | If `restic_create_schedule` is set to `true`, this backup is scheduled and tries to create a systemd timer unit. If it fails, it is creating a cronjob. |
| `schedule_oncalendar` | ``'*-*-* 02:00:00'`` | The time for the systemd timer. Please notice the randomDelaySec option. By Default the backup is done every night at 2 am (+0-4h). But only if scheduled is true. |
| `schedule_minute` | no (`0`) | Minute when the job is run. ( 0-59, *, */2, etc ) |

View file

@ -5,6 +5,7 @@ restic_download_path: '/opt/restic'
restic_install_path: '/usr/local/bin'
restic_script_dir: '/opt/restic'
restic_backup_script_shell: sh
restic_pid_dir: '/var/run/restic'
restic_log_dir: '{{ restic_script_dir }}/log'
restic_repos: {}
restic_backups: []
@ -15,6 +16,7 @@ restic_backup_now: false
restic_no_log: true
restic_user: restic
restic_create_user: "{{ restic_user != 'root' }}"
restic_dir_owner: '{{ restic_user }}'
restic_dir_group: '{{ restic_user }}'

View file

@ -13,4 +13,4 @@
- restic_create_schedule
- item.name is defined
- item.scheduled | default(false)
- ansible_service_mgr == 'systemd'
- ansible_facts['service_mgr'] == 'systemd'

View file

@ -7,7 +7,7 @@
success_msg: "Congratulations. You are using ansible version {{ ansible_version.full }}"
delegate_to: localhost
when:
- ansible_service_mgr != 'systemd' or restic_force_cron | default(false) or restic_schedule_type == "cronjob"
- ansible_facts['service_mgr'] != 'systemd' or restic_force_cron | default(false) or restic_schedule_type == "cronjob"
register: old_af
failed_when: false
ignore_errors: true

View file

@ -3,4 +3,4 @@
- name: Message
ansible.builtin.fail:
msg: 'Your {{ ansible_system }} is not yet supported'
msg: 'Your {{ ansible_facts["system"] }} is not yet supported'

View file

@ -3,4 +3,4 @@
- name: Message
ansible.builtin.debug:
msg: 'Your {{ ansible_system }} is not supported'
msg: 'Your {{ ansible_facts["system"] }} is not supported'

View file

@ -26,7 +26,7 @@
- name: Ensure restic binary has cap_dac_read_search capability
community.general.capabilities:
path: "/opt/restic/bin/restic-{{ restic_version }}"
path: "{{ restic_download_path }}/bin/restic-{{ restic_version }}"
capability: cap_dac_read_search=+ep
state: present

View file

@ -24,18 +24,18 @@
loop_control:
loop_var: loop_distribution
vars:
distribution: '{{ ansible_distribution }}'
distribution_version: '{{ ansible_distribution_version }}'
distribution_major_version: '{{ ansible_distribution_major_version }}'
distribution: '{{ ansible_facts["distribution"] }}'
distribution_version: '{{ ansible_facts["distribution_version"] }}'
distribution_major_version: '{{ ansible_facts["distribution_major_version"] }}'
- name: Schedule restic backup
ansible.builtin.include_tasks: 'schedule.yml'
loop_control:
loop_var: loop_distribution
vars:
distribution: '{{ ansible_distribution }}'
distribution_version: '{{ ansible_distribution_version }}'
distribution_major_version: '{{ ansible_distribution_major_version }}'
distribution: '{{ ansible_facts["distribution"] }}'
distribution_version: '{{ ansible_facts["distribution_version"] }}'
distribution_major_version: '{{ ansible_facts["distribution_major_version"] }}'
- name: Set user permissions on folders
ansible.builtin.include_tasks: 'permissions.yml'

View file

@ -1,4 +1,13 @@
---
- name: Ensure pid folder exists and is writeable
become: true
ansible.builtin.file:
path: "{{ restic_pid_dir }}"
state: directory
owner: "{{ restic_user }}"
group: "{{ restic_user }}"
mode: "0755"
- name: Ensure log folder exists and is writeable
become: true
ansible.builtin.file:
@ -11,6 +20,7 @@
become: true
ansible.builtin.file:
path: "{{ restic__cache_dir }}"
state: directory
owner: "{{ restic_user }}"
group: "{{ restic_user }}"
mode: "0750"
@ -24,5 +34,6 @@
group: "{{ restic_user }}"
recurse: true
with_items:
- "{{ restic_pid_dir }}"
- "{{ restic_log_dir }}"
- "{{ restic__cache_dir }}"

View file

@ -1,7 +1,7 @@
---
- name: (SCHEDULE) (SYSTEMD) create systemd timer
when:
- ansible_service_mgr == 'systemd'
- ansible_facts['service_mgr'] == 'systemd'
- restic_schedule_type == "systemd"
- restic_create_schedule | bool
block:

View file

@ -2,14 +2,14 @@
- name: (SCHEDULE) create restic systemd timer
ansible.builtin.include_tasks: restic_create_systemd.yml
when:
- ansible_service_mgr == 'systemd'
- ansible_facts['service_mgr'] == 'systemd'
- restic_schedule_type == "systemd"
- restic_create_schedule | bool
- name: (SCHEDULE) delete systemd timers if available
ansible.builtin.include_tasks: restic_delete_systemd.yml
when:
- ansible_service_mgr == 'systemd'
- ansible_facts['service_mgr'] == 'systemd'
- restic_schedule_type == "cronjob" or restic_force_cron | default(false)
- restic_create_schedule | bool
@ -21,13 +21,13 @@
ansible.builtin.include_tasks: restic_create_cron.yml
when:
- restic_create_schedule | bool
- ansible_service_mgr != 'systemd' or restic_force_cron | default(false) or restic_schedule_type == "cronjob"
- ansible_facts['service_mgr'] != 'systemd' or restic_force_cron | default(false) or restic_schedule_type == "cronjob"
- name: (SCHEDULE) remove restic cronjobs
ansible.builtin.include_tasks: restic_delete_cron.yml
when:
- restic_create_schedule | bool
- ansible_service_mgr == 'systemd'
- ansible_facts['service_mgr'] == 'systemd'
- not restic_force_cron | default(false)
- restic_schedule_type != "cronjob"
- not restic_do_not_cleanup_cron | bool

View file

@ -5,3 +5,6 @@
name: "{{ restic_user }}"
shell: "/sbin/nologin"
system: true
when:
- restic_create_user | bool
- restic_user != 'root'

View file

@ -42,3 +42,6 @@ BACKUP_NAME={{ item.name }}
{% if item.src is defined %}
BACKUP_SOURCE={{ item.src }}
{% endif %}
{% if restic__cache_config | bool -%}
export RESTIC_CACHE_DIR={{ restic__cache_dir }}
{% endif %}

View file

@ -3,20 +3,28 @@
# Backup script for {{ item.src|default('stdin') }}
# Use this file to create a Backup and prune existing data with one execution.
pid="/var/run/restic_backup_{{ item.name | regex_replace('\'', '\'\\\'\'') }}.pid"
pid="{{ restic_pid_dir }}/backup_{{ item.name | regex_replace('\'', '\'\\\'\'') }}.pid"
trap "rm -f $pid" SIGSEGV
trap "rm -f $pid" SIGINT
if [ -e $pid ]; then
echo "Another version of this restic backup script is already running!"
# Read the PID from the file
OLD_PID=$(cat "$pid")
# Check if the process is actually running
if ps -p "$OLD_PID" > /dev/null 2>&1; then
echo "Another version of this restic backup script is already running! (PID: $OLD_PID)"
{% if item.mail_on_error is defined and item.mail_on_error == true %}
mail -s "starting restic backup failed on {{ ansible_hostname }}" {{ item.mail_address }} <<< "Another restic backup process is already running. We canceled starting a new restic backup script running at {{ ansible_hostname }} at $(date -u '+%Y-%m-%d %H:%M:%S').
mail -s "starting restic backup failed on {{ ansible_facts['hostname'] }}" {{ item.mail_address }} <<< "Another restic backup process is already running. We canceled starting a new restic backup script running at {{ ansible_facts['hostname'] }} at $(date -u '+%Y-%m-%d %H:%M:%S').
{%- if item.src is defined -%}
{{ ' ' }}We tried to backup '{{ item.src }}'.
{%- endif -%}
{{ ' ' }}Please repair the restic-{{ item.name | replace(' ', '') }} job."
{% endif %}
exit # pid file exists, another instance is running, so now we politely exit
exit 1
else
echo "Warning: Stale PID file found. (process $OLD_PID is not running). Proceeding with execution" >&2
fi
else
echo $$ > $pid # pid file doesn't exit, create one and go on
fi
@ -43,7 +51,7 @@ fi
{% endif %}
{% if restic__cache_config | bool -%}
export XDG_CACHE_HOME={{ restic__cache_dir }}
export RESTIC_CACHE_DIR={{ restic__cache_dir }}
{% endif %}
{% if restic__limit_cpu_usage | bool -%}
@ -245,7 +253,7 @@ then
else
echo "$(date -u '+%Y-%m-%d %H:%M:%S') ERROR" {{ pre_backup_cmd_result_log }}
{% if item.mail_on_error is defined and item.mail_on_error == true %}
mail -s "restic backup failed on {{ ansible_hostname }}" {{ item.mail_address }} <<< "Something went wrong while running restic backup script running at {{ ansible_hostname }} at $(date -u '+%Y-%m-%d %H:%M:%S').
mail -s "restic backup failed on {{ ansible_facts['hostname'] }}" {{ item.mail_address }} <<< "Something went wrong while running restic backup script running at {{ ansible_facts['hostname'] }} at $(date -u '+%Y-%m-%d %H:%M:%S').
{%- if item.src is defined -%}
{{ ' ' }}We tried to backup '{{ item.src }}'.
{%- endif -%}
@ -283,7 +291,8 @@ fi
} \
{% endif %} {{ backup_output_log }}
case $? in
BACKUP_EXIT_CODE=$?
case $BACKUP_EXIT_CODE in
0)
echo "$(date -u '+%Y-%m-%d %H:%M:%S') OK" {{ backup_result_log }}
;;
@ -293,7 +302,7 @@ case $? in
*)
echo "$(date -u '+%Y-%m-%d %H:%M:%S') ERROR" {{ backup_result_log }}
{% if item.mail_on_error is defined and item.mail_on_error == true %}
mail -s "restic backup failed on {{ ansible_hostname }}" {{ item.mail_address }} <<< "Something went wrong while running restic backup script running at {{ ansible_hostname }} at $(date -u '+%Y-%m-%d %H:%M:%S').
mail -s "restic backup failed on {{ ansible_facts['hostname'] }}" {{ item.mail_address }} <<< "Something went wrong while running restic backup script running at {{ ansible_facts['hostname'] }} at $(date -u '+%Y-%m-%d %H:%M:%S').
{%- if item.src is defined -%}
{{ ' ' }}We tried to backup '{{ item.src }}'.
{%- endif -%}
@ -314,12 +323,15 @@ if [[ $? -eq 0 ]]
then
echo "$(date -u '+%Y-%m-%d %H:%M:%S') OK" {{ forget_result_log }}
{% if item.monitoring_call is defined %}
{{ item.monitoring_call }}
# Only call monitoring if backup also succeeded (exit code 0 or 3)
if [[ $BACKUP_EXIT_CODE -eq 0 ]]; then
{{ item.monitoring_call }}
fi
{% endif %}
else
echo "$(date -u '+%Y-%m-%d %H:%M:%S') ERROR" {{ forget_result_log }}
{% if item.mail_on_error is defined and item.mail_on_error == true %}
mail -s "restic backup failed on {{ ansible_hostname }}" {{ item.mail_address }} <<< "Something went wrong while running restic backup script running at {{ ansible_hostname }} at $(date -u '+%Y-%m-%d %H:%M:%S').
mail -s "restic backup failed on {{ ansible_facts['hostname'] }}" {{ item.mail_address }} <<< "Something went wrong while running restic backup script running at {{ ansible_facts['hostname'] }} at $(date -u '+%Y-%m-%d %H:%M:%S').
{%- if item.src is defined -%}
{{ ' ' }}We tried to backup '{{ item.src }}'.
{%- endif -%}
@ -334,15 +346,17 @@ fi
#}
{% if item.past_backup_cmd is defined %}
{{ item.past_backup_cmd }} {{ post_backup_cmd_output_log }}
{% if item.post_backup_cmd is defined %}
{% elif item.post_backup_cmd is defined %}
{{ item.post_backup_cmd }} {{ post_backup_cmd_output_log }}
{% endif %}
{% if item.past_backup_cmd is defined or item.post_backup_cmd is defined %}
if [[ $? -eq 0 ]]
then
echo "$(date -u '+%Y-%m-%d %H:%M:%S') OK" {{ post_backup_cmd_result_log }}
else
echo "$(date -u '+%Y-%m-%d %H:%M:%S') ERROR" {{ post_backup_cmd_result_log }}
{% if item.mail_on_error is defined and item.mail_on_error == true %}
mail -s "restic backup failed on {{ ansible_hostname }}" {{ item.mail_address }} <<< "Something went wrong while running restic backup script running at {{ ansible_hostname }} at $(date -u '+%Y-%m-%d %H:%M:%S').
mail -s "restic backup failed on {{ ansible_facts['hostname'] }}" {{ item.mail_address }} <<< "Something went wrong while running restic backup script running at {{ ansible_facts['hostname'] }} at $(date -u '+%Y-%m-%d %H:%M:%S').
{%- if item.src is defined -%}
{{ ' ' }}We tried to backup '{{ item.src }}'.
{%- endif -%}

View file

@ -15,9 +15,9 @@ restic_create_paths:
restic_bin_path: '{{ restic_download_path }}/bin/restic-{{ restic_version }}'
restic_url_r: 'https://github.com/restic/restic/releases/download/'
arch: '{{ ansible_architecture }}'
arch: '{{ ansible_facts["architecture"] }}'
restic_platform: '{{ _platform_map[arch] | default(arch) }}'
restic_system: '{{ ansible_system | lower }}'
restic_system: '{{ ansible_facts["system"] | lower }}'
restic_url_v: 'v{{ restic_version }}/restic_{{ restic_version }}_'
restic_file: '{{ restic_system }}_{{ restic_platform }}.bz2'
restic_url_default: '{{ restic_url_r }}{{ restic_url_v }}{{ restic_file }}'

View file

@ -1,14 +1,14 @@
---
restic_os_variables:
files:
- '{{ ansible_distribution }}-{{ ansible_distribution_version }}.yml'
- '{{ ansible_distribution }}-{{ ansible_distribution_major_version }}.yml'
- '{{ ansible_distribution }}.yml'
- '{{ ansible_os_family }}.yml'
- '{{ ansible_system }}.yml'
- '{{ ansible_facts["distribution"] }}-{{ ansible_facts["distribution_version"] }}.yml'
- '{{ ansible_facts["distribution"] }}-{{ ansible_facts["distribution_major_version"] }}.yml'
- '{{ ansible_facts["distribution"] }}.yml'
- '{{ ansible_facts["os_family"] }}.yml'
- '{{ ansible_facts["system"] }}.yml'
- 'defaults.yml'
paths:
- 'vars'
playbook_version_number: 30 # should be int
playbook_version_number: 31 # should be int
playbook_version_path: 'do1jlr.restic.version'