# vars in tasks

**URL:** <https://forum.ansible.com/t/vars-in-tasks/12885>\
**Category:** Ansible Project\
**Tags:** ansible-project\
**Created:** [May 30, 2013, 1:48pm UTC](https://forum.ansible.com/t/vars-in-tasks/12885 "2013-05-30T13:48:14Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![Michael\_DeHaan2](https://avatars.discourse-cdn.com/v4/letter/m/da6949/32.png) [@Michael\_DeHaan2](https://forum.ansible.com/u/Michael_DeHaan2)\
**Post date:** [May 30, 2013, 1:48pm UTC](https://forum.ansible.com/t/vars-in-tasks/12885/1 "2013-05-30T13:48:14Z")

</div>

This is definitely what parameterized roles (or even task includes) are intended for.

And no, you can’t pass in variables to templates like this.

You can use the ‘set\_fact’ module however to change the values of variables if you need to, but I’d be inclined to use a parameterized task or role.

–Michael

---

<div class="post-metadata">

**Author:** ![Bryan\_Larsen](https://avatars.discourse-cdn.com/v4/letter/b/9de053/32.png) [@Bryan\_Larsen](https://forum.ansible.com/u/Bryan_Larsen)\
**Post date:** [May 30, 2013, 1:58pm UTC](https://forum.ansible.com/t/vars-in-tasks/12885/2 "2013-05-30T13:58:01Z")

</div>

The point is that both files are part of the same unit – they’d never be done in isolation, so using a parametrized role would definitely break encapsulation.

But a parametrized include should work since the task files inside a role are not intended to be run separately. It’s slightly more awkward than the example I gave, but not bad.

thanks,  
Bryan

---

<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 30, 2013, 3:11pm UTC](https://forum.ansible.com/t/vars-in-tasks/12885/3 "2013-05-30T15:11:29Z")

</div>

something like this should work for you:

- template: src=templ.j2 dest=dest{{item.suffix}}  
with\_items:
- { var: foo, suffix: 1}
- { var: bar, suffix: 2}

inside the template you need to use item.var instead of var

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan2](https://avatars.discourse-cdn.com/v4/letter/m/da6949/32.png) [@Michael\_DeHaan2](https://forum.ansible.com/u/Michael_DeHaan2)\
**Post date:** [May 30, 2013, 5:50pm UTC](https://forum.ansible.com/t/vars-in-tasks/12885/4 "2013-05-30T17:50:51Z")

</div>

One of the goals of Ansible is to not make sure there are a lot of idioms to remember.

I think it would be conceptually more interesting to allow any arbitrary variables fed to the template module to be accepted into the variable namespace, but the downside is if you typo something like owner=username as ownr=username it doesn’t do what you want.

Given this is the first time I’ve seen a request for this, I’m inclined to say we don’t add anything just yet.

I’m really curious as to the underlying use case and why you are templating the file differently but reusing the template, but yet it’s not a role.

---

<div class="post-metadata">

**Author:** ![Bryan\_Larsen](https://avatars.discourse-cdn.com/v4/letter/b/9de053/32.png) [@Bryan\_Larsen](https://forum.ansible.com/u/Bryan_Larsen)\
**Post date:** [May 31, 2013, 2:02pm UTC](https://forum.ansible.com/t/vars-in-tasks/12885/5 "2013-05-31T14:02:11Z")

</div>

I thought task includes were working well for me, but I ran into another problem.

Here’s what I’ve got:

- include: template.yml listenPort=80 file=clara.conf socketPort={{ socket.port }} dev={{ env.development }}
- include: template.yml listenPort=4080 file=clara-test.conf port=4105 socketPort=10085 hostname=clara-test.local dev= test=true  
when: env.development

The first line shouldn’t have to include socketPort={{ socket.port}}, but I had to do that because I couldn’t put something like socket={port: 4105} on the second line.

It works well for socketPort, but the same trick doesn’t work for the other variable, which is a boolean. I thought I had it figured out:

- include: template.yml listenPort=80 file=clara.conf socketPort={{ socket.port }} dev={{ env.development|default(‘’, true) }}

but that throws the error

File “/exo/ansible/lib/ansible/playbook/play.py”, line 280, in \_load\_tasks  
(k,v) = t.split(“=”, 1)  
ValueError: need more than 1 value to unpack

I worked around the problem by using a string comparison in the template.

---

<div class="post-metadata">

**Author:** ![Bryan\_Larsen](https://avatars.discourse-cdn.com/v4/letter/b/9de053/32.png) [@Bryan\_Larsen](https://forum.ansible.com/u/Bryan_Larsen)\
**Post date:** [May 31, 2013, 2:04pm UTC](https://forum.ansible.com/t/vars-in-tasks/12885/6 "2013-05-31T14:04:17Z")

</div>

> I’m really curious as to the underlying use case and why you are templating the file differently but reusing the template, but yet it’s not a role.

We’re using ansible to deploy to vagrant & to production. For vagrant, the same service is available on two different ports with two slightly different configurations.

Bryan

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan2](https://avatars.discourse-cdn.com/v4/letter/m/da6949/32.png) [@Michael\_DeHaan2](https://forum.ansible.com/u/Michael_DeHaan2)\
**Post date:** [May 31, 2013, 2:15pm UTC](https://forum.ansible.com/t/vars-in-tasks/12885/7 "2013-05-31T14:15:50Z")

</div>

Ok in this case, you don’t want to use two different tasks in the same playbook.

What you should do is put your production hosts in one group and your vagrant hosts in another group, and then specify the ports or other variables in group\_vars. (You could also pass in the name of a variable file for vars\_files with -e, like “-e mode=production”) and then:

vars\_files:

- “vars/{{ mode }}.yml”

# assumes 1.2 syntax

But I like group\_vars better.

The template can also leverage conditionals in Jinja2 for slightly different configurations.

---

<div class="post-metadata">

**Author:** ![Bryan\_Larsen](https://avatars.discourse-cdn.com/v4/letter/b/9de053/32.png) [@Bryan\_Larsen](https://forum.ansible.com/u/Bryan_Larsen)\
**Post date:** [May 31, 2013, 2:22pm UTC](https://forum.ansible.com/t/vars-in-tasks/12885/8 "2013-05-31T14:22:44Z")

</div>

There are several reasons why that doesn’t work.

1: the values for the first file are already coming from a file in the group\_vars directory. It’s the second file that has to be different.

2: I want to use the same template for the second file. DRY means that nobody will forget to update one template file and not the other.

3: the group\_vars file is generated from the conf.json file that our service uses to configure itself.

Bryan

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan2](https://avatars.discourse-cdn.com/v4/letter/m/da6949/32.png) [@Michael\_DeHaan2](https://forum.ansible.com/u/Michael_DeHaan2)\
**Post date:** [May 31, 2013, 2:36pm UTC](https://forum.ansible.com/t/vars-in-tasks/12885/9 "2013-05-31T14:36:27Z")

</div>

I’m not seeing any reasons why it won’t work, but I’ll share some more details…

Answer to question 1 – If you need different variables for group 2 you could easily set them like so:

group\_vars/prod

---

<div class="post-metadata">

**Author:** ![Bryan\_Larsen](https://avatars.discourse-cdn.com/v4/letter/b/9de053/32.png) [@Bryan\_Larsen](https://forum.ansible.com/u/Bryan_Larsen)\
**Post date:** [May 31, 2013, 2:46pm UTC](https://forum.ansible.com/t/vars-in-tasks/12885/10 "2013-05-31T14:46:56Z")

</div>

I’ll state my problem again.

production has a conf file with port 80.dev has a conf file with port 80 and another conf file with port 4080.

I want to use the same template to produce all three conf files. It’s a good rule of thumb: if dev & production use two different files, eventually somebody’s going to only update the dev file and things will break in production.

Bryan

---

<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 31, 2013, 3:34pm UTC](https://forum.ansible.com/t/vars-in-tasks/12885/11 "2013-05-31T15:34:40Z")

</div>

I normally do this with:

production  
ports:

- 80

devel  
ports:

- 90
- 8080

template

{% for port in ports %}  
listen {{port}}  
{% endfor %}

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan](https://avatars.discourse-cdn.com/v4/letter/m/c4cdca/32.png) [@Michael\_DeHaan](https://forum.ansible.com/u/Michael_DeHaan)\
**Post date:** [May 31, 2013, 3:41pm UTC](https://forum.ansible.com/t/vars-in-tasks/12885/12 "2013-05-31T15:41:34Z")

</div>

Or just have a flag that says “production” and have ifs in your template.

Also easy.

---

<div class="post-metadata">

**Author:** ![Matt\_Coddington](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Matt\_Coddington](https://forum.ansible.com/u/Matt_Coddington)\
**Post date:** [May 31, 2013, 3:43pm UTC](https://forum.ansible.com/t/vars-in-tasks/12885/13 "2013-05-31T15:43:52Z")

</div>

I think Bryan L is looking to have two separate files, not two ports in a single file… but Brian C, your reply yesterday is working for me doing a similar thing that came up this morning… i have a server that needs two files, coming from the same template, one ends up in /mysql/stage1/my.cnf and one in /mysql/stage2/my.cnf. I understand that there are different ways to model this with groups and roles, but following your advice from yesterday:

- template: src=my.cnf.j2 dest=/mysq/{{ [item.name](http://item.name) }}/my.cnf  
with\_items:
- { name: stage1, ip: 1.1.1.1, id: 5 }
- { name: stage2, ip: 2.2.2.2, id: 10 }

I had no idea that the “items” in with\_items translated into variables you could use in your templates, but it works great… i can use {{ [item.name](http://item.name) }}, {{ item.ip }} and {{ [item.id](http://item.id) }} in my template as expected.

matt

---

<div class="post-metadata">

**Author:** ![Bryan\_Larsen](https://avatars.discourse-cdn.com/v4/letter/b/9de053/32.png) [@Bryan\_Larsen](https://forum.ansible.com/u/Bryan_Larsen)\
**Post date:** [May 31, 2013, 3:47pm UTC](https://forum.ansible.com/t/vars-in-tasks/12885/14 "2013-05-31T15:47:24Z")

</div>

There are TWO files produced on dev, from the SAME template.

How do you write an if statement that takes one branch the first time and the other branch the second time, if all of the variables that you pass into the template are the same for both instantiations of the template?

That’s why I want to pass in a variable to the template from the task. So that the template knows whether it’s the first instantiation or the second.

Bryan

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan2](https://avatars.discourse-cdn.com/v4/letter/m/da6949/32.png) [@Michael\_DeHaan2](https://forum.ansible.com/u/Michael_DeHaan2)\
**Post date:** [May 31, 2013, 4:22pm UTC](https://forum.ansible.com/t/vars-in-tasks/12885/15 "2013-05-31T16:22:15Z")

</div>

Understood.

You could also consider using Jinja2 includes so that they reuse some common files.

I’m hesistant to allow templates to be parameterized due to the issue of being able to mistype a parameter that has meaning like ownre or moed and it not tell you that you mistyped the parameter.
