mirror of
				https://github.com/kevinveenbirkenbach/computer-playbook.git
				synced 2025-10-31 10:19:09 +00:00 
			
		
		
		
	Optimized code and solved bugs
This commit is contained in:
		| @@ -1,8 +1,8 @@ | ||||
| from ansible.errors import AnsibleFilterError | ||||
| import os | ||||
| import sys | ||||
| import yaml | ||||
|  | ||||
|  | ||||
| class FilterModule(object): | ||||
|     def filters(self): | ||||
|         return { | ||||
| @@ -15,48 +15,67 @@ class FilterModule(object): | ||||
|           1) directly in group_names, or | ||||
|           2) the application_id of any role reachable (recursively) | ||||
|              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): | ||||
|             raise AnsibleFilterError(f"Expected applications as dict, got {type(applications).__name__}") | ||||
|         if not isinstance(group_names, (list, tuple)): | ||||
|             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__) | ||||
|         project_root = os.path.abspath(os.path.join(plugin_dir, '..')) | ||||
|         roles_dir = os.path.join(project_root, 'roles') | ||||
|  | ||||
|         # recursively collect all roles reachable from the given groups | ||||
|         def collect_roles(role, seen): | ||||
|             if role in seen: | ||||
|                 return | ||||
|             seen.add(role) | ||||
|             meta_file = os.path.join(roles_dir, role, 'meta', 'main.yml') | ||||
|             if not os.path.isfile(meta_file): | ||||
|                 return | ||||
|             try: | ||||
|                 with open(meta_file) as f: | ||||
|                     meta = yaml.safe_load(f) or {} | ||||
|             except Exception: | ||||
|                 return | ||||
|             for dep in meta.get('dependencies', []): | ||||
|                 if isinstance(dep, str): | ||||
|                     dep_name = dep | ||||
|                 elif isinstance(dep, dict): | ||||
|                     dep_name = dep.get('role') or dep.get('name') | ||||
|                 else: | ||||
|                     continue | ||||
|                 collect_roles(dep_name, seen) | ||||
|         return os.path.join(project_root, 'roles') | ||||
|  | ||||
|     def _collect_reachable_roles(self, group_names, roles_dir): | ||||
|         """Recursively collect all roles reachable from the given groups via meta/dependencies.""" | ||||
|         included_roles = set() | ||||
|         for grp in group_names: | ||||
|             collect_roles(grp, included_roles) | ||||
|         for group in group_names: | ||||
|             self._collect_roles_from_group(group, included_roles, roles_dir) | ||||
|         return included_roles | ||||
|  | ||||
|         # gather application_ids from those roles | ||||
|     def _collect_roles_from_group(self, group, seen, roles_dir): | ||||
|         """Recursively collect roles from a specific group.""" | ||||
|         if group in seen: | ||||
|             return | ||||
|         seen.add(group) | ||||
|  | ||||
|         meta_file = os.path.join(roles_dir, group, 'meta', 'main.yml') | ||||
|         if not os.path.isfile(meta_file): | ||||
|             return | ||||
|  | ||||
|         try: | ||||
|             with open(meta_file) as f: | ||||
|                 meta = yaml.safe_load(f) or {} | ||||
|         except Exception: | ||||
|             return | ||||
|  | ||||
|         for dep in meta.get('dependencies', []): | ||||
|             dep_name = self._get_dependency_name(dep) | ||||
|             if dep_name: | ||||
|                 self._collect_roles_from_group(dep_name, seen, roles_dir) | ||||
|  | ||||
|     def _get_dependency_name(self, dependency): | ||||
|         """Extract the dependency role name from the meta data.""" | ||||
|         if isinstance(dependency, str): | ||||
|             return dependency | ||||
|         elif isinstance(dependency, dict): | ||||
|             return dependency.get('role') or dependency.get('name') | ||||
|         return None | ||||
|  | ||||
|     def _gather_application_ids(self, included_roles, roles_dir): | ||||
|         """Gather application_ids from the roles.""" | ||||
|         included_app_ids = set() | ||||
|         for role in included_roles: | ||||
|             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 {} | ||||
|             except Exception: | ||||
|                 continue | ||||
|  | ||||
|             app_id = vars_data.get('application_id') | ||||
|             if isinstance(app_id, str) and 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 = {} | ||||
|         for app_key, cfg in applications.items(): | ||||
|             if app_key in group_names or app_key in included_app_ids: | ||||
|                 result[app_key] = cfg | ||||
|  | ||||
|         return result | ||||
|         return result | ||||
|   | ||||
| @@ -5,71 +5,79 @@ class FilterModule(object): | ||||
|         return {'canonical_domains_map': self.canonical_domains_map} | ||||
|  | ||||
|     def canonical_domains_map(self, apps, primary_domain): | ||||
|         def parse_entry(domains_cfg, key, app_id): | ||||
|             if key not in domains_cfg: | ||||
|                 return None | ||||
|             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 | ||||
|  | ||||
|         """ | ||||
|         Maps applications to their canonical domains, checking for conflicts  | ||||
|         and ensuring all domains are valid and unique across applications. | ||||
|         """ | ||||
|         result = {} | ||||
|         seen = {} | ||||
|         seen_domains = {} | ||||
|  | ||||
|         for app_id, cfg in apps.items(): | ||||
|             domains_cfg = cfg.get('domains') | ||||
|             if not domains_cfg or 'canonical' not in domains_cfg: | ||||
|                 default = f"{app_id}.{primary_domain}" | ||||
|                 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] | ||||
|                 self._add_default_domain(app_id, primary_domain, seen_domains, result) | ||||
|                 continue | ||||
|  | ||||
|             entry = domains_cfg['canonical'] | ||||
|  | ||||
|             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__}" | ||||
|                 ) | ||||
|             canonical_domains = domains_cfg['canonical'] | ||||
|             self._process_canonical_domains(app_id, canonical_domains, seen_domains, 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: | ||||
|     editorial_responsible:  "Johannes Gutenberg" | ||||
|     source_code:            "https://github.com/kevinveenbirkenbach/cymais" | ||||
|     imprint: >- | ||||
|       {{ "{protocol}://{domain}/imprint.html" | ||||
|         | safe_placeholders({ | ||||
|             'protocol': web_protocol, | ||||
|             'domain':   domains.html_server | ||||
|           }) | ||||
|       }} | ||||
|     imprint: "{{web_protocol}}://{{domains['html-server']}}/imprint.html" | ||||
| @@ -1,8 +1,3 @@ | ||||
| - name: "Debug: cloudflare_domains" | ||||
|   debug: | ||||
|     var: cloudflare_domains | ||||
|   when: enable_debug | ||||
|  | ||||
| - name: Create or update Cloudflare A-record for {{ item }} | ||||
|   community.general.cloudflare_dns: | ||||
|     api_token: "{{ cloudflare_api_token }}" | ||||
|   | ||||
| @@ -283,7 +283,7 @@ HELP_URL=https://docs.bigbluebutton.org/greenlight/gl-overview.html | ||||
| #   approval - For approve/decline registration | ||||
| DEFAULT_REGISTRATION=invite | ||||
|  | ||||
| {% if applications[application_id].features.oidc | bool %} | ||||
| {% if applications | is_feature_enabled('oidc',application_id) %} | ||||
| ### EXTERNAL AUTHENTICATION METHODS | ||||
| # @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: | ||||
|   ## 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'" | ||||
| {% if applications[application_id].features.oidc | bool %} | ||||
| {% if applications | is_feature_enabled('oidc',application_id) %} | ||||
|   # Deactivate Default Login | ||||
|   - 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 | ||||
|   | ||||
| @@ -77,7 +77,7 @@ ESPOCRM_CONFIG_LDAP_USER_LOGIN_FILTER=(sAMAccountName=%USERNAME%) | ||||
| # OpenID Connect settings (optional) | ||||
| # 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 | ||||
|   | ||||
| @@ -17,7 +17,7 @@ listmonk_settings: | ||||
|          "provider_url": oidc.client.issuer_url, | ||||
|          "client_secret": oidc.client.secret | ||||
|       } | to_json }} | ||||
|     when: applications[application_id].features.oidc | bool | ||||
|     when: applications | is_feature_enabled('oidc',application_id) | ||||
|  | ||||
|   # hCaptcha toggles and credentials | ||||
|   - key: "security.enable_captcha" | ||||
|   | ||||
| @@ -158,7 +158,7 @@ API_TOKEN={{applications.mailu.credentials.api_token}} | ||||
| AUTH_REQUIRE_TOKENS=True | ||||
|  | ||||
|  | ||||
| {% if applications[application_id].features.oidc | bool %} | ||||
| {% if applications | is_feature_enabled('oidc',application_id) %} | ||||
| ###################################  | ||||
| # OpenID Connect settings | ||||
| ################################### | ||||
|   | ||||
| @@ -8,7 +8,7 @@ cert_mount_directory:     "{{docker_compose.directories.volumes}}certs/" | ||||
|  | ||||
| # Use dedicated source for oidc if activated   | ||||
| # @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) }}" | ||||
| http_port:                "{{ ports.localhost.http[application_id] }}" | ||||
| @@ -52,7 +52,7 @@ SMTP_OPENSSL_VERIFY_MODE=none | ||||
| SMTP_ENABLE_STARTTLS=auto | ||||
| 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 | ||||
| ################################### | ||||
|   | ||||
| @@ -20,8 +20,6 @@ oidc: | ||||
|   # @see https://apps.nextcloud.com/apps/sociallogin | ||||
|   flavor:                     "oidc_login"                                      # Keeping on sociallogin because the other option is not implemented yet                                              | ||||
| 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: | ||||
|   matomo:                       true | ||||
|   css:                          true | ||||
|   | ||||
| @@ -1,15 +1,15 @@ | ||||
| http_address            =   "0.0.0.0:4180" | ||||
| cookie_secret           =   "{{ applications[oauth2_proxy_application_id].credentials.oauth2_proxy_cookie_secret }}" | ||||
| 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 }}" | ||||
| cookie_domains          =   ["{{ domains[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. | ||||
| 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. | ||||
|  | ||||
| # keycloak provider | ||||
| client_secret           =   "{{ oidc.client.secret }}" | ||||
| 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 }}" | ||||
| provider                =   "oidc" | ||||
| provider_display_name   =   "Keycloak" | ||||
|   | ||||
| @@ -17,6 +17,8 @@ csp: | ||||
|   flags: | ||||
|     script-src: | ||||
|       unsafe-inline: true | ||||
|     style-src: | ||||
|       unsafe-inline: true   | ||||
| domains: | ||||
|   canonical: | ||||
|     - "project.{{ primary_domain }}" | ||||
| @@ -1,5 +1,5 @@ | ||||
| application_id:               "pgadmin" | ||||
| 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_group:                "{{pgadmin_user}}" | ||||
| @@ -1,3 +1,3 @@ | ||||
| application_id:       "phpmyadmin" | ||||
| 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 | ||||
|         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 %} | ||||
|         redirected_domains.append("{{domains | get_domain('mailu')}}") | ||||
|         {%- endif %} | ||||
|   | ||||
| @@ -1,2 +1,2 @@ | ||||
| application_id: "html_server" | ||||
| application_id: "html-server" | ||||
| domain:         "{{domains | get_domain(application_id)}}" | ||||
| @@ -9,14 +9,17 @@ | ||||
|     set_fact: | ||||
|       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 | ||||
|     set_fact: | ||||
|       current_play_applications: >- | ||||
|         {{  | ||||
|           defaults_applications |  | ||||
|           combine(applications | default({}, true), recursive=True) | | ||||
|           applications | | ||||
|           applications_if_group_and_deps(group_names) | ||||
|           }} | ||||
|         }} | ||||
|  | ||||
|   - name: Merge current play domain definitions | ||||
|     set_fact: | ||||
| @@ -26,28 +29,29 @@ | ||||
|             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  | ||||
|     set_fact: | ||||
|       current_play_redirect_domain_mappings: >- | ||||
|       current_play_domain_mappings_redirect: >- | ||||
|         {{  | ||||
|           current_play_applications | | ||||
|           domain_mappings(primary_domain) |  | ||||
|           merge_mapping(redirect_domain_mappings, 'source')  | ||||
|         }} | ||||
|  | ||||
|   - name: Merge application definitions | ||||
|   - name: Set current play all domains incl. www redirect if enabled | ||||
|     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 | ||||
|     set_fact: | ||||
|   | ||||
| @@ -32,7 +32,7 @@ | ||||
|   include_role: | ||||
|     name: nginx-redirect-domains | ||||
|   vars: | ||||
|     domain_mappings: "{{current_play_redirect_domain_mappings}}" | ||||
|     domain_mappings: "{{ current_play_domain_mappings_redirect}}" | ||||
|  | ||||
| - name: setup www redirect  | ||||
|   when: ("www_redirect" in group_names) | ||||
|   | ||||
| @@ -15,9 +15,9 @@ class TestLoadConfigurationFilter(unittest.TestCase): | ||||
|     def setUp(self): | ||||
|         _cfg_cache.clear() | ||||
|         self.f = FilterModule().filters()['load_configuration'] | ||||
|         self.app = 'html_server' | ||||
|         self.app = 'html-server' | ||||
|         self.nested_cfg = { | ||||
|             'html_server': { | ||||
|             'html-server': { | ||||
|                 'features': {'matomo': True}, | ||||
|                 '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.path.isdir', 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.yaml.safe_load', return_value={'html_server': {}}) | ||||
|     @patch('load_configuration.open', mock_open(read_data="html-server: {}")) | ||||
|     @patch('load_configuration.yaml.safe_load', return_value={'html-server': {}}) | ||||
|     def test_key_not_found_after_load(self, *_): | ||||
|         with self.assertRaises(AnsibleFilterError): | ||||
|             self.f(self.app, 'does.not.exist') | ||||
|   | ||||
		Reference in New Issue
	
	Block a user