question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Document testinfra vars management

See original GitHub issue

Issue Type

  • Feature request

Molecule and Ansible details

ansible --version && molecule --version

ansible 2.7.6
  config file = /home/ben/.ansible.cfg
  configured module search path = [u'/home/ben/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /home/ben/venv_ansible-2.7.6/local/lib/python2.7/site-packages/ansible
  executable location = /home/ben/venv_ansible-2.7.6/bin/ansible
  python version = 2.7.15rc1 (default, Nov 12 2018, 14:31:15) [GCC 7.3.0]
molecule, version 2.19.0

Molecule installation method (one of):

  • pip

Ansible installation method (one of):

  • pip

Desired Behavior

Warning: this could be considered two issues/features.

  1. When working with the provisioner section of molecule.yml for a scenario and feeding TestInfra tests, I notice that I have to violate DRY and explicitly define the values of role variables (e.g. those defined within defaults/main.yml) within the provisioner.inventory.group_vars/host_vars section of molecule.yml for the values to be picked up within TestInfra tests.

  2. Moreover, when defining the values of these vars within molecule.yml, I cannot reference the values of other variables using the "{{ }}" Ansible syntax. The double-curly braces seem to be interpreted as string literals and the value is not being substituted.

Examples:

  1. Given defaults/main.yml has the following:
win_mssql_instances:
  - instance_name: MSSQLSERVER
    features: SQLENGINE
    instance_collation: SQL_Latin1_General_CP1_CI_AS
    sysadmins:
      - "{{ inventory_hostname_short[:15] }}\\{{ ansible_user }}"
    sqlusers:
      - "{{ inventory_hostname_short[:15] }}\\{{ ansible_user }}"
    setupadmins:
      - "{{ inventory_hostname_short[:15] }}\\{{ ansible_user }}"
    svcaccount: "{{ inventory_hostname_short[:15] }}\\{{ ansible_user }}"
    svcpassword: "{{ ansible_password }}"
    instance_dir: C:\Program Files\Microsoft SQL Server
    installdb_path: C:\Program Files\Microsoft SQL Server\MSSQLSERVER\MSSQL\Data
    userldb_path: C:\Program Files\Microsoft SQL Server\MSSQLSERVER\MSSQL\Data
    userdblog_path: C:\Program Files\Microsoft SQL Server\MSSQLSERVER\MSSQL\Data
    tempdb_path: C:\Program Files\Microsoft SQL Server\MSSQLSERVER\MSSQL\Data
    tempdblog_path: C:\Program Files\Microsoft SQL Server\MSSQLSERVER\MSSQL\Data
    backup_path: C:\Program Files\Microsoft SQL Server\MSSQLSERVER\MSSQL\Backup
    databases:
      - mssql_db

If my molecule.yml does NOT also define this, then my TestInfra test:

def test_installed(host):
    """
    Checks that the package is installed
    :param host: instance under test
    :return: None
    """

    # get variables defined in molecule.yml inventory
    ansible_vars = host.ansible.get_variables()
    instances = ansible_vars["win_mssql_instances"]

    for inst in instances:
        path = inst["instance_dir"]
        ansible_args = "path='" + path + "' state=file"

        assert host.ansible("win_file",
                            ansible_args)["changed"] is False

Fails with:

$ molecule verify

>       instances = ansible_vars["win_mssql_instances"]
E       KeyError: 'win_mssql_instances'

However, if I do something like this (repeat myself) in my molecule.yml:

provisioner:
  name: ansible
  inventory:
    group_vars:
      mssql:
        win_mssql_instances:
          - instance_name: MSSQLSERVER
            features: SQLENGINE
            instance_collation: SQL_Latin1_General_CP1_CI_AS
            sysadmins:
              - "{{ inventory_hostname_short[:15] }}\\{{ ansible_user }}"
            sqlusers:
              - "{{ inventory_hostname_short[:15] }}\\{{ ansible_user }}"
            setupadmins:
              - "{{ inventory_hostname_short[:15] }}\\{{ ansible_user }}"
            svcaccount: "{{ inventory_hostname_short[:15] }}\\{{ ansible_user }}"
            svcpassword: "{{ ansible_password }}"
            instance_dir: C:\Program Files\Microsoft SQL Server
            installdb_path: C:\Program Files\Microsoft SQL Server\MSSQLSERVER\MSSQL\Data
            userldb_path: C:\Program Files\Microsoft SQL Server\MSSQLSERVER\MSSQL\Data
            userdblog_path: C:\Program Files\Microsoft SQL Server\MSSQLSERVER\MSSQL\Data
            tempdb_path: C:\Program Files\Microsoft SQL Server\MSSQLSERVER\MSSQL\Data
            tempdblog_path: C:\Program Files\Microsoft SQL Server\MSSQLSERVER\MSSQL\Data
            backup_path: C:\Program Files\Microsoft SQL Server\MSSQLSERVER\MSSQL\Backup
            databases:
              - mssql_db

Then it works as expected:

$ molecule verify

Verifier completed successfully.
  1. Given that I seem to have to do this (repeat myself) for role verification, then I often run into item/issue 2 where I cannot use the double-curly brace notation to reference Ansible magic vars or other vars within the role construct. This is again in relation to molecule verify and NOT molecule converge.

For example:

Given my molecule.yml contains:

provisioner:
  name: ansible
  inventory:
    group_vars:
      mssql:
        win_mssql_tmpdir: "C:\\TEMP\\Microsoft"
        win_mssql_extract_to: "{{ win_mssql_tmpdir}}\\MSSQL"
        win_mssql_extracts_path: "{{ win_mssql_extract_to }}\\Enterprise_Edition_x64\\setup.exe"

And my TestInfra test looks like:

def test_installer_extracted(host):
    """
    Checks that the installer is extracted
    :param host: instance under test
    :return: None
    """

    # get variables defined in molecule.yml inventory
    ansible_vars = host.ansible.get_variables()
    path = ansible_vars["win_mssql_extracts_path"]

    ansible_args = "path='" + path + "' state=file"

    assert host.ansible("win_file",
                        ansible_args)["changed"] is False

You can see the double-curly braces coming through seemingly as a string literal in the informational output:

INFO:testinfra:RUN Ansible('win_file', u"path='{{ win_mssql_extract_to }}\\Enterprise_Edition_x64\\setup.exe' state=file", {'check': True}): {'_ansible_no_log': False, '_ansible_parsed': True, u'changed': False}
tests/test_default.py::test_installer_extracted[ansible://knemol-ar-win-mssql-benlocal.kiewittest.com] PASSED

What’s more concerning, it is not properly reporting changed and the test is passing. If I hard-code an invalid file path (like I think I should):

provisioner:
  name: ansible
  inventory:
    group_vars:
      mssql:
        win_mssql_extracts_path: "C:\\fubar\\setup.exe"

I see an error that is apparently swallowed resulting in a passed test:

INFO:testinfra:RUN Ansible('win_file', u"path='C:\\fubar\\setup.exe' state=file", {'check': True}): {'_ansible_no_log': False,
 '_ansible_parsed': True,
 u'changed': False,
 u'msg': u"Get-AnsibleParam: Parameter 'path' has an invalid path 'C:\x0cubar\\setup.exe' specified."}
tests/test_default.py::test_installer_extracted[ansible://knemol-ar-win-mssql-benlocal.kiewittest.com] PASSED

But if I hard-code the path to handle the backslashes correctly for TestInfra:

provisioner:
  name: ansible
  inventory:
    group_vars:
      mssql:
        win_mssql_extracts_path: "C:\\\\fubar\\\\setup.exe"

I get this:

INFO:testinfra:RUN Ansible('win_file', u"path='C:\\\\fubar\\\\setup.exe' state=file", {'check': True}): {'_ansible_no_log': False,
 '_ansible_parsed': True,
 u'changed': False,
 u'msg': u'path C:\\fubar\\setup.exe will not be created'}
    tests/test_default.py::test_installer_extracted[ansible://knemol-ar-win-mssql-benlocal.kiewittest.com] PASSED

These appear to be TestInfra issues and/or Molecule feeding TestInfra, and they could be specific to my Windows-based roles under test, I’m not sure. I know there is a discussion about Molecule Verification in general (e.g. using a verify.yml Ansible playbook to do it). I kind of prefer the notion of a separate tool verifying Ansible rather than using Ansible to verify itself (this recent Boeing/FAA thing comes to mind).

Anyhow, my primary request is the whole not having to repeat yourself in molecule.yml, but we’ll see how this shakes out pending future verification discussions.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:5 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
1eftycommented, May 10, 2019

I found myself in this situation as well. You can create a pytest fixture to limit repetition.

@pytest.fixture(scope='module')
def AnsibleRoleDefaults(host):
  return host.ansible(
    'include_vars', '../../defaults/main.yml'
  }['ansible_facts']

def test_thing(host, AnsibleRoleDefaults):
  var = AnsibleRoleDefaults['var']
  var2 = host.ansible.get_variables()['var']

Due to the way testifnra creates the host fixture, using include_vars will work like it does within a play. So for some cases you might want to use debug msg={{ lookup('template','../../vars/main.yml') | from_yaml }}" this will get you the variables without bothering the variable space.


Would it be out of scope for molecule to provide these?

0reactions
RebelCodeBasecommented, Aug 4, 2019

Here is a pytest plugin that exposes ansible variables and facts, gopass secrets and the ansible python api as pytest fixtures in testinfra tests for molecule: testaid

Read more comments on GitHub >

github_iconTop Results From Across the Web

Modules — testinfra 7.0.2.dev1+gfc4bfd1.d20221210 ...
testinfra.modules.file.File class. group ¶ ... Returns a dict of ansible variables ... Test pip package manager and packages. is_installed ¶.
Read more >
testinfra Documentation - Read the Docs
With Testinfra you can write unit tests in Python to test actual state of your servers configured by management tools.
Read more >
testinfra(1) - Arch manual pages
With Testinfra you can write unit tests in Python to test actual state of your servers configured by management tools like Salt, Ansible,...
Read more >
Using Ansible variables in testinfra - python - Stack Overflow
Is this coming from a custom fact on the remote host, or is this set in a local variable file? – larsks. Oct...
Read more >
Ansible Best Practices: Part 2 - Polar Squad
Just use Ansible to enforce them rather than creating a hard to manage blob of entangled variables. Automation should make your life easier, ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found