Ansible fact cycle condition judgment

Ansible fact

Ansible is actually a variable that ansible automatically detects on the managed host. The fact contains host related information that can be used like regular variables, conditions, loops in play, or any other statement that depends on the values collected from the managed host.

Some of the facts collected for managed hosts may include:

  • Host name
  • Kernel version
  • network interface
  • IP address
  • Operating system version
  • Various environmental variables
  • Number of CPU s
  • Memory provided or available
  • disk space available

With the help of facts, the state of the managed host can be easily retrieved and the operation to be performed can be determined according to the state. For example:

  • You can restart the server by running the conditional task based on the fact that it contains the current kernel version of the managed host
  • MySQL configuration files can be customized based on available memory through fact reporting
  • You can set the IPv4 address used in the configuration file based on the value of the fact

Usually, each play will automatically run the setup module to collect facts before performing the first task.

One way to view the facts collected for the managed host is to run a collection of facts and use the debug module to display ansible_ Short playbook of facts variable value.

The following table shows some facts that may be collected from managed nodes and can be used in playbook:
Example of Ansible fact

factvariable
Short host nameansible_facts['hostname']
Fully qualified domain nameansible_facts['fqdn']
IPv4 addressansible_facts['default_ipv4']['address']
Name list of all network interfacesansible_facts['interfaces']
/Size of dev/vda1 disk partitionansible_facts['devices']['vda']['partitions']['vda1']['size']
DNS server listansible_facts['dns']['nameservers']
Currently running kernel versionansible_facts['kernel']
[root@master xm]# cat fact.yml 
---
- hosts: 192.168.72.137
  tasks:
    - debug:
        var: ansible_facts


[root@master xm]# ansible-playbook fact.yml 

PLAY [192.168.72.137] ******************************************************************************************************************

TASK [Gathering Facts] *****************************************************************************************************************
Enter passphrase for key '/root/.ssh/id_rsa': 
ok: [192.168.72.137]

