Merging dictionaries for "environment" parameter

1,984 views
Skip to first unread message

Steven Ringo

unread,
Jul 31, 2014, 7:15:34 PM7/31/14
to ansible...@googlegroups.com

Hi,

I am wanting to use the environment task parameter with dictionaries taken from two roles, e.g.

in roles/ruby/vars/main.yml:

ruby_environment:
    GEM_HOME: "/home/deploy/.gem/ruby/2.1.2"
    PATH:     "/home/deploy/.gem/ruby/2.1.2/bin:/opt/rubies/ruby-2.1.2/lib/ruby/gems/2.1.0/bin:/opt/rubies/ruby-2.1.2/bin"

in roles/rails/tasks/main.yml, I am wanting to do something like this:

- name: execute bundler
  command: bundle install --deployment
  environment:
    "{{ ruby_environment }}" merged with "RAILS_ENV: production"

Is this possible?

Thanks,

Steve

Steven Ringo

unread,
Jul 31, 2014, 7:24:40 PM7/31/14
to ansible...@googlegroups.com
To add: would prefer not to use hash_behaviour = merge if possible.


Michael DeHaan

unread,
Jul 31, 2014, 7:56:39 PM7/31/14
to ansible...@googlegroups.com
I think this might be proposing something like a jinja2 filter that merges one hash with another and returns it.

I'm not aware of this, but some other folks go deeper than me.

I'm not opposed to a filter plugin function being added that does this being added if that makes sense.




On Thu, Jul 31, 2014 at 7:24 PM, Steven Ringo <goo...@stevenringo.com> wrote:
To add: would prefer not to use hash_behaviour = merge if possible.


--
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/f2468b4d-0e07-401e-8f95-fe40405d4fc7%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Steven Ringo

unread,
Jul 31, 2014, 8:00:34 PM7/31/14
to ansible...@googlegroups.com
I thought it might be possible to loop over each hash respectively and then create a new one with all of those.

Michael DeHaan

unread,
Jul 31, 2014, 8:06:11 PM7/31/14
to ansible...@googlegroups.com
That in particular, I'd think no.

What I'd really like might look something like

environment: "{{ dict1 | update(dict2) }}"

Anybody done anything like that with stock Jinja2-voodoo magic?  If not, it's about a two liner in filter_plugins/core.py to expose the native hash update function.



Brian Coca

unread,
Aug 1, 2014, 8:53:38 AM8/1/14
to ansible...@googlegroups.com
dict1 + dict2 

I also have an update to 'set theory' that will allow you to do dict1|union(dict2)

Michael DeHaan

unread,
Aug 1, 2014, 9:14:11 AM8/1/14
to ansible...@googlegroups.com
So that's a thing already with {{ dict1 + dict2 }}?  

Nice.




On Fri, Aug 1, 2014 at 8:53 AM, Brian Coca <bria...@gmail.com> wrote:
dict1 + dict2 

I also have an update to 'set theory' that will allow you to do dict1|union(dict2)

--
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.

Evgeny Goldin

unread,
Oct 24, 2014, 6:08:40 PM10/24/14
to ansible...@googlegroups.com
Not really. Python doesn't allow to merge two hashes using "{{ env1 + env2 }}". Here's what worked for me:

playbooks/filter_plugins/filters.py:

------------------------------------------------
def merge( hash_a, hash_b ):
  return dict(hash_a.items() + hash_b.items());

class FilterModule( object ):
  def filters( self ):
    return { 'merge' : merge }
------------------------------------------------

and then:

environment: "{{ env1 | merge( env2 ) }}"

Michael DeHaan

unread,
Oct 24, 2014, 8:09:22 PM10/24/14
to ansible...@googlegroups.com
I think your filter plugin could be more easily written:

hash_a.update(hash_b)

perhaps?

If you send in a pull request, this seems reasonable to have as a core filter.

