Add Ansible integration for device management and deployment automation
- 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
This commit is contained in:
201
ansible/deploy.yml
Normal file
201
ansible/deploy.yml
Normal file
@@ -0,0 +1,201 @@
|
||||
---
|
||||
# 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 }}"
|
||||
Reference in New Issue
Block a user