TASK [debug] ***************************************************************************************************************************
ok: [192.168.72.137] => {
    "ansible_facts": {
        "all_ipv4_addresses": [
            "192.168.72.137"
        ],
        "all_ipv6_addresses": [
            "fe80::7014:45ea:bce2:63"
        ],
        "ansible_local": {},
........

Replace facts with dynamic values

[root@master xm]# cat fact.yml 
---
- hosts: 192.168.72.137
  tasks:
    - debug:
            msg: >
              The IPv4 address of {{ ansible_facts['default_ipv4']['address'] }} is {{ ansible_facts['fqdn'] }}

[root@master xm]# ansible-playbook fact.yml 

PLAY [192.168.72.137] ******************************************************************************************************************

TASK [Gathering Facts] *****************************************************************************************************************
Enter passphrase for key '/root/.ssh/id_rsa': 
ok: [192.168.72.137]

TASK [debug] ***************************************************************************************************************************
ok: [192.168.72.137] => {
    "msg": "The IPv4 address of 192.168.72.137 is localhost.localdomain\n"
}

PLAY RECAP *****************************************************************************************************************************
192.168.72.137             : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

//You can use the setup module to display all the facts
[root@master xm]# ansible 192.168.72.137 -m setup
Enter passphrase for key '/root/.ssh/id_rsa': 
192.168.72.137 | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "192.168.72.137"
        ],
        "ansible_all_ipv6_addresses": [
            "fe80::7014:45ea:bce2:63"
        ],
        "ansible_apparmor": {
            "status": "disabled"
        },
        "ansible_architecture": "x86_64",
        "ansible_bios_date": "07/22/2020",
        "ansible_bios_version": "6.00",
........

Turn off fact collection

Closing facts can improve the running speed (gather_facts: no), or you can use the setup module to collect facts manually

[root@master xm]# cat fact.yml 
---
- hosts: 192.168.72.137
  gather_facts: no
  tasks:
    - setup:
    - debug:
        var:
          ansible_facts

[root@master xm]# ansible-playbook fact.yml 

PLAY [192.168.72.137] ******************************************************************************************************************

TASK [setup] ***************************************************************************************************************************
Enter passphrase for key '/root/.ssh/id_rsa': 
ok: [192.168.72.137]

TASK [debug] ***************************************************************************************************************************
ok: [192.168.72.137] => {
    "ansible_facts": {
        "all_ipv4_addresses": [
            "192.168.72.137"
        ],
        "all_ipv6_addresses": [
            "fe80::7014:45ea:bce2:63"
        ],
.......

Custom facts

In addition to using the facts captured by the system, we can also customize the facts and store them locally on each managed host. These facts are consolidated into a standard list of facts collected when the setup module runs on the managed host. They enable the managed host to provide arbitrary variables to Ansible to adjust the behavior of play.

Custom facts can be defined in static files. The format can be INI files or JSON. They can also be executable scripts that generate JSON output, just like dynamic manifest scripts.

With custom facts, we can define specific values for the managed host for play to populate the configuration file or run tasks conditionally. Dynamic custom facts allow you to programmatically determine the values of these facts at play runtime, and even determine which facts to provide.

By default, the setup module is from / etc / ansible / facts.com of each managed host Load custom facts in the files and scripts in the D directory. The name of each file or script must be in The end of fact can only be used. The dynamic custom fact script must output the fact in JSON format and must be an executable file.

The following is a static custom fact file written in INI format. The custom fact file in INI format contains the top-level value defined by a part, followed by the key value pair for the fact to be defined:

[root@master xm]# cat xxx.fact 
[bbc]
package = httpd
service = httpd
state = started
enabled = yes

[root@master xm]# cat fact.yml 
---
- hosts: 192.168.72.137
  vars:
    dir: /etc/ansible/facts.d
    file: xxx.fact
  tasks:
    - name: create dir
      file:
        state: directory
        recurse: yes
        path: "{{ dir }}"
    - name: create file
      copy:
        src: "{{ file }}"
        dest: "{{ dir }}"

[root@master xm]# ansible-playbook fact.yml 

PLAY [192.168.72.137] ******************************************************************************************************************

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

TASK [create dir] **********************************************************************************************************************
ok: [192.168.72.137]

TASK [create file] *********************************************************************************************************************
changed: [192.168.72.137]

PLAY RECAP *****************************************************************************************************************************
192.168.72.137             : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   


Magic variable

Some variables are not facts or configured through the setup module, but are also automatically set by Ansible. These magic variables can also be used to obtain information related to a specific managed host.

There are four most commonly used:

Magic variableexplain
hostvarsA variable that contains a managed host and can be used to get the value of a variable of another managed host. If facts have not been collected for the managed host, it will not contain the facts for that host
group_namesLists all groups to which the currently managed host belongs
groupsLists all groups and hosts in the list
inventory_hostnameContains the host name of the currently managed host configured in the manifest. For various reasons, it may be different from the host name reported in the fact

There are many other "magic variables". For more information, see the following link: https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable

loop

By using loops, the task of using the first mock exam is not necessary. For example, instead of writing five tasks to ensure that there are five users, they just need to write one task to iterate over a list of five users to ensure that they all exist.

Ansible supports iterative tasks on a set of projects using the loop keyword. Loops can be configured to repeat tasks using items in the list, the contents of files in the list, a generated sequence of numbers, or a more complex structure.

Simple cycle

[root@master xm]# cat sb.yml 
---
- hosts: 192.168.72.137
  tasks:
    - name:
      user:
        name: "{{ item }}"
        state: present
      loop:
        - xxx
        - zzz

[root@master xm]# ansible-playbook sb.yml 

PLAY [192.168.72.137] ******************************************************************************************************************

TASK [Gathering Facts] *****************************************************************************************************************
Enter passphrase for key '/root/.ssh/id_rsa': 
ok: [192.168.72.137]

TASK [user] ****************************************************************************************************************************
changed: [192.168.72.137] => (item=xxx)
changed: [192.168.72.137] => (item=zzz)

PLAY RECAP *****************************************************************************************************************************
192.168.72.137             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   


Circular hash or dictionary list

The loop list does not need to be a simple list of values. In the following example, each item in the list is actually a hash or dictionary. Each hash or dictionary in the example has two keys, name and groups. The value of each key in the current item loop variable can be passed through item Name and item Groups variable.

[root@master xm]# cat sb.yml 
---
- hosts: 192.168.72.137
  tasks:
    - name:
      user:
        name: "{{ item.name }}"
        groups: "{{ item.groups }}"
        state: present
      loop:
        - name: xm
          groups: xxx
        - name: slf
          groups: zzz

[root@master xm]# ansible-playbook sb.yml 

PLAY [192.168.72.137] ******************************************************************************************************************

TASK [Gathering Facts] *****************************************************************************************************************
Enter passphrase for key '/root/.ssh/id_rsa': 
ok: [192.168.72.137]

TASK [user] ****************************************************************************************************************************
changed: [192.168.72.137] => (item={'name': 'xm', 'groups': 'xxx'})
changed: [192.168.72.137] => (item={'name': 'slf', 'groups': 'zzz'})

PLAY RECAP *****************************************************************************************************************************
192.168.72.137             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   



Use the Register variable with Loop

[root@master xm]# cat sb.yml 
---
- hosts: 192.168.72.137
  tasks:
    - name:
      user:
        name: "{{ item.name }}"
        groups: "{{ item.groups }}"
        state: present
      loop:
        - name: xm
          groups: xxx
        - name: slf
          groups: zzz
      register: result
    - name:
      debug:
        var: result

[root@master xm]# ansible-playbook sb.yml 

PLAY [192.168.72.137] ******************************************************************************************************************

TASK [Gathering Facts] *****************************************************************************************************************
Enter passphrase for key '/root/.ssh/id_rsa': 
ok: [192.168.72.137]

TASK [user] ****************************************************************************************************************************
ok: [192.168.72.137] => (item={'name': 'xm', 'groups': 'xxx'})
ok: [192.168.72.137] => (item={'name': 'slf', 'groups': 'zzz'})

TASK [debug] ***************************************************************************************************************************
ok: [192.168.72.137] => {
    "result": {
        "changed": false,
        "msg": "All items completed",
        "results": [
.......

Conditional judgment

Ansible can use conditions to perform tasks or play when specific conditions are met. For example, a condition can be used to determine the available memory on the managed host before ansible installs or configures the service.

We can use conditions to distinguish different managed hosts and assign functional roles according to their conditions. Playbook variables, registered variables, and Ansible facts can all be tested by conditions. You can use operators that compare strings, numeric data, and Boolean values.

The following scenarios illustrate the use of conditions in Ansible:

  • You can define a hard limit (such as min_memory) in the variable and compare it with the available memory on the managed host.
  • Ansible can capture and evaluate the output of a command to determine whether a task has been completed before performing further operations. For example, if a program fails, it will pass through batch processing.
  • The Ansible fact can be used to determine the managed host network configuration and determine the template file to send (such as network binding or relay).
  • You can evaluate the number of CPU s to determine how to properly tune a Web server.
  • Compare the registered variables with predefined variables to determine whether the service has changed. For example, test MD5 of the service configuration file to verify and see if the service has changed.

Conditional task syntax

The when statement is used to run a task conditionally. It takes the condition to be tested as the value. If the conditions are met, run the task. If the conditions are not met, the task is skipped.

//If the value is true, it will run. If the value is false, it will be skipped
[root@master xm]# cat sb.yml 
---
- hosts: 192.168.72.137
  vars:
    slf: true
  tasks:
    - name:
      user:
        name: "{{ item.name }}"
        groups: "{{ item.groups }}"
        state: present
      loop:
        - name: xm
          groups: xxx
        - name: slf
          groups: zzz
      when: slf

Example conditions

operationExample
Equal to (value is string)ansible_machine == "x86_64"
Equal to (value is numeric)max_memory == 512
less thanmin_memory < 128
greater thanmin_memory > 256
Less than or equal tomin_memory <= 256
Greater than or equal tomin_memory >= 512
Not equal tomin_memory != 512
Variable existsmin_memory is defined
Variable does not existmin_memory is not defined
The boolean variable is true. 1. True or yes evaluates to truememory_available
The boolean variable is False. 0, False, or no evaluate to Falsenot memory_available
The value of the first variable exists as the value in the list of the second variableansible_distribution in supported_distros

Test multiple conditions

A when statement can be used to evaluate multiple conditions. Use the and and or keywords to combine conditions and use parentheses to group conditions.

If the conditional statement is satisfied when any of the conditions is true, the or statement should be used. For example, if the computer is running Red Hat Enterprise linux or Fedora, the following conditions are met:

when: ansible_distribution == "Redhat" or ansible_distribution == "Fedora"

When using the and operation, both conditions must be true to satisfy the entire conditional statement. For example, if the remote host is Red Hat Enterprise Linux 7 5 host, and the installed kernel is the specified version, the following conditions will be met:

when: ansible_distribution_version == "7.5" and ansible_kernel == "3.10.0-327.el7.x86_64"

The when keyword also supports the use of lists to describe condition lists. When you provide a list to the when keyword, all conditions are combined using the and operation. The following example demonstrates another way to combine multiple conditional statements using the and operator:

when:
  - ansible_distribution_version == "7.5"
  - ansible_kernel == "3.10.0-327.el7.x86_64"

This format improves readability, which is a key goal of writing Ansible Playbook well.

By grouping conditions with parentheses, you can express more complex conditional statements. For example, if the computer is running Red Hat Enterprise Linux 7 or Fedora 28, the following conditional statements are met. This example uses greater than characters so that the long condition can be divided into multiple lines in the playbook for easy reading.

when: >
  ( ansible_distribution == "Redhat" and
    ansible_distribution_major_version == "7" )
  or
  ( ansible_distribution == "Fedora" and
    ansible_distribution_major_version == "28" )

Combining loops and conditional tasks

---
- hosts: 192.168.72.137
  tasks:
    - name:
      yum:
        name: mariadb-server
        state: latest
      loop: "{{ ansible_mounts }}"
      when: item.mount == "/" and item.size_available > 10000000

[root@master xm]# ansible-playbook xx.yml 

PLAY [192.168.72.137] ******************************************************************************************************************

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

TASK [yum] *****************************************************************************************************************************
ok: [192.168.72.137] => (item={'mount': '/', 'device': '/dev/mapper/rhel-root', 'fstype': 'xfs', 'options': 'rw,seclabel,relatime,attr2,inode64,noquota', 'size_total': 50390917120, 'size_available': 47464321024, 'block_size': 4096, 'block_total': 12302470, 'block_available': 11587969, 'block_used': 714501, 'inode_total': 24616960, 'inode_available': 24552800, 'inode_used': 64160, 'uuid': '22c13e5c-701e-4552-94a1-520b0b285506'})
skipping: [192.168.72.137] => (item={'mount': '/boot', 'device': '/dev/nvme0n1p1', 'fstype': 'xfs', 'options': 'rw,seclabel,relatime,attr2,inode64,noquota', 'size_total': 1063256064, 'size_available': 876052480, 'block_size': 4096, 'block_total': 259584, 'block_available': 213880, 'block_used': 45704, 'inode_total': 524288, 'inode_available': 523987, 'inode_used': 301, 'uuid': 'cd44aec7-b06c-4df8-9fa6-187c3222f148'}) 

PLAY RECAP *****************************************************************************************************************************
192.168.72.137             : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

//When vsftpd is running, restart httpd
---
- hosts: 192.168.72.137
  tasks:
    - name:
      shell: systemctl status vsftpd
      ignore_errors: yes
      register: result

    - name:
      service:
        name: httpd
        state: restarted
      when: result.rc == 0

[root@master xm]# ansible-playbook xx.yml 

PLAY [192.168.72.137] ******************************************************************************************************************

TASK [Gathering Facts] *****************************************************************************************************************
Enter passphrase for key '/root/.ssh/id_rsa': 
ok: [192.168.72.137]

TASK [shell] ***************************************************************************************************************************
fatal: [192.168.72.137]: FAILED! => {"changed": true, "cmd": "systemctl status vsftpd", "delta": "0:00:00.009824", "end": "2021-07-25 06:32:27.841754", "msg": "non-zero return code", "rc": 4, "start": "2021-07-25 06:32:27.831930", "stderr": "Unit vsftpd.service could not be found.", "stderr_lines": ["Unit vsftpd.service could not be found."], "stdout": "", "stdout_lines": []}
...ignoring

TASK [service] *************************************************************************************************************************
skipping: [192.168.72.137]

PLAY RECAP *****************************************************************************************************************************
192.168.72.137             : ok=2    changed=1    unreachable=0    failed=0    skipped=1    rescued=0    ignored=1   


Keywords: Linux Operation & Maintenance ansible shell playbook

Added by alex_savin on Fri, 14 Jan 2022 09:26:23 +0200