# hostvars in only\_if

**URL:** <https://forum.ansible.com/t/hostvars-in-only-if/11998>\
**Category:** Ansible Project\
**Created:** [October 18, 2012, 5:02pm UTC](https://forum.ansible.com/t/hostvars-in-only-if/11998 "2012-10-18T17:02:39Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Grzegorz\_Nosek](https://avatars.discourse-cdn.com/v4/letter/g/5daacb/32.png) [@Grzegorz\_Nosek](https://forum.ansible.com/u/Grzegorz_Nosek)\
**Post date:** [October 18, 2012, 5:02pm UTC](https://forum.ansible.com/t/hostvars-in-only-if/11998/1 "2012-10-18T17:02:39Z")

</div>

Hello again,

I have the following inventory:

[physical]  
[somehost.example.com](http://somehost.example.com) vpn\_ip=10.0.1.1  
[anotherhost.example.com](http://anotherhost.example.com) vpn\_ip=10.0.2.1

[differenthost.example.com](http://differenthost.example.com)

and a task:

hosts: vpn\_hub.example.com  
tasks:

- action: template src=templates/openvpn-server-ccd.conf dest=/home/ansible/ccd/$item  
with\_items: ${groups.physical}  
only\_if: “$hostvars[‘$item’][‘vpn\_ip’]”

Right now ansible explodes while trying to evaluate the only\_if condition (KeyError: ‘[somehost.example.com](http://somehost.example.com)’).  
Is it possible to somehow limit the rule to only generate configs for hosts that have the vpn\_ip variable set, or should I make a dedicated group for that? My inventory is actually a script so that’s not too big a deal, but I’d rather keep this logic in one place. Accessing {{ hostvars[item].vpn\_ip }} in the template works fine and I feel I’m 99% there, I just get redundant files for hosts without vpn\_ip set.

BTW, is there some documentation about how only\_if actually works, i.e. what’s the exact format ($foo isn’t really Python) and what are the available variables?

Thanks,  
Grzegorz Nosek

---

<div class="post-metadata">

**Author:** ![Daniel\_Hokka\_Zakriss](https://avatars.discourse-cdn.com/v4/letter/d/f05b48/32.png) [@Daniel\_Hokka\_Zakriss](https://forum.ansible.com/u/Daniel_Hokka_Zakriss)\
**Post date:** [October 18, 2012, 5:10pm UTC](https://forum.ansible.com/t/hostvars-in-only-if/11998/2 "2012-10-18T17:10:37Z")

</div>

Grzegorz Nosek wrote:

> Hello again,
> 
> I have the following inventory:
> 
> [physical]  
> somehost.example.com vpn\_ip=10.0.1.1  
> anotherhost.example.com vpn\_ip=10.0.2.1  
> differenthost.example.com
> 
> and a task:
> 
> hosts: vpn\_hub.example.com  
> tasks:  
> &nbsp;&nbsp;- action: template src=templates/openvpn-server-ccd.conf  
> dest=/home/ansible/ccd/$item  
> &nbsp;&nbsp;&nbsp;&nbsp;with\_items: ${groups.physical}  
> &nbsp;&nbsp;&nbsp;&nbsp;only\_if: "$hostvars['$item']['vpn\_ip']"

What you want is  
only\_if: is\_set('${hostvars.{$item}.vpn\_ip}')  
as what you presently have will expand the list and then access variables.

> Right now ansible explodes while trying to evaluate the only\_if condition  
> (KeyError: 'somehost.example.com').  
> Is it possible to somehow limit the rule to only generate configs for  
> hosts  
> that have the vpn\_ip variable set, or should I make a dedicated group for  
> that? My inventory is actually a script so that's not too big a deal, but  
> I'd rather keep this logic in one place. Accessing {{  
> hostvars[item].vpn\_ip  
> }} in the template works fine and I feel I'm 99% there, I just get  
> redundant files for hosts without vpn\_ip set.
> 
> BTW, is there some documentation about how only\_if actually works, i.e.  
> what's the exact format ($foo isn't really Python) and what are the  
> available variables?

It is the regular ansible variable replacement, followed by being  
evaluated by Python. Same variables are available as for your everywhere  
else you'd use a variable.

Daniel

---

<div class="post-metadata">

**Author:** ![Grzegorz\_Nosek](https://avatars.discourse-cdn.com/v4/letter/g/5daacb/32.png) [@Grzegorz\_Nosek](https://forum.ansible.com/u/Grzegorz_Nosek)\
**Post date:** [October 18, 2012, 5:39pm UTC](https://forum.ansible.com/t/hostvars-in-only-if/11998/3 "2012-10-18T17:39:18Z")

</div>

W dniu 18.10.2012 19:10, Daniel Hokka Zakrisson pisze:

> What you want is  
> only\_if: is\_set('${hostvars.{$item}.vpn\_ip}')  
> as what you presently have will expand the list and then access variables.

Does this handle dots in $item? All the hosts are skipped if I use this.

> It is the regular ansible variable replacement, followed by being  
> evaluated by Python. Same variables are available as for your everywhere  
> else you'd use a variable.

Thanks, I guess I'll just have to get used to it, doesn't feel natural  
to me right now (why not e.g. jinja snippets?).

Best regards,  
Grzegorz Nosek

---

<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:** [October 18, 2012, 5:43pm UTC](https://forum.ansible.com/t/hostvars-in-only-if/11998/4 "2012-10-18T17:43:12Z")

</div>

only\_if is completely unnatural and is being used to levels I really  
didn't imagine people would try.

In order to eliminate the need for people to write lines of things  
that are essentially code in their playbooks, the 'when' operator is  
coming in 0.9 -- and needs to be able to completely handle these kinds  
of use cases.

As for no Jinja, well, we don't want to template the whole playbook --  
that's kind of gross and defeats the purpose of configuration being  
data.

Plus, it leads to a lot of gross abuses and eventually you start  
shooting yourself in the foot. We used to allow Jinja2 inside of  
individual template calls, but we removed that because it ended up  
being pretty slow, and again, abused often.

I guess understand that only\_if is unintuitive, sure, but when the  
'when' operator is available, that will result internally as an  
'only\_if' and you can replace all of it if you want with something a  
lot more human friendly

---

<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:** [October 18, 2012, 5:44pm UTC](https://forum.ansible.com/t/hostvars-in-only-if/11998/5 "2012-10-18T17:44:37Z")

</div>

Some uses of only\_if I really do like, BTW, are the simple ones:

only\_if: $last\_result.changed

only\_if: '$last\_result.rc == 2'

I think trying to do complicated things with it is often a sign of a  
modelling problem that implies playbooks should be arranged  
differently, though not in all cases.

---

<div class="post-metadata">

**Author:** ![Grzegorz\_Nosek](https://avatars.discourse-cdn.com/v4/letter/g/5daacb/32.png) [@Grzegorz\_Nosek](https://forum.ansible.com/u/Grzegorz_Nosek)\
**Post date:** [October 18, 2012, 6:05pm UTC](https://forum.ansible.com/t/hostvars-in-only-if/11998/6 "2012-10-18T18:05:10Z")

</div>

W dniu 18.10.2012 19:43, Michael DeHaan pisze:

> only\_if is completely unnatural and is being used to levels I really  
> didn't imagine people would try.

Does my case count as weird, too? 😉 I'm mostly curious, as currently I  
just generate another group and put the relevant hosts there. But yeah,  
I'd like to remove policy from my hosts file too (and leave just the  
interface to the one true source of host info).  
hostvars['any\_host\_at\_all'] from current devel is great, BTW.

> In order to eliminate the need for people to write lines of things  
> that are essentially code in their playbooks, the 'when' operator is  
> coming in 0.9 -- and needs to be able to completely handle these kinds  
> of use cases.

What is it going to do? It's kind of hard to google for 😉

FWIW, the other type of conditions I'm using is unfortunately embedded  
in shell (grep foo /etc/bar || do\_something\_to\_etc\_bar, not really a  
lineinfile nor creates=/etc/bar)

> As for no Jinja, well, we don't want to template the whole playbook --  
> that's kind of gross and defeats the purpose of configuration being  
> data.
> 
> Plus, it leads to a lot of gross abuses and eventually you start  
> shooting yourself in the foot. We used to allow Jinja2 inside of  
> individual template calls, but we removed that because it ended up  
> being pretty slow, and again, abused often.

Yeah, I guess you're right.

BTW, should I feel bad for wanting template str="{{ foo }}"  
dest=/some/where.conf earlier today? 😉

> I guess understand that only\_if is unintuitive, sure, but when the  
> 'when' operator is available, that will result internally as an  
> 'only\_if' and you can replace all of it if you want with something a  
> lot more human friendly

Can't wait to see "when" then.

Best regards,  
Grzegorz Nosek
