Merged from veridion-gitea and veridion-act-runner-gitea repos. nult (Null-T) - instant teleportation from Strugatsky's Noon Universe. Like Null-T, this toolkit instantly deploys infrastructure. Roles: - gitea: Gitea server with PostgreSQL (Docker Compose) - act_runner: Gitea Actions runner Playbooks: - gitea.yml: Deploy Gitea server - act-runner.yml: Deploy Act Runner - site.yml: Deploy all services Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
139 lines
5.9 KiB
YAML
139 lines
5.9 KiB
YAML
---
|
|
# =============================================================================
|
|
# Backup Tasks - Using Official Gitea Dump
|
|
# =============================================================================
|
|
#
|
|
# Uses the official `gitea dump` command for comprehensive backup.
|
|
# Reference: https://docs.gitea.com/administration/backup-and-restore
|
|
#
|
|
# The dump creates a ZIP containing:
|
|
# - app.ini and custom/ directory (configuration)
|
|
# - All git repositories
|
|
# - Database SQL dump (gitea-db.sql)
|
|
# - Attachments, avatars, LFS objects
|
|
#
|
|
# Note: We run the dump while Gitea is running. The official docs recommend
|
|
# stopping Gitea for perfect consistency, but docker exec requires a running
|
|
# container. The consistency risk during the brief dump operation is minimal.
|
|
# =============================================================================
|
|
|
|
# Set up variables for this backup run.
|
|
# gitea_backup_timestamp: Used in filename for unique identification (e.g., 20260114T143022)
|
|
# gitea_backup_dir_path: Where backups are stored on the host filesystem
|
|
- name: Set backup variables
|
|
ansible.builtin.set_fact:
|
|
gitea_backup_timestamp: "{{ ansible_facts['date_time']['iso8601_basic_short'] }}"
|
|
gitea_backup_dir_path: "{{ gitea_install_dir }}/{{ gitea_backup_dir }}"
|
|
|
|
# Ensure the backup directory exists on the host.
|
|
# Mode 0750: owner read/write/execute, group read/execute, others no access
|
|
- name: Ensure backup directory exists
|
|
ansible.builtin.file:
|
|
path: "{{ gitea_backup_dir_path }}"
|
|
state: directory
|
|
mode: "0750"
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Create Backup Using Official Gitea Dump
|
|
# -----------------------------------------------------------------------------
|
|
# Run the official gitea dump command inside the running container.
|
|
#
|
|
# Command breakdown:
|
|
# docker exec {{ container }} - Execute command inside the container
|
|
# /usr/local/bin/gitea dump - The gitea binary with dump subcommand
|
|
# -c /data/gitea/conf/app.ini - Path to config file (tells gitea where data is)
|
|
# -w /tmp - Working directory for temporary files
|
|
# -f /tmp/gitea-backup-*.zip - Output filename for the backup archive
|
|
#
|
|
# Note: We write to /tmp inside the container first, then copy out.
|
|
# This avoids permission issues with mounted volumes.
|
|
|
|
- name: Run gitea dump command
|
|
ansible.builtin.command:
|
|
cmd: >-
|
|
docker exec -u git {{ gitea_container_name }}
|
|
/usr/local/bin/gitea dump
|
|
-c /data/gitea/conf/app.ini
|
|
-w /tmp
|
|
-f /tmp/gitea-backup-{{ gitea_backup_timestamp }}.zip
|
|
register: gitea_dump_result
|
|
changed_when: true
|
|
|
|
# Copy backup from container to host filesystem
|
|
# docker cp copies files between container and host.
|
|
# Format: docker cp container:/path/in/container /path/on/host
|
|
- name: Copy backup from container to host
|
|
ansible.builtin.command:
|
|
cmd: >-
|
|
docker cp
|
|
{{ gitea_container_name }}:/tmp/gitea-backup-{{ gitea_backup_timestamp }}.zip
|
|
{{ gitea_backup_dir_path }}/gitea-backup-{{ gitea_backup_timestamp }}.zip
|
|
changed_when: true
|
|
|
|
# Clean up the backup file inside the container
|
|
# We don't want to leave large files in the container's /tmp
|
|
# failed_when: false - Don't fail if cleanup fails (backup already succeeded)
|
|
- name: Remove backup file from container
|
|
ansible.builtin.command:
|
|
cmd: >-
|
|
docker exec -u git {{ gitea_container_name }}
|
|
rm /tmp/gitea-backup-{{ gitea_backup_timestamp }}.zip
|
|
changed_when: true
|
|
failed_when: false
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Backup Verification
|
|
# -----------------------------------------------------------------------------
|
|
# Verify the backup was actually created and is not empty.
|
|
# This catches cases where the command succeeded but produced no output.
|
|
|
|
- name: Verify backup file exists
|
|
ansible.builtin.stat:
|
|
path: "{{ gitea_backup_dir_path }}/gitea-backup-{{ gitea_backup_timestamp }}.zip"
|
|
register: gitea_backup_file
|
|
|
|
# Display backup info for operator visibility
|
|
# Size calculation: bytes / 1048576 = megabytes (1024*1024)
|
|
- name: Display backup info
|
|
ansible.builtin.debug:
|
|
msg: >-
|
|
Backup completed: {{ gitea_backup_dir_path }}/gitea-backup-{{ gitea_backup_timestamp }}.zip
|
|
Size: {{ (gitea_backup_file.stat.size / 1048576) | round(2) }}MB
|
|
when: gitea_backup_file.stat.exists | default(false)
|
|
|
|
- name: Fail if backup file is missing or empty
|
|
ansible.builtin.fail:
|
|
msg: "Backup file is missing or empty. Cannot proceed."
|
|
when:
|
|
- not ansible_check_mode
|
|
- not gitea_backup_file.stat.exists or gitea_backup_file.stat.size == 0
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Backup Rotation
|
|
# -----------------------------------------------------------------------------
|
|
# Keep only the N most recent backups (controlled by gitea_backup_retention).
|
|
# This prevents disk space from being exhausted by old backups.
|
|
|
|
# Find all existing backup files matching our naming pattern
|
|
- name: Find old backup files
|
|
ansible.builtin.find:
|
|
paths: "{{ gitea_backup_dir_path }}"
|
|
patterns: "gitea-backup-*.zip"
|
|
file_type: file
|
|
register: gitea_old_backup_files
|
|
|
|
# Delete old backups, keeping only the most recent ones.
|
|
# Logic breakdown:
|
|
# gitea_old_backup_files.files | sort(attribute='mtime') - Sort by modification time (oldest first)
|
|
# [:-gitea_backup_retention] - Slice: all except last N items
|
|
# (Python slice notation: [:-5] = all but last 5)
|
|
# Example: If we have 7 backups and retention=5, this deletes the 2 oldest.
|
|
- name: Remove old backups beyond retention limit
|
|
ansible.builtin.file:
|
|
path: "{{ item.path }}"
|
|
state: absent
|
|
loop: "{{ (gitea_old_backup_files.files | sort(attribute='mtime'))[:-gitea_backup_retention] }}"
|
|
loop_control:
|
|
label: "{{ item.path | basename }}"
|
|
when: gitea_old_backup_files.files | length > gitea_backup_retention
|