Ansible Advent Calendar 2023 9日目の記事です。
やりたいこと
拠点に所属する機器に対して作業をするとき同拠点内の機器でエラーがあったとき ほかの機器の後続スキップさせたいので考えてみました。
機器1と機器8で何かしらの処理が失敗するとします。
この場合、拠点1の機器2と機器3,拠点3の機器7と機器9も後続処理をスキップさせたいといったものです。
拠点1 機器1 × ← 失敗 機器2 ← 失敗してないけどスキップ 機器3 ← 失敗してないけどスキップ 拠点2 機器3 機器5 機器6 拠点3 機器7 ← 失敗してないけどスキップ 機器8 × ← 失敗 機器9 ← 失敗してないけどスキップ
手順
inventory
インベントリは以下のように作成しました
グループA,B,Cにそれぞれ3ホストづつ所属させています。
グループ変数に定義したgroup_idは、所属するグループ(拠点)を識別させるものです。 グループ名と一致させています(Playbookで動的に取得させようともしましたが、ホストが複数のグループに所属していたりするのを考えるのが面倒だったのでこの形にしちゃいました)
--- all: children: targets: children: groupA: hosts: host1: ansible_connection: local host2: ansible_connection: local host3: ansible_connection: local vars: group_id: groupA groupB: hosts: host4: ansible_connection: local host5: ansible_connection: local host6: ansible_connection: local vars: group_id: groupB groupC: hosts: host7: ansible_connection: local host8: ansible_connection: local host9: ansible_connection: local vars: group_id: groupC
Playbook
block/resucueとgroup_byを使って処理が失敗したホストをfailedグループに含め、
マジック変数のgroupsとグループ変数に定義したgroup_idを使って自分が所属するグループのホスト一覧を取得し、failedグループに含まれているホストが含まれてない場合のみ処理させます。
intersectフィルタはリストの共通する要素を抽出するもので、failedグループと共通する要素があればグループ内に失敗していたホストがあるといった条件にしました。
最後にfailedグループで処理することで失敗したホストを対象のなんやかんやできます resuceが動くとタスクの失敗ステータスが「取り消され」、成功したかのように続行していきます。
--- - name: グループ内の1hostが失敗していたら、ほかの処理も止めたい hosts: targets gather_facts: false connection: local tasks: - name: block block: - name: なにかしらの失敗 fail: msg: "Fail" when: "inventory_hostname == 'host1' or inventory_hostname == 'host8'" rescue: - name: 失敗したホストfailedグループに追加 group_by: key: failed - name: block when: ( groups[group_id] | intersect(groups['failed']) | length ) == 0 block: - name: 失敗無いグループのホストのみ処理 debug: msg: "Errorないよ" rescue: - name: 失敗したホストfailedグループに追加 group_by: key: failed - name: 失敗したホストの所属するグループを表示 hosts: failed gather_facts: false connection: local tasks: - name: dev debug: msg: "{{ group_id }}" - name: fail fail: msg: "Error"
実行結果
実行結果はこちらです。 rescueに引っかかるhost1とhost8は、後続の「失敗無いグループのホストのみ処理」でも実行対象になっていることから失敗が取り消されていることも確認できます
想定通り、host1の所属するgroupAとhost8が所属するgroupCの別ホストは処理をスキップさせ グループ内に失敗のないgroupBのみ処理させることができました
$ ansible-playbook group_in_error.yml -i hosts.yaml PLAY [グループ内の1hostが失敗していたら、ほかの処理も止めたい] ****************************************************** TASK [なにかしらの失敗] ********************************************************************************************* fatal: [host1]: FAILED! => {"changed": false, "msg": "Fail"} skipping: [host2] skipping: [host3] skipping: [host4] skipping: [host5] skipping: [host6] skipping: [host7] fatal: [host8]: FAILED! => {"changed": false, "msg": "Fail"} skipping: [host9] TASK [失敗したホストfailedグループに追加] *************************************************************************** changed: [host1] changed: [host8] TASK [失敗無いグループのホストのみ処理] ***************************************************************************** skipping: [host1] skipping: [host2] skipping: [host3] ok: [host4] => { "msg": "Errorないよ" } ok: [host5] => { "msg": "Errorないよ" } ok: [host6] => { "msg": "Errorないよ" } skipping: [host7] skipping: [host8] skipping: [host9] PLAY [失敗したホストの所属するグループを表示] *********************************************************************** TASK [dev] ********************************************************************************************************** ok: [host1] => { "msg": "groupA" } ok: [host8] => { "msg": "groupC" } TASK [fail] ********************************************************************************************************* fatal: [host1]: FAILED! => {"changed": false, "msg": "Error"} fatal: [host8]: FAILED! => {"changed": false, "msg": "Error"} PLAY RECAP ********************************************************************************************************** host1 : ok=2 changed=1 unreachable=0 failed=1 skipped=1 rescued=1 ignored=0 host2 : ok=0 changed=0 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0 host3 : ok=0 changed=0 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0 host4 : ok=1 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0 host5 : ok=1 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0 host6 : ok=1 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0 host7 : ok=0 changed=0 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0 host8 : ok=2 changed=1 unreachable=0 failed=1 skipped=1 rescued=1 ignored=0 host9 : ok=0 changed=0 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
わーい
別解も知りたい