variables and their (multiple layer) resolution

I have a playbook, and in one of the templates I need to walk over all the hosts in certain groups grabbing their hostvars etc.

I followed http://docs.ansible.com/faq.html and everything seems to work as expected but with one quirk:

In template I have:

{% for host in groups[‘nova’] %}
{% set myvars=hostvars[host] %}




{% endfor %}

in group_vars/nova.yml I have:


service_admin_ip: 192.168.0.138
service_public_ip: “{{ ansible_default_ipv4.address }}”
service_internal_ip: “{{ ansible_default_ipv4.address }}”

service_region: RegionOne

so as a result I get:

Note that service_public_ip did not get resolved as expected (even though facts were collected for that host already), and service_admin_ip works fine when I hardcode it and don’t use facts. Is there a way to get around this issue? I do not want to drop ansible_default_ipv4 stuff into the role’s playbook but prefer to keep it “configurable” with some sane default (default_ipv4). What am I missing in this?

P.S.
I have some other plays where group_vars/all.yml defines vars in similar fashion (referencing some of the facts) and those work just fine.

Shall I assume that below is a bug?

Looks like it’s some sort of problem with templates, consider this simplified playbook:

roles/keystone/tasks/main.yml:

Dmitry Makovey <droopy4096@gmail.com> napisał:

Looks like it's some sort of problem with templates, consider this
simplified playbook:

roles/keystone/tasks/main.yml:

---

- name: test template
template: src=template.j2 dest=/tmp/template.txt

- name: test simple var
debug: var=simple_var

- name: test nested var
debug: var=nested_var

- name: test fact var
debug: var=fact_var

and roles/keystone/templates/templatej.j2:
-------
{{ simple_var }}
{{ nested_var }}
{{ fact_var }}

Var extraction:

{% for h in groups['keystone'] %}
{% set myvars=hostvars[h] %}
{{ myvars.simple_var }}
{{ myvars.nested_var }}
{{ myvars.fact_var }}
{% endfor %}

-------

the playbook output is as expected - vars all rendered properly ,
however
templates are not so clean:
-------
Simple var
Simple var
192.168.0.138

Var extraction:

  Simple var
{{simple_var}}
{{ansible_default_ipv4.address}}

-------

as you can see when iterating over hosts from the group for some reason

vars are not being resolved as expected.

The reason is: multiple layers of resolution are implemented as a magic dictionary that renders the variables on access. For some reason it explicitly ignores fancy dictionaries, and hostvars is one of those (it has some magic for caching).
I think it's a bug, but that should be decided by devs. Still, filling an issue should be OK :slight_smile:

There was a ticket raised (possibly by you) recently that recursion in Jinja2 templates does not appear to be a thing. Since I think that’s filed already, we should be good to go, but I would consider this as something that should work.

As an alternative, if you put the variable name directly in the template, or use the “set_fact” module to assign the variable to a new name, you should be ok.

There was a ticket raised (possibly by you) recently that recursion in Jinja2 templates does not appear to be a thing. Since I think that’s filed already, we should be good to go, but I would consider this as something that should work.

yes, I did file a ticket ( https://github.com/ansible/ansible/issues/7799 ) as I was digging deeper into this issue it felt more and more like a bug, but I was hoping it was just me {ab,mis}using it.

As an alternative, if you put the variable name directly in the template, or use the “set_fact” module to assign the variable to a new name, you should be ok.

thanks for the tip - I did test this workaround and it works, albeit it puts quite a few extra items in a playbook to work around the issue. Just for posterity trick like that worked for me so far:

prepend to site.yml …

  • hosts: keystone
    tasks:
  • set_fact: nested_var={{ nested_var }}

makes variable resolution inside Jinja template consistent with resolution in playbook. Ain’t pretty but it works.

Bonus question: can I write above statement using “with_items” so at least I don’t have to copy-paste entire stanza and only have to enumerate var names? (my guess is “no” but hey, maybe I’m wrong?)

“Bonus question: can I write above statement using “with_items” so at least I don’t have to copy-paste entire stanza and only have to enumerate var names? (my guess is “no” but hey, maybe I’m wrong?)”

This seems to be another topic, so let’s start a new thread on that, though seems easy for you to try first and maybe post if it’s not :slight_smile:

It was discussed recently that in templates variables were not being recursive as they should be.

This is something we will look into.