--- # Ansible Playbook: Emergency Rollback # Purpose: Rollback to previous working deployment # Usage: ansible-playbook -i inventory/production.yml playbooks/rollback.yml - name: Rollback Production Deployment hosts: production_server become: no vars: registry_url: "git.michaelschiemer.de:5000" image_name: "framework" stack_name: "framework" rollback_tag: "{{ rollback_tag | default('latest') }}" tasks: - name: Display rollback warning debug: msg: | ⚠️ ROLLBACK IN PROGRESS This will revert services to a previous image. Current target: {{ rollback_tag }} - name: Pause for confirmation (manual runs only) pause: prompt: "Press ENTER to continue with rollback, or Ctrl+C to abort" when: ansible_check_mode is not defined - name: Get list of available image tags shell: | docker images {{ registry_url }}/{{ image_name }} --format "{{`{{.Tag}}`}}" | grep -v buildcache | head -10 register: available_tags changed_when: false - name: Display available tags debug: msg: | Available image tags for rollback: {{ available_tags.stdout_lines | join('\n') }} - name: Verify rollback image exists docker_image: name: "{{ registry_url }}/{{ image_name }}" tag: "{{ rollback_tag }}" source: pull register: rollback_image ignore_errors: yes - name: Fail if image doesn't exist fail: msg: "Rollback image {{ registry_url }}/{{ image_name }}:{{ rollback_tag }} not found" when: rollback_image is failed - name: Rollback web service docker_swarm_service: name: "{{ stack_name }}_web" image: "{{ registry_url }}/{{ image_name }}:{{ rollback_tag }}" force_update: yes update_config: parallelism: 2 delay: 5s state: present register: web_rollback - name: Rollback queue-worker service docker_swarm_service: name: "{{ stack_name }}_queue-worker" image: "{{ registry_url }}/{{ image_name }}:{{ rollback_tag }}" force_update: yes update_config: parallelism: 1 delay: 5s state: present register: worker_rollback - name: Wait for rollback to complete pause: seconds: 30 - name: Verify rollback success shell: | docker service ps {{ stack_name }}_web --filter "desired-state=running" --format "{{`{{.CurrentState}}`}}" | head -1 register: rollback_state changed_when: false - name: Test service health uri: url: "https://michaelschiemer.de/health" validate_certs: no status_code: [200, 302] timeout: 10 register: health_check ignore_errors: yes - name: Record rollback in history copy: content: | Rollback: {{ ansible_date_time.iso8601 }} Previous Image: {{ registry_url }}/{{ image_name }}:latest Rollback Image: {{ registry_url }}/{{ image_name }}:{{ rollback_tag }} Status: {{ health_check.status | default('UNKNOWN') }} Reason: Manual rollback or deployment failure dest: "/home/deploy/deployments/rollback-{{ ansible_date_time.epoch }}.log" mode: '0644' - name: Display rollback summary debug: msg: | {% if health_check is succeeded %} ✅ Rollback completed successfully {% else %} ❌ Rollback completed but health check failed {% endif %} Image: {{ registry_url }}/{{ image_name }}:{{ rollback_tag }} Web Service: {{ web_rollback.changed | ternary('ROLLED BACK', 'NO CHANGE') }} Worker Service: {{ worker_rollback.changed | ternary('ROLLED BACK', 'NO CHANGE') }} Health Status: {{ health_check.status | default('FAILED') }} - name: Alert if rollback failed fail: msg: "Rollback completed but health check failed. Manual intervention required." when: health_check is failed