koh’s blog

Sys Admin who loves automation

TestinfraとAnsibleを組み合わせて使う

For English

インフラテストツールのTestinfraをAnsibleと組み合わせて使用すると色々と捗るよという投稿です。
Testinfraについては以前ブログを書いているので見ていただければと。

koh-sh.hatenablog.com

Inventoryの共有

TestinfraはAnsibleのInventoryの情報を参照することができます。
そのためAnsibleで管理している情報をそのままテストへ活用できます。

https://testinfra.readthedocs.io/en/latest/backends.html#ansible

$ py.test --hosts='ansible://all' # tests all inventory hosts
$ py.test --hosts='ansible://host1,ansible://host2'
$ py.test --hosts='ansible://web*'
$ py.test --force-ansible --hosts='ansible://all'
$ py.test --hosts='ansible://host?force_ansible=True'

Inventoryファイルをansible.cfg等で設定せずにオプションで指定する場合には--ansible-inventory=ANSIBLE_INVENTORYで指定できます。

Ansibleのmoduleの実行

Testinfraのテストの中でAnsibleのmoduleを実行することができます。

https://testinfra.readthedocs.io/en/latest/modules.html#ansible

[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("ansible://Vag1")

In [3]: host.ansible("command", "echo foo", check=False)
Out[3]:
{'ansible_facts': {'discovered_interpreter_python': '/usr/bin/python'},
 'changed': True,
 'cmd': ['echo', 'foo'],
 'delta': '0:00:00.004734',
 'end': '2019-10-05 15:07:42.251008',
 'rc': 0,
 'start': '2019-10-05 15:07:42.246274',
 'stderr': '',
 'stderr_lines': [],
 'stdout': 'foo',
 'stdout_lines': ['foo']}

In [4]:

こちらはcommandモジュールを実行してみた例です。
実行した結果としてchangedやrc, stdout等Ansibleで実行したときと同様のデータが帰ってきます。

setupモジュールを使用するテストとしては下記のようなイメージでしょうか。

[koh@kohs-MBP] ~/vag_test
% cat test_ansible.py
def test_dns(host):
    nameservers = host.ansible("setup")["ansible_facts"]["ansible_dns"]["nameservers"]
    assert '10.1.1.1' in nameservers
[koh@kohs-MBP] ~/vag_test
% 
[koh@kohs-MBP] ~/vag_test
% py.test -v test_ansible.py --hosts='ansible://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, inifile: pytest.ini
plugins: xonsh-0.8.12, testinfra-3.0.5
collected 1 item

test_ansible.py::test_dns[ansible://Vag1] FAILED                                              [100%]

============================================= FAILURES ==============================================
_____________________________________ test_dns[ansible://Vag1] ______________________________________

host = <testinfra.host.Host object at 0x10e9be748>

    def test_dns(host):
        nameservers = host.ansible("setup")["ansible_facts"]["ansible_dns"]["nameservers"]
>       assert '10.1.1.1' in nameservers
E       AssertionError: assert '10.1.1.1' in ['10.0.2.3']

test_ansible.py:3: AssertionError
===================================== 1 failed in 2.17 seconds ======================================
zsh: exit 1     py.test -v test_ansible.py --hosts='ansible://Vag1'
[koh@kohs-MBP] ~/vag_test
%

setupの結果からnameserverの情報を取得しテストすることができました。

Variableの共有

Ansible側で定義されているVariableを参照できます。
参照できる変数はhost_varsとgroup_varsで定義されているものとinventory_hostname等の一部の変数です。
Playbook内でinclude_vars等で定義しているものは参照できないのでご注意ください。

[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("ansible://Vag1")

In [3]: host.ansible.get_variables()
Out[3]:
{'aaa': 'bbb',
 'foo': 'bar',
 'hoge': 'fuga',
 'inventory_hostname': 'Vag1',
 'group_names': ['Vag'],
 'groups': {'Vag': ['Vag1', 'Vag2', 'Vag3'], 'all': ['Vag1', 'Vag2', 'Vag3']}}

In [4]:

まとめ

現在MoleculeでもTestinfraがデフォルトのテストツールとして採用されているように、かなりAnsibleとの相性がいいと感じました。
Testinfraは他にもDockerやKubenatesとも組み合わせることができるので色々と試していきたいです。