Create a varaible list conditionally from dictionary items

8,162 views
Skip to first unread message

Javeria Khan

unread,
May 20, 2015, 8:41:00 AM5/20/15
to ansible...@googlegroups.com
Hi,

I've tried searching everything but can't find a possible solution. I have a yml that defines all my variables for a playbook and I need to do something like the following inside of it:
----------------
my_dict:
 - {  item_en: True,  name: name1, type:  type1,  key: value1 }
 - {  item_en: False, name: name2, type:  type2,  key: value2 }
 - {  item_en: True,  name: name3, type:  type3,  key: value3 }

my_list:
{%  for item in my_dict %}
{% if my_dict[item].item_en == True %}
    {{ my_dict[item].name  }}
{% endfor %}
---------------

So basically I need 'my_list' to be a list of 'names' from every dict object that has item_en = True. Based on the data structure above, it would look like this:

my_list:
 - name1
 - name3

I know this is possible using the jinja loop syntax in a template but this isn't a template file.

Thanks 

Matt Martz

unread,
May 20, 2015, 9:20:17 AM5/20/15
to ansible...@googlegroups.com
I think you want something like:

my_list: "{{ my_dict|selectattr('item_en')|map(attribute='name')|list }}"
--
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/5e6a8d23-4835-44c2-9902-5ec3a49feebb%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


--
Matt Martz
@sivel
sivel.net

Christian Thiemann

unread,
May 20, 2015, 12:54:48 PM5/20/15
to ansible...@googlegroups.com
Matt's solution is fine (and elegant!) for simple cases like this particular one. However, I found myself needing to filter items on some more complex conditions a few times and started using the Jinja do extension to effectively turn variable assignments into arbitrary computations:

my_list: |
 
{%- set names = [] -%}
 
{%- for item in my_dict if item.item_en -%}
   
{%- do names.append(item.name) -%}
 
{%- endfor -%}
 
{{ names }}

It's important to do proper whitespace-control (the dashes in {%- ... -%}) because in the end the string assigned to my_list must be "['name1', 'name3']" and not something like "   ['name1', 'name3']". In the former case, Ansible converts it to a proper list (because the value starts with '['), in the latter my_list would be assigned the actual string "   [...]".

And you need to enable the Jinja extension in your ansible.cfg:

[defaults]
jinja2_extensions
= jinja2.ext.do

As mentioned in the beginning, this isn't really necessary in this case and certainly isn't very much in Ansible's spirit of simplicity, but it has saved me from duplicating information across multiple variables several times.
To unsubscribe from this group and stop receiving emails from it, send an email to ansible-project+unsubscribe@googlegroups.com.
To post to this group, send email to ansible-project@googlegroups.com.

Shawn Ferry

unread,
May 20, 2015, 2:37:26 PM5/20/15
to ansible...@googlegroups.com
Why not something like this?

do_something_with: item.name
with_items: your_dict
when: item.item_en == True

Javeria Khan

unread,
May 20, 2015, 2:55:20 PM5/20/15
to ansible...@googlegroups.com
Thanks guys, 

Christian is your solution doable in a regular yml? I thought jinja constructs were only allowed in jinja templates? What I have is a regular .yml that defines all my variables.

Shawn I believe your solution requires creating a task to loop over my_dict, I prefer to do it outside of the playbook.

Javeria Khan

unread,
May 20, 2015, 3:19:53 PM5/20/15
to ansible...@googlegroups.com

Also, another quick question. If I was using my_dict in a task loop, could i put a condition on: 



with_items: my_dict
when: item.key is defined


will that work?

Shawn Ferry

unread,
May 20, 2015, 3:50:07 PM5/20/15
to ansible...@googlegroups.com
On Wed, May 20, 2015 at 3:19 PM Javeria Khan <javer...@gmail.com> wrote:

Also, another quick question. If I was using my_dict in a task loop, could i put a condition on: 


Right that is my example. Here it is in code when item_en is false the item is skipped.

TASK: [Loop] ******************************************************************
changed: [127.0.0.1] => (item={'key': 'value1', 'type': 'type1', 'name': 'name1', 'item_en': True})
skipping: [127.0.0.1] => (item={'key': 'value2', 'type': 'type2', 'name': 'name2', 'item_en': False})
changed: [127.0.0.1] => (item={'key': 'value3', 'type': 'type3', 'name': 'name3', 'item_en': True})

 


with_items: my_dict
when: item.key is defined


will that work?

--
You received this message because you are subscribed to a topic in the Google Groups "Ansible Project" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/ansible-project/VerPXFuLUb0/unsubscribe.
To unsubscribe from this group and all its topics, 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/6f3689d8-51e5-4fdb-ac81-2b7f43b81ccb%40googlegroups.com.

Christian Thiemann

unread,
May 20, 2015, 3:54:35 PM5/20/15
to ansible...@googlegroups.com
Yes, I have that stuff in my group_vars/all and in various vars.yml files. There no special magic to it except that you have to enable the do extension in ansible.cfg.

Every string variable in Ansible is fed through the templating engine:

---

foobar_config_path
: "/etc/foobar"

foobar_foomatic_file
: "{{ foobar_config_path }}/foomatic.conf"

greeting
: "Hello {% for host in groups['all'] %}{{ host }}, {% endfor %} and everybody else!"

block_string
: |
 
This is just a convenient YAML way for assigning multi-line strings to a variable,
  possibly
with {{ 'splendid' if datacenter_location == 'UK' else 'awesome' }} magic
  embedded
in it...

Javeria Khan

unread,
May 20, 2015, 4:35:47 PM5/20/15
to ansible...@googlegroups.com
Right thanks guys. And what about using a condition that checks if my_dict contains a entry with name == name2 ? Its not a loop, just a conditional for file include so I need a one liner.


Reply all
Reply to author
Forward
0 new messages