Assign values to variables using a loop (set_fact or other?) - ansible

Using an Ansible task, I'm trying to create variables and associated values from a returned loop object.
Ref: https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html
- name: Get values
someModule:
input_from_loop: "{{ item }}"
loop:
- "foo"
- "bar"
register: get_result
Gives
get_result:
changed: false
msg: All items completed
results:
- ansible_loop_var: item
item: foo
alpha:
beta:
content: someFooValue
- ansible_loop_var: item
item: bar
alpha:
beta:
content: someBarValue
With this get_result object, I'm trying to create variables and associated values such that:
Pseudocode:
- name: Assign values
set_fact:
"{{ item.item }}":"{{ item.alpha.beta.content }}"
loop: get_result.results
To result in:
foo:someFooValue
bar:someBarValue
I can't seem to get around the error
Implicit map keys need to be followed by map values"
I do not want to create a new object, just variables with values for later use (in existing tasks).
I've tried a few approaches to no avail.
[Or can it happen on each iteration of the initial loop calling the module?]

Now that I am rereading your your requirements, I am wondering if you are not looking for variables at the top level of your host that would be named
foo and contain someFooValue
bar and contain someBarValue
If this is the case, then most of that is above does still apply, the registering of the fact only change:
- set_fact: { "{{ item.0 }}": "{{ item.1 }}" }
loop: "{{
get_result.results | map(attribute='item') | zip(
get_result.results | map(attribute='alpha.beta.content')
)
}}"
Which gives you the two expected variables with the corresponding values.
ok: [localhost] =>
foo: someFooValue
ok: [localhost] =>
bar: someBarValue
What you can do in those kind of cases is to break down the dictionary in multiple lists, all containing one of the field you are interested into, with the map filter, then reconstruct a list of list with the help of the zip filter. And finally, join everything together.
So, with a task like:
- set_fact:
formatted_fact: "{{
get_result.results | map(attribute='item') | zip(
get_result.results | map(attribute='alpha.beta.content')
) | map('join', ':') | join('\n')
}}"
You get your expected output:
formatted_fact: |-
foo:someFooValue
bar:someBarValue
Given those couple of tasks, we have the two possibilities:
- set_fact:
formatted_fact: "{{
get_result.results | map(attribute='item') | zip(
get_result.results | map(attribute='alpha.beta.content')
) | map('join', ':') | join('\n')
}}"
vars:
get_result:
changed: false
msg: All items completed
results:
- ansible_loop_var: item
item: foo
alpha:
beta:
content: someFooValue
- ansible_loop_var: item
item: bar
alpha:
beta:
content: someBarValue
- debug:
var: formatted_fact
- set_fact: { "{{ item.0 }}": "{{ item.1 }}" }
loop: "{{
get_result.results | map(attribute='item') | zip(
get_result.results | map(attribute='alpha.beta.content')
)
}}"
vars:
get_result:
changed: false
msg: All items completed
results:
- ansible_loop_var: item
item: foo
alpha:
beta:
content: someFooValue
- ansible_loop_var: item
item: bar
alpha:
beta:
content: someBarValue
- debug:
var: foo
- debug:
var: bar
They would yield:
TASK [set_fact] **************************************************************
ok: [localhost]
TASK [debug] *****************************************************************
ok: [localhost] =>
formatted_fact: |-
foo:someFooValue
bar:someBarValue
TASK [set_fact] **************************************************************
ok: [localhost] => (item=['foo', 'someFooValue'])
ok: [localhost] => (item=['bar', 'someBarValue'])
TASK [debug] *****************************************************************
ok: [localhost] =>
foo: someFooValue
TASK [debug] *****************************************************************
ok: [localhost] =>
bar: someBarValue

For example
_query: '[].{key: item, value: alpha.beta.content}'
result: "{{ get_result.results|json_query(_query)|items2dict }}"
gives the expected result
result:
bar: someBarValue
foo: someFooValue
Example of a complete playbook (for testing)
- hosts: localhost
vars:
get_result:
changed: false
msg: All items completed
results:
- ansible_loop_var: item
item: foo
alpha:
beta:
content: someFooValue
- ansible_loop_var: item
item: bar
alpha:
beta:
content: someBarValue
_query: '[].{key: item, value: alpha.beta.content}'
result: "{{ get_result.results|json_query(_query)|items2dict }}"
tasks:
- debug:
var: result

