Working with different Ansible operators

In this section we will learn about different operators we can use with Ansible playbooks to perform different tasks. For mathematical operations we can use Arithmetic operators, similarly for comparison we can use comparison and test operators and so on. We will discuss about these individual operators in detail.

 

Arithmetic Operators

In this section we will use different arithmetic operators to perform some mathematical calculation inside the ansible playbook. We will use the common arithmetic operators which we would use any where inside the Jinja2 syntax for variable.

List of arithmetic operators

ExpressionDefinition
+Adds two objects together. Usually the objects are numbers, but if both are strings or lists, you can concatenate them this way.
-Subtract the second number from the first one. {{ 3 - 2 }} is 1.
/Divide two numbers. The return value will be a floating point number. {{ 1 / 2 }} is {{ 0.5 }}.
//Divide two numbers and return the truncated integer result. {{ 20 // 7 }} is 2.
%Calculate the remainder of an integer division. {{ 11 % 7 }} is 4.
*Multiply the left operand with the right one. {{ 2 * 2 }} would return 4.
**Raise the left operand to the power of the right operand. {{ 2**3 }} would return 8.

 

In this sample playbook arithmetic_operators.yml I am performing different kinds of arithmetic operations:

---
 - name: Perform arithmetic operations
   hosts: localhost
   gather_facts: false
   vars:
     num1: 30
     num2: 15
   tasks:
     - name: "Calculations"
       debug:
         msg:
          - "The value of num1 is: {{ num1 }}"
          - "The value of num2 is: {{ num2 }}"
          - "Multiply num1 and num2: {{ num1*num2 }}"
          - "Add num1 and num2: {{ num1+num2 }}"
          - "Subtract num2 from num1: {{ num1-num2 }}"
          - "Divide num1 by num2: {{ num1/num2 }}"
          - "Check remainder: {{ num1%num2 }}"

Let us execute the playbook:

[ansible@controller ~]$ ansible-playbook arithmetic_operators.yml

PLAY [Perform arithmetic operations] *************************************************************************************

TASK [Calculations] ******************************************************************************************************
ok: [localhost] => {
    "msg": [
        "The value of num1 is: 30",
        "The value of num2 is: 15",
        "Multiply num1 and num2: 450",
        "Add num1 and num2: 45",
        "Subtract num2 from num1: 15",
        "Divide num1 by num2: 2.0",
        "Check remaininder: 0"
    ]
}

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

So you can see that we had defined two numerical variables on which we have performed all kinds of different mathematical operations such as addition, subtract, multiple, divide etc and it can't get any simpler.

 

Comparison Operator

Comparisons are used in many places with Ansible. Task conditionals are comparisons. Jinja2 control structures often use comparisons. Some filters use comparisons, as well. To master Ansible's usage of Jinja2, it is important to understand which comparisons are available. Like most languages, Jinja2 comes equipped with the standard set of comparison expressions you would expect, which will render a Boolean true or false.

The expressions in Jinja2 are as follows:

ExpressionDefinition
==Compares two objects for equality
!=Compares two objects for inequality
>True if the left-hand side is greater than the right-hand side
<True if the left-hand side is less than the right- hand side
>=True if the left-hand side is greater than or equal to the right-hand side
<=True if the left-hand side is less than or equal to the right-hand side

In this section I have created a sample playbook comparison-playbook.yml in which I will use these comparison operators using two variables

---
 - name: Comparison Operators for Ansible
   hosts: localhost
   gather_facts: false
   vars:
     num1: 10
     num2: 20
   tasks:
     - debug:
         msg:
          - "The value of num1 is {{ num1 }} and num2 {{ num2 }}"
          - "num1 is equal to num2: {{ num1==num2 }}"
          - "num1 is not equal to num2: {{ num1 != num2 }}"
          - "num1 greater than num2: {{ num1 > num2 }}"
          - "num1 is less than num2: {{ num1 < num2 }}" - "num1 is greater than or equal to num2: {{ num1 >= num2 }}"
          - "num1 is less than or equal to num2: {{ num1 >= num2 }}"

Let us check the output from this playbook execution:

[ansible@controller ~]$ ansible-playbook comparison-playbook.yml

PLAY [Comparison Operators for Ansible] **********************************************************************************

TASK [debug] *************************************************************************************************************
ok: [localhost] => {
    "msg": [
        "The value of num1 is 10 and num2 20",
        "num1 is equal to num2: False",
        "num1 is not equal to num2: True",
        "num1 greater than num2: False",
        "num1 is less than num2: True",
        "num1 is greater than or equal to num2: False",
        "num1 is less than or equal to num2: False"
    ]
}

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

From the output you can check the status of the comparison operator result. Based on the comparison check we get return value as TRUE or FALSE

 

Test operators

A test in Jinja2 is used to see if a value is something. In fact, the is operator is used to initiate a test. Tests are used any place a Boolean result is desired, such as with if expressions and task conditionals. There are many built-in tests, but we'll highlight a few of the particularly useful ones:

  • defined: Returns true if the variable is defined
  • undefined: The opposite of defined
  • none: Returns true if the variable is defined, but the value is none
  • even: Returns true if the number is divisible by 2
  • odd: Returns true if the number is not divisible by 2
  • To test if a value is not something, simply use is not.

In this sample playbook test_operators.yml I am using different kinds of test operators verify different scenarios:

