1. Management facts
1.1Ansible facts
Is 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.
Get facts based on module
[root@master project]# ansible all -m setup / / get the controlled machine facts [root@master project]# ansible all -m setup | less / / use this command to see the front of the fact
Get facts based on playbook
--- - hosts: 192.168.8.132 tasks: - name: test debug: var: ansible_facts['default_ipv4']['address'] //Get the default IPv4 address fact
[root@master project]# ansible-playbook playbook/test.yml PLAY [192.168.8.132] *************************************************************************** TASK [Gathering Facts] ************************************************************************* ok: [192.168.8.132] TASK [test] ************************************************************************************ ok: [192.168.8.132] => { "ansible_facts['default_ipv4']['address']": "192.168.8.132" } PLAY RECAP ************************************************************************************* 192.168.8.132 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [root@master project]#
The following table shows some facts that may be collected from managed nodes and can be used in playbook:
Example of Ansible fact
fact | variable |
---|---|
Short host name | ansible_facts['hostname'] |
Fully qualified domain name | ansible_facts['fqdn'] |
IPv4 address | ansible_facts['default_ipv4']['address'] |
Name list of all network interfaces | ansible_facts['interfaces'] |
/Size of dev/vda1 disk partition | ansible_facts['devices']['vda']['partitions']['vda1']['size'] |
DNS server list | ansible_facts['dns']['nameservers'] |
Currently running kernel version | ansible_facts['kernel'] |
If the value of a variable is of hash / dictionary type, two syntax can be used to get its value. For example:
- ansible_facts['default_ipv4']['address'] can also be written as ansible_facts.default_ipv4.address
- ansible_facts['dns']['nameservers'] can also be written as ansible_facts.dns.nameservers
When using a fact in play, Ansible dynamically replaces the variable name of the fact with the corresponding value:
//Gets the default ipvd address with host name fqdn --- - hosts: 192.168.8.132 tasks: - name: test debug: msg: > The host named {{ ansible_facts['fqdn'] }} of ip is {{ ansible_facts['default_ipv4']['address'] }}
[root@master project]# ansible-playbook playbook/test.yml PLAY [192.168.8.132] *************************************************************************** TASK [Gathering Facts] ************************************************************************* ok: [192.168.8.132] TASK [test] ************************************************************************************ ok: [192.168.8.132] => { "msg": "The host named localhost.localdomain of ip is 192.168.8.132 \n" } PLAY RECAP ************************************************************************************* 192.168.8.132 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Insert in the [default] section of the Ansible configuration file_ facts_ as_ Set the vars parameter to False to turn off the old naming system. The default setting is currently True.
# inject_facts_as_vars = True
1.2 close fact collection
Sometimes we don't want to collect facts for play. The reasons for this may be:
- Not prepared to use any facts
- Hope to speed up play
- You want to reduce the load caused by play on the managed host
- The managed host cannot run the setup module for some reason
- You need to install some prerequisite software before collecting facts
For the above reasons, we may want to turn off the fact collection function permanently or temporarily. To disable the fact collection function for play, you can turn gather_ Set the facts keyword to no:
--- - name: gather_facts hosts: 192.168.8.132 gather_facts: no tasks: - name: get gather_facts setup: - name: debug debug: var: ansible_facts
1.3 creating 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:
//Create custom facts on the controlled machine [root@localhost ~]# mkdir -p /etc/ansible/facts.d [root@localhost ~]# cd /etc/ansible/facts.d/ [root@localhost facts.d]# vim test.fact [root@localhost facts.d]# cat test.fact [ckages] web_package = httpd db_package = mariadb-server [users] user1 = joe user2 = janepackages] [root@localhost facts.d]#
//Verify the effect on the host
...skipping... "ansible_local": { "test": { "ckages": { "db_package": "mariadb-server", "web_package": "httpd" }, "users": { "user1": "joe", "user2": "janepackages]" } } }, "ansible_lsb": {}, "ansible_lvm": {
2. Preparation of conditions and tasks
2.1 iterative tasks using loops
By using loops, the task of using the first mock exam is not necessary. For example, instead of writing three tasks to ensure that there are three users, they just need to write one task to iterate over a list of three 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.
2.2 simple cycle
A simple loop iterates over a set of projects. Add the loop keyword to the task and take the list of items that should be iterated by it as the value. The loop variable item holds the values used during each iteration.
Consider the following code snippet, which uses the user module three times to create three users:
- hosts: 192.168.8.132 gather_facts: no tasks: - name: create user user: name: pyd1 state: present - name: create user user: name: pyd2 state: present - name: create user user: name: pyd3 state: present
These two tasks can be rewritten to create three users using a simple loop;
--- - hosts: 192.168.8.132 gather_facts: no tasks: - name: create user user: name: '{{ item }}' state: present loop: - pyd1 - pyd2 - pyd3
[root@localhost ~]# id pyd1 uid=1002(pyd1) gid=1002(pyd1) group=1002(pyd1) [root@localhost ~]# id pyd2 uid=1003(pyd2) gid=1003(pyd2) group=1003(pyd2) [root@localhost ~]# id pyd3 uid=1004(pyd3) gid=1004(pyd3) group=1004(pyd3) [root@localhost ~]#
You can provide the list used by loop through a variable. In the following example, the variable vars / users YML contains a list of services that need to be running.
--- - hosts: 192.168.8.132 gather_facts: no vars_files: - vars/users.yml tasks: - name: create user user: name: '{{ item }}' state: present loop: "{{ users }}" [root@master project]# cat playbook/vars/users.yml users: - pyd4 - pyd5 - pyd6 [root@master project]#
[root@localhost ~]# id pyd4 uid=1005(pyd4) gid=1005(pyd4) group=1005(pyd4) [root@localhost ~]# id pyd5 uid=1006(pyd5) gid=1006(pyd5) group=1006(pyd5) [root@localhost ~]# id pyd6 uid=1007(pyd6) gid=1007(pyd6) group=1007(pyd6) [root@localhost ~]#
2.3 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 uid. The value of each key in the current item loop variable can be passed through item Name and item Uid variable to retrieve.
--- - hosts: 192.168.8.132 gather_facts: no vars_files: - vars/users.yml tasks: - name: create user user: name: '{{ item.name }}' uid: '{{ item.uid }}' state: present loop: "{{ users }}" [root@master project]# cat playbook/vars/users.yml users: - name: pyd8 uid: 2200 - name: pyd9 uid: 2500 - name: pyd10 uid: 3000 [root@master project]#
[root@localhost ~]# id pyd8 uid=2200(pyd8) gid=2200(pyd8) group=2200(pyd8) [root@localhost ~]# id pyd9 uid=2500(pyd9) gid=1500(pyd9) group=1500(pyd9) [root@localhost ~]# id pyd10 uid=3000(pyd10) gid=2000(pyd10) group=2000(pyd10) [root@localhost ~]#
2.4 bad keywords of earlier styles
In Ansible2 Before 5, most playbooks used different loop syntax. Multiple cyclic keywords are provided with the prefix whth_, Followed by the name of the Ansible lookup plug-in. This circular syntax is common in existing playbooks, but may be deprecated at some point in the future.
Ansible loop of earlier style
Bad keyword | describe |
---|---|
with_items | The behavior is the same as the loop keyword of a simple list, such as a string list or a hash / dictionary list. But different from loop, if it is with_items provides a list of lists, They will be flattened into a single level list. The loop variable item holds the list items used during each iteration. |
with_file | This keyword requires a list of control node file names. The cyclic variable item saves the contents of the corresponding file in the file list during each iteration |
with_sequence | This keyword does not require a list, but requires parameters to generate a list of values from a sequence of numbers. The loop variable item saves the value of a generated item in the generated sequence during each iteration. |
With in playbook_ An example of items is as follows:
--- - hosts: 192.168.8.132 gather_facts: no vars_files: - vars/users.yml tasks: - name: create user user: name: '{{ item.name }}' uid: '{{ item.uid }}' state: present with_items: "{{ users }}"
From ansible2 Starting with 5, it is recommended to write a loop using the loop keyword.
2.5 use Register variable with Loop
The register keyword can also capture the output of a circular task. The following code snippet shows the structure of the register variable in a circular task:
--- - hosts: 192.168.8.132 gather_facts: no tasks: - name: test command: 'echo hello {{ item }},how are you.' loop: - tom - Bob - alice register: result //Register echo_item variable - debug: var: result //echo_ The contents of the item variable are displayed on the screen
ok: [192.168.8.132] => { "result": { "changed": true, "msg": "All items completed", "results": [ { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "ansible_loop_var": "item", "changed": true, "cmd": [ "echo", "hello", "tom,how", "are", "you."
2.6 running tasks conditionally
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.
2.6.1 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.
One of the simplest conditions that can be tested is whether a boolean variable is True or False. The when statement in the following example causes the task to run only when power is ` True:
--- - hosts: 192.168.8.132 gather_facts: no vars_files: - vars/users.yml vars: power: False tasks: - name: create user user: name: '{{ item.name }}' uid: '{{ item.uid }}' state: present loop: '{{ users }}' when: power [root@master project]# ansible-playbook playbook/usrs.yml PLAY [192.168.8.132] *************************************************************************** TASK [create user] ***************************************************************************** skipping: [192.168.8.132] => (item={'name': 'pyd8', 'uid': 2200}) skipping: [192.168.8.132] => (item={'name': 'pyd9', 'uid': 2500}) skipping: [192.168.8.132] => (item={'name': 'pyd10', 'uid': 3000}) PLAY RECAP ************************************************************************************* 192.168.8.132 : ok=0 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
--- - hosts: 192.168.8.132 gather_facts: no vars_files: - vars/users.yml vars: power: True tasks: - name: create user user: name: '{{ item.name }}' uid: '{{ item.uid }}' state: absent loop: '{{ users }}' when: power [root@master project]# ansible-playbook playbook/usrs.yml PLAY [192.168.8.132] *************************************************************************** TASK [create user] ***************************************************************************** changed: [192.168.8.132] => (item={'name': 'pyd8', 'uid': 2200}) changed: [192.168.8.132] => (item={'name': 'pyd9', 'uid': 2500}) changed: [192.168.8.132] => (item={'name': 'pyd10', 'uid': 3000}) PLAY RECAP ************************************************************************************* 192.168.8.132 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
--- - hosts: 192.168.8.132 gather_facts: no vars_files: - vars/users.yml vars: power: True tasks: - name: create user user: name: '{{ item.name }}' uid: '{{ item.uid }}' state: present loop: '{{ users }}' when: '"{{ item.name }}" == "pyd7"' //When the condition is pyd8, I execute this command. If not, I skip it directly
[root@master project]# ansible-playbook playbook/usrs.yml PLAY [192.168.8.132] *************************************************************************** TASK [create user] ***************************************************************************** [WARNING]: conditional statements should not include jinja2 templating delimiters such as {{ }} or {% %}. Found: "{{ item.name }}" == "pyd8" changed: [192.168.8.132] => (item={'name': 'pyd8', 'uid': 2200}) skipping: [192.168.8.132] => (item={'name': 'pyd9', 'uid': 2500}) skipping: [192.168.8.132] => (item={'name': 'pyd10', 'uid': 3000}) PLAY RECAP ************************************************************************************* 192.168.8.132 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [root@master project]#
The following example tests my_ Whether the service variable has a value. If there is a value, it will be my_ The value of service is used as the name of the package to install. If my is not defined_ Service variable, the task is skipped and no error is displayed.
--- - name: test httpd is Defined Demo hosts: httpd vars: my_service: httpd tasks: - name: '{{ my_service }} package is installed' dnf: name: '{{ my_service }}' when: my_service is defined
[root@master project]# ansible-playbook playbook/test.yml PLAY [test httpd is Defined Demo] ************************************************************** TASK [Gathering Facts] ************************************************************************* ok: [192.168.8.132] TASK [httpd package is installed] ************************************************************** changed: [192.168.8.132] PLAY RECAP ************************************************************************************* 192.168.8.132 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
The following table shows some operations that can be used when processing conditions:
Example conditions
operation | Example |
---|---|
Equal to (value is string) | ansible_machine == "x86_64" |
Equal to (value is numeric) | max_memory == 512 |
less than | min_memory < 128 |
greater than | min_memory > 256 |
Less than or equal to | min_memory <= 256 |
Greater than or equal to | min_memory >= 512 |
Not equal to | min_memory != 512 |
Variable exists | min_memory is defined |
Variable does not exist | min_memory is not defined |
The boolean variable is true. 1. True or yes evaluates to true | memory_available |
The boolean variable is False. 0, False, or no evaluate to False | not memory_available |
The value of the first variable exists as the value in the list of the second variable | ansible_distribution in supported_distros |