【Ansible】我想要在Ansible中使用集合论过滤器

首先

我认为在 Ansible 中,有时我们想要比较两个列表,并提取出同时存在于两个列表中或只存在于其中一个列表中的元素。在这种情况下,使用集合过滤器非常方便,我试着实际使用了一下。

太长不看

Ansibleでは以下の集合論フィルターが使用可能。リストだけでなく、辞書のリストに対しても使用可能。

集合論フィルター
演算子
説明
記載例

unique

重複を排除
{{ list_A | unique }}

intersect
A ∩ B
積集合(AかつB)
{{ list_A | intersect(list_B) }}

union
A ∪ B
和集合(AまたはB)※AかつBも含まれる
{{ list_A | union(list_B) }}

symmetric_difference
A xor B
排他的論理和(AのみまたはBのみ)※AかつBは含まれない
{{ list_A | symmetric_difference(list_B) }}

difference
A ー B
差集合(AにはあるがBにはない)
{{ list_A | difference(list_B) }}

辞書のリスト同士を比較した際に同じ要素とみなされるには、辞書内のすべてのキーと値が一致している必要がある。

集合論フィルターを活用することで、辞書のリスト同士の比較が容易になる。

前提

    Ansibleにおけるフィルターの使い方を理解していること

执行环境

    • Python: 3.9.16

 

    • Ansible: 2.9.7

 

    Jinja2: 3.0.3

請提供更多詳細信息。

1. 使用集合论过滤器对列表进行操作。

1-1. 运行Playbook

    • Playbookでは、以下2つのことを確認します

変数list_uniqueに対し、リストの重複が排除されること(unique)
変数list_Aとlist_Bに対し、正しい演算が行われること(intersect/union/symmetric_difference/difference)

---
- name: "List set theory filters"
  hosts: localhost
  vars:
    list_unique: [1, 2, 3, 2, 3, 4]    # 2と3が重複
    list_A: [1, 2, 3, 4]   # 3と4が重複
    list_B: [3, 4, 5, 6]
  gather_facts: false
  tasks:
    - name: Test unique
      debug:
        msg: "{{ list_unique | unique }}"

    - name: Test intersect
      debug:
        msg: "{{ list_A | intersect(list_B) }}"

    - name: Test union
      debug:
        msg: "{{ list_A | union(list_B) }}"

    - name: Test symmetric_difference
      debug:
        msg: "{{ list_A | symmetric_difference(list_B) }}"

    - name: Test difference
      debug:
        msg: "{{ list_A | difference(list_B) }}"

1-2. 执行结果

我成功地达到了预期的结果。

$ ansible-playbook list_set_theory_filters.yml
PLAY [List set theory filters] *******************************************************************

TASK [Test unique] *******************************************************************************
ok: [localhost] =>
  msg:
  - 1
  - 2
  - 3
  - 4

TASK [Test intersect] ****************************************************************************
ok: [localhost] =>
  msg:
  - 3
  - 4

TASK [Test union] ********************************************************************************
ok: [localhost] =>
  msg:
  - 1
  - 2
  - 3
  - 4
  - 5
  - 6

TASK [Test symmetric_difference] *****************************************************************
ok: [localhost] =>
  msg:
  - 1
  - 2
  - 5
  - 6

TASK [Test difference] ***************************************************************************
ok: [localhost] =>
  msg:
  - 1
  - 2

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

2. 使用集合论过滤器来筛选字典列表。

2-1. 执行Playbook

    • Playbookでは1つ前と同様に、以下2つのことを確認します

変数list_uniqueに対し、リストの重複が排除されること(unique)
変数list_Aとlist_Bに対し、正しい演算が行われること(intersect/union/symmetric_difference/difference)

---
- name: "Dict set theory filters"
  hosts: localhost
  vars:
    list_unique:
      - {id: 1, name: "test 1"}
      - {id: 2, name: "test 2"}
      - {id: 3, name: "test 3"}
      - {id: 2, name: "test 2"}
      - {id: 3, name: "test 3"}
      - {id: 4, name: "test 4"}
    list_A:
      - {id: 1, name: "test 1"}
      - {id: 2, name: "test 2"}
      - {id: 3, name: "test 3"}
      - {id: 4, name: "test 4"}
    list_B:
      - {id: 3, name: "test 3"}
      - {id: 4, name: "test 4"}
      - {id: 5, name: "test 5"}
      - {id: 6, name: "test 6"}
  gather_facts: false
  tasks:
    - name: Test unique
      debug:
        msg: "{{ list_unique | unique }}"

    - name: Test intersect
      debug:
        msg: "{{ list_A | intersect(list_B) }}"

    - name: Test union
      debug:
        msg: "{{ list_A | union(list_B) }}"

    - name: Test symmetric_difference
      debug:
        msg: "{{ list_A | symmetric_difference(list_B) }}"

    - name: Test difference
      debug:
        msg: "{{ list_A | difference(list_B) }}"

