使用带有嵌套字典的 Ansible ini_file?

0xC*_*22L 5 configuration-management ansible

我想要实现的是以下内容。假设我们有一个类似于以下的剧本:

---

- hosts: local
  tasks:
    - ini_file:
      path: test.ini
      create: yes
      section: "{{???}}"
      option: "{{???}}"
      value: "{{???}}"
    loop: "{{inidict ...???}}"
  vars:
    inidict:
      section1:
        option1: value1
        option2: value2
      section2:
        option1: value1
        option2: value2
Run Code Online (Sandbox Code Playgroud)

上面的剧本是无效的,因为其中有几行???

现在我的目标是将此字典映射到 INI 文件中的部分/选项/值,并获得以下 INI 内容:

[section1]
option1 = value1
option2 = value2

[section2]
option1 = value1
option2 = value2
Run Code Online (Sandbox Code Playgroud)

不幸的是,这似乎失败了,因为我需要为循环添加二级嵌套,以某种方式循环遍历外部循环中的部分,然后遍历内部循环中的选项/值。

有没有比在角色中包装一个循环级别并include_role在传递节名称和列表选项/值作为变量?

我想一种替代方法可能是以某种方式“展平”字典,从而产生相当于(YAML)的东西:

  vars:
    inicontents:
      - section: section1
        key: option1
        value: value1
      - section: section1
        key: option2
        value: value2
      - section: section2
        key: option1
        value: value1
      - section: section2
        key: option2
        value: value2
Run Code Online (Sandbox Code Playgroud)

我只想保持 DRY 并避免部分名称的重复,因为 dict 显然可以完美地映射到 INI 文件的“数据模型”上。

小智 5

除了使用您的“扁平”版本之外,我不知道默认情况下使用 ansible 执行此操作的方法。幸运的是,您可以两全其美,并编写自己的过滤器插件来为您扁平化字典。只需将如下内容添加到filter_plugins项目目录或中的目录中~/.ansible/plugins/filter_plugins,并将其命名为filters.py

class FilterModule(object):
    def filters(self):
        return { 'ini_dict_flatten': self.ini_dict_flatten }

    def ini_dict_flatten(self, arg):
        ret = []
        for section, subdict in arg.items():
            for key, value in subdict.items():
                ret.append(dict(section=section,
                                key=key,
                                value=value))
        return ret

Run Code Online (Sandbox Code Playgroud)

之后,您可以在项目中使用新的过滤器,如下所示:

- hosts: localhost
  tasks:
    - ini_file:
        path: /tmp/test.ini
        create: yes
        section: "{{ item.section }}"
        option: "{{ item.key }}"
        value: "{{ item.value }}"
      loop: "{{ inidict | ini_dict_flatten }}"
  vars:
    inidict:
      section1:
        option1: value1
        option2: value2
      section2:
        option1: value1
        option2: value2

Run Code Online (Sandbox Code Playgroud)

如果您了解 python,有时会有所帮助,因为这样您就可以为 ansible 编写自己的插件。

编辑:我还将包括一个可读性较差且不推荐的解决方案。由于loop:使用 json 格式的字符串,并且 jinja2 在处理字符串之前应用于 ansible 中的字符串,因此您可以使用 jinja 逻辑直接在 playbook 中为您创建“扁平”布局。这个解决方案比编写自己的过滤器更丑陋且可重用性较差,但在技术上仍然有效。

- hosts: localhost
  vars:
    inidict:
      section1:
        option1: value1
        option2: value2
      section2:
        option1: value1
        option2: value2
  tasks:
    - ini_file:
        path: /tmp/test.ini
        create: yes
        section: "{{ item.section }}"
        option: "{{ item.key }}"
        value: "{{ item.value }}"
      loop: >-
        [
        {% for section, subdict in inidict.items() %}
          {% for key, value in subdict.items() %}
            {'section': '{{ section }}',
             'key': '{{ key }}',
             'value': '{{ value }}'}
            {% if not loop.last %}
              ,
            {% endif %}
          {% endfor %}
          {% if not loop.last %}
            ,
          {% endif %}
        {% endfor %}
        ]

Run Code Online (Sandbox Code Playgroud)