Question:
Hello everyone. I came across a curious problem.
Input data (ansible 2.2):
- Inventory
[api]
api01.domain.tld max_fails=12 fail_timeout=70
api02.domain.tld max_fails=13 fail_timeout=70
api03.domain.tld max_fails=12 fail_timeout=70
api04.domain.tld max_fails=12 fail_timeout=70
- Template for describing nginx upstreams (the second loop is important):
{% for upstream1 in nginx_upstreams1.iteritems() %}
upstream {{ upstream1[0] }} {
{% for item in upstream1[1] %}
{{ item }};
{% endfor %}
{% for host in groups[upstream1[0]] %}
# {{ host }}
server {{ hostvars[host].ansible_eth0.ipv4.address }} ;
{{ hostvars[host].max_fails }}
{% endfor %}
}
{% endfor %}
max_fails {{ hostvars['api01.domain.tld'].max_fails }}
max_fails {{ hostvars['api02.domain.tld'].max_fails }}
- As a result, I get that
a) the code - {{ hostvars[host].max_fails }}
– produces "msg": "AnsibleUndefinedVariable: 'dict object' has no attribute 'max_fails'"
b) when I specify the hostname in hostvars with my hands, everything works out correctly ( max_fails {{ hostvars['api01.domain.tld'].max_fails }}
)
c) when I watch ad-hoc debugging output via -m debug
, or hostvars[host]
to a rendered template – max_fails
is there.
What am I doing wrong?
Answer:
I rather have a comment "on my version of ansible everything works", I am writing an answer only so that the listings are readable.
I also want you to make a fully reproducible example since some variables are missing (nginx_upstreams1) – and I had to throw them away. Perhaps this affected the execution of the script.
By the way, I do not remember if there is some kind of service variable host
but I know for sure that in all scripts I prefer to call the variable for bypassing item
. Is it possible that there is some new variable introduced in 2.2?
The script itself:
- name: http://ru.stackoverflow.com/questions/601512/
hosts: api
tasks:
- name: template nginx conf
template:
src="test.j2"
dest="/home/ansible/test.txt"
Sample:
upstream {
{% for host in groups['api'] %}
# {{ host }}
server {{ hostvars[host].ansible_eth0.ipv4.address }} ;
{{ hostvars[host].max_fails }}
{% endfor %}
}
max_fails {{ hostvars['api01.domain.tld'].max_fails }}
max_fails {{ hostvars['api02.domain.tld'].max_fails }}
Software version:
$ ansible --version
ansible 2.1.2.0
config file = /home/ak/ansible/so/601512/ansible.cfg
configured module search path = Default w/o overrides
PS And even through a variable it works:
Script:
- name: http://ru.stackoverflow.com/questions/601512/
hosts: api
vars:
group_name: "api"
tasks:
- name: debug group_name
debug: msg="{{ group_name }}"
- name: template nginx conf
template:
src="test.j2"
dest="/home/ansible/test.txt"
Sample:
upstream {
{% for host in groups['api'] %}
# {{ host }}
server {{ hostvars[host].ansible_eth0.ipv4.address }} ;
{{ hostvars[host].max_fails }}
{% endfor %}
{% for host in groups[group_name] %}
# {{ host }}
server {{ hostvars[host].ansible_eth0.ipv4.address }} ;
{{ hostvars[host].max_fails }}
{% endfor %}
}
max_fails {{ hostvars['api01.domain.tld'].max_fails }}
max_fails {{ hostvars['api02.domain.tld'].max_fails }}
PPS Likewise, no problem and around play_hosts
do a workaround: https://stackoverflow.com/questions/39005760/ansible-play-hosts-template-loop