web-dev-qa-db-fra.com

Dictionnaire de boucle dans le modèle ansible

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"
}
11
tweeks200

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

5
Arbab Nazar

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.

9
Mike Stankavich

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.

6
jwodder

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!

1
Holden