Initial commit: nult - Ansible deployment toolkit
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>
This commit is contained in:
138
roles/gitea/tasks/backup.yml
Normal file
138
roles/gitea/tasks/backup.yml
Normal file
@@ -0,0 +1,138 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# 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
|
||||
139
roles/gitea/tasks/config.yml
Normal file
139
roles/gitea/tasks/config.yml
Normal file
@@ -0,0 +1,139 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# Configuration Tasks - Update Domain Settings
|
||||
# =============================================================================
|
||||
#
|
||||
# Updates Gitea's app.ini configuration file with the new domain.
|
||||
#
|
||||
# The app.ini file lives inside the Docker volume at /data/gitea/conf/app.ini.
|
||||
# We extract it, modify it on the host, then copy it back into the container.
|
||||
#
|
||||
# Settings that need updating for domain rename:
|
||||
# [server]
|
||||
# DOMAIN = git.veridion.ru (web domain)
|
||||
# SSH_DOMAIN = git.veridion.ru (SSH clone URLs)
|
||||
# ROOT_URL = https://git.veridion.ru/ (base URL for all links)
|
||||
#
|
||||
# Reference: https://docs.gitea.com/administration/config-cheat-sheet
|
||||
# =============================================================================
|
||||
|
||||
# Create a temporary directory on the host for config editing.
|
||||
# We'll extract app.ini here, modify it, then copy back.
|
||||
# check_mode: false - tempfile is harmless, needed for subsequent tasks
|
||||
- name: Create temporary directory for config editing
|
||||
ansible.builtin.tempfile:
|
||||
state: directory
|
||||
prefix: gitea_config_
|
||||
register: gitea_config_temp_dir
|
||||
check_mode: false
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Extract Configuration from Container
|
||||
# -----------------------------------------------------------------------------
|
||||
# docker cp extracts files from a container to the host filesystem.
|
||||
# Format: docker cp <container>:<path_in_container> <path_on_host>
|
||||
# check_mode: false - read-only extraction needed for lineinfile to evaluate changes
|
||||
|
||||
- name: Extract app.ini from Gitea container
|
||||
ansible.builtin.command:
|
||||
cmd: "docker cp {{ gitea_container_name }}:/data/gitea/conf/app.ini {{ gitea_config_temp_dir.path }}/app.ini"
|
||||
changed_when: false
|
||||
check_mode: false
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Update Domain Settings
|
||||
# -----------------------------------------------------------------------------
|
||||
# Using lineinfile module to update specific settings in app.ini.
|
||||
# Each task finds a line matching the regexp and replaces it.
|
||||
#
|
||||
# lineinfile parameters:
|
||||
# path: File to modify
|
||||
# regexp: Pattern to find (uses Python regex)
|
||||
# line: Replacement line
|
||||
# backrefs: If true, allows using \1, \2 for captured groups (not used here)
|
||||
#
|
||||
# The regexp patterns:
|
||||
# ^DOMAIN\s*= Matches "DOMAIN = " at start of line, with any whitespace
|
||||
# ^\s*DOMAIN\s*= Would also match indented lines (not typical in app.ini)
|
||||
|
||||
- name: Update DOMAIN setting in app.ini
|
||||
ansible.builtin.lineinfile:
|
||||
path: "{{ gitea_config_temp_dir.path }}/app.ini"
|
||||
regexp: '^DOMAIN\s*='
|
||||
line: "DOMAIN = {{ gitea_domain }}"
|
||||
register: gitea_domain_updated
|
||||
|
||||
- name: Update SSH_DOMAIN setting in app.ini
|
||||
ansible.builtin.lineinfile:
|
||||
path: "{{ gitea_config_temp_dir.path }}/app.ini"
|
||||
regexp: '^SSH_DOMAIN\s*='
|
||||
line: "SSH_DOMAIN = {{ gitea_ssh_domain }}"
|
||||
register: gitea_ssh_domain_updated
|
||||
|
||||
# ROOT_URL must include the protocol (https://) and trailing slash
|
||||
- name: Update ROOT_URL setting in app.ini
|
||||
ansible.builtin.lineinfile:
|
||||
path: "{{ gitea_config_temp_dir.path }}/app.ini"
|
||||
regexp: '^ROOT_URL\s*='
|
||||
line: "ROOT_URL = {{ gitea_root_url }}/"
|
||||
register: gitea_root_url_updated
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Apply Security Hardening (Optional)
|
||||
# -----------------------------------------------------------------------------
|
||||
# These settings enhance security. They're applied during domain update
|
||||
# since we're already modifying the config.
|
||||
#
|
||||
# Each setting is conditional on whether the variable is defined,
|
||||
# allowing operators to skip specific hardening options.
|
||||
|
||||
# Password hashing: argon2 is more secure than pbkdf2 (Gitea default)
|
||||
- name: Update password hash algorithm
|
||||
ansible.builtin.lineinfile:
|
||||
path: "{{ gitea_config_temp_dir.path }}/app.ini"
|
||||
regexp: '^PASSWORD_HASH_ALGO\s*='
|
||||
line: "PASSWORD_HASH_ALGO = {{ gitea_password_hash_algo }}"
|
||||
insertafter: '^\[security\]'
|
||||
when: gitea_password_hash_algo is defined
|
||||
|
||||
# Disable git hooks to prevent arbitrary code execution
|
||||
- name: Update git hooks setting
|
||||
ansible.builtin.lineinfile:
|
||||
path: "{{ gitea_config_temp_dir.path }}/app.ini"
|
||||
regexp: '^DISABLE_GIT_HOOKS\s*='
|
||||
line: "DISABLE_GIT_HOOKS = {{ gitea_disable_git_hooks | lower }}"
|
||||
insertafter: '^\[security\]'
|
||||
when: gitea_disable_git_hooks is defined
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copy Updated Configuration Back to Container
|
||||
# -----------------------------------------------------------------------------
|
||||
# docker cp can also copy from host to container.
|
||||
# Format: docker cp <path_on_host> <container>:<path_in_container>
|
||||
|
||||
- name: Copy updated app.ini back to container
|
||||
ansible.builtin.command:
|
||||
cmd: "docker cp {{ gitea_config_temp_dir.path }}/app.ini {{ gitea_container_name }}:/data/gitea/conf/app.ini"
|
||||
changed_when: true
|
||||
when: gitea_domain_updated.changed or gitea_ssh_domain_updated.changed or gitea_root_url_updated.changed
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Cleanup
|
||||
# -----------------------------------------------------------------------------
|
||||
# Remove the temporary directory we created.
|
||||
# check_mode: false - clean up the temp dir we created with check_mode: false
|
||||
|
||||
- name: Remove temporary config directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ gitea_config_temp_dir.path }}"
|
||||
state: absent
|
||||
check_mode: false
|
||||
|
||||
# Display summary of changes for operator visibility
|
||||
- name: Display configuration changes
|
||||
ansible.builtin.debug:
|
||||
msg: |
|
||||
Configuration updated:
|
||||
DOMAIN = {{ gitea_domain }}
|
||||
SSH_DOMAIN = {{ gitea_ssh_domain }}
|
||||
ROOT_URL = {{ gitea_root_url }}/
|
||||
126
roles/gitea/tasks/deploy.yml
Normal file
126
roles/gitea/tasks/deploy.yml
Normal file
@@ -0,0 +1,126 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# Deploy Tasks - Pull Images and Restart Services
|
||||
# =============================================================================
|
||||
#
|
||||
# Performs the actual deployment:
|
||||
# 1. Pull the new Docker images
|
||||
# 2. Restart services with --wait flag (waits for healthchecks)
|
||||
# 3. Verify the deployment
|
||||
#
|
||||
# This task relies on healthchecks defined in docker-compose.yml:
|
||||
# - PostgreSQL: pg_isready checks database is accepting connections
|
||||
# - Gitea: curl to /api/healthz checks web server is responding
|
||||
#
|
||||
# The --wait flag makes docker compose block until all services are healthy.
|
||||
# This is cleaner than manually polling with Ansible loops.
|
||||
#
|
||||
# Database migrations happen AUTOMATICALLY when Gitea starts with a new
|
||||
# version. The start_period in Gitea's healthcheck allows time for this.
|
||||
#
|
||||
# Reference: https://docs.gitea.com/installation/upgrade-from-gitea
|
||||
# =============================================================================
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Pull New Docker Images
|
||||
# -----------------------------------------------------------------------------
|
||||
# Pull images before stopping services to minimize downtime.
|
||||
# This downloads the new image layers while the old containers still run.
|
||||
|
||||
- name: Pull new Docker images
|
||||
ansible.builtin.command:
|
||||
cmd: "docker compose -f {{ gitea_install_dir }}/docker-compose.yml pull"
|
||||
register: gitea_docker_pull
|
||||
changed_when: "'Pulled' in gitea_docker_pull.stdout or 'Downloaded' in gitea_docker_pull.stdout"
|
||||
|
||||
- name: Display image pull results
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ gitea_docker_pull.stdout_lines | default(['Images already up to date']) }}"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Restart Services with Healthcheck Wait
|
||||
# -----------------------------------------------------------------------------
|
||||
# docker compose up -d --wait:
|
||||
# -d : Detached mode (run in background)
|
||||
# --wait : Block until all services are healthy (based on healthcheck)
|
||||
#
|
||||
# This single command:
|
||||
# 1. Stops old containers if config changed
|
||||
# 2. Creates new containers with new images
|
||||
# 3. Waits for healthchecks to pass
|
||||
#
|
||||
# Timeout is set high (5 minutes) to allow for:
|
||||
# - Database startup
|
||||
# - Gitea migrations (can take time on version upgrades)
|
||||
# - ACME certificate issuance (30-60 seconds for new domain)
|
||||
|
||||
- name: Restart services and wait for healthy
|
||||
ansible.builtin.command:
|
||||
cmd: "docker compose -f {{ gitea_install_dir }}/docker-compose.yml up -d --wait"
|
||||
chdir: "{{ gitea_install_dir }}"
|
||||
register: gitea_compose_up
|
||||
changed_when: true
|
||||
# 5 minute timeout for migrations + ACME certificate
|
||||
timeout: 300
|
||||
|
||||
- name: Display compose output
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ gitea_compose_up.stdout_lines | default(['Services started']) }}"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Verify Deployment
|
||||
# -----------------------------------------------------------------------------
|
||||
# Additional verification beyond healthchecks.
|
||||
|
||||
# Check container health status
|
||||
# check_mode: false - read-only, shows current state during dry run
|
||||
- name: Verify container health status
|
||||
ansible.builtin.command:
|
||||
cmd: "docker compose -f {{ gitea_install_dir }}/docker-compose.yml ps --format json"
|
||||
register: gitea_compose_status
|
||||
changed_when: false
|
||||
check_mode: false
|
||||
|
||||
- name: Display container status
|
||||
ansible.builtin.debug:
|
||||
msg: "Container status: {{ gitea_compose_status.stdout }}"
|
||||
|
||||
# Check Gitea logs for migration activity
|
||||
# check_mode: false - read-only, shows current logs during dry run
|
||||
- name: Check Gitea logs for errors or migrations
|
||||
ansible.builtin.command:
|
||||
cmd: "docker logs --tail 30 {{ gitea_container_name }}"
|
||||
register: gitea_logs
|
||||
changed_when: false
|
||||
check_mode: false
|
||||
|
||||
- name: Display recent Gitea logs
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ gitea_logs.stdout_lines[-10:] | default(['No logs available']) }}"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Final Summary
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
- name: Deployment summary
|
||||
ansible.builtin.debug:
|
||||
msg: |
|
||||
============================================
|
||||
DEPLOYMENT COMPLETE
|
||||
============================================
|
||||
Domain: https://{{ gitea_domain }}/
|
||||
SSH: ssh://git@{{ gitea_domain }}:{{ gitea_ssh_external_port }}/
|
||||
Gitea: {{ gitea_version }}
|
||||
PostgreSQL: {{ gitea_postgres_version }}
|
||||
|
||||
Healthchecks passed - services are running.
|
||||
|
||||
Verify manually:
|
||||
1. Login at https://{{ gitea_domain }}/
|
||||
2. Clone a repo via HTTPS and SSH
|
||||
3. Check Settings > Admin for version info
|
||||
|
||||
If act-runner was configured, update its config:
|
||||
vault_gitea_instance_url: https://{{ gitea_domain }}
|
||||
vault_gitea_registry: {{ gitea_domain }}
|
||||
============================================
|
||||
39
roles/gitea/tasks/main.yml
Normal file
39
roles/gitea/tasks/main.yml
Normal file
@@ -0,0 +1,39 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# Gitea Role - Main Task Orchestration
|
||||
# =============================================================================
|
||||
#
|
||||
# This file controls the execution order of all tasks.
|
||||
# Tasks are designed to be idempotent and safe to run multiple times.
|
||||
#
|
||||
# IMPORTANT: Database migrations are handled AUTOMATICALLY by Gitea on startup.
|
||||
# The backup task MUST run before any changes to allow rollback.
|
||||
#
|
||||
# Reference: https://docs.gitea.com/installation/upgrade-from-gitea
|
||||
# =============================================================================
|
||||
|
||||
- name: Include preflight checks
|
||||
ansible.builtin.include_tasks: preflight.yml
|
||||
tags:
|
||||
- preflight
|
||||
- always
|
||||
|
||||
- name: Include backup tasks
|
||||
ansible.builtin.include_tasks: backup.yml
|
||||
tags:
|
||||
- backup
|
||||
|
||||
- name: Include configuration tasks
|
||||
ansible.builtin.include_tasks: config.yml
|
||||
tags:
|
||||
- config
|
||||
|
||||
- name: Include upgrade tasks
|
||||
ansible.builtin.include_tasks: upgrade.yml
|
||||
tags:
|
||||
- upgrade
|
||||
|
||||
- name: Include deployment tasks
|
||||
ansible.builtin.include_tasks: deploy.yml
|
||||
tags:
|
||||
- deploy
|
||||
144
roles/gitea/tasks/preflight.yml
Normal file
144
roles/gitea/tasks/preflight.yml
Normal file
@@ -0,0 +1,144 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# Preflight Checks
|
||||
# =============================================================================
|
||||
#
|
||||
# Validates prerequisites before making any changes.
|
||||
# Fails fast with clear error messages if requirements are not met.
|
||||
#
|
||||
# Reference: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/assert_module.html
|
||||
# =============================================================================
|
||||
|
||||
- name: Verify required variables are defined
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- gitea_domain is defined
|
||||
- gitea_domain | length > 0
|
||||
- gitea_db_password is defined
|
||||
- gitea_db_password | length > 0
|
||||
- gitea_install_dir is defined
|
||||
fail_msg: >-
|
||||
Required variables missing. Ensure vault.yml contains:
|
||||
vault_gitea_domain, vault_gitea_db_password.
|
||||
Ensure inventory contains: gitea_install_dir.
|
||||
quiet: true
|
||||
|
||||
- name: Check if Docker is installed
|
||||
ansible.builtin.command:
|
||||
cmd: docker --version
|
||||
register: gitea_docker_check
|
||||
changed_when: false
|
||||
check_mode: false
|
||||
failed_when: gitea_docker_check.rc != 0
|
||||
|
||||
- name: Verify Docker daemon is running
|
||||
ansible.builtin.command:
|
||||
cmd: docker info
|
||||
register: gitea_docker_info
|
||||
changed_when: false
|
||||
check_mode: false
|
||||
failed_when: gitea_docker_info.rc != 0
|
||||
|
||||
- name: Check if Gitea install directory exists
|
||||
ansible.builtin.stat:
|
||||
path: "{{ gitea_install_dir }}"
|
||||
register: gitea_dir_stat
|
||||
|
||||
- name: Verify Gitea install directory exists
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- gitea_dir_stat.stat.exists
|
||||
- gitea_dir_stat.stat.isdir
|
||||
fail_msg: "Gitea install directory not found: {{ gitea_install_dir }}"
|
||||
quiet: true
|
||||
|
||||
- name: Check if docker-compose.yml exists
|
||||
ansible.builtin.stat:
|
||||
path: "{{ gitea_install_dir }}/docker-compose.yml"
|
||||
register: gitea_compose_stat
|
||||
|
||||
- name: Verify docker-compose.yml exists
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- gitea_compose_stat.stat.exists
|
||||
fail_msg: "docker-compose.yml not found in {{ gitea_install_dir }}"
|
||||
quiet: true
|
||||
|
||||
# Find the mount point containing gitea_install_dir using df command.
|
||||
# This is more reliable than substring matching on ansible_mounts.
|
||||
# check_mode: false - df is read-only, safe to run even in --check mode
|
||||
- name: Find mount point for install directory
|
||||
ansible.builtin.command:
|
||||
cmd: "df --output=target {{ gitea_install_dir }}"
|
||||
register: gitea_df_result
|
||||
changed_when: false
|
||||
check_mode: false
|
||||
|
||||
# Parse mount point from df output (first line is header, second is mount)
|
||||
- name: Parse mount point from df output
|
||||
ansible.builtin.set_fact:
|
||||
gitea_mount_point: "{{ gitea_df_result.stdout_lines[-1] | trim }}"
|
||||
|
||||
# Look up full mount info (size_available, etc.) from gathered facts
|
||||
- name: Get mount info from ansible_facts
|
||||
ansible.builtin.set_fact:
|
||||
gitea_install_mount: "{{ ansible_facts['mounts'] | selectattr('mount', 'equalto', gitea_mount_point) | first }}"
|
||||
|
||||
# Check available space: 2GB = 2 * 1024^3 = 2147483648 bytes
|
||||
- name: Verify sufficient disk space (minimum 2GB)
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- gitea_install_mount.size_available > 2147483648
|
||||
fail_msg: >-
|
||||
Insufficient disk space on {{ gitea_install_mount.mount }}.
|
||||
Available: {{ (gitea_install_mount.size_available / 1073741824) | round(2) }}GB.
|
||||
Minimum required: 2GB.
|
||||
quiet: true
|
||||
|
||||
- name: Check if Gitea container is running
|
||||
ansible.builtin.command:
|
||||
cmd: docker ps --filter "name={{ gitea_container_name }}" --format "{{ '{{' }}.Names{{ '}}' }}"
|
||||
register: gitea_container_check
|
||||
changed_when: false
|
||||
check_mode: false
|
||||
|
||||
- name: Display Gitea container status
|
||||
ansible.builtin.debug:
|
||||
msg: "Gitea container status: {{ 'running' if gitea_container_name in gitea_container_check.stdout else 'not running' }}"
|
||||
|
||||
- name: Check if database container is running
|
||||
ansible.builtin.command:
|
||||
cmd: docker ps --filter "name={{ gitea_db_container_name }}" --format "{{ '{{' }}.Names{{ '}}' }}"
|
||||
register: gitea_db_container_check
|
||||
changed_when: false
|
||||
check_mode: false
|
||||
|
||||
- name: Display database container status
|
||||
ansible.builtin.debug:
|
||||
msg: "Database container status: {{ 'running' if gitea_db_container_name in gitea_db_container_check.stdout else 'not running' }}"
|
||||
|
||||
# Verify DNS is configured before proceeding.
|
||||
# ACME certificate issuance will fail without valid DNS.
|
||||
- name: Check DNS resolution for domain
|
||||
ansible.builtin.command:
|
||||
cmd: "dig +short {{ gitea_domain }}"
|
||||
register: gitea_dns_check
|
||||
changed_when: false
|
||||
check_mode: false
|
||||
failed_when: false
|
||||
|
||||
- name: Display DNS resolution result
|
||||
ansible.builtin.debug:
|
||||
msg: "DNS for {{ gitea_domain }} resolves to: {{ gitea_dns_check.stdout_lines | default(['UNRESOLVED']) | join(', ') }}"
|
||||
|
||||
# Fail if DNS doesn't resolve (can be skipped with gitea_skip_gitea_dns_check=true)
|
||||
- name: Verify DNS resolves for domain
|
||||
ansible.builtin.fail:
|
||||
msg: >-
|
||||
DNS for {{ gitea_domain }} does not resolve.
|
||||
ACME certificate issuance will fail without valid DNS.
|
||||
Ensure A record points to this server before proceeding.
|
||||
To skip this check, set gitea_skip_gitea_dns_check=true.
|
||||
when:
|
||||
- gitea_dns_check.stdout | length == 0
|
||||
- not (gitea_skip_gitea_dns_check | default(false) | bool)
|
||||
67
roles/gitea/tasks/upgrade.yml
Normal file
67
roles/gitea/tasks/upgrade.yml
Normal file
@@ -0,0 +1,67 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# Upgrade Tasks - Deploy New docker-compose.yml
|
||||
# =============================================================================
|
||||
#
|
||||
# Deploys the templated docker-compose.yml with the new Gitea version.
|
||||
#
|
||||
# This task uses Ansible's template module to generate docker-compose.yml
|
||||
# from a Jinja2 template. The template allows us to:
|
||||
# - Update the Gitea image version
|
||||
# - Update the PostgreSQL image version
|
||||
# - Apply configuration from Ansible variables
|
||||
#
|
||||
# The template is stored at: roles/gitea/templates/docker-compose.yml.j2
|
||||
#
|
||||
# After this task, the docker-compose.yml on the server will reference
|
||||
# the new image versions, but containers aren't restarted yet.
|
||||
# That happens in deploy.yml.
|
||||
# =============================================================================
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Backup Current docker-compose.yml
|
||||
# -----------------------------------------------------------------------------
|
||||
# Even though we have a full gitea dump backup, it's useful to have
|
||||
# the docker-compose.yml readily available for quick rollback.
|
||||
|
||||
- name: Backup current docker-compose.yml before upgrade
|
||||
ansible.builtin.copy:
|
||||
src: "{{ gitea_install_dir }}/docker-compose.yml"
|
||||
dest: "{{ gitea_install_dir }}/docker-compose.yml.backup"
|
||||
remote_src: true
|
||||
mode: "0640"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Deploy New docker-compose.yml from Template
|
||||
# -----------------------------------------------------------------------------
|
||||
# The template module:
|
||||
# 1. Reads the Jinja2 template (docker-compose.yml.j2)
|
||||
# 2. Substitutes all {{ variable }} placeholders with actual values
|
||||
# 3. Writes the result to the destination path
|
||||
#
|
||||
# Key variables used in the template:
|
||||
# gitea_version - Docker image tag (e.g., "1.25")
|
||||
# postgres_version - PostgreSQL image tag (e.g., "17-alpine")
|
||||
# gitea_db_password - Database password (from vault)
|
||||
# gitea_user_uid/gid - Container user/group IDs
|
||||
# gitea_http_port - Internal HTTP port (3000)
|
||||
# gitea_ssh_port - Internal SSH port (22)
|
||||
# gitea_ssh_external_port - External SSH port (2222)
|
||||
|
||||
- name: Deploy docker-compose.yml from template
|
||||
ansible.builtin.template:
|
||||
src: docker-compose.yml.j2
|
||||
dest: "{{ gitea_install_dir }}/docker-compose.yml"
|
||||
mode: "0640"
|
||||
# Validate the YAML syntax before deploying
|
||||
validate: "docker compose -f %s config --quiet"
|
||||
register: gitea_compose_deployed
|
||||
|
||||
# Display what changed for operator visibility
|
||||
- name: Display upgrade info
|
||||
ansible.builtin.debug:
|
||||
msg: |
|
||||
docker-compose.yml updated:
|
||||
Gitea version: {{ gitea_version }}
|
||||
PostgreSQL version: {{ gitea_postgres_version }}
|
||||
Template changed: {{ gitea_compose_deployed.changed }}
|
||||
Reference in New Issue
Block a user