mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-07-05 08:23:08 +02:00
Reorgenized test structure and added validation of inventory before deployment
This commit is contained in:
parent
fe04f1955f
commit
a9f55579a2
@ -4,8 +4,9 @@ import argparse
|
|||||||
import subprocess
|
import subprocess
|
||||||
import os
|
import os
|
||||||
import datetime
|
import datetime
|
||||||
|
import sys
|
||||||
|
|
||||||
def run_ansible_playbook(inventory, playbook, modes, limit=None, password_file=None, verbose=0, skip_tests:bool=False):
|
def run_ansible_playbook(inventory, playbook, modes, limit=None, password_file=None, verbose=0, skip_tests=False):
|
||||||
start_time = datetime.datetime.now()
|
start_time = datetime.datetime.now()
|
||||||
print(f"\n▶️ Script started at: {start_time.isoformat()}\n")
|
print(f"\n▶️ Script started at: {start_time.isoformat()}\n")
|
||||||
|
|
||||||
@ -94,6 +95,10 @@ def main():
|
|||||||
"--skip-tests", action="store_true",
|
"--skip-tests", action="store_true",
|
||||||
help="Skip running 'make test' even if tests are normally enabled."
|
help="Skip running 'make test' even if tests are normally enabled."
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--skip-validation", action="store_true",
|
||||||
|
help="Skip inventory validation before deployment."
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-v", "--verbose", action="count", default=0,
|
"-v", "--verbose", action="count", default=0,
|
||||||
help="Increase verbosity level. Multiple -v flags increase detail (e.g., -vvv for maximum log output)."
|
help="Increase verbosity level. Multiple -v flags increase detail (e.g., -vvv for maximum log output)."
|
||||||
@ -101,6 +106,17 @@ def main():
|
|||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if not args.skip_validation:
|
||||||
|
print("\n🔍 Validating inventory before deployment...\n")
|
||||||
|
try:
|
||||||
|
subprocess.run(
|
||||||
|
[sys.executable, os.path.join(script_dir, "validate_inventory.py"), os.path.dirname(args.inventory)],
|
||||||
|
check=True
|
||||||
|
)
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
print("\n❌ Inventory validation failed. Deployment aborted.\n", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
modes = {
|
modes = {
|
||||||
"mode_reset": args.reset,
|
"mode_reset": args.reset,
|
||||||
"mode_test": args.test,
|
"mode_test": args.test,
|
||||||
|
@ -46,6 +46,22 @@ def compare_application_keys(applications, defaults, source_file):
|
|||||||
return errors
|
return errors
|
||||||
|
|
||||||
|
|
||||||
|
def compare_user_keys(users, default_users, source_file):
|
||||||
|
errors = []
|
||||||
|
for username, user_conf in users.items():
|
||||||
|
if username not in default_users:
|
||||||
|
print(f"Warning: {source_file}: Unknown user '{username}' (not in default_users)", file=sys.stderr)
|
||||||
|
continue
|
||||||
|
|
||||||
|
default_conf = default_users.get(username, {})
|
||||||
|
for key in user_conf:
|
||||||
|
if key in ("password", "credentials", "mailu_token"):
|
||||||
|
continue # ignore credentials/password
|
||||||
|
if key not in default_conf:
|
||||||
|
raise Exception(f"{source_file}: Missing default for user '{username}': key '{key}'")
|
||||||
|
return errors
|
||||||
|
|
||||||
|
|
||||||
def load_inventory_files(inventory_dir):
|
def load_inventory_files(inventory_dir):
|
||||||
all_data = {}
|
all_data = {}
|
||||||
inventory_path = Path(inventory_dir)
|
inventory_path = Path(inventory_dir)
|
||||||
@ -69,32 +85,51 @@ def load_inventory_files(inventory_dir):
|
|||||||
return all_data
|
return all_data
|
||||||
|
|
||||||
|
|
||||||
def find_defaults_applications_file():
|
def find_single_file(pattern):
|
||||||
candidates = list(Path("group_vars/all").glob("*_applications.yml"))
|
candidates = list(Path("group_vars/all").glob(pattern))
|
||||||
if len(candidates) != 1:
|
if len(candidates) != 1:
|
||||||
raise RuntimeError(f"Expected exactly one *_applications.yml file in group_vars/all, found {len(candidates)}")
|
raise RuntimeError(f"Expected exactly one {pattern} file in group_vars/all, found {len(candidates)}")
|
||||||
return candidates[0]
|
return candidates[0]
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description="Verify application variable consistency with defaults.")
|
parser = argparse.ArgumentParser(description="Verify application and user variable consistency with defaults.")
|
||||||
parser.add_argument("inventory_dir", help="Path to inventory directory (contains inventory.yml and *_vars/)")
|
parser.add_argument("inventory_dir", help="Path to inventory directory (contains inventory.yml and *_vars/)")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
defaults_path = find_defaults_applications_file()
|
defaults_path = find_single_file("*_applications.yml")
|
||||||
|
users_path = find_single_file("*users.yml")
|
||||||
|
|
||||||
defaults_data = load_yaml_file(defaults_path)
|
defaults_data = load_yaml_file(defaults_path)
|
||||||
|
default_users_data = load_yaml_file(users_path)
|
||||||
|
|
||||||
defaults = defaults_data.get("defaults_applications", {}) if defaults_data else {}
|
defaults = defaults_data.get("defaults_applications", {}) if defaults_data else {}
|
||||||
|
default_users = default_users_data.get("default_users", {}) if default_users_data else {}
|
||||||
|
|
||||||
if not defaults:
|
if not defaults:
|
||||||
print(f"Error: No 'defaults_applications' found in {defaults_path}.", file=sys.stderr)
|
print(f"Error: No 'defaults_applications' found in {defaults_path}.", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
if not default_users:
|
||||||
|
print(f"Error: No 'default_users' found in {users_path}.", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
all_errors = []
|
all_errors = []
|
||||||
|
|
||||||
inventory_files = load_inventory_files(args.inventory_dir)
|
inventory_files = load_inventory_files(args.inventory_dir)
|
||||||
for source_path, app_data in inventory_files.items():
|
for source_path, app_data in inventory_files.items():
|
||||||
errors = compare_application_keys(app_data, defaults, str(source_path))
|
errors = compare_application_keys(app_data, defaults, str(source_path))
|
||||||
all_errors.extend(errors)
|
all_errors.extend(errors)
|
||||||
|
|
||||||
|
# Load all users.yml files from inventory
|
||||||
|
for path in Path(args.inventory_dir).rglob("*.yml"):
|
||||||
|
data = load_yaml_file(path)
|
||||||
|
if isinstance(data, dict) and "users" in data:
|
||||||
|
try:
|
||||||
|
compare_user_keys(data["users"], default_users, str(path))
|
||||||
|
except Exception as e:
|
||||||
|
print(e, file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
if all_errors:
|
if all_errors:
|
||||||
print("Validation failed with the following issues:")
|
print("Validation failed with the following issues:")
|
||||||
for err in all_errors:
|
for err in all_errors:
|
21
tests/integration/test_check_init_files.py
Normal file
21
tests/integration/test_check_init_files.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
class TestInitFiles(unittest.TestCase):
|
||||||
|
def test_all_test_dirs_have_init(self):
|
||||||
|
"""
|
||||||
|
Ensure every subdirectory in the 'tests' folder (excluding '__pycache__') contains an '__init__.py' file.
|
||||||
|
"""
|
||||||
|
tests_root = Path(__file__).resolve().parents[2] / "tests"
|
||||||
|
|
||||||
|
for path in tests_root.rglob("*"):
|
||||||
|
if path.is_dir() and "__pycache__" not in path.parts:
|
||||||
|
init_file = path / "__init__.py"
|
||||||
|
with self.subTest(directory=str(path.relative_to(tests_root))):
|
||||||
|
self.assertTrue(
|
||||||
|
init_file.exists(),
|
||||||
|
f"Missing __init__.py in directory: {path}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
0
tests/unit/cli/__init__.py
Normal file
0
tests/unit/cli/__init__.py
Normal file
@ -5,7 +5,7 @@ from unittest import mock
|
|||||||
|
|
||||||
# Ensure cli module is importable
|
# Ensure cli module is importable
|
||||||
dir_path = os.path.abspath(
|
dir_path = os.path.abspath(
|
||||||
os.path.join(os.path.dirname(__file__), '../../cli')
|
os.path.join(os.path.dirname(__file__), '../../../cli')
|
||||||
)
|
)
|
||||||
sys.path.insert(0, dir_path)
|
sys.path.insert(0, dir_path)
|
||||||
|
|
@ -43,7 +43,7 @@ class TestGenerateDefaultApplicationsUsers(unittest.TestCase):
|
|||||||
When a users.yml exists with defined users, the script should inject a 'users'
|
When a users.yml exists with defined users, the script should inject a 'users'
|
||||||
mapping in the generated YAML, mapping each username to a Jinja2 reference.
|
mapping in the generated YAML, mapping each username to a Jinja2 reference.
|
||||||
"""
|
"""
|
||||||
script_path = Path(__file__).resolve().parents[2] / "cli" / "generate_applications.py"
|
script_path = Path(__file__).resolve().parents[3] / "cli" / "generate_applications.py"
|
||||||
result = subprocess.run([
|
result = subprocess.run([
|
||||||
"python3", str(script_path),
|
"python3", str(script_path),
|
||||||
"--roles-dir", str(self.roles_dir),
|
"--roles-dir", str(self.roles_dir),
|
@ -29,7 +29,7 @@ class TestGenerateDefaultApplications(unittest.TestCase):
|
|||||||
shutil.rmtree(self.temp_dir)
|
shutil.rmtree(self.temp_dir)
|
||||||
|
|
||||||
def test_script_generates_expected_yaml(self):
|
def test_script_generates_expected_yaml(self):
|
||||||
script_path = Path(__file__).resolve().parent.parent.parent / "cli" / "generate_applications.py"
|
script_path = Path(__file__).resolve().parent.parent.parent.parent / "cli" / "generate_applications.py"
|
||||||
|
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
[
|
[
|
@ -7,7 +7,7 @@ import shutil
|
|||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
# Adjust path to include cli/ folder
|
# Adjust path to include cli/ folder
|
||||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../..", "cli")))
|
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../../..", "cli")))
|
||||||
|
|
||||||
from generate_playbook import build_dependency_graph, topological_sort, generate_playbook_entries
|
from generate_playbook import build_dependency_graph, topological_sort, generate_playbook_entries
|
||||||
|
|
@ -7,7 +7,7 @@ import yaml
|
|||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
# Add cli/ to import path
|
# Add cli/ to import path
|
||||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../..", "cli")))
|
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../../..", "cli")))
|
||||||
|
|
||||||
import generate_users
|
import generate_users
|
||||||
|
|
@ -10,7 +10,7 @@ from unittest.mock import patch
|
|||||||
sys.path.insert(
|
sys.path.insert(
|
||||||
0,
|
0,
|
||||||
os.path.abspath(
|
os.path.abspath(
|
||||||
os.path.join(os.path.dirname(__file__), "../../cli")
|
os.path.join(os.path.dirname(__file__), "../../../cli")
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
134
tests/unit/cli/test_validate_inventory.py
Normal file
134
tests/unit/cli/test_validate_inventory.py
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
import unittest
|
||||||
|
import tempfile
|
||||||
|
import shutil
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
SCRIPT_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../../cli/validate_inventory.py"))
|
||||||
|
|
||||||
|
class TestValidateInventory(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.temp_dir = tempfile.mkdtemp()
|
||||||
|
self.group_vars_all = Path(self.temp_dir) / "group_vars" / "all"
|
||||||
|
self.group_vars_all.mkdir(parents=True)
|
||||||
|
|
||||||
|
self.inventory_dir = Path(self.temp_dir) / "inventory"
|
||||||
|
self.inventory_dir.mkdir()
|
||||||
|
|
||||||
|
# Create default applications file
|
||||||
|
self.default_applications = {
|
||||||
|
"defaults_applications": {
|
||||||
|
"app1": {
|
||||||
|
"port": 8080,
|
||||||
|
"enabled": True,
|
||||||
|
"settings": {
|
||||||
|
"theme": "dark"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(self.group_vars_all / "01_applications.yml").write_text(
|
||||||
|
yaml.dump(self.default_applications), encoding="utf-8"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create default users file
|
||||||
|
self.default_users = {
|
||||||
|
"default_users": {
|
||||||
|
"alice": {
|
||||||
|
"email": "alice@example.com",
|
||||||
|
"role": "admin"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(self.group_vars_all / "01_users.yml").write_text(
|
||||||
|
yaml.dump(self.default_users), encoding="utf-8"
|
||||||
|
)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
shutil.rmtree(self.temp_dir)
|
||||||
|
|
||||||
|
def run_script(self, expected_code=0):
|
||||||
|
result = subprocess.run(
|
||||||
|
[sys.executable, SCRIPT_PATH, str(self.inventory_dir)],
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
encoding="utf-8",
|
||||||
|
cwd=self.temp_dir
|
||||||
|
)
|
||||||
|
if result.returncode != expected_code:
|
||||||
|
print("STDOUT:", result.stdout)
|
||||||
|
print("STDERR:", result.stderr)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def test_valid_inventory(self):
|
||||||
|
(self.inventory_dir / "group_vars.yml").write_text(yaml.dump({
|
||||||
|
"applications": {
|
||||||
|
"app1": {
|
||||||
|
"port": 8080,
|
||||||
|
"enabled": True,
|
||||||
|
"settings": {
|
||||||
|
"theme": "dark"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"users": {
|
||||||
|
"alice": {
|
||||||
|
"email": "alice@example.com",
|
||||||
|
"role": "admin",
|
||||||
|
"password": "secret"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}), encoding="utf-8")
|
||||||
|
|
||||||
|
result = self.run_script(expected_code=0)
|
||||||
|
self.assertIn("Inventory directory is valid against defaults", result.stdout)
|
||||||
|
|
||||||
|
def test_unknown_user_warning(self):
|
||||||
|
(self.inventory_dir / "invalid_users.yml").write_text(yaml.dump({
|
||||||
|
"users": {
|
||||||
|
"bob": {
|
||||||
|
"email": "bob@example.com",
|
||||||
|
"role": "user"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}), encoding="utf-8")
|
||||||
|
|
||||||
|
result = self.run_script(expected_code=0)
|
||||||
|
self.assertIn("Warning", result.stderr)
|
||||||
|
|
||||||
|
def test_missing_user_key_fails(self):
|
||||||
|
(self.inventory_dir / "invalid_key.yml").write_text(yaml.dump({
|
||||||
|
"users": {
|
||||||
|
"alice": {
|
||||||
|
"email": "alice@example.com",
|
||||||
|
"role": "admin",
|
||||||
|
"extra": "unexpected"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}), encoding="utf-8")
|
||||||
|
|
||||||
|
result = self.run_script(expected_code=1)
|
||||||
|
self.assertIn("Missing default for user 'alice': key 'extra'", result.stderr)
|
||||||
|
|
||||||
|
def test_missing_application_key_fails(self):
|
||||||
|
(self.inventory_dir / "missing_key.yml").write_text(yaml.dump({
|
||||||
|
"applications": {
|
||||||
|
"app1": {
|
||||||
|
"port": 8080,
|
||||||
|
"enabled": True,
|
||||||
|
"settings": {
|
||||||
|
"theme": "dark"
|
||||||
|
},
|
||||||
|
"extra_setting": True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}), encoding="utf-8")
|
||||||
|
|
||||||
|
result = self.run_script(expected_code=1)
|
||||||
|
self.assertIn("Missing default for app1: extra_setting", result.stdout)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
0
tests/unit/filter_plugins/__init__.py
Normal file
0
tests/unit/filter_plugins/__init__.py
Normal file
@ -6,7 +6,7 @@ from ansible.errors import AnsibleFilterError
|
|||||||
|
|
||||||
# ensure filter_plugins is on the path
|
# ensure filter_plugins is on the path
|
||||||
dir_path = os.path.abspath(
|
dir_path = os.path.abspath(
|
||||||
os.path.join(os.path.dirname(__file__), '../../filter_plugins')
|
os.path.join(os.path.dirname(__file__), '../../../filter_plugins')
|
||||||
)
|
)
|
||||||
sys.path.insert(0, dir_path)
|
sys.path.insert(0, dir_path)
|
||||||
|
|
@ -6,7 +6,7 @@ import unittest
|
|||||||
sys.path.insert(
|
sys.path.insert(
|
||||||
0,
|
0,
|
||||||
os.path.abspath(
|
os.path.abspath(
|
||||||
os.path.join(os.path.dirname(__file__), "../../roles/docker-matrix")
|
os.path.join(os.path.dirname(__file__), "../../../roles/docker-matrix")
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -7,7 +7,7 @@ import os
|
|||||||
sys.path.insert(
|
sys.path.insert(
|
||||||
0,
|
0,
|
||||||
os.path.abspath(
|
os.path.abspath(
|
||||||
os.path.join(os.path.dirname(__file__), "../../")
|
os.path.join(os.path.dirname(__file__), "../../../")
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -7,7 +7,7 @@ import os
|
|||||||
sys.path.insert(
|
sys.path.insert(
|
||||||
0,
|
0,
|
||||||
os.path.abspath(
|
os.path.abspath(
|
||||||
os.path.join(os.path.dirname(__file__), "../../")
|
os.path.join(os.path.dirname(__file__), "../../../")
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -5,7 +5,7 @@ import sys
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
# Add filter_plugins/ to the import path
|
# Add filter_plugins/ to the import path
|
||||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../..", "filter_plugins")))
|
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../../..", "filter_plugins")))
|
||||||
|
|
||||||
from docker_image import FilterModule
|
from docker_image import FilterModule
|
||||||
|
|
@ -4,7 +4,7 @@ import unittest
|
|||||||
|
|
||||||
# Add the filter_plugins directory to the import path
|
# Add the filter_plugins directory to the import path
|
||||||
dir_path = os.path.abspath(
|
dir_path = os.path.abspath(
|
||||||
os.path.join(os.path.dirname(__file__), '../../filter_plugins')
|
os.path.join(os.path.dirname(__file__), '../../../filter_plugins')
|
||||||
)
|
)
|
||||||
sys.path.insert(0, dir_path)
|
sys.path.insert(0, dir_path)
|
||||||
|
|
@ -5,7 +5,7 @@ import os
|
|||||||
# Ensure filter_plugins directory is on the path
|
# Ensure filter_plugins directory is on the path
|
||||||
sys.path.insert(
|
sys.path.insert(
|
||||||
0,
|
0,
|
||||||
os.path.abspath(os.path.join(os.path.dirname(__file__), '../../filter_plugins'))
|
os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../filter_plugins'))
|
||||||
)
|
)
|
||||||
|
|
||||||
from generate_all_domains import FilterModule
|
from generate_all_domains import FilterModule
|
@ -5,7 +5,7 @@ import os
|
|||||||
# Ensure filter_plugins directory is on the path
|
# Ensure filter_plugins directory is on the path
|
||||||
sys.path.insert(
|
sys.path.insert(
|
||||||
0,
|
0,
|
||||||
os.path.abspath(os.path.join(os.path.dirname(__file__), '../filter_plugins'))
|
os.path.abspath(os.path.join(os.path.dirname(__file__), '../../filter_plugins'))
|
||||||
)
|
)
|
||||||
|
|
||||||
from generate_base_sld_domains import FilterModule
|
from generate_base_sld_domains import FilterModule
|
@ -4,7 +4,7 @@ import unittest
|
|||||||
|
|
||||||
# Add the filter_plugins directory to the import path
|
# Add the filter_plugins directory to the import path
|
||||||
dir_path = os.path.abspath(
|
dir_path = os.path.abspath(
|
||||||
os.path.join(os.path.dirname(__file__), '../../filter_plugins')
|
os.path.join(os.path.dirname(__file__), '../../../filter_plugins')
|
||||||
)
|
)
|
||||||
sys.path.insert(0, dir_path)
|
sys.path.insert(0, dir_path)
|
||||||
|
|
@ -4,7 +4,7 @@ import unittest
|
|||||||
|
|
||||||
# Add the filter_plugins directory to the import path
|
# Add the filter_plugins directory to the import path
|
||||||
dir_path = os.path.abspath(
|
dir_path = os.path.abspath(
|
||||||
os.path.join(os.path.dirname(__file__), '../../filter_plugins')
|
os.path.join(os.path.dirname(__file__), '../../../filter_plugins')
|
||||||
)
|
)
|
||||||
sys.path.insert(0, dir_path)
|
sys.path.insert(0, dir_path)
|
||||||
|
|
@ -7,7 +7,7 @@ import os
|
|||||||
sys.path.insert(
|
sys.path.insert(
|
||||||
0,
|
0,
|
||||||
os.path.abspath(
|
os.path.abspath(
|
||||||
os.path.join(os.path.dirname(__file__), '../../filter_plugins')
|
os.path.join(os.path.dirname(__file__), '../../../filter_plugins')
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -5,7 +5,7 @@ from unittest.mock import patch, mock_open
|
|||||||
from ansible.errors import AnsibleFilterError
|
from ansible.errors import AnsibleFilterError
|
||||||
|
|
||||||
# make sure our plugin is on PYTHONPATH
|
# make sure our plugin is on PYTHONPATH
|
||||||
root = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../filter_plugins'))
|
root = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../filter_plugins'))
|
||||||
sys.path.insert(0, root)
|
sys.path.insert(0, root)
|
||||||
|
|
||||||
import load_configuration
|
import load_configuration
|
@ -5,7 +5,7 @@ import unittest
|
|||||||
sys.path.insert(
|
sys.path.insert(
|
||||||
0,
|
0,
|
||||||
os.path.abspath(
|
os.path.abspath(
|
||||||
os.path.join(os.path.dirname(__file__), "../../")
|
os.path.join(os.path.dirname(__file__), "../../../")
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -5,7 +5,7 @@ import os
|
|||||||
# Ensure filter_plugins directory is on the path
|
# Ensure filter_plugins directory is on the path
|
||||||
sys.path.insert(
|
sys.path.insert(
|
||||||
0,
|
0,
|
||||||
os.path.abspath(os.path.join(os.path.dirname(__file__), '../../filter_plugins'))
|
os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../filter_plugins'))
|
||||||
)
|
)
|
||||||
|
|
||||||
from safe_join import safe_join
|
from safe_join import safe_join
|
@ -5,7 +5,7 @@ import os
|
|||||||
# Ensure filter_plugins directory is on the path
|
# Ensure filter_plugins directory is on the path
|
||||||
sys.path.insert(
|
sys.path.insert(
|
||||||
0,
|
0,
|
||||||
os.path.abspath(os.path.join(os.path.dirname(__file__), '../../filter_plugins'))
|
os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../filter_plugins'))
|
||||||
)
|
)
|
||||||
|
|
||||||
from safe import safe_placeholders
|
from safe import safe_placeholders
|
@ -6,7 +6,7 @@ from jinja2 import Undefined
|
|||||||
# Ensure filter_plugins directory is on the path
|
# Ensure filter_plugins directory is on the path
|
||||||
sys.path.insert(
|
sys.path.insert(
|
||||||
0,
|
0,
|
||||||
os.path.abspath(os.path.join(os.path.dirname(__file__), '../../filter_plugins'))
|
os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../filter_plugins'))
|
||||||
)
|
)
|
||||||
|
|
||||||
from safe import FilterModule
|
from safe import FilterModule
|
0
tests/unit/lookup_plugins/__init__.py
Normal file
0
tests/unit/lookup_plugins/__init__.py
Normal file
@ -6,7 +6,7 @@ import unittest
|
|||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
dir_path = os.path.abspath(
|
dir_path = os.path.abspath(
|
||||||
os.path.join(os.path.dirname(__file__), '../../lookup_plugins')
|
os.path.join(os.path.dirname(__file__), '../../../lookup_plugins')
|
||||||
)
|
)
|
||||||
sys.path.insert(0, dir_path)
|
sys.path.insert(0, dir_path)
|
||||||
|
|
@ -5,7 +5,7 @@ import shutil
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
# Adjust the PYTHONPATH to include the lookup_plugins folder from the docker-portfolio role.
|
# Adjust the PYTHONPATH to include the lookup_plugins folder from the docker-portfolio role.
|
||||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../../roles/docker-portfolio/lookup_plugins'))
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../../../roles/docker-portfolio/lookup_plugins'))
|
||||||
|
|
||||||
from docker_cards import LookupModule
|
from docker_cards import LookupModule
|
||||||
|
|
0
tests/unit/module_utils/__init__.py
Normal file
0
tests/unit/module_utils/__init__.py
Normal file
@ -4,17 +4,10 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
# Add module_utils/ to the import path
|
# Add the project root/module_utils to the import path
|
||||||
sys.path.insert(
|
CURRENT_DIR = os.path.dirname(__file__)
|
||||||
0,
|
PROJECT_ROOT = os.path.abspath(os.path.join(CURRENT_DIR, "../../.."))
|
||||||
os.path.abspath(
|
sys.path.insert(0, PROJECT_ROOT)
|
||||||
os.path.join(
|
|
||||||
os.path.dirname(__file__),
|
|
||||||
"../../..",
|
|
||||||
"module_utils",
|
|
||||||
)
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
from module_utils.cert_utils import CertUtils
|
from module_utils.cert_utils import CertUtils
|
||||||
|
|
0
tests/unit/roles/__init__.py
Normal file
0
tests/unit/roles/__init__.py
Normal file
@ -8,7 +8,7 @@ import sys
|
|||||||
def load_optimizer_module():
|
def load_optimizer_module():
|
||||||
module_path = os.path.abspath(os.path.join(
|
module_path = os.path.abspath(os.path.join(
|
||||||
os.path.dirname(__file__),
|
os.path.dirname(__file__),
|
||||||
'..', "..", 'roles', 'system-storage-optimizer', 'files', 'system-storage-optimizer.py'
|
'..', "..", "..","..",'roles', 'system-storage-optimizer', 'files', 'system-storage-optimizer.py'
|
||||||
))
|
))
|
||||||
spec = importlib.util.spec_from_file_location('storage_optimizer', module_path)
|
spec = importlib.util.spec_from_file_location('storage_optimizer', module_path)
|
||||||
optimizer = importlib.util.module_from_spec(spec)
|
optimizer = importlib.util.module_from_spec(spec)
|
Loading…
x
Reference in New Issue
Block a user