インフラテストツールのTestinfraを試してみた
For English
ServerSpecの代替になりうるテストツールのTestinfraを試してみたメモです。
以前別のテストツールのgossの記事も書いたので合わせて読んでいただければと。
Serverspecに代わるサーバテストツールGossを試してみた
Testinfraとは
https://testinfra.readthedocs.io/en/latest/
About With Testinfra you can write unit tests in Python to test actual state of your servers configured by management tools like Salt, Ansible, Puppet, Chef and so on. Testinfra aims to be a Serverspec equivalent in python and is written as a plugin to the powerful Pytest test engine
ざっくりいうとServerSpecのpython版で、Ansibleやchefなどの構成管理ツール実行後のテスト用途に使えるよ。とあります。
特徴
ServerSpecと比較した際に以下のような違いがあります。
豊富なバックエンド
TestinfraではシンプルなSSH以外にもリモートホストへの接続方法があります。
Ansibleのinventoryを共有できたり、docker,kubectlなどコンテナにも対応しています。
https://testinfra.readthedocs.io/en/latest/backends.html
- local
- paramiko
- docker
- ssh
- salt
- ansible
- kubectl
- winrm
- LXC/LXD
上記に対応しています。
対話式での実行
https://testinfra.readthedocs.io/en/latest/api.html
対話式での実行が可能なので、ファイルに書き出すことなくより手軽にテストできます。
ipython等と組み合わせるとより使いやすいです。
[koh@kohs-MBP] ~/vag_test % ipython Python 3.7.3 (default, May 1 2019, 16:07:48) Type 'copyright', 'credits' or 'license' for more information IPython 7.5.0 -- An enhanced Interactive Python. Type '?' for help. In [1]: import testinfra In [2]: host = testinfra.get_host("paramiko://vagrant@Vag1:22", sudo=True) In [3]: host.file("/etc/passwd").mode == 0o644 Out[3]: True In [4]:
試してみる
環境
実行元
MacOS Mojave 10.14.5
Python 3.7.3
実行先
CentOS 7.5.1804 on Vagrant
Python 2.7.5
インストール
実行元にpipでインストールします。
$ pip install testinfra
テスト作成
テストファイルを作成します。
test_first.py(クリックで展開)
def test_passwd_file(host):
passwd = host.file("/etc/passwd")
assert passwd.contains("root")
assert passwd.user == "root"
assert passwd.group == "root"
assert passwd.mode == 0o644
def test_nginx_running_and_enabled(host):
nginx = host.service("nginx")
assert nginx.is_running
assert nginx.is_enabled
def test_selinux(host):
cmd = host.run("/usr/sbin/getenforce")
assert cmd.stdout == "Enforcing\n"
テストの内容としては
となっています。
テスト実施
では実際にテストを実施してみます。
ローカルのMacからVagrant上のCentOSにSSHで接続してテストします。
なおVagrantにはnginxをインストールして起動させています。
テスト実施(クリックで展開)
[koh@kohs-MBP] ~/vag_test
% py.test -v test_first.py --connection=ssh --host=Vag1
======================================== test session starts ========================================
platform darwin -- Python 3.7.3, pytest-4.4.1, py-1.8.0, pluggy-0.9.0 -- /Users/koh/.pyenv/versions/3.7.3/bin/python3.7
cachedir: .pytest_cache
rootdir: /Users/koh/vag_test
plugins: xonsh-0.8.12, testinfra-3.0.5
collected 3 items
test_first.py::test_passwd_file[ssh://Vag1] PASSED [ 33%]
test_first.py::test_nginx_running_and_enabled[ssh://Vag1] PASSED [ 66%]
test_first.py::test_selinux[ssh://Vag1] PASSED [100%]
===================================== 3 passed in 3.22 seconds ======================================
[koh@kohs-MBP] ~/vag_test
%
結構見やすいですね。
では試しにNginxを停止してテストします。
テスト実施(クリックで展開)
[koh@kohs-MBP] ~/vag_test
% py.test -v test_first.py --connection=ssh --host=Vag1
======================================== test session starts ========================================
platform darwin -- Python 3.7.3, pytest-4.4.1, py-1.8.0, pluggy-0.9.0 -- /Users/koh/.pyenv/versions/3.7.3/bin/python3.7
cachedir: .pytest_cache
rootdir: /Users/koh/vag_test
plugins: xonsh-0.8.12, testinfra-3.0.5
collected 3 items
test_first.py::test_passwd_file[ssh://Vag1] PASSED [ 33%]
test_first.py::test_nginx_running_and_enabled[ssh://Vag1] FAILED [ 66%]
test_first.py::test_selinux[ssh://Vag1] PASSED [100%]
============================================= FAILURES ==============================================
____________________________ test_nginx_running_and_enabled[ssh://Vag1] _____________________________
host = <testinfra.host.Host object at 0x103826438>
def test_nginx_running_and_enabled(host):
nginx = host.service("nginx")
> assert nginx.is_running
E assert False
E + where False = <service nginx>.is_running
test_first.py:11: AssertionError
================================ 1 failed, 2 passed in 3.06 seconds =================================
zsh: exit 1 py.test -v test_first.py --connection=ssh --host=Vag1
[koh@kohs-MBP] ~/vag_test
%
どの項目でコケたのか、どのようにコケたのかもわかりやすいです。
複数ホストにも実行可能で、どのホストのどこでコケたのかわかりやすいです。
テスト実施(クリックで展開)
[koh@kohs-MBP] ~/vag_test
% py.test -v test_first.py --connection=ssh --host=Vag1,Vag2
======================================== test session starts ========================================
platform darwin -- Python 3.7.3, pytest-4.4.1, py-1.8.0, pluggy-0.9.0 -- /Users/koh/.pyenv/versions/3.7.3/bin/python3.7
cachedir: .pytest_cache
rootdir: /Users/koh/vag_test
plugins: xonsh-0.8.12, testinfra-3.0.5
collected 6 items
test_first.py::test_passwd_file[ssh://Vag1] PASSED [ 16%]
test_first.py::test_nginx_running_and_enabled[ssh://Vag1] PASSED [ 33%]
test_first.py::test_selinux[ssh://Vag1] PASSED [ 50%]
test_first.py::test_passwd_file[ssh://Vag2] PASSED [ 66%]
test_first.py::test_nginx_running_and_enabled[ssh://Vag2] FAILED [ 83%]
test_first.py::test_selinux[ssh://Vag2] FAILED [100%]
============================================= FAILURES ==============================================
____________________________ test_nginx_running_and_enabled[ssh://Vag2] _____________________________
host = <testinfra.host.Host object at 0x11026f4e0>
def test_nginx_running_and_enabled(host):
nginx = host.service("nginx")
> assert nginx.is_running
E assert False
E + where False = <service nginx>.is_running
test_first.py:11: AssertionError
_____________________________________ test_selinux[ssh://Vag2] ______________________________________
host = <testinfra.host.Host object at 0x11026f4e0>
def test_selinux(host):
cmd = host.run("/usr/sbin/getenforce")
> assert cmd.stdout == "Enforcing\n"
E AssertionError: assert 'Permissive\n' == 'Enforcing\n'
E - Permissive
E + Enforcing
test_first.py:17: AssertionError
================================ 2 failed, 4 passed in 6.14 seconds =================================
zsh: exit 1 py.test -v test_first.py --connection=ssh --host=Vag1,Vag2
[koh@kohs-MBP] ~/vag_test
%
まとめ
やはりServerSpecと比較すると使用できるmodule(resource)の数であったり、ネット上のドキュメントの量(特に日本語)に関してはServerSpecのほうが優れています。
ただ上記の通りTestinfraのほうが優れてる点も多いため、python派の方はTestinfraも検討する価値はあるのではないでしょうか。