with_items combined with when to set variables and then break

Hi everyone,

I have already read several post about this but haven’t found the answer.
Basically I would like to set some variables when a condition is met while looping over a list of dictionaries, and then stop the loop and keep the variables to use them afterwards.

This code shows when the condition is met (prints ok) but the loop keeps iterating and the content of the variables is lost :

`

  • name: Check if the customer already exists in the Ops db
    set_fact:
    customer_found: true
    customer_id: item[‘id’]
    customer_name: item[‘customer_details’][‘name’]
    customer_size: item[‘customer_details’][‘size’]
    when: item[‘customer_details’][‘country’] == (tenant_country_code_2l | trim) and item[‘customer_details’][‘icn’] == tenant_icn_7d
    with_items: “{{ customers_data }}”
    `

This is the output:

`
TASK [… : Check if the customer already exists in the DB]
ok: [runner_ansible] => (item={u’id’: u’0’, u’customer_details’: {u’country’: u’DE’, u’size’: u’small’, u’icn’: u’1234569’, u’name’: u’CustomerTenant019’}})
skipping: [runner_ansible] => (item={u’id’: u’1’, u’customer_details’: {u’country’: u’FR’, u’size’: u’small’, u’icn’: u’999999’, u’name’: u’ODM team’}})

TASK [… : Print the customer id]
ok: [runner_ansible] => {}

MSG:

Customer id = item[‘id’]

`

The variable customer_id seems not to be assigned as ‘item[‘id’]’ is printed.

I’ve got the feeling there should be a better way to achieve this with ansible, and anyway, this code does not work.

Any help will be much appreciated.

Best,
Sabrina

Hi everyone,

I have already read several post about this but haven't found the answer.
Basically I would like to set some variables when a condition is met while
looping over a list of dictionaries, and then stop the loop and keep the
variables to use them afterwards.

This code shows when the condition is met (prints ok) but the loop keeps
iterating and the content of the variables is lost :
- name: Check if the customer already exists in the Ops db
  set_fact:
    customer_found: true
    customer_id: item['id']
    customer_name: item['customer_details']['name']
    customer_size: item['customer_details']['size']
  when: item['customer_details']['country'] == (tenant_country_code_2l > trim) and item['customer_details']['icn'] == tenant_icn_7d
  with_items: "{{ customers_data }}"

Variables in Ansible need to be enclosed in {{ }} unless you already are in Jinga template like in when:
But you items in set_facts need {{ }}

   customer_id: "{{ item['id'] }}"

Do that to all of them.

It will still loop over all the items, there are no way to stop that with with_items.
And if more than one record match the last one will stick in the variables.

This is the output:
TASK [.. : Check if the customer already exists in the DB]
ok: [runner_ansible] => (item={u'id': u'0', u'customer_details': {u'country'
: u'DE', u'size': u'small', u'icn': u'1234569', u'name': u
'CustomerTenant019'}})
skipping: [runner_ansible] => (item={u'id': u'1', u'customer_details': {u
'country': u'FR', u'size': u'small', u'icn': u'999999', u'name': u'ODM team'
}})

TASK [.. : Print the customer id]
ok: [runner_ansible] => {}

MSG:

Customer id = item['id']

Here you see that the variables got the value item['id'] and not the content of the variable when {{}} if forgotten.

The variable customer_id seems not to be assigned as 'item['id']' is
printed.

I've got the feeling there should be a better way to achieve this with
ansible, and anyway, this code does not work.

You could do something like this.

   - set_fact:
       customer: "{{ (customers_data | selectattr('customer_details.country', 'equalto', tenant_country_code_2l

trim) | selectattr('customer_details.icn', 'equalto', tenant_icn_7d) |

first | default(False) ) }}"

If the customer doesn't exist customer = False, it it exist you will have customer.id, customer.customer_details.country and so on.
The syntax customer.id is the same as customer['id'], reason I use the former is to avoid escaping the quotes hell.

And to use it you could do something like this

   - debug: msg="Customer exist"
     when: customer.id is defined

   - debug: msg="Customer doesn't exist"
     when: customer.id is not defined

Thanks a lot Kai, I didn’t know about this and didn’t think about this (I stupidly lost few hours):

But you items in set_facts need {{ }}
customer_id: “{{ item[‘id’] }}”

It works fine now :).

Best,
Sabrina

> It will still loop over all the items, there are no way to stop that with with_items.

> And if more than one record match the last one will stick in the variables.

Yes, thanks, that’s exactly what I want.
In my case, there should be only one match, if there are 2, this means there’s a duplicate entry, which is not normal and should be reported.
If there a way to know the number of matches?

I can see 2 hits in the log:
`

ok: [runner_ansible] => (item={‘id’: ‘xxx’, ‘customer_details’: {}}) => {

ok: [runner_ansible] => (item={‘id’: ‘yyy’, ‘customer_details’: {}}) => {

`
Does a variable store the number of hits?