Ansible nested loop using index.

53 views
Skip to first unread message

Lionel H

unread,
Sep 27, 2018, 10:22:38 AM9/27/18
to Ansible Project
Hi all, 

Hope I will find the information here :-)

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 :-)


Best regards,

Lionel.

Matt Martz

unread,
Sep 27, 2018, 11:06:29 AM9/27/18
to ansible...@googlegroups.com
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"
    ]
}

--
You received this message because you are subscribed to the Google Groups "Ansible Project" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ansible-proje...@googlegroups.com.
To post to this group, send email to ansible...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ansible-project/5edde98f-64f5-447f-beae-22dc5d21a00b%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


--
Matt Martz
@sivel
sivel.net

Lionel H

unread,
Sep 28, 2018, 2:03:05 AM9/28/18
to Ansible Project
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.

Lionel H

unread,
Sep 28, 2018, 2:38:02 AM9/28/18
to Ansible Project
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.

Kai Stian Olstad

unread,
Sep 28, 2018, 4:23:18 PM9/28/18
to ansible...@googlegroups.com
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 }}"


--
Kai Stian Olstad


Felix Fontein

unread,
Sep 28, 2018, 4:31:36 PM9/28/18
to ansible...@googlegroups.com
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

Lionel H

unread,
Oct 1, 2018, 5:00:43 AM10/1/18
to Ansible Project
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 :-)

Anyway, this is working now.


Huge thanks ;-)

Lionel. 
Reply all
Reply to author
Forward
0 new messages