Interpolating Ansible jinja in testinfra
One of idiosyncrasies of Ansible with pytest (testinfra) is that whilst you have access to inventory, any Jinja there will mess up you badly, as you will have a literal value with mustaches instead of expected interpolation.
Imagine an inventory:
foo:
foo1:
foobar: 42
foobar_slug: 'slug_{{ foobar }}'
Nothing fancy, right? (It become more fancy as soon as you get to {{ hostvars[groups.bar[0]].foo }}
)
You can use foobar_slug
in Ansible playbooks without any issues. But if you ever try to use it in tests (via host.ansible.get_inventory()
) it starts to fall apart. Because you get literal slug_{{ foobar }}
instead of expected slug_42
.
There is a neat trick. You can use debug
module of ansible to evaluate any jinja expression.
This is ‘magical fixture’:
@pytest.fixture(scope="module")
def eval(host):
def inner_eval(var):
return host.ansible("debug", "var=%s" % var)[var]
return inner_eval
You get fixture eval
, which allow you to safely extract value from inventory:
def test_foo(eval):
assert eval('foo_slug') == 'foo_42'
If you are not familiar with this ‘return inner…’, it’s a development pattern called ‘factory’. Instead of returning a value we return a function which can return a value.