Regarding the question in the headline
How to assign values to variables using a loop (set_fact)?
and the mentioned "pseudocode" I like to note that such approach might work, as the following test
---
- hosts: localhost
become: false
gather_facts: false
vars:
varKey: "TEST"
varVal: "testValue"
tasks:
- name: Create variable dynamic
set_fact:
"{{ varKey }}_{{ item }}": "{{ varVal }}_{{ item }}"
loop: [1, 2, 3]
- name: Show variable
debug:
var: TEST_{{ item }}
loop: ["1", "2", "3"]
results into an output of
TASK [Create variable dynamic] *********
ok: [localhost] => (item=1)
ok: [localhost] => (item=2)
ok: [localhost] => (item=3)
TASK [Show variable] *********
ok: [localhost] => (item=1) =>
TEST_1: testValue_1
ansible_loop_var: item
item: '1'
ok: [localhost] => (item=2) =>
TEST_2: testValue_2
ansible_loop_var: item
item: '2'
ok: [localhost] => (item=3) =>
TEST_3: testValue_3
ansible_loop_var: item
item: '3'
and also
- name: Create variable dynamic
set_fact:
"{{ item }}": "{{ item }}"
loop: [A1, A2, A3]
- name: Show variable
debug:
var: "{{ item }}"
loop: [A1, A2, A3]
into
TASK [Create variable dynamic] **********
ok: [localhost] => (item=A1)
ok: [localhost] => (item=A2)
ok: [localhost] => (item=A3)
TASK [Show variable] **********
ok: [localhost] => (item=A1) =>
A1: A1
ansible_loop_var: item
item: A1
ok: [localhost] => (item=A2) =>
A2: A2
ansible_loop_var: item
item: A2
ok: [localhost] => (item=A3) =>
A3: A3
ansible_loop_var: item
item: A3

Related

Unicode error while increment variable value

