changed_when と failed_when によるタスク状態の制御
このステップでは、Ansible がタスクの結果をどのように解釈するかをより細かく制御する方法を学びます。ここでは、changed_when と failed_when という 2 つの強力なディレクティブについて説明します。
changed_when: デフォルトでは、ansible.builtin.command や ansible.builtin.shell のようなモジュールは、実行したコマンドがシステムを変更しなかった場合でも、ほぼ常に「changed」状態を報告します。changed_when を使用すると、タスクが「changed」として報告されるかどうかを決定するカスタム条件を定義できます。これは、冪等性のある playbook を記述し、ハンドラーを正確にトリガーするために重要です。
failed_when: 場合によっては、コマンドの終了ステータスコードがゼロ以外であっても (Ansible はこれを失敗と見なします)、その結果が許容できることがあります。failed_when を使用すると、デフォルトの失敗条件を上書きでき、コマンドの出力や特定の終了コードなど、よりインテリジェントな基準に基づいて playbook を続行できます。
まず、新しいプロジェクト ディレクトリを設定しましょう。
cd ~/project
mkdir control-state-lab
cd control-state-lab
localhost 用の標準的な inventory ファイルを作成します。
nano inventory
次のコンテンツを追加します。
localhost ansible_connection=local
エディターを保存して終了します (Ctrl+X、Y、Enter)。
changed_when の使用
まず、コマンド タスクがデフォルトでどのように動作するかを見てみましょう。date コマンドを実行する playbook を作成します。このコマンドは日付を出力するだけでシステムを変更しませんが、command モジュールはこれを変更として報告します。
新しい playbook playbook.yml を作成します。
nano playbook.yml
次のコンテンツを入力します。
---
- name: Control Task State
hosts: localhost
tasks:
- name: Check local time (default behavior)
ansible.builtin.command: date
保存して終了します。次に、playbook を実行します。
ansible-playbook -i inventory playbook.yml
出力で、システムに変更が加えられていないにもかかわらず、タスクが changed=1 として報告されていることに注意してください。
...
TASK [Check local time (default behavior)] *************************************
changed: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 ...
次に、changed_when を使用して、このコマンドがシステムを変更しないことを Ansible に伝えます。playbook.yml を変更します。
nano playbook.yml
タスクに changed_when: false を追加します。
---
- name: Control Task State
hosts: localhost
tasks:
- name: Check local time (with changed_when)
ansible.builtin.command: date
changed_when: false
保存して終了します。playbook を再度実行します。
ansible-playbook -i inventory playbook.yml
今回は、タスクが ok を報告し、最終的な要約で changed=0 が表示されます。デフォルトの動作を正常にオーバーライドしました。
...
TASK [Check local time (with changed_when)] ************************************
ok: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 ...
failed_when の使用
次に、failed_when を調べます。存在しないファイルの存在を確認するタスクを作成します。コマンドはデフォルトで「失敗」します。
まず、ダミー ファイルを作成して検索対象とします。
echo "System is running" > status.txt
次に、playbook.yml を変更して、このファイル内の単語 "ERROR" を検索します。grep コマンドは、単語が見つからないため終了ステータス コード 1 で終了します。これは Ansible が失敗と解釈します。
nano playbook.yml
コンテンツを次のように置き換えます。
---
- name: Control Task State
hosts: localhost
tasks:
- name: Check for ERROR in status file (will fail)
ansible.builtin.command: grep ERROR status.txt
保存して終了します。playbook を実行します。
ansible-playbook -i inventory playbook.yml
予想どおり、playbook の実行は FAILED! メッセージで停止します。
...
TASK [Check for ERROR in status file (will fail)] ******************************
fatal: [localhost]: FAILED! => {"changed": true, "cmd": ["grep", "ERROR", "status.txt"], "delta": "...", "end": "...", "msg": "non-zero return code", "rc": 1, ...}
...
これは私たちが望むものではありません。 "ERROR" が存在しないことは、私たちにとって成功条件です。failed_when を使用して、何が失敗を構成するかを再定義できます。コマンドの戻りコードが 1 より大きい場合にのみ失敗するように Ansible に指示します。戻りコード 1 (パターンが見つからない) は、成功と見なされるようになります。また、戻りコード (rc) を検査するためにタスクの結果を register する必要があります。
最後に playbook.yml を変更します。
nano playbook.yml
register と failed_when で playbook を更新します。
---
- name: Control Task State
hosts: localhost
tasks:
- name: Check for ERROR in status file (with failed_when)
ansible.builtin.command: grep ERROR status.txt
register: grep_result
failed_when: grep_result.rc > 1
changed_when: false
grep は読み取り専用操作であり、システムを変更しないため、changed_when: false も追加しました。
保存して終了します。最後の playbook を実行します。
ansible-playbook -i inventory playbook.yml
成功しました!タスクの戻りコードは 1 であり、新しい失敗条件 (rc > 1) を満たさないため、タスクは ok を報告します。playbook は正常に完了します。
...
TASK [Check for ERROR in status file (with failed_when)] ***********************
ok: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 ...
これで、changed_when と failed_when を使用してタスクの成功、変更、および失敗の状態を正確に定義する方法を学びました。これにより、より堅牢でインテリジェントな自動化が可能になります。