Skip to content

Commit

Permalink
Define ANSIBLE_HOME to isolate from user environment
Browse files Browse the repository at this point in the history
  • Loading branch information
ssbarnea committed Jan 6, 2025
1 parent 306fbe9 commit 6a370a2
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 20 deletions.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"source.fixAll": "explicit",
"source.organizeImports": "explicit"
},
"editor.defaultFormatter": "ms-python.black-formatter",
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.formatOnSave": true
},
"editor.formatOnSave": true,
Expand Down
38 changes: 24 additions & 14 deletions src/ansible_compat/prerun.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,32 @@
"""Utilities for configuring ansible runtime environment."""

import hashlib
import os
import warnings
from pathlib import Path


def get_cache_dir(project_dir: Path) -> Path:
"""Compute cache directory to be used based on project path."""
# we only use the basename instead of the full path in order to ensure that
# we would use the same key regardless the location of the user home
# directory or where the project is clones (as long the project folder uses
# the same name).
basename = project_dir.resolve().name.encode(encoding="utf-8")
# 6 chars of entropy should be enough
cache_key = hashlib.sha256(basename).hexdigest()[:6]
cache_dir = (
Path(os.getenv("XDG_CACHE_HOME", "~/.cache")).expanduser()
/ "ansible-compat"
/ cache_key
)
"""Compute cache directory to be used based on project path.
If isolated=True, it will ensure ANSIBLE_HOME is defined.
"""
ansible_home: Path
if "ANSIBLE_HOME" in os.environ:
cache_dir = Path(os.environ["ANSIBLE_HOME"])
ansible_home = cache_dir
elif "VIRTUAL_ENV" in os.environ:
cache_dir = Path(os.environ["VIRTUAL_ENV"]) / ".ansible"
ansible_home = cache_dir
msg = f"ANSIBLE_HOME is not set, will will define it to {ansible_home} to ensure test isolation."
warnings.warn(msg, stacklevel=1)
os.environ["ANSIBLE_HOME"] = ansible_home.as_posix()
else:
cache_dir = Path("~/.ansible").expanduser() / ".ansible"
ansible_home = cache_dir

# create expected directory structure in order to avoid possible warnings
# or errors from ansible (ansible-galaxy in particular)
for subdir in ("roles",):
(Path(ansible_home) / subdir).mkdir(parents=True, exist_ok=True)

return cache_dir
4 changes: 2 additions & 2 deletions src/ansible_compat/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,8 @@ def __init__(
if "PYTHONWARNINGS" not in self.environ: # pragma: no cover
self.environ["PYTHONWARNINGS"] = "ignore:Blowfish has been deprecated"

if isolated:
self.cache_dir = get_cache_dir(self.project_dir)
self.cache_dir = get_cache_dir(self.project_dir)

self.config = AnsibleConfig(cache_dir=self.cache_dir)

# Add the sys.path to the collection paths if not isolated
Expand Down
13 changes: 10 additions & 3 deletions test/test_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ def test_runtime_prepare_ansible_paths_validation() -> None:
runtime._prepare_ansible_paths()


@pytest.mark.filterwarnings("ignore::UserWarning")
@pytest.mark.parametrize(
("folder", "role_name", "isolated"),
(
Expand Down Expand Up @@ -652,10 +653,10 @@ def test_upgrade_collection(runtime_tmp: Runtime) -> None:
runtime_tmp.require_collection("community.molecule", "0.1.0")


def test_require_collection_no_cache_dir() -> None:
@pytest.mark.filterwarnings("ignore::UserWarning")
def test_require_collection_not_isolated() -> None:
"""Check require_collection without a cache directory."""
runtime = Runtime()
assert not runtime.cache_dir
runtime = Runtime(isolated=False)
runtime.require_collection("community.molecule", "0.1.0", install=True)


Expand Down Expand Up @@ -1018,10 +1019,16 @@ def test_get_galaxy_role_name_invalid() -> None:
assert _get_galaxy_role_name(galaxy_infos) == ""


@pytest.mark.filterwarnings("ignore::UserWarning")
def test_runtime_has_playbook() -> None:
"""Tests has_playbook method."""
runtime = Runtime(require_module=True)

runtime.prepare_environment(
required_collections={"community.molecule": "0.1.0"},
install_local=True,
)

assert not runtime.has_playbook("this-does-not-exist.yml")
# call twice to ensure cache is used:
assert not runtime.has_playbook("this-does-not-exist.yml")
Expand Down

0 comments on commit 6a370a2

Please sign in to comment.