17

我正在尝试使用 jinja2 通过 ansible 模板循环字典以创建多个数据源,但收到此错误[{'msg': "AnsibleUndefinedVariable: One or more undefined variables: 'dict object' has no attribute 'value'", 'failed': True}]}

运行调试任务时,它确实会返回正确的值,所以我觉得我的问题出在模板本身,但我一直无法弄清楚我做错了什么。

Ansible 任务

- 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 字典

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 模板

{% 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 %}

调试输出

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"
}
4

5 回答 5

21

我今天发现使用 dict.values() 循环遍历每个 dict 元素的值而不是其键。所以你应该可以为你的模板使用这样的东西。

{% 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 %}

我知道这是事后诸葛亮,但也许其他寻找这个答案的人可以利用这个额外的发现。

于 2017-05-03T16:45:03.620 回答
6

在 Jinja 中,whendatabases是一个字典,for items in databases将(如在 Python 中)迭代字典的,而不是它的键/值对。因此,在您的模板中,item.value(我假设是items.value)应该是databases[items]为了获取与 key 关联的值items

于 2016-06-10T20:59:13.237 回答
6

您可以通过像这样修改 jinja2 模板和任务来实现您的目标:

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 }}" />

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

希望对您有所帮助,请根据您的要求调整您的任务

于 2016-06-11T05:40:00.943 回答
1

迈克,你的回答为我今天节省了很多搜索时间。

就我而言,我使用的是一个字典列表,所以我必须有两个 if 语句,如下所示:

{% for dict_item in quotes %}
  {% for item in dict_item.values() %}
.. {{ item.symbol }}
.. {{ item.price }}
  {% endfor %}
{% endfor %}

谢谢!

于 2019-04-25T16:33:41.997 回答
0

如果您使用的是 Python 3,则应该是:

{% for key, value in dictionary.items() %}
     <resource name="{{ value.db_resource }}" ...
{% endfor %}
于 2021-11-21T05:22:17.073 回答