首页 > 解决方案 > 使用带有 Ansible 的分隔符从字符串列表创建字典

问题描述

我有一个嵌套的字符串列表,我正在尝试将其转换为字典。该列表似乎采用合理的格式,但每次我附加到它时,我的字典都会被覆盖。

初始名单:

TASK [test first_list] **********************************************************************************************************************************************************************************************************************************************************************************************************
ok: [node11] => {
    "first_list": [
        [
            "DEVNAME: /dev/sanstorage/node11-data103-2fd31b74e1ef5a8006c9ce9000b10399f",
            "UUID: 2751719f-d1a2-49b0-9e42-3d686c90d2e6",
            "TYPE: xfs"
        ],
        [
            "DEVNAME: /dev/sanstorage/node11-data104-2e81f1279171dce656c9ce9000b10399f",
            "UUID: 6a6265d6-b103-471e-9e25-e8cc5f5585a8",
            "TYPE: xfs"
        ],
        [
            "DEVNAME: /dev/sanstorage/node11-data102-2e385a327788d866e6c9ce9000b10399f",
            "UUID: 8c52d974-8584-4aa6-89b8-f1e1db016118",
            "TYPE: xfs"
        ],
        [
            "DEVNAME: /dev/sanstorage/node11-data101-241afe5ab93b5c0ee6c9ce9000b10399f",
            "UUID: 94b56164-6717-4b82-8f11-86fd94a39672",
            "TYPE: xfs"
        ],
        [
            "DEVNAME: /dev/sanstorage/node11-data100-25626d38d4c4239456c9ce9000b10399f",
            "UUID: 55a1a388-fe0a-4dd0-980a-a10c5317952e",
            "TYPE: xfs"
        ],
        [
            "DEVNAME: /dev/sanstorage/node11-data114-231d2661b7ab88f8f6c9ce9000b10399f",
            "UUID: f87ad708-1d12-41a5-9441-d32a97b5318c",
            "TYPE: ext4"
        ],
        [
            "DEVNAME: /dev/sanstorage/node11-data115-2d3a824975e90550f6c9ce9000b10399f",
            "UUID: b8b79886-9710-4205-900b-7b9d7d4ad933",
            "TYPE: ext4"
        ],
        [
            "DEVNAME: /dev/sanstorage/oneview-FA-data8165-284392eae1ad17d846c9ce9000b10399f",
            "UUID: c5a43057-676e-49b7-b2a9-b53a40f7010b",
            "TYPE: xfs"
        ],
        [
            "DEVNAME: /dev/sanstorage/oneview-FA-data3420-2e262703236f9b7046c9ce9000b10399f",
            "UUID: 1a70c187-9364-4f48-92f8-f9b9dec9824f",
            "TYPE: xfs"
        ],
        [
            "DEVNAME: /dev/sanstorage/node11-data112-2464954fd324508e66c9ce9000b10399f",
            "UUID: 2238a12e-2ca1-466e-8617-11051e1d612e",
            "TYPE: ext4"
        ],
        [
            "DEVNAME: /dev/sanstorage/node11-data111-25bb14827531149456c9ce9000b10399f",
            "UUID: db37479f-80b0-46b2-85e0-aef679bea164",
            "TYPE: ext4"
        ],
        [
            "DEVNAME: /dev/sanstorage/node11-data105-28ac6825aa80520d46c9ce9000b10399f",
            "UUID: e987fc7c-9a4f-46ea-91f0-4d5f37d3421e",
            "TYPE: xfs"
        ],
        [
            "DEVNAME: /dev/sanstorage/node11-data113-2177c50c4dd5063506c9ce9000b10399f",
            "UUID: 36c1194d-ac4f-4cee-8688-353974cb6be0",
            "TYPE: ext4"
        ]
    ]
}

从这里开始,我尝试形成一个字典,但最后只存储最后一个列表条目:

TASK [test final_list] **********************************************************************************************************************************************************************************************************************************************************************************************************
ok: [node11] => {
    "final_list": {
        "DEVNAME": "/dev/sanstorage/node11-data113-2177c50c4dd5063506c9ce9000b10399f",
        "TYPE": "ext4",
        "UUID": "36c1194d-ac4f-4cee-8688-353974cb6be0"
    }
}

