backup-homarr: rootless rclone install + delete older R2 versions
This commit is contained in:
parent
734935708a
commit
6df0813628
@ -137,18 +137,40 @@
|
|||||||
group: "{{ deploy_user }}"
|
group: "{{ deploy_user }}"
|
||||||
mode: "0750"
|
mode: "0750"
|
||||||
|
|
||||||
- name: Ensure rclone is installed (rootless via user bin if needed)
|
- name: Ensure rclone is installed (ROOTLESS — no sudo; installs to ~/.local/bin)
|
||||||
block:
|
block:
|
||||||
- name: rclone present?
|
- name: rclone present on PATH or in ~/.local/bin?
|
||||||
ansible.builtin.command: rclone version
|
ansible.builtin.shell: 'command -v rclone || command -v "$HOME/.local/bin/rclone"'
|
||||||
register: rc_ver
|
register: rc_ver
|
||||||
changed_when: false
|
changed_when: false
|
||||||
failed_when: false
|
failed_when: false
|
||||||
- name: Install rclone via official script (needs sudo)
|
|
||||||
ansible.builtin.shell: curl -fsSL https://rclone.org/install.sh | sudo bash
|
- name: Install rclone rootless (download static binary to ~/.local/bin)
|
||||||
when: rc_ver.rc != 0
|
when: rc_ver.rc != 0
|
||||||
|
block:
|
||||||
|
- name: Ensure ~/.local/bin exists
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "/home/{{ deploy_user }}/.local/bin"
|
||||||
|
state: directory
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Download + unpack latest rclone linux-amd64 into ~/.local/bin (rootless, python unzip)
|
||||||
|
ansible.builtin.shell: |
|
||||||
|
set -e
|
||||||
|
D="$(mktemp -d)"; cd "$D"
|
||||||
|
curl -fsSL https://downloads.rclone.org/rclone-current-linux-amd64.zip -o rclone.zip
|
||||||
|
python3 -c "import zipfile,glob,shutil,os,stat; z=zipfile.ZipFile('rclone.zip'); z.extractall('.'); b=glob.glob('rclone-*-linux-amd64/rclone')[0]; dst=os.path.expanduser('~/.local/bin/rclone'); shutil.copy(b,dst); os.chmod(dst, 0o755)"
|
||||||
changed_when: true
|
changed_when: true
|
||||||
|
|
||||||
|
- name: Resolve rclone binary path (PATH or ~/.local/bin)
|
||||||
|
ansible.builtin.shell: 'command -v rclone || echo "/home/{{ deploy_user }}/.local/bin/rclone"'
|
||||||
|
register: rclone_bin_res
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Set rclone binary fact
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
rclone_bin: "{{ rclone_bin_res.stdout_lines[0] }}"
|
||||||
|
|
||||||
- name: "Stop Homarr (consistent sqlite snapshot)"
|
- name: "Stop Homarr (consistent sqlite snapshot)"
|
||||||
community.docker.docker_compose_v2:
|
community.docker.docker_compose_v2:
|
||||||
project_src: "{{ homarr_dir }}"
|
project_src: "{{ homarr_dir }}"
|
||||||
@ -192,7 +214,7 @@
|
|||||||
|
|
||||||
- name: Upload tar to R2 (r2:<bucket>/homarr/<file>)
|
- name: Upload tar to R2 (r2:<bucket>/homarr/<file>)
|
||||||
ansible.builtin.command:
|
ansible.builtin.command:
|
||||||
cmd: rclone copyto "{{ backup_dir }}/{{ backup_name }}" "r2:{{ r2_bucket }}/homarr/{{ backup_name }}" --s3-no-check-bucket
|
cmd: "{{ rclone_bin }} copyto \"{{ backup_dir }}/{{ backup_name }}\" \"r2:{{ r2_bucket }}/homarr/{{ backup_name }}\" --s3-no-check-bucket"
|
||||||
environment: "{{ rclone_env }}"
|
environment: "{{ rclone_env }}"
|
||||||
register: upload
|
register: upload
|
||||||
changed_when: true
|
changed_when: true
|
||||||
@ -200,12 +222,29 @@
|
|||||||
|
|
||||||
- name: Verify object exists in R2
|
- name: Verify object exists in R2
|
||||||
ansible.builtin.command:
|
ansible.builtin.command:
|
||||||
cmd: rclone lsf "r2:{{ r2_bucket }}/homarr/{{ backup_name }}"
|
cmd: "{{ rclone_bin }} lsf \"r2:{{ r2_bucket }}/homarr/{{ backup_name }}\""
|
||||||
environment: "{{ rclone_env }}"
|
environment: "{{ rclone_env }}"
|
||||||
register: verify
|
register: verify
|
||||||
changed_when: false
|
changed_when: false
|
||||||
failed_when: backup_name not in verify.stdout
|
failed_when: backup_name not in verify.stdout
|
||||||
|
|
||||||
|
- name: List existing Homarr backups in R2 for this host
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: "{{ rclone_bin }} lsf \"r2:{{ r2_bucket }}/homarr/\""
|
||||||
|
environment: "{{ rclone_env }}"
|
||||||
|
register: r2_listing
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Delete OLDER R2 backups for this host (keep only the one just uploaded)
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: "{{ rclone_bin }} deletefile \"r2:{{ r2_bucket }}/homarr/{{ item }}\""
|
||||||
|
environment: "{{ rclone_env }}"
|
||||||
|
loop: "{{ r2_listing.stdout_lines }}"
|
||||||
|
when:
|
||||||
|
- item is match('homarr-' ~ inventory_hostname ~ '-.*\.tar$')
|
||||||
|
- item != backup_name
|
||||||
|
changed_when: true
|
||||||
|
|
||||||
- name: Prune old LOCAL tars (keep {{ keep_local }} newest)
|
- name: Prune old LOCAL tars (keep {{ keep_local }} newest)
|
||||||
ansible.builtin.shell: >-
|
ansible.builtin.shell: >-
|
||||||
ls -1t "{{ backup_dir }}"/homarr-*.tar 2>/dev/null | tail -n +{{ keep_local + 1 }} | xargs -r rm -f
|
ls -1t "{{ backup_dir }}"/homarr-*.tar 2>/dev/null | tail -n +{{ keep_local + 1 }} | xargs -r rm -f
|
||||||
@ -216,7 +255,8 @@
|
|||||||
ansible.builtin.debug:
|
ansible.builtin.debug:
|
||||||
msg: >-
|
msg: >-
|
||||||
Backed up {{ backup_name }} ({{ (bkstat.stat.size / 1048576) | round(1) }} MB)
|
Backed up {{ backup_name }} ({{ (bkstat.stat.size / 1048576) | round(1) }} MB)
|
||||||
-> r2:{{ r2_bucket }}/homarr/ ; Homarr healthy (HTTP {{ health.status }}).
|
-> r2:{{ r2_bucket }}/homarr/ (older versions for {{ inventory_hostname }} deleted) ;
|
||||||
|
Homarr healthy (HTTP {{ health.status }}).
|
||||||
|
|
||||||
- name: "Cleanup runner temp key"
|
- name: "Cleanup runner temp key"
|
||||||
hosts: localhost
|
hosts: localhost
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user