How to check set_fact in molecule?

457 views Asked by At

I've created a simple task which creates a fact (new variable):

---
- name: Define internal user based on prefix
  set_fact:
    role_user_uid: "{{ lookup('vars', '{{ user_prefix }}_uid', default='') }}"

where user_prefix is defined in defaults/ as user_prefix: "ansible".

How can I create a test which checks that user_prefix has a specific value?

I've tried via testinfra

@pytest.fixture()
def AnsibleVars(host):
    all_vars = host.ansible.get_variables()
    return all_vars

def test_user_exists(host,AnsibleVars):
    print(AnsibleVars)
    var_prefix = AnsibleVars['user_prefix']

and via ansible provider:

- name: "test default user"
  assert:
    that:
      user_prefix == "ansible"

but I get errors that user_prefix is note defined.

I did enable gather_facts: yes in verify.yml

1

There are 1 answers

0
davedittrich On BEST ANSWER

The way I handle this is to save all vars to a .yml file at the end of the converge stage, so I can then later perform pytest tests based on the state of variables when converge completes.

The task to do this is placed in the converge.yml file for the scenario:

  post_tasks:
    - name: Dump all variables used to converge for later use.
      ansible.builtin.copy:
        content: |
          {{ vars | to_yaml }}
        dest: /tmp/ansible-vars.yml
        mode: 0o600
      changed_when: false
      delegate_to: localhost

To access these variables during pytest tests, do something along the lines of:

import os
import testinfra.utils.ansible_runner
import pytest
import yaml


with open('/tmp/ansible-vars.yml', 'r') as yaml_file:
    ansible_vars = yaml.safe_load(yaml_file)


def get_homedir(host=None, user=None):
    """Get user's home directory path in instance."""
    cmd = host.run(f'/usr/bin/getent passwd {user}')
    return cmd.stdout.split(':')[5]


@pytest.fixture(params=ansible_vars.get('accounts', []))
def fixture_users(request):
    return request.param


def test_bashrc_sources_aliases(host, fixture_users):
    user = fixture_users
    homedir = get_homedir(host=host, user=user)
    f = host.file(os.path.join(homedir, '.bashrc'))
    assert f.exists
    assert f.user == user
    assert r'. ~/.bash_aliases' in f.content_string

Not perfect, but DRY and avoids hard-coding and coupling of tasks to tests.

Don't forget to add this to the cleanup stage:

    - name: Delete variables saved from converge step.
      ansible.builtin.file:
        path: /tmp/ansible-vars.yml
        state: absent
      changed_when: false
      delegate_to: localhost

If anyone has a better way to do this, chime in! :)