理想情况下,它看起来像这样,我猜我需要将字典嵌套在列表中?

    "final list": [
        {
            "DEVNAME: /dev/sanstorage/node11-data103-2fd31b74e1ef5a8006c9ce9000b10399f",
            "UUID: 2751719f-d1a2-49b0-9e42-3d686c90d2e6",
            "TYPE: xfs"
        },
        {
            "DEVNAME: /dev/sanstorage/node11-data104-2e81f1279171dce656c9ce9000b10399f",
            "UUID: 6a6265d6-b103-471e-9e25-e8cc5f5585a8",
            "TYPE: xfs"
        },
        {
            "DEVNAME: /dev/sanstorage/node11-data102-2e385a327788d866e6c9ce9000b10399f",
            "UUID: 8c52d974-8584-4aa6-89b8-f1e1db016118",
            "TYPE: xfs"
        },
... snip ...

以下是剧本的重要部分:

    - set_fact:
        first_list: "{{ first_list | default([]) + [disk_data.split('\n')] }}"
      vars:
        disk_data: '{{ item.stdout }}'        
      with_items: "{{ disk_check.results }}"

    - name: test first_list
      debug:
        var: first_list
    
    - set_fact: final_list:{}

    - set_fact:
        final_list: "{{ final_list | default([]) | combine(dict([ item.partition(':')[::2]|map('trim')])) }}"
      with_items: "{{ first_list }}"

    - name: test final_list
      debug:
        var: final_list

想法?

标签: ansible

解决方案


TL;博士

- debug:
    msg: "{{ disk_check.results | map(attribute='stdout') | map('from_yaml') | list }}"

您没有提供返回的初始任务disk_check。从您在示例中的用法来看,我认为它是循环中使用的shellor任务是理所当然的。command

同时,您仍然提供了足够的信息,因此我们可以避免陷入x/y 问题。您的问题基本上是“如何在分隔符上拆分字符串并使用结果创建字典?” 你真正想要的是更多“如何将表示 yaml dict 的字符串解析为实际的 dict?”

开始

- set_fact:
    first_list: "{{ first_list | default([]) + [disk_data.split('\n')] }}"
  vars:
    disk_data: '{{ item.stdout }}'        
  with_items: "{{ disk_check.results }}"

这将遍历您的所有命令结果,stdout在新行上拆分并将该列表添加到顶级列表中。

由于 的输出shell/command包含一个stdout_lines属性,并且我们可以使用jinja2map过滤器从字典列表中提取属性,因此可以一次性替换它,而无需使用以下 jinja 表达式运行任务:

"{{ disk_check.results | map(attribute='stdout_lines') | list }}"

但我们仍然会走错路。

让我们看看你的一个(重建的)stdout个人results

"stdout": "DEVNAME: /dev/sanstorage/node11-data102-2e385a327788d866e6c9ce9000b10399f\nUUID: 8c52d974-8584-4aa6-89b8-f1e1db016118\nTYPE: xfs"

这是 yaml 字典的字符串表示形式。Ansible 有一个from_yaml过滤器。我们可以使用map过滤器对列表中的每个元素应用过滤器。

下面的剧本尝试复制您的原始数据以一次性显示它

---
- name: Parse a yaml dict in each element of a list
  hosts: localhost
  gather_facts: false

  vars:
    example_disks: 3

  tasks:

    - name: Faking your disk check supposed command
      shell: |-
        cat <<EOF
        DEVNAME: /dev/sanstorage/node{{ (item | string)*2 }}-data{{ (item | string)*3 }}-$(uuidgen)
        UUID: $(uuidgen)
        TYPE: xfs
        EOF
      loop: "{{ range(1, example_disks+1) }}"
      register: disk_check

    - name: Show the original data (use -v to trigger)
      debug:
        var: disk_check
        verbosity: 1

    - name: Display a list of dicts from the above result
      debug:
        msg: "{{ disk_check.results | map(attribute='stdout') | map('from_yaml') | list }}"

并给出(运行-v以显示中间调试):

PLAY [Parse a yaml dict in each element of a list] *************************************************************************************************************************************************************************************

TASK [Faking your disk check supposed command] *****************************************************************************************************************************************************************************************
changed: [localhost] => (item=1)
changed: [localhost] => (item=2)
changed: [localhost] => (item=3)

TASK [Show the original data (use -v to trigger)] **********************************************************************************************************************************************************************************************************
skipping: [localhost]

TASK [Display a list of dicts from the above result] ***********************************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": [
        {
            "DEVNAME": "/dev/sanstorage/node11-data111-10e7a318-62af-46db-895e-5d94b0c2cf88",
            "TYPE": "xfs",
            "UUID": "5a87ae1c-c312-4325-88ac-b9cc1edfa69b"
        },
        {
            "DEVNAME": "/dev/sanstorage/node22-data222-18247d1d-87b2-4c7d-8d48-cd333d7530f9",
            "TYPE": "xfs",
            "UUID": "bc0d7f1a-16e4-4694-b3e2-904e69cc208d"
        },
        {
            "DEVNAME": "/dev/sanstorage/node33-data333-21bc7fde-645f-4cf2-9e18-72d004700085",
            "TYPE": "xfs",
            "UUID": "58985028-3eb1-4f34-90e9-f0e4c8257607"
        }
    ]
}

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

推荐阅读