Fetching varialble data into loops iterate/repeat

Hi Team,

Greetings for the day!

I have a variables called ‘aggregates’ under vars which ontaints cluster1,cluster3,cluster2…etc and aggr1,aggr2,aggr3…etc list as mentioned below.

{
“aggregates”: [
[
“Cluster1”,
“aggr1”
],
[
“Cluster1”,
“aggr2”
],
[
“Cluster1”,
“aggr4”
],
[
“Cluster2”,
“aggr1”
],
[
“Cluster3”,
“aggr2”
]
]
}

Your ‘aggregates’ is a list of lists. For each aggregate list item, you have a two-element list where element [0] is cluster name and element [1] is aggregate name.

Loop through aggregates, and use item.0 for cluster and item.1 for hostname ?

  • name: Get info
    na_ontap_rest_info:
    <<: *login
    gather_subset:
  • storage/volumes
    parameters:
    aggregates.name: “{{ item.1 }}”
    hostname: “{{ item.0 }}”
    use_python_keys: true
    register: vol_data
    loop: “{{ aggregates }}”
    loop_control:
    label: “{{ ?? }}”
    no_log: false
  • debug: var=vol_data

Walter

Yes, I got it what I was looking for.

Thank you very much for your help Todd and Walter.

If you are defining aggregates (vs getting from some other task register var), there is another way you could construct your aggregates var.

aggregates:

  • { cluster: “Cluster 1”, aggregate: “aggr1” }

  • { cluster: “Cluster 1”, aggregate: “aggr2” }

  • { cluster: “Cluster 1”, aggregate: “aggr4” }

  • { cluster: “Cluster 2”, aggregate: “aggr1” }

  • { cluster: “Cluster 3”, aggregate: “aggr2” }

This syntax makes it really easy to add more items and maintain proper syntax.

Your item.0 changes to item.cluster, and your item.1 change to item.aggregate.

  • name: Get info
    na_ontap_rest_info:
    <<: *login
    gather_subset:

  • storage/volumes
    parameters:
    aggregates.name: “{{ item.cluster }}”
    hostname: “{{ item.aggregate }}”
    use_python_keys: true
    register: vol_data
    loop: “{{ aggregates }}”
    no_log: false

  • debug: var=vol_data

This might be more description and easier for someone else to make the connection between your aggregates var and your loop references. The aggregates var is still a list. It is a list of JSON dictionary items.

Hi, All and Walter,

Thank you for good suggestions.

That’s a really good way to deal with it but there is something I should mention here to request help.

Actually below aggregates data coming from another set_task ( see below) which contains a list data.

vars:
aggregates:

aggregates data coming below set_fact.

  • set_fact:
    aggregates: “{{ aggregates|default() + ([item.item]| product(item | json_query(get_attrs)))| map(‘flatten’)|list }}”
    vars:
    get_attrs: “ontap_info.storage_aggregates.records[*].[name]”
    loop: “{{ ontap.results }}”
    no_log: true

Looking for:
As above mentioned set_fact giving data into list into lists, Can we make aggregates data into dict structure as mentioned below from same set_fact ?

aggregates:

  • { cluster: “Cluster 1”, aggregate: “aggr1” }

  • { cluster: “Cluster 1”, aggregate: “aggr2” }

  • { cluster: “Cluster 1”, aggregate: “aggr4” }

  • { cluster: “Cluster 2”, aggregate: “aggr1” }

  • { cluster: “Cluster 3”, aggregate: “aggr2” }

Thank you for your time and helping out.

No problem.

  • name: convert list of lists to list of dicts

set_fact:

json_list: “{{ aggregates2 | map(‘zip’,[‘cluster’,‘aggregate’]) | map(‘map’,‘reverse’) | map(‘community.general.dict’) }}”

produces

“json_list”: [

{

“aggregate”: “aggr1”,

“cluster”: “Cluster 1”

},

{

“aggregate”: “aggr2”,

“cluster”: “Cluster 1”

},

{

“aggregate”: “aggr4”,

“cluster”: “Cluster 1”

},

{

“aggregate”: “aggr1”,

“cluster”: “Cluster 2”

},

{

“aggregate”: “aggr2”,

“cluster”: “Cluster 3”

}

]

Walter

Hi,

Is there any version dependance to use community.general.dict? my current Ansible version 2.9.13.

When i use

  • name: convert list of lists to list of dicts
    set_fact:
    json_list: “{{ aggregates | map(‘zip’,[‘cluster’,‘aggregate’]) | map(‘map’,‘reverse’) | map(‘community.general.dict’) }}”

output:
ok: [localhost] => {
“json_list”: “<generator object sync_do_map at 0x7f47f2a99fc0>”

When i use:

  • name: convert list of lists to list of dicts
    set_fact:
    json_list: “{{ aggregates | map(‘zip’,[‘cluster’,‘aggregate’]) | map(‘map’,‘reverse’) | map(‘community.general.dict’)|list }}”

Output:
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: jinja2.exceptions.TemplateRuntimeError: No filter named ‘community.general.dict’.
fatal: [localhost]: FAILED! => {
“changed”: false
}

Absent community.general.dict you can do it in two steps:

  • name: convert list of lists to list of dicts 1

set_fact:

json_list: “{{ aggregates2 | map(‘zip’,[‘cluster’,‘aggregate’]) | map(‘map’,‘reverse’) }}”

loop: “{{ aggregates2 }}”

  • name: convert list of lists to list of dicts 2

set_fact:

new_list: “{{ (new_list | default()) + [ { item.0.0: item.0.1, item.1.0: item.1.1 } ] }}”

loop: “{{ json_list }}”

Walter

Hi Walter,

Sorry for the trouble. I got still some error

TASK [convert list of lists to list of dicts] ***********************************************************************************************************************************************
ok: [localhost] => (item=[‘cluster1’, ‘aggr1’])
ok: [localhost] => (item=[‘cluster1’, ‘aggr2’])
ok: [localhost] => (item=[‘cluster1’, ‘aggr3’])
ok: [localhost] => (item=[‘cluster1’, ‘aggr2’])
ok: [localhost] => (item=[‘cluster2’, ‘aggr4’])

TASK [convert list of lists to list of dicts 2] *********************************************************************************************************************************************
fatal: [localhost]: FAILED! => {}

MSG:

Invalid data passed to ‘loop’, it requires a list, got this instead: <generator object sync_do_map at 0x7f086aad40f8>. Hint: If you passed a list/dict of just one element, try adding wantlist=True to your lookup invocation or use q/query instead of lookup.

The same playbook also giving issue from end. May be i will look into in deep if any version dependance.

the output i got for you provided playbook:

TASK [convert list of lists to list of dicts 1] *********************************************************************************************************************************************
ok: [ciccdot1] => (item=[‘Cluster 1’, ‘aggr1’])
ok: [ciccdot1] => (item=[‘Cluster 1’, ‘aggr2’])
ok: [ciccdot1] => (item=[‘Cluster 1’, ‘aggr4’])
ok: [ciccdot1] => (item=[‘Cluster 2’, ‘aggr1’])
ok: [ciccdot1] => (item=[‘Cluster 3’, ‘aggr2’])

TASK [convert list of lists to list of dicts 2] *********************************************************************************************************************************************
fatal: [ciccdot1]: FAILED! => {}

MSG:

Invalid data passed to ‘loop’, it requires a list, got this instead: <generator object sync_do_map at 0x7f1b5adf7830>. Hint: If you passed a list/dict of just one element, try adding wantlist=True to your lookup invocation or use q/query instead of lookup.

You probably need to upgrade your ansible.

Walter

Yes guess so, Thanking you once again.