--- - name: Dump Supabase database to local temp file hosts: supabase connection: local gather_facts: false tasks: - name: Set backup filename ansible.builtin.set_fact: _backup_filename: >- {{ backup_file_prefix + '-' + now(fmt='%Y-%m') + '-monthly.sql.gz' if now(fmt='%-d') == '1' else backup_file_prefix + '-' + now(fmt='%Y%m%d-%H%M%S') + '.sql.gz' }} - name: Create local temporary directory ansible.builtin.tempfile: state: directory suffix: .backup register: _tmpdir - name: Dump and compress database ansible.builtin.shell: cmd: "set -o pipefail && pg_dump '{{ supabase.postgres_url }}' | gzip > '{{ _tmpdir.path }}/{{ _backup_filename }}'" executable: /bin/bash changed_when: true no_log: true - name: Register backup info for storage play ansible.builtin.add_host: name: _backup_info groups: backup_info _backup_filename: "{{ _backup_filename }}" _tmpdir_path: "{{ _tmpdir.path }}" _backup_file_prefix: "{{ backup_file_prefix }}" - name: Store backup on bab1 and enforce retention hosts: backup_dest gather_facts: false vars: _src_filename: "{{ hostvars['_backup_info']['_backup_filename'] }}" _src_tmpdir: "{{ hostvars['_backup_info']['_tmpdir_path'] }}" _prefix: "{{ hostvars['_backup_info']['_backup_file_prefix'] }}" tasks: - name: Ensure backup directory exists ansible.builtin.file: path: "{{ backup_base_dir }}" state: directory mode: '0750' - name: Copy backup file to bab1 ansible.builtin.copy: src: "{{ _src_tmpdir }}/{{ _src_filename }}" dest: "{{ backup_base_dir }}/{{ _src_filename }}" mode: '0640' - name: Find regular backup files older than retention period ansible.builtin.find: paths: "{{ backup_base_dir }}" patterns: "{{ _prefix }}-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9]*.sql.gz" age: "{{ backup_retain_regular_days }}d" age_stamp: mtime register: _regular_old - name: Delete regular backups beyond age limit ansible.builtin.file: path: "{{ item.path }}" state: absent loop: "{{ _regular_old.files }}" - name: Find all regular backup files ansible.builtin.find: paths: "{{ backup_base_dir }}" patterns: "{{ _prefix }}-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9]*.sql.gz" register: _regular_all - name: Delete oldest regular backups beyond count limit ansible.builtin.file: path: "{{ item.path }}" state: absent loop: "{{ (_regular_all.files | sort(attribute='mtime'))[: [(_regular_all.files | length - backup_retain_regular_count), 0] | max | int] }}" - name: Find monthly backup files older than retention period ansible.builtin.find: paths: "{{ backup_base_dir }}" patterns: "{{ _prefix }}-[0-9][0-9][0-9][0-9]-[0-9][0-9]-monthly.sql.gz" age: "{{ backup_retain_monthly_days }}d" age_stamp: mtime register: _monthly_old - name: Delete monthly backups beyond age limit ansible.builtin.file: path: "{{ item.path }}" state: absent loop: "{{ _monthly_old.files }}" - name: Find all monthly backup files ansible.builtin.find: paths: "{{ backup_base_dir }}" patterns: "{{ _prefix }}-[0-9][0-9][0-9][0-9]-[0-9][0-9]-monthly.sql.gz" register: _monthly_all - name: Delete oldest monthly backups beyond count limit ansible.builtin.file: path: "{{ item.path }}" state: absent loop: "{{ (_monthly_all.files | sort(attribute='mtime'))[: [(_monthly_all.files | length - backup_retain_monthly_count), 0] | max | int] }}" - name: Remove local temporary directory ansible.builtin.file: path: "{{ _src_tmpdir }}" state: absent delegate_to: localhost