格式化 Ansible/Jinja2 中的项目列表

Formatting a list of items in Ansible/Jinja2

是否可以使用 Ansible / Jinja2 中的格式化字符串将 lists/dicts 列表转换为字符串列表?

我知道我可以做类似的事情:

{{["First: %d", "Second: %d"] | map("format", 1) | join(", ") }}

得到First: 1, Second 1.

是否可以做类似的事情

{{[[1, 1], [2, 2]] | map("format", "Num %d, %d") | join(", ") }}

并导致 Num 1, 1, Num 2, 2?

没有。这是不可能的。 format的参数是相反的,例如

    - debug:
        msg: "{{ ['v1 %s', 'v2 %s']|map('format', 'XYZ')|list }}"

给予

  msg:
  - v1 XYZ
  - v2 XYZ

相反,可以映射 joinregex_replace,例如

    - debug:
        msg: "{{ _list|
                 map('join', ',')|
                 map('regex_replace', _regex, _replace)|
                 join(', ') }}"
      vars:
        _list: [[1,1],[2,2]]
        _regex: '^(.*),(.*)$'
        _replace: 'Num , '

做这份工作

  msg: Num 1, 1, Num 2, 2

使用核心 format 过滤器是不可能的。但是如果你愿意写几行python,用自定义过滤器就可以轻松解决这个问题。我去了最简单的演示,您可能必须强化代码并修复边缘情况以供实际使用。您可能想查看 plugin development documentation 了解更多信息。

对于此示例,如果您想在不同项目之间共享,我会将自定义文件保存在 filter_plugins directory adjacent to my test playbook. You can save it in a collection or a role 中。

filter_plugins/my_format_filters.py


def reverse_format(param_list, format_string):
    """format format_sting using elements in param_list"""
    return format_string % tuple(param_list)


class FilterModule(object):
    """my format filters."""

    def filters(self):
        """Return the filter list."""
        return {
            'reverse_format': reverse_format
        }

然后是以下示例剧本:

---
- name: custom filter demo
  hosts: localhost
  gather_facts: false

  tasks:
    - name: map custom reverse_format filter
      debug:
        msg: '{{ item.replacements | map("reverse_format", item.format) | join(", ") }}'
      loop:
        - replacements:
            - [1, 1]
            - [2, 2]
          format: "Num %d, %d"
        - replacements:
            - ['Jack', 'John', 12]
            - ['Mary', 'Alicia', 34]
          format: "%s owes %s %d€"

给出:

PLAY [custom filter demo] **************************************************************************************************************************************************************************************************************

TASK [map custom reverse_format filter] ************************************************************************************************************************************************************************************************
ok: [localhost] => (item={'replacements': [[1, 1], [2, 2]], 'format': 'Num %d, %d'}) => {
    "msg": "Num 1, 1, Num 2, 2"
}
ok: [localhost] => (item={'replacements': [['Jack', 'John', 12], ['Mary', 'Alicia', 34]], 'format': '%s owes %s %d€'}) => {
    "msg": "Jack owes John 12€, Mary owes Alicia 34€"
}

PLAY RECAP *****************************************************************************************************************************************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

在已经接受的答案的基础上,这里有一个版本也支持 dicts/objects:

的馈送列表
class FilterModule(object):
    """my format filters."""

    def filters(self):
        """Return the filter list."""
        return {
            'reverse_format': self.reverse_format
        }

    def reverse_format(self, value, format_string):
        """format format_sting using elements in param_list"""
        return format_string.format(**value)

用法示例:

{{ hostvars.values() |
    map('reverse_format', 'This is inventory host {inventory_hostname}!' | 
    join('\n') }}