Using TestInfra with Ansible backend for testing purposes. Everything goes fine except using Ansible itself while running tests
test.py
import pytest
def test_zabbix_agent_package(host):
package = host.package("zabbix-agent")
assert package.is_installed
package_version = host.ansible("debug", "msg={{ zabbix_agent_version }}")["msg"]
(...)
where zabbix_agent_version is an Ansible variable from group_vars. It can be obtained by running this playbook
- hosts: all
become: true
tasks:
- name: debug
debug: msg={{ zabbix_agent_version }}
command executing tests
pytest --connection=ansible --ansible-inventory=inventory --hosts=$hosts -v test.py
ansible.cfg
[defaults]
timeout = 10
host_key_checking = False
library=library/
retry_files_enabled = False
roles_path=roles/
pipelining=true
ConnectTimeout=60
remote_user=deploy
private_key_file=/opt/jenkins/.ssh/deploy
the output I get is
self = <ansible>, module_name = 'debug', module_args = 'msg={{ zabbix_agent_version }}', check = True, kwargs = {}
result = {'failed': True, 'msg': "the field 'args' has an invalid value, which appears to include a variable that is undefined. The error was: 'zabbix_agent_version' is undefined"}
def __call__(self, module_name, module_args=None, check=True, **kwargs):
if not self._host.backend.HAS_RUN_ANSIBLE:
raise RuntimeError((
"Ansible module is only available with ansible "
"connection backend"))
result = self._host.backend.run_ansible(
module_name, module_args, check=check, **kwargs)
if result.get("failed", False) is True:
> raise AnsibleException(result)
E AnsibleException: Unexpected error: {'failed': True,
E 'msg': u"the field 'args' has an invalid value, which appears to include a variable that is undefined. The error was: 'zabbix_agent_version' is undefined"}
/usr/lib/python2.7/site-packages/testinfra/modules/ansible.py:70: AnsibleException
Any idea why Ansible can't see this variable when running testinfra's Ansible module while it can see it while running Ansible alone?
If zabbix_agent_version
is a variable set using group_vars
, then it seems as if you should be accessing it using host.ansible.get_variables()
rather than running debug
task. In any case, both should work. If I have, in my current directory:
test_myvar.py
group_vars/
all.yml
And in group_vars/all.yml
I have:
myvar: value
And in test_myvar.py
I have:
def test_myvar_using_get_variables(host):
all_variables = host.ansible.get_variables()
assert 'myvar' in all_variables
assert all_variables['myvar'] == 'myvalue'
def test_myvar_using_debug_var(host):
result = host.ansible("debug", "var=myvar")
assert 'myvar' in result
assert result['myvar'] == 'myvalue'
def test_myvar_using_debug_msg(host):
result = host.ansible("debug", "msg={{ myvar }}")
assert 'msg' in result
assert result['msg'] == 'myvalue'
Then all tests pass:
$ py.test --connection=ansible --ansible-inventory=hosts -v
test_myvar.py
============================= test session starts ==============================
platform linux2 -- Python 2.7.13, pytest-3.2.3, py-1.4.34, pluggy-0.4.0 -- /home/lars/env/common/bin/python2
cachedir: .cache
rootdir: /home/lars/tmp/testinfra, inifile:
plugins: testinfra-1.8.1.dev2
collected 3 items
test_myvar.py::test_myvar_using_get_variables[ansible://localhost] PASSED
test_myvar.py::test_myvar_using_debug_var[ansible://localhost] PASSED
test_myvar.py::test_myvar_using_debug_msg[ansible://localhost] PASSED
=========================== 3 passed in 1.77 seconds ===========================
Can you confirm that the layout of our files (in particular, the location of your group_vars
directory relative to the your tests) matches what I've shown here?
I chased an answer to this for days. Here's what finally worked for me. Essentially you are using testinfra's Ansible module to access the include_vars function of Ansible.
import pytest
@pytest.fixture()
def AnsibleVars(host):
ansible_vars = host.ansible(
"include_vars", "file=./group_vars/all/vars.yml")
return ansible_vars["ansible_facts"]
Then in my tests, I included the function as a parameter:
def test_something(host, AnsibleVars):
This solution was taken partially from https://github.com/metacloud/molecule/issues/151
I had an interesting issue where I was trying to include the variables from my main playbook and I was receiving an error of "must be stored as a dictionary/hash" when including the playbook.yml file. Separating the variables out into the group_vars/all/vars.yml file resolved that error.