pytest-dev / pytest-testinfra

Testinfra test your infrastructures
https://testinfra.readthedocs.io
Apache License 2.0
2.38k stars 355 forks source link

Ansible hostpattern for ansible connection #602

Open ITD27M01 opened 3 years ago

ITD27M01 commented 3 years ago

Hi,

Is there any way to pass the ansible hostpattern to testinfra_hosts? I have dynamic inventory which provides all the hosts from Prod and Dev environments. I'm working with them like:

ansible-playbook play.yaml --limit Prod
ansible-playbook play.yaml --limit Dev

But both environments have the same groups (db, web, app). Can I pass host pattern like 'db:&Prod' to testinfra_hosts ?

https://docs.ansible.com/ansible/latest/user_guide/intro_patterns.html

philpep commented 3 years ago

Hi, testinfra will match hosts and/or groups but no patterns yet. I guess this should be feasible in the future.

ITD27M01 commented 3 years ago

Hi @philpep

As an example, you can consider the corresponding lookup plugin - inventory_hostnames. It returns the list of hostnames which can be used as a source for testinfra_hosts: https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/lookup/inventory_hostnames.py

Is there any reason to use external call to ansible-inventory cmd?

ITD27M01 commented 3 years ago

A've played with this:

> python
Python 3.8.5 (default, Sep  4 2020, 02:22:02) 
[Clang 10.0.0 ] :: Anaconda, Inc. on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from ansible.parsing.dataloader import DataLoader
>>> from ansible.inventory.manager import InventoryManager
>>> loader = DataLoader()
>>> inventory = InventoryManager(loader=loader, sources='inventory')
>>> inventory.get_hosts(pattern='db:&Prod')
>>> ['my', 'hosts', 'from', 'Prod']
>>> inventory.get_hosts(pattern='db:&Dev')
>>> ['my', 'hosts', 'from', 'Dev']

Inventory sources can be retrieved from config or from cmdline.

philpep commented 3 years ago

@ITD27M01 thanks for your inputs !

I think we must avoid to use the "API" because we do this in the past and caused us a lot of issues (tl;dr; ansible API isn't stable and practical). I didn't manage to run inventory_hostnames module with the command line but I just saw ansible has a --list-hosts option that output hosts matching pattern:

ansible -m noop --list-hosts <pattern>

If some of you have some time to spend on it that would be an awesome contribution :)

amarao commented 3 years ago

I played a bit with --list-hosts, and it works.

patterns:

It looks like it solves all practical issues.

The problem I see here is the & use. It's used in parameters of 'host url' (ansible://group?force_ansibe=True&sudo=True), and adding & in the url (ansible://group:&group2?force_ansibe=True&sudo=True) looks a bit hard to understand for humans (and robots?).

philpep commented 3 years ago

@amarao yes I think theses special characters should be urlencoded, which will not help humans :/

Note we can also use plain options instead of url, e.g. python -m pytest --connection ansible --sudo --force-ansible --hosts 'g1:&g2' which is more readable. (but not supposed through testinfra_hosts defined in module).

amarao commented 3 years ago

Command line options is not always available. Consider molecule scenario:

...
verifier:
  name: testinfra
  options:
    sudo: false
    showlocals: true
    verbose: true
    color: 'yes'

Molecule picks up all tests inside tests directory, so if there are different tests for different groups, the single option is to have testinfra_hosts magical variable inside each module.

The actual call to Testinfra from Molecule looks like this:

pytest --ansible-inventory ../cache/molecule/../default/inventory --color yes --connection ansible --debug -p no:cacheprovider --showlocals .../molecule/default/tests/test_one.py .../molecule/default/tests/test_two.py ....

So, the testinfra_hosts, is, basically, the single way to customize tests target.

Code0x58 commented 5 months ago

753 improves matching to allow patterns, without being dependent on ansible modules