When I work with static variables it works absolutely fine. But when I try to use dynamic it does not work.
The playbook:
---
- hosts: Swi1
vars:
NewOne: 0
provider:
host: "192.168.0.30"
transport: "cli"
username: "cisco"
password: "cisco"
tasks:
- name: gather facts
register: iosfacts
ios_facts:
provider: "{{ provider }}"
- name: Display the value of the counter
debug:
msg: "NewOne={{ NewOne }} / Data type={{ NewOne | type_debug }}"
- name: interface description
set_fact:
NewOne: " {{ NewOne + 1 }}"
parents: "interface {{ item.key }}"
with_dict: "{{ iosfacts.ansible_facts.ansible_net_interfaces }}"
when: item.value.operstatus == "up"
- debug:
msg: " This is Debug {{ NewOne }}"
Gives the error:
fatal: [Swi1]: FAILED! => {"msg": "Unexpected templating type error
occurred on ({{ NewOne + 1 }}): coercing to Unicode: need string or
buffer, int found"}
If you want to do an increment on a variable, you need to recast it as an int, as set_fact will always make you end up with a string.
As an example, the two tasks:
- set_fact:
NewOne: "{{ NewOne | d(0) + 1 }}"
- debug:
var: NewOne | type_debug
Are giving
TASK [set_fact] ***************************************************************
ok: [localhost]
TASK [debug] ******************************************************************
ok: [localhost] =>
NewOne | type_debug: str
The fix is, then, to use the int filter.
Given:
- set_fact:
NewOne: "{{ NewOne | d(0) | int + 1 }}"
loop: "{{ range(1, 4) }}"
- debug:
var: NewOne
This yields the expected
TASK [set_fact] ***************************************************************
ok: [localhost] => (item=1)
ok: [localhost] => (item=2)
ok: [localhost] => (item=3)
TASK [debug] ******************************************************************
ok: [localhost] =>
NewOne: '3'
But then with your use case, there are more elaborated and shorter way to achieve the same:
- set_fact:
NewOne: >-
{{
iosfacts
.ansible_facts
.ansible_net_interfaces
| selectattr('value.operstatus', '==', 'up')
| length
}}
Given:
- debug:
msg: >-
{{
iosfacts
.ansible_facts
.ansible_net_interfaces
| selectattr('value.operstatus', '==', 'up')
| length
}}
vars:
iosfacts:
ansible_facts:
ansible_net_interfaces:
- value:
operstatus: up
- value:
operstatus: down
- value:
operstatus: up
This yields:
ok: [localhost] =>
msg: '2'
It seems you are trying to implement a loop counter with a programming paradigm, which isn't plain possible in that way since Ansible is not a programming language but a Configuration Management Tool in which you declare a state.
Your current issue is reproducible in the following way:
---
- hosts: localhost
become: false
gather_facts: false
vars:
NewOne: 0
tasks:
- name: Show var
debug:
msg: "{{ NewOne | type_debug }}"
- name: Add value
set_fact:
NewOne: " {{ NewOne + 1 }}"
loop: [1, 2, 3]
- name: Show result
debug:
msg: "{{ NewOne }}
resulting into an output of
TASK [Add value] *************
ok: [localhost] => (item=1)
fatal: [localhost]: FAILED! =>
msg: 'Unexpected templating type error occurred on ( {{ NewOne + 1 }}): coercing to Unicode: need string or buffer, int found'
Possible Solutions
You may have a look into Migrating from with_X to loop and Extended loop variables as an iteration counter is already provided there.
An other approach is given via type casting with filter in the answer of #β.εηοιτ.βε.
There as well if you are just interested in the amount of occurrences of certain status, like interface status up or down.
Further Q&A
Ansible set_fact type cast
Further Documentation
Discovering the data type
Forcing the data type

Ansible task async with poll=0 doesn't move on from task

ansible version: 4.10.0
I am hoping to make this task async on a single host. When I use poll:0, I had expected it to fire off the task and move on, but it instead takes longer than when async is not used.
- name: "setup test databases on cluster"
block:
- name: "generate list of databases"
set_fact:
test_database_list: "{{ test_database_list | default([])+['test_db%02d'| format(item)] }}"
loop: "{{ range(1,10+1,1)| list }}"
- name: "create test database(s) on cluster"
postgresql_db:
name: "{{ item }}"
with_items: "{{ test_database_list }}"
become_user: postgres
- name: "install postgresql extensions"
postgresql_ext:
db: "{{ item[0] }}"
name: "{{ item[1] }}"
with_nested:
- "{{ test_database_list }}"
- - pageinspect
- pg_buffercache
- pg_freespacemap
- pg_prewarm
- pg_stat_statements
- pg_visibility
- pg_trgm
- pgrowlocks
- pgstattuple
become_user: postgres
async: 30
poll: 0
register: postgres_ext_install_status
- ansible.builtin.async_status:
jid: "{{ item.ansible_job_id }}"
loop: "{{ postgres_ext_install_status.results }}"
loop_control:
label: "{{ item.item }}"
register: job_result
until: job_result.finished
retries: 100
delay: 2
- debug:
msg: "{{ item.start }} -- {{ item.end }} -- {{ item.delta }}"
loop: "job_result.results"
loop_control:
label: "{{ item.item.item }}
Here is the output: https://pastebin.com/DTkbbqgR
The documentation clearly states that poll:0 will cause the play to move on from the task, but it instead stays on the task and slowly moves through each of the extensions for each database before moving onto the next task.
Am I misunderstanding the use of async / poll?
The following example works for running async on a single host and having it move on from the task.
- hosts: localhost
gather_facts: no
tasks:
- name: sleep 10s
command: "sleep 10"
loop: "{{range(3)|list}}"
async: 11
poll: 0
How is this different from what I am doing?
EDIT: Added more code and link to results
Use aync_status and take a look at the timing, e.g.
- hosts: localhost
gather_facts: false
tasks:
- shell: 'sleep 2 && echo {{ item.0 }}{{ item.1 }}'
with_nested:
- [a, b]
- [1, 2, 3]
async: 30
poll: 0
register: result
- async_status:
jid: "{{ item.ansible_job_id }}"
loop: "{{ result.results }}"
loop_control:
label: "{{ item.item }}"
register: job_result
until: job_result.finished
retries: 100
delay: 2
- debug:
msg: "{{ item.start }} {{ item.end }} {{ item.delta }}"
loop: "{{ job_result.results }}"
loop_control:
label: "{{ item.item.item }}"
gives
PLAY [localhost] ************************************************************
TASK [shell] ****************************************************************
changed: [localhost] => (item=['a', 1])
changed: [localhost] => (item=['a', 2])
changed: [localhost] => (item=['a', 3])
changed: [localhost] => (item=['b', 1])
changed: [localhost] => (item=['b', 2])
changed: [localhost] => (item=['b', 3])
TASK [async_status] *********************************************************
FAILED - RETRYING: [localhost]: async_status (100 retries left).
changed: [localhost] => (item=['a', 1])
changed: [localhost] => (item=['a', 2])
changed: [localhost] => (item=['a', 3])
changed: [localhost] => (item=['b', 1])
changed: [localhost] => (item=['b', 2])
changed: [localhost] => (item=['b', 3])
TASK [debug] ****************************************************************
ok: [localhost] => (item=['a', 1]) =>
msg: 2022-02-23 01:43:53.697183 2022-02-23 01:43:55.703037 0:00:02.005854
ok: [localhost] => (item=['a', 2]) =>
msg: 2022-02-23 01:43:53.987039 2022-02-23 01:43:55.993030 0:00:02.005991
ok: [localhost] => (item=['a', 3]) =>
msg: 2022-02-23 01:43:54.269019 2022-02-23 01:43:56.275290 0:00:02.006271
ok: [localhost] => (item=['b', 1]) =>
msg: 2022-02-23 01:43:54.592526 2022-02-23 01:43:56.601432 0:00:02.008906
ok: [localhost] => (item=['b', 2]) =>
msg: 2022-02-23 01:43:54.880133 2022-02-23 01:43:56.886689 0:00:02.006556
ok: [localhost] => (item=['b', 3]) =>
msg: 2022-02-23 01:43:55.220324 2022-02-23 01:43:57.228616 0:00:02.008292

Ansible iteration over nested dictionary

With Ansible 2.10, I am trying to iterate over a nested dictionary. The dictionary looks like that:
var1:
d1:
t1:
- p1
- p2
t2:
- p1
d2:
t1:
- p1
I would like the function return something like that:
d1, t1, p1
d1, t1, p2
d1, t2, p1
...
For any help, I will be grateful!
There are other (and possibly more convenient) ways to do this depending on your exact requirement. Changing your data structure might as well be an option.
Meanwhile, here is a solution to store the combinations in a list of 3 element tuples that you can reuse elsewhere.
---
- name: Product for nested dictionnary
hosts: localhost
gather_facts: false
vars:
var1:
d1:
t1:
- p1
- p2
t2:
- p1
d2:
t1:
- p1
tasks:
- name: Level 1 product (d* X t*)
set_fact:
level1: >-
{{
level1 | default([])
+
[item] | product(var1[item] | list)
}}
loop: "{{ var1 | list }}"
- name: Level 2 product (d* X t* X p*)
set_fact:
level2: >-
{{
level2 | default([])
+
[item] | product(var1[item.0][item.1]) | map('flatten')
}}
loop: "{{ level1 }}"
- name: Result
debug:
msg: "{{ item.0 }}, {{ item.1 }}, {{ item.2 }}"
loop: "{{ level2 }}"
Which gives:
PLAY [Product for nested dictionnary] **************************************************************************************************************************************************************************************************
TASK [Level 1 product (d* X t*)] *******************************************************************************************************************************************************************************************************
ok: [localhost] => (item=d1)
ok: [localhost] => (item=d2)
TASK [Level 2 product (d* X t* X p*)] **************************************************************************************************************************************************************************************************
ok: [localhost] => (item=['d1', 't1'])
ok: [localhost] => (item=['d1', 't2'])
ok: [localhost] => (item=['d2', 't1'])
TASK [Result] **************************************************************************************************************************************************************************************************************************
ok: [localhost] => (item=['d1', 't1', 'p1']) => {
"msg": "d1, t1, p1"
}
ok: [localhost] => (item=['d1', 't1', 'p2']) => {
"msg": "d1, t1, p2"
}
ok: [localhost] => (item=['d1', 't2', 'p1']) => {
"msg": "d1, t2, p1"
}
ok: [localhost] => (item=['d2', 't1', 'p1']) => {
"msg": "d2, t1, p1"
}
PLAY RECAP *****************************************************************************************************************************************************************************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
The "Jinja-free" version below
shell> cat next_loop.yml
- set_fact:
_batch: []
- set_fact:
_batch: "{{ _batch + [[ei.key, item.0.key, item.1]] }}"
with_subelements:
- "{{ ei.value|dict2items }}"
- value
- set_fact:
out: "{{ out|default([]) + _batch }}"
- include_tasks: next_loop.yml
loop: "{{ var1|dict2items }}"
loop_control:
loop_var: ei
- debug:
msg: "{{ item|join(',') }}"
loop: "{{ out }}"
gives the same result
msg: d1,t1,p1
msg: d1,t1,p2
msg: d1,t2,p1
msg: d2,t1,p1

Iterating list of dictionaries with dictionary

I'm having trouble grasping data manipulation in Ansible. Here's the setup:
- hosts: emirr01
gather_facts: no
vars:
setup:
- emirr01: { label: "label1" }
- emirr02: { label: "label2" }
- emirr03: { label: "label3" }
lookup: [ "emirr01", "emirr02"]
use_labels: [ ]
tasks:
- debug: msg="setup={{ setup }}"
- debug: msg="lookup={{ lookup }}"
- debug: msg="item0={{ item.0 }} item1={{ item.1 }}"
when: inventory_hostname == item.1
with_nested:
- "{{ setup }}"
- "{{ lookup }}"
- set_fact:
use_labels: "{{ use_labels + [ item.1.label ] }}"
when: item.0 == item.1.label
with_nested:
- "{{ setup }}"
- "{{ lookup }}"
- debug: msg="use_labels={{ use_labels }}"
What I need is to set a fact use_labels which is a list of labels as defined in setup list for each host found in lookup list. What I expect is a list like this:
[ "label1", "label2" ]
My problem is not being able to "reach" label in a list I get in item.1 which is (example):
item1=[{'emirr02': {'label': 'label2'}}
Here's is the error:
$ ansible-playbook test.yml -l emirr01
PLAY [emirr01] ****************************************************************************************************************************************************************************************************************************************************************************************************************************
TASK [debug] ******************************************************************************************************************************************************************************************************************************************************************************************************************************
ok: [emirr01] =>
msg: 'setup=[{''emirr01'': {''label'': ''label1''}}, {''emirr02'': {''label'': ''label2''}}, {''emirr03'': {''label'': ''label3''}}]'
TASK [debug] ******************************************************************************************************************************************************************************************************************************************************************************************************************************
ok: [emirr01] =>
msg: lookup=['emirr01', 'emirr02']
TASK [debug] ******************************************************************************************************************************************************************************************************************************************************************************************************************************
ok: [emirr01] => (item=[{'emirr01': {'label': 'label1'}}, 'emirr01']) =>
msg: 'item0={''emirr01'': {''label'': ''label1''}} item1=emirr01'
skipping: [emirr01] => (item=[{'emirr01': {'label': 'label1'}}, 'emirr02'])
ok: [emirr01] => (item=[{'emirr02': {'label': 'label2'}}, 'emirr01']) =>
msg: 'item0={''emirr02'': {''label'': ''label2''}} item1=emirr01'
skipping: [emirr01] => (item=[{'emirr02': {'label': 'label2'}}, 'emirr02'])
ok: [emirr01] => (item=[{'emirr03': {'label': 'label3'}}, 'emirr01']) =>
msg: 'item0={''emirr03'': {''label'': ''label3''}} item1=emirr01'
skipping: [emirr01] => (item=[{'emirr03': {'label': 'label3'}}, 'emirr02'])
TASK [set_fact] ***************************************************************************************************************************************************************************************************************************************************************************************************************************
fatal: [emirr01]: FAILED! =>
msg: |-
The conditional check 'item.0 == item.1.label' failed. The error was: error while evaluating conditional (item.0 == item.1.label): 'ansible.utils.unsafe_proxy.AnsibleUnsafeText object' has no attribute 'label'
The error appears to be in '/home/ansible/test.yml': line 21, column 7, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
- set_fact:
^ here
It all boils down to "digging" for a value from a dictionary in a list. Does anyone have an idea of how to reach item.1.label? It's a little bit frustrating since this is trivial in Python or other programming languages but in Ansible... Or maybe my mistake is to use a wrong kind of with_* loop for this purpose?
Q: "Expect a list like this [label1, label2]"
setup:
- emirr01: { label: "label1" }
- emirr02: { label: "label2" }
- emirr03: { label: "label3" }
lookup: [ "emirr01", "emirr02"]
A: This is a typical example of a wrong data structure for this use-case. A list of dictionaries can't be used in mapping the filter extract. Moreover, the keys in the dictionaries don't have to be unique, because they are hidden in the items of the list. The solution is simple with the data in the dictionary
setup:
emirr01: { label: "label1" }
emirr02: { label: "label2" }
emirr03: { label: "label3" }
- set_fact:
use_labels: "{{ lookup|map('extract', setup, 'label')|list }}"
gives
use_labels:
- label1
- label2
One of the options is creating a dictionary from the list first. For example
- set_fact:
setup2: "{{ setup2|default({})|combine(item) }}"
loop: "{{ setup }}"
Then the dictionary setup2 can be used to get the same result
It's possible to filter the list directly. For example, the task below gives the same result too
- set_fact:
use_labels: "{{ setup|map('dict2items')|map('first')|
selectattr('key', 'in', lookup )|
map(attribute='value.label')|
list }}"
Your issue with the with_nested is actually coming from how those "two-lists" loops are working.
When you are using loops like with_nested, the item.0 is the item of the first list, while the item.1 is the item of the second list.
Because lookup is a list and not a list of dictionaries like
lookup:
- label: "emirr01"
- label: "emirr02"
You can use the value of item.1 right away.
So the way to have you issue fixed is to use it this way:
- set_fact:
use_labels: "{{ use_labels + [ item.0[item.1].label ] }}"
when: item.0[item.1].label is defined
with_nested:
- "{{ setup }}"
- "{{ lookup }}"
Here is a playbook demonstrating this:
- hosts: localhost
gather_facts: no
tasks:
- set_fact:
use_labels: "{{ use_labels | default([]) + [ item.0[item.1].label ] }}"
when: item.0[item.1].label is defined
with_nested:
- "{{ setup }}"
- "{{ lookup }}"
vars:
setup:
- emirr01:
label: "label1"
- emirr02:
label: "label2"
- emirr03:
label: "label3"
lookup:
- "emirr01"
- "emirr02"
- debug:
msg: "{{ use_labels }}"
Wich gives:
PLAY [localhost] ***************************************************************************************************
TASK [set_fact] ****************************************************************************************************
ok: [localhost] => (item=[{'emirr01': {'label': 'label1'}}, 'emirr01'])
skipping: [localhost] => (item=[{'emirr01': {'label': 'label1'}}, 'emirr02'])
skipping: [localhost] => (item=[{'emirr02': {'label': 'label2'}}, 'emirr01'])
ok: [localhost] => (item=[{'emirr02': {'label': 'label2'}}, 'emirr02'])
skipping: [localhost] => (item=[{'emirr03': {'label': 'label3'}}, 'emirr01'])
skipping: [localhost] => (item=[{'emirr03': {'label': 'label3'}}, 'emirr02'])
TASK [debug] *******************************************************************************************************
ok: [localhost] => {
"msg": [
"label1",
"label2"
]
}
PLAY RECAP *********************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

