🫠

【Ansible】with_itemsとloopは同じ動作ではない。

2024/12/18に公開

公式サイトによれば、with_items:loop: + flatten(levels=1)で置換できるとある。
ところが特定のデータを渡すと同じ動作をしなくてハマった。

https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_loops.html#with-items
with_items is replaced by loop and the flatten filter.

- name: with_items
  ansible.builtin.debug:
    msg: "{{ item }}"
  with_items: "{{ items }}"

- name: with_items -> loop
  ansible.builtin.debug:
    msg: "{{ item }}"
  loop: "{{ items|flatten(levels=1) }}"

同じ動作にならないパターンを試す

まずVarsを用意する。

  vars:
    extra_items:
      - src: "src_path_B"
        dest: "dest_path_B"

Varsを組み込んだTaskを用意する。

- name: with_items
  ansible.builtin.debug:
    msg: "{{ item }}"
  with_items:
    - src: "src_path_A"
      dest: "dest_path_A"
    - "{{ extra_items }}"

- name: with_items -> loop
  ansible.builtin.debug:
    msg: "{{ item }}"
  loop:
    - src: "src_path_A"
      dest: "dest_path_A"
    - "{{ extra_items|flatten(levels=1) }}"

実行する。

  • with_itemsの結果
ok: [localhost] => (item={'src': 'src_path_A', 'dest': 'dest_path_A'}) => {
    "msg": {
        "dest": "dest_path_A",
        "src": "dest_path_A"
    }
}

ok: [localhost] => (item={'dest': 'dest_path_B', 'src': 'src_path_B'}) => {
    "msg": {
        "dest": "dest_path_B",
        "src": "dest_path_B"
    }
}
  • loopの結果 -> 変数参照している方だけ[]が付いたまま
ok: [localhost] => (item={'src': 'src_path_A', 'dest': 'dest_path_A'}) => {
    "msg": {
        "dest": "dest_path_B",
        "src": "dest_path_B"
    }
}

ok: [localhost] => (item=[{'dest': 'dest_path_A', 'src': 'src_path_A'}]) => {
    "msg": [
        {
            "dest": "dest_path_A",
            "src": "src_path_A"
        }
    ]

このようにloopの方だと階層が狂うのでうまく動作しない。
listの中でlistが入った変数を読んでいるのでnested listになってしまう。
flattenで階層を揃えようとしてもなぜだか揃わない。
with_itemsを使った場合、nested listになっていてもよしなに階層を合わせてくれる。

with_Xは非推奨になっているわけではなく当面使えるとあるので、with_Xを使っておこう。

We have not deprecated the use of with_<lookup> - that syntax will still be valid for the foreseeable future.

Discussion