Skip to content
This repository was archived by the owner on Sep 14, 2023. It is now read-only.

Commit d561ac0

Browse files
committed
Add option to add markers for unavailable drivers
This will allow users to run only scenarios that can be run on their machines. Initial implementation does validation only for delegated and docker drivers. For delegated driver, we assume current inventory is valid if we find presence of zuul variable. This should protect againt accidental execution of ansible tasks on localhost.
1 parent adc4002 commit d561ac0

File tree

3 files changed

+102
-3
lines changed

3 files changed

+102
-3
lines changed

README.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,17 @@ executed inside a specific scenario.
4848

4949
All tests are added the ``molecule`` marker.
5050

51+
This plugin also adds a new pytest option named
52+
``--molecule-unavailable-driver=skip`` which can be used to tell it what to do
53+
when molecule drivers are not loading. Current default is ``skip`` but you
54+
can choose other marks like ``xfail`` or empty string if you want to disable
55+
this functionality.
56+
57+
Current implementation of this feature validates only ``docker`` and
58+
``delegated`` drivers. Due to the potential destructive nature of delegated
59+
driver, scenarios running it will run only if Ansible detects one of the
60+
following variables as defined: ``zuul``, ``use_for_testing``.
61+
5162
Installation
5263
------------
5364

pytest_molecule/__init__.py

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,95 @@
1111
from molecule.config import molecule_drivers
1212

1313

14+
def pytest_addoption(parser):
15+
group = parser.getgroup("molecule")
16+
help_msg = (
17+
"What marker to add to molecule scenarios when driver is "
18+
"unavailable. (ex: skip, xfail)"
19+
)
20+
default = "skip"
21+
dest = "molecule_unavailable_driver"
22+
23+
group.addoption(
24+
"--molecule-unavailable-driver",
25+
action="store",
26+
dest=dest,
27+
default=default,
28+
help=help_msg,
29+
)
30+
31+
parser.addini(dest, help_msg, default=default)
32+
33+
1434
def pytest_configure(config):
1535

36+
config.option.molecule = {}
1637
for driver in molecule_drivers():
1738
config.addinivalue_line(
1839
"markers", "{0}: mark test to run only when {0} is available".format(driver)
1940
)
41+
config.option.molecule[driver] = {"available": True}
42+
# TODO(ssbarnea): extend molecule itself to allow it to report usable drivers
43+
if driver == "docker":
44+
try:
45+
import docker
46+
47+
# validate docker connectivity
48+
# Default docker value is 60s but we want to fail faster
49+
# With parallel execution 5s proved to give errors.
50+
c = docker.from_env(timeout=10, version="auto")
51+
if not c.ping():
52+
raise Exception("Failed to ping docker server.")
53+
54+
except Exception as e:
55+
msg = "Molecule {} driver is not available due to: {}.".format(
56+
driver, e
57+
)
58+
if config.option.molecule_unavailable_driver:
59+
msg += " We will tag scenarios using it with '{}' marker.".format(
60+
config.option.molecule_unavailable_driver
61+
)
62+
logging.getLogger().warning(msg)
63+
config.option.molecule[driver]["available"] = False
64+
65+
if driver == "delegated":
66+
# To protect ourselves from case where a molecule scenario using
67+
# `delegated` is accidentally altering the localhost on a developer
68+
# machine, we verify run delegated tests only when ansible `zuul`
69+
# or `use_for_testing` vars are defined.
70+
cmd = [
71+
"ansible",
72+
"localhost",
73+
"-e",
74+
"ansible_connection=local" "-o",
75+
"-m",
76+
"shell",
77+
"-a",
78+
"exit {% if zuul is defined or use_for_testing is defined %}0{% else %}1{% endif %}",
79+
]
80+
try:
81+
p = subprocess.Popen(
82+
cmd,
83+
stdout=subprocess.DEVNULL,
84+
stderr=subprocess.DEVNULL,
85+
universal_newlines=True,
86+
)
87+
p.wait()
88+
if p.returncode != 0:
89+
raise Exception(
90+
"Error code %s returned by: %s" % (p.returncode, " ".join(cmd))
91+
)
92+
except Exception:
93+
msg = "Molecule {} driver was not enabled because missing zuul.build variable in current inventory.".format(
94+
driver
95+
)
96+
if config.option.molecule_unavailable_driver:
97+
msg += " We will tag scenarios using it with '{}' marker.".format(
98+
config.option.molecule_unavailable_driver
99+
)
100+
logging.getLogger().warning(msg)
101+
config.option.molecule[driver]["available"] = False
102+
20103
config.addinivalue_line("markers", "molecule: mark used by all molecule scenarios")
21104

22105
# validate selinux availability
@@ -65,6 +148,11 @@ def __init__(self, name, parent):
65148
)
66149
self.add_marker(p)
67150
self.add_marker("molecule")
151+
if (
152+
self.config.option.molecule_unavailable_driver
153+
and not self.config.option.molecule[self.molecule_driver]["available"]
154+
):
155+
self.add_marker(self.config.option.molecule_unavailable_driver)
68156

69157
def runtest(self):
70158
folders = self.fspath.dirname.split(os.sep)
@@ -80,7 +168,6 @@ def runtest(self):
80168
cmd.extend(shlex.split(opts))
81169

82170
print("running: %s (from %s)" % (" ".join(quote(arg) for arg in cmd), cwd))
83-
84171
try:
85172
# Workaround for STDOUT/STDERR line ordering issue:
86173
# https://github.com/pytest-dev/pytest/issues/5449

tox.ini

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,17 @@ deps =
1818
pytest-html>=1.21.0
1919
selinux>=0.1.5rc1
2020
commands =
21+
ansible-inventory --graph
2122
pytest --collect-only
2223
# pytest already needs built wheel in dist/
2324
python -m pep517.build \
2425
--source \
2526
--binary \
2627
--out-dir {toxinidir}/dist/ {toxinidir}
27-
pytest --color=yes --html={envlogdir}/reports.html --self-contained-html {tty:-s} -k foo
28+
pytest --color=yes --html={envlogdir}/reports.html --self-contained-html {tty:-s} --molecule-unavailable-driver= -k foo
2829
setenv =
2930
ANSIBLE_FORCE_COLOR={env:ANSIBLE_FORCE_COLOR:1}
30-
ANSIBLE_INVENTORY={toxinidir}/tests/hosts.ini
31+
ANSIBLE_INVENTORY={env:ANSIBLE_INVENTORY:{toxinidir}/../zuul-infra/inventory.yml}
3132
ANSIBLE_CONFIG={toxinidir}/ansible.cfg
3233
ANSIBLE_NOCOWS=1
3334
ANSIBLE_RETRY_FILES_ENABLED=0

0 commit comments

Comments
 (0)