# Append to lists

**URL:** <https://forum.ansible.com/t/append-to-lists/15234>\
**Category:** Ansible Project\
**Created:** [May 14, 2014, 5:04pm UTC](https://forum.ansible.com/t/append-to-lists/15234 "2014-05-14T17:04:54Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Martin\_Devlin](https://avatars.discourse-cdn.com/v4/letter/m/9fc29f/32.png) [@Martin\_Devlin](https://forum.ansible.com/u/Martin_Devlin)\
**Post date:** [May 14, 2014, 5:04pm UTC](https://forum.ansible.com/t/append-to-lists/15234/1 "2014-05-14T17:04:54Z")

</div>

Why can't I append to a list so that items in different group\_vars, for example, can stack up in the same list depending on which inventory groups a node is a member of.

E.g:

group\_vars/chocolate includes:

sauces:

&nbsp;&nbsp;-name : chocolate  
&nbsp;&nbsp;&nbsp;value: yummy

group\_vars/strawberry includes:

sauces:

&nbsp;&nbsp;-name : strawberry  
&nbsp;&nbsp;&nbsp;value: more\_yummy

So that in some task I can use sauces to iterate over both?

Using ansible 1.6.0

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [May 14, 2014, 10:19pm UTC](https://forum.ansible.com/t/append-to-lists/15234/2 "2014-05-14T22:19:35Z")

</div>

hash\_behavior merge would merge hashes, though in your case, what you have is a list of hashes.

Thus hash\_behavior doesn’t apply.

---

<div class="post-metadata">

**Author:** ![Martin\_Devlin](https://avatars.discourse-cdn.com/v4/letter/m/9fc29f/32.png) [@Martin\_Devlin](https://forum.ansible.com/u/Martin_Devlin)\
**Post date:** [May 15, 2014, 5:16am UTC](https://forum.ansible.com/t/append-to-lists/15234/3 "2014-05-15T05:16:27Z")

</div>

Thanks, so is there no way to do this at the moment?

Why I want to this:

I have several kinds of web site definitions and in production they live on separate nodes. However in dev/test I want the same node to host them on and I want to use the combined list in a with\_nested. But I can quite easily think of many other applications for this. I just want to be sure it's not supported at the moment and if there's a reason I shouldn't be trying to do it like this.

---

<div class="post-metadata">

**Author:** ![Martin\_Devlin](https://avatars.discourse-cdn.com/v4/letter/m/9fc29f/32.png) [@Martin\_Devlin](https://forum.ansible.com/u/Martin_Devlin)\
**Post date:** [May 15, 2014, 6:12am UTC](https://forum.ansible.com/t/append-to-lists/15234/4 "2014-05-15T06:12:07Z")

</div>

Thanks, so is there no way to do this at the moment?

Why I want to this:

I have several kinds of web site definitions and in production they live on separate nodes. However in dev/test I want the same node to host them on and I want to use the combined list in a with\_nested. But I can quite easily think of many other applications for this. I just want to be sure it's not supported at the moment and if there's a reason I shouldn't be trying to do it like this.

---

<div class="post-metadata">

**Author:** ![drybjed](https://avatars.discourse-cdn.com/v4/letter/d/48db29/32.png) [@drybjed](https://forum.ansible.com/u/drybjed)\
**Post date:** [May 15, 2014, 6:27am UTC](https://forum.ansible.com/t/append-to-lists/15234/5 "2014-05-15T06:27:06Z")

</div>

Here’s my solution with nginx (role: [https://github.com/ginas/ginas/tree/master/playbooks/roles/nginx](https://github.com/ginas/ginas/tree/master/playbooks/roles/nginx)).

My websites are defined as hashes in inventory variables, like this:

inventory\_nginx\_site1:  
default: False  
name: ‘subdomain.{{ ansible\_domain }}’  
root: ‘/path/to/website’

inventory\_nginx\_site2:  
default: False  
name: ‘othersite.(( ansible\_domain }}’  
root: ‘/other/site’

And my nginx role operates on lists of hashes, so in inventory I can do this:

nginx\_servers:

- ‘{{ nginx\_server\_default }}’
- ‘{{ inventory\_nginx\_site1 }}’
- ‘{{ inventory\_nginx\_site2 }}’

This way I can use default server defined by a role for given host, and add additional websites as subdomains of that host (or I could replace default website entirely, of I want to, either by omitting or rewriting ‘nginx\_server\_default’ hash (it is defined in nginx/defaults/main.yml). I can also define ‘nginx\_servers’ multiple times, for example in other roles vars/ directory, and make nginx manage their websites (I do that with phpMyAdmin, GitLab, ownCloud and others - you can look in that roles for example usage).

---

<div class="post-metadata">

**Author:** ![Serge\_van\_Ginderacht](https://avatars.discourse-cdn.com/v4/letter/s/b782af/32.png) [@Serge\_van\_Ginderacht](https://forum.ansible.com/u/Serge_van_Ginderacht)\
**Post date:** [May 15, 2014, 6:59am UTC](https://forum.ansible.com/t/append-to-lists/15234/6 "2014-05-15T06:59:13Z")

</div>

If you enable the hash\_merge behaviour, you can (ab)use hashes:

group\_vars/chocolate::

sauces:  
chocolate:

- name : chocolate  
value : yummy

group\_vars/strawberry:

sauces:  
strawberry:

- name : strawberry  
value : even\_yummier

And then iterate over sauces.values()  
(You’d probably need to use with\_flattened in this case)

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [May 15, 2014, 11:27am UTC](https://forum.ansible.com/t/append-to-lists/15234/7 "2014-05-15T11:27:43Z")

</div>

Correct, the issue was the OP did not have a hash to start with, but a list.

---

<div class="post-metadata">

**Author:** ![Martin\_Devlin](https://avatars.discourse-cdn.com/v4/letter/m/9fc29f/32.png) [@Martin\_Devlin](https://forum.ansible.com/u/Martin_Devlin)\
**Post date:** [May 15, 2014, 12:41pm UTC](https://forum.ansible.com/t/append-to-lists/15234/8 "2014-05-15T12:41:38Z")

</div>

Thanks everyone. I think what I was after was confirmation that appending lists in this fashion wasn't supported and it seems it isn't. Maciej Delmanowski's suggestion looks like a viable workaround though so I'll give it a go.

Apologies for the duplicate post in the first instance, Michael

---

<div class="post-metadata">

**Author:** ![Smoothify](https://avatars.discourse-cdn.com/v4/letter/s/6a8cbe/32.png) [@Smoothify](https://forum.ansible.com/u/Smoothify)\
**Post date:** [May 15, 2014, 1:24pm UTC](https://forum.ansible.com/t/append-to-lists/15234/9 "2014-05-15T13:24:53Z")

</div>

I needed the same thing recently, and wrote an internal module that appends one list to another, similar to set\_fact.

However, after I had done so I noticed the union filter for jinja templates:  
[http://docs.ansible.com/playbooks\_variables.html#set-theory-filters](http://docs.ansible.com/playbooks_variables.html#set-theory-filters)

This means you could do probably do the following (assuming sauces is already defined somewhere as an empty list):

group\_vars/chocolate includes:

sauces\_add:

-name : chocolate  
value: yummy

sauces: “{{ sauces | union(sauces\_add) }}”

or you could even chain the merges:

sauces: “{{ sauces | union(sauces\_chocolate) | union(sauces\_strawberry) }}”

---

<div class="post-metadata">

**Author:** ![Martin\_Devlin](https://avatars.discourse-cdn.com/v4/letter/m/9fc29f/32.png) [@Martin\_Devlin](https://forum.ansible.com/u/Martin_Devlin)\
**Post date:** [May 15, 2014, 9:56pm UTC](https://forum.ansible.com/t/append-to-lists/15234/10 "2014-05-15T21:56:53Z")

</div>

I tried this but couldn't get this to work in variables files. I think union is only available in templates.

Serge van Ginderachter's suggestion is the only one I've tried that meets my requirement and it's not ideal as he admits himself.

I thought stacking variables like this would make sense; I can see quite a few uses for it in a hierarchical inventory structure, but the fact that no one has requested it as a feature suggests to me I'm approaching group\_vars in the wrong way; I'm coming to it from using hiera in puppet.

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [May 15, 2014, 9:59pm UTC](https://forum.ansible.com/t/append-to-lists/15234/11 "2014-05-15T21:59:43Z")

</div>

hiera is brain damage that comes up because Puppet didn’t really model groups and such correctly to begin with.

As for your union example above, when you can’t get something to work, say how and give examples of what you tried and what you got back. It’s the only really way we can help with questions.

Thanks!

---

<div class="post-metadata">

**Author:** ![Martin\_Devlin](https://avatars.discourse-cdn.com/v4/letter/m/9fc29f/32.png) [@Martin\_Devlin](https://forum.ansible.com/u/Martin_Devlin)\
**Post date:** [May 16, 2014, 4:41pm UTC](https://forum.ansible.com/t/append-to-lists/15234/12 "2014-05-16T16:41:25Z")

</div>

OK, thanks for persevering with this! So in group\_vars I have lists like this:

ext\_vhosts:

- name : site1  
hostname : “{{ site1\_hostname }}”  
ipaddress : “{{ site1\_ip\_address }}”  
ssl\_cn : “{{ site1\_ssl\_hostname }}”  
ssl\_key : site1.key  
ssl\_crt : site1.crt  
ssl\_pem : site1.pem  
apache\_dir : site1  
conf\_file : site1.conf

- name : site2  
hostname : “{{ site2\_hostname }}”  
ipaddress : “{{ site2\_ip\_address }}”  
ssl\_cn : “{{ site2\_ssl\_hostname }}”  
ssl\_key : site2.key  
ssl\_crt : site2.crt  
ssl\_pem : site2.pem  
apache\_dir : site2d  
conf\_file : site2d.conf

int\_vhosts:

- name : site3  
hostname : “{{ site3\_hostname }}”  
ipaddress : “{{ site3\_ip\_address }}”  
ssl\_cn : “{{ site3\_ssl\_hostname }}”  
ssl\_key : site3.key  
ssl\_crt : site3.crt  
ssl\_pem : site3.pem  
apache\_dir : site3  
conf\_file : site3.conf

- name : site4  
hostname : “{{ site4\_hostname }}”  
ipaddress : “{{ site4\_ip\_address }}”  
ssl\_cn : “{{ site4\_ssl\_hostname }}”  
ssl\_key : site4.key  
ssl\_crt : site4.crt  
ssl\_pem : site4.pem  
apache\_dir : site4d  
conf\_file : site4d.conf

etc…

I can use ext\_vhosts and int\_vhosts just fine, I just can’t join them together.

The test case is as simple as:

debug : msg=“{{ vhosts }}”

So this in the /defaults/main.yml:

vhosts :   
vhosts : "{{ vhosts|union(ext\_vhosts)|union(int\_vhosts) }}

Yields an empty list

vhosts : “{{ vhosts|union(ext\_vhosts) }}”  
vhosts : “{{ vhosts|union(int\_vhosts) }}”"

Yields an empty list

In both cases debug : msg=“{{ ext\_vhosts }}” shows the expected values.

If I put the same structures in vars/main.yml I get “an unexpected type error occured. Error was unhashable type: ‘dict’”

If I put the union statements in the respective group\_vars files I get “recursive loop detected in template string {{vhosts|union(ext\_vhosts)}}”

I hope it’s just a case of putting them in a different file or that there’s just a bit of missing syntax somewhere.

---

<div class="post-metadata">

**Author:** ![Martin\_Devlin](https://avatars.discourse-cdn.com/v4/letter/m/9fc29f/32.png) [@Martin\_Devlin](https://forum.ansible.com/u/Martin_Devlin)\
**Post date:** [May 16, 2014, 5:04pm UTC](https://forum.ansible.com/t/append-to-lists/15234/13 "2014-05-16T17:04:49Z")

</div>

Apologies, the empty list outcomes are when I have left a vhosts : knocking about somewhere. The error is in fact the same in all cases:

“recursive loop detected in template string”

---

<div class="post-metadata">

**Author:** ![Brian\_Coca1](https://avatars.discourse-cdn.com/v4/letter/b/278dde/32.png) [@Brian\_Coca1](https://forum.ansible.com/u/Brian_Coca1)\
**Post date:** [May 16, 2014, 5:43pm UTC](https://forum.ansible.com/t/append-to-lists/15234/14 "2014-05-16T17:43:25Z")

</div>

​create new vars, not a self referencing one

---

<div class="post-metadata">

**Author:** ![Martin\_Devlin](https://avatars.discourse-cdn.com/v4/letter/m/9fc29f/32.png) [@Martin\_Devlin](https://forum.ansible.com/u/Martin_Devlin)\
**Post date:** [May 16, 2014, 6:22pm UTC](https://forum.ansible.com/t/append-to-lists/15234/15 "2014-05-16T18:22:46Z")

</div>

Yes I imagine the problem with union is that a list can't union with itself. I could try:

dummy :

vhosts : "{{ dummy|union(ext\_hosts)etc...

---

<div class="post-metadata">

**Author:** ![Brian\_Coca1](https://avatars.discourse-cdn.com/v4/letter/b/278dde/32.png) [@Brian\_Coca1](https://forum.ansible.com/u/Brian_Coca1)\
**Post date:** [May 16, 2014, 6:27pm UTC](https://forum.ansible.com/t/append-to-lists/15234/16 "2014-05-16T18:27:53Z")

</div>

I'm not sure why you need an empty list to start, am I missing something?

---

<div class="post-metadata">

**Author:** ![Brian\_Coca1](https://avatars.discourse-cdn.com/v4/letter/b/278dde/32.png) [@Brian\_Coca1](https://forum.ansible.com/u/Brian_Coca1)\
**Post date:** [May 16, 2014, 6:29pm UTC](https://forum.ansible.com/t/append-to-lists/15234/17 "2014-05-16T18:29:30Z")

</div>

I would write it this way:

vhosts : “{{ ext\_vhosts|union(int\_vhosts) }}”  
​

---

<div class="post-metadata">

**Author:** ![Martin\_Devlin](https://avatars.discourse-cdn.com/v4/letter/m/9fc29f/32.png) [@Martin\_Devlin](https://forum.ansible.com/u/Martin_Devlin)\
**Post date:** [May 16, 2014, 8:39pm UTC](https://forum.ansible.com/t/append-to-lists/15234/18 "2014-05-16T20:39:24Z")

</div>

Of course, thanks. I'll give it a go on Monday.

Thanks again everyone for your help.

---

<div class="post-metadata">

**Author:** ![Martin\_Devlin](https://avatars.discourse-cdn.com/v4/letter/m/9fc29f/32.png) [@Martin\_Devlin](https://forum.ansible.com/u/Martin_Devlin)\
**Post date:** [May 16, 2014, 8:56pm UTC](https://forum.ansible.com/t/append-to-lists/15234/19 "2014-05-16T20:56:23Z")

</div>

I still think having the ability to append to lists is a valid use case for a roles-orientated solution.

Consider the examples of packages or iptables or sudoers permissions. Lists are the obvious way to express these. So:

You have a base role for your organisation specifying common requirements. In addition you have specific requirements for particular roles. Moreover, in some circumstances, you might want nodes to be multi-roled.

The ability to append to lists in the way I've described frees you from having to consider, a priori, which set of these requirements a given task will have to address. The tasks can concentrate simply on applying the requirements, leaving the user free to define them in whatever (possibly dumb) way they see fit.

This is constructive feedback; I really like the product and will choose it over puppet every time from now given the choice.

---

<div class="post-metadata">

**Author:** ![Brian\_Coca1](https://avatars.discourse-cdn.com/v4/letter/b/278dde/32.png) [@Brian\_Coca1](https://forum.ansible.com/u/Brian_Coca1)\
**Post date:** [May 16, 2014, 9:05pm UTC](https://forum.ansible.com/t/append-to-lists/15234/20 "2014-05-16T21:05:19Z")

</div>

have you tried vhosts.appen(ext\_hosts)?​ i don’t know if that works but it would be built in if jinja2 allows it

[Next page](https://forum.ansible.com/t/append-to-lists/15234.md?page=2)
