Switch to terraform
This commit is contained in:
308
ansible/gitea/migration/playbook.yml
Normal file
308
ansible/gitea/migration/playbook.yml
Normal 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"
|
||||
|
||||
============================================
|
||||
Reference in New Issue
Block a user