I have the following task:
- name: copy server.xml
template: src=server.xml dest=/var/containers/{{ item.key }}/conf
with_dict: containers
And I've also added the containers dictionary in my group_vars
containers:
frontend:
http_port: 8080
backend:
http_port: 8081
Finally here is the relevant snippet from server.xml
<Connector port="{{ http_port }}" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
What I want to happen is that the relevant http_port gets used in the template module. But instead I get and error:
fatal: [localhost] => {'msg': "AnsibleUndefinedVariable: One or more undefined variables: 'http_port' is undefined", 'failed': True}
Is this possible? How do I leverage an item's values for variable substitution?
Using {{ item.value.http_port }}
is exactly the right solution.
When you pass with_dict, it loops through the task passing each of the items in your containers dictionary as {{ item }}
, where the item has a key and whatever values that dictionary item contains - in your case, key/value pairs where the keys are http_port and the values are those two different integers - but you can pass seriously complex nested dictionaries where it gets even more important to access things with the {{ item.value.http_port }}
syntax you came up with.
The thing to be wary of as you get to more complex template usage is how to mix stuff up and set defaults and use if-statements when you have some extra variables to template for one host (or container, or whatever) but not another.
To get to grips on it, read up on Jinja2, the language Ansible interprets templates in. A good example would be something like serving files over SSL on your frontend here, but not the backend. Use syntax like {{ foo | default('bar') }}
to avoid Ansible getting angry about you trying to use undefined variables, and if-statements so as to make sure you're only templating the stuff you need.
A rough sketch - say you had:
containers:
frontend:
http_port: 8080
https_port: 8443
ssl_cert: ./files/keystore
ssl_pass: "{{ vaulted_vars.ssl_pass }}"
backend:
http_port: 8081
In that case, imagining you'd had a task to copy that keystore over onto the filesystem when needed, you could use something along the lines of:
<Connector port="{{ item.value.http_port }}" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="{{ item.value.https_port | default('8443')" />
{% if item.value.ssl_cert is defined %}
scheme="https" secure="true" SSLEnabled="true"
keystoreFile="${user.home}/.keystore" keystorePass="{{ item.value.ssl_pass }}"
clientAuth="false" sslProtocol="TLS"/>
{% endif %}
Happy templating!
来源:https://stackoverflow.com/questions/26020465/ansible-with-dict-template-use