てくなべ (tekunabe)

ansible / network / automation / StackStorm

Ansible の loop は flatten されない(with_items ではなく with_list と同じ)

■ はじめに

Ansible 2.5 で with_* の代わりに利用できる loop キーワードが利用できるようになりました。

今まで with_items と同じと思い込んでいたのですが、そうではなく with_list と同じ、ということに気がついたのでまとめます。 違いは、一段階flatten(ネストを平らにして展開)されるか、されないかです。

キーワード  flatten
with_items 一段階 flatten される
with_listloop flatten されない

■ 検証

違いを確認するために、簡単な Playbook で検証します。

Playbook

- hosts: localhost
  gather_facts: no
  connection: local

  vars:
    testitems:
      - [1, 2]
      - 3

  tasks:
    - name: with_items
      debug:
        msg: "{{ item }}"
      with_items: "{{ testitems }}"

    - name: with_list
      debug:
        msg: "{{ item }}"
      with_list: "{{ testitems }}"

    - name: normal loop
      debug:
        msg: "{{ item }}"
      loop: "{{ testitems }}"

実行結果

akira:~/environment $ ansible-playbook -i inventory looptest.yml 

PLAY [localhost] ***********************************************

TASK [with_items] **********************************************
ok: [localhost] => (item=None) => {
    "msg": 1
}
ok: [localhost] => (item=None) => {
    "msg": 2
}
ok: [localhost] => (item=None) => {
    "msg": 3
}

TASK [with_list] ***********************************************
ok: [localhost] => (item=None) => {
    "msg": [
        1, 
        2
    ]
}
ok: [localhost] => (item=None) => {
    "msg": 3
}

TASK [normal loop] *********************************************
ok: [localhost] => (item=None) => {
    "msg": [
        1, 
        2
    ]
}
ok: [localhost] => (item=None) => {
    "msg": 3
}

PLAY RECAP *****************************************************
localhost       : ok=3    changed=0    unreachable=0    failed=0   

このように、 [[1, 2], 3] というネストされたリストが、

  • with_items は flatten されて、 123 という3回のループ
  • with_listloop は flatten されず、 [1, 2]3 という2回のループ

になったことが確認できました。

with_items を loop で置き換えるなら、| flatten(levels=1) する

loop でも flatten フィルターを通すと flatten されて、 with_items と同じ動作になります。

    - name: loop with flatten
      debug:
        msg: "{{ item }}"
      loop: "{{ testitems | flatten(levels=1) }}"
akira:~/environment $ ansible-playbook -i inventory looptest.yml 

PLAY [localhost] ***********************************************

TASK [loop with flatten] ***************************************
ok: [localhost] => (item=None) => {
    "msg": 1
}
ok: [localhost] => (item=None) => {
    "msg": 2
}
ok: [localhost] => (item=None) => {
    "msg": 3
}

PLAY RECAP ************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0   


■ まとめ

  • 通常の loop は、with_list と同じく、 flatten されない

  • フィルター| flatten(levels=1)| を通すと、with_items と同じく一段階 flatten される

ということが分かりました。これから Playbook のサンプルは with_* ではなく、 loop が増えてくるのではないかと思います。

参考

Ansible 2.5 へのポーティングガイドで with_x から loop への以降方法が記載されています。 https://docs.ansible.com/ansible/latest/porting_guides/porting_guide_2.5.html#migrating-from-with-x-to-loop