はじめに
Ansibleでループ処理を実現するためには、with_items
やwith_dict
を使います。
では、多重ループを実現するためにはどうすればいいでしょうか。
ループさせる変数がディクショナリかリストかで実現方法が変わります。
ディクショナリの場合
- with_dict
とinclude
,loop_control
を使う
リストの場合
- with_subelements
を使う
sample
では、実際に試してみます。
ディレクトリ構成
dict_loop.yml
dict_loop_inner.yml
list_loop.yml
hosts/local #inventory
host_vars/
|--localhost.yml
inventory
localhostで実行するためのインベントリファイルを用意します。
[local]
localhost
vars
こんな感じに変数を定義します。今回はhost_varsで定義しました。
---
my_vars:
dict_loop:
outer_item1:
inner:
foo: inner_item1_1
hoge: inner_item1_2
outer_item2:
inner:
foo: inner_item2_1
hoge: inner_item2_2
list_loop:
- outer: outer_item1
inner:
- inner_item1_1
- inner_item1_2
- outer: outer_item2
inner:
- inner_item2_1
- inner_item2_2
Playbook
ディクショナリの多重ループ
varsの該当箇所
---
my_vars:
dict_loop:
outer_item1:
inner:
foo: inner_item1_1
hoge: inner_item1_2
outer_item2:
inner:
foo: inner_item2_1
hoge: inner_item2_2
dict_loop.yml
まずwith_dict
で、外側のループ対象を指定します。その際、loop_control
のloop_var
で指定した任意の変数名に値がセットされます。
この場合、outer_item1、outer_item2がouter_item
にセットされます。
参考:公式ドキュメント
---
- name: dict_loop
hosts: localhost
connection: local
tasks:
- name: outer loop
include: dict_loop_inner.yml
with_dict: "{{ my_vars.dict_loop }}"
loop_control:
loop_var: outer_item
dict_loop_inner.yml
そして、outer_item
ごとにinclude
で指定されたdict_loop_inner.ymlが実行されます。
includeされたタスクの中でもouter_item
を参照できます。そして、outer_item
の子要素であるinner
をwith_dict
のループ対象に指定することで多重ループを実現します。
loop_control
でこの値をinner_item
にセットしているので(必須ではありませんが)、inner_item.value
として値(この場合、inner_item1_1,inner_item1_2...)が取り出せます。
---
- name: inner loop
debug:
msg: "outer:{{ outer_item.key }} inner:{{ inner_item.value }}"
with_dict: "{{ outer_item.value.inner }}"
loop_control:
loop_var: inner_item
実行
$ ansible-playbook -i hosts/local -l localhost dict_loop.yml
結果
PLAY [dict_loop] ***************************************************************
TASK [outer loop _raw_params=inner_loop.yml] ***********************************
included: /PATH/TO/inner_loop.yml for localhost
included: /PATH/TO/inner_loop.yml for localhost
TASK [inner loop msg=outer:{{ outer_item.key }} inner:{{ inner_item.value }}] **
ok: [localhost] => (item={'key': u'foo', 'value': u'inner_item1_1'}) => {
"inner_item": {
"key": "foo",
"value": "inner_item1_1"
},
"msg": "outer:outer_item1 inner:inner_item1_1"
}
ok: [localhost] => (item={'key': u'hoge', 'value': u'inner_item1_2'}) => {
"inner_item": {
"key": "hoge",
"value": "inner_item1_2"
},
"msg": "outer:outer_item1 inner:inner_item1_2"
}
TASK [inner loop msg=outer:{{ outer_item.key }} inner:{{ inner_item.value }}] **
ok: [localhost] => (item={'key': u'foo', 'value': u'inner_item2_1'}) => {
"inner_item": {
"key": "foo",
"value": "inner_item2_1"
},
"msg": "outer:outer_item2 inner:inner_item2_1"
}
ok: [localhost] => (item={'key': u'hoge', 'value': u'inner_item2_2'}) => {
"inner_item": {
"key": "hoge",
"value": "inner_item2_2"
},
"msg": "outer:outer_item2 inner:inner_item2_2"
}
リストの多重ループ
varsの該当箇所
---
my_vars:
list_loop:
- outer: outer_item1
inner:
- inner_item1_1
- inner_item1_2
- outer: outer_item2
inner:
- inner_item2_1
- inner_item2_2
list_loop.yml
with_subelements
で、外側のループ対象と内側のループ対象を定義します。
タスク中で、前者がitem.0
に、後者がitem.1
にセットされます。
3重以上の多重ループには対応していません。
---
- name: list_loop
hosts: localhost
connection: local
tasks:
- debug:
msg: "outer:{{ item.0.outer }} inner:{{ item.1 }}"
with_subelements:
- "{{ my_vars.list_loop }}"
- inner
実行
$ ansible-playbook -i hosts/local -l localhost list_loop.yml
結果
PLAY [list_loop] ***************************************************************
TASK [debug msg=outer:{{ item.0.outer }} inner:{{ item.1 }}] *******************
ok: [localhost] => (item=({u'outer': u'outer_item1'}, u'inner_item1_1')) => {
"item": [
{
"outer": "outer_item1"
},
"inner_item1_1"
],
"msg": "outer:outer_item1 inner:inner_item1_1"
}
ok: [localhost] => (item=({u'outer': u'outer_item1'}, u'inner_item1_2')) => {
"item": [
{
"outer": "outer_item1"
},
"inner_item1_2"
],
"msg": "outer:outer_item1 inner:inner_item1_2"
}
ok: [localhost] => (item=({u'outer': u'outer_item2'}, u'inner_item2_1')) => {
"item": [
{
"outer": "outer_item2"
},
"inner_item2_1"
],
"msg": "outer:outer_item2 inner:inner_item2_1"
}
ok: [localhost] => (item=({u'outer': u'outer_item2'}, u'inner_item2_2')) => {
"item": [
{
"outer": "outer_item2"
},
"inner_item2_2"
],
"msg": "outer:outer_item2 inner:inner_item2_2"
}
まとめ
Ansibleでの2種類の多重ループの方法についてご紹介しました。
with_dict
とinclude
,loop_control
を使えば複雑な多重ループを実現できますが、反面playbookの見通しが悪くなります。
個人的に、多重ループはwith_subelements
で処理できるレベルに留めるのがいいと思います。