はじめに
Ansible Roleに、想定外の状態で停止するエラー処理を実装していること
があると思います。このエラー処理が発生することをテストするにはどうすればよいかを
考えてみました。
TL;DR
- エラー処理が発生することをテストをするには、
block
セクションでAnsible Roleを
実行してエラーを起こし、rescue
セクションでエラーの内容を確認する。 -
rescue
セクションでは、変数ansible_failed_task
とansible_failed_result
で
エラーが発生したタスクの状況が確認可能。
前提条件
- Ansible Roleの基本的なディレクトリ構成を理解していること。
- Ansibleにおける
block
セクション、rescue
セクションの使い方を理解していること。
実行環境
- Python: 3.6.8
- Ansible: 2.9.7
詳細
1. テストするAnsible Role
- 今回はテスト用にAnsible Role「check-pass-flag」を作成しました。
メイン処理(tasks/main.yml)はシンプルで、変数pass_flag
がtrue
でない場合に
エラーが発生します。 - Ansible Roleでは、想定通りのタスクでエラーが発生するかを確認できるように、以下に注意しました。
- タスク名は重複しないようにする
- assertモジュールにはエラーメッセージ(fail_msg)を明示する
tasks/main.yml
---
- name: "Task1 - display pass_flag"
debug:
var: pass_flag
- name: "Task2 - check if pass_flag is true"
assert:
that:
- pass_flag is boolean
- pass_flag is true
fail_msg: "This task failed because pass_flag is not true" # エラーメッセージ
2. エラー内容の確認
2-1. エラー内容の確認用Playbook
- ここでは、エラー内容の確認用Playbookを実行します。ポイントは以下の通りです。
- 変数
pass_flag
をfalse
(trueではない値)にして、あえてAnsible Roleでエラーを
発生させる -
block
セクションでAnsible Roleを実行してエラーを起こし、rescue
セクションで
エラーの内容を確認する。エラーの内容は、変数ansible_failed_task
と
ansible_failed_result
に格納されるので、debug
モジュールで確認する
- 変数
test-check-pass-flag-1.yml
---
- name: "Test Ansible Role check-pass-flag"
hosts: localhost
vars:
pass_flag: false
gather_facts: false
tasks:
- block:
# ポイント1: 変数pass_flagがfalseなのでエラーが発生する
- name: "Import check-pass-flag"
import_role:
name: "check-pass-flag"
rescue:
# ポイント2: blockでエラーが発生すると以下の処理が実行される
- name: "Display ansible_failed_task"
debug:
var: ansible_failed_task
- name: "Display ansible_failed_result"
debug:
var: ansible_failed_result
2-2. 変数ansible_failed_taskの確認
Playbookを実行すると、想定通りAnsible Roleのタスク「Task2 - check if pass_flag is true」
でエラーが発生したので、まずは変数ansible_failed_task
の内容を確認します。
テストとして、エラーメッセージ(args.fail_msg)やエラーしたタスク名(name)が確認できそうです。
ansible_failed_task
---
args:
that:
- pass_flag is boolean
- pass_flag is true
fail_msg: This task failed because pass_flag is not true # エラーメッセージ
action: assert
async_val: 0
async: 0
changed_when: []
delay: 5
delegate_to: None
delegate_facts: None
failed_when: []
loop: None
loop_control: None
notify: None
poll: 15
register: None
retries: 3
until: []
loop_with: None
name: Task2 - check if pass_flag is true # エラーしたタスク名
# ~以下、省略~
2-3. 変数ansible_failed_resultの確認
変数ansible_failed_result
も同様に確認します。内容はansible_failed_task
より
少ないようですが、エラーしたassert文が何かまでわかります。
テストとして、エラーしたassert文(assertion)とエラーメッセージ(msg)が確認できそうです。
ansible_failed_result
---
assertion: pass_flag is true # エラーしたassert文
changed: false
evaluated_to: false
failed: true
msg: This task failed because pass_flag is not true # エラーメッセージ
3. エラー処理の動作確認
3-1. エラー処理の動作確認用Playbook
- ここでは、エラー処理の動作確認用Playbookを実行します。ポイントは以下の通りです。
- Ansible Roleでエラーが発生しなかった場合に備えて、failモジュールで強制的にエラーを発生させる
- 変数
ansible_failed_task
とansible_failed_result
の内容にもとづき、
assertモジュールで想定通りのエラーが発生していることを確認する
test-check-pass-flag-2.yml
---
- name: "Test Ansible Role check-pass-flag"
hosts: localhost
vars:
pass_flag: false
gather_facts: false
tasks:
- block:
# 変数pass_flagがfalseなのでエラーが発生する
- name: "Import check-pass-flag"
import_role:
name: "check-pass-flag"
# ポイント1: Ansible Roleでエラーが発生しなかった場合、ここでエラーになる
- name: "Force fail"
fail:
rescue:
# ポイント2: エラーしたタスク名とエラーメッセージを確認
- name: "Check ansible_failed_task"
assert:
that:
- ansible_failed_task.name == 'Task2 - check if pass_flag is true'
- >-
ansible_failed_task.args.fail_msg
== 'This task failed because pass_flag is not true'
# ポイント2: エラーしたassert文とエラーメッセージを確認
- name: "Check ansible_failed_result"
assert:
that:
- ansible_failed_result.assertion == 'pass_flag is true'
- >-
ansible_failed_result.msg
== 'This task failed because pass_flag is not true'
3-2. Playbookの実行結果
Playbookを実行すると、想定通りAnsible Roleのタスク「Task2 - check if pass_flag is true」
でエラーが発生していますが、rescue
セクションで想定通りのエラー処理が発生していることを確認できています。
$ ansible-playbook test-check-pass-flag-2.yml
PLAY [Test Ansible Role check-pass-flag] *******************************************************************************
TASK [check-pass-flag : Task1 - display pass_flag] *********************************************************************
ok: [localhost] =>
pass_flag: false
TASK [check-pass-flag : Task2 - check if pass_flag is true] ************************************************************
fatal: [localhost]: FAILED! => changed=false
assertion: pass_flag is true
evaluated_to: false
msg: This task failed because pass_flag is not true
TASK [Check ansible_failed_task] ***************************************************************************************
ok: [localhost] => changed=false
msg: All assertions passed
TASK [Check ansible_failed_result] *************************************************************************************
ok: [localhost] => changed=false
msg: All assertions passed
PLAY RECAP *************************************************************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=1 ignored=0
さいごに
-
block
セクションでAnsible Roleを実行してエラーを起こし、rescue
セクションで
エラーの内容を確認することで、エラー処理の動作確認ができました。 - Ansible Roleのテストについて、正常の動作だけでなくエラー処理の動作確認も
することで、より品質の高いAnsible Roleが開発できるのではないかと思います。
参考URL
-
Ansible Documentation - Blocks
- Blocksの使い方、エラー処理の方法など