Saturday, 29 November 2025

Ansible - 5. Interesting facts


1) command is the shorthand version of fully qualified name ansible.builtin.command , and is the Recommended standard for production and complex playbooks.

example,

- name: List files
  command: ls -l /tmp


- name: List files
  ansible.builtin.command: ls -l /tmp


2) command cannot run shell operators like |, >, &&. For that, use shell module or ansible.builtin.shell.- can you show me an exmple

Below will fail :

- name: List files in /tmp and save to file 
  ansible.builtin.command: ls /tmp > /tmp/files.txt

Correct way:

- name: List files in /tmp and save to file
  ansible.builtin.shell: ls /tmp > /tmp/files.txt


3)  Why simple hostname task is reported as CHANGED by ansible ?

[oracle@oel01db ansible-project]$ ansible all -i inventory/hosts -m command -a "hostname"
192.168.0.156 | CHANGED | rc=0 >>
oel02db.mydb.com
[oracle@oel01db ansible-project]$

n Ansible, a task is marked CHANGED if the module cannot guarantee that the command did nothing — and the command module always assumes the command may have changed something.

hostname command itself does nothing harmful — it only prints the hostname —
but Ansible does not know that.
So it marks it as changed.

How to force it to show OK (not changed)

Use changed_when: false

You CANNOT control changed_when in an ad-hoc command.

We need to use inside playbook
- hosts: all
  tasks:
    - name: Show hostname
      command: hostname
      changed_when: false

4) In Ansible, these two options control when a task is marked as failed and when it is marked as changed.
Let’s break them down simply:

failed_when: false

Meaning

No matter what happens (even if the command returns a non-zero exit status), Ansible will NOT mark the task as failed.

Use case

Useful when:

  • A command normally returns a non-zero code but it should NOT be treated as an error.

  • You want to continue even if the command fails.

Example (Oracle user check)

- name: Check if Oracle user exists command: id oracle register: user_check failed_when: false

🔍 If id oracle fails because user doesn’t exist, the play continues.


or 

- name: 💾 Check Free Disk Space

  hosts: webservers

  tasks:

    - name: Get /var filesystem usage

      ansible.builtin.command: df -h /var

      register: disk_usage_result # 1. Register the command output

      changed_when: false         # 2. Tell Ansible this task never changes the system


This makes sure Ansible does not treat the command as a change to the system.

Even if the command runs successfully, Ansible reports:

ok

instead of:

changed



changed_when: false

Meaning

Even if the command makes changes or returns something unusual, Ansible will NOT mark the task as changed.

Use case

Used for:

  • Read-only tasks (checks, queries)

  • Idempotency — run every time but never show “CHANGED”

Example

- name: Check if database already exists command: sqlplus -s system/Pass123 @"check_db.sql" register: db_status changed_when: false

🔍 This is a check-only task. It should NEVER show as “changed”.


5) Ansible facts 

1. The Role of the Gathering Facts Task

Ansible automatically collects information about the remote host at the beginning of every play by default. This process is handled by a special task called Gathering Facts, which runs before any of your defined tasks.

  • When you run your playbook, the first output you see is usually:

    TASK [Gathering Facts] ********************************************
    ok: [hostname]
    
  • This task uses the setup module internally to query the remote system for hundreds of pieces of information, including network interfaces, memory, disk space, and, most importantly, operating system details.

2. Fact Variables

The information collected during the "Gathering Facts" task is stored in a dictionary named ansible_facts. All variables starting with ansible_ (like ansible_os_family, ansible_distribution, ansible_default_ipv4) are readily available for use in any task that follows the fact-gathering step.

In your conditional example:

when: ansible_os_family == "RedHat"

Ansible looks up the value of the ansible_os_family key inside the ansible_facts dictionary that was automatically created, and uses that value to evaluate the condition. You don't need to explicitly call the setup module because it runs automatically.

Controlling Fact Gathering

If you wanted to manually control when facts are gathered (e.g., to speed up a very short playbook), you could disable the automatic gathering at the play level and then run the setup module manually later:

---
- name: Conditional demo
  hosts: all
  gather_facts: false # Turns off automatic fact gathering

  tasks:
    - name: Explicitly gather facts
      ansible.builtin.setup:
        filter: ansible_os_family # Only gather this specific fact to save time
    
    # ... your tasks can now use ansible_os_family ...


6. The PLAY RECAP ok= counter includes every single task that executed and did not fail. It combines the tasks that were marked ok (green) AND the tasks that were marked changed (yellow).



No comments:

Post a Comment

Building a Safer PostgreSQL CI/CD Pipeline with GitHub Actions: Dev → PR Review → Test Promotion

In my previous post, we explored a simple push-to-main deployment strategy . While functional, that model is not considered an industry best...