How to use comparison operators with dictionary values?

I am trying to write a task that stores the dictionary values in variable based on the condition .
I'm new to this technology. Please anyone help on the below request.
I tried with the below code. Please check below.
- set_fact:
v1: "{{ v1|default([]) + item.keys() if item.values() == false else 1 }}"
loop: "{{ dv }}"
'dv' is a dictionary.
[{1A:True},{2A:True},{3A:False},{4A:False}]
Actually, here I'm trying to store false values in v1 by using comparison operators only.
Expected output:
v1 should contain following list:
[3A,4A]
Ansible Version: 2.5.15
Below works for me:
---
- hosts: localhost
vars:
dv:
1A: 'True'
2A: 'False'
3A: 'True'
4A: 'False'
tasks:
- name: debug
debug:
msg: "{{ item.value }}"
loop: "{{ dv | dict2items }}"
- set_fact:
v1: "{{ v1| default([]) + item.key if (item.value in 'False') else('') }}"
loop: "{{ dv | dict2items }}"
- debug:
var: v1
output -->
TASK [set_fact] *********************************************************************************************************
ok: [localhost] => (item={'key': u'1A', 'value': u'True'})
ok: [localhost] => (item={'key': u'3A', 'value': u'True'})
ok: [localhost] => (item={'key': u'2A', 'value': u'False'})
ok: [localhost] => (item={'key': u'4A', 'value': u'False'})
TASK [debug] ************************************************************************************************************
ok: [localhost] => {
"v1": "2A4A"
}
You can try the below code.
- hosts: localhost
connection: local
vars:
dv: [{1A:True},{2A:True},{3A:False},{4A:False}]
v2: []
v1: []
tasks:
- set_fact:
v1: "{{ v1|default([]) }} + [ {{ v1.append((item.keys()|first).split(':')[0]) if (item.keys()|first).split(':')[1] == 'False' else v2.append('1') }} ]"
with_items: "{{ dv }}"
- debug:
msg: "{{ v1 }}"
Here v2 is a variable declared to direct if the conditions are not met.
Output of the a above code is a below:
ok: [localhost] => {
"msg": [
"3A",
"4A"
]
}

Resources