Switch to terraform

This commit is contained in:
Prox
2026-02-15 18:37:15 +02:00
commit a7062b43ab
70 changed files with 6063 additions and 0 deletions

View File

@@ -0,0 +1,308 @@
---
# =============================================================================
# Gitea Migration Playbook
# =============================================================================
# Migrates Gitea from stuslab.cc to code.stuslab.cc with Authentik OAuth
#
# Prerequisites:
# 1. Authentik deployed at auth.stuslab.cc
# 2. DNS record: code.stuslab.cc -> 94.130.181.201
# 3. group_vars/vault.yml with authentik bootstrap token
#
# Usage:
# ansible-playbook -i inventory.yml playbook.yml --ask-vault-pass
#
# What this playbook does:
# 1. Validates existing Gitea installation
# 2. Creates backup of gitea_data/
# 3. Updates app.ini with new domain settings
# 4. Deploys updated Caddyfile with redirect
# 5. Creates OAuth application in Authentik
# 6. Verifies migration success
# =============================================================================
- name: Migrate Gitea to code.stuslab.cc
hosts: gitea_servers
become: true
vars_files:
- group_vars/gitea_servers.yml
- group_vars/vault.yml
# ===========================================================================
# Pre-flight Validation
# ===========================================================================
pre_tasks:
- name: Validate required variables
ansible.builtin.assert:
that:
- gitea_domain is defined
- gitea_old_domain is defined
- authentik_domain is defined
- vault_authentik_bootstrap_token is defined
- vault_authentik_bootstrap_token != "PASTE_AUTHENTIK_BOOTSTRAP_TOKEN_HERE"
fail_msg: |
Required variables not configured!
1. Copy vault.yml.example to vault.yml
2. Add your Authentik bootstrap token
3. Encrypt with: ansible-vault encrypt group_vars/vault.yml
- name: Check existing Gitea installation
ansible.builtin.stat:
path: "{{ gitea_base_dir }}/gitea_data/gitea/conf/app.ini"
register: existing_gitea
- name: Fail if no existing Gitea found
ansible.builtin.fail:
msg: |
No existing Gitea installation found at {{ gitea_base_dir }}
Expected app.ini at: {{ gitea_base_dir }}/gitea_data/gitea/conf/app.ini
when: not existing_gitea.stat.exists
- name: Display pre-flight status
ansible.builtin.debug:
msg: |
============================================
Gitea Migration Pre-flight Check
============================================
Current domain: {{ gitea_old_domain }}
Target domain: {{ gitea_domain }}
Authentik: {{ authentik_domain }}
Base dir: {{ gitea_base_dir }}
============================================
- name: Verify Authentik is reachable
ansible.builtin.uri:
url: "https://{{ authentik_domain }}/api/v3/core/brands/"
method: GET
headers:
Authorization: "Bearer {{ vault_authentik_bootstrap_token }}"
status_code: 200
timeout: 30
register: authentik_check
ignore_errors: true
- name: Warn if Authentik not reachable
ansible.builtin.debug:
msg: |
WARNING: Authentik not reachable at https://{{ authentik_domain }}
OAuth setup will be skipped. You can run it manually later.
when: authentik_check.failed
tasks:
# =========================================================================
# Stage 1: Backup (skip if recent backup exists)
# =========================================================================
- name: Create backup directory
ansible.builtin.file:
path: "{{ gitea_backup_dir }}"
state: directory
mode: "0755"
when: gitea_create_backup
- name: Check for existing backup from today
ansible.builtin.find:
paths: "{{ gitea_backup_dir }}"
patterns: "gitea-backup-{{ ansible_date_time.date | replace('-', '') }}*.tar.gz"
register: existing_backups
when: gitea_create_backup
- name: Set backup needed flag
ansible.builtin.set_fact:
backup_needed: "{{ gitea_create_backup and (existing_backups.files | length == 0) }}"
- name: Skip backup message
ansible.builtin.debug:
msg: "Backup already exists from today: {{ existing_backups.files[0].path | basename }}. Skipping backup."
when:
- gitea_create_backup
- existing_backups.files | length > 0
- name: Stop Gitea container for consistent backup
ansible.builtin.command:
cmd: docker compose stop gitea
chdir: "{{ gitea_base_dir }}"
when: backup_needed
changed_when: true
- name: Generate backup timestamp
ansible.builtin.set_fact:
backup_timestamp: "{{ ansible_date_time.iso8601_basic_short }}"
when: backup_needed
- name: Create backup archive
ansible.builtin.archive:
path: "{{ gitea_data_dir }}"
dest: "{{ gitea_backup_dir }}/gitea-backup-{{ backup_timestamp }}.tar.gz"
format: gz
when: backup_needed
- name: Display backup status
ansible.builtin.debug:
msg: "Backup created: {{ gitea_backup_dir }}/gitea-backup-{{ backup_timestamp }}.tar.gz"
when: backup_needed
- name: Upload backup to GDrive (if configured)
ansible.builtin.command:
cmd: "rclone copy {{ gitea_backup_dir }}/gitea-backup-{{ backup_timestamp }}.tar.gz GDrive:backups/gitea/"
when:
- backup_needed
- gitea_backup_to_gdrive
ignore_errors: true
register: gdrive_upload
changed_when: gdrive_upload.rc == 0
# =========================================================================
# Stage 2: Domain Migration (app.ini)
# =========================================================================
- name: Update app.ini ROOT_URL
ansible.builtin.lineinfile:
path: "{{ gitea_data_dir }}/gitea/conf/app.ini"
regexp: '^ROOT_URL\s*='
line: "ROOT_URL = https://{{ gitea_domain }}/"
backup: true
- name: Update app.ini SSH_DOMAIN
ansible.builtin.lineinfile:
path: "{{ gitea_data_dir }}/gitea/conf/app.ini"
regexp: '^SSH_DOMAIN\s*='
line: "SSH_DOMAIN = {{ gitea_ssh_domain }}"
- name: Update app.ini DOMAIN
ansible.builtin.lineinfile:
path: "{{ gitea_data_dir }}/gitea/conf/app.ini"
regexp: '^DOMAIN\s*='
line: "DOMAIN = {{ gitea_domain }}"
# =========================================================================
# Stage 3: Deploy Updated Configuration
# =========================================================================
- name: Deploy docker-compose.yml
ansible.builtin.template:
src: templates/docker-compose.yml.j2
dest: "{{ gitea_base_dir }}/docker-compose.yml"
mode: "0644"
backup: true
- name: Deploy Caddyfile with domain redirect
ansible.builtin.template:
src: templates/Caddyfile.j2
dest: "{{ gitea_base_dir }}/Caddyfile"
mode: "0644"
backup: true
- name: Start services
ansible.builtin.command:
cmd: docker compose up -d
chdir: "{{ gitea_base_dir }}"
changed_when: true
- name: Wait for Caddy to start (port 443)
ansible.builtin.wait_for:
port: 443
host: 127.0.0.1
delay: 5
timeout: 60
- name: Wait for Gitea container to be healthy
ansible.builtin.command:
cmd: docker compose ps gitea --format json
chdir: "{{ gitea_base_dir }}"
register: gitea_container
until: "'running' in gitea_container.stdout"
retries: 12
delay: 5
changed_when: false
# =========================================================================
# Stage 4: Authentik OAuth Setup
# =========================================================================
- name: Install jq for OAuth setup script
ansible.builtin.apt:
name: jq
state: present
update_cache: true
when: not authentik_check.failed
- name: Deploy Gitea OAuth setup script
ansible.builtin.template:
src: templates/setup-gitea-oauth.sh.j2
dest: "{{ gitea_base_dir }}/setup-gitea-oauth.sh"
mode: "0755"
when: not authentik_check.failed
- name: Run Gitea OAuth setup on Authentik
ansible.builtin.command:
cmd: "{{ gitea_base_dir }}/setup-gitea-oauth.sh"
register: oauth_setup
when: not authentik_check.failed
changed_when: true
- name: Display OAuth setup output
ansible.builtin.debug:
var: oauth_setup.stdout_lines
when:
- not authentik_check.failed
- oauth_setup is defined
# =========================================================================
# Stage 5: Verification
# =========================================================================
- name: Wait for Gitea to be healthy on new domain
ansible.builtin.uri:
url: "https://{{ gitea_domain }}/api/v1/version"
method: GET
status_code: 200
timeout: 30
validate_certs: true
register: gitea_health
until: gitea_health.status == 200
retries: 12
delay: 10
ignore_errors: true
- name: Check old domain redirect
ansible.builtin.uri:
url: "https://{{ gitea_old_domain }}/"
method: GET
follow_redirects: none
status_code: [301, 302, 308]
validate_certs: true
register: redirect_check
ignore_errors: true
- name: Display migration status
ansible.builtin.debug:
msg: |
============================================
Gitea Migration Complete!
============================================
New URL: https://{{ gitea_domain }}
Old URL: https://{{ gitea_old_domain }} (redirects)
Health check: {{ 'PASSED' if gitea_health.status == 200 else 'PENDING - may need DNS propagation' }}
Redirect check: {{ 'PASSED' if redirect_check.status in [301, 302, 308] else 'PENDING' }}
Backup: {{ gitea_backup_dir }}/gitea-backup-{{ backup_timestamp | default('N/A') }}.tar.gz
============================================
MANUAL STEPS REQUIRED:
============================================
1. DNS (if not done):
Add A record: code.stuslab.cc -> 94.130.181.201
2. OAuth Configuration in Gitea UI:
- Go to: https://{{ gitea_domain }}/admin/auths/new
- See credentials: cat /tmp/gitea-oauth-credentials.json
3. Test git operations:
ssh -T git@{{ gitea_ssh_domain }} -p {{ gitea_ssh_port }}
git clone git@{{ gitea_ssh_domain }}:user/repo.git
============================================
View logs:
ssh root@{{ ansible_host }} "cd {{ gitea_base_dir }} && docker compose logs -f"
============================================