J'essaie de boucler un dictionnaire via un modèle ansible en utilisant jinja2 pour créer un certain nombre de sources de données, mais je reçois cette erreur [{'msg': "AnsibleUndefinedVariable: One or more undefined variables: 'dict object' has no attribute 'value'", 'failed': True}]}
Lors de l'exécution d'une tâche de débogage, elle récupère les valeurs correctes, donc j'ai l'impression que mon problème se trouve dans le modèle lui-même, mais je n'ai pas pu comprendre ce que je fais mal.
Tâche impossible
- 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
Dictionnaire Ansible
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
modèle Jinja2
{% 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 %}
sortie de débogage
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"
}
Vous pouvez atteindre votre objectif en modifiant votre modèle et tâche jinja2 comme ceci:
Modèle Jinja2:
<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 }}" />
Tâches Ansible:
- 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 }}"
J'espère que cela pourrait vous aider, veuillez ajuster vos tâches selon vos besoins
J'ai découvert aujourd'hui que l'utilisation de dict.values () boucle sur les valeurs de chaque élément dict plutôt que sur ses clés. Vous devriez donc pouvoir utiliser quelque chose comme ça pour votre modèle.
{% 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 %}
Je sais que c'est bien après coup, mais peut-être que quelqu'un d'autre à la recherche de cette réponse peut utiliser cette découverte supplémentaire.
Dans Jinja, lorsque databases
est un dictionnaire, for items in databases
va (comme en Python) parcourir le keys du dictionnaire, pas ses paires clé/valeur. Ainsi, dans votre modèle, item.value
(dont je suppose qu'il est censé être items.value
) devrait être databases[items]
afin d'obtenir la valeur associée à la clé items
.
Mike, ta réponse m'a sauvé beaucoup de recherches aujourd'hui.
Dans mon cas, j'utilisais une liste de dict, j'ai donc dû avoir deux déclarations if, quelque chose comme ceci:
{% for dict_item in quotes %}
{% for item in dict_item.values() %}
.. {{ item.symbol }}
.. {{ item.price }}
{% endfor %}
{% endfor %}
Je vous remercie!