Ansible - 当使用带有with_items的set_fact模块时,如何在字典中附加新密钥?

时间:2015-08-02 14:13:13

标签: ansible

我想在使用带有with_items的set_fact时将键添加到字典中。这是一个小POC,它将帮助我完成其他一些工作。我试图概括POC,以便从中删除所有不相关的细节。

当我执行下面的代码时,它会显示一个字典,其中只有一个键对应于with_items的最后一项。它似乎正在重新创建一个新字典,或者可能会覆盖with_items中每个项目的现有字典。我想要一本包含所有键的字典。

代码:

---
- hosts: localhost
  connection: local
  vars:
      some_value: 12345
      dict: {}
  tasks:
     - set_fact: {
          dict: "{
             {{ item }}: {{ some_value }}
             }"
            }
       with_items:
          - 1
          - 2
          - 3
     - debug: msg="{{ dict }}"

4 个答案:

答案 0 :(得分:23)

这也可以在不使用Ansible 2.2中测试的插件的情况下完成。

---
- hosts: localhost
  connection: local
  vars:
    some_value: 12345
    dict: {}
  tasks:
  - set_fact:
      dict: "{{ dict | combine( { item: some_value } ) }}"
    with_items:
      - 1
      - 2
      - 3
  - debug: msg="{{ dict }}"

或者,这可以在没有包含文件的复杂单线程的情况下编写。

  tasks:
  - include: append_dict.yml
    with_items: [1, 2, 3]

append_dict.yml:

- name: "Append dict: define helper variable"
  set_fact:
    _append_dict: "{ '{{ item }}': {{ some_value }} }"

- name: "Append dict: execute append"
  set_fact:
    dict: "{{ dict | combine( _append_dict ) }}"

输出:

TASK [debug]
*******************************************************************
ok: [localhost] => {
    "msg": {
        "1": "12345",
        "2": "12345",
        "3": "12345"
    }
}

'周围的单引号{{ some_value }}是明确存储字符串值所必需的。

此语法也可用于通过引用dictwith_dict使用item.keyitem.value元素追加。

可以在同一步骤中执行添加前缀和后缀或哈希的操作,例如

    set_fact:
      dict: "{{ dict | combine( { item.key + key_postfix: item.value + '_' +  item.value | hash('md5') } ) }}"

答案 1 :(得分:6)

使用filter plugin

首先,在您的ansible base目录中创建一个名为filter_plugins/makedict.py的新文件。

现在创建一个名为“makedict”(或任何你想要的)的新函数,它接受一个值和一个列表并返回一个新的字典,其中键是列表的元素,值总是相同的。

class FilterModule(object):
     def filters(self):
         return { 'makedict': lambda _val, _list: { k: _val for k in _list }  }

现在,您可以使用剧本中的新过滤器来实现所需的结果:

- hosts: 127.0.0.1
  connection: local
  vars:
      my_value: 12345
      my_keys: [1, 2, 3]
  tasks:
    - set_fact: my_dict="{{ my_value | makedict(my_keys) }}"
    - debug: msg="{{ item.key }}={{ item.value }}"
      with_dict: "{{my_dict}}"

您可以使用filter_plugins中的ansible.cfg选项customize the location过滤插件。

答案 2 :(得分:1)

这似乎不再适用于ansible 2.5

---
- hosts: localhost
  connection: local
  vars:
    some_value: 12345
    dict: {}
  tasks:
  - set_fact:
      dict: "{{ dict | combine( { item: some_value } ) }}"
    with_items:
      - 1
      - 2
      - 3
  - debug: msg="{{ dict }}"

仅返回上一个值{"dict":{"3": "some value"}}

我建议你这样做:

- set_fact:
    __dict: |
        {% for item in  [1,2,3] %}
        {{item}}: "value"
        {% endfor %}

- set_fact:
    final_dict: "{{__dict|from_yaml}}"

- debug: 
  var: final_dict

答案 3 :(得分:0)

另一个解决方案可能是在Ansible 2.9.6中测试过的解决方案。

此解决方案带来了额外的好处,您不必事先在_dict部分中声明vars。这是通过| default({})管道实现的,该管道确保_dict为空时循环不会在第一次迭代中失败。

此外,由于dict是为_dict保留的特殊关键字,因此必须将dict重命名为<class 'dict'>。已被引用(不幸的是,仅在devel分支)here

---
- hosts: localhost
  connection: local
  vars:
    some_value: 12345
  tasks:
  - set_fact:
      _dict: "{{ _dict | default({}) | combine( { item: some_value } ) }}"
    with_items:
      - 1
      - 2
      - 3
  - debug: msg="{{ _dict }}"