Operating loop results with dict or array

The scenario is that we have two different loops, and we want to operate their result together with a with_nested. So, here we have two loops:

- name: Get home files with names from 1 to 4 
  shell: "ls /home/ansible/{{ item }}"
  ignore_errors: yes
  register: files_1_4
  with_items:
    - 1
    - 2
    - 3
    - 4 #doesn't exist to do the example more interesting

- name: Get home files with names from 5 to 8
  shell: "ls /home/ansible/{{ item }}"
  ignore_errors: yes
  register: files_5_8
  with_items:
    - 5
    - 6
    - 7
    - 8

If you want to operate this together you will need to create a dict (or array) in order to be able to operate them.

So, what we should do is use set_fact to create this dict:

- name: Creating the dict with files that exists
  set_fact:
    existing_files_1_4: "{{ existing_files_1_4|default([]) + [ {'name': item.item } ] }}"
  when: ( item.rc == 0 ) # Just as example
  with_items:
    - "{{ files_1_4.results }}"

- name: Creating the dict with files that exists
  set_fact: 
    existing_files_5_8: "{{ existing_files_5_8|default([]) + [ {'name': item.item } ] }}"
  when: ( item.rc == 0 ) # Just as example
  with_items:
    - "{{ files_5_8.results }}"

And now we’re able to use with_nested with both items. Take into account that we were saving item.item, but you could save item.stdout_lines for example.

- name: Echo result
  shell: "echo {{ item.0.name }} {{ item.1.name }}"
  with_nested:
    - "{{ existing_files_1_4 }}"
    - "{{ existing_files_5_8 }}"
  ignore_errors: yes

And if you check the result you will see something like:

TASK [Echo result] *************************************************************
changed: [server] => (item=[{'name': 1}, {'name': 5}])
changed: [server] => (item=[{'name': 1}, {'name': 6}])
changed: [server] => (item=[{'name': 1}, {'name': 7}])
changed: [server] => (item=[{'name': 2}, {'name': 5}])
changed: [server] => (item=[{'name': 2}, {'name': 6}])
changed: [server] => (item=[{'name': 2}, {'name': 7}])
changed: [server] => (item=[{'name': 3}, {'name': 5}])
changed: [server] => (item=[{'name': 3}, {'name': 6}])
changed: [server] => (item=[{'name': 3}, {'name': 7}])

If instead of using a dict, you want to use an array, you should set_fact as follows

- set_fact:
    existing_files_1_4: "{{ existing_files_1_4|default({}) | combine ( { item.item: item.stdout } ) }}"
  when: (item.rc == 0)
  with_items:
    - "{{ files_1_4.results }}"
Advertisements

Debug (properly) data registered with a loop

If you take a look at official documentation of Ansible to learn how to use register with a loop, you will see that the data that is registered is not really usable when debugging.

Example:

- shell: echo "{{ item }}"
  with_items:
    - one
    - two
  register: echo

If you want to show only the ‘stdout_lines’ of this task you will need to do:

- debug:
  msg: "{{ echo.results|map(attribute='stdout_lines')|list }}"

The output won’t be perfect, but for sure will be more usable:

ok: [server] => {
 "msg": [
     [
         "one"
     ],
     [
         "two"
     ]
   ]
}