- Added ansible/ directory with playbooks for: * deploy.yml: Update applications on devices from git * commands.yml: Execute arbitrary commands on devices * system_update.yml: OS updates and health checks * inventory.ini: Device and group configuration * README.md: Comprehensive Ansible guide * requirements.txt: Installation instructions - Added ansible_integration.py: Python module wrapping Ansible operations - Added utils_ansible.py: Updated utilities using Ansible instead of HTTP commands Key benefits: - Idempotent operations with error recovery - Comprehensive logging and backup - Multi-device orchestration - Better reliability and control - Replaces unreliable direct HTTP command execution
202 lines
5.7 KiB
YAML
202 lines
5.7 KiB
YAML
---
|
|
# deploy.yml - Deploy updates to Prezenta Work devices
|
|
# Handles pulling latest code and restarting services
|
|
|
|
- name: Deploy Prezenta Work Updates
|
|
hosts: prezenta_devices
|
|
gather_facts: yes
|
|
serial: 1 # Deploy one device at a time to avoid service interruption
|
|
|
|
vars:
|
|
app_directory: "/srv/prezenta_work"
|
|
git_branch: "dev"
|
|
restart_service: true
|
|
backup_before_deploy: true
|
|
|
|
tasks:
|
|
- name: Display deployment information
|
|
debug:
|
|
msg: "Deploying to {{ inventory_hostname }} ({{ ansible_host }})"
|
|
|
|
# Pre-deployment checks
|
|
- name: Check if app directory exists
|
|
stat:
|
|
path: "{{ app_directory }}"
|
|
register: app_dir_stat
|
|
|
|
- name: Fail if app directory doesn't exist
|
|
fail:
|
|
msg: "Application directory {{ app_directory }} not found on {{ inventory_hostname }}"
|
|
when: not app_dir_stat.stat.exists
|
|
|
|
# Backup current code
|
|
- name: Create backup directory
|
|
file:
|
|
path: "{{ app_directory }}/backups"
|
|
state: directory
|
|
mode: '0755'
|
|
when: backup_before_deploy
|
|
|
|
- name: Backup current code
|
|
shell: |
|
|
cd {{ app_directory }}
|
|
tar -czf backups/backup_{{ ansible_date_time.iso8601_basic_short }}.tar.gz \
|
|
--exclude=.git \
|
|
--exclude=__pycache__ \
|
|
--exclude=data \
|
|
--exclude=Files \
|
|
.
|
|
register: backup_result
|
|
when: backup_before_deploy
|
|
|
|
- name: Display backup created
|
|
debug:
|
|
msg: "Backup created: {{ backup_result.stdout_lines }}"
|
|
when: backup_before_deploy and backup_result is not skipped
|
|
|
|
# Pull latest code
|
|
- name: Fetch latest from repository
|
|
shell: |
|
|
cd {{ app_directory }}
|
|
git fetch origin
|
|
register: git_fetch
|
|
changed_when: "'Fetching' in git_fetch.stdout or 'Receiving' in git_fetch.stdout"
|
|
|
|
- name: Checkout dev branch
|
|
shell: |
|
|
cd {{ app_directory }}
|
|
git checkout {{ git_branch }}
|
|
register: git_checkout
|
|
|
|
- name: Pull latest changes
|
|
shell: |
|
|
cd {{ app_directory }}
|
|
git pull origin {{ git_branch }}
|
|
register: git_pull
|
|
changed_when: "'Already up to date' not in git_pull.stdout"
|
|
|
|
- name: Display git pull result
|
|
debug:
|
|
msg: "{{ git_pull.stdout }}"
|
|
|
|
# Verify deployment
|
|
- name: Check Python syntax
|
|
shell: |
|
|
python3 -m py_compile {{ app_directory }}/app.py
|
|
register: syntax_check
|
|
changed_when: false
|
|
failed_when: syntax_check.rc != 0
|
|
|
|
- name: Verify all modules compile
|
|
shell: |
|
|
cd {{ app_directory }}
|
|
python3 -m py_compile *.py
|
|
register: module_check
|
|
changed_when: false
|
|
|
|
- name: Verify configuration
|
|
shell: |
|
|
cd {{ app_directory }}
|
|
python3 -c "import config_settings; print('✓ Configuration OK')"
|
|
register: config_check
|
|
changed_when: false
|
|
|
|
- name: Display verification results
|
|
debug:
|
|
msg: "{{ config_check.stdout }}"
|
|
|
|
# Restart application
|
|
- name: Restart Prezenta application
|
|
block:
|
|
- name: Stop Prezenta service
|
|
systemd:
|
|
name: prezenta
|
|
state: stopped
|
|
daemon_reload: yes
|
|
become: yes
|
|
when: restart_service
|
|
|
|
- name: Wait for service to stop
|
|
pause:
|
|
seconds: 2
|
|
|
|
- name: Start Prezenta service
|
|
systemd:
|
|
name: prezenta
|
|
state: started
|
|
enabled: yes
|
|
become: yes
|
|
when: restart_service
|
|
|
|
- name: Verify service is running
|
|
systemd:
|
|
name: prezenta
|
|
state: started
|
|
become: yes
|
|
register: service_status
|
|
until: service_status.status.ActiveState == "active"
|
|
retries: 3
|
|
delay: 5
|
|
rescue:
|
|
- name: Service restart failed, attempting manual restart
|
|
debug:
|
|
msg: "Attempting to restart application manually on {{ inventory_hostname }}"
|
|
|
|
- name: Kill existing processes
|
|
shell: |
|
|
pkill -f "python3.*app.py" || true
|
|
become: yes
|
|
|
|
- name: Wait before restart
|
|
pause:
|
|
seconds: 3
|
|
|
|
- name: Start application in background
|
|
shell: |
|
|
cd {{ app_directory }}
|
|
nohup python3 app.py > data/startup.log 2>&1 &
|
|
become: yes
|
|
become_user: pi
|
|
|
|
# Post-deployment verification
|
|
- name: Wait for application to start
|
|
pause:
|
|
seconds: 5
|
|
|
|
- name: Check application status via HTTP
|
|
uri:
|
|
url: "http://{{ ansible_host }}:80/status"
|
|
method: GET
|
|
status_code: [200, 404]
|
|
timeout: 10
|
|
register: app_status
|
|
retries: 3
|
|
delay: 2
|
|
until: app_status.status in [200, 404]
|
|
|
|
- name: Display application status
|
|
debug:
|
|
msg: "Application on {{ inventory_hostname }} is running"
|
|
when: app_status.status in [200, 404]
|
|
|
|
# Log deployment
|
|
- name: Record deployment in log
|
|
lineinfile:
|
|
path: "{{ app_directory }}/data/deploy.log"
|
|
line: "[{{ ansible_date_time.iso8601 }}] Deployed {{ git_branch }} from {{ ansible_user }}@monitoring_server"
|
|
create: yes
|
|
state: present
|
|
|
|
- name: Log deployment summary
|
|
debug:
|
|
msg: |
|
|
Deployment completed for {{ inventory_hostname }}
|
|
Branch: {{ git_branch }}
|
|
Status: SUCCESS
|
|
Last git commit: {{ git_pull.stdout_lines[-1] if git_pull.stdout_lines else 'Unknown' }}
|
|
|
|
post_tasks:
|
|
- name: Send deployment notification
|
|
debug:
|
|
msg: "Deployment notification: {{ inventory_hostname }} updated to {{ git_branch }}"
|