--- # Restore Forgejo from backup # Restores database, repositories, configuration, and data - name: Restore Forgejo from Backup hosts: forgejo become: yes gather_facts: yes vars_files: - vars/main.yml - vars/secrets.yml vars: # Must be provided via --extra-vars backup_timestamp: "" backup_source: "local" # local or s3 force_restore: false pre_tasks: - name: Validate backup timestamp ansible.builtin.fail: msg: "Please provide backup_timestamp via --extra-vars 'backup_timestamp=20240115T120000'" when: backup_timestamp == "" - name: Display restore information ansible.builtin.debug: msg: | ======================================== WARNING: This will restore Forgejo data ======================================== Backup timestamp: {{ backup_timestamp }} Source: {{ backup_source }} This operation will: 1. Stop Forgejo service 2. Restore database 3. Restore repositories 4. Restore configuration 5. Restart services Current data will be backed up first. - name: Confirm restore operation ansible.builtin.pause: prompt: "Type 'yes' to continue with restore" register: restore_confirm when: not force_restore - name: Validate confirmation ansible.builtin.fail: msg: "Restore cancelled by user" when: not force_restore and restore_confirm.user_input != 'yes' tasks: - name: Create pre-restore backup ansible.builtin.include_tasks: backup.yml vars: backup_filename: "pre-restore-{{ ansible_date_time.iso8601_basic_short }}.tar.gz" - name: Download backup from S3 if needed when: backup_source == 's3' block: - name: Create temporary download directory ansible.builtin.file: path: "{{ forgejo_backup_path }}/restore-temp" state: directory mode: '0750' - name: Download backups from S3 ansible.builtin.command: cmd: > aws s3 cp s3://{{ forgejo_backup_s3_bucket }}/backups/{{ item }}-{{ backup_timestamp }}.tar.gz {{ forgejo_backup_path }}/{{ item }}-{{ backup_timestamp }}.tar.gz --endpoint-url {{ forgejo_s3_endpoint }} environment: AWS_ACCESS_KEY_ID: "{{ forgejo_s3_access_key }}" AWS_SECRET_ACCESS_KEY: "{{ forgejo_s3_secret_key }}" loop: - database - repositories - config - data no_log: yes - name: Verify backup files exist ansible.builtin.stat: path: "{{ forgejo_backup_path }}/{{ item }}-{{ backup_timestamp }}.tar.gz" register: backup_files loop: - repositories - config - data failed_when: not backup_files.results | map(attribute='stat.exists') | list | min - name: Verify database backup exists ansible.builtin.stat: path: "{{ forgejo_backup_path }}/database-{{ backup_timestamp }}.sql.gz" register: db_backup failed_when: not db_backup.stat.exists - name: Stop Forgejo service community.docker.docker_compose_v2: project_src: "{{ forgejo_base_path }}" state: stopped - name: Restore PostgreSQL database when: forgejo_db_type == 'postgres' block: - name: Drop existing database community.postgresql.postgresql_db: name: "{{ forgejo_db_name }}" state: absent become_user: postgres - name: Recreate database community.postgresql.postgresql_db: name: "{{ forgejo_db_name }}" encoding: UTF8 lc_collate: en_US.UTF-8 lc_ctype: en_US.UTF-8 template: template0 state: present become_user: postgres - name: Decompress database backup ansible.builtin.command: cmd: gunzip -c {{ forgejo_backup_path }}/database-{{ backup_timestamp }}.sql.gz register: db_dump - name: Restore database community.postgresql.postgresql_db: name: "{{ forgejo_db_name }}" state: restore target: "{{ forgejo_backup_path }}/database-{{ backup_timestamp }}.sql" become_user: postgres - name: Clear existing repositories ansible.builtin.file: path: "{{ forgejo_data_path }}/git" state: absent - name: Restore repositories ansible.builtin.unarchive: src: "{{ forgejo_backup_path }}/repositories-{{ backup_timestamp }}.tar.gz" dest: "{{ forgejo_data_path }}" remote_src: yes owner: "{{ forgejo_user }}" group: "{{ forgejo_group }}" - name: Restore configuration ansible.builtin.unarchive: src: "{{ forgejo_backup_path }}/config-{{ backup_timestamp }}.tar.gz" dest: "{{ forgejo_base_path }}" remote_src: yes owner: "{{ forgejo_user }}" group: "{{ forgejo_group }}" - name: Restore data files ansible.builtin.unarchive: src: "{{ forgejo_backup_path }}/data-{{ backup_timestamp }}.tar.gz" dest: "{{ forgejo_data_path }}" remote_src: yes owner: "{{ forgejo_user }}" group: "{{ forgejo_group }}" - name: Set correct permissions ansible.builtin.file: path: "{{ item }}" owner: "{{ forgejo_user }}" group: "{{ forgejo_group }}" recurse: yes loop: - "{{ forgejo_data_path }}/git" - "{{ forgejo_data_path }}/attachments" - "{{ forgejo_data_path }}/lfs" - "{{ forgejo_config_path }}" - name: Start Forgejo service community.docker.docker_compose_v2: project_src: "{{ forgejo_base_path }}" state: present - name: Wait for Forgejo to be ready ansible.builtin.uri: url: "http://localhost:{{ forgejo_http_port }}" status_code: 200 register: health_check until: health_check.status == 200 retries: 30 delay: 2 - name: Run integrity checks ansible.builtin.command: cmd: docker exec forgejo forgejo doctor check --all register: integrity_check failed_when: false - name: Display integrity check results ansible.builtin.debug: msg: "{{ integrity_check.stdout_lines }}" post_tasks: - name: Verify Forgejo health ansible.builtin.uri: url: "http://localhost:{{ forgejo_http_port }}/api/healthz" status_code: 200 register: health - name: Clean up temporary files ansible.builtin.file: path: "{{ forgejo_backup_path }}/restore-temp" state: absent when: backup_source == 's3' - name: Display completion message ansible.builtin.debug: msg: | ======================================== Restore Complete! ======================================== Restored from backup: {{ backup_timestamp }} Forgejo is now running with restored data. Please verify: 1. Login works correctly 2. Repositories are accessible 3. All data is present Original data was backed up before restore. ========================================