Coder Social home page Coder Social logo

Question: accessing values of variables as they are being used for provisioning an instance inside Testinfra tests about molecule HOT 7 CLOSED

ansible avatar ansible commented on July 17, 2024
Question: accessing values of variables as they are being used for provisioning an instance inside Testinfra tests

from molecule.

Comments (7)

abeluck avatar abeluck commented on July 17, 2024 3

@Perdjesk Very nice!
You can remove the need for an external file by using copy instead of template:

   - name: dump
      copy:
        content: |
          {{ vars | to_yaml }}
        dest: /tmp/ansible-vars.yml

from molecule.

Perdjesk avatar Perdjesk commented on July 17, 2024 1

I had an use case in which I wanted to inspect variables set with set_fact during the role's tasks. In order to have access to those variables in TestInfra code, the variables are dumped to the instance filesystem as a post_tasksof the converge playbook and loaded from filesystem during TestInfra test.

Molecule converge playbook:

---
- name: Converge
  hosts: all
  roles:
    - role: <role>

  post_tasks:
    - name: dump
      template:
        src: templates/ansible-vars.yml.j2
        dest: /tmp/ansible-vars.yml
      changed_when: False

Note: changed_when: False is required since the the vars being dumped contains variables that change at each Ansible run (timestamp, run duration, ..). Without it the idempotence step will fail.

templates/ansible-vars.yml.j2:

{{ vars | to_yaml }}

test_default.py:

import os

import yaml

import testinfra.utils.ansible_runner

testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
    os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all')


def test_ansible_vars(host):

    stream = host.file('/tmp/ansible-vars.yml').content
    ansible_vars = yaml.load(stream)
    assert ansible_vars['var_to_test'] == 'expected_value_of_var'

from molecule.

melodous avatar melodous commented on July 17, 2024

Hi tjanez,

We load ansible variables files (defaults and vars) with the following functions, maybe it works for you:

@pytest.fixture(scope="module")
def AnsibleDefaults(Ansible):
return Ansible("include_vars","./defaults/main.yml")["ansible_facts"]

@pytest.fixture(scope="module")
def AnsibleVars(Ansible):
return Ansible("include_vars","./vars/main.yml")["ansible_facts"]

Regards

Raรบl Melo

from molecule.

retr0h avatar retr0h commented on July 17, 2024

Also, molecule executes ansible-playbook with an inventory path of -i .molecule/ansible_inventory. However, in molecule's case this is host inventory. Only the contents of this file, are available to testinfra. I would have expected Ansible to provide defaults as part of this inventory. However, @melodous has come up with a rather creative solution.

from molecule.

tjanez avatar tjanez commented on July 17, 2024

@melodous, thanks for sharing your code, it was very valuable.

I had to adapt your approach a bit since I want to create a role that loads different variables depending on value of ansible_distribution and another variable (postgresql_install_source in the example code below):

import os.path

import pytest

@pytest.fixture()
def AnsibleDistribution(Ansible):
    return Ansible("setup")["ansible_facts"]["ansible_distribution"]

@pytest.fixture()
def AnsiblePostgresqlInstallSource(Ansible):
    return Ansible("debug", "msg={{ postgresql_install_source }}")["msg"]

@pytest.fixture()
def AnsibleVars(Ansible, AnsibleDistribution, AnsiblePostgresqlInstallSource):
    if AnsibleDistribution == "fedora":
        vars_file = "fedora.yml"
    elif AnsibleDistribution in ["CentOS", "RedHat"]:
        if AnsiblePostgresqlInstallSource == "centos_scl_repo":
            vars_file = "centos_scl_repo.yml"
        else:
            vars_file = "RedHat.yml"
    else:
        raise ValueError("Unsupported distribution: " + AnsibleDistribution)
    return Ansible("include_vars", os.path.join("./vars/", vars_file))["ansible_facts"]

def test_postgresql_running_and_enabled(Service, AnsibleVars):
    postgresql = Service(AnsibleVars["postgresql_unit_name"])
    assert postgresql.is_running
    assert postgresql.is_enabled

I had to modify .molecule/ansible_inventory and define the postgresql_install_source variable there since this is what gets passed to Testinfra (as @retr0h explained in the previous comment).

However, this is not very usable yet since .molecule/ansible_inventory is over-written after performing a cycle of commands:

molecule destroy
molecule create
molecule converge

Is it possible to specify additional variables to put into the inventory file for an instance at the level of molecule.yml?
Or is there another approach that would be able to control the values of variables of a role on a particular instance and the values could also be accessed from Testinfra tests?

from molecule.

retr0h avatar retr0h commented on July 17, 2024

Is it possible to specify additional variables to put into the inventory file for an instance at the level of molecule.yml?
Or is there another approach that would be able to control the values of variables of a role on a particular instance and the values could also be accessed from Testinfra tests?

Not currently, but welcome PRs.

from molecule.

akerouanton avatar akerouanton commented on July 17, 2024

Once #3313 got merged, you can use the following line to get all the vars defined for a given host (including host/group vars and recursive variable expansion):

# molecule/defaults/group_vars/my_group.yml
foo: foo
bar: "{{ foo }}bar"
ansible_vars = host.ansible('debug', 'msg={{ hostvars[inventory_hostname] }}')
print(ansible_vars['msg']['bar']) # Will output: foobar

from molecule.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.