Pages

Friday, 22 November 2019

EX294: Ansible Facts

0 Basic idea

Before running any task on a managed node, ansible first tries to detect the state of the targeted machine. What's detected is called a "fact", all the "fact" collected is called "facts". Some common facts are the hostname, OS type, IP addresses, disks, and file systems. 

As a result, the following tasks can run conditionally based on these "facts". For example, a task may run differently on a Linux node and a Solaris node.

1 module "setup"

In Ansible, every task is implemented by a module. Collecting facts is not an exception. The module used by Ansible to collect facts is named "setup". By default, before running any playbook ansible-playbook runs the "setup" module first. So "setup" can be the most common task at all.

So we can always see ansible-playbook printing the following message.

TASK [Gathering Facts] ****************************

Now that "setup" is a module, we can also run it by ansible command.

$ ansible localhost -m setup
localhost | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "192.168.100.1",
            "192.168.42.1",
            "192.168.122.1",
            "192.168.0.31",
            "192.168.121.1"
        ],
...

The output can be very long depending on the configuration of the managed node.
From the output, we can at least know that the collected facts are saved as a python dictionary type variable called "ansible_facts".

2. How to use facts?

As facts are saved as a variable named "ansible_facts", it can be used like any other variable in a playbook.

2.1 print the facts

Sometimes, printing facts is important for us to monitor the managed nodes. We can use "debug" module to print out any fact(s) collected.

---
- hosts: localhost
  tasks:
      - name: print firt IP address
        debug: var=ansible_facts.all_ipv4_addresses[0]

      - name: print hostname
        debug: var=ansible_facts.hostname

      - name: print CPU cores
        debug: var=ansible_facts.processor_cores

Note: the var parameter of the debug module already runs in JinJa2 context and has an implicit {{ }} wrapping, so no JinJa2 delimiters here.

$ ansible-playbook playbook.yml

PLAY [localhost] *******************************************************************************************

TASK [Gathering Facts] *************************************************************************************
ok: [localhost]

TASK [print firt IP address] *******************************************************************************
ok: [localhost] => {
    "ansible_facts.all_ipv4_addresses[0]": "192.168.100.1"
}

TASK [print hostname] **************************************************************************************
ok: [localhost] => {
    "ansible_facts.hostname": "cf-31"
}

TASK [print CPU cores] *************************************************************************************
ok: [localhost] => {
    "ansible_facts.processor_cores": "2"
}

PLAY RECAP *************************************************************************************************
localhost                  : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

2.2 conditionally run tasks based on facts

In this example, the first task only runs on CentOS 7.7 nodes.
- hosts: home
  tasks:
      - name: "run this task only on CentOS 7.7"
        shell: "cat /etc/os-release"
        register: r
        when: "'CentOS' in ansible_facts.distribution and '7.7' in ansible_facts.distribution_version"

      - debug: var=r.stdout

Note: "when" runs in JinJa2 context and has an implicit {{}} wrapping, so no JinJa2 delimiters here.

No comments:

Post a Comment