2018年12月11日火曜日

Assertモジュールによる「テスト、確認の自動化」とTAP(Test Anything Protocol)


このエントリーをはてなブックマークに追加


本記事は以下の12日目の記事です。ノウハウの塊です。
https://qiita.com/advent-calendar/2018/ansibleblogger

こっちもおすすめです。
https://qiita.com/advent-calendar/2018/ansible

Ansibleの「自動化の確かさ」ををテストするノウハウも最近ちらほらと出始めました。

このあたりの記事はとても参考になります。

- コードとしてITインフラを定義する――自動化を超えた継続的改善の実現とは
- Molecule入門
- Ansible Playbook の CI をまわす
- GitLab CIでAnsibleの自作モジュールのCIをやってみる

Moleculeはとても良いです。Roleのテストの方向性が固まって来た感があります。インフラCI実践ガイドで取り上げたかったですが、執筆の構想をしたときにはそれほどメジャーではなかったので見送りました(入れておけばよかった・・・

インフラにおけるAnsibleのテストはこんな感じで整理できます。

(1)Role単品のテスト
(2)Roleを組み合わせときのテスト
(3)出来上がった結果を確認するテスト
(4)上記が時間経過や周辺環境の変更があっても動くのかを確認するテスト

(1)はMoleculeでほぼ十分です。(4)に関しては(1, 2, 3)に対してマトリックスを組んでのテストになります。

(2)は現状では少々悩ましいです。問題が出やすいところでもあります。特にチームで開発した場合には、単品のロールとしては完璧でも、組み合わせると矛盾がでるケースがあるからです。Moleculeだけでできるのかもうちょっと研究が必要。

(3)はインテグレーションテストやシステムテストに相当するテストです。ここはテストのシナリオを書いて、独自で実装する必要があります。いわゆるブラックボックステストとして非機能要件やシステムの振る舞いを確認する必要があります。

前置きは長くなりましたが、Ansibleでなにかを確認したいとき、そこで活躍するのが assert モジュールです。
https://docs.ansible.com/ansible/latest/modules/assert_module.html



assert モジュールは判定に特化したモジュールで、似たモジュールに fail があります。
https://docs.ansible.com/ansible/latest/modules/fail_module.html

assert は成功の条件を記述し、fail は失敗の条件を記述します。どちらを使うかは好みですが、むやみに混在させると混乱するので、正常系のチェックは assert, エラー系は fail などとルールを作っておくとよいです。

こういう使い方をよくします。

- ignore_errors: yes
  block:
  - name: check hoge
    shell: test hoge hoge
    register: result_hoge

  - name: check foo
    shell: test foo foo
    register: result_foo

  - name: check bar
    shell: test bar bar
    register: result_bar

- name: validate results
  assert:
    that: "{{ result.failed == false }}"
  loop:
    - result_hoge
    - result_foo
    - result_bar
  loop_control:
    loop_var: result

最初に、ignore_errors: yes でシナリオを全部流しておき、最後に結果の検証をまとめて行います。普通に書くとエラーが発生した箇所で止まってしまって残りの検証が行われないので、こうするとエラー箇所の特定などに何かと便利です。

Playbookはテスト結果が見にくいので、TAP形式(Test Anything Protocol)形式にすると結果がわかりやすくなります。こんなPluginがあります。
https://github.com/benwebber/ansible-tap

こんな感じでテスト結果を出力してくれます。

TAP version 13
ok - setup: Gathering Facts
ok - include_role
ok - command: Is httpd package installed?
ok - command: Is index.html present?
ok - command: Is httpd processe started?
ok - command: Is httpd service enabled?
ok - wait_for: Is port 80 opened?
ok - uri: Does the server return 200 OK?
ok - assert: check test results
1..9

Travis CI上のサンプルとログはこちら。
- https://github.com/irixjp/sd2018-ansible-ci/tree/ansible-tap
- OK https://travis-ci.org/irixjp/sd2018-ansible-ci/jobs/442512944#L741
- NG https://travis-ci.org/irixjp/sd2018-ansible-ci/jobs/442512949#L742

ignore_errors: yes 部分も出力してくれるので、とてもわかり易いです。
エラーの場合は、エラーメッセージを出力してくれます。

TAP形式は別の形式に簡単に加工できますので、こういうの を試してみるとCIに"和み"を持ち込むことができるかもしれません。