mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-06-25 11:45:32 +02:00
Optimized code and solved bugs
This commit is contained in:
parent
2f1d6a5178
commit
d5dd568994
@ -1,8 +1,8 @@
|
|||||||
from ansible.errors import AnsibleFilterError
|
from ansible.errors import AnsibleFilterError
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
class FilterModule(object):
|
class FilterModule(object):
|
||||||
def filters(self):
|
def filters(self):
|
||||||
return {
|
return {
|
||||||
@ -15,48 +15,67 @@ class FilterModule(object):
|
|||||||
1) directly in group_names, or
|
1) directly in group_names, or
|
||||||
2) the application_id of any role reachable (recursively)
|
2) the application_id of any role reachable (recursively)
|
||||||
from any group in group_names via meta/dependencies.
|
from any group in group_names via meta/dependencies.
|
||||||
Expects:
|
|
||||||
- applications: dict mapping application_id → config
|
|
||||||
- group_names: list of active role names
|
|
||||||
"""
|
"""
|
||||||
# validate inputs
|
self._validate_inputs(applications, group_names)
|
||||||
|
|
||||||
|
roles_dir = self._get_roles_directory()
|
||||||
|
|
||||||
|
included_roles = self._collect_reachable_roles(group_names, roles_dir)
|
||||||
|
included_app_ids = self._gather_application_ids(included_roles, roles_dir)
|
||||||
|
|
||||||
|
return self._filter_applications(applications, group_names, included_app_ids)
|
||||||
|
|
||||||
|
def _validate_inputs(self, applications, group_names):
|
||||||
|
"""Validate the inputs for correct types."""
|
||||||
if not isinstance(applications, dict):
|
if not isinstance(applications, dict):
|
||||||
raise AnsibleFilterError(f"Expected applications as dict, got {type(applications).__name__}")
|
raise AnsibleFilterError(f"Expected applications as dict, got {type(applications).__name__}")
|
||||||
if not isinstance(group_names, (list, tuple)):
|
if not isinstance(group_names, (list, tuple)):
|
||||||
raise AnsibleFilterError(f"Expected group_names as list/tuple, got {type(group_names).__name__}")
|
raise AnsibleFilterError(f"Expected group_names as list/tuple, got {type(group_names).__name__}")
|
||||||
|
|
||||||
# locate roles directory (assume plugin sits in filter_plugins/)
|
def _get_roles_directory(self):
|
||||||
|
"""Locate and return the roles directory."""
|
||||||
plugin_dir = os.path.dirname(__file__)
|
plugin_dir = os.path.dirname(__file__)
|
||||||
project_root = os.path.abspath(os.path.join(plugin_dir, '..'))
|
project_root = os.path.abspath(os.path.join(plugin_dir, '..'))
|
||||||
roles_dir = os.path.join(project_root, 'roles')
|
return os.path.join(project_root, 'roles')
|
||||||
|
|
||||||
# recursively collect all roles reachable from the given groups
|
def _collect_reachable_roles(self, group_names, roles_dir):
|
||||||
def collect_roles(role, seen):
|
"""Recursively collect all roles reachable from the given groups via meta/dependencies."""
|
||||||
if role in seen:
|
included_roles = set()
|
||||||
|
for group in group_names:
|
||||||
|
self._collect_roles_from_group(group, included_roles, roles_dir)
|
||||||
|
return included_roles
|
||||||
|
|
||||||
|
def _collect_roles_from_group(self, group, seen, roles_dir):
|
||||||
|
"""Recursively collect roles from a specific group."""
|
||||||
|
if group in seen:
|
||||||
return
|
return
|
||||||
seen.add(role)
|
seen.add(group)
|
||||||
meta_file = os.path.join(roles_dir, role, 'meta', 'main.yml')
|
|
||||||
|
meta_file = os.path.join(roles_dir, group, 'meta', 'main.yml')
|
||||||
if not os.path.isfile(meta_file):
|
if not os.path.isfile(meta_file):
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(meta_file) as f:
|
with open(meta_file) as f:
|
||||||
meta = yaml.safe_load(f) or {}
|
meta = yaml.safe_load(f) or {}
|
||||||
except Exception:
|
except Exception:
|
||||||
return
|
return
|
||||||
|
|
||||||
for dep in meta.get('dependencies', []):
|
for dep in meta.get('dependencies', []):
|
||||||
if isinstance(dep, str):
|
dep_name = self._get_dependency_name(dep)
|
||||||
dep_name = dep
|
if dep_name:
|
||||||
elif isinstance(dep, dict):
|
self._collect_roles_from_group(dep_name, seen, roles_dir)
|
||||||
dep_name = dep.get('role') or dep.get('name')
|
|
||||||
else:
|
|
||||||
continue
|
|
||||||
collect_roles(dep_name, seen)
|
|
||||||
|
|
||||||
included_roles = set()
|
def _get_dependency_name(self, dependency):
|
||||||
for grp in group_names:
|
"""Extract the dependency role name from the meta data."""
|
||||||
collect_roles(grp, included_roles)
|
if isinstance(dependency, str):
|
||||||
|
return dependency
|
||||||
|
elif isinstance(dependency, dict):
|
||||||
|
return dependency.get('role') or dependency.get('name')
|
||||||
|
return None
|
||||||
|
|
||||||
# gather application_ids from those roles
|
def _gather_application_ids(self, included_roles, roles_dir):
|
||||||
|
"""Gather application_ids from the roles."""
|
||||||
included_app_ids = set()
|
included_app_ids = set()
|
||||||
for role in included_roles:
|
for role in included_roles:
|
||||||
vars_file = os.path.join(roles_dir, role, 'vars', 'main.yml')
|
vars_file = os.path.join(roles_dir, role, 'vars', 'main.yml')
|
||||||
@ -67,14 +86,17 @@ class FilterModule(object):
|
|||||||
vars_data = yaml.safe_load(f) or {}
|
vars_data = yaml.safe_load(f) or {}
|
||||||
except Exception:
|
except Exception:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
app_id = vars_data.get('application_id')
|
app_id = vars_data.get('application_id')
|
||||||
if isinstance(app_id, str) and app_id:
|
if isinstance(app_id, str) and app_id:
|
||||||
included_app_ids.add(app_id)
|
included_app_ids.add(app_id)
|
||||||
|
|
||||||
# build filtered result: include any application whose key is in group_names or in included_app_ids
|
return included_app_ids
|
||||||
|
|
||||||
|
def _filter_applications(self, applications, group_names, included_app_ids):
|
||||||
|
"""Filter and return the applications that match the conditions."""
|
||||||
result = {}
|
result = {}
|
||||||
for app_key, cfg in applications.items():
|
for app_key, cfg in applications.items():
|
||||||
if app_key in group_names or app_key in included_app_ids:
|
if app_key in group_names or app_key in included_app_ids:
|
||||||
result[app_key] = cfg
|
result[app_key] = cfg
|
||||||
|
|
||||||
return result
|
return result
|
@ -5,71 +5,79 @@ class FilterModule(object):
|
|||||||
return {'canonical_domains_map': self.canonical_domains_map}
|
return {'canonical_domains_map': self.canonical_domains_map}
|
||||||
|
|
||||||
def canonical_domains_map(self, apps, primary_domain):
|
def canonical_domains_map(self, apps, primary_domain):
|
||||||
def parse_entry(domains_cfg, key, app_id):
|
"""
|
||||||
if key not in domains_cfg:
|
Maps applications to their canonical domains, checking for conflicts
|
||||||
return None
|
and ensuring all domains are valid and unique across applications.
|
||||||
entry = domains_cfg[key]
|
"""
|
||||||
if isinstance(entry, dict):
|
|
||||||
values = list(entry.values())
|
|
||||||
elif isinstance(entry, list):
|
|
||||||
values = entry
|
|
||||||
else:
|
|
||||||
raise AnsibleFilterError(
|
|
||||||
f"Unexpected type for 'domains.{key}' in application '{app_id}': {type(entry).__name__}"
|
|
||||||
)
|
|
||||||
for d in values:
|
|
||||||
if not isinstance(d, str) or not d.strip():
|
|
||||||
raise AnsibleFilterError(
|
|
||||||
f"Invalid domain entry in '{key}' for application '{app_id}': {d!r}"
|
|
||||||
)
|
|
||||||
return values
|
|
||||||
|
|
||||||
result = {}
|
result = {}
|
||||||
seen = {}
|
seen_domains = {}
|
||||||
|
|
||||||
for app_id, cfg in apps.items():
|
for app_id, cfg in apps.items():
|
||||||
domains_cfg = cfg.get('domains')
|
domains_cfg = cfg.get('domains')
|
||||||
if not domains_cfg or 'canonical' not in domains_cfg:
|
if not domains_cfg or 'canonical' not in domains_cfg:
|
||||||
default = f"{app_id}.{primary_domain}"
|
self._add_default_domain(app_id, primary_domain, seen_domains, result)
|
||||||
if default in seen:
|
|
||||||
raise AnsibleFilterError(
|
|
||||||
f"Domain '{default}' is already configured for '{seen[default]}' and '{app_id}'"
|
|
||||||
)
|
|
||||||
seen[default] = app_id
|
|
||||||
result[app_id] = [default]
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
entry = domains_cfg['canonical']
|
canonical_domains = domains_cfg['canonical']
|
||||||
|
self._process_canonical_domains(app_id, canonical_domains, seen_domains, result)
|
||||||
if isinstance(entry, dict):
|
|
||||||
for name, domain in entry.items():
|
|
||||||
if not isinstance(domain, str) or not domain.strip():
|
|
||||||
raise AnsibleFilterError(
|
|
||||||
f"Invalid domain entry in 'canonical' for application '{app_id}': {domain!r}"
|
|
||||||
)
|
|
||||||
if domain in seen:
|
|
||||||
raise AnsibleFilterError(
|
|
||||||
f"Domain '{domain}' is already configured for '{seen[domain]}' and '{app_id}'"
|
|
||||||
)
|
|
||||||
seen[domain] = app_id
|
|
||||||
result[app_id] = entry.copy()
|
|
||||||
|
|
||||||
elif isinstance(entry, list):
|
|
||||||
for domain in entry:
|
|
||||||
if not isinstance(domain, str) or not domain.strip():
|
|
||||||
raise AnsibleFilterError(
|
|
||||||
f"Invalid domain entry in 'canonical' for application '{app_id}': {domain!r}"
|
|
||||||
)
|
|
||||||
if domain in seen:
|
|
||||||
raise AnsibleFilterError(
|
|
||||||
f"Domain '{domain}' is already configured for '{seen[domain]}' and '{app_id}'"
|
|
||||||
)
|
|
||||||
seen[domain] = app_id
|
|
||||||
result[app_id] = list(entry)
|
|
||||||
|
|
||||||
else:
|
|
||||||
raise AnsibleFilterError(
|
|
||||||
f"Unexpected type for 'domains.canonical' in application '{app_id}': {type(entry).__name__}"
|
|
||||||
)
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def _add_default_domain(self, app_id, primary_domain, seen_domains, result):
|
||||||
|
"""
|
||||||
|
Add the default domain for an application if no canonical domains are defined.
|
||||||
|
Ensures the domain is unique across applications.
|
||||||
|
"""
|
||||||
|
default_domain = f"{app_id}.{primary_domain}"
|
||||||
|
if default_domain in seen_domains:
|
||||||
|
raise AnsibleFilterError(
|
||||||
|
f"Domain '{default_domain}' is already configured for "
|
||||||
|
f"'{seen_domains[default_domain]}' and '{app_id}'"
|
||||||
|
)
|
||||||
|
seen_domains[default_domain] = app_id
|
||||||
|
result[app_id] = [default_domain]
|
||||||
|
|
||||||
|
def _process_canonical_domains(self, app_id, canonical_domains, seen_domains, result):
|
||||||
|
"""
|
||||||
|
Process the canonical domains for an application, handling both lists and dicts,
|
||||||
|
and ensuring each domain is unique.
|
||||||
|
"""
|
||||||
|
if isinstance(canonical_domains, dict):
|
||||||
|
self._process_canonical_domains_dict(app_id, canonical_domains, seen_domains, result)
|
||||||
|
elif isinstance(canonical_domains, list):
|
||||||
|
self._process_canonical_domains_list(app_id, canonical_domains, seen_domains, result)
|
||||||
|
else:
|
||||||
|
raise AnsibleFilterError(
|
||||||
|
f"Unexpected type for 'domains.canonical' in application '{app_id}': "
|
||||||
|
f"{type(canonical_domains).__name__}"
|
||||||
|
)
|
||||||
|
|
||||||
|
def _process_canonical_domains_dict(self, app_id, domains_dict, seen_domains, result):
|
||||||
|
"""
|
||||||
|
Process a dictionary of canonical domains for an application.
|
||||||
|
"""
|
||||||
|
for name, domain in domains_dict.items():
|
||||||
|
self._validate_and_check_domain(app_id, domain, seen_domains)
|
||||||
|
result[app_id] = domains_dict.copy()
|
||||||
|
|
||||||
|
def _process_canonical_domains_list(self, app_id, domains_list, seen_domains, result):
|
||||||
|
"""
|
||||||
|
Process a list of canonical domains for an application.
|
||||||
|
"""
|
||||||
|
for domain in domains_list:
|
||||||
|
self._validate_and_check_domain(app_id, domain, seen_domains)
|
||||||
|
result[app_id] = list(domains_list)
|
||||||
|
|
||||||
|
def _validate_and_check_domain(self, app_id, domain, seen_domains):
|
||||||
|
"""
|
||||||
|
Validate the domain and check if it has already been assigned to another application.
|
||||||
|
"""
|
||||||
|
if not isinstance(domain, str) or not domain.strip():
|
||||||
|
raise AnsibleFilterError(
|
||||||
|
f"Invalid domain entry in 'canonical' for application '{app_id}': {domain!r}"
|
||||||
|
)
|
||||||
|
if domain in seen_domains:
|
||||||
|
raise AnsibleFilterError(
|
||||||
|
f"Domain '{domain}' is already configured for '{seen_domains[domain]}' and '{app_id}'"
|
||||||
|
)
|
||||||
|
seen_domains[domain] = app_id
|
||||||
|
@ -30,10 +30,4 @@ defaults_service_provider:
|
|||||||
legal:
|
legal:
|
||||||
editorial_responsible: "Johannes Gutenberg"
|
editorial_responsible: "Johannes Gutenberg"
|
||||||
source_code: "https://github.com/kevinveenbirkenbach/cymais"
|
source_code: "https://github.com/kevinveenbirkenbach/cymais"
|
||||||
imprint: >-
|
imprint: "{{web_protocol}}://{{domains['html-server']}}/imprint.html"
|
||||||
{{ "{protocol}://{domain}/imprint.html"
|
|
||||||
| safe_placeholders({
|
|
||||||
'protocol': web_protocol,
|
|
||||||
'domain': domains.html_server
|
|
||||||
})
|
|
||||||
}}
|
|
@ -1,8 +1,3 @@
|
|||||||
- name: "Debug: cloudflare_domains"
|
|
||||||
debug:
|
|
||||||
var: cloudflare_domains
|
|
||||||
when: enable_debug
|
|
||||||
|
|
||||||
- name: Create or update Cloudflare A-record for {{ item }}
|
- name: Create or update Cloudflare A-record for {{ item }}
|
||||||
community.general.cloudflare_dns:
|
community.general.cloudflare_dns:
|
||||||
api_token: "{{ cloudflare_api_token }}"
|
api_token: "{{ cloudflare_api_token }}"
|
||||||
|
@ -283,7 +283,7 @@ HELP_URL=https://docs.bigbluebutton.org/greenlight/gl-overview.html
|
|||||||
# approval - For approve/decline registration
|
# approval - For approve/decline registration
|
||||||
DEFAULT_REGISTRATION=invite
|
DEFAULT_REGISTRATION=invite
|
||||||
|
|
||||||
{% if applications[application_id].features.oidc | bool %}
|
{% if applications | is_feature_enabled('oidc',application_id) %}
|
||||||
### EXTERNAL AUTHENTICATION METHODS
|
### EXTERNAL AUTHENTICATION METHODS
|
||||||
# @See https://docs.bigbluebutton.org/greenlight/v3/external-authentication/
|
# @See https://docs.bigbluebutton.org/greenlight/v3/external-authentication/
|
||||||
#
|
#
|
||||||
|
@ -118,7 +118,7 @@ run:
|
|||||||
## If you want to set the 'From' email address for your first registration, uncomment and change:
|
## If you want to set the 'From' email address for your first registration, uncomment and change:
|
||||||
## After getting the first signup email, re-comment the line. It only needs to run once.
|
## After getting the first signup email, re-comment the line. It only needs to run once.
|
||||||
#- exec: rails r "SiteSetting.notification_email='info@unconfigured.discourse.org'"
|
#- exec: rails r "SiteSetting.notification_email='info@unconfigured.discourse.org'"
|
||||||
{% if applications[application_id].features.oidc | bool %}
|
{% if applications | is_feature_enabled('oidc',application_id) %}
|
||||||
# Deactivate Default Login
|
# Deactivate Default Login
|
||||||
- exec: rails r "SiteSetting.enable_local_logins = false"
|
- exec: rails r "SiteSetting.enable_local_logins = false"
|
||||||
- exec: rails r "SiteSetting.enable_passkeys = false" # https://meta.discourse.org/t/passwordless-login-using-passkeys/285589
|
- exec: rails r "SiteSetting.enable_passkeys = false" # https://meta.discourse.org/t/passwordless-login-using-passkeys/285589
|
||||||
|
@ -77,7 +77,7 @@ ESPOCRM_CONFIG_LDAP_USER_LOGIN_FILTER=(sAMAccountName=%USERNAME%)
|
|||||||
# OpenID Connect settings (optional)
|
# OpenID Connect settings (optional)
|
||||||
# Applied only if the feature flag is true
|
# Applied only if the feature flag is true
|
||||||
# ------------------------------------------------
|
# ------------------------------------------------
|
||||||
{% if applications[application_id].features.oidc | bool %}
|
{% if applications | is_feature_enabled('oidc',application_id) %}
|
||||||
|
|
||||||
# ------------------------------------------------
|
# ------------------------------------------------
|
||||||
# OpenID Connect settings
|
# OpenID Connect settings
|
||||||
|
@ -17,7 +17,7 @@ listmonk_settings:
|
|||||||
"provider_url": oidc.client.issuer_url,
|
"provider_url": oidc.client.issuer_url,
|
||||||
"client_secret": oidc.client.secret
|
"client_secret": oidc.client.secret
|
||||||
} | to_json }}
|
} | to_json }}
|
||||||
when: applications[application_id].features.oidc | bool
|
when: applications | is_feature_enabled('oidc',application_id)
|
||||||
|
|
||||||
# hCaptcha toggles and credentials
|
# hCaptcha toggles and credentials
|
||||||
- key: "security.enable_captcha"
|
- key: "security.enable_captcha"
|
||||||
|
@ -158,7 +158,7 @@ API_TOKEN={{applications.mailu.credentials.api_token}}
|
|||||||
AUTH_REQUIRE_TOKENS=True
|
AUTH_REQUIRE_TOKENS=True
|
||||||
|
|
||||||
|
|
||||||
{% if applications[application_id].features.oidc | bool %}
|
{% if applications | is_feature_enabled('oidc',application_id) %}
|
||||||
###################################
|
###################################
|
||||||
# OpenID Connect settings
|
# OpenID Connect settings
|
||||||
###################################
|
###################################
|
||||||
|
@ -8,7 +8,7 @@ cert_mount_directory: "{{docker_compose.directories.volumes}}certs/"
|
|||||||
|
|
||||||
# Use dedicated source for oidc if activated
|
# Use dedicated source for oidc if activated
|
||||||
# @see https://github.com/heviat/Mailu-OIDC/tree/2024.06
|
# @see https://github.com/heviat/Mailu-OIDC/tree/2024.06
|
||||||
docker_source: "{{ 'ghcr.io/heviat' if applications[application_id].features.oidc | bool else 'ghcr.io/mailu' }}"
|
docker_source: "{{ 'ghcr.io/heviat' if applications | is_feature_enabled('oidc',application_id) else 'ghcr.io/mailu' }}"
|
||||||
|
|
||||||
domain: "{{ domains | get_domain(application_id) }}"
|
domain: "{{ domains | get_domain(application_id) }}"
|
||||||
http_port: "{{ ports.localhost.http[application_id] }}"
|
http_port: "{{ ports.localhost.http[application_id] }}"
|
@ -52,7 +52,7 @@ SMTP_OPENSSL_VERIFY_MODE=none
|
|||||||
SMTP_ENABLE_STARTTLS=auto
|
SMTP_ENABLE_STARTTLS=auto
|
||||||
SMTP_FROM_ADDRESS=Mastodon <{{ users['no-reply'].email }}>
|
SMTP_FROM_ADDRESS=Mastodon <{{ users['no-reply'].email }}>
|
||||||
|
|
||||||
{% if applications[application_id].features.oidc | bool %}
|
{% if applications | is_feature_enabled('oidc',application_id) %}
|
||||||
###################################
|
###################################
|
||||||
# OpenID Connect settings
|
# OpenID Connect settings
|
||||||
###################################
|
###################################
|
||||||
|
@ -20,8 +20,6 @@ oidc:
|
|||||||
# @see https://apps.nextcloud.com/apps/sociallogin
|
# @see https://apps.nextcloud.com/apps/sociallogin
|
||||||
flavor: "oidc_login" # Keeping on sociallogin because the other option is not implemented yet
|
flavor: "oidc_login" # Keeping on sociallogin because the other option is not implemented yet
|
||||||
credentials:
|
credentials:
|
||||||
# database_password: Null # Needs to be set in inventory file
|
|
||||||
# administrator_password: None # Keep in mind to change the password fast after creation and activate 2FA
|
|
||||||
features:
|
features:
|
||||||
matomo: true
|
matomo: true
|
||||||
css: true
|
css: true
|
||||||
|
@ -3,13 +3,13 @@ cookie_secret = "{{ applications[oauth2_proxy_application_id].creden
|
|||||||
email_domains = "{{ primary_domain }}"
|
email_domains = "{{ primary_domain }}"
|
||||||
cookie_secure = "true" # True is necessary to force the cookie set via https
|
cookie_secure = "true" # True is necessary to force the cookie set via https
|
||||||
upstreams = "http://{{ applications[oauth2_proxy_application_id].oauth2_proxy.application }}:{{ applications[oauth2_proxy_application_id].oauth2_proxy.port }}"
|
upstreams = "http://{{ applications[oauth2_proxy_application_id].oauth2_proxy.application }}:{{ applications[oauth2_proxy_application_id].oauth2_proxy.port }}"
|
||||||
cookie_domains = ["{{ domains[oauth2_proxy_application_id] }}", "{{ domains | get_domain('keycloak') }}"] # Required so cookie can be read on all subdomains.
|
cookie_domains = ["{{ domains | get_domain(oauth2_proxy_application_id) }}", "{{ domains | get_domain('keycloak') }}"] # Required so cookie can be read on all subdomains.
|
||||||
whitelist_domains = [".{{ primary_domain }}"] # Required to allow redirection back to original requested target.
|
whitelist_domains = [".{{ primary_domain }}"] # Required to allow redirection back to original requested target.
|
||||||
|
|
||||||
# keycloak provider
|
# keycloak provider
|
||||||
client_secret = "{{ oidc.client.secret }}"
|
client_secret = "{{ oidc.client.secret }}"
|
||||||
client_id = "{{ oidc.client.id }}"
|
client_id = "{{ oidc.client.id }}"
|
||||||
redirect_url = "{{ web_protocol }}://{{domains[oauth2_proxy_application_id]}}/oauth2/callback"
|
redirect_url = "{{ web_protocol }}://{{ domains | get_domain(oauth2_proxy_application_id) }}/oauth2/callback"
|
||||||
oidc_issuer_url = "{{ oidc.client.issuer_url }}"
|
oidc_issuer_url = "{{ oidc.client.issuer_url }}"
|
||||||
provider = "oidc"
|
provider = "oidc"
|
||||||
provider_display_name = "Keycloak"
|
provider_display_name = "Keycloak"
|
||||||
|
@ -17,6 +17,8 @@ csp:
|
|||||||
flags:
|
flags:
|
||||||
script-src:
|
script-src:
|
||||||
unsafe-inline: true
|
unsafe-inline: true
|
||||||
|
style-src:
|
||||||
|
unsafe-inline: true
|
||||||
domains:
|
domains:
|
||||||
canonical:
|
canonical:
|
||||||
- "project.{{ primary_domain }}"
|
- "project.{{ primary_domain }}"
|
@ -1,5 +1,5 @@
|
|||||||
application_id: "pgadmin"
|
application_id: "pgadmin"
|
||||||
database_type: "postgres"
|
database_type: "postgres"
|
||||||
database_host: "{{ 'central-' + database_type if applications | is_feature_enabled('central_database',application_id)"
|
database_host: "{{ 'central-' + database_type if applications | is_feature_enabled('central_database',application_id) }}"
|
||||||
pgadmin_user: 5050
|
pgadmin_user: 5050
|
||||||
pgadmin_group: "{{pgadmin_user}}"
|
pgadmin_group: "{{pgadmin_user}}"
|
@ -1,3 +1,3 @@
|
|||||||
application_id: "phpmyadmin"
|
application_id: "phpmyadmin"
|
||||||
database_type: "mariadb"
|
database_type: "mariadb"
|
||||||
database_host: "{{ 'central-' + database_type if applications | is_feature_enabled('central_database',application_id)"
|
database_host: "{{ 'central-' + database_type if applications | is_feature_enabled('central_database',application_id) }}"
|
@ -47,7 +47,7 @@ for filename in os.listdir(config_path):
|
|||||||
# Prepare the URL and expected status codes
|
# Prepare the URL and expected status codes
|
||||||
url = f"{{ web_protocol }}://{domain}"
|
url = f"{{ web_protocol }}://{domain}"
|
||||||
|
|
||||||
redirected_domains = [domain['source'] for domain in {{current_play_redirect_domain_mappings}}]
|
redirected_domains = [domain['source'] for domain in {{ current_play_domain_mappings_redirect}}]
|
||||||
{%- if domains.mailu | safe_var | bool %}
|
{%- if domains.mailu | safe_var | bool %}
|
||||||
redirected_domains.append("{{domains | get_domain('mailu')}}")
|
redirected_domains.append("{{domains | get_domain('mailu')}}")
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
application_id: "html_server"
|
application_id: "html-server"
|
||||||
domain: "{{domains | get_domain(application_id)}}"
|
domain: "{{domains | get_domain(application_id)}}"
|
@ -9,12 +9,15 @@
|
|||||||
set_fact:
|
set_fact:
|
||||||
system_email: "{{ default_system_email | combine(system_email | default({}, true), recursive=True) }}"
|
system_email: "{{ default_system_email | combine(system_email | default({}, true), recursive=True) }}"
|
||||||
|
|
||||||
|
- name: Merge application definitions
|
||||||
|
set_fact:
|
||||||
|
applications: "{{ defaults_applications | combine(applications | default({}, true), recursive=True) }}"
|
||||||
|
|
||||||
- name: Merge current play applications
|
- name: Merge current play applications
|
||||||
set_fact:
|
set_fact:
|
||||||
current_play_applications: >-
|
current_play_applications: >-
|
||||||
{{
|
{{
|
||||||
defaults_applications |
|
applications |
|
||||||
combine(applications | default({}, true), recursive=True) |
|
|
||||||
applications_if_group_and_deps(group_names)
|
applications_if_group_and_deps(group_names)
|
||||||
}}
|
}}
|
||||||
|
|
||||||
@ -26,28 +29,29 @@
|
|||||||
combine(domains | default({}, true), recursive=True)
|
combine(domains | default({}, true), recursive=True)
|
||||||
}}
|
}}
|
||||||
|
|
||||||
- name: Set current play all domains incl. www redirect if enabled
|
|
||||||
set_fact:
|
|
||||||
current_play_domains_all: >-
|
|
||||||
{{
|
|
||||||
current_play_domains |
|
|
||||||
generate_all_domains(
|
|
||||||
('www_redirect' in group_names)
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
|
|
||||||
- name: Set current play redirect domain mappings
|
- name: Set current play redirect domain mappings
|
||||||
set_fact:
|
set_fact:
|
||||||
current_play_redirect_domain_mappings: >-
|
current_play_domain_mappings_redirect: >-
|
||||||
{{
|
{{
|
||||||
current_play_applications |
|
current_play_applications |
|
||||||
domain_mappings(primary_domain) |
|
domain_mappings(primary_domain) |
|
||||||
merge_mapping(redirect_domain_mappings, 'source')
|
merge_mapping(redirect_domain_mappings, 'source')
|
||||||
}}
|
}}
|
||||||
|
|
||||||
- name: Merge application definitions
|
- name: Set current play all domains incl. www redirect if enabled
|
||||||
set_fact:
|
set_fact:
|
||||||
applications: "{{ defaults_applications | combine(applications | default({}, true), recursive=True) }}"
|
current_play_domains_all: >-
|
||||||
|
{{
|
||||||
|
(current_play_domains |
|
||||||
|
combine(
|
||||||
|
current_play_domain_mappings_redirect |
|
||||||
|
items2dict(key_name='target', value_name='source'),
|
||||||
|
recursive=True
|
||||||
|
)) |
|
||||||
|
generate_all_domains(
|
||||||
|
('www_redirect' in group_names)
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
|
||||||
- name: Merge domain definitions for all domains
|
- name: Merge domain definitions for all domains
|
||||||
set_fact:
|
set_fact:
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
include_role:
|
include_role:
|
||||||
name: nginx-redirect-domains
|
name: nginx-redirect-domains
|
||||||
vars:
|
vars:
|
||||||
domain_mappings: "{{current_play_redirect_domain_mappings}}"
|
domain_mappings: "{{ current_play_domain_mappings_redirect}}"
|
||||||
|
|
||||||
- name: setup www redirect
|
- name: setup www redirect
|
||||||
when: ("www_redirect" in group_names)
|
when: ("www_redirect" in group_names)
|
||||||
|
@ -15,9 +15,9 @@ class TestLoadConfigurationFilter(unittest.TestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
_cfg_cache.clear()
|
_cfg_cache.clear()
|
||||||
self.f = FilterModule().filters()['load_configuration']
|
self.f = FilterModule().filters()['load_configuration']
|
||||||
self.app = 'html_server'
|
self.app = 'html-server'
|
||||||
self.nested_cfg = {
|
self.nested_cfg = {
|
||||||
'html_server': {
|
'html-server': {
|
||||||
'features': {'matomo': True},
|
'features': {'matomo': True},
|
||||||
'domains': {'canonical': ['html.example.com']}
|
'domains': {'canonical': ['html.example.com']}
|
||||||
}
|
}
|
||||||
@ -76,8 +76,8 @@ class TestLoadConfigurationFilter(unittest.TestCase):
|
|||||||
@patch('load_configuration.os.listdir', return_value=['r1'])
|
@patch('load_configuration.os.listdir', return_value=['r1'])
|
||||||
@patch('load_configuration.os.path.isdir', return_value=True)
|
@patch('load_configuration.os.path.isdir', return_value=True)
|
||||||
@patch('load_configuration.os.path.exists', return_value=True)
|
@patch('load_configuration.os.path.exists', return_value=True)
|
||||||
@patch('load_configuration.open', mock_open(read_data="html_server: {}"))
|
@patch('load_configuration.open', mock_open(read_data="html-server: {}"))
|
||||||
@patch('load_configuration.yaml.safe_load', return_value={'html_server': {}})
|
@patch('load_configuration.yaml.safe_load', return_value={'html-server': {}})
|
||||||
def test_key_not_found_after_load(self, *_):
|
def test_key_not_found_after_load(self, *_):
|
||||||
with self.assertRaises(AnsibleFilterError):
|
with self.assertRaises(AnsibleFilterError):
|
||||||
self.f(self.app, 'does.not.exist')
|
self.f(self.app, 'does.not.exist')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user