Ansible nested loop using index.

Hi all,

Hope I will find the information here :slight_smile:

I need to loop over 2 lists, the first one is just a list of Integers, things get tricky here because the second list needs the input from the first list to loop over. In fact, the list is included in a dictionary where keys are integers.

One example will be more self-explanatory:

1st list:
chains = [1, 2, 3, 4, 5]

2nd list:
chains_config:
1:
foo: bar
configs:

  • type: routed
    version: 0.1

  • type: bridged
    version: 0.2

2:
foo: baz
configs:

  • type: routed
    version: 1.0

  • type: bridged
    version: 1.1

… and 3, 4, 5 you get the idea.

So I need to loop over this configs key and the chains list is defined by the user input.

In python I would do this way:

for chain in chains:
for config in chains_config[chain][‘configs’]:
print(config.type).

Now, and to convert this into ansible code?

I hope that you get the point :slight_smile:

Best regards,

Lionel.

What is your end goal? How do you plan to use this data, assuming you could loop the way you want?

Something like the following:

“{{ chains|map(‘extract’, chains_config)|map(attribute=‘configs’)|flatten|map(attribute=‘type’)|flatten }}”

Gives:

ok: [localhost] => {
“msg”: [
“routed”,
“bridged”,
“routed”,
“bridged”
]
}

Hi matt,

Thanks for your reply !

That’s already a good example, But I need somehow also to retrieve the index which is the chain number.

Let’s simplify and say we only have one type of deployment (routed or bridged):

chains_config:
1:
foo: bar
configs:

  • type: bridged
    version: 0.2

2:
foo: baz
configs:

  • type: routed
    version: 1.0

To briefly explain the context we have two type of network deployment (routed or bridged). Each of these network deployment have their own
set of network interfaces / VLANs. The VLAN used is guess from the chain number and type of deployment. And the type of deployment is specified in the chains_config dict.
On top of this network architecture a docker container is applied for network type / VLANs.

A dumb naive approach would be:

  • name: Creating docker network for the chain
    include_role:
    name: docker_chain_network
    vars:
    docker_network:
    name: macvlan{{item.key}}0{{ ‘6’ if item.value.type == ‘routed’ else ‘5’ }}
    driver: macvlan
    driver_options:
    parent: “{{ ‘eno52’ if routed else ‘eno51’ }}”.{{item.key}}0{{ ‘6’ if item.value.type == routed else ‘5’ }}"
    with: ? map/select ?

item.key ==> Would be each index of chains list (iteratively).
item.value.type ==> Would be type of deployment based the index above; like in python: chains_config[item.key][‘configs’][‘type’]

docker_chain_network is just a role applying docker_network module with the vars passed to the role.

This is rather complex stuff. Thanks for taking your time and for your answers.

Best regards,

Lionel.

Replying to my-self,

I managed somehow to make some progress, but now the issue is that it merge the results like the following:

Given the following config:

chains_config:
1:
foo: bar
configs:

  • type: bridged
    version: 0.2

2:
foo: baz
configs:

  • type: routed
    version: 1.0

chains = [1, 2]

And using that loop with debug:

  • debug: msg=“chain={{ item.0 }}, configs={{ item.1.type }}”
    with_nested:
  • “{{ chains }}”
  • “{{ chains |map(‘extract’, chains_config) |map(attribute=‘configs’) |list }}”

I have the following output:

ok: [server] => (item=None) => {
“msg”: “chain=1, configs=bridged”
}
ok: [server] => (item=None) => {
“msg”: “chain=1, configs=routed”
}
ok: [server] => (item=None) => {
“msg”: “chain=2, configs=bridged”
}
ok: [server] => (item=None) => {
“msg”: “chain=2, configs=routed”
}

Which is not really right as not bridged config is defined for chain 2 and no routed is defined for chain 1.

Best regards,

Lionel H.

I haven't understood what your are trying in your previous mails, but based on this one you are looking for this?

  - debug: msg="chain={{ item.key }}, configs={{ item.value.configs.0.type }}"
    with_dict: "{{ chains_config }}"

If you would like to use the chains it would be something like this

  - debug: msg="chain={{ item }}, configs={{ chains_config[item].configs.0.type }}"
    with_item: "{{ chains }}"

Hi Lionel,

I've written a lookup plugin
(https://github.com/felixfontein/ansible-dependentloop/) which you
could use for this:

- debug:
     msg: "index={{ item.0 }} foo={{ chains_config[item.0].foo }}
           type={{ index.1.type }} version={{ index.1.version }}"
   with_dependent:
     - chains
     - "chains_config[item.0].configs"

Cheers,
Felix

Hi Felix,

Oh waw! Definitely what I was looking for. Shame that we have to resort to custom plugins to achieve such a common things…

In my findings I was hoping maybe to find some sort of lookup plugins to filter a dict based on a provided list of keys like:
{{ mydict | filter_by_keys([1, 2]) }} to only select those keys from the dictionary but it seems not yet implemented! Maybe a good entrypoint for me to start
digging into ansible plugin creation :slight_smile:

Anyway, this is working now.

Huge thanks :wink:

Lionel.