mirror of
				https://github.com/kevinveenbirkenbach/computer-playbook.git
				synced 2025-10-31 18:29:21 +00:00 
			
		
		
		
	Added gid to applications to make them posix group ldap compatible
This commit is contained in:
		
							
								
								
									
										6
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								Makefile
									
									
									
									
									
								
							| @@ -31,7 +31,5 @@ install: build | ||||
| 	@echo "⚙️  Install complete." | ||||
|  | ||||
| test: | ||||
| 	@echo "🧪 Running Unit Tests..." | ||||
| 	python -m unittest discover -s tests/unit | ||||
| 	@echo "🔬 Running Integration Tests..." | ||||
| 	python -m unittest discover -s tests/integration | ||||
| 	@echo "🧪 Running Tests..." | ||||
| 	python -m unittest discover -s tests | ||||
							
								
								
									
										0
									
								
								__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -6,6 +6,11 @@ import yaml | ||||
| import sys | ||||
| from pathlib import Path | ||||
|  | ||||
| plugin_path = Path(__file__).resolve().parent / ".." / "lookup_plugins" | ||||
| sys.path.insert(0, str(plugin_path)) | ||||
|  | ||||
| from application_gid import LookupModule | ||||
|  | ||||
| def load_yaml_file(path): | ||||
|     """Load a YAML file if it exists, otherwise return an empty dict.""" | ||||
|     if not path.exists(): | ||||
| @@ -37,6 +42,7 @@ def main(): | ||||
|     # Initialize result structure | ||||
|     result = {"defaults_applications": {}} | ||||
|  | ||||
|     gid_lookup = LookupModule() | ||||
|     # Process each role for application configs | ||||
|     for role_dir in sorted(roles_dir.iterdir()): | ||||
|         role_name = role_dir.name | ||||
| @@ -67,6 +73,12 @@ def main(): | ||||
|  | ||||
|         config_data = load_yaml_file(config_file) | ||||
|         if config_data: | ||||
|             try: | ||||
|                 gid_number = gid_lookup.run([application_id], roles_dir=str(roles_dir))[0] | ||||
|             except Exception as e: | ||||
|                 print(f"Warning: failed to determine gid for '{application_id}': {e}", file=sys.stderr) | ||||
|                 sys.exit(1) | ||||
|             config_data["group_id"] = gid_number | ||||
|             result["defaults_applications"][application_id] = config_data | ||||
|             users_meta_file = role_dir / "meta" / "users.yml" | ||||
|             transformed_users = {} | ||||
|   | ||||
							
								
								
									
										42
									
								
								lookup_plugins/application_gid.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								lookup_plugins/application_gid.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| from __future__ import (absolute_import, division, print_function) | ||||
