mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-07-17 22:14:25 +02:00
Fail safed more parts of the code
This commit is contained in:
parent
066b4d59d6
commit
ead60dab84
@ -1,46 +1,37 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
# cli/meta/applications/all.py
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import glob
|
|
||||||
import os
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
# Import the Ansible filter implementation
|
||||||
try:
|
try:
|
||||||
import yaml
|
from filter_plugins.get_all_application_ids import get_all_application_ids
|
||||||
except ImportError:
|
except ImportError:
|
||||||
sys.stderr.write("PyYAML is required. Install with `pip install pyyaml`.\n")
|
sys.stderr.write("Filter plugin `get_all_application_ids` not found. Ensure `filter_plugins/get_all_application_ids.py` is in your PYTHONPATH.\n")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def find_application_ids():
|
def find_application_ids():
|
||||||
"""
|
"""
|
||||||
Searches all files matching roles/*/vars/main.yml for the key 'application_id'
|
Legacy function retained for reference.
|
||||||
and returns a list of all found IDs.
|
Delegates to the `get_all_application_ids` filter plugin.
|
||||||
"""
|
"""
|
||||||
pattern = os.path.join('roles', '*', 'vars', 'main.yml')
|
return get_all_application_ids()
|
||||||
app_ids = []
|
|
||||||
|
|
||||||
for filepath in glob.glob(pattern):
|
|
||||||
try:
|
|
||||||
with open(filepath, 'r', encoding='utf-8') as f:
|
|
||||||
data = yaml.safe_load(f)
|
|
||||||
except Exception as e:
|
|
||||||
sys.stderr.write(f"Error reading {filepath}: {e}\n")
|
|
||||||
continue
|
|
||||||
|
|
||||||
if isinstance(data, dict) and 'application_id' in data:
|
|
||||||
app_ids.append(data['application_id'])
|
|
||||||
|
|
||||||
return sorted(set(app_ids))
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description='Output a list of all application_id values defined in roles/*/vars/main.yml'
|
description='Output a list of all application_id values defined in roles/*/vars/main.yml'
|
||||||
)
|
)
|
||||||
# No arguments other than --help
|
|
||||||
parser.parse_args()
|
parser.parse_args()
|
||||||
|
|
||||||
ids = find_application_ids()
|
try:
|
||||||
|
ids = find_application_ids()
|
||||||
|
except Exception as e:
|
||||||
|
sys.stderr.write(f"Error retrieving application IDs: {e}\n")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
for app_id in ids:
|
for app_id in ids:
|
||||||
print(app_id)
|
print(app_id)
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ import argparse
|
|||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
def get_role_folder(application_id, roles_path):
|
def get_role(application_id, roles_path):
|
||||||
"""
|
"""
|
||||||
Find the role directory under `roles_path` whose vars/main.yml contains the specified application_id.
|
Find the role directory under `roles_path` whose vars/main.yml contains the specified application_id.
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ def main():
|
|||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
folder = get_role_folder(args.application_id, args.roles_path)
|
folder = get_role(args.application_id, args.roles_path)
|
||||||
print(folder)
|
print(folder)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
except RuntimeError as err:
|
except RuntimeError as err:
|
||||||
|
40
filter_plugins/get_all_application_ids.py
Normal file
40
filter_plugins/get_all_application_ids.py
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# filter_plugins/get_all_application_ids.py
|
||||||
|
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
|
def get_all_application_ids(roles_dir='roles'):
|
||||||
|
"""
|
||||||
|
Ansible filter to retrieve all unique application_id values
|
||||||
|
defined in roles/*/vars/main.yml files.
|
||||||
|
|
||||||
|
:param roles_dir: Base directory for Ansible roles (default: 'roles')
|
||||||
|
:return: Sorted list of unique application_id strings
|
||||||
|
"""
|
||||||
|
pattern = os.path.join(roles_dir, '*', 'vars', 'main.yml')
|
||||||
|
app_ids = []
|
||||||
|
|
||||||
|
for filepath in glob.glob(pattern):
|
||||||
|
try:
|
||||||
|
with open(filepath, 'r', encoding='utf-8') as f:
|
||||||
|
data = yaml.safe_load(f)
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if isinstance(data, dict) and 'application_id' in data:
|
||||||
|
app_ids.append(data['application_id'])
|
||||||
|
|
||||||
|
return sorted(set(app_ids))
|
||||||
|
|
||||||
|
|
||||||
|
class FilterModule(object):
|
||||||
|
"""
|
||||||
|
Ansible filter plugin for retrieving application IDs.
|
||||||
|
"""
|
||||||
|
def filters(self):
|
||||||
|
return {
|
||||||
|
'get_all_application_ids': get_all_application_ids
|
||||||
|
}
|
51
filter_plugins/get_application_id.py
Normal file
51
filter_plugins/get_application_id.py
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# filter_plugins/get_application_id.py
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import yaml
|
||||||
|
from ansible.errors import AnsibleFilterError
|
||||||
|
|
||||||
|
|
||||||
|
def get_application_id(role_name):
|
||||||
|
"""
|
||||||
|
Jinja2/Ansible filter: given a role name, load its vars/main.yml and return the application_id value.
|
||||||
|
"""
|
||||||
|
# Construct path: assumes current working directory is project root
|
||||||
|
vars_file = os.path.join(os.getcwd(), 'roles', role_name, 'vars', 'main.yml')
|
||||||
|
|
||||||
|
if not os.path.isfile(vars_file):
|
||||||
|
raise AnsibleFilterError(f"Vars file not found for role '{role_name}': {vars_file}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Read entire file content to avoid lazy stream issues
|
||||||
|
with open(vars_file, 'r', encoding='utf-8') as f:
|
||||||
|
content = f.read()
|
||||||
|
data = yaml.safe_load(content)
|
||||||
|
except Exception as e:
|
||||||
|
raise AnsibleFilterError(f"Error reading YAML from {vars_file}: {e}")
|
||||||
|
|
||||||
|
# Ensure parsed data is a mapping
|
||||||
|
if not isinstance(data, dict):
|
||||||
|
raise AnsibleFilterError(
|
||||||
|
f"Error reading YAML from {vars_file}: expected mapping, got {type(data).__name__}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Detect malformed YAML: no valid identifier-like keys
|
||||||
|
valid_key_pattern = re.compile(r'^[A-Za-z_][A-Za-z0-9_]*$')
|
||||||
|
if data and not any(valid_key_pattern.match(k) for k in data.keys()):
|
||||||
|
raise AnsibleFilterError(f"Error reading YAML from {vars_file}: invalid top-level keys")
|
||||||
|
|
||||||
|
if 'application_id' not in data:
|
||||||
|
raise AnsibleFilterError(f"Key 'application_id' not found in {vars_file}")
|
||||||
|
|
||||||
|
return data['application_id']
|
||||||
|
|
||||||
|
|
||||||
|
class FilterModule(object):
|
||||||
|
"""
|
||||||
|
Ansible filter plugin entry point.
|
||||||
|
"""
|
||||||
|
def filters(self):
|
||||||
|
return {
|
||||||
|
'get_application_id': get_application_id,
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
'''
|
'''
|
||||||
Ansible filter plugin: get_role_folder
|
Ansible filter plugin: get_role
|
||||||
|
|
||||||
This filter inspects each role under the given roles directory, loads its vars/main.yml,
|
This filter inspects each role under the given roles directory, loads its vars/main.yml,
|
||||||
and returns the role folder name whose application_id matches the provided value.
|
and returns the role folder name whose application_id matches the provided value.
|
||||||
@ -10,7 +10,7 @@ import os
|
|||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
def get_role_folder(application_id, roles_path='roles'):
|
def get_role(application_id, roles_path='roles'):
|
||||||
"""
|
"""
|
||||||
Find the role directory under `roles_path` whose vars/main.yml contains the given application_id.
|
Find the role directory under `roles_path` whose vars/main.yml contains the given application_id.
|
||||||
|
|
||||||
@ -40,9 +40,9 @@ def get_role_folder(application_id, roles_path='roles'):
|
|||||||
|
|
||||||
class FilterModule(object):
|
class FilterModule(object):
|
||||||
"""
|
"""
|
||||||
Register the get_role_folder filter
|
Register the get_role filter
|
||||||
"""
|
"""
|
||||||
def filters(self):
|
def filters(self):
|
||||||
return {
|
return {
|
||||||
'get_role_folder': get_role_folder,
|
'get_role': get_role,
|
||||||
}
|
}
|
@ -38,15 +38,15 @@ ports:
|
|||||||
matomo: 8018
|
matomo: 8018
|
||||||
listmonk: 8019
|
listmonk: 8019
|
||||||
discourse: 8020
|
discourse: 8020
|
||||||
synapse: 8021
|
matrix_synapse: 8021
|
||||||
element: 8022
|
matrix_element: 8022
|
||||||
openproject: 8023
|
openproject: 8023
|
||||||
gitlab: 8024
|
gitlab: 8024
|
||||||
akaunting: 8025
|
akaunting: 8025
|
||||||
moodle: 8026
|
moodle: 8026
|
||||||
taiga: 8027
|
taiga: 8027
|
||||||
friendica: 8028
|
friendica: 8028
|
||||||
portfolio: 8029
|
web-app-port-ui: 8029
|
||||||
bluesky_api: 8030
|
bluesky_api: 8030
|
||||||
bluesky_web: 8031
|
bluesky_web: 8031
|
||||||
keycloak: 8032
|
keycloak: 8032
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
(function() {
|
(function() {
|
||||||
var primary = "{{ primary_domain }}";
|
var primary = "{{ primary_domain }}";
|
||||||
var allowedOrigin = "https://{{ domains | get_domain('portfolio') }}";
|
var allowedOrigin = "https://{{ domains | get_domain('web-app-port-ui') }}";
|
||||||
|
|
||||||
function notifyParent() {
|
function notifyParent() {
|
||||||
try {
|
try {
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
name: srv-web-7-6-composer
|
name: srv-web-7-6-composer
|
||||||
vars:
|
vars:
|
||||||
domain: "{{domains.matrix.synapse}}"
|
domain: "{{domains.matrix.synapse}}"
|
||||||
http_port: "{{ports.localhost.http.synapse}}"
|
http_port: "{{ports.localhost.http.matrix_synapse}}"
|
||||||
|
|
||||||
- name: create {{well_known_directory}}
|
- name: create {{well_known_directory}}
|
||||||
file:
|
file:
|
||||||
@ -36,7 +36,7 @@
|
|||||||
dest: "{{nginx.directories.http.servers}}{{domains.matrix.synapse}}.conf"
|
dest: "{{nginx.directories.http.servers}}{{domains.matrix.synapse}}.conf"
|
||||||
vars:
|
vars:
|
||||||
domain: "{{domains.matrix.synapse}}" # Didn't work in the past. May it works now. This does not seem to work @todo Check how to solve without declaring set_fact, seems a bug at templates
|
domain: "{{domains.matrix.synapse}}" # Didn't work in the past. May it works now. This does not seem to work @todo Check how to solve without declaring set_fact, seems a bug at templates
|
||||||
http_port: "{{ports.localhost.http.synapse}}"
|
http_port: "{{ports.localhost.http.matrix_synapse}}"
|
||||||
notify: restart nginx
|
notify: restart nginx
|
||||||
|
|
||||||
- name: "include role srv-proxy-6-6-domain for {{application_id}}"
|
- name: "include role srv-proxy-6-6-domain for {{application_id}}"
|
||||||
@ -44,7 +44,7 @@
|
|||||||
name: srv-proxy-6-6-domain
|
name: srv-proxy-6-6-domain
|
||||||
vars:
|
vars:
|
||||||
domain: "{{domains.matrix.element}}"
|
domain: "{{domains.matrix.element}}"
|
||||||
http_port: "{{ports.localhost.http.element}}"
|
http_port: "{{ports.localhost.http.matrix_element}}"
|
||||||
|
|
||||||
- name: include create-and-seed-database.yml for multiple bridges
|
- name: include create-and-seed-database.yml for multiple bridges
|
||||||
include_tasks: create-and-seed-database.yml
|
include_tasks: create-and-seed-database.yml
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
- SYNAPSE_SERVER_NAME={{domains.matrix.synapse}}
|
- SYNAPSE_SERVER_NAME={{domains.matrix.synapse}}
|
||||||
- SYNAPSE_REPORT_STATS=no
|
- SYNAPSE_REPORT_STATS=no
|
||||||
ports:
|
ports:
|
||||||
- "127.0.0.1:{{ports.localhost.http.synapse}}:{{ container_port }}"
|
- "127.0.0.1:{{ports.localhost.http.matrix_synapse}}:{{ container_port }}"
|
||||||
{% include 'roles/docker-container/templates/healthcheck/curl.yml.j2' %}
|
{% include 'roles/docker-container/templates/healthcheck/curl.yml.j2' %}
|
||||||
{% if bridges | length > 0 %}
|
{% if bridges | length > 0 %}
|
||||||
{% for item in bridges %}
|
{% for item in bridges %}
|
||||||
@ -36,7 +36,7 @@
|
|||||||
volumes:
|
volumes:
|
||||||
- ./element-config.json:/app/config.json
|
- ./element-config.json:/app/config.json
|
||||||
ports:
|
ports:
|
||||||
- "127.0.0.1:{{ports.localhost.http.element}}:{{ container_port }}"
|
- "127.0.0.1:{{ports.localhost.http.matrix_element}}:{{ container_port }}"
|
||||||
{% include 'roles/docker-container/templates/healthcheck/wget.yml.j2' %}
|
{% include 'roles/docker-container/templates/healthcheck/wget.yml.j2' %}
|
||||||
{% include 'roles/docker-container/templates/networks.yml.j2' %}
|
{% include 'roles/docker-container/templates/networks.yml.j2' %}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ server {
|
|||||||
{# Somehow .j2 doesn't interpretate the passed variable right. For this reasons this redeclaration is necessary #}
|
{# Somehow .j2 doesn't interpretate the passed variable right. For this reasons this redeclaration is necessary #}
|
||||||
{# Could be that this is related to the set_fact use #}
|
{# Could be that this is related to the set_fact use #}
|
||||||
{% set domain = domains.matrix.synapse %}
|
{% set domain = domains.matrix.synapse %}
|
||||||
{% set http_port = ports.localhost.http.synapse %}
|
{% set http_port = ports.localhost.http.matrix_synapse %}
|
||||||
|
|
||||||
server_name {{domains.matrix.synapse}};
|
server_name {{domains.matrix.synapse}};
|
||||||
{% include 'roles/srv-web-7-7-letsencrypt/templates/ssl_header.j2' %}
|
{% include 'roles/srv-web-7-7-letsencrypt/templates/ssl_header.j2' %}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# PortWebUI
|
# PortUI
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
|
@ -16,13 +16,13 @@ class LookupModule(LookupBase):
|
|||||||
This lookup iterates over all roles whose folder name starts with 'web-app-'
|
This lookup iterates over all roles whose folder name starts with 'web-app-'
|
||||||
and generates a list of dictionaries (cards). For each role, it:
|
and generates a list of dictionaries (cards). For each role, it:
|
||||||
|
|
||||||
- Extracts the application_id (everything after "web-app-")
|
- Reads application_id from the role's vars/main.yml
|
||||||
- Reads the title from the role's README.md (the first H1 line)
|
- Reads the title from the role's README.md (the first H1 line)
|
||||||
- Retrieves the description from galaxy_info.description in meta/main.yml
|
- Retrieves the description from galaxy_info.description in meta/main.yml
|
||||||
- Retrieves the icon class from galaxy_info.logo.class
|
- Retrieves the icon class from galaxy_info.logo.class
|
||||||
- Retrieves the tags from galaxy_info.galaxy_tags
|
- Retrieves the tags from galaxy_info.galaxy_tags
|
||||||
- Builds the URL using the 'domains' variable (e.g. domains | get_domain(application_id))
|
- Builds the URL using the 'domains' variable
|
||||||
- Sets the iframe flag from applications[application_id].features.iframe
|
- Sets the iframe flag from applications[application_id].features.portfolio_iframe
|
||||||
|
|
||||||
Only cards whose application_id is included in the variable group_names are returned.
|
Only cards whose application_id is included in the variable group_names are returned.
|
||||||
"""
|
"""
|
||||||
@ -40,11 +40,22 @@ class LookupModule(LookupBase):
|
|||||||
role_basename = os.path.basename(role_dir)
|
role_basename = os.path.basename(role_dir)
|
||||||
|
|
||||||
# Skip roles not starting with "web-app-"
|
# Skip roles not starting with "web-app-"
|
||||||
if not role_basename.startswith("web-app-"):
|
if not role_basename.startswith("web-app-"): # Ensure prefix
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Extract application_id from role name
|
# Load application_id from role's vars/main.yml
|
||||||
application_id = role_basename[len("web-app-"):]
|
vars_path = os.path.join(role_dir, "vars", "main.yml")
|
||||||
|
try:
|
||||||
|
if not os.path.isfile(vars_path):
|
||||||
|
raise AnsibleError(f"Vars file not found for role '{role_basename}': {vars_path}")
|
||||||
|
with open(vars_path, "r", encoding="utf-8") as vf:
|
||||||
|
vars_content = vf.read()
|
||||||
|
vars_data = yaml.safe_load(vars_content) or {}
|
||||||
|
application_id = vars_data.get("application_id")
|
||||||
|
if not application_id:
|
||||||
|
raise AnsibleError(f"Key 'application_id' not found in {vars_path}")
|
||||||
|
except Exception as e:
|
||||||
|
raise AnsibleError(f"Error getting application_id for role '{role_basename}': {e}")
|
||||||
|
|
||||||
# Skip roles not listed in group_names
|
# Skip roles not listed in group_names
|
||||||
if application_id not in group_names:
|
if application_id not in group_names:
|
||||||
@ -65,25 +76,24 @@ class LookupModule(LookupBase):
|
|||||||
title_match = re.search(r'^#\s+(.*)$', readme_content, re.MULTILINE)
|
title_match = re.search(r'^#\s+(.*)$', readme_content, re.MULTILINE)
|
||||||
title = title_match.group(1).strip() if title_match else application_id
|
title = title_match.group(1).strip() if title_match else application_id
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise AnsibleError("Error reading '{}': {}".format(readme_path, str(e)))
|
raise AnsibleError(f"Error reading '{readme_path}': {e}")
|
||||||
|
|
||||||
# Extract metadata from meta/main.yml
|
# Extract metadata from meta/main.yml
|
||||||
try:
|
try:
|
||||||
with open(meta_path, "r", encoding="utf-8") as f:
|
with open(meta_path, "r", encoding="utf-8") as f:
|
||||||
meta_data = yaml.safe_load(f)
|
meta_data = yaml.safe_load(f) or {}
|
||||||
|
|
||||||
galaxy_info = meta_data.get("galaxy_info", {})
|
galaxy_info = meta_data.get("galaxy_info", {})
|
||||||
|
|
||||||
# If display is set to False ignore it
|
# If display is set to False ignore it
|
||||||
if not galaxy_info.get("display", True):
|
if not galaxy_info.get("display", True):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
description = galaxy_info.get("description", "")
|
description = galaxy_info.get("description", "")
|
||||||
logo = galaxy_info.get("logo", {})
|
logo = galaxy_info.get("logo", {})
|
||||||
icon_class = logo.get("class", "fa-solid fa-cube")
|
icon_class = logo.get("class", "fa-solid fa-cube")
|
||||||
tags = galaxy_info.get("galaxy_tags", [])
|
tags = galaxy_info.get("galaxy_tags", [])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise AnsibleError("Error reading '{}': {}".format(meta_path, str(e)))
|
raise AnsibleError(f"Error reading '{meta_path}': {e}")
|
||||||
|
|
||||||
# Retrieve domains and applications from the variables
|
# Retrieve domains and applications from the variables
|
||||||
domains = variables.get("domains", {})
|
domains = variables.get("domains", {})
|
||||||
@ -94,7 +104,7 @@ class LookupModule(LookupBase):
|
|||||||
domain_url = domain_url[0]
|
domain_url = domain_url[0]
|
||||||
elif isinstance(domain_url, dict):
|
elif isinstance(domain_url, dict):
|
||||||
domain_url = next(iter(domain_url.values()))
|
domain_url = next(iter(domain_url.values()))
|
||||||
|
|
||||||
# Construct the URL using the domain_url if available.
|
# Construct the URL using the domain_url if available.
|
||||||
url = "https://" + domain_url if domain_url else ""
|
url = "https://" + domain_url if domain_url else ""
|
||||||
|
|
||||||
@ -107,7 +117,7 @@ class LookupModule(LookupBase):
|
|||||||
"title": title,
|
"title": title,
|
||||||
"text": description,
|
"text": description,
|
||||||
"url": url,
|
"url": url,
|
||||||
"link_text": "Explore {}".format(title),
|
"link_text": f"Explore {title}",
|
||||||
"iframe": iframe,
|
"iframe": iframe,
|
||||||
"tags": tags,
|
"tags": tags,
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
galaxy_info:
|
galaxy_info:
|
||||||
author: "Kevin Veen-Birkenbach"
|
author: "Kevin Veen-Birkenbach"
|
||||||
description: "Portfolio to showcase your projects and creative work with a focus on user experience and easy customization. 🚀"
|
description: "PortUI provides CyMaIS users with a unified web interface to easily access all their applications in one place"
|
||||||
license: "CyMaIS NonCommercial License (CNCL)"
|
license: "CyMaIS NonCommercial License (CNCL)"
|
||||||
license_url: "https://s.veen.world/cncl"
|
license_url: "https://s.veen.world/cncl"
|
||||||
company: |
|
company: |
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
application_id: "web-app-port-ui"
|
application_id: "web-app-port-ui"
|
||||||
docker_repository_address: "https://github.com/kevinveenbirkenbach/port-web-ui"
|
docker_repository_address: "https://github.com/kevinveenbirkenbach/port-ui"
|
||||||
config_inventory_path: "{{ inventory_dir }}/files/{{ inventory_hostname }}/docker/web-app-port-ui/config.yaml.j2"
|
config_inventory_path: "{{ inventory_dir }}/files/{{ inventory_hostname }}/docker/web-app-port-ui/config.yaml.j2"
|
||||||
docker_repository: true
|
docker_repository: true
|
@ -0,0 +1,51 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import unittest
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from filter_plugins.get_all_application_ids import get_all_application_ids
|
||||||
|
|
||||||
|
class TestApplicationIDsInPorts(unittest.TestCase):
|
||||||
|
def test_all_ports_application_ids_are_valid(self):
|
||||||
|
# Path to the ports definition file
|
||||||
|
ports_file = os.path.abspath(
|
||||||
|
os.path.join(
|
||||||
|
os.path.dirname(__file__), '..', '..', 'group_vars', 'all', '09_ports.yml'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
with open(ports_file, 'r', encoding='utf-8') as f:
|
||||||
|
data = yaml.safe_load(f)
|
||||||
|
|
||||||
|
# Collect all referenced application IDs under ports.hosttype.porttype
|
||||||
|
refs = set()
|
||||||
|
ports = data.get('ports', {}) or {}
|
||||||
|
for hosttype, porttypes in ports.items():
|
||||||
|
if not isinstance(porttypes, dict):
|
||||||
|
continue
|
||||||
|
for porttype, apps in porttypes.items():
|
||||||
|
if not isinstance(apps, dict):
|
||||||
|
continue
|
||||||
|
for app_id in apps.keys():
|
||||||
|
refs.add(app_id)
|
||||||
|
|
||||||
|
# Retrieve valid application IDs from Ansible roles
|
||||||
|
valid_ids = set(get_all_application_ids())
|
||||||
|
|
||||||
|
# Identify IDs that are neither valid nor have a valid prefix before the first underscore
|
||||||
|
missing = []
|
||||||
|
for app_id in refs:
|
||||||
|
if app_id in valid_ids:
|
||||||
|
continue
|
||||||
|
prefix = app_id.split('_', 1)[0]
|
||||||
|
if prefix in valid_ids:
|
||||||
|
continue
|
||||||
|
missing.append(app_id)
|
||||||
|
|
||||||
|
if missing:
|
||||||
|
self.fail(
|
||||||
|
f"Undefined application IDs in ports definition: {', '.join(sorted(missing))}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
@ -9,10 +9,15 @@ class TestAnsibleRolesMetadata(unittest.TestCase):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls):
|
def setUpClass(cls):
|
||||||
if not os.path.isdir(cls.ROLES_DIR):
|
all_dirs = os.listdir(cls.ROLES_DIR)
|
||||||
raise unittest.SkipTest(f"Roles directory not found at {cls.ROLES_DIR}")
|
cls.roles = [
|
||||||
cls.roles = [d for d in os.listdir(cls.ROLES_DIR)
|
d for d in all_dirs
|
||||||
if os.path.isdir(os.path.join(cls.ROLES_DIR, d))]
|
if (
|
||||||
|
os.path.isdir(os.path.join(cls.ROLES_DIR, d))
|
||||||
|
and d != '__pycache__'
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def test_each_role_has_valid_meta(self):
|
def test_each_role_has_valid_meta(self):
|
||||||
"""
|
"""
|
||||||
|
@ -1,51 +1,74 @@
|
|||||||
import os
|
import os
|
||||||
import unittest
|
|
||||||
import yaml
|
|
||||||
import glob
|
import glob
|
||||||
|
import yaml
|
||||||
import warnings
|
import warnings
|
||||||
|
import unittest
|
||||||
|
|
||||||
class TestApplicationIdMatchesRoleName(unittest.TestCase):
|
# import your filters
|
||||||
def test_application_id_matches_role_directory(self):
|
from filter_plugins.invokable_paths import get_invokable_paths, get_non_invokable_paths
|
||||||
"""
|
|
||||||
Warn if application_id in vars/main.yml does not match
|
class TestApplicationIdAndInvocability(unittest.TestCase):
|
||||||
the role directory basename, to avoid confusion.
|
@classmethod
|
||||||
If vars/main.yml is missing, do nothing.
|
def setUpClass(cls):
|
||||||
"""
|
# locate roles dir (two levels up)
|
||||||
# locate the 'roles' directory (two levels up)
|
|
||||||
base_dir = os.path.dirname(__file__)
|
base_dir = os.path.dirname(__file__)
|
||||||
roles_dir = os.path.abspath(os.path.join(base_dir, '..', '..', 'roles'))
|
cls.roles_dir = os.path.abspath(os.path.join(base_dir, '..', '..', 'roles'))
|
||||||
|
|
||||||
# iterate over each role folder
|
# get lists of invokable and non-invokable role *names*
|
||||||
for role_path in glob.glob(os.path.join(roles_dir, '*')):
|
# filters return dash-joined paths; for top-level roles names are just the basename
|
||||||
|
cls.invokable = {
|
||||||
|
p.split('-', 1)[0]
|
||||||
|
for p in get_invokable_paths()
|
||||||
|
}
|
||||||
|
cls.non_invokable = {
|
||||||
|
p.split('-', 1)[0]
|
||||||
|
for p in get_non_invokable_paths()
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_application_id_presence_and_match(self):
|
||||||
|
"""
|
||||||
|
- Invokable roles must have application_id defined (else fail).
|
||||||
|
- Non-invokable roles must NOT have application_id (else fail).
|
||||||
|
- If application_id exists but != folder name, warn and recommend aligning.
|
||||||
|
"""
|
||||||
|
for role_path in glob.glob(os.path.join(self.roles_dir, '*')):
|
||||||
if not os.path.isdir(role_path):
|
if not os.path.isdir(role_path):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
role_name = os.path.basename(role_path)
|
role_name = os.path.basename(role_path)
|
||||||
vars_main = os.path.join(role_path, 'vars', 'main.yml')
|
vars_main = os.path.join(role_path, 'vars', 'main.yml')
|
||||||
|
|
||||||
# skip roles without vars/main.yml
|
# load vars/main.yml if it exists
|
||||||
if not os.path.exists(vars_main):
|
data = {}
|
||||||
continue
|
if os.path.exists(vars_main):
|
||||||
|
with open(vars_main, 'r', encoding='utf-8') as f:
|
||||||
with open(vars_main, 'r', encoding='utf-8') as f:
|
data = yaml.safe_load(f) or {}
|
||||||
data = yaml.safe_load(f) or {}
|
|
||||||
|
|
||||||
app_id = data.get('application_id')
|
app_id = data.get('application_id')
|
||||||
if app_id is None:
|
|
||||||
|
if role_name in self.invokable:
|
||||||
|
# must have application_id
|
||||||
|
if app_id is None:
|
||||||
|
self.fail(f"{role_name}: invokable role is missing 'application_id' in vars/main.yml")
|
||||||
|
elif role_name in self.non_invokable:
|
||||||
|
# must NOT have application_id
|
||||||
|
if app_id is not None:
|
||||||
|
self.fail(f"{role_name}: non-invokable role should not define 'application_id' in vars/main.yml")
|
||||||
|
else:
|
||||||
|
# roles not mentioned in categories.yml? we'll skip them
|
||||||
|
continue
|
||||||
|
|
||||||
|
# if present but mismatched, warn
|
||||||
|
if app_id is not None and app_id != role_name:
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
f"{role_name}: 'application_id' is missing in vars/main.yml. "
|
f"{role_name}: 'application_id' is '{app_id}',"
|
||||||
f"Consider setting it to '{role_name}' to avoid confusion."
|
f" but the folder name is '{role_name}'."
|
||||||
)
|
" Consider setting application_id to exactly the role folder name to avoid confusion."
|
||||||
elif app_id != role_name:
|
|
||||||
warnings.warn(
|
|
||||||
f"{role_name}: 'application_id' is '{app_id}', "
|
|
||||||
f"but the folder name is '{role_name}'. "
|
|
||||||
"This can lead to confusion—using the directory name "
|
|
||||||
"as the application_id is recommended."
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# always pass
|
# if we get here, all presence/absence checks passed
|
||||||
self.assertTrue(True)
|
self.assertTrue(True)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@ -20,7 +20,8 @@ class TestDependencyApplicationId(unittest.TestCase):
|
|||||||
vars_file = os.path.join(role_path, 'vars', 'main.yml')
|
vars_file = os.path.join(role_path, 'vars', 'main.yml')
|
||||||
if not os.path.isfile(vars_file):
|
if not os.path.isfile(vars_file):
|
||||||
return None
|
return None
|
||||||
data = yaml.safe_load(open(vars_file, encoding='utf-8')) or {}
|
with open(vars_file, encoding='utf-8') as f:
|
||||||
|
data = yaml.safe_load(f) or {}
|
||||||
return data.get('application_id')
|
return data.get('application_id')
|
||||||
|
|
||||||
# Iterate all roles
|
# Iterate all roles
|
||||||
@ -33,7 +34,9 @@ class TestDependencyApplicationId(unittest.TestCase):
|
|||||||
if not os.path.isfile(meta_file):
|
if not os.path.isfile(meta_file):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
meta = yaml.safe_load(open(meta_file, encoding='utf-8')) or {}
|
with open(meta_file, encoding='utf-8') as f:
|
||||||
|
meta = yaml.safe_load(f) or {}
|
||||||
|
|
||||||
deps = meta.get('dependencies', [])
|
deps = meta.get('dependencies', [])
|
||||||
if not isinstance(deps, list):
|
if not isinstance(deps, list):
|
||||||
continue
|
continue
|
||||||
|
46
tests/integration/test_get_domain_application_ids.py
Normal file
46
tests/integration/test_get_domain_application_ids.py
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
# Ensure filter_plugins is on the path
|
||||||
|
PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||||
|
sys.path.insert(0, PROJECT_ROOT)
|
||||||
|
|
||||||
|
from filter_plugins.get_all_application_ids import get_all_application_ids
|
||||||
|
|
||||||
|
class TestGetDomainApplicationIds(unittest.TestCase):
|
||||||
|
"""
|
||||||
|
Integration test to verify that all string literals passed to get_domain()
|
||||||
|
correspond to valid application_id values defined in roles/*/vars/main.yml.
|
||||||
|
"""
|
||||||
|
|
||||||
|
GET_DOMAIN_PATTERN = re.compile(r"get_domain\(\s*['\"]([^'\"]+)['\"]\s*\)")
|
||||||
|
|
||||||
|
def test_get_domain_literals_are_valid_ids(self):
|
||||||
|
# Collect all application IDs from roles
|
||||||
|
valid_ids = set(get_all_application_ids())
|
||||||
|
|
||||||
|
# Walk through project files
|
||||||
|
invalid_usages = []
|
||||||
|
for root, dirs, files in os.walk(PROJECT_ROOT):
|
||||||
|
# Skip tests directory to avoid matching in test code
|
||||||
|
if 'tests' in root.split(os.sep):
|
||||||
|
continue
|
||||||
|
for fname in files:
|
||||||
|
if not fname.endswith('.py'):
|
||||||
|
continue
|
||||||
|
path = os.path.join(root, fname)
|
||||||
|
with open(path, 'r', encoding='utf-8') as f:
|
||||||
|
content = f.read()
|
||||||
|
for match in self.GET_DOMAIN_PATTERN.finditer(content):
|
||||||
|
literal = match.group(1)
|
||||||
|
if literal not in valid_ids:
|
||||||
|
invalid_usages.append((path, literal))
|
||||||
|
|
||||||
|
if invalid_usages:
|
||||||
|
msgs = [f"{path}: '{lit}' is not a valid application_id" for path, lit in invalid_usages]
|
||||||
|
self.fail("Found invalid get_domain() usages:\n" + "\n".join(msgs))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
42
tests/integration/test_roles_folder_names.py
Normal file
42
tests/integration/test_roles_folder_names.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
class TestRolesFolderNames(unittest.TestCase):
|
||||||
|
def test_no_underscore_in_role_folder_names(self):
|
||||||
|
"""
|
||||||
|
Integration test that verifies none of the folders under 'roles' contain an underscore in their name,
|
||||||
|
ignoring the '__pycache__' folder.
|
||||||
|
"""
|
||||||
|
# Determine the absolute path to the 'roles' directory
|
||||||
|
roles_dir = os.path.abspath(
|
||||||
|
os.path.join(
|
||||||
|
os.path.dirname(__file__), '..', '..', 'roles'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# List all entries in the roles directory
|
||||||
|
try:
|
||||||
|
entries = os.listdir(roles_dir)
|
||||||
|
except FileNotFoundError:
|
||||||
|
self.fail(f"Roles directory not found at expected location: {roles_dir}")
|
||||||
|
|
||||||
|
# Identify any role folders containing underscores, excluding '__pycache__'
|
||||||
|
invalid = []
|
||||||
|
for name in entries:
|
||||||
|
# Skip the '__pycache__' directory
|
||||||
|
if name == '__pycache__':
|
||||||
|
continue
|
||||||
|
path = os.path.join(roles_dir, name)
|
||||||
|
if os.path.isdir(path) and '_' in name:
|
||||||
|
invalid.append(name)
|
||||||
|
|
||||||
|
# Fail the test if any invalid folder names are found
|
||||||
|
if invalid:
|
||||||
|
self.fail(
|
||||||
|
f"Role folder names must not contain underscores: {', '.join(sorted(invalid))}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
55
tests/unit/filter_plugins/test_get_all_application_ids.py
Normal file
55
tests/unit/filter_plugins/test_get_all_application_ids.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import unittest
|
||||||
|
import tempfile
|
||||||
|
import os
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from filter_plugins.get_all_application_ids import get_all_application_ids
|
||||||
|
|
||||||
|
class TestGetAllApplicationIds(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
# Create a temporary directory to act as the roles base
|
||||||
|
self.tmpdir = tempfile.TemporaryDirectory()
|
||||||
|
self.roles_dir = os.path.join(self.tmpdir.name, 'roles')
|
||||||
|
os.makedirs(self.roles_dir)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
# Clean up temporary directory
|
||||||
|
self.tmpdir.cleanup()
|
||||||
|
|
||||||
|
def create_role(self, role_name, data):
|
||||||
|
# Helper to create roles/<role_name>/vars/main.yml with given dict
|
||||||
|
path = os.path.join(self.roles_dir, role_name, 'vars')
|
||||||
|
os.makedirs(path, exist_ok=True)
|
||||||
|
with open(os.path.join(path, 'main.yml'), 'w', encoding='utf-8') as f:
|
||||||
|
yaml.safe_dump(data, f)
|
||||||
|
|
||||||
|
def test_single_application_id(self):
|
||||||
|
self.create_role('role1', {'application_id': 'app1'})
|
||||||
|
result = get_all_application_ids(self.roles_dir)
|
||||||
|
self.assertEqual(result, ['app1'])
|
||||||
|
|
||||||
|
def test_multiple_application_ids(self):
|
||||||
|
self.create_role('role1', {'application_id': 'app1'})
|
||||||
|
self.create_role('role2', {'application_id': 'app2'})
|
||||||
|
result = get_all_application_ids(self.roles_dir)
|
||||||
|
self.assertEqual(sorted(result), ['app1', 'app2'])
|
||||||
|
|
||||||
|
def test_duplicate_application_ids(self):
|
||||||
|
self.create_role('role1', {'application_id': 'app1'})
|
||||||
|
self.create_role('role2', {'application_id': 'app1'})
|
||||||
|
result = get_all_application_ids(self.roles_dir)
|
||||||
|
self.assertEqual(result, ['app1'])
|
||||||
|
|
||||||
|
def test_missing_application_id(self):
|
||||||
|
self.create_role('role1', {'other_key': 'value'})
|
||||||
|
result = get_all_application_ids(self.roles_dir)
|
||||||
|
self.assertEqual(result, [])
|
||||||
|
|
||||||
|
def test_no_roles_directory(self):
|
||||||
|
# Point to a non-existent directory
|
||||||
|
empty_dir = os.path.join(self.tmpdir.name, 'no_roles_here')
|
||||||
|
result = get_all_application_ids(empty_dir)
|
||||||
|
self.assertEqual(result, [])
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
63
tests/unit/filter_plugins/test_get_application_id.py
Normal file
63
tests/unit/filter_plugins/test_get_application_id.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
# tests/unit/filter_plugins/test_get_application_id.py
|
||||||
|
import unittest
|
||||||
|
import os
|
||||||
|
import tempfile
|
||||||
|
import shutil
|
||||||
|
import yaml
|
||||||
|
from ansible.errors import AnsibleFilterError
|
||||||
|
from filter_plugins.get_application_id import get_application_id
|
||||||
|
|
||||||
|
class TestGetApplicationIdFilter(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
# Create a temporary project directory and switch to it
|
||||||
|
self.tmpdir = tempfile.mkdtemp()
|
||||||
|
self.original_cwd = os.getcwd()
|
||||||
|
os.chdir(self.tmpdir)
|
||||||
|
|
||||||
|
# Create the roles/testrole/vars directory structure
|
||||||
|
self.role_name = 'testrole'
|
||||||
|
self.vars_dir = os.path.join('roles', self.role_name, 'vars')
|
||||||
|
os.makedirs(self.vars_dir)
|
||||||
|
self.vars_file = os.path.join(self.vars_dir, 'main.yml')
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
# Return to original cwd and remove temp directory
|
||||||
|
os.chdir(self.original_cwd)
|
||||||
|
shutil.rmtree(self.tmpdir)
|
||||||
|
|
||||||
|
def write_vars_file(self, content):
|
||||||
|
with open(self.vars_file, 'w') as f:
|
||||||
|
yaml.dump(content, f)
|
||||||
|
|
||||||
|
def test_returns_application_id(self):
|
||||||
|
# Given a valid vars file with application_id
|
||||||
|
expected_id = '12345'
|
||||||
|
self.write_vars_file({'application_id': expected_id})
|
||||||
|
# When
|
||||||
|
result = get_application_id(self.role_name)
|
||||||
|
# Then
|
||||||
|
self.assertEqual(result, expected_id)
|
||||||
|
|
||||||
|
def test_file_not_found_raises_error(self):
|
||||||
|
# Given no vars file for a nonexistent role
|
||||||
|
with self.assertRaises(AnsibleFilterError) as cm:
|
||||||
|
get_application_id('nonexistent_role')
|
||||||
|
self.assertIn("Vars file not found", str(cm.exception))
|
||||||
|
|
||||||
|
def test_missing_key_raises_error(self):
|
||||||
|
# Given a vars file without application_id
|
||||||
|
self.write_vars_file({'other_key': 'value'})
|
||||||
|
with self.assertRaises(AnsibleFilterError) as cm:
|
||||||
|
get_application_id(self.role_name)
|
||||||
|
self.assertIn("Key 'application_id' not found", str(cm.exception))
|
||||||
|
|
||||||
|
def test_invalid_yaml_raises_error(self):
|
||||||
|
# Write invalid YAML content
|
||||||
|
with open(self.vars_file, 'w') as f:
|
||||||
|
f.write(":::not a yaml:::")
|
||||||
|
with self.assertRaises(AnsibleFilterError) as cm:
|
||||||
|
get_application_id(self.role_name)
|
||||||
|
self.assertIn("Error reading YAML", str(cm.exception))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
@ -5,7 +5,7 @@ import unittest
|
|||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from ansible.errors import AnsibleFilterError
|
from ansible.errors import AnsibleFilterError
|
||||||
from filter_plugins.get_role_folder import get_role_folder
|
from filter_plugins.get_role import get_role
|
||||||
|
|
||||||
class TestGetRoleFolder(unittest.TestCase):
|
class TestGetRoleFolder(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -35,20 +35,20 @@ class TestGetRoleFolder(unittest.TestCase):
|
|||||||
|
|
||||||
def test_find_existing_role(self):
|
def test_find_existing_role(self):
|
||||||
# Should find role1 for application_id 'app-123'
|
# Should find role1 for application_id 'app-123'
|
||||||
result = get_role_folder('app-123', roles_path=self.roles_dir)
|
result = get_role('app-123', roles_path=self.roles_dir)
|
||||||
self.assertEqual(result, 'role1')
|
self.assertEqual(result, 'role1')
|
||||||
|
|
||||||
def test_no_match_raises(self):
|
def test_no_match_raises(self):
|
||||||
# No role has application_id 'nonexistent'
|
# No role has application_id 'nonexistent'
|
||||||
with self.assertRaises(AnsibleFilterError) as cm:
|
with self.assertRaises(AnsibleFilterError) as cm:
|
||||||
get_role_folder('nonexistent', roles_path=self.roles_dir)
|
get_role('nonexistent', roles_path=self.roles_dir)
|
||||||
self.assertIn("No role found with application_id 'nonexistent'", str(cm.exception))
|
self.assertIn("No role found with application_id 'nonexistent'", str(cm.exception))
|
||||||
|
|
||||||
def test_missing_roles_path(self):
|
def test_missing_roles_path(self):
|
||||||
# Path does not exist
|
# Path does not exist
|
||||||
invalid_path = os.path.join(self.tempdir, 'invalid')
|
invalid_path = os.path.join(self.tempdir, 'invalid')
|
||||||
with self.assertRaises(AnsibleFilterError) as cm:
|
with self.assertRaises(AnsibleFilterError) as cm:
|
||||||
get_role_folder('any', roles_path=invalid_path)
|
get_role('any', roles_path=invalid_path)
|
||||||
self.assertIn(f"Roles path not found: {invalid_path}", str(cm.exception))
|
self.assertIn(f"Roles path not found: {invalid_path}", str(cm.exception))
|
||||||
|
|
||||||
def test_invalid_yaml_raises(self):
|
def test_invalid_yaml_raises(self):
|
||||||
@ -59,7 +59,7 @@ class TestGetRoleFolder(unittest.TestCase):
|
|||||||
f.write("::: invalid yaml :::")
|
f.write("::: invalid yaml :::")
|
||||||
|
|
||||||
with self.assertRaises(AnsibleFilterError) as cm:
|
with self.assertRaises(AnsibleFilterError) as cm:
|
||||||
get_role_folder('app-123', roles_path=self.roles_dir)
|
get_role('app-123', roles_path=self.roles_dir)
|
||||||
self.assertIn('Failed to load', str(cm.exception))
|
self.assertIn('Failed to load', str(cm.exception))
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# tests/unit/lookup_plugins/test_docker_cards.py
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
@ -9,14 +11,22 @@ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../../../roles/web-a
|
|||||||
|
|
||||||
from docker_cards import LookupModule
|
from docker_cards import LookupModule
|
||||||
|
|
||||||
|
|
||||||
class TestDockerCardsLookup(unittest.TestCase):
|
class TestDockerCardsLookup(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
# Create a temporary directory to simulate the roles directory.
|
# Create a temporary directory to simulate the roles directory.
|
||||||
self.test_roles_dir = tempfile.mkdtemp(prefix="test_roles_")
|
self.test_roles_dir = tempfile.mkdtemp(prefix="test_roles_")
|
||||||
# Create a sample role "web-app-port-ui".
|
|
||||||
|
# Create a sample role "web-app-port-ui" under that directory.
|
||||||
self.role_name = "web-app-port-ui"
|
self.role_name = "web-app-port-ui"
|
||||||
self.role_dir = os.path.join(self.test_roles_dir, self.role_name)
|
self.role_dir = os.path.join(self.test_roles_dir, self.role_name)
|
||||||
os.makedirs(os.path.join(self.role_dir, "meta"))
|
os.makedirs(os.path.join(self.role_dir, "meta"))
|
||||||
|
os.makedirs(os.path.join(self.role_dir, "vars"))
|
||||||
|
|
||||||
|
# Create vars/main.yml so get_application_id() can find the application_id.
|
||||||
|
vars_main = os.path.join(self.role_dir, "vars", "main.yml")
|
||||||
|
with open(vars_main, "w", encoding="utf-8") as f:
|
||||||
|
f.write("application_id: portfolio\n")
|
||||||
|
|
||||||
# Create a sample README.md with a H1 line for the title.
|
# Create a sample README.md with a H1 line for the title.
|
||||||
readme_path = os.path.join(self.role_dir, "README.md")
|
readme_path = os.path.join(self.role_dir, "README.md")
|
||||||
@ -54,11 +64,11 @@ galaxy_info:
|
|||||||
"group_names": ["portfolio"]
|
"group_names": ["portfolio"]
|
||||||
}
|
}
|
||||||
result = lookup_module.run([self.test_roles_dir], variables=fake_variables)
|
result = lookup_module.run([self.test_roles_dir], variables=fake_variables)
|
||||||
|
|
||||||
# The result is a list containing one list of card dictionaries.
|
# The result is a list containing one list of card dictionaries.
|
||||||
self.assertIsInstance(result, list)
|
self.assertIsInstance(result, list)
|
||||||
self.assertEqual(len(result), 1)
|
self.assertEqual(len(result), 1)
|
||||||
|
|
||||||
cards = result[0]
|
cards = result[0]
|
||||||
self.assertIsInstance(cards, list)
|
self.assertIsInstance(cards, list)
|
||||||
# Since "portfolio" is in group_names, one card should be present.
|
# Since "portfolio" is in group_names, one card should be present.
|
||||||
@ -80,21 +90,22 @@ galaxy_info:
|
|||||||
"applications": {
|
"applications": {
|
||||||
"portfolio": {
|
"portfolio": {
|
||||||
"features": {
|
"features": {
|
||||||
"iframe": True
|
"portfolio_iframe": True
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"group_names": [] # Not including "portfolio"
|
"group_names": [] # Not including "portfolio"
|
||||||
}
|
}
|
||||||
result = lookup_module.run([self.test_roles_dir], variables=fake_variables)
|
result = lookup_module.run([self.test_roles_dir], variables=fake_variables)
|
||||||
|
|
||||||
# Since the application_id is not in group_names, no card should be added.
|
# Since the application_id is not in group_names, no card should be added.
|
||||||
self.assertIsInstance(result, list)
|
self.assertIsInstance(result, list)
|
||||||
self.assertEqual(len(result), 1)
|
self.assertEqual(len(result), 1)
|
||||||
|
|
||||||
cards = result[0]
|
cards = result[0]
|
||||||
self.assertIsInstance(cards, list)
|
self.assertIsInstance(cards, list)
|
||||||
self.assertEqual(len(cards), 0)
|
self.assertEqual(len(cards), 0)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user