如何根据字典变量名称的正则表达式将多个字典变量组合到数组中

时间:2019-04-11 23:50:57

标签: merge ansible jinja2

我的清单中有多个以'my_var_ *'开头的dict变量。我想将它们组合成一系列名为“ my_var”的字典

在我的剧本中,我使用'set_fact:'来创建'my_var'变量,方法是尝试使用选择过滤器并匹配正则表达式从“ hostvars ['localhost']”中提取匹配的变量,但join仅适用在弦上。

variables.yml

    my_var_1:
        element1: value11
        element2: value12
    my_var_2:
        element1: value21
        element2: value22

playbook.yml

    - hosts: localhost
      connection: local
      gather_facts: False
      tasks:
        - set_fact:
            my_var: "{{ hostvars['localhost'] | select('match', '^my_var_*') | join(', ' }}"
        - debug:
            msg: "{{ my_var }}"

是否可以像这样将这些“ dict”变量连接到“数组”中?

    my_var:
      - element1: value11
        element2: value12
      - element1: value21
        element2: value22

甚至可能

    my_var:
      - name: 1
        element1: value11
        element2: value12
      - name: 2
        element1: value21
        element2: value22

1 个答案:

答案 0 :(得分:1)

您非常接近,但正如您指出的那样,字符串上的join方法用于连接字符串。您想要附加列表,并使用+运算符完成。

还有其他一些问题:

表达式:

hostvars['localhost'] | select('match', '^my_var_*')

将产生一个看起来像这样的列表:

[
  "my_var_1",
  "my_var_2"
]

...这不是您想要的。您需要这些变量的,而不是键名。我们可以使用dict2items过滤器和selectattr过滤器来生成所需的数据:

---
- hosts: localhost
  gather_facts: false
  tasks:
    - name: set facts on localhost
      set_fact:
        my_var_1:
            element1: value11
            element2: value12
        my_var_2:
            element1: value21
            element2: value22

- hosts: localhost
  gather_facts: false
  tasks:
    - name: merge vars into my_var
      set_fact:
        my_var: "{{ hostvars['localhost']|dict2items|selectattr('key', 'match', '^my_var_')|map(attribute='value')|list }}"

    - name: show content of my_var
      debug:
        var: my_var

这将产生以下输出:

TASK [show content of my_var] ************************************************************************************
ok: [localhost] => {
    "my_var": [
        {
            "element1": "value11", 
            "element2": "value12"
        }, 
        {
            "element1": "value21", 
            "element2": "value22"
        }
    ]
}

如果您摆脱了map(attribute='value')过滤器,则会得到:

TASK [show content of my_var] *****************************************************************************************
ok: [localhost] => {
    "my_var": [
        {
            "key": "my_var_1", 
            "value": {
                "element1": "value11", 
                "element2": "value12"
            }
        }, 
        {
            "key": "my_var_2", 
            "value": {
                "element1": "value21", 
                "element2": "value22"
            }
        }
    ]
}

这并不是您要求的第二个选项,但确实包含键名和值。


其他说明:

  1. 在上面,我使用了运行set_fact的单独播放来设置这些变量的值,因为该解决方案仅在变量是宿主变量(也称为“事实”)时才有效而不是全局变量。您不会在问题中显示如何设置这些变量,所以我不知道这是否能按编写的方式正常工作。

  2. 在正则表达式中,*表示“前面的字符零次或多次”,因此表达式^my_var_*将与my_varmy_var_1,{ {1}},my_var______________,依此类推。您只需编写my_varfoo即可选择您感兴趣的变量名(这将选择以文本^my_var_开头的任何内容)。