- 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
256 lines
9.8 KiB
YAML
256 lines
9.8 KiB
YAML
---
|
||
# Rollback Redeploy
|
||
# Restores Traefik and Gitea from backup created before redeploy
|
||
#
|
||
# Usage:
|
||
# ansible-playbook -i inventory/production.yml playbooks/maintenance/rollback-redeploy.yml \
|
||
# --vault-password-file secrets/.vault_pass \
|
||
# -e "backup_name=redeploy-backup-1234567890"
|
||
|
||
- name: Rollback Redeploy
|
||
hosts: production
|
||
gather_facts: yes
|
||
become: no
|
||
vars:
|
||
traefik_stack_path: "{{ stacks_base_path }}/traefik"
|
||
gitea_stack_path: "{{ stacks_base_path }}/gitea"
|
||
backup_base_path: "{{ backups_path | default('/home/deploy/backups') }}"
|
||
backup_name: "{{ backup_name | default('') }}"
|
||
|
||
tasks:
|
||
- name: Validate backup name
|
||
ansible.builtin.fail:
|
||
msg: "backup_name is required. Use: -e 'backup_name=redeploy-backup-1234567890'"
|
||
when: backup_name == ""
|
||
|
||
- name: Check if backup directory exists
|
||
ansible.builtin.stat:
|
||
path: "{{ backup_base_path }}/{{ backup_name }}"
|
||
register: backup_dir_stat
|
||
|
||
- name: Fail if backup not found
|
||
ansible.builtin.fail:
|
||
msg: "Backup directory not found: {{ backup_base_path }}/{{ backup_name }}"
|
||
when: not backup_dir_stat.stat.exists
|
||
|
||
- name: Display rollback plan
|
||
ansible.builtin.debug:
|
||
msg: |
|
||
================================================================================
|
||
ROLLBACK REDEPLOY
|
||
================================================================================
|
||
|
||
This playbook will restore from backup: {{ backup_base_path }}/{{ backup_name }}
|
||
|
||
Steps:
|
||
1. Stop Traefik and Gitea stacks
|
||
2. Restore Gitea volumes
|
||
3. Restore SSL certificates (acme.json)
|
||
4. Restore Gitea configuration (app.ini)
|
||
5. Restore Traefik configuration
|
||
6. Restore PostgreSQL data (if applicable)
|
||
7. Restart stacks
|
||
8. Verify
|
||
|
||
⚠️ WARNING: This will overwrite current state!
|
||
|
||
================================================================================
|
||
|
||
# ========================================
|
||
# 1. STOP STACKS
|
||
# ========================================
|
||
- 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: Stop Gitea stack
|
||
ansible.builtin.shell: |
|
||
cd {{ gitea_stack_path }}
|
||
docker compose down
|
||
register: gitea_stop
|
||
changed_when: gitea_stop.rc == 0
|
||
failed_when: false
|
||
|
||
# ========================================
|
||
# 2. RESTORE GITEA VOLUMES
|
||
# ========================================
|
||
- name: List Gitea volume backups
|
||
ansible.builtin.shell: |
|
||
ls -1 "{{ backup_base_path }}/{{ backup_name }}/gitea-volume-"*.tar.gz 2>/dev/null || echo ""
|
||
register: gitea_volume_backups
|
||
changed_when: false
|
||
|
||
- name: Restore Gitea volumes
|
||
ansible.builtin.shell: |
|
||
for backup_file in {{ backup_base_path }}/{{ backup_name }}/gitea-volume-*.tar.gz; do
|
||
if [ -f "$backup_file" ]; then
|
||
volume_name=$(basename "$backup_file" .tar.gz | sed 's/gitea-volume-//')
|
||
echo "Restoring volume: $volume_name"
|
||
docker volume create "$volume_name" 2>/dev/null || true
|
||
docker run --rm \
|
||
-v "$volume_name:/target" \
|
||
-v "{{ backup_base_path }}/{{ backup_name }}:/backup:ro" \
|
||
alpine sh -c "cd /target && tar xzf /backup/$(basename $backup_file)"
|
||
fi
|
||
done
|
||
when: gitea_volume_backups.stdout != ""
|
||
register: gitea_volumes_restore
|
||
changed_when: gitea_volumes_restore.rc == 0
|
||
|
||
# ========================================
|
||
# 3. RESTORE SSL CERTIFICATES
|
||
# ========================================
|
||
- name: Restore acme.json
|
||
ansible.builtin.copy:
|
||
src: "{{ backup_base_path }}/{{ backup_name }}/acme.json"
|
||
dest: "{{ traefik_stack_path }}/acme.json"
|
||
remote_src: yes
|
||
mode: '0600'
|
||
register: acme_restore
|
||
changed_when: acme_restore.rc == 0
|
||
|
||
# ========================================
|
||
# 4. RESTORE CONFIGURATIONS
|
||
# ========================================
|
||
- name: Restore Gitea docker-compose.yml
|
||
ansible.builtin.copy:
|
||
src: "{{ backup_base_path }}/{{ backup_name }}/gitea-docker-compose.yml"
|
||
dest: "{{ gitea_stack_path }}/docker-compose.yml"
|
||
remote_src: yes
|
||
mode: '0644'
|
||
register: gitea_compose_restore
|
||
changed_when: gitea_compose_restore.rc == 0
|
||
failed_when: false
|
||
|
||
- name: Restore Traefik configuration
|
||
ansible.builtin.shell: |
|
||
cd {{ traefik_stack_path }}
|
||
tar xzf "{{ backup_base_path }}/{{ backup_name }}/traefik-config.tar.gz" 2>/dev/null || echo "Some files may be missing"
|
||
register: traefik_config_restore
|
||
changed_when: traefik_config_restore.rc == 0
|
||
failed_when: false
|
||
|
||
# ========================================
|
||
# 5. RESTORE POSTGRESQL DATA
|
||
# ========================================
|
||
- name: Find PostgreSQL backup
|
||
ansible.builtin.shell: |
|
||
ls -1 "{{ backup_base_path }}/{{ backup_name }}/postgresql-all-"*.sql.gz 2>/dev/null | head -1 || echo ""
|
||
register: postgres_backup_file
|
||
changed_when: false
|
||
|
||
- name: Restore PostgreSQL database
|
||
ansible.builtin.shell: |
|
||
cd {{ stacks_base_path }}/postgresql
|
||
if docker compose ps postgres | grep -q "Up"; then
|
||
gunzip -c "{{ postgres_backup_file.stdout }}" | docker compose exec -T postgres psql -U postgres
|
||
echo "PostgreSQL restored"
|
||
else
|
||
echo "PostgreSQL not running, skipping restore"
|
||
fi
|
||
when: postgres_backup_file.stdout != ""
|
||
register: postgres_restore
|
||
changed_when: false
|
||
failed_when: false
|
||
|
||
# ========================================
|
||
# 6. RESTART STACKS
|
||
# ========================================
|
||
- 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 | 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
|
||
|
||
- name: Deploy Gitea stack
|
||
community.docker.docker_compose_v2:
|
||
project_src: "{{ gitea_stack_path }}"
|
||
state: present
|
||
pull: always
|
||
register: gitea_deploy
|
||
|
||
- name: Restore Gitea app.ini
|
||
ansible.builtin.shell: |
|
||
if [ -f "{{ backup_base_path }}/{{ backup_name }}/gitea-app.ini" ]; then
|
||
cd {{ gitea_stack_path }}
|
||
docker compose exec -T gitea sh -c "cat > /data/gitea/conf/app.ini" < "{{ backup_base_path }}/{{ backup_name }}/gitea-app.ini"
|
||
docker compose restart gitea
|
||
echo "app.ini restored and Gitea restarted"
|
||
else
|
||
echo "No app.ini backup found"
|
||
fi
|
||
register: gitea_app_ini_restore
|
||
changed_when: false
|
||
failed_when: false
|
||
|
||
- name: Wait for Gitea to be ready
|
||
ansible.builtin.shell: |
|
||
cd {{ gitea_stack_path }}
|
||
docker compose ps gitea | 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
|
||
|
||
# ========================================
|
||
# 7. VERIFY
|
||
# ========================================
|
||
- name: Wait for Gitea to be healthy
|
||
ansible.builtin.shell: |
|
||
cd {{ gitea_stack_path }}
|
||
docker compose exec -T gitea 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
|
||
|
||
- name: Summary
|
||
ansible.builtin.debug:
|
||
msg: |
|
||
================================================================================
|
||
ROLLBACK SUMMARY
|
||
================================================================================
|
||
|
||
Restored from backup: {{ backup_base_path }}/{{ backup_name }}
|
||
|
||
Restored:
|
||
- Gitea volumes: {% if gitea_volumes_restore.changed %}✅{% else %}ℹ️ No volumes to restore{% endif %}
|
||
- SSL certificates: {% if acme_restore.changed %}✅{% else %}ℹ️ Not found{% endif %}
|
||
- Gitea docker-compose.yml: {% if gitea_compose_restore.changed %}✅{% else %}ℹ️ Not found{% endif %}
|
||
- Traefik configuration: {% if traefik_config_restore.rc == 0 %}✅{% else %}⚠️ Some files may be missing{% endif %}
|
||
- PostgreSQL data: {% if postgres_restore.rc == 0 and 'restored' in postgres_restore.stdout %}✅{% else %}ℹ️ Not restored{% endif %}
|
||
- Gitea app.ini: {% if gitea_app_ini_restore.rc == 0 and 'restored' in gitea_app_ini_restore.stdout %}✅{% else %}ℹ️ Not found{% endif %}
|
||
|
||
Status:
|
||
- Traefik: {% if traefik_ready.rc == 0 %}✅ Running{% else %}❌ Not running{% endif %}
|
||
- Gitea: {% if gitea_ready.rc == 0 %}✅ Running{% else %}❌ Not running{% endif %}
|
||
- Gitea Health: {% if gitea_health.stdout == 'HEALTHY' %}✅ Healthy{% else %}❌ Not healthy{% endif %}
|
||
|
||
Next steps:
|
||
1. Test Gitea: curl -k https://{{ gitea_domain }}/api/healthz
|
||
2. Check logs if issues: cd {{ gitea_stack_path }} && docker compose logs gitea --tail=50
|
||
|
||
================================================================================
|
||
|
||
|