| __metaclass__ = type | ||||
|  | ||||
| import os | ||||
| import yaml | ||||
|  | ||||
| from ansible.plugins.lookup import LookupBase | ||||
| from ansible.errors import AnsibleError | ||||
|  | ||||
| class LookupModule(LookupBase): | ||||
|  | ||||
|     def run(self, terms, variables=None, **kwargs): | ||||
|         application_id = terms[0] | ||||
|         base_gid = kwargs.get('base_gid', 10000) | ||||
|         roles_dir = kwargs.get('roles_dir', 'roles') | ||||
|  | ||||
|         if not os.path.isdir(roles_dir): | ||||
|             raise AnsibleError(f"Roles directory '{roles_dir}' not found") | ||||
|  | ||||
|         matched_roles = [] | ||||
|  | ||||
|         for root, dirs, files in os.walk(roles_dir): | ||||
|             if os.path.basename(root) == "vars" and "main.yml" in files: | ||||
|                 vars_path = os.path.join(root, "main.yml") | ||||
|                 try: | ||||
|                     with open(vars_path, 'r') as f: | ||||
|                         data = yaml.safe_load(f) or {} | ||||
|                         app_id = data.get('application_id') | ||||
|                         if app_id: | ||||
|                             matched_roles.append((app_id, vars_path)) | ||||
|                 except Exception as e: | ||||
|                     raise AnsibleError(f"Error parsing {vars_path}: {e}") | ||||
|  | ||||
|         # sort alphabetically by application_id | ||||
|         sorted_ids = sorted(app_id for app_id, _ in matched_roles) | ||||
|  | ||||
|         try: | ||||
|             index = sorted_ids.index(application_id) | ||||
|         except ValueError: | ||||
|             raise AnsibleError(f"Application ID '{application_id}' not found in any role") | ||||
|  | ||||
|         return [base_gid + index] | ||||
| @@ -46,6 +46,10 @@ docker exec -it ldap bash -c "ldapsearch -LLL -o ldif-wrap=no -x -D \"\$LDAP_ADM | ||||
| ### Delete Groups and Subgroup | ||||
| To delete the group inclusive all subgroups use: | ||||
| ```bash | ||||
| docker exec -it ldap bash -c "ldapsearch -LLL -o ldif-wrap=no -x -D \"\$LDAP_ADMIN_DN\" -w \"\$LDAP_ADMIN_PASSWORD\" -b \"ou=applications,ou=groups,\$LDAP_ROOT\" dn | sed -n 's/^dn: //p' | tac | while read -r dn; do echo \"Deleting \$dn\"; ldapdelete -x -D \"\$LDAP_ADMIN_DN\" -w \"\$LDAP_ADMIN_PASSWORD\" \"\$dn\"; done" | ||||
|  | ||||
| docker exec -it ldap \ | ||||
|   ldapdelete -x \ | ||||
|     -D "$LDAP_ADMIN_DN" \ | ||||
|     -w "$LDAP_ADMIN_PASSWORD" \ | ||||
|     -r \ | ||||
|     "ou=groups,dc=veen,dc=world" | ||||
| ``` | ||||
| @@ -1,34 +1,30 @@ | ||||
| {% for application_id, application_config in applications.items() %} | ||||
|  | ||||
|   {# 1. Build up roles dict, defaulting to {} if rbac oder roles fehlt, then ensure administrator immer dabei ist #} | ||||
|   {% set base_roles = application_config.rbac.roles | default({}) %} | ||||
|   {% set roles = base_roles | combine({ | ||||
|       'administrator': { | ||||
|         'description': 'Has full administrative access: manage themes, plugins, settings, and users' | ||||
|       } | ||||
|     })  | ||||
| {%- for application_id, application_config in applications.items() %} | ||||
|   {%- set base_roles = application_config.rbac.roles | default({}) %} | ||||
|   {%- set roles = base_roles | combine({ | ||||
|         'administrator': { | ||||
|           'description': 'Has full administrative access: manage themes, plugins, settings, and users' | ||||
|         } | ||||
|       })  | ||||
|   %} | ||||
|  | ||||
|   {# 2. Emit role definitions #} | ||||
|   {% for role_name, role_conf in roles.items() %} | ||||
|   {%- for role_name, role_conf in roles.items() %} | ||||
| dn: cn={{ application_id }}-{{ role_name }},{{ ldap.dn.ou.roles }} | ||||
| objectClass: top | ||||
| objectClass: organizationalRole | ||||
| objectClass: posixGroup | ||||
| gidNumber: {{ application_config['group_id'] }} | ||||
| cn: {{ application_id }}-{{ role_name }} | ||||
| description: {{ role_conf.description }} | ||||
|  | ||||
|     {# 3. Assign only if user has that role #} | ||||
|     {% for username, user_config in users.items() %} | ||||
|         {% set user_roles = user_config.roles | default([]) %} | ||||
|         {% if role_name in user_roles %} | ||||
|     {%- for username, user_config in users.items() %} | ||||
|       {%- set user_roles = user_config.roles | default([]) %} | ||||
|       {%- if role_name in user_roles %} | ||||
| dn: cn={{ application_id }}-{{ role_name }},{{ ldap.dn.ou.roles }} | ||||
| changetype: modify | ||||
| add: roleOccupant | ||||
| roleOccupant: {{ ldap.attributes.user_id }}={{ username }},{{ ldap.dn.ou.users }} | ||||
|  | ||||
|         {% endif %} | ||||
|     {% endfor %} | ||||
|  | ||||
|   {% endfor %} | ||||
|  | ||||
| {% endfor %} | ||||
|       {%- endif %} | ||||
|     {%- endfor %} | ||||
|   {%- endfor %} | ||||
| {%- endfor %} | ||||
|   | ||||
							
								
								
									
										0
									
								
								tests/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								tests/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								tests/integration/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								tests/integration/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								tests/unit/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								tests/unit/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										62
									
								
								tests/unit/test_application_gid.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								tests/unit/test_application_gid.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| import os | ||||
| import sys | ||||
| import tempfile | ||||
| import shutil | ||||
| import unittest | ||||
| import yaml | ||||
|  | ||||
| dir_path = os.path.abspath( | ||||
|     os.path.join(os.path.dirname(__file__), '../../lookup_plugins') | ||||
| ) | ||||
| sys.path.insert(0, dir_path) | ||||
|  | ||||
| from application_gid import LookupModule | ||||
|  | ||||
|  | ||||
| class TestApplicationGidLookup(unittest.TestCase): | ||||
|  | ||||
|     def setUp(self): | ||||
|         # Create a temporary roles directory | ||||
|         self.temp_dir = tempfile.mkdtemp() | ||||
|         self.roles_dir = os.path.join(self.temp_dir, "roles") | ||||
|         os.mkdir(self.roles_dir) | ||||
|  | ||||
|         # Define mock application_ids | ||||
|         self.applications = { | ||||
|             "nextcloud": "docker-nextcloud", | ||||
|             "moodle": "docker-moodle", | ||||
|             "wordpress": "docker-wordpress", | ||||
|             "taiga": "docker-taiga" | ||||
|         } | ||||
|  | ||||
|         # Create fake role dirs and vars/main.yml | ||||
|         for app_id, dirname in self.applications.items(): | ||||
|             role_path = os.path.join(self.roles_dir, dirname, "vars") | ||||
|             os.makedirs(role_path) | ||||
|             with open(os.path.join(role_path, "main.yml"), "w") as f: | ||||
|                 yaml.dump({"application_id": app_id}, f) | ||||
|  | ||||
|         self.lookup = LookupModule() | ||||
|  | ||||
|     def tearDown(self): | ||||
|         shutil.rmtree(self.temp_dir) | ||||
|  | ||||
|     def test_gid_lookup(self): | ||||
|         # The sorted application_ids: [moodle, nextcloud, taiga, wordpress] | ||||
|         expected_order = ["moodle", "nextcloud", "taiga", "wordpress"] | ||||
|         for i, app_id in enumerate(expected_order): | ||||
|             result = self.lookup.run([app_id], roles_dir=self.roles_dir) | ||||
|             self.assertEqual(result, [10000 + i]) | ||||
|  | ||||
|     def test_custom_base_gid(self): | ||||
|         result = self.lookup.run(["taiga"], roles_dir=self.roles_dir, base_gid=20000) | ||||
|         self.assertEqual(result, [20002])  # 2nd index in sorted list | ||||
|  | ||||
|     def test_application_id_not_found(self): | ||||
|         with self.assertRaises(Exception) as context: | ||||
|             self.lookup.run(["unknownapp"], roles_dir=self.roles_dir) | ||||
|         self.assertIn("Application ID 'unknownapp' not found", str(context.exception)) | ||||
|  | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     unittest.main() | ||||
		Reference in New Issue
	
	Block a user