検証環境はこちらを利用しています。
CentOS Linux release 7.9.2009 (Core)
python version 2.7.5
ansible 2.9.23
こちらのドキュメントを参考にしています。
https://docs.ansible.com/ansible/2.9_ja/user_guide/playbooks_loops.html
まずは標準的なループから試してみます。localhostに対してdebugモジュールでメッセージを表示する処理を書きました。出力するメッセージの内容をloopに並べて2つ指定し、msgで変数itemを出力するように書きます。
---
- hosts: localhost
gather_facts: no
tasks:
- name: loop test
debug:
msg: "{{ item }}"
loop:
- "test message1"
- "test message2"
[root@ansible-ctl ~]# ansible-playbook -i /etc/ansible/hosts loop-test.yml
PLAY [localhost] *****************************************************************************************************************************************
TASK [loop test] *****************************************************************************************************************************************
ok: [localhost] => (item=test message1) => {
"msg": "test message1"
}
ok: [localhost] => (item=test message2) => {
"msg": "test message2"
}
PLAY RECAP ***********************************************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@ansible-ctl ~]#
2つのメッセージが出力されました。ループ処理されていることがわかります。
次はハッシュリストを使用したループを試してみます。ここでもdebugモジュールを使用し、loopで指定した内容をmsgで出力します。ハッシュリストの場合、変数の指定が item.<key> になります。
---
- hosts: localhost
gather_facts: no
tasks:
- name: loop test
debug:
msg: "name: {{ item.name }}, message: {{ item.message }}"
loop:
- { name: 'test1', message: 'test message1' }
- { name: 'test2', message: 'test message2' }
[root@ansible-ctl ~]# ansible-playbook -i /etc/ansible/hosts loop-test2.yml
PLAY [localhost] *****************************************************************************************************************************************
TASK [loop test] *****************************************************************************************************************************************
ok: [localhost] => (item={u'message': u'test message1', u'name': u'test1'}) => {
"msg": "name: test1, message: test message1"
}
ok: [localhost] => (item={u'message': u'test message2', u'name': u'test2'}) => {
"msg": "name: test2, message: test message2"
}
PLAY RECAP ***********************************************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@ansible-ctl ~]#
item.nameとitem.messageが繰り返し出力されました。
OSユーザを作成する場合などに各ユーザに指定する値を変えて繰り返せるので使えるかもしれません。
次はディクショナリーのループです
---
- hosts: localhost
gather_facts: no
tasks:
- name: loop test
debug:
msg: "key: {{ item.key }}, value: {{ item.value }}"
loop: "{{ dic_test|dict2items }}"
vars:
dic_test:
name: test1
color: red
[root@ansible-ctl ~]# ansible-playbook -i /etc/ansible/hosts loop-test3.yml
PLAY [localhost] *****************************************************************************************************************************************
TASK [loop test] *****************************************************************************************************************************************
ok: [localhost] => (item={u'key': u'color', u'value': u'red'}) => {
"msg": "key: color, value: red"
}
ok: [localhost] => (item={u'key': u'name', u'value': u'test1'}) => {
"msg": "key: name, value: test1"
}
PLAY RECAP ***********************************************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@ansible-ctl ~]#
変数でディクショナリーを使った場合のループ処理のやり方のようですが、いまいち使えるシチュエーションが思いついていないです。
次は、ループした内容を変数に登録した場合の動作です。loopで2つ値を指定し、shellモジュールを実行した結果を変数echoに登録しています。そして変数echoの内容を出力しているものと、変数echoから特定の値だけ出力する場合の指定方法をみています。
---
- hosts: localhost
gather_facts: no
tasks:
- name: loop test
shell: "echo {{ item }}"
loop:
- "one"
- "two"
register: echo
- name: show var
debug:
msg: "{{ echo }}"
- name: show var echo
debug:
msg: "{{ echo.results[0].item }}"
[root@ansible-ctl ~]# ansible-playbook -i /etc/ansible/hosts loop-test4.yml
PLAY [localhost] *****************************************************************************************************************************************
TASK [loop test] *****************************************************************************************************************************************
changed: [localhost] => (item=one)
changed: [localhost] => (item=two)
TASK [show var] ******************************************************************************************************************************************
ok: [localhost] => {
"msg": {
"changed": true,
"msg": "All items completed",
"results": [
{
"ansible_loop_var": "item",
"changed": true,
"cmd": "echo one",
"delta": "0:00:00.003615",
"end": "2021-08-06 20:50:42.578516",
"failed": false,
"invocation": {
"module_args": {
"_raw_params": "echo one",
"_uses_shell": true,
"argv": null,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"stdin_add_newline": true,
"strip_empty_ends": true,
"warn": true
}
},
"item": "one",
"rc": 0,
"start": "2021-08-06 20:50:42.574901",
"stderr": "",
"stderr_lines": [],
"stdout": "one",
"stdout_lines": [
"one"
]
},
{
"ansible_loop_var": "item",
"changed": true,
"cmd": "echo two",
"delta": "0:00:00.003554",
"end": "2021-08-06 20:50:42.719830",
"failed": false,
"invocation": {
"module_args": {
"_raw_params": "echo two",
"_uses_shell": true,
"argv": null,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"stdin_add_newline": true,
"strip_empty_ends": true,
"warn": true
}
},
"item": "two",
"rc": 0,
"start": "2021-08-06 20:50:42.716276",
"stderr": "",
"stderr_lines": [],
"stdout": "two",
"stdout_lines": [
"two"
]
}
]
}
}
TASK [show var echo] *************************************************************************************************************************************
ok: [localhost] => {
"msg": "one"
}
PLAY RECAP ***********************************************************************************************************************************************
localhost : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@ansible-ctl ~]#
変数echoの中のresultsの中に、ループを実行した内容が登録されているのがわかります。
次は入れ子のリストでのループです。少しこの指定の仕方はよく理解できていないのですが、サンプルを参考に以下のように書きました。
---
- hosts: localhost
gather_facts: no
tasks:
- name: loop test
shell: "echo {{ item[0] }} {{ item[1] }}"
loop: "{{ ['alice','bob'] |product([ 'clientdb', 'employeedb', 'providerdb' ])|list }}"
- name: show var
debug:
msg: "{{ ['alice','bob'] |product([ 'clientdb', 'employeedb', 'providerdb' ])|list }}"
[root@ansible-ctl ~]# ansible-playbook -i /etc/ansible/hosts loop-test5.yml
PLAY [localhost] *****************************************************************************************************************************************
TASK [loop test] *****************************************************************************************************************************************
changed: [localhost] => (item=[u'alice', u'clientdb'])
changed: [localhost] => (item=[u'alice', u'employeedb'])
changed: [localhost] => (item=[u'alice', u'providerdb'])
changed: [localhost] => (item=[u'bob', u'clientdb'])
changed: [localhost] => (item=[u'bob', u'employeedb'])
changed: [localhost] => (item=[u'bob', u'providerdb'])
TASK [show var] ******************************************************************************************************************************************
ok: [localhost] => {
"msg": [
[
"alice",
"clientdb"
],
[
"alice",
"employeedb"
],
[
"alice",
"providerdb"
],
[
"bob",
"clientdb"
],
[
"bob",
"employeedb"
],
[
"bob",
"providerdb"
]
]
}
PLAY RECAP ***********************************************************************************************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@ansible-ctl ~]#
動きとしては、リストの各要素に対してもう一つのリストの全要素分、ループが回ったという感じでしょうか。こちらも中々上手く使うにはどうしたらいいのか考え中です。
次は条件を指定してループを回すやり方です。ここではloopではなくuntilを使用します。
ループの条件は実行結果を登録した変数resultのstdoutに文字列testが見つかるまで。リトライは5回、間隔は3秒を指定しています。
shellモジュールで文字列tstを出力するだけなので、条件が満たされることはありません。
---
- hosts: localhost
gather_facts: no
tasks:
- name: loop test
shell: "echo tst"
register: result
until: result.stdout.find("test") != -1
retries: 5
delay: 3
[root@ansible-ctl ~]# ansible-playbook -i /etc/ansible/hosts loop-test6.yml
PLAY [localhost] *****************************************************************************************************************************************
TASK [loop test] *****************************************************************************************************************************************
FAILED - RETRYING: loop test (5 retries left).
FAILED - RETRYING: loop test (4 retries left).
FAILED - RETRYING: loop test (3 retries left).
FAILED - RETRYING: loop test (2 retries left).
FAILED - RETRYING: loop test (1 retries left).
fatal: [localhost]: FAILED! => {"attempts": 5, "changed": true, "cmd": "echo tst", "delta": "0:00:00.003339", "end": "2021-08-06 21:11:07.081726", "rc": 0, "start": "2021-08-06 21:11:07.078387", "stderr": "", "stderr_lines": [], "stdout": "tst", "stdout_lines": ["tst"]}
PLAY RECAP ***********************************************************************************************************************************************
localhost : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
[root@ansible-ctl ~]#
5回リトライして、最終的にFAILEDで終了しました。何かしらの処理待ちを行いたい場合に使えそうです。
Ansibleではloopで指定して繰り返す、変数の作り方によって繰り返すといった書き方ができるようです。構築の自動化をする場合、同じ処理だけどサーバによってパラメータを変えたい時などにloopは使えそうです。
コメント