从ansible中的字典列表中过滤与条件匹配的元素

lin*_*fan 5 ansible

下面是我的数据的一个人为示例。当列表中的任何字典mylst.env具有带有名称的键时,我想提取所有客户的姓名n1 我想这可以通过嵌套循环来完成,但无法弄清楚如何实现。

- hosts: localhost
  gather_facts: no
  vars:
    - mylst:
        - apiVersion: v1
          name: customer1
          metaData:
              cycles: 10
              ships: 12
          env:
            - name: n1
              value: v1
            - name: n2
              value: v2
        - apiVersion: v1
          name: customer2
          metaData:
              cycles: 10
              ships: 12
          env:
            - name: n1
              value: v1
            - name: n3
              value: v3
        - apiVersion: v1
          name: customer3
          metaData:
              cycles: 10
              ships: 12
          env:
            - name: n3
              value: v1
            - name: n4
              value: v4
  tasks:
  - set_fact: 
       cust_lst: "{{ cust_lst|default([]) + [item.name] }}"
    with_items: "{{ mylst }}"
    # loop through item.env and look for elements where elem.name == n1
    when: item.env | length > 0

  - debug: var=cust_lst 
Run Code Online (Sandbox Code Playgroud)

Mat*_*t P 10

过滤json_query器是完成此类任务的绝佳工具。你需要花一点时间来理解,但请尝试一下:

  - set_fact:
      cust_lst: "{{ mylst | json_query(query) }}"
    vars:
      query: "[?env[?name=='n1']].name"
Run Code Online (Sandbox Code Playgroud)

您可以在官方文档和这篇无耻插入的博客文章中找到更多信息


ili*_*-sp 3

您可以使用列表map上的过滤器item.env来获取每个元素包含的名称列表mylst。然后,如果关键字“n1”在该列表中,则添加到final_var. 请看下面

剧本:

---
- hosts: localhost
  gather_facts: false
  vars:
    mylst:
    - apiVersion: v1
      name: customer1
      metaData:
          cycles: 10
          ships: 12
      env:
        - name: n1
          value: v1
        - name: n2
          value: v2
    - apiVersion: v1
      name: customer2
      metaData:
          cycles: 10
          ships: 12
      env:
        - name: n1
          value: v1
        - name: n3
          value: v3
    - apiVersion: v1
      name: customer3
      metaData:
          cycles: 10
          ships: 12
      env:
        - name: n3
          value: v1
        - name: n4
          value: v4
    - apiVersion: v1
      name: customer4
      metaData:
          cycles: 10
          ships: 12
      env:
        - name2: n3
          value: v1
        - name2: n4
          value: v4

  tasks:

  - name: prepare var
    set_fact:
      final_var: "{{ final_var | default([]) + [item.name] }}"
    when: '"n1" in {{ item.env | selectattr("name", "defined") | map(attribute="name") | list }}'
    with_items:
    - "{{ mylst }}"

  - name: print var
    debug:
      var: final_var
Run Code Online (Sandbox Code Playgroud)

您会注意到我在 中添加了第四个元素,其中mylst不包含 key =“name”的属性。这些将被过滤器过滤掉selectattr("name", "defined",然后传递给地图过滤器。

输出:

PLAY [localhost] *******************************************************************************************************************************************************************************************************

TASK [prepare var] *****************************************************************************************************************************************************************************************************
[WARNING]: conditional statements should not include jinja2 templating delimiters such as {{ }} or {% %}. Found: "n1" in {{ item.env | selectattr("name", "defined") | map(attribute="name") | list }}

ok: [localhost] => (item={'apiVersion': 'v1', 'name': 'customer1', 'metaData': {'cycles': 10, 'ships': 12}, 'env': [{'name': 'n1', 'value': 'v1'}, {'name': 'n2', 'value': 'v2'}]})
ok: [localhost] => (item={'apiVersion': 'v1', 'name': 'customer2', 'metaData': {'cycles': 10, 'ships': 12}, 'env': [{'name': 'n1', 'value': 'v1'}, {'name': 'n3', 'value': 'v3'}]})
skipping: [localhost] => (item={'apiVersion': 'v1', 'name': 'customer3', 'metaData': {'cycles': 10, 'ships': 12}, 'env': [{'name': 'n3', 'value': 'v1'}, {'name': 'n4', 'value': 'v4'}]}) 
skipping: [localhost] => (item={'apiVersion': 'v1', 'name': 'customer4', 'metaData': {'cycles': 10, 'ships': 12}, 'env': [{'name2': 'n3', 'value': 'v1'}, {'name2': 'n4', 'value': 'v4'}]}) 

TASK [print var] *******************************************************************************************************************************************************************************************************
ok: [localhost] => {
    "final_var": [
        "customer1",
        "customer2"
    ]
}

PLAY RECAP *************************************************************************************************************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  
Run Code Online (Sandbox Code Playgroud)

希望这些有帮助。

对于 ansible 2.7.5 错误(如下面的评论所述)

该任务被发现规避了 2.7.5 错误:

  - name: prepare var
    set_fact:
      final_var: "{{ final_var | default([]) + [item.name] }}"
    when: "'n1' in item.env | selectattr('name', 'defined') | map(attribute='name') | list"
    with_items:
    - "{{ mylst }}"
Run Code Online (Sandbox Code Playgroud)