159 lines
6.3 KiB
YAML
159 lines
6.3 KiB
YAML
---
|
|
# playbooks/docker/deploy_gitea.yml
|
|
#
|
|
# Purpose:
|
|
# Deploy Gitea as a Swarm stack pinned to swarm-manager-1, with a dedicated
|
|
# Postgres sidecar and persistent bind mounts under /mnt/homelab/apps/gitea.
|
|
#
|
|
# Data protection:
|
|
# Preflight checks require all data paths to exist before deploy.
|
|
# If paths are missing, deployment fails early to avoid creating an empty
|
|
# data root over an existing Gitea installation.
|
|
#
|
|
# Usage:
|
|
# ansible-playbook -i inventory/hosts.ini playbooks/docker/deploy_gitea.yml
|
|
#
|
|
# Validate only (no Swarm mutations):
|
|
# ansible-playbook -i inventory/hosts.ini playbooks/docker/deploy_gitea.yml \
|
|
# -e "stack_validate_only=true"
|
|
#
|
|
# Tear down:
|
|
# ansible-playbook -i inventory/hosts.ini playbooks/docker/deploy_gitea.yml \
|
|
# -e "gitea_deploy_state=absent"
|
|
|
|
- name: Deploy Gitea Swarm stack
|
|
hosts: swarm_managers
|
|
become: true
|
|
gather_facts: false
|
|
vars_files:
|
|
- ../../group_vars/all.yml
|
|
vars:
|
|
gitea_deploy_target: "{{ edge_routing.swarm.stack_deploy_target | default(groups['swarm_managers'][0]) }}"
|
|
|
|
tasks:
|
|
|
|
# --------------------------------------------------
|
|
# STEP 0: Assert required secrets are present
|
|
# --------------------------------------------------
|
|
|
|
- name: Assert vault_gitea_db_password is defined and non-empty
|
|
ansible.builtin.assert:
|
|
that:
|
|
- vault_gitea_db_password is defined
|
|
- vault_gitea_db_password | trim | length > 0
|
|
fail_msg: >-
|
|
vault_gitea_db_password is not defined or is empty.
|
|
Encrypt and store it in group_vars/vault/all.yml with:
|
|
ansible-vault encrypt_string 'your-db-password' --name 'vault_gitea_db_password'
|
|
when: inventory_hostname == gitea_deploy_target
|
|
|
|
- name: Assert vault_gitea_db_password is not a placeholder
|
|
ansible.builtin.assert:
|
|
that:
|
|
- vault_gitea_db_password not in ['change-me', 'changeme', 'your-db-password']
|
|
fail_msg: "vault_gitea_db_password still appears to be a placeholder. Set a real vault value before deploy."
|
|
when: inventory_hostname == gitea_deploy_target
|
|
|
|
# --------------------------------------------------
|
|
# STEP 1: Assert Swarm manager is active
|
|
# WHY exact equality: search('active') matches 'inactive' as a substring.
|
|
# The format string yields 'active|true' only for a healthy manager.
|
|
# --------------------------------------------------
|
|
|
|
- name: Collect Swarm manager state
|
|
ansible.builtin.command: >
|
|
docker info --format '{{ "{{" }}.Swarm.LocalNodeState{{ "}}" }}|{{ "{{" }}.Swarm.ControlAvailable{{ "}}" }}'
|
|
register: _swarm_info
|
|
changed_when: false
|
|
when: inventory_hostname == gitea_deploy_target
|
|
|
|
- name: Assert target is an active Swarm manager
|
|
ansible.builtin.assert:
|
|
that:
|
|
- _swarm_info.stdout == 'active|true'
|
|
fail_msg: >-
|
|
{{ inventory_hostname }} must be an active Swarm manager.
|
|
Expected 'active|true', got '{{ _swarm_info.stdout | default('unknown') }}'.
|
|
when: inventory_hostname == gitea_deploy_target
|
|
|
|
# --------------------------------------------------
|
|
# STEP 2: Validate pre-existing persistent data paths
|
|
# WHY: Missing paths cause Gitea to bootstrap a fresh install over existing
|
|
# data. The operator must create or restore paths before deploying.
|
|
# --------------------------------------------------
|
|
|
|
- name: Stat required Gitea bind-mount paths
|
|
ansible.builtin.stat:
|
|
path: "{{ item }}"
|
|
register: _gitea_path_stat
|
|
loop:
|
|
- /mnt/homelab/apps/gitea
|
|
- /mnt/homelab/apps/gitea/data
|
|
- /mnt/homelab/apps/gitea/data/db
|
|
when: inventory_hostname == gitea_deploy_target
|
|
|
|
- name: Assert required Gitea paths exist before deploy
|
|
ansible.builtin.assert:
|
|
that:
|
|
- item.stat.exists
|
|
- item.stat.isdir
|
|
fail_msg: >-
|
|
Required Gitea path '{{ item.item }}' is missing on {{ inventory_hostname }}.
|
|
Create or restore this directory first to protect existing data.
|
|
loop: "{{ _gitea_path_stat.results }}"
|
|
when: inventory_hostname == gitea_deploy_target
|
|
|
|
# --------------------------------------------------
|
|
# STEP 3: Deploy Gitea stack
|
|
# --------------------------------------------------
|
|
|
|
- name: Deploy Gitea stack
|
|
ansible.builtin.include_role:
|
|
name: swarm_stack_deploy
|
|
vars:
|
|
stack_name: "gitea"
|
|
stack_compose_src: "{{ playbook_dir }}/../../templates/stacks/gitea.stack.yml"
|
|
# WHY gitea_deploy_state (not stack_state): using stack_state directly
|
|
# creates a Jinja2 self-reference loop inside the role.
|
|
stack_state: "{{ gitea_deploy_state | default('present') }}"
|
|
stack_required_external_networks:
|
|
- proxy-net
|
|
stack_required_directories:
|
|
- /mnt/homelab/apps/gitea
|
|
- /mnt/homelab/apps/gitea/data
|
|
- /mnt/homelab/apps/gitea/data/db
|
|
when: inventory_hostname == gitea_deploy_target
|
|
|
|
# --------------------------------------------------
|
|
# STEP 4: Wait for service convergence
|
|
# --------------------------------------------------
|
|
|
|
- name: Wait for Gitea server service to converge
|
|
ansible.builtin.command: >
|
|
docker service ls --filter name=gitea_server --format '{{ "{{" }}.Replicas{{ "}}" }}'
|
|
register: _gitea_replicas
|
|
retries: 18
|
|
delay: 10
|
|
until: _gitea_replicas.stdout is search('1/1')
|
|
changed_when: false
|
|
when:
|
|
- inventory_hostname == gitea_deploy_target
|
|
- gitea_deploy_state | default('present') == 'present'
|
|
- not ansible_check_mode
|
|
tags: [verify]
|
|
|
|
- name: Report Gitea deployment result
|
|
ansible.builtin.debug:
|
|
msg:
|
|
- "================================================"
|
|
- "Gitea deployment complete."
|
|
- "================================================"
|
|
- "Stack : gitea"
|
|
- "Manager : {{ inventory_hostname }} ({{ ansible_host | default('') }})"
|
|
- "URL : https://git.castaldifamily.com"
|
|
- "Data root : /mnt/homelab/apps/gitea"
|
|
- "Services : gitea_server, gitea_gitea-db"
|
|
- "================================================"
|
|
when: inventory_hostname == gitea_deploy_target
|
|
tags: [always]
|