I'd probably call it 'update' if I'm correct on the above, which I think I am.  If not, perhaps "merge".





Brian Coca

unread,
Oct 28, 2014, 11:36:20 PM10/28/14
to ansible...@googlegroups.com

I could swear I had patched the union filter to use update when dicts were passed in, let me try this again.

Brian Coca

kesten broughton

unread,
Nov 26, 2014, 9:57:59 AM11/26/14
to ansible...@googlegroups.com
It would be nicer to have a filter for jinja2, but this works:

defaults.yml
d1:
  k1: 1

d2:
  k1: 2
  k2: 3

tasks/main.yml
- name: dbg
  debug: msg="{{d1}}     {{d2}}"

- set_fact:
     d1: "{% do d1.update(d2) %}{{d1}}"

- debug: msg="{{d1['k1']}}"

OUTPUT

TASK: [gnf_data | dbg] ********************************************************
<deploy-test-1> ESTABLISH CONNECTION FOR USER: ubuntu
ok: [deploy-test-1] => {
    "msg": "{'k1': 1}     {'k2': 3, 'k1': 2}"
}

TASK: [gnf_data | set_fact ] **************************************************
<deploy-test-1> ESTABLISH CONNECTION FOR USER: ubuntu
ok: [deploy-test-1] => {"ansible_facts": {"d1": {"k1": 2, "k2": 3}}}

TASK: [gnf_data | debug msg="{{d1['k1']}}"] ***********************************
<deploy-test-1> ESTABLISH CONNECTION FOR USER: ubuntu
ok: [deploy-test-1] => {
    "msg": "2"

T.N. T.

unread,
Mar 16, 2015, 10:46:12 AM3/16/15
to ansible...@googlegroups.com
On Saturday, October 25, 2014 at 2:09:22 AM UTC+2, Michael DeHaan wrote:
I think your filter plugin could be more easily written:

hash_a.update(hash_b)

perhaps?

If you send in a pull request, this seems reasonable to have as a core filter.

I'd probably call it 'update' if I'm correct on the above, which I think I am.  If not, perhaps "merge".


I had exactly the same idea. Did anybody do a PR for this? I don't see it in 1.9 nor in devel.

If nobody else has time for it I could do it. I think this is really a gap. Anyway this way is definitely more what they call pythonic than tweaking the union filter. 

My code  is simply:

def update(dic, odic):
    dic
.update(odic)
   
return dic


class FilterModule(object):

    
def filters(self):
       
return {

            
'update': update,
           
'update_dict': update,
           
'merge_dict': update
       
}



Brian Coca

unread,
Mar 16, 2015, 12:01:33 PM3/16/15
to ansible...@googlegroups.com
there is a hash_merge PR pending but it won't make it into 1.9.




--
Brian Coca

T.N. T.

unread,
Mar 16, 2015, 1:09:16 PM3/16/15
to ansible...@googlegroups.com


On Monday, March 16, 2015 at 5:01:33 PM UTC+1, Brian Coca wrote:
there is a hash_merge PR pending but it won't make it into 1.9.

Looks nice. And nice to know. Thank you!

ke...@collectivehealth.com

unread,
Aug 21, 2015, 3:46:12 PM8/21/15
to Ansible Project
Looks like update doesn't do a recursive hash merge. This might be the solution, https://www.xormedia.com/recursively-merge-dictionaries-in-python/
Is the best practice be to add this as a jinja filter?

This message may contain confidential, proprietary, or protected information.  If you are not the intended recipient, you may not review, copy, or distribute this message. If you received this message in error, please notify the sender by reply email and delete this message.

vadyochik

unread,
Aug 29, 2016, 10:24:36 AM8/29/16
to Ansible Project
For version 2.0+ check this please:


"combine" filter might be what someone is searching for.

пятница, 21 августа 2015 г., 22:46:12 UTC+3 пользователь ke...@collectivehealth.com написал:
Reply all
Reply to author
Forward
0 new messages