Ansible: 2つのリストの組み合わせを処理する

はじめに

Playbookを書いていると多次元のデータをループさせて処理させる場合がよくあります。

以下のようなデータ構造を考えてみます。

people:
  - taro
  - jiro
  - saburo
sports:
  - soccer
  - baseball
  - bascketball

上記の2つのリストを使って、 <who> likes <sport> のような文字列の組み合わせをそれぞれ出力したいとします。

多重ループ

loop を利用して多重ループを構成する場合は内側のループを構成するタスクを別ファイルに分けて、外側のループから include_task を使って呼び出します。

site_doubleloop.yml

---
- name: Process data with double loop
  hosts: localhost
  vars:
    people:
      - taro
      - jiro
      - saburo
    sports:
      - soccer
      - baseball
      - bascketball
  tasks:
    - name: Outer loop call inner loop
      include_tasks: "inner_loop.yml"
      loop: "{{ people }}"
      loop_control:
        loop_var: person

inner_loop.yml

---
- name: Output
  debug:
    msg: "{{ person }} likes {{ sport }}"
  loop: "{{ sports }}"
  loop_control:
    loop_var: sport
TASK [Output] *******************************************************
ok: [localhost] => (item=soccer) => {
    "msg": "taro likes soccer"
}
ok: [localhost] => (item=baseball) => {
    "msg": "taro likes baseball"
}
ok: [localhost] => (item=bascketball) => {
    "msg": "taro likes bascketball"
}

TASK [Output] *******************************************************
ok: [localhost] => (item=soccer) => {
    "msg": "jiro likes soccer"
}
ok: [localhost] => (item=baseball) => {
    "msg": "jiro likes baseball"
}
ok: [localhost] => (item=bascketball) => {
    "msg": "jiro likes bascketball"
}

TASK [Output] *******************************************************
ok: [localhost] => (item=soccer) => {
    "msg": "saburo likes soccer"
}
ok: [localhost] => (item=baseball) => {
    "msg": "saburo likes baseball"
}
ok: [localhost] => (item=bascketball) => {
    "msg": "saburo likes bascketball"
}

filter を使ってデータを合成する

リストの直積を生成する product フィルタを利用します。前の方法と違い、タスクファイルを分ける必要がないためロジックがシンプルになります。

site_singleloop_with_product_filter.yml

- name: Process 2 lists data with product filter
  hosts: localhost
  vars:
    people:
      - taro
      - jiro
      - saburo
    sports:
      - soccer
      - baseball
      - bascketball
  tasks:
    - name: Generate product of the lists
      ansible.builtin.set_fact:
        _pdct: "{{ people | product(sports) }}"

    - name: Output them
      ansible.builtin.debug:
        var: _pdct

    - name: Generate Strings with the product
      debug:
        msg: "{{ item[0] }} likes {{ item[1] }}"
      loop: "{{ _pdct }}"
PLAY [Process 2 lists data with product filter] ************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] *************************************************************************************************************************************************************************************************************************************
ok: [localhost]

TASK [Generate product of the lists] ***********************************************************************************************************************************************************************************************************************
ok: [localhost]

TASK [Output them] *****************************************************************************************************************************************************************************************************************************************
ok: [localhost] => {
    "_pdct": [
        [
            "taro",
            "soccer"
        ],
        [
            "taro",
            "baseball"
        ],
        [
            "taro",
            "bascketball"
        ],
        [
            "jiro",
            "soccer"
        ],
        [
            "jiro",
            "baseball"
        ],
        [
            "jiro",
            "bascketball"
        ],
        [
            "saburo",
            "soccer"
        ],
        [
            "saburo",
            "baseball"
        ],
        [
            "saburo",
            "bascketball"
        ]
    ]
}

TASK [Generate Strings with the product] *******************************************************************************************************************************************************************************************************************
ok: [localhost] => (item=['taro', 'soccer']) => {
    "msg": "taro likes soccer"
}
ok: [localhost] => (item=['taro', 'baseball']) => {
    "msg": "taro likes baseball"
}
ok: [localhost] => (item=['taro', 'bascketball']) => {
    "msg": "taro likes bascketball"
}
ok: [localhost] => (item=['jiro', 'soccer']) => {
    "msg": "jiro likes soccer"
}
ok: [localhost] => (item=['jiro', 'baseball']) => {
    "msg": "jiro likes baseball"
}
ok: [localhost] => (item=['jiro', 'bascketball']) => {
    "msg": "jiro likes bascketball"
}
ok: [localhost] => (item=['saburo', 'soccer']) => {
    "msg": "saburo likes soccer"
}
ok: [localhost] => (item=['saburo', 'baseball']) => {
    "msg": "saburo likes baseball"
}
ok: [localhost] => (item=['saburo', 'bascketball']) => {
    "msg": "saburo likes bascketball"
}

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

# おわりに

2つのリストに対して要素の組み合わせを処理する方法をまとめました。