如何使用嵌套 list/dict 解析带有 ansible 的文本?

How to parse text with ansible using a nested list/dict?

我有一个需要解析的文本文件,因此我可以通过带有 ansible 的 REST API 使用它。

10.0.0.0/16 Building-A
10.1.0.0/16 Building-A
10.2.0.0/16 Building-B
10.3.0.0/16 Building-B

我需要将此文本转换为如下内容:

{
   "parsed":[
      {
         "Building-A":[
            "10.0.0.0/16",
            "10.1.0.0/16"
         ]
      },
      {
         "Building-B":[
            "10.2.0.0/16",
            "10.3.0.0/16"
         ]
      }
   ]
}

目前我运行下面的剧本来测试文本解析,没有成功。创建的列表不是唯一的。

- name: Test
  hosts: localhost
  tasks:
   - name: Combine
     ansible.builtin.set_fact:
       parsed: "{{ (parsed | default([])) | union( [{item.split()[1]: item.split()[0] }] ) }}"
     loop: "{{ lookup('file','hostgroups.txt').strip().splitlines() }}"

   - name: Debug
     ansible.builtin.debug:
       var: parsed
ok: [localhost] => {
    "parsed": [
        {
            "Building-A": "10.0.0.0/16"
        },
        {
            "Building-A": "10.1.0.0/16"
        },
        {
            "Building-B": "10.2.0.0/16"
        },
        {
            "Building-B": "10.3.0.0/16"
        }
    ]
}

感谢您提供有关辅助变量和 groupby 过滤器的提示。这是最终剧本:

- name: Test
  hosts: localhost
#  strategy: free
  tasks:
   - name: Get List
     ansible.builtin.set_fact:
       parsed_list: "{{ parsed_list | default([]) + [_item] }}"
     loop: "{{ lookup('file','hostgroups.txt').strip().splitlines() }}"
     vars:
       _list: "{{ item.split() }}"
       _item: "{{ {'Name': _list[1], 'Subnet': _list[0] } }}"

   - name: Debug parsed_list
     ansible.builtin.debug:
       var: parsed_list

   - name: Group parsed_list
     ansible.builtin.set_fact.set_fact:
      parsed_group: "{{ parsed_group | default([]) + [{_key: _value}] }}"
     loop: "{{ parsed_list | groupby('Name') }}"
     vars:
       _key: "{{ item.0 }}"
       _value: "{{ item.1 | map(attribute='Subnet') | list }}"

   - name: Debug parsed_group
     ansible.builtin.debug:
       var: parsed_group

解析内容,例如

  - set_fact:
      parsed_list: "{{ parsed_list|d([]) + [_item] }}"
    loop: "{{ lookup('file','hostgroups.txt').splitlines() }}"
    vars:
      _array: "{{ item.split() }}"
      _item: "{{ {'building': _array.1, 'ip': _array.0} }}"

给予

  parsed_list:
  - building: Building-A
    ip: 10.0.0.0/16
  - building: Building-A
    ip: 10.1.0.0/16
  - building: Building-B
    ip: 10.2.0.0/16
  - building: Building-B
    ip: 10.3.0.0/16

然后,使用过滤器 groupby 并创建列表

  - set_fact:
      parsed: "{{ parsed|d([]) + [{_key: _val}] }}"
    loop: "{{ parsed_list|groupby('building') }}"
    vars:
      _key: "{{ item.0 }}"
      _val: "{{ item.1|map(attribute='ip')|list }}"

给予

  parsed:
  - Building-A:
    - 10.0.0.0/16
    - 10.1.0.0/16
  - Building-B:
    - 10.2.0.0/16
    - 10.3.0.0/16

在某些情况下,字典可能是更好的结构,例如

  - set_fact:
      parsed_dict: "{{ parsed_dict|d({})|combine({_key: _val}) }}"
    loop: "{{ parsed_list|groupby('building') }}"
    vars:
      _key: "{{ item.0 }}"
      _val: "{{ item.1|map(attribute='ip')|list }}"

给予

  parsed_dict:
    Building-A:
    - 10.0.0.0/16
    - 10.1.0.0/16
    Building-B:
    - 10.2.0.0/16
    - 10.3.0.0/16