From 4efff406edcf7341f2956e9209a976608dc2f65e Mon Sep 17 00:00:00 2001 From: Sylvain DAVID Date: Tue, 24 Oct 2017 15:21:47 +0200 Subject: [PATCH 01/12] include remote server name into backup/prune script filename, same for cron.d filename. beware of dots inside a filename in cron.d files --- tasks/borgbackup_client.yml | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/tasks/borgbackup_client.yml b/tasks/borgbackup_client.yml index 39fb077..a7ee100 100644 --- a/tasks/borgbackup_client.yml +++ b/tasks/borgbackup_client.yml @@ -80,30 +80,35 @@ failed_when: (borgbackup_initialize_result.rc != 0) and (borgbackup_initialize_result.stderr != "") and ('already exists' not in borgbackup_initialize_result.stderr) when: item.name not in initialized_repos -- name: backup scripts +- name: generate filename for backup / prune scripts + set_fact: + backup_suffix_script_filename: "backup_{{ borgbackup_client_backup_server.split('.')[0] }}" + prune_suffix_script_filename: "prune_{{ borgbackup_client_backup_server.split('.')[0] }}" + +- name: deploy backup scripts template: - dest: "{{ borgbackup_client_scripts_dir }}/{{ item.name }}.sh" + dest: "{{ borgbackup_client_scripts_dir }}/{{ item.name }}_{{ backup_suffix_script_filename }}.sh" src: job.sh.j2 owner: root group: root mode: 0700 with_items: "{{ borgbackup_client_jobs }}" -- name: backup cronjobs +- name: schedule backup scripts on cron cron: name: "borg backup {{ item.name }}" user: root - job: "{{ borgbackup_client_scripts_dir }}/{{ item.name }}.sh 2>&1 | /usr/bin/logger -t borgbackup" + job: "{{ borgbackup_client_scripts_dir }}/{{ item.name }}_{{ backup_suffix_script_filename }}.sh 2>&1 | /usr/bin/logger -t borgbackup" day: "{{ item.day | default('*') }}" hour: "{{ item.hour | default('1') }}" minute: "{{ item.minute | default('0') }}" state: present - cron_file: "borgbackup_backup" + cron_file: "borgbackup_{{ item.name }}_{{ backup_suffix_script_filename }}" with_items: "{{ borgbackup_client_jobs }}" - name: deploy prune scripts template: - dest: "{{ borgbackup_client_scripts_dir }}/prune_{{ item.name }}.sh" + dest: "{{ borgbackup_client_scripts_dir }}/{{ item.name }}_{{ prune_suffix_script_filename }}.sh" src: prune_job.sh.j2 owner: root group: root @@ -115,11 +120,11 @@ cron: name: "borg prune {{ item.name }}" user: root - job: "{{ borgbackup_client_scripts_dir }}/prune_{{ item.name }}.sh 2>&1 | /usr/bin/logger -t borgbackup" + job: "{{ borgbackup_client_scripts_dir }}/{{ item.name }}_{{ prune_suffix_script_filename }}.sh 2>&1 | /usr/bin/logger -t borgbackup" day: "{{ item.day | default('*') }}" hour: "{{ item.hour | default('1') }}" minute: "{{ item.minute | default('0') }}" state: present - cron_file: "borgbackup_prune" + cron_file: "borgbackup_{{ item.name }}_{{ prune_suffix_script_filename }}" with_items: "{{ borgbackup_prune_jobs }}" when: borgbackup_prune_enabled From ef47267b98183d66d96f56fcfe2c8560806fb9b6 Mon Sep 17 00:00:00 2001 From: Sylvain DAVID Date: Tue, 24 Oct 2017 15:35:18 +0200 Subject: [PATCH 02/12] backup name include hour and minute instead of time to allow multiple backup per day --- templates/job.sh.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/job.sh.j2 b/templates/job.sh.j2 index 8a5489b..0b5530f 100644 --- a/templates/job.sh.j2 +++ b/templates/job.sh.j2 @@ -9,7 +9,7 @@ REPOSITORY={{ borgbackup_server_user }}@{{ borgbackup_client_backup_server }}:{{ {{ borgbackup_binary }} create \ {{ item.options | default('--compression zlib,6') }} \ - $REPOSITORY::{{ ansible_hostname }}-$(date -I) \ + $REPOSITORY::{{ ansible_hostname }}-$(date +%Y-%m-%d_%H-%M) \ {{ item.directories | join(' ') }} \ {% for e in item.excludes %} --exclude '{{ e }}' \ From 8d9dde6b21a996fdda58d0d63f4e883c7a63158b Mon Sep 17 00:00:00 2001 From: Sylvain DAVID Date: Tue, 24 Oct 2017 15:51:44 +0200 Subject: [PATCH 03/12] add random_minute, random_hour quick and dirty --- defaults/main.yml | 64 +++++++++++++++++++++++++------------ tasks/borgbackup_client.yml | 8 ++--- 2 files changed, 48 insertions(+), 24 deletions(-) diff --git a/defaults/main.yml b/defaults/main.yml index 40655d7..fc2e9af 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -1,52 +1,76 @@ --- +## +## borg installation +## + borgbackup_install_from_binary: True borgbackup_install_from_repo: False - borgbackup_binary_version: "1.0.9" borgbackup_binary_platform: "borg-linux64" borgbackup_binary_uri: "https://github.com/borgbackup/borg/releases/download/{{ borgbackup_binary_version }}/{{ borgbackup_binary_platform }}" borgbackup_binary: "/usr/local/bin/borg" + + + +## +## borg server configuration +## +borgbackup_server: False +borgbackup_server_user: "borgbackup" +borgbackup_server_group: "borgbackup" +borgbackup_server_home: "/srv/borgbackup" +borgbackup_server_pool: "{{ borgbackup_server_home }}/repos" + + + +## +## borg client configuration +## borgbackup_client: False + # Specify the SSH private key type to use. By default role will generate # ED25519 keys if they are supported by the remote host, otherwise RSA keys # will be generated. borgbackup_client_ssh_key_type: '{{ "ed25519" if ("ssh-ed25519" in borgbackup_register_key_types.stdout_lines) else "rsa" }}' + borgbackup_client_ssh_key_file: "/root/.ssh/id_{{ borgbackup_client_ssh_key_type }}-backup" borgbackup_client_ssh_key_comment: 'root@{{ ansible_hostname }} generated by Ansible' borgbackup_client_scripts_dir: "/etc/borg" borgbackup_encryption_mode: "none" borgbackup_passphrase: "yoursecret" + +borgbackup_client_backup_server: +borgbackup_client_jobs: + +# example : #borgbackup_client_backup_server: backup01.example.com #borgbackup_client_jobs: # - name: system # options: "--compression zlib,6" # day: "*" -# hour: "{{ 6 | random }}" -# minute: "{{ 59 | random }}" +# hour: 0 +# minute: 0 # directories: # - "/etc/" # - "/home" # excludes: [] +# random_hour: 5 +# random_minute: 59 -borgbackup_server: False -borgbackup_server_user: "borgbackup" -borgbackup_server_group: "borgbackup" -borgbackup_server_home: "/srv/borgbackup" -borgbackup_server_pool: "{{ borgbackup_server_home }}/repos" +#borgbackup_prune_jobs: +# - name: system +# prune_options: "--keep-daily=7 --keep-weekly=4" +# day: "*" +# hour: 12 +# minute: 0 +# random_hour: 5 +# random_minute: 59 -borgbackup_prune_enabled: yes -borgbackup_prune_jobs: - - name: system - prune_options: "--keep-daily=7 --keep-weekly=4" - day: "*" - hour: "{{ 4 }}" - minute: "{{ 0 }}" - - name: scripts - prune_options: "--keep-within=10d" - day: "*" - hour: "{{ 4 }}" - minute: "{{ 0 }}" +# random_hour : a indempotent random value is computed between 0 and the value specified. +# Then, the crontab hour will be addition of hour and random_hour. +# random_minute has same behaviour. +# purpose is to set indempotent random crontab values that differs when many jobs are croned. diff --git a/tasks/borgbackup_client.yml b/tasks/borgbackup_client.yml index a7ee100..672ace5 100644 --- a/tasks/borgbackup_client.yml +++ b/tasks/borgbackup_client.yml @@ -100,8 +100,8 @@ user: root job: "{{ borgbackup_client_scripts_dir }}/{{ item.name }}_{{ backup_suffix_script_filename }}.sh 2>&1 | /usr/bin/logger -t borgbackup" day: "{{ item.day | default('*') }}" - hour: "{{ item.hour | default('1') }}" - minute: "{{ item.minute | default('0') }}" + hour: "{{ item.hour + (item.random_hour | random(seed=backup_suffix_script_filename)) | default('1') }}" + minute: "{{ item.minute + (item.random_minute | random(seed=backup_suffix_script_filename)) | default('0') }}" state: present cron_file: "borgbackup_{{ item.name }}_{{ backup_suffix_script_filename }}" with_items: "{{ borgbackup_client_jobs }}" @@ -122,8 +122,8 @@ user: root job: "{{ borgbackup_client_scripts_dir }}/{{ item.name }}_{{ prune_suffix_script_filename }}.sh 2>&1 | /usr/bin/logger -t borgbackup" day: "{{ item.day | default('*') }}" - hour: "{{ item.hour | default('1') }}" - minute: "{{ item.minute | default('0') }}" + hour: "{{ item.hour + (item.random_hour | random(seed=prune_suffix_script_filename)) | default('1') }}" + minute: "{{ item.minute + (item.random_minute | random(seed=prune_suffix_script_filename)) | default('0') }}" state: present cron_file: "borgbackup_{{ item.name }}_{{ prune_suffix_script_filename }}" with_items: "{{ borgbackup_prune_jobs }}" From e4202bfb410f84ded97e78612a9919edf99b4f24 Mon Sep 17 00:00:00 2001 From: Sylvain DAVID Date: Wed, 25 Oct 2017 15:37:27 +0200 Subject: [PATCH 04/12] improve documentation, fix many randomization issues : minute/hour seed should differ, remainder operation on hour/minute after computing, seed should differ on every host --- defaults/main.yml | 17 +++++++++-------- tasks/borgbackup_client.yml | 8 ++++---- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/defaults/main.yml b/defaults/main.yml index fc2e9af..0e333c1 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -52,23 +52,24 @@ borgbackup_client_jobs: # - name: system # options: "--compression zlib,6" # day: "*" -# hour: 0 -# minute: 0 +# hour: 0 # default value = 1 +# minute: 0 # default value = 0 +# random_hour: 5 # default value : ignore randomization +# random_minute: 59 # default value : ignore randomization # directories: # - "/etc/" # - "/home" # excludes: [] -# random_hour: 5 -# random_minute: 59 +borgbackup_prune_enabled: yes #borgbackup_prune_jobs: # - name: system # prune_options: "--keep-daily=7 --keep-weekly=4" # day: "*" -# hour: 12 -# minute: 0 -# random_hour: 5 -# random_minute: 59 +# hour: 12 # default value = 1 +# minute: 0 # default value = 0 +# random_hour: 5 # default value : ignore randomization +# random_minute: 59 # default value : ignore randomization # random_hour : a indempotent random value is computed between 0 and the value specified. # Then, the crontab hour will be addition of hour and random_hour. diff --git a/tasks/borgbackup_client.yml b/tasks/borgbackup_client.yml index 672ace5..3609a61 100644 --- a/tasks/borgbackup_client.yml +++ b/tasks/borgbackup_client.yml @@ -100,8 +100,8 @@ user: root job: "{{ borgbackup_client_scripts_dir }}/{{ item.name }}_{{ backup_suffix_script_filename }}.sh 2>&1 | /usr/bin/logger -t borgbackup" day: "{{ item.day | default('*') }}" - hour: "{{ item.hour + (item.random_hour | random(seed=backup_suffix_script_filename)) | default('1') }}" - minute: "{{ item.minute + (item.random_minute | random(seed=backup_suffix_script_filename)) | default('0') }}" + hour: "{{ (item.hour | default(1)) + (item.random_hour | random(seed=item.name + backup_suffix_script_filename + ansible_host))%24 if item.random_hour is defined else item.hour | default(1) }}" + minute: "{{ (item.minute | default(0)) + (item.random_minute | random(seed=ansible_host + item.name + backup_suffix_script_filename))%60 if item.random_minute is defined else item.minute | default(0) }}" state: present cron_file: "borgbackup_{{ item.name }}_{{ backup_suffix_script_filename }}" with_items: "{{ borgbackup_client_jobs }}" @@ -122,8 +122,8 @@ user: root job: "{{ borgbackup_client_scripts_dir }}/{{ item.name }}_{{ prune_suffix_script_filename }}.sh 2>&1 | /usr/bin/logger -t borgbackup" day: "{{ item.day | default('*') }}" - hour: "{{ item.hour + (item.random_hour | random(seed=prune_suffix_script_filename)) | default('1') }}" - minute: "{{ item.minute + (item.random_minute | random(seed=prune_suffix_script_filename)) | default('0') }}" + hour: "{{ (item.hour | default(1)) + (item.random_hour | random(seed=item.name + prune_suffix_script_filename + ansible_host))%24 if item.random_hour is defined else item.hour | default(1) }}" + minute: "{{ (item.minute | default(0)) + (item.random_minute | random(seed=ansible_host + item.name + prune_suffix_script_filename))%60 if item.random_minute is defined else item.minute | default(0) }}" state: present cron_file: "borgbackup_{{ item.name }}_{{ prune_suffix_script_filename }}" with_items: "{{ borgbackup_prune_jobs }}" From 10532fc61636e286c0f05e8189ffe6f2765ec353 Mon Sep 17 00:00:00 2001 From: Sylvain DAVID Date: Thu, 26 Oct 2017 17:36:44 +0200 Subject: [PATCH 05/12] add support lan-free backup --- defaults/main.yml | 4 ++++ tasks/borgbackup_client.yml | 5 +++-- templates/job.sh.j2 | 2 +- templates/prune_job.sh.j2 | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/defaults/main.yml b/defaults/main.yml index 0e333c1..7110ac0 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -43,7 +43,11 @@ borgbackup_client_scripts_dir: "/etc/borg" borgbackup_encryption_mode: "none" borgbackup_passphrase: "yoursecret" +# backup server IP or FQDN used during ansible installation AND backup operation. borgbackup_client_backup_server: + +# if defined, IP or FQDN used on backup operation. Usefull in case of LAN-free backup +borgbackup_client_backup_server_lanfreebackup: borgbackup_client_jobs: # example : diff --git a/tasks/borgbackup_client.yml b/tasks/borgbackup_client.yml index 3609a61..87b177d 100644 --- a/tasks/borgbackup_client.yml +++ b/tasks/borgbackup_client.yml @@ -50,7 +50,7 @@ state: directory - name: check if the repositories already exist - command: "{{ borgbackup_binary }} list {{ borgbackup_server_user }}@{{ borgbackup_client_backup_server }}:{{ item.name }}" + command: "{{ borgbackup_binary }} list {{ borgbackup_server_user }}@{{ borgbackup_client_backup_server_lanfreebackup | default(borgbackup_client_backup_server) }}:{{ item.name }}" environment: - BORG_RSH: "ssh -o StrictHostKeyChecking=no -i {{ borgbackup_client_ssh_key_file }}" - BORG_PASSPHRASE: "{{ borgbackup_passphrase }}" @@ -71,7 +71,7 @@ when: item.rc == 0 - name: initialize repositories - command: "{{ borgbackup_binary }} init --encryption {{ borgbackup_encryption_mode }} {{ borgbackup_server_user }}@{{ borgbackup_client_backup_server }}:{{ item.name }}" + command: "{{ borgbackup_binary }} init --encryption {{ borgbackup_encryption_mode }} {{ borgbackup_server_user }}@{{ borgbackup_client_backup_server_lanfreebackup | default(borgbackup_client_backup_server) }}:{{ item.name }}" environment: - BORG_RSH: "ssh -o StrictHostKeyChecking=no -i {{ borgbackup_client_ssh_key_file }}" - BORG_PASSPHRASE: "{{ borgbackup_passphrase }}" @@ -85,6 +85,7 @@ backup_suffix_script_filename: "backup_{{ borgbackup_client_backup_server.split('.')[0] }}" prune_suffix_script_filename: "prune_{{ borgbackup_client_backup_server.split('.')[0] }}" + - name: deploy backup scripts template: dest: "{{ borgbackup_client_scripts_dir }}/{{ item.name }}_{{ backup_suffix_script_filename }}.sh" diff --git a/templates/job.sh.j2 b/templates/job.sh.j2 index 0b5530f..24c2d44 100644 --- a/templates/job.sh.j2 +++ b/templates/job.sh.j2 @@ -5,7 +5,7 @@ set -e export BORG_RSH="ssh -i {{ borgbackup_client_ssh_key_file }}" export BORG_PASSPHRASE="{{ borgbackup_passphrase }}" -REPOSITORY={{ borgbackup_server_user }}@{{ borgbackup_client_backup_server }}:{{ item.name }} +REPOSITORY={{ borgbackup_server_user }}@{{ borgbackup_client_backup_server_lanfreebackup | default(borgbackup_client_backup_server) }}:{{ item.name }} {{ borgbackup_binary }} create \ {{ item.options | default('--compression zlib,6') }} \ diff --git a/templates/prune_job.sh.j2 b/templates/prune_job.sh.j2 index 4f532de..46ea122 100644 --- a/templates/prune_job.sh.j2 +++ b/templates/prune_job.sh.j2 @@ -5,7 +5,7 @@ set -e export BORG_RSH="ssh -i {{ borgbackup_client_ssh_key_file }}" export BORG_PASSPHRASE="{{ borgbackup_passphrase }}" -REPOSITORY={{ borgbackup_server_user }}@{{ borgbackup_client_backup_server }}:{{ item.name }} +REPOSITORY={{ borgbackup_server_user }}@{{ borgbackup_client_backup_server_lanfreebackup | default(borgbackup_client_backup_server) }}:{{ item.name }} {{ borgbackup_binary }} prune \ {{ item.prune_options }} \ From bd769aa8942a0a861d1c5900d679970db3acc089 Mon Sep 17 00:00:00 2001 From: Sylvain DAVID Date: Fri, 10 Nov 2017 23:12:16 +0100 Subject: [PATCH 06/12] change default version to 1.1.2 --- defaults/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/defaults/main.yml b/defaults/main.yml index 7110ac0..7ad3a9b 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -6,7 +6,7 @@ borgbackup_install_from_binary: True borgbackup_install_from_repo: False -borgbackup_binary_version: "1.0.9" +borgbackup_binary_version: "1.1.2" borgbackup_binary_platform: "borg-linux64" borgbackup_binary_uri: "https://github.com/borgbackup/borg/releases/download/{{ borgbackup_binary_version }}/{{ borgbackup_binary_platform }}" borgbackup_binary: "/usr/local/bin/borg" From e242f2b6ae7256ca1fa22011571abe72ddb2e44e Mon Sep 17 00:00:00 2001 From: Sylvain DAVID Date: Fri, 10 Nov 2017 23:14:44 +0100 Subject: [PATCH 07/12] feature : add repository check job. --- defaults/main.yml | 19 ++++++++++++++++--- tasks/borgbackup_client.yml | 36 ++++++++++++++++++++++++++++++++++-- templates/check_job.sh.j2 | 13 +++++++++++++ 3 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 templates/check_job.sh.j2 diff --git a/defaults/main.yml b/defaults/main.yml index 7ad3a9b..d634d2e 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -75,7 +75,20 @@ borgbackup_prune_enabled: yes # random_hour: 5 # default value : ignore randomization # random_minute: 59 # default value : ignore randomization -# random_hour : a indempotent random value is computed between 0 and the value specified. -# Then, the crontab hour will be addition of hour and random_hour. -# random_minute has same behaviour. +borgbackup_check_enabled: yes +#borgbackup_check_jobs: +# - name: system +# check_options: "--verbose" +# day: 1 +# hour: 12 # default value = 1 +# minute: 0 # default value = 0 +# random_hour: 5 # default value : ignore randomization +# random_minute: 59 # default value : ignore randomization +# random_day: 27 # default value : ignore randomization + +# about random : # purpose is to set indempotent random crontab values that differs when many jobs are croned. +# random_hour : if defined, a indempotent random value is computed between 0 and the value specified. +# Then, the crontab hour will be addition of hour and random_hour. +# a modulo 24 is applied in order to ensure valid hour are specified. +# random_minute and random_day works the same way. diff --git a/tasks/borgbackup_client.yml b/tasks/borgbackup_client.yml index 87b177d..7a79708 100644 --- a/tasks/borgbackup_client.yml +++ b/tasks/borgbackup_client.yml @@ -80,12 +80,15 @@ failed_when: (borgbackup_initialize_result.rc != 0) and (borgbackup_initialize_result.stderr != "") and ('already exists' not in borgbackup_initialize_result.stderr) when: item.name not in initialized_repos -- name: generate filename for backup / prune scripts +- name: generate filename for backup / prune / check scripts set_fact: backup_suffix_script_filename: "backup_{{ borgbackup_client_backup_server.split('.')[0] }}" prune_suffix_script_filename: "prune_{{ borgbackup_client_backup_server.split('.')[0] }}" + check_suffix_script_filename: "check_{{ borgbackup_client_backup_server.split('.')[0] }}" - +# +# backup scripts +# - name: deploy backup scripts template: dest: "{{ borgbackup_client_scripts_dir }}/{{ item.name }}_{{ backup_suffix_script_filename }}.sh" @@ -107,6 +110,9 @@ cron_file: "borgbackup_{{ item.name }}_{{ backup_suffix_script_filename }}" with_items: "{{ borgbackup_client_jobs }}" +# +# prune scripts +# - name: deploy prune scripts template: dest: "{{ borgbackup_client_scripts_dir }}/{{ item.name }}_{{ prune_suffix_script_filename }}.sh" @@ -129,3 +135,29 @@ cron_file: "borgbackup_{{ item.name }}_{{ prune_suffix_script_filename }}" with_items: "{{ borgbackup_prune_jobs }}" when: borgbackup_prune_enabled + +# +# check repository scripts +# +- name: deploy check scripts + template: + dest: "{{ borgbackup_client_scripts_dir }}/{{ item.name }}_{{ check_suffix_script_filename }}.sh" + src: check_job.sh.j2 + owner: root + group: root + mode: 0700 + with_items: "{{ borgbackup_check_jobs }}" + when: borgbackup_check_enabled + +- name: schedule check scripts on cron + cron: + name: "borg check {{ item.name }}" + user: root + job: "{{ borgbackup_client_scripts_dir }}/{{ item.name }}_{{ check_suffix_script_filename }}.sh 2>&1 | /usr/bin/logger -t borgbackup" + day: "{{ (item.day | default(1)) + (item.random_day | random(seed=item.name + check_suffix_script_filename + ansible_host))%28 if item.random_day is defined else item.day | default(1) }}" + hour: "{{ (item.hour | default(1)) + (item.random_hour | random(seed=item.name + check_suffix_script_filename + ansible_host))%24 if item.random_hour is defined else item.hour | default(1) }}" + minute: "{{ (item.minute | default(0)) + (item.random_minute | random(seed=ansible_host + item.name + check_suffix_script_filename))%60 if item.random_minute is defined else item.minute | default(0) }}" + state: present + cron_file: "borgbackup_{{ item.name }}_{{ check_suffix_script_filename }}" + with_items: "{{ borgbackup_check_jobs }}" + when: borgbackup_check_enabled diff --git a/templates/check_job.sh.j2 b/templates/check_job.sh.j2 new file mode 100644 index 0000000..cbeed9d --- /dev/null +++ b/templates/check_job.sh.j2 @@ -0,0 +1,13 @@ +#!/bin/sh + +set -e + +export BORG_RSH="ssh -i {{ borgbackup_client_ssh_key_file }}" +export BORG_PASSPHRASE="{{ borgbackup_passphrase }}" + +REPOSITORY={{ borgbackup_server_user }}@{{ borgbackup_client_backup_server_lanfreebackup | default(borgbackup_client_backup_server) }}:{{ item.name }} + +{{ borgbackup_binary }} check --show-rc --verbose \ + {{ item.check_options }} \ + $REPOSITORY \ + 2>&1 | /usr/bin/logger -t borgbackup_check_{{ item.name }}_{{ borgbackup_client_backup_server }} From 96beed90e2553904859417c0d072198cd6dda29d Mon Sep 17 00:00:00 2001 From: Sylvain DAVID Date: Fri, 10 Nov 2017 23:21:47 +0100 Subject: [PATCH 08/12] binary install now use symlinks to support ugrades --- tasks/install_binary.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tasks/install_binary.yml b/tasks/install_binary.yml index dfbd39a..0d1aed7 100644 --- a/tasks/install_binary.yml +++ b/tasks/install_binary.yml @@ -1,4 +1,14 @@ --- - name: Download borg binary - get_url: url="{{ borgbackup_binary_uri }}" dest="{{ borgbackup_binary }}" mode=755 + get_url: + url: "{{ borgbackup_binary_uri }}" + dest: "{{ borgbackup_binary }}-{{ borgbackup_binary_version }}" + mode: "755" + +- name: Link install + file: + src: "{{ borgbackup_binary }}-{{ borgbackup_binary_version }}" + dest: "{{ borgbackup_binary }}" + state: link + force: yes From 7ec815c3d42dde502c51a979af91c273b589ee4c Mon Sep 17 00:00:00 2001 From: Sylvain DAVID Date: Fri, 10 Nov 2017 23:21:58 +0100 Subject: [PATCH 09/12] feature : increase verbosity of create/prune job and send to syslog --- templates/job.sh.j2 | 3 ++- templates/prune_job.sh.j2 | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/templates/job.sh.j2 b/templates/job.sh.j2 index 24c2d44..4fd5792 100644 --- a/templates/job.sh.j2 +++ b/templates/job.sh.j2 @@ -7,10 +7,11 @@ export BORG_PASSPHRASE="{{ borgbackup_passphrase }}" REPOSITORY={{ borgbackup_server_user }}@{{ borgbackup_client_backup_server_lanfreebackup | default(borgbackup_client_backup_server) }}:{{ item.name }} -{{ borgbackup_binary }} create \ +{{ borgbackup_binary }} create --show-rc --verbose --stats \ {{ item.options | default('--compression zlib,6') }} \ $REPOSITORY::{{ ansible_hostname }}-$(date +%Y-%m-%d_%H-%M) \ {{ item.directories | join(' ') }} \ {% for e in item.excludes %} --exclude '{{ e }}' \ {% endfor %} + 2>&1 | /usr/bin/logger -t borgbackup_backup_{{ item.name }}_{{ borgbackup_client_backup_server }} \ No newline at end of file diff --git a/templates/prune_job.sh.j2 b/templates/prune_job.sh.j2 index 46ea122..34e2ae7 100644 --- a/templates/prune_job.sh.j2 +++ b/templates/prune_job.sh.j2 @@ -7,6 +7,7 @@ export BORG_PASSPHRASE="{{ borgbackup_passphrase }}" REPOSITORY={{ borgbackup_server_user }}@{{ borgbackup_client_backup_server_lanfreebackup | default(borgbackup_client_backup_server) }}:{{ item.name }} -{{ borgbackup_binary }} prune \ +{{ borgbackup_binary }} prune --show-rc --verbose --stats \ {{ item.prune_options }} \ - $REPOSITORY + $REPOSITORY \ + 2>&1 | /usr/bin/logger -t borgbackup_prune_{{ item.name }}_{{ borgbackup_client_backup_server }} From f7caee0af342816d441fcdb1efa7c9027dde834b Mon Sep 17 00:00:00 2001 From: Sylvain DAVID Date: Thu, 3 May 2018 10:41:52 +0200 Subject: [PATCH 10/12] feature : add lastlog status into /var/cache/borg for supervision, rename backup job as create job to fit with borg commands, improve documentation, change default version --- README.md | 2 +- defaults/main.yml | 43 +++++++----- tasks/borgbackup_client.yml | 83 ++++++++++++++++------- tasks/borgbackup_server.yml | 10 +++ templates/check_job.sh.j2 | 3 +- templates/{job.sh.j2 => create_job.sh.j2} | 3 +- templates/prune_job.sh.j2 | 3 +- 7 files changed, 100 insertions(+), 47 deletions(-) rename templates/{job.sh.j2 => create_job.sh.j2} (73%) diff --git a/README.md b/README.md index c883bf3..9d5aea3 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Example Playbook - role: SphericalElephant.borgbackup borgbackup_client: True borgbackup_client_backup_server: backup01.example.com - borgbackup_client_jobs: + borgbackup_create_jobs: - name: system day: "*" hour: "0" diff --git a/defaults/main.yml b/defaults/main.yml index d634d2e..7e0f715 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -1,29 +1,32 @@ --- ## -## borg installation +## borgbackup package/binary installation ## - borgbackup_install_from_binary: True borgbackup_install_from_repo: False -borgbackup_binary_version: "1.1.2" +borgbackup_binary_version: "1.1.4" borgbackup_binary_platform: "borg-linux64" borgbackup_binary_uri: "https://github.com/borgbackup/borg/releases/download/{{ borgbackup_binary_version }}/{{ borgbackup_binary_platform }}" borgbackup_binary: "/usr/local/bin/borg" - - - ## -## borg server configuration +## borgbackup server configuration ## borgbackup_server: False borgbackup_server_user: "borgbackup" borgbackup_server_group: "borgbackup" borgbackup_server_home: "/srv/borgbackup" borgbackup_server_pool: "{{ borgbackup_server_home }}/repos" +# ssh pubkey list of sysadmins that manage the borg server +borgbackup_server_admins: [] - +## +## borgbackup general configuration +## +# encryption +borgbackup_encryption_mode: "none" +borgbackup_passphrase: "yoursecret" ## ## borg client configuration @@ -40,21 +43,24 @@ borgbackup_client_ssh_key_type: '{{ "ed25519" borgbackup_client_ssh_key_file: "/root/.ssh/id_{{ borgbackup_client_ssh_key_type }}-backup" borgbackup_client_ssh_key_comment: 'root@{{ ansible_hostname }} generated by Ansible' borgbackup_client_scripts_dir: "/etc/borg" -borgbackup_encryption_mode: "none" -borgbackup_passphrase: "yoursecret" + +# lastlog parsed by supervision +borgbackup_client_lastlog_dir: "/var/cache/borg" # backup server IP or FQDN used during ansible installation AND backup operation. borgbackup_client_backup_server: # if defined, IP or FQDN used on backup operation. Usefull in case of LAN-free backup borgbackup_client_backup_server_lanfreebackup: -borgbackup_client_jobs: -# example : -#borgbackup_client_backup_server: backup01.example.com -#borgbackup_client_jobs: +# you have to set at least a "create" job. +# "prune" and "checks" jobs are optionnal, but you should use it too. +borgbackup_create_jobs: + +# borgbackup jobs examples : +#borgbackup_create_jobs: # - name: system -# options: "--compression zlib,6" +# options: "--lock-wait 7200 --compression lzma" # day: "*" # hour: 0 # default value = 1 # minute: 0 # default value = 0 @@ -68,7 +74,7 @@ borgbackup_client_jobs: borgbackup_prune_enabled: yes #borgbackup_prune_jobs: # - name: system -# prune_options: "--keep-daily=7 --keep-weekly=4" +# prune_options: "--lock-wait 7200 --keep-daily=7 --keep-weekly=4 --keep-monthly=12 --keep-yearly=-1" # day: "*" # hour: 12 # default value = 1 # minute: 0 # default value = 0 @@ -78,7 +84,7 @@ borgbackup_prune_enabled: yes borgbackup_check_enabled: yes #borgbackup_check_jobs: # - name: system -# check_options: "--verbose" +# check_options: "--lock-wait 28800" # day: 1 # hour: 12 # default value = 1 # minute: 0 # default value = 0 @@ -87,7 +93,8 @@ borgbackup_check_enabled: yes # random_day: 27 # default value : ignore randomization # about random : -# purpose is to set indempotent random crontab values that differs when many jobs are croned. +# TL;DR : if 'random_hour' is set, then 'hour' will be set by a random value within range 'hour' up to 'hour+random_hour' +# purpose is to set indempotent random crontab values. Usefull when many jobs are croned toward a small number of repository servers. # random_hour : if defined, a indempotent random value is computed between 0 and the value specified. # Then, the crontab hour will be addition of hour and random_hour. # a modulo 24 is applied in order to ensure valid hour are specified. diff --git a/tasks/borgbackup_client.yml b/tasks/borgbackup_client.yml index 7a79708..d2caaaf 100644 --- a/tasks/borgbackup_client.yml +++ b/tasks/borgbackup_client.yml @@ -1,5 +1,9 @@ --- +# +# client installation task +# + - name: check available SSH key types shell: ssh -Q key 2>/dev/null || echo "ssh-rsa" register: borgbackup_register_key_types @@ -49,12 +53,20 @@ mode: 0750 state: directory +- name: backup supervision lastlog dir + file: + path: "{{ borgbackup_client_lastlog_dir }}" + owner: root + group: root + mode: 0755 + state: directory + - name: check if the repositories already exist command: "{{ borgbackup_binary }} list {{ borgbackup_server_user }}@{{ borgbackup_client_backup_server_lanfreebackup | default(borgbackup_client_backup_server) }}:{{ item.name }}" environment: - BORG_RSH: "ssh -o StrictHostKeyChecking=no -i {{ borgbackup_client_ssh_key_file }}" - BORG_PASSPHRASE: "{{ borgbackup_passphrase }}" - with_items: "{{ borgbackup_client_jobs }}" + with_items: "{{ borgbackup_create_jobs }}" register: list_repos failed_when: False changed_when: False @@ -75,45 +87,52 @@ environment: - BORG_RSH: "ssh -o StrictHostKeyChecking=no -i {{ borgbackup_client_ssh_key_file }}" - BORG_PASSPHRASE: "{{ borgbackup_passphrase }}" - with_items: "{{ borgbackup_client_jobs }}" + with_items: "{{ borgbackup_create_jobs }}" register: borgbackup_initialize_result failed_when: (borgbackup_initialize_result.rc != 0) and (borgbackup_initialize_result.stderr != "") and ('already exists' not in borgbackup_initialize_result.stderr) when: item.name not in initialized_repos -- name: generate filename for backup / prune / check scripts +- name: generate filename for create / prune / check scripts set_fact: - backup_suffix_script_filename: "backup_{{ borgbackup_client_backup_server.split('.')[0] }}" + create_suffix_script_filename: "create_{{ borgbackup_client_backup_server.split('.')[0] }}" prune_suffix_script_filename: "prune_{{ borgbackup_client_backup_server.split('.')[0] }}" check_suffix_script_filename: "check_{{ borgbackup_client_backup_server.split('.')[0] }}" # -# backup scripts +# borg create scripts # -- name: deploy backup scripts +- name: deploy borg create scripts template: - dest: "{{ borgbackup_client_scripts_dir }}/{{ item.name }}_{{ backup_suffix_script_filename }}.sh" - src: job.sh.j2 + dest: "{{ borgbackup_client_scripts_dir }}/{{ item.name }}_{{ create_suffix_script_filename }}.sh" + src: create_job.sh.j2 owner: root group: root mode: 0700 - with_items: "{{ borgbackup_client_jobs }}" + with_items: "{{ borgbackup_create_jobs }}" -- name: schedule backup scripts on cron +- name: schedule borg create scripts on cron cron: name: "borg backup {{ item.name }}" user: root - job: "{{ borgbackup_client_scripts_dir }}/{{ item.name }}_{{ backup_suffix_script_filename }}.sh 2>&1 | /usr/bin/logger -t borgbackup" - day: "{{ item.day | default('*') }}" - hour: "{{ (item.hour | default(1)) + (item.random_hour | random(seed=item.name + backup_suffix_script_filename + ansible_host))%24 if item.random_hour is defined else item.hour | default(1) }}" - minute: "{{ (item.minute | default(0)) + (item.random_minute | random(seed=ansible_host + item.name + backup_suffix_script_filename))%60 if item.random_minute is defined else item.minute | default(0) }}" + job: "{{ borgbackup_client_scripts_dir }}/{{ item.name }}_{{ create_suffix_script_filename }}.sh 2>&1 | /usr/bin/logger -t borgbackup" + day: "{{ (item.day | default(1)) + (item.random_day | random(seed=item.name + check_suffix_script_filename + ansible_host))%28 if item.random_day is defined else item.day | default('*') }}" + hour: "{{ (item.hour | default(1)) + (item.random_hour | random(seed=item.name + create_suffix_script_filename + ansible_host))%24 if item.random_hour is defined else item.hour | default(1) }}" + minute: "{{ (item.minute | default(0)) + (item.random_minute | random(seed=ansible_host + item.name + create_suffix_script_filename))%60 if item.random_minute is defined else item.minute | default(0) }}" state: present - cron_file: "borgbackup_{{ item.name }}_{{ backup_suffix_script_filename }}" - with_items: "{{ borgbackup_client_jobs }}" + cron_file: "borgbackup_{{ item.name }}_{{ create_suffix_script_filename }}" + with_items: "{{ borgbackup_create_jobs }}" + +- name: deploy borg create fake logs, when no log yet + shell: echo -ne "FAKE LOG\nterminating with success status, rc 0\n" | tee "{{ borgbackup_client_lastlog_dir }}/{{ item.name }}_{{ create_suffix_script_filename }}.lastlog" + args: + chdir: "{{ borgbackup_client_lastlog_dir }}" + creates: "{{ borgbackup_client_lastlog_dir }}/{{ item.name }}_{{ create_suffix_script_filename }}.lastlog" + with_items: "{{ borgbackup_create_jobs }}" # -# prune scripts +# borg prune scripts # -- name: deploy prune scripts +- name: deploy borg prune scripts template: dest: "{{ borgbackup_client_scripts_dir }}/{{ item.name }}_{{ prune_suffix_script_filename }}.sh" src: prune_job.sh.j2 @@ -123,23 +142,30 @@ with_items: "{{ borgbackup_prune_jobs }}" when: borgbackup_prune_enabled -- name: schedule prune scripts on cron +- name: schedule borg prune scripts on cron cron: name: "borg prune {{ item.name }}" user: root job: "{{ borgbackup_client_scripts_dir }}/{{ item.name }}_{{ prune_suffix_script_filename }}.sh 2>&1 | /usr/bin/logger -t borgbackup" - day: "{{ item.day | default('*') }}" - hour: "{{ (item.hour | default(1)) + (item.random_hour | random(seed=item.name + prune_suffix_script_filename + ansible_host))%24 if item.random_hour is defined else item.hour | default(1) }}" + day: "{{ (item.day | default(1)) + (item.random_day | random(seed=item.name + check_suffix_script_filename + ansible_host))%28 if item.random_day is defined else item.day | default('*') }}" + hour: "{{ (item.hour | default(1)) + (item.random_hour | random(seed=item.name + prune_suffix_script_filename + ansible_host))%24 if item.random_hour is defined else item.hour | default(2) }}" minute: "{{ (item.minute | default(0)) + (item.random_minute | random(seed=ansible_host + item.name + prune_suffix_script_filename))%60 if item.random_minute is defined else item.minute | default(0) }}" state: present cron_file: "borgbackup_{{ item.name }}_{{ prune_suffix_script_filename }}" with_items: "{{ borgbackup_prune_jobs }}" when: borgbackup_prune_enabled +- name: deploy borg prune fake logs, when no log yet + shell: echo -ne "FAKE LOG\nterminating with success status, rc 0\n" | tee "{{ borgbackup_client_lastlog_dir }}/{{ item.name }}_{{ prune_suffix_script_filename }}.lastlog" + args: + chdir: "{{ borgbackup_client_lastlog_dir }}" + creates: "{{ borgbackup_client_lastlog_dir }}/{{ item.name }}_{{ prune_suffix_script_filename }}.lastlog" + with_items: "{{ borgbackup_prune_jobs }}" + # -# check repository scripts +# borg check scripts # -- name: deploy check scripts +- name: deploy borg check scripts template: dest: "{{ borgbackup_client_scripts_dir }}/{{ item.name }}_{{ check_suffix_script_filename }}.sh" src: check_job.sh.j2 @@ -149,15 +175,22 @@ with_items: "{{ borgbackup_check_jobs }}" when: borgbackup_check_enabled -- name: schedule check scripts on cron +- name: schedule borg check scripts on cron cron: name: "borg check {{ item.name }}" user: root job: "{{ borgbackup_client_scripts_dir }}/{{ item.name }}_{{ check_suffix_script_filename }}.sh 2>&1 | /usr/bin/logger -t borgbackup" day: "{{ (item.day | default(1)) + (item.random_day | random(seed=item.name + check_suffix_script_filename + ansible_host))%28 if item.random_day is defined else item.day | default(1) }}" - hour: "{{ (item.hour | default(1)) + (item.random_hour | random(seed=item.name + check_suffix_script_filename + ansible_host))%24 if item.random_hour is defined else item.hour | default(1) }}" + hour: "{{ (item.hour | default(1)) + (item.random_hour | random(seed=item.name + check_suffix_script_filename + ansible_host))%24 if item.random_hour is defined else item.hour | default(3) }}" minute: "{{ (item.minute | default(0)) + (item.random_minute | random(seed=ansible_host + item.name + check_suffix_script_filename))%60 if item.random_minute is defined else item.minute | default(0) }}" state: present cron_file: "borgbackup_{{ item.name }}_{{ check_suffix_script_filename }}" with_items: "{{ borgbackup_check_jobs }}" when: borgbackup_check_enabled + +- name: deploy borg check fake logs, when no log yet + shell: echo -ne "FAKE LOG\nterminating with success status, rc 0\n" | tee "{{ borgbackup_client_lastlog_dir }}/{{ item.name }}_{{ check_suffix_script_filename }}.lastlog" + args: + chdir: "{{ borgbackup_client_lastlog_dir }}" + creates: "{{ borgbackup_client_lastlog_dir }}/{{ item.name }}_{{ check_suffix_script_filename }}.lastlog" + with_items: "{{ borgbackup_check_jobs }}" \ No newline at end of file diff --git a/tasks/borgbackup_server.yml b/tasks/borgbackup_server.yml index db4a6cc..bf613bd 100644 --- a/tasks/borgbackup_server.yml +++ b/tasks/borgbackup_server.yml @@ -1,5 +1,9 @@ --- +# +# server installation task +# + - name: create group for borg group: name: "{{ borgbackup_server_group }}" @@ -32,3 +36,9 @@ group: "{{ borgbackup_server_group }}" mode: 0600 state: touch + +- name: add ssh-pubkey admin users to backup server + authorized_key: + user: "{{ borgbackup_server_user }}" + key: "{{ item }}" + with_items: "{{ borgbackup_server_admins }}" \ No newline at end of file diff --git a/templates/check_job.sh.j2 b/templates/check_job.sh.j2 index cbeed9d..ddcaf84 100644 --- a/templates/check_job.sh.j2 +++ b/templates/check_job.sh.j2 @@ -10,4 +10,5 @@ REPOSITORY={{ borgbackup_server_user }}@{{ borgbackup_client_backup_server_lanfr {{ borgbackup_binary }} check --show-rc --verbose \ {{ item.check_options }} \ $REPOSITORY \ - 2>&1 | /usr/bin/logger -t borgbackup_check_{{ item.name }}_{{ borgbackup_client_backup_server }} + 2>&1 | tee {{ borgbackup_client_lastlog_dir }}/{{ item.name }}_{{ check_suffix_script_filename }}.lastlog \ + | /usr/bin/logger -t borgbackup_check_{{ item.name }}_{{ borgbackup_client_backup_server }} diff --git a/templates/job.sh.j2 b/templates/create_job.sh.j2 similarity index 73% rename from templates/job.sh.j2 rename to templates/create_job.sh.j2 index 4fd5792..08564b1 100644 --- a/templates/job.sh.j2 +++ b/templates/create_job.sh.j2 @@ -14,4 +14,5 @@ REPOSITORY={{ borgbackup_server_user }}@{{ borgbackup_client_backup_server_lanfr {% for e in item.excludes %} --exclude '{{ e }}' \ {% endfor %} - 2>&1 | /usr/bin/logger -t borgbackup_backup_{{ item.name }}_{{ borgbackup_client_backup_server }} \ No newline at end of file + 2>&1 | tee {{ borgbackup_client_lastlog_dir }}/{{ item.name }}_{{ create_suffix_script_filename }}.lastlog \ + | /usr/bin/logger -t borgbackup_backup_{{ item.name }}_{{ borgbackup_client_backup_server }} \ No newline at end of file diff --git a/templates/prune_job.sh.j2 b/templates/prune_job.sh.j2 index 34e2ae7..5977439 100644 --- a/templates/prune_job.sh.j2 +++ b/templates/prune_job.sh.j2 @@ -10,4 +10,5 @@ REPOSITORY={{ borgbackup_server_user }}@{{ borgbackup_client_backup_server_lanfr {{ borgbackup_binary }} prune --show-rc --verbose --stats \ {{ item.prune_options }} \ $REPOSITORY \ - 2>&1 | /usr/bin/logger -t borgbackup_prune_{{ item.name }}_{{ borgbackup_client_backup_server }} + 2>&1 | tee {{ borgbackup_client_lastlog_dir }}/{{ item.name }}_{{ prune_suffix_script_filename }}.lastlog \ + | /usr/bin/logger -t borgbackup_prune_{{ item.name }}_{{ borgbackup_client_backup_server }} From 54dae41af2101bc90fa9a5e5edf28fcd56f4c444 Mon Sep 17 00:00:00 2001 From: Sylvain DAVID Date: Sat, 19 May 2018 23:59:18 +0200 Subject: [PATCH 11/12] fix : borgbackup_client_backup_server_lanfreebackup is optional, admins keys can be removed, change default borg backup log --- README.md | 7 +++++++ defaults/main.yml | 9 +++++++-- tasks/borgbackup_server.yml | 6 ++++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9d5aea3..ff482ee 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,13 @@ Example Playbook day: "*" hour: "8" minute: "0" + borgbackup_check_jobs: + - name: system + check_options: "--lock-wait 28800" + day: "1" + hour: "12" + minute: "0" + You can easily assign client and server attributes from your inventory with something similar to the following: diff --git a/defaults/main.yml b/defaults/main.yml index 7e0f715..f148745 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -20,6 +20,11 @@ borgbackup_server_home: "/srv/borgbackup" borgbackup_server_pool: "{{ borgbackup_server_home }}/repos" # ssh pubkey list of sysadmins that manage the borg server borgbackup_server_admins: [] +# - key: "ssh-rsa abc123..." +# - key: "ssh-rsa abc456..." +# state: present +# - key: "ssh-rsa abc789..." +# state: absent ## ## borgbackup general configuration @@ -45,13 +50,13 @@ borgbackup_client_ssh_key_comment: 'root@{{ ansible_hostname }} generated by Ans borgbackup_client_scripts_dir: "/etc/borg" # lastlog parsed by supervision -borgbackup_client_lastlog_dir: "/var/cache/borg" +borgbackup_client_lastlog_dir: "/var/log/borg" # backup server IP or FQDN used during ansible installation AND backup operation. borgbackup_client_backup_server: # if defined, IP or FQDN used on backup operation. Usefull in case of LAN-free backup -borgbackup_client_backup_server_lanfreebackup: +#borgbackup_client_backup_server_lanfreebackup: # you have to set at least a "create" job. # "prune" and "checks" jobs are optionnal, but you should use it too. diff --git a/tasks/borgbackup_server.yml b/tasks/borgbackup_server.yml index bf613bd..8258254 100644 --- a/tasks/borgbackup_server.yml +++ b/tasks/borgbackup_server.yml @@ -40,5 +40,7 @@ - name: add ssh-pubkey admin users to backup server authorized_key: user: "{{ borgbackup_server_user }}" - key: "{{ item }}" - with_items: "{{ borgbackup_server_admins }}" \ No newline at end of file + key: "{{ item.key }}" + state: "{{ item.state | default('present') }}" + with_items: "{{ borgbackup_server_admins }}" + From 5d9a89a37a7a3ec51e69188a28202dd56e7c523b Mon Sep 17 00:00:00 2001 From: Sylvain David Date: Wed, 19 Dec 2018 17:30:01 +0100 Subject: [PATCH 12/12] add retries, move to version 1.1.7, repo relocation is ok --- defaults/main.yml | 8 +++++++- templates/check_job.sh.j2 | 17 ++++++++++++----- templates/create_job.sh.j2 | 25 ++++++++++++++++--------- templates/prune_job.sh.j2 | 17 ++++++++++++----- 4 files changed, 47 insertions(+), 20 deletions(-) diff --git a/defaults/main.yml b/defaults/main.yml index f148745..8978d9b 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -5,7 +5,7 @@ ## borgbackup_install_from_binary: True borgbackup_install_from_repo: False -borgbackup_binary_version: "1.1.4" +borgbackup_binary_version: "1.1.7" borgbackup_binary_platform: "borg-linux64" borgbackup_binary_uri: "https://github.com/borgbackup/borg/releases/download/{{ borgbackup_binary_version }}/{{ borgbackup_binary_platform }}" borgbackup_binary: "/usr/local/bin/borg" @@ -58,6 +58,12 @@ borgbackup_client_backup_server: # if defined, IP or FQDN used on backup operation. Usefull in case of LAN-free backup #borgbackup_client_backup_server_lanfreebackup: +# max retry attempt on create/prune/check task failure. only one attempt if unset. +#borgbackup_task_retry: 3 + +# retry attempt wait time +#borgbackup_task_retry_wait: 30 + # you have to set at least a "create" job. # "prune" and "checks" jobs are optionnal, but you should use it too. borgbackup_create_jobs: diff --git a/templates/check_job.sh.j2 b/templates/check_job.sh.j2 index ddcaf84..c2c521b 100644 --- a/templates/check_job.sh.j2 +++ b/templates/check_job.sh.j2 @@ -4,11 +4,18 @@ set -e export BORG_RSH="ssh -i {{ borgbackup_client_ssh_key_file }}" export BORG_PASSPHRASE="{{ borgbackup_passphrase }}" +export BORG_RELOCATED_REPO_ACCESS_IS_OK=yes REPOSITORY={{ borgbackup_server_user }}@{{ borgbackup_client_backup_server_lanfreebackup | default(borgbackup_client_backup_server) }}:{{ item.name }} -{{ borgbackup_binary }} check --show-rc --verbose \ - {{ item.check_options }} \ - $REPOSITORY \ - 2>&1 | tee {{ borgbackup_client_lastlog_dir }}/{{ item.name }}_{{ check_suffix_script_filename }}.lastlog \ - | /usr/bin/logger -t borgbackup_check_{{ item.name }}_{{ borgbackup_client_backup_server }} +retry={{ borgbackup_task_retry | default(1) }} +step_status=0 +while [ $retry -gt 0 ]; do + {{ borgbackup_binary }} check --show-rc --verbose \ + {{ item.check_options }} \ + $REPOSITORY \ + 2>&1 | tee {{ borgbackup_client_lastlog_dir }}/{{ item.name }}_{{ check_suffix_script_filename }}.lastlog \ + | /usr/bin/logger -t borgbackup_check_{{ item.name }}_{{ borgbackup_client_backup_server }} + for i in ${PIPESTATUS[@]}; do let step_status+=$i ;done + if [ $step_status -eq 0 ]; then retry=0; else sleep {{ borgbackup_task_retry_wait | default(30) }}; let retry-=1; fi +done diff --git a/templates/create_job.sh.j2 b/templates/create_job.sh.j2 index 08564b1..a7c0a49 100644 --- a/templates/create_job.sh.j2 +++ b/templates/create_job.sh.j2 @@ -4,15 +4,22 @@ set -e export BORG_RSH="ssh -i {{ borgbackup_client_ssh_key_file }}" export BORG_PASSPHRASE="{{ borgbackup_passphrase }}" +export BORG_RELOCATED_REPO_ACCESS_IS_OK=yes REPOSITORY={{ borgbackup_server_user }}@{{ borgbackup_client_backup_server_lanfreebackup | default(borgbackup_client_backup_server) }}:{{ item.name }} -{{ borgbackup_binary }} create --show-rc --verbose --stats \ - {{ item.options | default('--compression zlib,6') }} \ - $REPOSITORY::{{ ansible_hostname }}-$(date +%Y-%m-%d_%H-%M) \ - {{ item.directories | join(' ') }} \ - {% for e in item.excludes %} - --exclude '{{ e }}' \ - {% endfor %} - 2>&1 | tee {{ borgbackup_client_lastlog_dir }}/{{ item.name }}_{{ create_suffix_script_filename }}.lastlog \ - | /usr/bin/logger -t borgbackup_backup_{{ item.name }}_{{ borgbackup_client_backup_server }} \ No newline at end of file +retry={{ borgbackup_task_retry | default(1) }} +step_status=0 +while [ $retry -gt 0 ]; do + {{ borgbackup_binary }} create --show-rc --verbose --stats \ + {{ item.options | default('--compression zlib,6') }} \ + $REPOSITORY::{{ ansible_hostname }}-$(date +%Y-%m-%d_%H-%M) \ + {{ item.directories | join(' ') }} \ + {% for e in item.excludes %} + --exclude '{{ e }}' \ + {% endfor %} + 2>&1 | tee {{ borgbackup_client_lastlog_dir }}/{{ item.name }}_{{ create_suffix_script_filename }}.lastlog \ + | /usr/bin/logger -t borgbackup_backup_{{ item.name }}_{{ borgbackup_client_backup_server }} + for i in ${PIPESTATUS[@]}; do let step_status+=$i ;done + if [ $step_status -eq 0 ]; then retry=0; else sleep {{ borgbackup_task_retry_wait | default(30) }}; let retry-=1; fi +done diff --git a/templates/prune_job.sh.j2 b/templates/prune_job.sh.j2 index 5977439..0e9bbf6 100644 --- a/templates/prune_job.sh.j2 +++ b/templates/prune_job.sh.j2 @@ -4,11 +4,18 @@ set -e export BORG_RSH="ssh -i {{ borgbackup_client_ssh_key_file }}" export BORG_PASSPHRASE="{{ borgbackup_passphrase }}" +export BORG_RELOCATED_REPO_ACCESS_IS_OK=yes REPOSITORY={{ borgbackup_server_user }}@{{ borgbackup_client_backup_server_lanfreebackup | default(borgbackup_client_backup_server) }}:{{ item.name }} -{{ borgbackup_binary }} prune --show-rc --verbose --stats \ - {{ item.prune_options }} \ - $REPOSITORY \ - 2>&1 | tee {{ borgbackup_client_lastlog_dir }}/{{ item.name }}_{{ prune_suffix_script_filename }}.lastlog \ - | /usr/bin/logger -t borgbackup_prune_{{ item.name }}_{{ borgbackup_client_backup_server }} +retry={{ borgbackup_task_retry | default(1) }} +step_status=0 +while [ $retry -gt 0 ]; do + {{ borgbackup_binary }} prune --show-rc --verbose --stats \ + {{ item.prune_options }} \ + $REPOSITORY \ + 2>&1 | tee {{ borgbackup_client_lastlog_dir }}/{{ item.name }}_{{ prune_suffix_script_filename }}.lastlog \ + | /usr/bin/logger -t borgbackup_prune_{{ item.name }}_{{ borgbackup_client_backup_server }} + for i in ${PIPESTATUS[@]}; do let step_status+=$i ;done + if [ $step_status -eq 0 ]; then retry=0; else sleep {{ borgbackup_task_retry_wait | default(30) }}; let retry-=1; fi +done