I'm trying to loop a dictionary through an ansible template using jinja2 to create a number of datasources but receive this error [{'msg': "AnsibleUndefinedVariable: One or more undefined variables: 'dict object' has no attribute 'value'", 'failed': True}]}
When running a debug task it does get the correct values back so I feel like my issue is in the template itself but I've been unable to figure out what I am doing wrong.
Ansible Task
- name: debug dictionary
debug: msg="{{ item.value.db_url }}"
with_dict: databases
- name: copy tomcat config files
template: src="{{ item.src }}" dest="{{ item.dest }}"
with_items:
- { src: 'context.xml.j2', dest: '/opt/tomcat/conf/context.xml'}
notify: restart tomcat
with_dict: databases
Ansible Dictionary
databases:
db1:
db_resource: jdbc/db1
db_maxidle: 50
db_maxconn: 350
db_maxwait: 10000
db_user: dbuser
db_pass: "{{ dbpass }}"
db_url: jdbc:postgresql://server:5432/dbname
db_driver: org.postgresql.Driver
Jinja2 Template
{% for items in databases %}
<resource name="{{ item.value.db_resource }}" auth="container" type="javax.sql.datasource" maxtotal="{{ item.value.db_maxconn }}" maxidle="{{ item.value.db_maxidle }}" maxwaitmillis="{{ item.value.db_maxwait }}" username="{{ item.value.db_user }}" password="{{ item.value.db_pass }}" driverclassname="{{ item.value.db_driver }}" url="{{ item.value.db_url }}" />
{% endfor %}
Debug Output
ok: [IP] => (item={'key': 'db1', 'value': {'db_maxwait': 10000, 'db_maxconn': 350, 'db_maxidle': 50, 'db_driver': 'org.postgresql.Driver', 'db_pass': u'REDACTED', 'db_resource': 'jdbc/db1', 'db_user': 'dbuser', 'db_url': 'jdbc:postgresql://server:5432/dbname'}}) => {
"item": {
"key": "db1",
"value": {
"db_driver": "org.postgresql.Driver",
"db_maxconn": 350,
"db_maxidle": 50,
"db_maxwait": 10000,
"db_pass": "REDACTED",
"db_resource": "jdbc/db1",
"db_url": "jdbc:postgresql://server:5432/db",
"db_user": "dbuser"
}
},
"msg": "jdbc:postgresql://server:5432/dbname"
}
I discovered today that using dict.values() loops over each dict element's values rather than its keys. So you should be able use something like this for your template.
{% for item in databases.values() %}
<resource name="{{ item.db_resource }}" auth="container" type="javax.sql.datasource" maxtotal="{{ item.db_maxconn }}" maxidle="{{ item.db_maxidle }}" maxwaitmillis="{{ item.db_maxwait }}" username="{{ item.db_user }}" password="{{ item.db_pass }}" driverclassname="{{ item.db_driver }}" url="{{ item.db_url }}" />
{% endfor %}
I know that it's way after the fact, but maybe somebody else searching for this answer can make use of this additional discovery.
You can achieve your goal by modifying your jinja2 template and task like this:
Jinja2 Template:
<resource name="{{ databases[item].db_resource }}" auth="container" type="javax.sql.datasource" maxtotal="{{ databases[item].db_maxconn }}" maxidle="{{ databases[item].db_maxidle }}" maxwaitmillis="{{ databases[item].db_maxwait }}" username="{{ databases[item].db_user }}" password="{{ databases[item].db_pass }}" driverclassname="{{ databases[item].db_driver }}" url="{{ databases[item].db_url }}" />
Ansible Tasks:
- name: debug dictionary
debug: msg="{{ databases[item].db_url }}"
with_items: "{{ databases | list }}"
- name: copy tomcat config files
template: src="{{ item.src }}" dest="{{ item.dest }}"
with_items:
- { src: 'context.xml.j2', dest: '/opt/tomcat/conf/context.xml'}
notify: restart tomcat
with_items: "{{ databases | list }}"
Hope that might help you, please adjust your tasks as per your requirement
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With