Ansible: Understanding the `subelements` lookup (`with_subelements`)
by yaobin.wen
The document of subelements lookup [1] is not clear and has confused people [2]. In this article, I’m going to explain how it works. But also note that the subelements lookup can be replaced by loop and the subelements filter [3].
The key to understanding with_subelements is to firstly understand Cartesian product:
In mathematics, specifically set theory, the Cartesian product of two sets A and B, denoted
A x B, is the set of all ordered pairs (a, b) where a is in A and b is in B.
For example, given two sets A and B:
A = { 1, 2 }
B = { 3, 4, 5 }
The Cartesian product of A and B are: (1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5).
In Python, itertools.product calculates the Cartesian product of input iterables (not limited to two input iterables). The example above can be implemented as follows:
>>> import itertools
>>> A = set([1, 2])
>>> A
{1, 2}
>>> B = set([3, 4, 5])
>>> B
{3, 4, 5}
>>> list(itertools.product(A, B))
[(1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5)]
>>>
with_subelements essentially calculates the Cartesian product of two lists. This is why it takes two input arguments. The special thing about with_subelements is: its second list is contained as a sub-element in the elements of the first list, hence the lookup name with_subelements. For example [2.1]:
---
- hosts: localhost
  gather_facts: no
  vars:
    families:
      - surname: Smith
        country: US
        children:
          - name: Mike
            age: 4
          - name: Kate
            age: 7
      - surname: Sanders
        country: UK
        children:
          - name: Pete
            age: 12
          - name: Sara
            age: 17
  tasks:
    - name: List children
      debug:
        msg: "Family={{ item.0.surname }} Child={{ item.1.name }} Age={{ item.1.age }}"
      with_subelements:
        - "{{ families }}"
        - children
The first list is families; the second list is children which is a sub-element in every element of the first list. Therefore, with_subelements calculates the Cartesian product of the two lists and produces the following list of pairs:
[
  ({u'country': u'US', u'surname': u'Smith'}, {u'age': 4, u'name': u'Mike'}),
  ({u'country': u'US', u'surname': u'Smith'}, {u'age': 7, u'name': u'Kate'}),
  ({u'country': u'UK', u'surname': u'Sanders'}, {u'age': 12, u'name': u'Pete'}),
  ({u'country': u'UK', u'surname': u'Sanders'}, {u'age': 17, u'name': u'Sara'})
]
So the result messages are:
Family=Smith Child=Mike Age=4
Family=Smith Child=Kate Age=7
Family=Sanders Child=Pete Age=12
Family=Sanders Child=Sara Age=17
Refer to subelements-lookup.yml to run the example code.
References:
Tags: Tech