hostvars in only_if

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:

  • 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’).
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

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:
  - action: template src=templates/openvpn-server-ccd.conf
dest=/home/ansible/ccd/$item
    with_items: ${groups.physical}
    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

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

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

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.

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? :wink: 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 :wink:

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? :wink:

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