Loop dictionary in ansible template
Solution 1
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
Solution 2
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.
Solution 3
In Jinja, when databases
is a dictionary, for items in databases
will (as in Python) iterate over the keys of the dictionary, not its key/value pairs. Thus, in your template, item.value
(which I'm assuming is meant to be items.value
) should be databases[items]
in order to get the value associated with the key items
.
Solution 4
Mike, your answer saved me a lot of searching today.
In my case I was using a list of dicts, so I had to have two if statements, something like this:
{% for dict_item in quotes %}
{% for item in dict_item.values() %}
.. {{ item.symbol }}
.. {{ item.price }}
{% endfor %}
{% endfor %}
Thank you!
tweeks200
Updated on July 09, 2022Comments
-
tweeks200 almost 2 years
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" }
-
tweeks200 almost 8 yearsThat seems to make progress. I get
One or more undefined variables: dict object has no element
now but the values do show in the error output. All the variables have values in the output. Any ideas? -
JJJ about 5 yearsPlease elaborate how your answer adds to the others, try to comment a bit in your code maybe.
-
Rick O'Shea about 2 yearsSomebody else was searching for this answer! Thanks.