
Ansible Firefighting Hotline Series (6): Automated Inspection of Key Linux Services (Easily Customizable)
Is your server down again? Donβt panic! This Ansible inspection “robot” can pinpoint the problematic service with one click!
<span><span>#Operations</span></span><span><span>#Automation</span></span><span><span>#Ansible</span></span><span><span>#ServerInspection</span></span><span><span>#Linux</span></span><span><span>#EfficiencyTool</span></span>
π‘ Thought Upgrade: From “Functional” to “Excellent”, Why Do We Choose Roles?π‘
Before we dive into practical applications, letβs discuss a deeper topic: Why do we bother to refactor a working Playbook into a more complex structure called a Role?
The answer is simple: We pursue not just functional automation, but maintainable, scalable, and collaborative excellent automation. This is a key step from amateur to professional.
1. Embrace Simplicity β¨ A lengthy Playbook is like a book without chapters; itβs exhausting to read. Roles break down a complex task (like service inspection) into several standard parts:
β’<span><span>tasks/</span></span>: Responsible for what to do.β’<span><span>defaults/</span></span>: Responsible for defining adjustable variables.β’<span><span>handlers/</span></span>: Responsible for responding to events. This way, your main playbook <span><span>site.yml</span></span> becomes extremely concise, like a senior manager who only needs to call which Role without worrying about the details. The entire automation process is clear at a glance.
2. Achieve Decoupling π This is one of the core values of Roles. We perfectly separate “what to check” (What – variables, such as service lists) from “how to check” (How – task logic) through the <span><span>defaults/main.yml</span></span> file.
β’When requirements change: For example, if you need to add a new service <span><span>nginx</span></span> to the inspection list, you only need to modify the variable file <span><span>defaults/main.yml</span></span>, without touching the core task logic <span><span>tasks/main.yml</span></span>. This greatly reduces the risk of introducing new errors due to modifications.
3. Pursue Reusability β»οΈ A well-written Role is a reusable “automation building block”. The <span><span>service_check</span></span> Role you create today can be reused in countless scenarios:
β’Daily health inspections.β’Environment checks before application releases.β’Status verification after security baseline hardening. You only need to call this complete and reliable inspection capability in any main playbook with one line of code: <span><span>roles: - service_check</span></span>.
4. Empower the Team π When automation is confined to a single Playbook file, it is merelyan individual tool. When you start building and using Roles, it transcends intoa team asset.
β’Knowledge Accumulation: Best practices are solidified in Roles, becoming shared, tested “standard components” for the team.β’Lowering Barriers: New members no longer need to understand complex script details; they only need to learn how to call these standardized Roles to quickly contribute value to the team.β’Accelerated Collaboration: Team members can collaborate, with some responsible for developing and maintaining foundational Roles (like <span><span>apache</span></span>, <span><span>mysql</span></span><code><span><span>), while others orchestrate these Roles to complete complex business deployments.</span></span><p><span><span>In summary, using Roles is our path to drive automation from</span></span><strong><span><span>individual heroism</span></span></strong><span><span> towards</span></span><strong><span><span>team-oriented, engineered, and sustainable development</span></span></strong><span><span>.</span></span></p><p><span><span>Hello to all the heroes fighting on the front lines of operations! π</span></span></p><p><strong><span><span>Ansible Firefighting Hotline</span></span></strong><span><span> is back online, and this time we are addressing the most heart-pounding issueβ</span></span><strong><span><span>core service status inspection</span></span></strong><span><span>!</span></span></p><p><span><span>Have you ever experienced such a terrifying moment:</span></span></p><span><span>β’</span></span><span><span>Woken up by an alarm call in the middle of the night, only to find that a critical service (like </span></span><code><span><span>sshd</span></span>) is down? π±β’Your boss requests a status report on services like <span><span>firewalld</span></span>, <span><span>chronyd</span></span> across hundreds of servers, and you can only log in one by one to execute <span><span>systemctl status</span></span> and manually compile the results? π¨π»π¦β’The system is unstable, and you want to quickly troubleshoot whether the basic services are the problem, but you donβt know where to start? π€
Today, we bring you a powerful toolβa reusable Ansible Role that acts like an intelligent inspection robot, automatically logging into all servers, checking all specified critical services, and collecting detailed reports!
π€© Inspection Report, A Sneak Peek!
After executing this Role, you will find a dedicated report generated for each server in the <span><span>/tmp/</span></span> directory, with clear and straightforward content:
# RHEL Key Service Status Check Report for rhel9.example.com
# Generated at: 2025-06-14T12:00:00Z
# ---
[Service Status Report: sshd]
Service Name: sshd.service
Current Status: RUNNING
Auto-start Configuration: ENABLED
Service Source: systemd
[Service Status Report: firewalld]
Service Name: firewalld.service
Current Status: RUNNING
Auto-start Configuration: ENABLED
Service Source: systemd
[Service Status Report: imaginary-service]
[CRITICAL] Service imaginary-service is not installed or recognized by systemdοΌ
...
It clearly indicates which services are not running and which services are not installed!
π₯ Evolution! From Playbook to Professional Role!
To make this inspection tool more professional and user-friendly, we have refactored it from a standalone <span><span>.yml</span></span> file into a standard Ansible Role. The benefits of this approach are:
β’Structured: Logic is clearer, and files serve their respective purposes.β’Configurable: Want to check different services? Just modify the variable file without touching the core logic!β’Reusable: This Role can be easily integrated into any other automation project!
π Foolproof Getting Started Guide (Three Steps to Success)
Step 1: π Create Role Directory Structure
First, create a standard Role directory structure. You can quickly generate it using the <span><span>ansible-galaxy init roles/service_check</span></span> command or manually create the following directories and files as shown:
.
βββ inventory # Your server inventory
βββ site.yml # Main playbook, responsible for calling Roles
βββ roles/
βββ service_check/
βββ defaults/
β βββ main.yml # π Define the list of services you want to check here!
βββ tasks/
βββ main.yml # Core task logic of the Role
Step 2: βοΈ Fill in the File Content
Fill in the prepared code into the corresponding files.
1. Role Default Variables: <span><span>roles/service_check/defaults/main.yml</span></span> Here, you can customize the list of services you want to inspect!
---
# roles/service_check/defaults/main.yml
# Define the list of services you want to inspect here, feel free to add or remove! (Please ensure the service names are correct!)
critical_services_list:
- sshd
- firewalld
- chronyd
- tuned
- NetworkManager
- rsyslog
- auditd
- crond
- dbus
- systemd-journald
# Define the path for the report
report_base_path: "/tmp"
collection_dest_path: "/tmp/"
2. Role Core Tasks: <span><span>roles/service_check/tasks/main.yml</span></span> This is the core logic of the inspection robot.
---
# roles/service_check/tasks/main.yml
- name: Stage 1.1 - Define the complete path for the report
ansible.builtin.set_fact:
report_file_path: "{{ report_base_path }}/linux_service_check_{{ inventory_hostname }}.txt"
- name: Stage 1.2 - Clean up old report files on remote hosts
ansible.builtin.file:
path: "{{ report_file_path }}"
state: absent
- name: Stage 1.3 - Collect necessary Facts (date and time)
ansible.builtin.setup:
filter:
- ansible_date_time
- name: Stage 1.4 - Efficiently collect all service information
ansible.builtin.service_facts:
register: service_facts_result
- name: Stage 1.5 - Create report file on remote host and write title
ansible.builtin.lineinfile:
path: "{{ report_file_path }}"
line: |
# RHEL Key Service Status Check Report for {{ inventory_hostname }}
# Generated at: {{ ansible_date_time.iso8601 }}
# ---
create: true
mode: '0644'
- name: Stage 1.6 - Loop through and check service status, writing to report
ansible.builtin.lineinfile:
path: "{{ report_file_path }}"
insertafter: EOF
create: false
line: |
{% set service_full_name = item + '.service' %}
{% if service_full_name in service_facts_result.ansible_facts.services %}
[Service Status Report: {{ item }}]
Service Name: {{ service_facts_result.ansible_facts.services[service_full_name].name | default('N/A') }}
Current Status: {{ service_facts_result.ansible_facts.services[service_full_name].state | upper | default('N/A') }}
Auto-start Configuration: {{ service_facts_result.ansible_facts.services[service_full_name].status | upper | default('N/A') }}
Service Source: {{ service_facts_result.ansible_facts.services[service_full_name].source | default('N/A') }}
{% else %}
[Service Status Report: {{ item }}]
[CRITICAL] Service {{ item }} is not installed or recognized by systemd!
{% endif %}
loop: "{{ critical_services_list }}"
3. Main Playbook: <span><span>site.yml</span></span> This file is now super simple; it only needs to “issue commands”.
---
- name: Play 1 - Execute service inspection on all hosts and generate reports
hosts: all
become: true
gather_facts: false # Role will collect as needed
roles:
- service_check
- name: Play 2 - Collect reports back to control node
hosts: all
gather_facts: false
# π¨ Bug fix: Define the variables needed for this Play, as this Play does not load the Role and cannot know the variables defined in the Role
vars:
report_base_path: "/tmp"
collection_dest_path: "/tmp/"
tasks:
- name: Pull report files from each target host
ansible.builtin.fetch:
src: "{{ report_base_path }}/linux_service_check_{{ inventory_hostname }}.txt"
dest: "{{ collection_dest_path }}"
flat: yes
- name: Play 3 - Final Confirmation
hosts: localhost
connection: local
gather_facts: false
tasks:
- name: Display final summary information on console
ansible.builtin.debug:
msg:
- "β
All inspection reports have been successfully collected!"
- "Reports are stored in the /tmp/ directory of the controller."
Step 3: π Run!
In the terminal, navigate to the project root directory and run the final command:
[root@ansible25 service_check]# ansible-playbook -i inventory site.yml
PLAY [Play 1 - Execute service inspection on all hosts and generate reports]
************************************************
TASK [service_check : Stage 1.1 - Define the complete path for the report]
ok: [Test-RHEL-7.9-1]
************************************************
TASK [service_check : Stage 1.2 - Clean up old report files on remote hosts]
changed: [Test-RHEL-7.9-1]
************************************************
TASK [service_check : Stage 1.3 - Collect necessary Facts (date and time)]
ok: [Test-RHEL-7.9-1]
************************************************
TASK [service_check : Stage 1.4 - Efficiently collect all service information]
ok: [Test-RHEL-7.9-1]
************************************************
TASK [service_check : Stage 1.5 - Create report file on remote host and write title]
changed: [Test-RHEL-7.9-1]
************************************************
TASK [service_check : Stage 1.6 - Loop through and check service status, writing to report]
************************************************
changed: [Test-RHEL-7.9-1] => (item=sshd)
changed: [Test-RHEL-7.9-1] => (item=firewalld)
changed: [Test-RHEL-7.9-1] => (item=chronyd)
changed: [Test-RHEL-7.9-1] => (item=tuned)
changed: [Test-RHEL-7.9-1] => (item=NetworkManager)
changed: [Test-RHEL-7.9-1] => (item=rsyslog)
changed: [Test-RHEL-7.9-1] => (item=auditd)
changed: [Test-RHEL-7.9-1] => (item=crond)
changed: [Test-RHEL-7.9-1] => (item=dbus)
changed: [Test-RHEL-7.9-1] => (item=systemd-journald)
************************************************
PLAY [Play 2 - Collect reports back to control node]
************************************************
TASK [Pull report files from each target host]
changed: [Test-RHEL-7.9-1]
************************************************
PLAY [Play 3 - Final Confirmation]
************************************************
TASK [Display final summary information on console]
ok: [localhost] =>
msg:
- "β
All inspection reports have been successfully collected!"
- "Reports are stored in the /tmp/ directory of the controller."
************************************************
PLAY RECAP
Test-RHEL-7.9-1 : ok=7 changed=4 unreachable=0 failed=0 ...
[root@ansible25 service_check]# more /tmp/linux_service_check_Test-RHEL-7.9-1.txt
# RHEL Key Service Status Check Report for Test-RHEL-7.9-1
# Generated at: 2025-07-27T23:02:20Z
# ---
[Service Status Report: sshd]
Service Name: sshd.service
Current Status: RUNNING
Auto-start Configuration: ENABLED
Service Source: systemd
[Service Status Report: firewalld]
Service Name: firewalld.service
Current Status: INACTIVE
Auto-start Configuration: DISABLED
Service Source: systemd
[Service Status Report: chronyd]
Service Name: chronyd.service
Current Status: RUNNING
Auto-start Configuration: ENABLED
Service Source: systemd
[Service Status Report: tuned]
Service Name: tuned.service
Current Status: RUNNING
Auto-start Configuration: ENABLED
Service Source: systemd
[Service Status Report: NetworkManager]
Service Name: NetworkManager.service
Current Status: RUNNING
Auto-start Configuration: ENABLED
Service Source: systemd
[Service Status Report: rsyslog]
Service Name: rsyslog.service
Current Status: RUNNING
Auto-start Configuration: ENABLED
Service Source: systemd
[Service Status Report: auditd]
Service Name: auditd.service
Current Status: RUNNING
Auto-start Configuration: ENABLED
Service Source: systemd
[Service Status Report: crond]
Service Name: crond.service
Current Status: RUNNING
Auto-start Configuration: ENABLED
Service Source: systemd
[Service Status Report: dbus]
Service Name: dbus.service
Current Status: RUNNING
Auto-start Configuration: STATIC
Service Source: systemd
[Service Status Report: systemd-journald]
Service Name: systemd-journald.service
Current Status: RUNNING
Auto-start Configuration: STATIC
Service Source: systemd
All done! Now, your automated inspection system is fully set up!
π Summary Moment: The “Treasure Insights” of Operations Personnel
This refactoring from Playbook to Role is not just a relocation of code, but an elevation of the philosophy of operational automation:
1Embrace Roles, Embrace the Future: Roles are the essence of Ansible. They make your automation code modular, configurable, and shareable. A Role you write today may become the cornerstone of another major project for you or your colleagues tomorrow.2Defaults (<span><span>defaults</span></span>) are Best Practices: Placing variable parts (like service lists) in <span><span>defaults/main.yml</span></span><span><span> is the golden rule of Role design. It provides users with great flexibility while maintaining the stability of core logic.</span></span><span><span>3</span></span><strong><code><span><span>service_facts</span></span> is the Inspection Tool: This module can retrieve the status of all services at once, which is much more efficient than calling the <span><span>systemd</span></span><span><span> module one by one in a loop, exemplifying performance optimization.</span></span><span><span>4</span></span><strong><span><span>Phased Execution, Clear Logic</span></span></strong><span><span>: Retaining the three-part playbook structure of "Generate -> Collect -> Confirm" ensures clarity and reliability in the workflow. Let all nodes complete their tasks first, then collect the results uniformly; this is a classic model for distributed task processing.</span></span><p><span><span>Do you feel like youβve grasped the correct way to use enterprise-level Ansible?</span></span></p><p><span><span>I have packaged this ready-to-use, structurally complete </span></span><strong><span><span>Ansible Role</span></span></strong><span><span> for you!</span></span></p><p><span><span>πππ</span></span></p><p><strong><span><span>Click on the "Read Original" below to get the complete Role source package!</span></span></strong></p><p><span><span>To access the original text, please scroll to the bottom of the page.</span></span></p><p><span><span>Hurry up and deploy a tireless automated inspection robot for you and your team! See you next time! π</span></span></p>