--- - name: "{{ app_name }} - Restore application data" block: - name: Set specific archive if provided ansible.builtin.set_fact: _restore_backup: "{{ app_restore_archive }}" when: app_restore_archive is defined - name: Verify specific archive exists (controller) ansible.builtin.stat: path: "{{ _restore_backup }}" delegate_to: localhost register: specific_archive_stat when: app_restore_archive is defined and app_restore_source | default('controller') == 'controller' - name: Verify specific archive exists (remote) ansible.builtin.stat: path: "{{ _restore_backup }}" register: specific_archive_stat when: app_restore_archive is defined and app_restore_source | default('controller') == 'remote' - name: Fail if specific archive doesn't exist ansible.builtin.fail: msg: "Specified restore archive does not exist: {{ _restore_backup }}" when: app_restore_archive is defined and not specific_archive_stat.stat.exists - name: Find latest backup on controller ansible.builtin.find: paths: "{{ app_backup_path }}" patterns: "{{ app_name }}-*.tar.gz" age: "-{{ app_restore_max_age_days | default(30) }}d" delegate_to: localhost register: controller_backups when: app_restore_source | default('controller') == 'controller' and app_restore_archive is not defined - name: Find latest backup on remote host ansible.builtin.find: paths: "{{ app_backup_path_remote | default(app_dir + '/backups') }}" patterns: "{{ app_name }}-*.tar.gz" age: "-{{ app_restore_max_age_days | default(30) }}d" register: remote_backups when: app_restore_source | default('controller') == 'remote' and app_restore_archive is not defined - name: Set latest backup file (controller) ansible.builtin.set_fact: _restore_backup: "{{ (controller_backups.files | sort(attribute='mtime') | last).path }}" when: app_restore_source | default('controller') == 'controller' and controller_backups.files | length > 0 and app_restore_archive is not defined - name: Set latest backup file (remote) ansible.builtin.set_fact: _restore_backup: "{{ (remote_backups.files | sort(attribute='mtime') | last).path }}" when: app_restore_source | default('controller') == 'remote' and remote_backups.files | length > 0 and app_restore_archive is not defined - name: Copy backup from controller to remote if needed ansible.builtin.copy: src: "{{ _restore_backup }}" dest: "{{ app_dir }}/restore_backup.tar.gz" owner: "{{ app_uid | default(omit) }}" group: "{{ app_gid | default(omit) }}" mode: "{{ app_permission_mode | default('0644') }}" when: app_restore_source | default('controller') == 'controller' and _restore_backup is defined register: copied_backup - name: Set restore path for remote backup ansible.builtin.set_fact: _restore_path: "{{ _restore_backup if app_restore_source | default('controller') == 'remote' else copied_backup.dest }}" when: _restore_backup is defined - name: Stop application for restore community.docker.docker_compose_v2: project_src: "{{ app_dir }}" state: stopped when: _restore_path is defined - name: Debug directory permissions before deletion ansible.builtin.shell: | ls -la "{{ item }}" ls -la "{{ item | dirname }}" whoami id loop: "{{ app_backup_subdirectories | default([]) }}" when: _restore_path is defined become: true register: debug_perms - name: Show debug output ansible.builtin.debug: var: debug_perms - name: Remove existing backup subdirectories for clean restore ansible.builtin.file: path: "{{ item }}" state: absent loop: "{{ app_backup_subdirectories | default([]) }}" when: _restore_path is defined become: true - name: Extract backup to application directory ansible.builtin.unarchive: src: "{{ _restore_path }}" dest: "{{ app_dir }}" owner: "{{ app_uid | default(omit) }}" group: "{{ app_gid | default(omit) }}" remote_src: true when: _restore_path is defined - name: Clean up copied backup file ansible.builtin.file: path: "{{ app_dir }}/restore_backup.tar.gz" state: absent when: app_restore_source | default('controller') == 'controller' and copied_backup is defined always: - name: Start application after restore community.docker.docker_compose_v2: project_src: "{{ app_dir }}" state: present when: _restore_path is defined tags: [restore]