Files
michaelschiemer/deployment/ansible/playbooks/setup/redeploy-traefik-gitea-clean.yml
Michael Schiemer 8f3c15ddbb fix(console): comprehensive TUI rendering fixes
- Fix Enter key detection: handle multiple Enter key formats (\n, \r, \r\n)
- Reduce flickering: lower render frequency from 60 FPS to 30 FPS
- Fix menu bar visibility: re-render menu bar after content to prevent overwriting
- Fix content positioning: explicit line positioning for categories and commands
- Fix line shifting: clear lines before writing, control newlines manually
- Limit visible items: prevent overflow with maxVisibleCategories/Commands
- Improve CPU usage: increase sleep interval when no events processed

This fixes:
- Enter key not working for selection
- Strong flickering of the application
- Menu bar not visible or being overwritten
- Top half of selection list not displayed
- Lines being shifted/misaligned
2025-11-10 11:06:07 +01:00

322 lines
12 KiB
YAML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
# Clean Redeploy Traefik and Gitea Stacks
# Complete redeployment with backup, container recreation, and verification
#
# Usage:
# # With automatic backup
# ansible-playbook -i inventory/production.yml playbooks/setup/redeploy-traefik-gitea-clean.yml \
# --vault-password-file secrets/.vault_pass
#
# # With existing backup
# ansible-playbook -i inventory/production.yml playbooks/setup/redeploy-traefik-gitea-clean.yml \
# --vault-password-file secrets/.vault_pass \
# -e "backup_name=redeploy-backup-1234567890" \
# -e "skip_backup=true"
- name: Clean Redeploy Traefik and Gitea
hosts: production
gather_facts: yes
become: no
vars:
traefik_stack_path: "{{ stacks_base_path }}/traefik"
gitea_stack_path: "{{ stacks_base_path }}/gitea"
gitea_url: "https://{{ gitea_domain }}"
traefik_container_name: "traefik"
gitea_container_name: "gitea"
backup_base_path: "{{ backups_path | default('/home/deploy/backups') }}"
skip_backup: "{{ skip_backup | default(false) | bool }}"
backup_name: "{{ backup_name | default('') }}"
tasks:
# ========================================
# 1. BACKUP (unless skipped)
# ========================================
- name: Set backup name fact
ansible.builtin.set_fact:
actual_backup_name: "{{ backup_name | default('redeploy-backup-' + ansible_date_time.epoch) }}"
when: not skip_backup
- name: Display backup note
ansible.builtin.debug:
msg: |
⚠️ NOTE: Backup should be run separately before redeploy:
ansible-playbook -i inventory/production.yml playbooks/maintenance/backup-before-redeploy.yml \
--vault-password-file secrets/.vault_pass \
-e "backup_name={{ actual_backup_name }}"
Or use existing backup with: -e "backup_name=redeploy-backup-XXXXX" -e "skip_backup=true"
when: not skip_backup
- name: Display redeployment plan
ansible.builtin.debug:
msg: |
================================================================================
CLEAN REDEPLOY TRAEFIK AND GITEA
================================================================================
This playbook will:
1. ✅ Backup ({% if skip_backup %}SKIPPED{% else %}Performed{% endif %})
2. ✅ Stop and remove Traefik containers (keeps acme.json)
3. ✅ Stop and remove Gitea containers (keeps volumes/data)
4. ✅ Sync latest stack configurations
5. ✅ Redeploy Traefik stack
6. ✅ Redeploy Gitea stack
7. ✅ Restore Gitea configuration (app.ini)
8. ✅ Verify service discovery
9. ✅ Test Gitea accessibility
⚠️ IMPORTANT:
- SSL certificates (acme.json) will be preserved
- Gitea data (volumes) will be preserved
- Only containers will be recreated
- Expected downtime: ~2-5 minutes
{% if not skip_backup %}
- Backup location: {{ backup_base_path }}/{{ actual_backup_name }}
{% endif %}
================================================================================
# ========================================
# 2. STOP AND REMOVE CONTAINERS
# ========================================
- name: Stop Traefik stack
ansible.builtin.shell: |
cd {{ traefik_stack_path }}
docker compose down
register: traefik_stop
changed_when: traefik_stop.rc == 0
failed_when: false
- name: Remove Traefik containers (if any remain)
ansible.builtin.shell: |
docker ps -a --filter "name={{ traefik_container_name }}" --format "{{ '{{' }}.ID{{ '}}' }}" | xargs -r docker rm -f 2>/dev/null || true
register: traefik_remove
changed_when: traefik_remove.rc == 0
failed_when: false
- name: Stop Gitea stack (preserves volumes)
ansible.builtin.shell: |
cd {{ gitea_stack_path }}
docker compose down
register: gitea_stop
changed_when: gitea_stop.rc == 0
failed_when: false
- name: Remove Gitea containers (if any remain, volumes are preserved)
ansible.builtin.shell: |
docker ps -a --filter "name={{ gitea_container_name }}" --format "{{ '{{' }}.ID{{ '}}' }}" | xargs -r docker rm -f 2>/dev/null || true
register: gitea_remove
changed_when: gitea_remove.rc == 0
failed_when: false
# ========================================
# 3. SYNC CONFIGURATIONS
# ========================================
- name: Get stacks directory path
ansible.builtin.set_fact:
stacks_source_path: "{{ playbook_dir | dirname | dirname | dirname }}/stacks"
delegate_to: localhost
run_once: true
- name: Sync stacks directory to production server
ansible.builtin.synchronize:
src: "{{ stacks_source_path }}/"
dest: "{{ stacks_base_path }}/"
delete: no
recursive: yes
rsync_opts:
- "--chmod=D755,F644"
- "--exclude=.git"
- "--exclude=*.log"
- "--exclude=data/"
- "--exclude=volumes/"
- "--exclude=acme.json" # Preserve SSL certificates
- "--exclude=*.key"
- "--exclude=*.pem"
# ========================================
# 4. ENSURE ACME.JSON EXISTS
# ========================================
- name: Check if acme.json exists
ansible.builtin.stat:
path: "{{ traefik_stack_path }}/acme.json"
register: acme_json_stat
- name: Ensure acme.json exists and has correct permissions
ansible.builtin.file:
path: "{{ traefik_stack_path }}/acme.json"
state: touch
mode: '0600'
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
become: yes
register: acme_json_ensure
# ========================================
# 5. REDEPLOY TRAEFIK
# ========================================
- name: Deploy Traefik stack
community.docker.docker_compose_v2:
project_src: "{{ traefik_stack_path }}"
state: present
pull: always
register: traefik_deploy
- name: Wait for Traefik to be ready
ansible.builtin.shell: |
cd {{ traefik_stack_path }}
docker compose ps {{ traefik_container_name }} | grep -Eiq "Up|running"
register: traefik_ready
changed_when: false
until: traefik_ready.rc == 0
retries: 12
delay: 5
failed_when: traefik_ready.rc != 0
# ========================================
# 6. REDEPLOY GITEA
# ========================================
- name: Deploy Gitea stack
community.docker.docker_compose_v2:
project_src: "{{ gitea_stack_path }}"
state: present
pull: always
register: gitea_deploy
- name: Wait for Gitea to be ready
ansible.builtin.shell: |
cd {{ gitea_stack_path }}
docker compose ps {{ gitea_container_name }} | grep -Eiq "Up|running"
register: gitea_ready
changed_when: false
until: gitea_ready.rc == 0
retries: 12
delay: 5
failed_when: gitea_ready.rc != 0
- name: Wait for Gitea to be healthy
ansible.builtin.shell: |
cd {{ gitea_stack_path }}
docker compose exec -T {{ gitea_container_name }} curl -f http://localhost:3000/api/healthz 2>&1 | grep -q "status.*pass" && echo "HEALTHY" || echo "NOT_HEALTHY"
register: gitea_health
changed_when: false
until: gitea_health.stdout == "HEALTHY"
retries: 30
delay: 2
failed_when: false
# ========================================
# 7. RESTORE GITEA CONFIGURATION
# ========================================
- name: Restore Gitea app.ini from backup
ansible.builtin.shell: |
if [ -f "{{ backup_base_path }}/{{ actual_backup_name }}/gitea-app.ini" ]; then
cd {{ gitea_stack_path }}
docker compose exec -T {{ gitea_container_name }} sh -c "cat > /data/gitea/conf/app.ini" < "{{ backup_base_path }}/{{ actual_backup_name }}/gitea-app.ini"
docker compose restart {{ gitea_container_name }}
echo "app.ini restored and Gitea restarted"
else
echo "No app.ini backup found, using default configuration"
fi
when: not skip_backup
register: gitea_app_ini_restore
changed_when: false
failed_when: false
# ========================================
# 8. VERIFY SERVICE DISCOVERY
# ========================================
- name: Wait for service discovery (Traefik needs time to discover Gitea)
ansible.builtin.pause:
seconds: 15
- name: Check if Gitea is in traefik-public network
ansible.builtin.shell: |
docker network inspect traefik-public --format '{{ '{{' }}range .Containers{{ '}}' }}{{ '{{' }}.Name{{ '}}' }} {{ '{{' }}end{{ '}}' }}' 2>/dev/null | grep -q {{ gitea_container_name }} && echo "YES" || echo "NO"
register: gitea_in_network
changed_when: false
- name: Test direct connection from Traefik to Gitea
ansible.builtin.shell: |
cd {{ traefik_stack_path }}
docker compose exec -T {{ traefik_container_name }} wget -qO- --timeout=5 http://{{ gitea_container_name }}:3000/api/healthz 2>&1 | head -5 || echo "CONNECTION_FAILED"
register: traefik_gitea_direct
changed_when: false
failed_when: false
# ========================================
# 9. FINAL VERIFICATION
# ========================================
- name: Test Gitea via HTTPS (with retries)
ansible.builtin.uri:
url: "{{ gitea_url }}/api/healthz"
method: GET
status_code: [200]
validate_certs: false
timeout: 10
register: gitea_https_test
until: gitea_https_test.status == 200
retries: 20
delay: 3
changed_when: false
failed_when: false
- name: Check SSL certificate status
ansible.builtin.shell: |
cd {{ traefik_stack_path }}
if [ -f acme.json ] && [ -s acme.json ]; then
echo "SSL certificates: PRESENT"
else
echo "SSL certificates: MISSING or EMPTY"
fi
register: ssl_status
changed_when: false
- name: Final status summary
ansible.builtin.debug:
msg: |
================================================================================
REDEPLOYMENT SUMMARY
================================================================================
Traefik:
- Status: {{ traefik_ready.rc | ternary('Up', 'Down') }}
- SSL Certificates: {{ ssl_status.stdout }}
Gitea:
- Status: {{ gitea_ready.rc | ternary('Up', 'Down') }}
- Health: {% if gitea_health.stdout == 'HEALTHY' %}✅ Healthy{% else %}❌ Not Healthy{% endif %}
- Configuration: {% if gitea_app_ini_restore.changed %}✅ Restored{% else %} Using default{% endif %}
Service Discovery:
- Gitea in network: {% if gitea_in_network.stdout == 'YES' %}✅{% else %}❌{% endif %}
- Direct connection: {% if 'CONNECTION_FAILED' not in traefik_gitea_direct.stdout %}✅{% else %}❌{% endif %}
Gitea Accessibility:
{% if gitea_https_test.status == 200 %}
✅ Gitea is reachable via HTTPS (Status: 200)
URL: {{ gitea_url }}
{% else %}
❌ Gitea is NOT reachable via HTTPS (Status: {{ gitea_https_test.status | default('TIMEOUT') }})
Possible causes:
1. SSL certificate is still being generated (wait 2-5 minutes)
2. Service discovery needs more time (wait 1-2 minutes)
3. Network configuration issue
Next steps:
- Wait 2-5 minutes and test again: curl -k {{ gitea_url }}/api/healthz
- Check Traefik logs: cd {{ traefik_stack_path }} && docker compose logs {{ traefik_container_name }} --tail=50
- Check Gitea logs: cd {{ gitea_stack_path }} && docker compose logs {{ gitea_container_name }} --tail=50
{% endif %}
{% if not skip_backup %}
Backup location: {{ backup_base_path }}/{{ actual_backup_name }}
To rollback: ansible-playbook -i inventory/production.yml playbooks/maintenance/rollback-redeploy.yml \
--vault-password-file secrets/.vault_pass \
-e "backup_name={{ actual_backup_name }}"
{% endif %}
================================================================================