Implemented new get_app_conf function

This commit is contained in:
2025-07-13 13:36:52 +02:00
parent a18e888044
commit c8669e19cf
5 changed files with 227 additions and 20 deletions

View File

@@ -1,9 +1,9 @@
from get_app_conf import get_app_conf
def is_feature_enabled(applications: dict, feature: str, application_id: str) -> bool:
"""
Return True if applications[application_id].features[feature] is truthy.
Wrapper for compatibility: Return True if applications[application_id].features[feature] is truthy.
"""
app = applications.get(application_id, {})
return bool(app.get('features', {}).get(feature, False))
return bool(get_app_conf(applications, application_id, f"features.{feature}", strict=False))
def get_docker_compose(path_docker_compose_instances: str, application_id: str) -> dict:
"""

View File

@@ -1,15 +1,13 @@
def get_docker_image(applications, application_id, image_key:str=None):
from get_app_conf import get_app_conf
def get_docker_image(applications, application_id, image_key: str = None):
"""
Wrapper for compatibility: Compose the docker image:version string.
Raises error if value missing, like before.
"""
image_key = image_key if image_key else application_id
docker = applications.get(application_id, {}).get("docker", {})
version = docker.get("versions", {}).get(image_key)
image = docker.get("images", {}).get(image_key)
if not image:
raise ValueError(f"Missing image for {application_id}:{image_key}")
if not version:
raise ValueError(f"Missing version for {application_id}:{image_key}")
image = get_app_conf(applications, application_id, f"docker.images.{image_key}", strict=True)
version = get_app_conf(applications, application_id, f"docker.versions.{image_key}", strict=True)
return f"{image}:{version}"
class FilterModule(object):

View File

@@ -0,0 +1,96 @@
# filter_plugins/get_app_conf.py
import re
from ansible.errors import AnsibleFilterError
class AppConfigKeyError(AnsibleFilterError, ValueError):
"""
Raised when a required application config key is missing (strict mode).
Compatible with Ansible error handling and Python ValueError.
"""
pass
def get_app_conf(applications, application_id, config_path, strict=True):
def access(obj, key, path_trace):
m = re.match(r"^([a-zA-Z0-9_]+)(?:\[(\d+)\])?$", key)
if not m:
raise AppConfigKeyError(
f"Invalid key format in config_path: '{key}'\n"
f"Full path so far: {'.'.join(path_trace)}\n"
f"application_id: {application_id}\n"
f"config_path: {config_path}"
)
k, idx = m.group(1), m.group(2)
if isinstance(obj, dict):
if k not in obj:
if strict:
raise AppConfigKeyError(
f"Key '{k}' not found in dict at '{key}'\n"
f"Full path so far: {'.'.join(path_trace)}\n"
f"Current object: {repr(obj)}\n"
f"application_id: {application_id}\n"
f"config_path: {config_path}"
)
return False
obj = obj[k]
else:
if strict:
raise AppConfigKeyError(
f"Expected dict for '{k}', got {type(obj).__name__} at '{key}'\n"
f"Full path so far: {'.'.join(path_trace)}\n"
f"Current object: {repr(obj)}\n"
f"application_id: {application_id}\n"
f"config_path: {config_path}"
)
return False
if idx is not None:
if not isinstance(obj, list):
if strict:
raise AppConfigKeyError(
f"Expected list for '{k}[{idx}]', got {type(obj).__name__}\n"
f"Full path so far: {'.'.join(path_trace)}\n"
f"Current object: {repr(obj)}\n"
f"application_id: {application_id}\n"
f"config_path: {config_path}"
)
return False
i = int(idx)
if i >= len(obj):
if strict:
raise AppConfigKeyError(
f"Index {i} out of range for list at '{k}'\n"
f"Full path so far: {'.'.join(path_trace)}\n"
f"Current object: {repr(obj)}\n"
f"application_id: {application_id}\n"
f"config_path: {config_path}"
)
return False
obj = obj[i]
return obj
path_trace = [f"applications[{repr(application_id)}]"]
try:
obj = applications[application_id]
except KeyError:
if strict:
raise AppConfigKeyError(
f"Application ID '{application_id}' not found in applications dict.\n"
f"path_trace: {path_trace}\n"
f"applications keys: {list(applications.keys())}\n"
f"config_path: {config_path}"
)
return False
for part in config_path.split("."):
path_trace.append(part)
obj = access(obj, part, path_trace)
if obj is False and not strict:
return False
return obj
class FilterModule(object):
''' CyMaIS application config extraction filters '''
def filters(self):
return {
'get_app_conf': get_app_conf,
}