feat(Deployment): Integrate Ansible deployment via PHP deployment pipeline
- Create AnsibleDeployStage using framework's Process module for secure command execution - Integrate AnsibleDeployStage into DeploymentPipelineCommands for production deployments - Add force_deploy flag support in Ansible playbook to override stale locks - Use PHP deployment module as orchestrator (php console.php deploy:production) - Fix ErrorAggregationInitializer to use Environment class instead of $_ENV superglobal Architecture: - BuildStage → AnsibleDeployStage → HealthCheckStage for production - Process module provides timeout, error handling, and output capture - Ansible playbook supports rollback via rollback-git-based.yml - Zero-downtime deployments with health checks
This commit is contained in:
142
deployment/infrastructure/playbooks/rollback-git-based.yml
Normal file
142
deployment/infrastructure/playbooks/rollback-git-based.yml
Normal file
@@ -0,0 +1,142 @@
|
||||
---
|
||||
# Git-based Rollback Playbook
|
||||
# Rolls back to the previous release by switching the symlink
|
||||
#
|
||||
# Usage:
|
||||
# ansible-playbook -i inventories/production/hosts.yml playbooks/rollback-git-based.yml
|
||||
# ansible-playbook -i inventories/production/hosts.yml playbooks/rollback-git-based.yml --extra-vars "rollback_to=20241025123456"
|
||||
|
||||
- name: Rollback Custom PHP Framework (Git-based)
|
||||
hosts: web_servers
|
||||
become: true
|
||||
|
||||
vars:
|
||||
app_name: michaelschiemer
|
||||
app_user: deploy
|
||||
app_group: deploy
|
||||
app_base_path: "/var/www/{{ app_name }}"
|
||||
releases_path: "{{ app_base_path }}/releases"
|
||||
current_path: "{{ app_base_path }}/current"
|
||||
|
||||
pre_tasks:
|
||||
- name: Check if deployment lock exists
|
||||
stat:
|
||||
path: "{{ app_base_path }}/.deploy.lock"
|
||||
register: deploy_lock
|
||||
|
||||
- name: Fail if deployment is in progress
|
||||
fail:
|
||||
msg: "Cannot rollback - deployment in progress"
|
||||
when: deploy_lock.stat.exists
|
||||
|
||||
- name: Create rollback lock
|
||||
file:
|
||||
path: "{{ app_base_path }}/.rollback.lock"
|
||||
state: touch
|
||||
owner: "{{ app_user }}"
|
||||
group: "{{ app_group }}"
|
||||
|
||||
tasks:
|
||||
- name: Get current release
|
||||
stat:
|
||||
path: "{{ current_path }}"
|
||||
register: current_release
|
||||
|
||||
- name: Fail if no current release exists
|
||||
fail:
|
||||
msg: "No current release found at {{ current_path }}"
|
||||
when: not current_release.stat.exists
|
||||
|
||||
- name: Get list of all releases
|
||||
find:
|
||||
paths: "{{ releases_path }}"
|
||||
file_type: directory
|
||||
register: all_releases
|
||||
|
||||
- name: Sort releases by creation time (newest first)
|
||||
set_fact:
|
||||
sorted_releases: "{{ all_releases.files | sort(attribute='ctime', reverse=true) }}"
|
||||
|
||||
- name: Determine target release for rollback
|
||||
set_fact:
|
||||
target_release: "{{ rollback_to if rollback_to is defined else sorted_releases[1].path }}"
|
||||
|
||||
- name: Verify target release exists
|
||||
stat:
|
||||
path: "{{ target_release }}"
|
||||
register: target_release_stat
|
||||
|
||||
- name: Fail if target release doesn't exist
|
||||
fail:
|
||||
msg: "Target release not found: {{ target_release }}"
|
||||
when: not target_release_stat.stat.exists
|
||||
|
||||
- name: Display rollback information
|
||||
debug:
|
||||
msg:
|
||||
- "Current release: {{ current_release.stat.lnk_source }}"
|
||||
- "Rolling back to: {{ target_release }}"
|
||||
|
||||
- name: Switch symlink to previous release
|
||||
file:
|
||||
src: "{{ target_release }}"
|
||||
dest: "{{ current_path }}"
|
||||
state: link
|
||||
owner: "{{ app_user }}"
|
||||
group: "{{ app_group }}"
|
||||
force: yes
|
||||
|
||||
- name: Wait for application to be ready
|
||||
wait_for:
|
||||
timeout: 5
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Health check after rollback
|
||||
uri:
|
||||
url: "http://{{ ansible_host }}/health/summary"
|
||||
method: GET
|
||||
return_content: yes
|
||||
status_code: 200
|
||||
register: health_check
|
||||
retries: 3
|
||||
delay: 5
|
||||
until: health_check.status == 200
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Log rollback
|
||||
lineinfile:
|
||||
path: "{{ app_base_path }}/deploy.log"
|
||||
line: "[{{ ansible_date_time.iso8601 }}] ROLLBACK: {{ current_release.stat.lnk_source }} -> {{ target_release }} - Health: {{ health_check.status | default('FAILED') }}"
|
||||
create: yes
|
||||
|
||||
- name: Display rollback result
|
||||
debug:
|
||||
msg:
|
||||
- "=========================================="
|
||||
- "Rollback completed"
|
||||
- "Previous: {{ current_release.stat.lnk_source }}"
|
||||
- "Current: {{ target_release }}"
|
||||
- "Health check: {{ health_check.status | default('FAILED') }}"
|
||||
- "=========================================="
|
||||
|
||||
post_tasks:
|
||||
- name: Remove rollback lock
|
||||
file:
|
||||
path: "{{ app_base_path }}/.rollback.lock"
|
||||
state: absent
|
||||
|
||||
rescue:
|
||||
- name: Remove rollback lock on failure
|
||||
file:
|
||||
path: "{{ app_base_path }}/.rollback.lock"
|
||||
state: absent
|
||||
|
||||
- name: Log rollback failure
|
||||
lineinfile:
|
||||
path: "{{ app_base_path }}/deploy.log"
|
||||
line: "[{{ ansible_date_time.iso8601 }}] ROLLBACK FAILED"
|
||||
create: yes
|
||||
|
||||
- name: Fail with error message
|
||||
fail:
|
||||
msg: "Rollback failed"
|
||||
Reference in New Issue
Block a user