Ansible Task Control

Ansible loops

The following loops are supported by Ansible:

  • Simple loops: A simple loop is a list of items that Ansible reads and iterate over. They are defined by providing a list of items to the with_items keyword. Consider the following snippet that uses the yum module twice in order to install two packages:

These two similar tasks using the yum module can be rewritten with a simple loop so that only one task is needed to install both packages:

The previous code can be replaced by having the packages inside an array called with the with_items keyword; the following playbook shows how to pass the array mail_services as an argument; the module will loop over the array to retrieve the name of the packages to install:

with_items example

 

  • List of hashes: When passing arrays as arguments, the array can be a list of hashes. The following snippet shows how a multidimensional array (an array with key-pair values) is passed to the user module in order to customize both   the name and the group:

 

  • Nested loops:  loops inside of loops called with the with_nested keyword. When nested loops are used, Ansible iterates over the first array as long as there are values in it. For example, when multiple MySQL privileges are
    required for multiple users, administrators can create a multidimensional array and invoke it with the with_nested keyword. The following snippet shows how to use the mysql_user module in a nested loop to grant two users a set of three privileges:

    In the previous example, the name of the users to create can also be an array defined in a variable. The following snippet shows how users are defined inside an array and passed as thefirst item of the array:

    The following table shows some additional types of loops supported by Ansible.
Loop   Keyword Description
with_file Takes a list of control node file names. item is set to the content of each file in sequence.
with_fileglob Takes a file name globbing pattern. item is set to each file in a directory on the control node that matches that pattern, in sequence, non-recursively.
with_sequence Generates a sequence of items in increasing numerical order. Can take start and end arguments which have a decimal, octal, or hexadecimal integer value.
with_random_choices Takes a list. item is set to one of the list items at random.

with_file example

 

To capture the output of a module that uses an array, the register keyword can be used with an array. Ansible will save the output in the variable. This can be useful if administrators want to review the result of the execution of a module. The following snippet shows how to register the content of the array after the iteration:

The echo will then contain the following information:

 

Conditionals
Ansible can use conditionals to execute tasks or plays when certain conditions are met. For example, a conditional can be used to determine the available memory on a managed host before Ansible installs or configures a service.

Ansible conditionals operators

Operator Example
Equal  "{{ 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"
Variable is set to 1, True, or yes  "{{ available_memory }}"
Variable is set to 0, False, or no  "not {{ available_memory }}"
Value is present in a variable or an array "{{ users }} in
users["db_admins"]"

 

When statement
To implement a conditional on an element, the when statement must be used, followed by the condition to test. When the statement is present, Ansible will evaluate it prior to executing the task. The following snippet shows a basic implementation of a when statement. Before creating the user db_admin, Ansible must ensure the managed host is part of the databases group:

Important
Notice the placement of the when statement. Because the when statement is not a module variable, it must be placed “outside” the module by being indented at the top level of the task. The when statement does not have to be at the top of the task. This breaks from the “top-down” ordering that is normal for Ansible.

when example

 

Multiple conditions
One when statement can be used to evaluate multiple values. To do so, conditionals can be combined with the and and or keywords or grouped with parentheses.

  • With the and operation, both conditions have to be true for the entire conditional statement to be met.

  • If a conditional statement should be met when either condition is true, then the or statement should be used.

  • More complex conditional statements can be clearly expressed through grouping conditions with parentheses to ensure that they are correctly interpreted.

 

Loops and conditionals can be combined. In the following example, the mariadb-server package will be installed by the yum module if there is a file system mounted on / with more than 300 MB free. The ansible_mounts fact is a list of dictionaries, each one representing facts about one mounted file system. The loop iterates over each dictionary in the list, and the conditional
statement is not met unless a dictionary is found representing a mounted file system where both conditions are true.

Important
When combining when with with_items, be aware that the when statement is
processed for each item.

Here is another example combining conditionals and registered variables. The following annotated playbook will restart the httpd service only if the postfix service is running.

1. Is Postfix running or not?
2. If it is not running and the command “fails”, do not stop processing
3. Saves information on the module’s result in a variable named result
4. Evaluates the output of the Postfix task. If the exit code of the systemctl command is 0, then Postfix is active and this task will restart the httpd service.

 

Using Booleans
Booleans are variables that take one of two possible values, which can be expressed as:
• True or Yes or 1
• False or No or 0

  • Booleans can be used as a simple switch to enable or disable tasks. To enable the task:

  • To disable the task:

 

Exercise: Constructing Flow Control

Create a task file named configure_database.yml. This will define the tasks to install the extra packages, update /etc/my.cnf from a copy stored on a web site, and start mariadb on the managed hosts. The include file can and will use the variables you defined in the playbook.yml file and inventory. The get_url module will need to set force=yes so that the my.cnf file is updated even if it already exists on the managed host, and will need to set correct permissions as well as SELinux contexts on the /etc/my.cnf file.  The file should read as follows:

In the same directory, create the playbook.yml playbook. Define a list variable, db_users, that consists of a list of two users, db_admin and db_user. Add a configure_database_path variable set to the file /etc/my.cnf. Create a task that uses a loop to create the users only if the managed host belongs to the databases host group.  In the playbook, add a task that uses the db_package variable to install the database software, only if the variable has been defined. Create a task to do basic configuration of the database. The task will run only when configure_database_path is defined. This task should include the configure_database.yml task file and define a local array extra_packages which will be used to specify additional packages needed for this configuration. Set that list variable to include a list of three packages: mariadb-bench, mariadb-libs, and mariadb-test.

The final playbook.yml  should now read in its entirety:

Run the playbook to install and configure the database on the managed hosts.

The output confirms the task file has been successfully included and executed.

Manually verify that the necessary packages have been installed on servera, that the /etc/my.cnf file is in place with the correct permissions, and that the two users have been created. Use an ad hoc command from workstation to servera to confirm the packages have been installed.

Confirm the my.cnf file has been successfully copied under /etc/.

Confirm the two users have been created.