--- # Service Restart Playbook # Restart specific services with proper dependency handling # Usage: ansible-playbook playbooks/restart_service.yml -e "service_name=plex host_target=atlantis" # Usage: ansible-playbook playbooks/restart_service.yml -e "service_name=immich-server host_target=atlantis wait_time=30" - name: Restart Service with Dependency Handling hosts: "{{ host_target | default('all') }}" gather_facts: yes vars: service_name: "{{ service_name | mandatory }}" force_restart: "{{ force_restart | default(false) }}" # Service dependency mapping service_dependencies: # Media stack dependencies plex: depends_on: [] restart_delay: 30 sonarr: depends_on: ["prowlarr"] restart_delay: 20 radarr: depends_on: ["prowlarr"] restart_delay: 20 lidarr: depends_on: ["prowlarr"] restart_delay: 20 bazarr: depends_on: ["sonarr", "radarr"] restart_delay: 15 jellyseerr: depends_on: ["plex", "sonarr", "radarr"] restart_delay: 25 # Immich stack immich-server: depends_on: ["immich-db", "immich-redis"] restart_delay: 30 immich-machine-learning: depends_on: ["immich-server"] restart_delay: 20 # Security stack vaultwarden: depends_on: ["vaultwarden-db"] restart_delay: 25 # Monitoring stack grafana: depends_on: ["prometheus"] restart_delay: 20 prometheus: depends_on: [] restart_delay: 30 tasks: - name: Validate required variables fail: msg: "service_name is required. Use -e 'service_name=SERVICE_NAME'" when: service_name is not defined or service_name == "" - name: Check if Docker is running systemd: name: docker register: docker_status failed_when: docker_status.status.ActiveState != "active" - name: Check if service exists shell: 'docker ps -a --filter "name={{ service_name }}" --format "{%raw%}{{.Names}}{%endraw%}"' register: service_exists changed_when: false - name: Fail if service doesn't exist fail: msg: "Service '{{ service_name }}' not found on {{ inventory_hostname }}" when: service_exists.stdout == "" - name: Get current service status shell: 'docker ps --filter "name={{ service_name }}" --format "{%raw%}{{.Status}}{%endraw%}"' register: service_status_before changed_when: false - name: Display pre-restart status debug: msg: | 🔄 RESTART REQUEST for {{ service_name }} on {{ inventory_hostname }} 📊 Current Status: {{ service_status_before.stdout | default('Not running') }} ⏱️ Wait Time: {{ wait_time | default(15) }} seconds 🔗 Dependencies: {{ service_dependencies.get(service_name, {}).get('depends_on', []) | join(', ') or 'None' }} - name: Check dependencies are running shell: 'docker ps --filter "name={{ item }}" --format "{%raw%}{{.Names}}{%endraw%}"' register: dependency_check loop: "{{ service_dependencies.get(service_name, {}).get('depends_on', []) }}" when: service_dependencies.get(service_name, {}).get('depends_on', []) | length > 0 - name: Warn about missing dependencies debug: msg: "⚠️ Warning: Dependency '{{ item.item }}' is not running" loop: "{{ dependency_check.results | default([]) }}" when: - dependency_check is defined - item.stdout == "" - name: Create pre-restart backup of logs shell: | mkdir -p /tmp/service_logs/{{ ansible_date_time.date }} docker logs {{ service_name }} --tail 100 > /tmp/service_logs/{{ ansible_date_time.date }}/{{ service_name }}_pre_restart.log 2>&1 ignore_errors: yes - name: Stop service gracefully shell: docker stop {{ service_name }} register: stop_result ignore_errors: yes - name: Force stop if graceful stop failed shell: docker kill {{ service_name }} when: - stop_result.rc != 0 - force_restart | bool - name: Wait for service to fully stop shell: 'docker ps --filter "name={{ service_name }}" --format "{%raw%}{{.Names}}{%endraw%}"' register: stop_check until: stop_check.stdout == "" retries: 10 delay: 2 - name: Start service shell: docker start {{ service_name }} register: start_result - name: Wait for service to be ready pause: seconds: "{{ service_dependencies.get(service_name, {}).get('restart_delay', wait_time | default(15)) }}" - name: Verify service is running shell: 'docker ps --filter "name={{ service_name }}" --format "{%raw%}{{.Status}}{%endraw%}"' register: service_status_after retries: 5 delay: 3 until: "'Up' in service_status_after.stdout" - name: Check service health (if health check available) shell: 'docker inspect {{ service_name }} --format="{%raw%}{{.State.Health.Status}}{%endraw%}"' register: health_check ignore_errors: yes changed_when: false - name: Wait for healthy status shell: 'docker inspect {{ service_name }} --format="{%raw%}{{.State.Health.Status}}{%endraw%}"' register: health_status until: health_status.stdout == "healthy" retries: 10 delay: 5 when: - health_check.rc == 0 - health_check.stdout != "none" ignore_errors: yes - name: Create post-restart log snapshot shell: | docker logs {{ service_name }} --tail 50 > /tmp/service_logs/{{ ansible_date_time.date }}/{{ service_name }}_post_restart.log 2>&1 ignore_errors: yes - name: Display restart results debug: msg: | ✅ SERVICE RESTART COMPLETE ================================ 🖥️ Host: {{ inventory_hostname }} 🔧 Service: {{ service_name }} 📊 Status Before: {{ service_status_before.stdout | default('Not running') }} 📊 Status After: {{ service_status_after.stdout }} {% if health_check.rc == 0 and health_check.stdout != "none" %} 🏥 Health Status: {{ health_status.stdout | default('Checking...') }} {% endif %} ⏱️ Restart Duration: {{ service_dependencies.get(service_name, {}).get('restart_delay', wait_time | default(15)) }} seconds 📝 Logs: /tmp/service_logs/{{ ansible_date_time.date }}/{{ service_name }}_*.log ================================ - name: Restart dependent services (if any) include_tasks: restart_dependent_services.yml vars: parent_service: "{{ service_name }}" when: restart_dependents | default(false) | bool handlers: - name: restart_dependent_services debug: msg: "This would restart services that depend on {{ service_name }}"