#!/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()