When automating system administration with Ansible, a common requirement is to restart services after configuration changes - but only when those services were already running. This avoids accidentally starting services that were intentionally stopped, while ensuring running services get their necessary reloads.
The standard service
module's restarted
state will restart regardless of initial state. While we could use shell
with platform-specific commands like systemctl is-active
, this breaks cross-platform compatibility - exactly what Ansible aims to solve.
Here's the cleanest approach combining Ansible's fact gathering with conditional execution:
- name: Check if service is currently running
ansible.builtin.service:
name: nginx
enabled: yes
register: service_status
changed_when: false
- name: Restart service if it was running
ansible.builtin.service:
name: nginx
state: restarted
when: service_status.state == "running"
For better integration with configuration file changes, use handlers with the same conditional logic:
handlers:
- name: Restart nginx if running
ansible.builtin.service:
name: nginx
state: restarted
when: service_status.state == "running"
tasks:
- name: Check nginx status
ansible.builtin.service:
name: nginx
register: service_status
changed_when: false
- name: Update nginx config
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: Restart nginx if running
While this approach works across init systems, consider these edge cases:
- For Docker containers: Check
service_status.state
against both "running" and "active" - For older SysV systems: Verify your Ansible version handles
status
commands properly
When dealing with multiple services, gather all statuses in a single task using loop
:
- name: Check multiple services
ansible.builtin.service:
name: "{{ item }}"
register: all_services
changed_when: false
loop:
- nginx
- postgresql
- redis
- name: Restart all running services
ansible.builtin.service:
name: "{{ item.item }}"
state: restarted
when: item.state == "running"
loop: "{{ all_services.results }}"
When managing services through Ansible, we often face a common scenario: needing to restart a service after configuration changes, but only if the service was already running. This becomes particularly important in production environments where we want to avoid accidentally starting services that were intentionally stopped.
Ansible's service
module provides excellent cross-platform compatibility (supporting systemd, upstart, sysvinit, etc.), but lacks a built-in way to check the current state before performing actions. The typical approach using changed_when
and handlers might restart services regardless of their initial state.
Here's the most elegant solution I've found that maintains portability across init systems:
- name: Gather service facts
ansible.builtin.service_facts:
- name: Restart service if it was running
ansible.builtin.service:
name: nginx
state: restarted
when: ansible_facts.services['nginx.service'].state == 'running'
For more robust handling across different scenarios:
- name: Conditional service restart with fallback
block:
- name: Check service status
ansible.builtin.command: systemctl is-active nginx
register: service_status
changed_when: false
ignore_errors: true
- name: Restart if was active
ansible.builtin.service:
name: nginx
state: restarted
when: service_status.rc == 0
rescue:
- name: Alternative service fact collection
ansible.builtin.service_facts:
- name: Fallback restart check
ansible.builtin.service:
name: nginx
state: restarted
when: ansible_facts.services.get('nginx.service', {}).get('state') == 'running'
For cleaner playbooks, implement this as a handler:
handlers:
- name: Conditional restart handler
ansible.builtin.service:
name: "{{ service_name }}"
state: restarted
when: ansible_facts.services["{{ service_name }}.service"].state == 'running'
Remember that service_facts
gathers information about all services. For large environments, consider:
- Running service facts once per playbook
- Caching facts with
fact_caching
- Using specific status commands for critical services