Ansible 101: #007 - Return values

Hello,

the Ansible Starter 101 continues. We have already reached part 7, which deals with task return values.

Now you're probably asking yourself: What the hell are return values and why do I need them?

Briefly summarized: When a task is executed, it produces a return value that contains information about the task result. We always need return values when we want to continue working in a task with the result of a previous task.


An example

As always, I will illustrate this with a small example. Let's say we want to check if a certain file exists on the remote system. We can check this with the "stat" module:

- name: Example for return values
  hosts: webservers
  tasks:
    - name: check if hosts file is there
      ansible.builtin.stat:
        path: /etc/hosts

When we now run this playbook, the result is initially very unspectacular:

PLAY [Example for return values] ****************************************************************************

TASK [Gathering Facts] ****************************************************************************
ok: [ansible-guide-1]
ok: [ansible-guide-2]

TASK [check if file is there] ****************************************************************************
ok: [ansible-guide-1]
ok: [ansible-guide-2]

PLAY RECAP ****************************************************************************
ansible-guide-1                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 
ansible-guide-2                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

As we can see, both tasks worked and returned the status "ok". And what do we get? Nothing so far. The "stat" module only collects statistics on a file (or path) and would return "ok" even if the file did not exist.

If we want to use the information collected for this file, we need to use the return value of the task. To record this, there is the "register" task parameter:

- name: Example for return Values
  hosts: webservers
  tasks:
    - name: check if hosts file is there
      ansible.builtin.stat:
        path: /etc/hosts
      register: my_var_with_return_value

This tells Ansible to store the return value of the "check if hosts file is there" task in a variable called "my_var_with_return_value". Now, the return value of each module contains different fields. However, we can find them in the official Ansible documentation for each module. For the stat module it is here:

https://docs.ansible.com/ansible/devel/collections/ansible/builtin/stat_module.html

The return value is stored in a dictionary. We have not covered this in detail yet, but it should be enough for now. To check if our file exists, we do the following:

- name: Example for return Values
  hosts: webservers
  tasks:
    - name: check if hosts file is there
      ansible.builtin.stat:
        path: /etc/hosts
      register: my_var_with_return_value

    - name: debug output
      ansible.builtin.debug:
        msg: "File exists is: {{ my_var_with_return_value.stat.exists }}"

If we run this playbook, we will get the following output:

PLAY [Example for return values] ****************************************************************************

TASK [Gathering Facts] ****************************************************************************
ok: [ansible-guide-1]
ok: [ansible-guide-2]

TASK [check if hosts file is there] ****************************************************************************
ok: [ansible-guide-1]
ok: [ansible-guide-2]

TASK [debug output] ****************************************************************************
ok: [ansible-guide-1] => {
    "msg": "File exists is: True"
}
ok: [ansible-guide-2] => {
    "msg": "File exists is: True"
}

PLAY RECAP ****************************************************************************
ansible-guide-1                  : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 
ansible-guide-2                  : ok=3    changed=0    unreachable=0    failed=0   2skipped=0    rescued=0    ignored=0 

The file “/etc/hosts” therefore exists on both of our test web servers.

Another example

In the same way, we could display the output of a shell command that we run through the "command" module:

- name: Example for return values
  hosts: ansible-guide-1
  tasks:
    - name: get os version
      ansible.builtin.command: "uname -a"
      register: my_var_with_return_value

    - name: debug output
      ansible.builtin.debug:
        msg: "{{ my_var_with_return_value.stdout }}"
PLAY [Beispiel mit Return Values] ****************************************************************************

TASK [Gathering Facts] ****************************************************************************
ok: [ansible-guide-1]

TASK [get os version] ****************************************************************************
changed: [ansible-guide-1]

TASK [debug output] ****************************************************************************
ok: [ansible-guide-1] => {
    "msg": ""msg": "NAME=\"Ubuntu\"\nVERSION=\"20.04.2 LTS (Focal Fossa)\"\nID=ubuntu\nID_LIKE=debian\nPRETTY_NAME=\"Ubuntu 20.04.2 LTS\"\nVERSION_ID=\"20.04\"\nHOME_URL=\"https://www.ubuntu.com/\"\nSUPPORT_URL=\"https://help.ubuntu.com/\"\nBUG_REPORT_URL=\"https://bugs.launchpad.net/ubuntu/\"\nPRIVACY_POLICY_URL=\"https://www.ubuntu.com/legal/terms-and-policies/privacy-policy\"\nVERSION_CODENAME=focal\nUBUNTU_CODENAME=focal"
}

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

So we run another task and store the return value in a variable using "register". Then we look at the structure of the return value:

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/command_module.html

Under "Return Values" we see that there is the field "stdout", i.e. the standard output of the called shell command. We will output this field again with the "debug" module.


Standard fields

In addition to the module-specific fields, there are some standard fields in every return value dictionary. Here are some examples:

Modified: Contains information as a Boolean (true/false) whether the task has returned the status "changed".

skipped: Contains information about whether the task was skipped.

failed: Hopefully false. Contains information about whether the task failed.

The full list can be found here:

https://docs.ansible.com/ansible/2.5/reference_appendices/common_return_values.html

What comes next

In the next part I would like to show you conditionals, which are conditions we can link to the execution of our tasks.

Best wishes and see you soon!

Mow