---
 - name: Test operators
   hosts: localhost
   gather_facts: false
   vars:
     list1: [this, is, a, sample, text]
     val1: "this"
     val2: "THIS"
     my_file_path: '/home/ansible/test_operators.yml'
     my_dir_path: '/home/ansible'
     my_link_path: '/tmp/dummy'
     my_name: 'Deepak Prasad'
     num1: 20
   tasks:
     - name: Validate test operators
       debug:
         msg:
          - "List contains {{ list1 }}"
          - "val1 is in list1: {{ val1 in list1 }}"
          - "val2 is in list1: {{ val2 in list1 }}"
          - "val2 is not in list1: {{ val2 not in list1 }}"
          - "num1 is defined: {{ num1 is defined }}"
          - "num2 is defined: {{ num2 is defined }}"
          - "num2 is undefined: {{ num2 is undefined }}"
          - "My name is lower case: {{ my_name is lower }}"
          - "num1 is even: {{ num1 is even }}"
          - "num1 is odd: {{ num1 is odd }}"
          - "Does file exists: {{ my_file_path is exists }}"
          - "Does directory exists: {{ my_dir_path is exists }}"
          - "Is {{ my_file_path }} a file: {{ my_file_path is file }}"
          - "Is {{ my_dir_path }} a directory: {{ my_dir_path is directory }}"
          - "Is {{ my_link_path }} a symbolic link: {{ my_link_path is link }}"

I don't think I need to explain the playbook as it should be pretty clear. We are trying to verify multiple scenarios with different test operators. Each one of these tests would return TRUE or FALSE based on the comparison result.

Let us execute this playbook:

[ansible@controller ~]$ ansible-playbook test_operators.yml

PLAY [Test operators] ****************************************************************************************************

TASK [Validate test operators] *******************************************************************************************
ok: [localhost] => {
    "msg": [
        "List contains ['this', 'is', 'a', 'sample', 'text']",
        "val1 is in list1: True",
        "val2 is in list1: False",
        "val2 is not in list1: True",
        "num1 is defined: True",
        "num2 is defined: False",
        "num2 is undefined: True",
        "My name is lower case: False",
        "num1 is even: True",
        "num1 is odd: False",
        "Does file exists: True",
        "Does directory exists: True",
        "Is /home/ansible/test_operators.yml is a file: True",
        "Is /home/ansible is directory: True",
        "Is /tmp/dummy is a symbolic link: True"
    ]
}

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

 

Logical Operators

Control structures within any programming language provide a way of defining paths for an executing program to flow through based on a condition. In addition to conditional logic, control structures also provide us with a way of repeating like tasks without duplicating code. This is commonly known as conditional logic and looping, respectively. Jinja provides us with a set of operators that allow us to loop or conditionally execute code. In this section, we will discuss conditional logic specifically and learn how to leverage it within the context of Jinja.

Conditional logic in code form might look something like the following (Python code):

# Python Conditional Logic Example
x = 0
if x == 0:
    print “Hello X is 0”
else:
    print “Hello X is NOT 0”

This Python code presents a simplistic example of conditional logic. It simply says that if x is equal to 0, then execute the print statement telling the user so. Within Jinja, we can implement a very similar set of logical operators. The only real difference in context is that within Jinja, all control structures and conditionalization are wrapped within {% %} tags.

Below is a similar implementation in Jinja

{% if condition %}
    execute_this
{% elif condition2 %}
    execute_this
{% else %}
    execute_this
{% endif %}

As we can see, the Jinja implementation also gives us the optional else-if statement. This provides us with additional capabilities when it comes to implementing conditional logic.

In this sample playbook we check the variable using if condition and if found we print something or else print something else using the logical operators:

---
 - name: Logical Operator
   hosts: server2
   gather_facts: false
   vars:
     hello: true
     say_something: "{% if hello == true %} Hello Jinja {% else %} Goodbye Ansible {% endif %}"
   tasks:
     - debug:
         msg:
          - "{{ say_something }}"

Let us execute this playbook:

[ansible@controller ~]$ ansible-playbook conditional-operator.yml

PLAY [Logical Operator] ********************************************************************************************

TASK [debug] *******************************************************************************************************
ok: [server2] => {
    "msg": [
        " Hello Jinja "
    ]
}

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

 

Similarly let us check some other logical operators in our next playbook logical-operator.yml. In this playbook we have combined test operators with logical "and" and "or" operators.

---
 - name: Logical Operators
   hosts: localhost
   gather_facts: false
   vars:
     x: 10
     y: 15
     list: [10,20,30]
   tasks:
     - debug:
         msg:
          - "The value of x is {{ x }} and the value of y is {{ y }}"
          - "Our list contains: {{ list }}"
          - "x < y and x in list: {{ x < y and x in list }}" - "x > y and x in list: {{ x > y and x in list }}"
          - "x in p or y in list: {{ x in list or y in list }}"

Let us execute this playbook:

[ansible@controller ~]$ ansible-playbook logical-operator.yml

PLAY [Logical Operators] *******************************************************************************************

TASK [debug] *******************************************************************************************************
ok: [localhost] => {
    "msg": [
        "The value of x is 10 and the value of y is 15",
        "Our list contains: [10, 20, 30]",
        "x < y and x in list: True", "x > y and x in list: False",
        "x in p or y in list: True"
    ]
}

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

Here we are comparing the values of x and y variable and also using and and or condition to check if respective variable exists in the list.

 

What's Next

Next in our Ansible Tutorial we will learn about different conditional statement which we can use with Ansible

 

Leave a Comment

Please use shortcodes <pre class=comments>your code</pre> for syntax highlighting when adding code.