Ansible:按特定字段比较两个数组

时间:2019-05-31 11:17:24

标签: ansible list-comparison

我有两个带有应用程序描述的数组:

source_array:
  - status: Active
    AppName": "Application 1"
    version: "0.1.1"
    metadata: ""
  - status": "Active"
    AppName: "Application 2"
    version: "0.2.2"
    metadata: "ID123"
  - status: "Active"
    AppName: "Application 3"
    version: "0.3.3"
    metadata: ""

并且:

target_array:
  - status: "Active"
    AppName: "Application 1"
    version: "0.1.1"
    metadata: ""
  - status: "Active"
    AppName: "Application 2"
    version: "0.2.2"
    metadata: "ID321"
  - status: "Active",
    AppName: "Application 3"
    version: "0.3.0"
    metadata: ""

我需要根据版本字段比较这两个数组。 因此,例如,所需的结果应该是:

[{
    "status": "Active",
    "AppName": "Application 3",
    "version": "0.3.0",
    "metadata": ""
}]

我尝试使用差异过滤器,但它还会返回secondf元素-因为它具有不同的元数据

- name: Comparing arrays
  set_fact:
    delta: "{{ source_array | difference(target_array) }}"

我得到的结果不正确:

[{
    "status": "Active",
    "AppName": "Application 2",
    "version": "0.2.2",
    "metadata": "ID123"
},
{
    "status": "Active",
    "AppName": "Application 3",
    "version": "0.3.3",
    "metadata": ""
},
{
    "status": "Active",
    "AppName": "Application 2",
    "version": "0.2.2",
    "metadata": "ID321"
},
{
    "status": "Active",
    "AppName": "Application 3",
    "version": "0.3.0",
    "metadata": ""
}]

任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:0)

这确实不平凡。您没有提供太多上下文,但是我怀疑您想做的事情是检查应用程序是否已经更新或应该更新。是吗?

这是一种方法:

- hosts: localhost
  vars:
    array1:
      - status: "Active"
        AppName: "Application 1"
        version: "0.1.1"
        metadata: ""
      - status: "Active"
        AppName: "Application 2"
        version: "0.2.2"
        metadata: "ID321"
      - status: "Active"
        AppName: "Application 3"
        version: "0.3.3"
        metadata: ""
    array2:
      - status: "Active"
        AppName: "Application 1"
        version: "0.1.1"
        metadata: ""
      - status: "Active"
        AppName: "Application 2"
        version: "0.2.2"
        metadata: "ID321"
      - status: "Active"
        AppName: "Application 3"
        version: "0.3.0"
        metadata: ""

  tasks:
    - name: "Show matching pattern"
      debug:
        msg: "{{'^' + (array1|map(attribute='version'))|difference(array2|map(attribute='version'))|join('|') + '$'}}"

    - name: "Compare arrays"
      debug:
        msg: "{{ array1 | selectattr('version', 'match', '^' + (array1|map(attribute='version'))|difference(array2|map(attribute='version'))|join('|') + '$') | list }}"

通过首先找到“较新版本”,然后根据这些版本筛选原始列表来工作。但这是一个脆弱的原因:

  • 现在假设您一个先验哪个数组包含“较新的”数据(此处所有较新的版本位于array1中)。
  • 如果数组中有两个或多个具有相同版本的元素,它将保留两个元素,而不知道选择哪个。

也许您应该考虑一个不同的数据结构,例如映射(dict)。请参见下面的current_state变量:

- hosts: localhost
  vars:
    current_state:
      "Application 1":
        status: "Active"
        version: "0.1.1"
        metadata: ""
      "Application 2":
        status: "Active"
        version: "0.2.2"
        metadata: "ID321"
      "Application 3":
        status: "Active"
        version: "0.3.0"
        metadata: ""
    new_applications:
      - status: "Active"
        AppName: "Application 1"
        version: "0.1.1"
        metadata: ""
      - status: "Active"
        AppName: "Application 2"
        version: "0.2.2"
        metadata: "ID321"
      - status: "Active"
        AppName: "Application 3"
        version: "0.3.3"
        metadata: ""
      - status: "Active"
        AppName: "Application 4"
        version: "0.1.0"
        metadata: ""
  tasks:
    - name: "Different appraoch"
      debug:
         msg: "{{ item.0 }} -- {{ item.1 }} -- Should update: {{ item.1.version is version((current_state[item.0]|default({'version': '0.0.0'}))['version'], '>') }}"
      loop: "{{ new_applications|map(attribute='AppName')|zip(new_applications)|list }}"

    - name: "Build 'current_state' from a list (if not available as is)"
      # There might be a smarter way using items2dict...
      set_fact:
        dict_from_list: "{{ dict_from_list|default({})|combine({item[0]: item[1]})}}"
      loop: "{{ new_applications|map(attribute='AppName')|zip(new_applications)|list }}"

    - debug:
        var: dict_from_list

此版本修复了上述两个问题中的最后一个。如果两个数组的顺序不相同,或者数组的长度不相同,它也会更健壮。

我选择忽略的第一个问题,因为尽管您的问题导致相信array1array2是可互换的,但我假设在给定的上下文中它们实际上不是可互换的。