Merging/extending List of Dicts?

93 views
Skip to first unread message

Nico K.

unread,
Mar 30, 2015, 8:58:07 AM3/30/15
to ansible...@googlegroups.com
Hi guys,

I'm trying to configure an EC2 Security Group using Ansible, since all of my security groups contain a set of 'base rules', I'm trying to split that portion out to avoid duplication.
To do so I have:

base_rules: [
                   { proto: ...
                   , from_port: ...
                   ...
                   },
                   { proto: ...
                   ...
                   ]

Which works fine on it's own, I have however been unable to add entries to it, or to pass in multiple lists of dicts to ec2_groups.
What I've tried is:

'{{ base_rules }} + {{ group_rules }}'  # whereby group_rules is defined similar to base_rules, this does run but complains.
'{{ base_rules }} + [ <define group_rules in line> ] # same result.

Anyone has a suggestion on how to deal with this?

Thanks,
Nico.

Brian Coca

unread,
Mar 30, 2015, 9:12:30 AM3/30/15
to ansible...@googlegroups.com
try {{ base_rule|union(group_rules) }}

--
Brian Coca

Nico K.

unread,
Mar 31, 2015, 4:16:58 PM3/31/15
to ansible...@googlegroups.com
Hey Brian,

Thanks for that, works like a charm.

I did notice there are a bunch of quoting issues going on, for instance:

x:
- y: b
  z: c
- y: "{{ d }}"
  z: "{{ e }}"

Works fine, where-as defining the structure as per my initial post the variable evaluation fails ( end up with {# x.item #} or group_id's that do not evaluate.
Now I will say, the variables are defined in group_vars over a couple of different groups and are then passed in through a 'with_items' iterator in the actual role.

Anyway, it's not a real problem since defining it as above works as expected.

Thanks again for your suggestion! 
Nico







koka424

unread,
Apr 14, 2015, 12:23:01 PM4/14/15
to ansible...@googlegroups.com
What if you go a few levels deeper? Say I have different rules for "all", "location", "groupA", and "groupB". I will always have base rules for "all". I may or may not have base rules for "location", "groupA", or "groupB".

Right now I am handling it like this. I am using Ansible 1.8.2 with hash merging turned on. I have a hash in each group_var that needs it.

group_vars/all:


base_rule
:
  all
:
    rule
:
     
- rule1


group_vars
/location:


base_rule
:
  location
:
    rule
:
     
- rule2


group_vars
/groupB:


base_rule
:
  groupB
:
    rule
:
     
- rule3

Then when I want to call them in a task I would do so like this:

- name: echo base rules
  shell
: /usr/bin/echo item.1
  with_subelements
:
   
- base_rule
   
- rule

In a jinja template I would use:

{% for key, value in base_rule.items() %}
{% for key, a in value.iteritems() %}
{% for rule in a %}
{{ rule }}
{% endfor %}
{% endfor %}
{% endfor %}

I was wondering if there were a better way do accomplish this. If I were to use union I would have to list out ever possible instance of the hash that I am trying to merge right? Something like:

{{ base_rule|union(location_rules)|union(groupA_rules)|union(groupB_rules) }}

Or is there a way to accomplish this without listing each hash that needs to be joined?

Thanks,

John
Reply all
Reply to author
Forward
0 new messages