--- - name: "{{ app_name }} - Backup application data" block: - name: Starting backup debug: msg: | Starting backup of {{ app_name }} Backing up dirs: {{ app_backup_subdirectories }} - name: Validate required backup variables ansible.builtin.fail: msg: "Required variable {{ item }} is not defined" when: vars[item] is not defined loop: - app_name - app_dir - backup_path - name: Set backup source paths ansible.builtin.set_fact: _backup_sources: "{{ app_backup_subdirectories | default([app_dir + '/*']) }}" - name: Create local backup directory on controller ansible.builtin.file: path: "{{ app_backup_path }}" state: directory mode: "0750" delegate_to: localhost - name: Create remote backup directory on host ansible.builtin.file: path: "{{ app_backup_path_remote | default(app_dir + '/backups') }}" state: directory owner: "{{ app_uid | default(omit) }}" group: "{{ app_gid | default(omit) }}" mode: "{{ app_permission_mode | default('0755') }}" - name: Stop application for backup community.docker.docker_compose_v2: project_src: "{{ app_dir }}" state: stopped when: app_backup_stop_services | default(true) - name: Create timestamped backup ansible.builtin.archive: path: "{{ _backup_sources }}" dest: "{{ app_backup_path_remote | default(app_dir + '/backups') }}/{{ app_name }}-{{ ansible_date_time.iso8601_basic_short }}.tar.gz" format: gz owner: "{{ app_uid | default(omit) }}" group: "{{ app_gid | default(omit) }}" mode: "{{ app_permission_mode | default('0644') }}" register: remote_backup - name: Copy backup to controller ansible.builtin.fetch: src: "{{ remote_backup.dest }}" dest: "{{ app_backup_path }}/{{ app_name }}-{{ ansible_date_time.iso8601_basic_short }}.tar.gz" flat: true when: remote_backup is succeeded - name: Clean old backups on controller ansible.builtin.find: paths: "{{ app_backup_path }}" patterns: "{{ app_name }}-*.tar.gz" age: "{{ app_backup_retention_days_controller | default(90) }}d" register: old_backups_controller delegate_to: localhost - name: Remove old backups from controller ansible.builtin.file: path: "{{ item.path }}" state: absent loop: "{{ old_backups_controller.files | default([]) }}" delegate_to: localhost - name: Clean old backups on remote host ansible.builtin.find: paths: "{{ app_backup_path_remote | default(app_dir + '/backups') }}" patterns: "{{ app_name }}-*.tar.gz" age: "{{ app_backup_retention_days_remote | default(7) }}d" register: old_backups_remote - name: Remove old backups from remote host ansible.builtin.file: path: "{{ item.path }}" state: absent loop: "{{ old_backups_remote.files | default([]) }}" always: - name: Restart application after backup community.docker.docker_compose_v2: project_src: "{{ app_dir }}" state: present when: app_backup_stop_services | default(true) tags: [backup] when: app_backup | bool