Restructured CLI logic

This commit is contained in:
2025-07-10 21:26:44 +02:00
parent 8457325b5c
commit c160c58a5c
44 changed files with 97 additions and 155 deletions

View File

View File

@@ -10,7 +10,7 @@ dir_path = os.path.abspath(
sys.path.insert(0, dir_path)
# Import functions and classes to test
from create_credentials import ask_for_confirmation, main
from cli.create.credentials import ask_for_confirmation, main
from utils.handler.vault import VaultHandler, VaultScalar
import subprocess
import tempfile
@@ -81,7 +81,7 @@ class TestCreateCredentials(unittest.TestCase):
with mock.patch('subprocess.run', return_value=completed):
# Run main with override for credentials.api_key and force to skip prompt
sys.argv = [
'create_credentials.py',
'create/credentials.py',
'--role-path', role_path,
'--inventory-file', inventory_file,
'--vault-password-file', vault_pw_file,

View File

@@ -6,7 +6,7 @@ import tempfile
from ruamel.yaml import YAML
# Import functions to test; adjust path as needed
from cli.create_web_app import (
from cli.create.role import (
get_next_network,
get_next_port,
load_yaml_with_comments,

View File

View File

@@ -1,4 +1,4 @@
# tests/cli/test_ensure_vars_main.py
# tests/cli/test_fix/vars_main_files.py
import os
import shutil
import tempfile
@@ -6,7 +6,7 @@ import unittest
import yaml
# Adjust this import to match the real path in your project
from cli.ensure_vars_main import run, ROLES_DIR
from cli.ensure.vars_main_files import run, ROLES_DIR
class TestEnsureVarsMain(unittest.TestCase):
def setUp(self):
@@ -17,11 +17,11 @@ class TestEnsureVarsMain(unittest.TestCase):
# Monkey-patch the module's ROLES_DIR to point here
self._orig_roles_dir = ROLES_DIR
setattr(__import__("cli.ensure_vars_main", fromlist=["ROLES_DIR"]), "ROLES_DIR", self.roles_dir)
setattr(__import__("cli.ensure.vars_main_files", fromlist=["ROLES_DIR"]), "ROLES_DIR", self.roles_dir)
def tearDown(self):
# restore and cleanup
setattr(__import__("cli.ensure_vars_main", fromlist=["ROLES_DIR"]), "ROLES_DIR", self._orig_roles_dir)
setattr(__import__("cli.ensure.vars_main_files", fromlist=["ROLES_DIR"]), "ROLES_DIR", self._orig_roles_dir)
shutil.rmtree(self.tmpdir)
def _make_role(self, name, vars_content=None):

View File

View File

@@ -7,9 +7,9 @@ import shutil
import yaml
# 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 cli.generate.conditional_role_include import build_dependency_graph, topological_sort, gen_condi_role_incl
class TestGeneratePlaybook(unittest.TestCase):
def setUp(self):
@@ -66,8 +66,8 @@ class TestGeneratePlaybook(unittest.TestCase):
# The expected order must be a → b → c, d can be anywhere before or after
self.assertTrue(sorted_roles.index('role-a') < sorted_roles.index('role-b') < sorted_roles.index('role-c'))
def test_generate_playbook_entries(self):
entries = generate_playbook_entries(self.temp_dir)
def test_gen_condi_role_incl(self):
entries = gen_condi_role_incl(self.temp_dir)
text = ''.join(entries)
self.assertIn("setup a", text)

View File

@@ -30,7 +30,7 @@ class TestGenerateDefaultApplications(unittest.TestCase):
shutil.rmtree(self.temp_dir)
def test_script_generates_expected_yaml(self):
script_path = Path(__file__).resolve().parent.parent.parent.parent / "cli" / "generate_applications.py"
script_path = Path(__file__).resolve().parent.parent.parent.parent.parent.parent / "cli/generate/defaults/applications.py"
result = subprocess.run(
[

View File

@@ -45,7 +45,7 @@ class TestGenerateDefaultApplicationsUsers(unittest.TestCase):
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.
"""
script_path = Path(__file__).resolve().parents[3] / "cli" / "generate_applications.py"
script_path = Path(__file__).resolve().parents[5] / "cli" / "generate/defaults/applications.py"
result = subprocess.run([
"python3", str(script_path),
"--roles-dir", str(self.roles_dir),

View File

@@ -7,9 +7,9 @@ import yaml
from collections import OrderedDict
# 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/generate/defaults/")))
import generate_users
import users
class TestGenerateUsers(unittest.TestCase):
def test_build_users_auto_increment_and_overrides(self):
@@ -18,24 +18,24 @@ class TestGenerateUsers(unittest.TestCase):
'bob': {'uid': 2000, 'email': 'bob@custom.com', 'description': 'Custom user'},
'carol': {}
}
users = generate_users.build_users(
build = users.build_users(
defs=defs,
primary_domain='example.com',
start_id=1001,
become_pwd='pw'
)
# alice should get uid/gid 1001
self.assertEqual(users['alice']['uid'], 1001)
self.assertEqual(users['alice']['gid'], 1001)
self.assertEqual(users['alice']['email'], 'alice@example.com')
self.assertEqual(build['alice']['uid'], 1001)
self.assertEqual(build['alice']['gid'], 1001)
self.assertEqual(build['alice']['email'], 'alice@example.com')
# bob overrides
self.assertEqual(users['bob']['uid'], 2000)
self.assertEqual(users['bob']['gid'], 2000)
self.assertEqual(users['bob']['email'], 'bob@custom.com')
self.assertIn('description', users['bob'])
self.assertEqual(build['bob']['uid'], 2000)
self.assertEqual(build['bob']['gid'], 2000)
self.assertEqual(build['bob']['email'], 'bob@custom.com')
self.assertIn('description', build['bob'])
# carol should get next free id = 1002
self.assertEqual(users['carol']['uid'], 1002)
self.assertEqual(users['carol']['gid'], 1002)
self.assertEqual(build['carol']['uid'], 1002)
self.assertEqual(build['carol']['gid'], 1002)
def test_build_users_default_lookup_password(self):
"""
@@ -44,14 +44,14 @@ class TestGenerateUsers(unittest.TestCase):
"""
defs = {'frank': {}}
lookup_template = '{{ lookup("password", "/dev/null length=42 chars=ascii_letters,digits") }}'
users = generate_users.build_users(
build = users.build_users(
defs=defs,
primary_domain='example.com',
start_id=1001,
become_pwd=lookup_template
)
self.assertEqual(
users['frank']['password'],
build['frank']['password'],
lookup_template,
"The lookup template string was not correctly applied as the default password"
)
@@ -63,14 +63,14 @@ class TestGenerateUsers(unittest.TestCase):
"""
defs = {'eva': {'password': 'custompw'}}
lookup_template = '{{ lookup("password", "/dev/null length=42 chars=ascii_letters,digits") }}'
users = generate_users.build_users(
build = users.build_users(
defs=defs,
primary_domain='example.com',
start_id=1001,
become_pwd=lookup_template
)
self.assertEqual(
users['eva']['password'],
build['eva']['password'],
'custompw',
"The override password was not correctly applied"
)
@@ -82,7 +82,7 @@ class TestGenerateUsers(unittest.TestCase):
'u2': {'uid': 1001}
}
with self.assertRaises(ValueError):
generate_users.build_users(defs, 'ex.com', 1001, 'pw')
users.build_users(defs, 'ex.com', 1001, 'pw')
def test_build_users_shared_gid_allowed(self):
# Allow two users to share the same GID when one overrides gid and the other uses that as uid
@@ -90,10 +90,10 @@ class TestGenerateUsers(unittest.TestCase):
'a': {'uid': 1500},
'b': {'gid': 1500}
}
users = generate_users.build_users(defs, 'ex.com', 1500, 'pw')
build = users.build_users(defs, 'ex.com', 1500, 'pw')
# Both should have gid 1500
self.assertEqual(users['a']['gid'], 1500)
self.assertEqual(users['b']['gid'], 1500)
self.assertEqual(build['a']['gid'], 1500)
self.assertEqual(build['b']['gid'], 1500)
def test_build_users_duplicate_username_email(self):
defs = {
@@ -102,11 +102,11 @@ class TestGenerateUsers(unittest.TestCase):
}
# second user with same username should raise
with self.assertRaises(ValueError):
generate_users.build_users(defs, 'ex.com', 1001, 'pw')
users.build_users(defs, 'ex.com', 1001, 'pw')
def test_dictify_converts_ordereddict(self):
od = generate_users.OrderedDict([('a', 1), ('b', {'c': 2})])
result = generate_users.dictify(OrderedDict(od))
od = users.OrderedDict([('a', 1), ('b', {'c': 2})])
result = users.dictify(OrderedDict(od))
self.assertIsInstance(result, dict)
self.assertEqual(result, {'a': 1, 'b': {'c': 2}})
@@ -122,13 +122,13 @@ class TestGenerateUsers(unittest.TestCase):
# role2 defines same user x with same value
with open(os.path.join(tmp, 'role2/users/main.yml'), 'w') as f:
yaml.safe_dump({'users': {'x': {'email': 'x@a'}}}, f)
defs = generate_users.load_user_defs(tmp)
defs = users.load_user_defs(tmp)
self.assertIn('x', defs)
# now conflict definition
with open(os.path.join(tmp, 'role2/users/main.yml'), 'w') as f:
yaml.safe_dump({'users': {'x': {'email': 'x@b'}}}, f)
with self.assertRaises(ValueError):
generate_users.load_user_defs(tmp)
users.load_user_defs(tmp)
finally:
shutil.rmtree(tmp)

View File

@@ -16,7 +16,7 @@ sys.path.insert(
from utils.handler.yaml import YamlHandler
from utils.handler.vault import VaultHandler, VaultScalar
from cli.utils.manager.inventory import InventoryManager
from utils.manager.inventory import InventoryManager
class TestInventoryManager(unittest.TestCase):

View File

View File

@@ -7,7 +7,7 @@ import subprocess
import sys
import yaml
SCRIPT_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../../cli/validate_inventory.py"))
SCRIPT_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../../../cli/validate/inventory.py"))
class TestValidateInventory(unittest.TestCase):
def setUp(self):