2-2. 执行结果

对于字典列表,我能够得到预期的结果。

$ ansible-playbook dict_set_theory_filters.yml
PLAY [Dict set theory filters] **********************************************************

TASK [Test unique] **********************************************************************
ok: [localhost] =>
  msg:
  - id: 1
    name: test 1
  - id: 2
    name: test 2
  - id: 3
    name: test 3
  - id: 4
    name: test 4

TASK [Test intersect] *******************************************************************
ok: [localhost] =>
  msg:
  - id: 3
    name: test 3
  - id: 4
    name: test 4

TASK [Test union] ***********************************************************************
ok: [localhost] =>
  msg:
  - id: 1
    name: test 1
  - id: 2
    name: test 2
  - id: 3
    name: test 3
  - id: 4
    name: test 4
  - id: 5
    name: test 5
  - id: 6
    name: test 6

TASK [Test symmetric_difference] ********************************************************
ok: [localhost] =>
  msg:
  - id: 1
    name: test 1
  - id: 2
    name: test 2
  - id: 5
    name: test 5
  - id: 6
    name: test 6

TASK [Test difference] ******************************************************************
ok: [localhost] =>
  msg:
  - id: 1
    name: test 1
  - id: 2
    name: test 2

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

2-3. 注意事项

    • 辞書のリスト同士を比較した際に同じ要素とみなされるには、辞書内のすべてのキーと値が一致している必要があります。

例1)intersectフィルターでidとnameの値は一致しているが、list_Bにのみキーhogeがあるので同じとみなされない

タスク
– name: Test intersect
debug:
msg: “{{ list_A | intersect(list_B) }}”
vars:
list_A:
– {id: 1, name: “test 1”}
list_B:
– {id: 1, name: “test 1”, hoge: “hoge”}

実行結果
TASK [Test intersect] ***************************************************************
ok: [localhost] =>
msg: []

例2)intersectフィルターで両方にキーidとnameはあるが、キーnameの値が異なるので同じとみなされない

タスク
– name: Test intersect
debug:
msg: “{{ list_A | intersect(list_B) }}”
vars:
list_A:
– {id: 1, name: “test 1”}
list_B:
– {id: 1, name: “hoge”}

結果
TASK [Test intersect] ***************************************************************
ok: [localhost] =>
msg: []

3. 实际案例 (shí lì)

通过使用集合论过滤器,可以容易地比较字典列表之间的差异。

3-1. 确认list_A和list_B中没有重复的元素

以下是确认List_A在List_B中没有重复的示例。根据这个例子,由于List_A和List_B中都有1,所以会产生错误。

タスク
– name: Check that there are no duplicates in list_A and list_B
assert:
that:
– (list_A | intersect(list_B)) | length == 0
fail_msg:
– “list_A and list_B: {{ list_A | intersect(list_B) }}”
– “Only list_A: {{ list_A | difference(list_B) }}”
– “Only list_B: {{ list_B | difference(list_A) }}”
vars:
list_A: [1]
list_B: [1, 2]

実行結果
TASK [Check that there are no duplicates in list_A and list_B] **********************
fatal: [localhost]: FAILED! => changed=false
assertion: (list_A | intersect(list_B)) | length == 0
evaluated_to: false
msg:
– ‘list_A and list_B: [1]’
– ‘Only list_A: []’
– ‘Only list_B: [2]’

确认list_A是否包含在list_B中 (A⊂B)

以下是在确认list_B包含list_A时的一个例子。在这个例子中,由于5包含在list_A中,因此会报错。

タスク
– name: Check that list_A is in list_B
assert:
that:
– (list_A | intersect(list_B)) == list_A
fail_msg:
– “list_A and list_B: {{ list_A | intersect(list_B) }}”
– “Only list_A: {{ list_A | difference(list_B) }}”
– “Only list_B: {{ list_B | difference(list_A) }}”
vars:
list_A: [1, 2, 5]
list_B: [1, 2, 3, 4]

実行結果
TASK [Check that list_A is in list_B] ***********************************
fatal: [localhost]: FAILED! => changed=false
assertion: (list_A | intersect(list_B)) == list_A
evaluated_to: false
msg:
– ‘list_A and list_B: [1, 2]’
– ‘Only list_A: [5]’
– ‘Only list_B: [3, 4]’

最后

    • 集合論フィルターを活用することで、辞書のリスト同士の比較が容易になるので積極的に活用しましょう。

 

    集合論フィルターの使い方を整理しながら、高校数学の「集合と論理」を思い出しました。懐かしいですね。

请参考以下链接

Ansible Documentation – Filters

集合論フィルターの使い方


广告
将在 10 秒后关闭
bannerAds