Skip to content

Commit

Permalink
Remove code that modifies ansible import paths
Browse files Browse the repository at this point in the history
As part of new test-isolation strategy, molecule will no longer take
care itself about modification of:

- ANSIBLE_COLLECTIONS_PATH
- ANSIBLE_ROLES_PATH
- ANSIBLE_LIBRARY
- ANSIBLE_FILTER_PLUGINS

Test isolation is supposed to be covered transparently by
ansible-compat runtime when code runs inside a virtual environment.

Related: https://ansible.readthedocs.io/projects/dev-tools/user-guide/test-isolation/
  • Loading branch information
ssbarnea committed Jan 27, 2025
1 parent bf96a11 commit 9a7d114
Show file tree
Hide file tree
Showing 8 changed files with 4 additions and 346 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -178,3 +178,4 @@ tests/fixtures/resources/.extensions/

# docs output
_readthedocs/
.ansible
2 changes: 1 addition & 1 deletion docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ alter them when needed.

Yes, roles contained in a
[monorepo](https://en.wikipedia.org/wiki/Monorepo) with other roles are
automatically picked up and `ANSIBLE_ROLES_PATH` is set accordingly. See
automatically picked up. See
[this
page](guides/monolith.md)
for more information.
Expand Down
3 changes: 0 additions & 3 deletions docs/guides/monolith.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,6 @@ $ molecule --debug test
DEBUG: ANSIBLE ENVIRONMENT
---
ANSIBLE_CONFIG: /private/tmp/monolith-repo/roles/baz/molecule/default/.molecule/ansible.cfg
ANSIBLE_FILTER_PLUGINS: /Users/jodewey/.pyenv/versions/2.7.13/lib/python2.7/site-packages/molecule/provisioner/ansible/plugins/filters:/private/tmp/monolith-repo/roles/baz/plugins/filters:/private/tmp/monolith-repo/roles/baz/molecule/default/.molecule/plugins/filters
ANSIBLE_LIBRARY: /Users/jodewey/.pyenv/versions/2.7.13/lib/python2.7/site-packages/molecule/provisioner/ansible/plugins/libraries:/private/tmp/monolith-repo/roles/baz/library:/private/tmp/monolith-repo/roles/baz/molecule/default/.molecule/library
ANSIBLE_ROLES_PATH: /private/tmp/monolith-repo/roles:/private/tmp/monolith-repo/roles/baz/molecule/default/.molecule/roles
```

Molecule can be customized any number of ways. Updating the
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ markers = [
"serial: Run this test serially via filelock.",
"extensive: marks tests that we want to skip by default, as they are indirectly covered by other tests"
]
norecursedirs = ["scenarios"]
norecursedirs = ["scenarios", ".ansible"]
testpaths = "tests"
verbosity_assertions = 2

Expand Down
192 changes: 0 additions & 192 deletions src/molecule/provisioner/ansible.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# pylint: disable=too-many-lines
# Copyright (c) 2015-2018 Cisco Systems, Inc.

# Permission is hereby granted, free of charge, to any person obtaining a copy
Expand Down Expand Up @@ -34,7 +33,6 @@
from ansible_compat.ports import cached_property

from molecule import util
from molecule.api import drivers
from molecule.provisioner import ansible_playbook, ansible_playbooks, base


Expand Down Expand Up @@ -211,18 +209,6 @@ class Ansible(base.Base):
This feature should be considered experimental.
Environment variables. Molecule does its best to handle common Ansible
paths. The defaults are as follows.
::
ANSIBLE_ROLES_PATH:
$runtime_cache_dir/roles:$ephemeral_directory/roles/:$project_directory/../:~/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles
ANSIBLE_LIBRARY:
$ephemeral_directory/modules/:$project_directory/library/:~/.ansible/plugins/modules:/usr/share/ansible/plugins/modules
ANSIBLE_FILTER_PLUGINS:
$ephemeral_directory/plugins/filter/:$project_directory/filter/plugins/:~/.ansible/plugins/filter:/usr/share/ansible/plugins/modules
Environment variables can be passed to the provisioner. Variables in this
section which match the names above will be appended to the above defaults,
and converted to absolute paths, where the relative parent is the
Expand Down Expand Up @@ -471,81 +457,13 @@ def default_env(self) -> dict[str, str]:
Returns:
Default set of environment variables.
"""
# Finds if the current project is part of an ansible_collections hierarchy
collection_indicator = "ansible_collections"
# isolating test environment by injects ephemeral scenario directory on
# top of the collection_path_list. This prevents dependency commands
# from installing dependencies to user list of collections.
collections_path_list = [
util.abs_path(
os.path.join( # noqa: PTH118
self._config.scenario.ephemeral_directory,
"collections",
),
),
]
if collection_indicator in self._config.project_directory:
collection_path, right = self._config.project_directory.rsplit(
collection_indicator,
1,
)
collections_path_list.append(util.abs_path(collection_path))
collections_path_list.extend(
[
util.abs_path(
os.path.join( # noqa: PTH118
os.path.expanduser("~"), # noqa: PTH111
".ansible/collections",
),
),
"/usr/share/ansible/collections",
"/etc/ansible/collections",
],
)

if os.environ.get("ANSIBLE_COLLECTIONS_PATH", ""):
collections_path_list.extend(
list(
map(
util.abs_path,
os.environ["ANSIBLE_COLLECTIONS_PATH"].split(":"),
),
),
)

roles_path_list = [
util.abs_path(
os.path.join(self._config.scenario.ephemeral_directory, "roles"), # noqa: PTH118
),
util.abs_path(
os.path.join(self._config.project_directory, os.path.pardir), # noqa: PTH118
),
util.abs_path(
os.path.join(os.path.expanduser("~"), ".ansible", "roles"), # noqa: PTH111, PTH118
),
"/usr/share/ansible/roles",
"/etc/ansible/roles",
]

if os.environ.get("ANSIBLE_ROLES_PATH", ""):
roles_path_list.extend(
list(map(util.abs_path, os.environ["ANSIBLE_ROLES_PATH"].split(":"))),
)

env = util.merge_dicts(
dict(os.environ),
{
"ANSIBLE_CONFIG": self.config_file,
"ANSIBLE_ROLES_PATH": ":".join(roles_path_list),
"ANSIBLE_COLLECTIONS_PATH": ":".join(collections_path_list),
"ANSIBLE_LIBRARY": ":".join(self._get_modules_directories()),
"ANSIBLE_FILTER_PLUGINS": ":".join(
self._get_filter_plugins_directories(),
),
},
)
env = util.merge_dicts(env, self._config.env)

return env # noqa: RET504

@property
Expand Down Expand Up @@ -607,25 +525,6 @@ def env(self) -> dict[str, str]:
env = self._config.config["provisioner"]["env"].copy()
# ensure that all keys and values are strings
env = {str(k): str(v) for k, v in env.items()}

library_path = default_env["ANSIBLE_LIBRARY"]
filter_plugins_path = default_env["ANSIBLE_FILTER_PLUGINS"]

try:
path = self._absolute_path_for(env, "ANSIBLE_LIBRARY")
library_path = f"{library_path}:{path}"
except KeyError:
pass

try:
path = self._absolute_path_for(env, "ANSIBLE_FILTER_PLUGINS")
filter_plugins_path = f"{filter_plugins_path}:{path}"
except KeyError:
pass

env["ANSIBLE_LIBRARY"] = library_path
env["ANSIBLE_FILTER_PLUGINS"] = filter_plugins_path

return util.merge_dicts(default_env, env)

@property
Expand Down Expand Up @@ -1024,96 +923,5 @@ def _default_to_regular(
def _get_plugin_directory(self) -> str:
return os.path.join(self.directory, "plugins") # noqa: PTH118

def _get_modules_directories(self) -> list[str]:
"""Return list of ansible module includes directories.
Adds modules directory from molecule and its plugins.
Returns:
List of module includes directories.
"""
paths: list[str | None] = []
if os.environ.get("ANSIBLE_LIBRARY"):
paths = list(map(util.abs_path, os.environ["ANSIBLE_LIBRARY"].split(":")))

paths.append(
util.abs_path(os.path.join(self._get_plugin_directory(), "modules")), # noqa: PTH118
)

for d in drivers().values():
p = d.modules_dir()
if p:
paths.append(p)
paths.extend(
[
util.abs_path(
os.path.join( # noqa: PTH118
self._config.scenario.ephemeral_directory,
"library",
),
),
util.abs_path(
os.path.join(self._config.project_directory, "library"), # noqa: PTH118
),
util.abs_path(
os.path.join( # noqa: PTH118
os.path.expanduser("~"), # noqa: PTH111
".ansible",
"plugins",
"modules",
),
),
"/usr/share/ansible/plugins/modules",
],
)

return [path for path in paths if path is not None]

def _get_filter_plugin_directory(self) -> str:
return util.abs_path(os.path.join(self._get_plugin_directory(), "filter")) # noqa: PTH118

def _get_filter_plugins_directories(self) -> list[str]:
"""Return list of ansible filter plugins includes directories.
Returns:
List of filter includes directories.
"""
paths: list[str | None] = []
if os.environ.get("ANSIBLE_FILTER_PLUGINS"):
paths = list(
map(util.abs_path, os.environ["ANSIBLE_FILTER_PLUGINS"].split(":")),
)

paths.extend(
[
self._get_filter_plugin_directory(),
util.abs_path(
os.path.join( # noqa: PTH118
self._config.scenario.ephemeral_directory,
"plugins",
"filter",
),
),
util.abs_path(
os.path.join( # noqa: PTH118
self._config.project_directory,
"plugins",
"filter",
),
),
util.abs_path(
os.path.join( # noqa: PTH118
os.path.expanduser("~"), # noqa: PTH111
".ansible",
"plugins",
"filter",
),
),
"/usr/share/ansible/plugins/filter",
],
)

return [path for path in paths if path is not None]

def _absolute_path_for(self, env: dict[str, str], key: str) -> str:
return ":".join([self.abs_path(p) for p in env[key].split(":")])
Loading

0 comments on commit 9a7d114

Please sign in to comment.