Search code examples
python-3.xansibletestinfra

testinfra - ansible variables not interpreted correctly


With testinfra, I'm using get_variables() method from testinfra.modules.ansible.Ansible but it seems that testinfra cannot evaluate my Ansible variable.

Let's describe my poc.

~/tmp/ansible-testinfra
├── inventories
│   ├── group_vars
│   │   └── all.yml
│   └── inventory.ini
└── test_simple.py

I defined 2 variables :

# inventories/group_vars/all.yml

---
one: "value one"
two: "{{ one }} and value two"

and my inventory.ini is a simple localhost :

# inventories/inventory

[all]
localhost

I created a very simple test like this :

# test_simple.py

import pprint

def test_print_variables(host):
    pprint.pprint(host.ansible.get_variables())
    
def test_variables(host):
    my_vars = host.ansible.get_variables()
    assert my_vars['two'] == 'value one and value two'

When I run pytest, here is my sdtout :

~/tmp/ansible-testinfra$ pytest --hosts "ansible://all?ansible_inventory=inventories/inventory.ini" -s --tb=no
============================================================================ test session starts ============================================================================
platform linux -- Python 3.6.9, pytest-6.2.2, py-1.10.0, pluggy-0.13.1
rootdir: /home/olhoa/tmp/ansible-testinfra
plugins: testinfra-6.1.0
collected 2 items                                                                                                                                                           

test_simple.py {'group_names': ['ungrouped'],
 'groups': {'all': ['localhost'], 'ungrouped': ['localhost']},
 'inventory_hostname': 'localhost',
 'one': 'value one',
 'two': '{{ one }} and value two'}
.F

========================================================================== short test summary info ==========================================================================
FAILED test_simple.py::test_variables[ansible://localhost] - AssertionError: assert '{{ one }} and value two' == 'value one and value two'

As you can see, variable one is not interpreted when used in variable two.

So, is this possible to do this and how ?

Thank you for your feedback ! :)


Solution

  • You're testing the inventory. The result is correct

    shell> ansible-inventory -i inventory.ini --graph --vars
    @all:
      |--@ungrouped:
      |  |--localhost
      |  |  |--{one = value one}
      |  |  |--{two = {{ one }} and value two}
      |--{one = value one}
      |--{two = {{ one }} and value two}
    

    Quoting from Glossary:

    Lazy Evaluation: In general, Ansible evaluates any variables in playbook content at the last possible second, which means that if you define a data structure that data structure itself can define variable values within it, and everything “just works” as you would expect. This also means variable strings can include other variables inside of those strings.

    To evaluate the variables in playbook content write one, e.g.

    shell> cat playbook
    - hosts: localhost
      tasks:
        - debug:
            var: one
        - debug:
            var: two
    

    gives

    shell> ansible-playbook playbook.yml -i inventory.ini
    
    ...
    
    TASK [debug] ************************************************************
    ok: [localhost] => 
      one: value one
    
    TASK [debug] ************************************************************
    ok: [localhost] => 
      two: value one and value two
    

    As a side note, see Understanding variable precedence. In Ansible, the variable precedence is rather complex, e.g.

    shell> ansible-playbook playbook.yml -i inventory.ini -e one=X
    
    ...
    
    TASK [debug] ************************************************************
    ok: [localhost] => 
      one: X
    
    TASK [debug] ************************************************************
    ok: [localhost] => 
      two: X and value two