#!/usr/bin/env python3 """ Script for generating Wiki page with Kubernetes services from k8s/ directory """ import os import yaml import json import sys from datetime import datetime from collections import defaultdict class K8sService: def __init__(self, name, category, path): self.name = name self.category = category self.path = path self.namespace = None self.deployment_type = "Unknown" self.helm_charts = [] self.services = [] self.ingresses = [] self.external_secrets = [] self.deployments = [] self.pvcs = [] self.argo_app = None self.files = [] def __repr__(self): return f"K8sService({self.name}, {self.deployment_type})" def parse_yaml_file(filepath): """Parse YAML file and return content""" try: with open(filepath, 'r') as f: # Load all documents in the file docs = list(yaml.safe_load_all(f)) return docs if len(docs) > 1 else docs[0] if docs else None except Exception as e: print(f" āš ļø Error parsing {filepath}: {e}") return None def analyze_service_directory(service_path, service_name, category): """Analyze a service directory and extract information""" service = K8sService(service_name, category, service_path) # List all files for file in os.listdir(service_path): if file.endswith('.yaml') or file.endswith('.yml'): service.files.append(file) filepath = os.path.join(service_path, file) # Parse YAML content content = parse_yaml_file(filepath) if not content: continue # Handle multiple documents in one file documents = content if isinstance(content, list) else [content] for doc in documents: if not isinstance(doc, dict) or 'kind' not in doc: continue kind = doc['kind'] metadata = doc.get('metadata', {}) # ArgoCD Application if kind == 'Application' and doc.get('apiVersion', '').startswith('argoproj.io'): service.argo_app = { 'name': metadata.get('name', ''), 'namespace': doc.get('spec', {}).get('destination', {}).get('namespace', ''), 'project': doc.get('spec', {}).get('project', ''), 'auto_sync': doc.get('spec', {}).get('syncPolicy', {}).get('automated') is not None } service.namespace = service.argo_app['namespace'] # Kustomization elif kind == 'Kustomization': if 'helmCharts' in doc: service.deployment_type = "Helm Chart" for chart in doc.get('helmCharts', []): service.helm_charts.append({ 'name': chart.get('name', ''), 'repo': chart.get('repo', ''), 'version': chart.get('version', ''), 'namespace': chart.get('namespace', service.namespace) }) else: service.deployment_type = "Kustomize" # Deployment elif kind == 'Deployment': service.deployments.append({ 'name': metadata.get('name', ''), 'namespace': metadata.get('namespace', service.namespace), 'replicas': doc.get('spec', {}).get('replicas', 1), 'containers': [c.get('name', '') for c in doc.get('spec', {}).get('template', {}).get('spec', {}).get('containers', [])] }) if service.deployment_type == "Unknown": service.deployment_type = "YAML Manifests" # Service elif kind == 'Service': svc_spec = doc.get('spec', {}) service.services.append({ 'name': metadata.get('name', ''), 'type': svc_spec.get('type', 'ClusterIP'), 'ports': svc_spec.get('ports', []) }) # Ingress elif kind == 'Ingress': rules = doc.get('spec', {}).get('rules', []) hosts = [] for rule in rules: if 'host' in rule: hosts.append(rule['host']) service.ingresses.append({ 'name': metadata.get('name', ''), 'hosts': hosts }) # ExternalSecret elif kind == 'ExternalSecret': service.external_secrets.append({ 'name': metadata.get('name', ''), 'store': doc.get('spec', {}).get('secretStoreRef', {}).get('name', '') }) # PersistentVolumeClaim elif kind == 'PersistentVolumeClaim': service.pvcs.append({ 'name': metadata.get('name', ''), 'size': doc.get('spec', {}).get('resources', {}).get('requests', {}).get('storage', '') }) # If no specific deployment type found but has YAML files if service.deployment_type == "Unknown" and service.files: service.deployment_type = "YAML Manifests" return service def generate_markdown_table(services): """Generate markdown table for services""" markdown = [] markdown.append("# Kubernetes Services") markdown.append("") markdown.append(f"*Automatically generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S UTC')}*") markdown.append("") # Group by category categories = defaultdict(list) for service in services: categories[service.category].append(service) # Statistics markdown.append("## Statistics") markdown.append("") markdown.append(f"- **Total Services**: {len(services)}") markdown.append(f"- **Categories**: {len(categories)}") helm_count = sum(1 for s in services if s.deployment_type == "Helm Chart") kustomize_count = sum(1 for s in services if s.deployment_type == "Kustomize") yaml_count = sum(1 for s in services if s.deployment_type == "YAML Manifests") markdown.append(f"- **Helm Charts**: {helm_count}") markdown.append(f"- **Kustomize**: {kustomize_count}") markdown.append(f"- **YAML Manifests**: {yaml_count}") markdown.append("") # Main table markdown.append("## All Services") markdown.append("") markdown.append("| Service | Category | Type | Namespace | Ingresses | Services | Secrets | Auto-Sync |") markdown.append("|---------|----------|------|-----------|-----------|----------|---------|-----------|") for category in sorted(categories.keys()): for service in sorted(categories[category], key=lambda x: x.name): # Service name with link to directory name_link = f"[{service.name}](k8s/{service.category}/{service.name}/)" # Deployment type with emoji type_emoji = { "Helm Chart": "šŸŽ©", "Kustomize": "šŸ”§", "YAML Manifests": "šŸ“„", "Unknown": "ā“" } type_str = f"{type_emoji.get(service.deployment_type, '')} {service.deployment_type}" # Ingresses ingresses = [] for ing in service.ingresses: for host in ing['hosts']: ingresses.append(f"[{host}](https://{host})") ingress_str = "
".join(ingresses) if ingresses else "-" # Services svc_list = [] for svc in service.services: ports = [f"{p.get('port', '?')}" for p in svc['ports']] svc_list.append(f"`{svc['name']}:{','.join(ports)}`") svc_str = "
".join(svc_list) if svc_list else "-" # External Secrets secrets_str = f"{len(service.external_secrets)} secrets" if service.external_secrets else "-" # Auto-sync auto_sync = "āœ…" if service.argo_app and service.argo_app.get('auto_sync') else "āŒ" markdown.append(f"| **{name_link}** | {category} | {type_str} | {service.namespace or '-'} | {ingress_str} | {svc_str} | {secrets_str} | {auto_sync} |") markdown.append("") # Detailed sections by category for category in sorted(categories.keys()): markdown.append(f"## {category.title()} Services") markdown.append("") for service in sorted(categories[category], key=lambda x: x.name): markdown.append(f"### {service.name}") markdown.append("") # Basic info markdown.append(f"- **Type**: {service.deployment_type}") markdown.append(f"- **Namespace**: {service.namespace or 'Not specified'}") markdown.append(f"- **Path**: `{service.path}`") # Helm charts if service.helm_charts: markdown.append("- **Helm Charts**:") for chart in service.helm_charts: markdown.append(f" - {chart['name']} v{chart['version']} from {chart['repo']}") # Deployments if service.deployments: markdown.append("- **Deployments**:") for dep in service.deployments: containers = ', '.join(dep['containers']) markdown.append(f" - {dep['name']} ({dep['replicas']} replicas) - Containers: {containers}") # Files if service.files: markdown.append(f"- **Files**: {', '.join(sorted(service.files))}") markdown.append("") markdown.append("---") markdown.append("*This page is automatically generated from k8s/ directory via CI/CD*") return "\n".join(markdown) def main(): if len(sys.argv) < 2: print("Usage: generate-k8s-wiki.py [output-file]") sys.exit(1) k8s_dir = sys.argv[1] output_file = sys.argv[2] if len(sys.argv) > 2 else "Kubernetes-Services.md" if not os.path.exists(k8s_dir): print(f"āŒ Directory {k8s_dir} not found") sys.exit(1) print(f"šŸ“‚ Scanning {k8s_dir}...") services = [] # Scan each category directory for category in ['apps', 'core', 'games']: category_path = os.path.join(k8s_dir, category) if not os.path.exists(category_path): print(f" āš ļø Category {category} not found") continue print(f"šŸ“ Processing {category}/...") # Scan each service in category for service_name in os.listdir(category_path): service_path = os.path.join(category_path, service_name) if os.path.isdir(service_path): print(f" šŸ” Analyzing {service_name}...") service = analyze_service_directory(service_path, service_name, category) services.append(service) print(f"\nāœ… Found {len(services)} services") # Generate markdown markdown = generate_markdown_table(services) # Write output with open(output_file, 'w', encoding='utf-8') as f: f.write(markdown) print(f"šŸ“„ Wiki page generated: {output_file}") print(f"šŸ“Š Total services: {len(services)}") if __name__ == "__main__": main()