monitor/views.py aktualisiert
Some checks failed
cloudmon GitOps Deploy / build-and-deploy (push) Failing after 23s

This commit is contained in:
bast 2026-11-02 17:05:54 +00:00
parent 29a15c61ba
commit 9e97423ba4

View file

@ -1,38 +1,39 @@
import json import json
import logging import base64
import requests
from django.http import JsonResponse from django.http import JsonResponse
from django.views.generic import TemplateView, View from django.views.generic import TemplateView, View
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
logger = logging.getLogger(__name__)
# Globaler In-Memory Speicher
CLUSTER_STATES = {}
class DashboardView(TemplateView): class DashboardView(TemplateView):
template_name = "monitor/dashboard.html" template_name = "monitor/dashboard.html"
@method_decorator(csrf_exempt, name='dispatch') class ClusterGraphDataView(View):
class StatePushReceiverView(View): """
def post(self, request, *args, **kwargs): Die offizielle cloudmon Enterprise-Schnittstelle:
token = request.headers.get("Authorization") Liest den Zustand direkt und live aus dem zentralen HashiCorp Consul KV-Store.
if token != "Bearer boday-cloudmon-super-token-2026": """
return JsonResponse({"error": "Unauthorized"}, status=401) def get(self, request, *args, **kwargs):
repo_name = request.GET.get("repo", "boday_tf")
# Consul HTTP-API Endpunkt abfragen (Interner Container-Name im Docker-Netz)
consul_url = f"http://consul:8500/v1/kv/terraform/states/{repo_name}"
try: try:
tf_data = json.loads(request.body.decode('utf-8')) response = requests.get(consul_url, timeout=5)
repo_name = request.GET.get("repo", "boday_tf") if response.status_code == 404:
return JsonResponse({"name": f"Keine Daten in Consul für '{repo_name}' gefunden.", "type": "Root", "children": []})
# KOMBI-PARSER: Erkennt automatisch, ob ein Plan-JSON oder ein State-JSON gepusht wurde consul_json = response.json()
resources = [] # Consul liefert eine Liste zurück, der Value ist Base64 codiert
if "values" in tf_data and "root_module" in tf_data["values"]: raw_value = consul_json[0].get("Value")
# Format aus 'terraform show -json' (Plan) if not raw_value:
resources = tf_data["values"]["root_module"].get("resources", []) return JsonResponse({"error": "Consul Key ist leer"}, status=400)
elif "resources" in tf_data:
# Format aus dem rohen '.tfstate' (State)
resources = tf_data.get("resources", [])
# Base64 decodieren, um an das echte Terraform-State-JSON zu kommen
state_json = json.loads(base64.b64decode(raw_value).decode('utf-8'))
# --- AB HIER GREIFT DEIN BEWÄHRTER KOMBI-PARSER ---
resources = state_json.get("resources", [])
ingresses = [] ingresses = []
services = {} services = {}
deployments = {} deployments = {}
@ -40,36 +41,24 @@ class StatePushReceiverView(View):
for res in resources: for res in resources:
res_type = res.get("type") res_type = res.get("type")
res_name = res.get("name") res_name = res.get("name")
# Attribut-Extraktion je nach JSON-Typ flexibel auflösen
instances = res.get("instances", []) instances = res.get("instances", [])
if isinstance(instances, list) and len(instances) > 0: if not instances or not isinstance(instances, list): continue
attributes = instances[0].get("attributes", {}) attributes = instances[0].get("attributes", {})
else:
attributes = res.get("values", {})
if not attributes:
continue
# JSON-Struktur-Normalisierung für Kubernetes-Metadaten
metadata = attributes.get("metadata", [{}]) metadata = attributes.get("metadata", [{}])
actual_name = metadata[0].get("name", res_name) if isinstance(metadata, list) else metadata.get("name", res_name) actual_name = metadata[0].get("name", res_name) if isinstance(metadata, list) else metadata.get("name", res_name)
if res_type == "kubernetes_ingress_v1" or res_type == "kubernetes_ingress": if res_type in ["kubernetes_ingress_v1", "kubernetes_ingress"]:
spec = attributes.get("spec", [{}]) spec = attributes.get("spec", [{}])
rules = spec[0].get("rule", []) if isinstance(spec, list) else spec.get("rule", []) rules = spec[0].get("rule", []) if isinstance(spec, list) else spec.get("rule", [])
ingresses.append({ ingresses.append({"name": actual_name, "rules": rules})
"name": actual_name,
"rules": rules
})
elif res_type in ["kubernetes_service", "kubernetes_service_v1"]: elif res_type in ["kubernetes_service", "kubernetes_service_v1"]:
services[actual_name] = {"name": actual_name, "type": "Service"} services[actual_name] = {"name": actual_name, "type": "Service"}
elif res_type in ["kubernetes_deployment", "kubernetes_deployment_v1"]: elif res_type in ["kubernetes_deployment", "kubernetes_deployment_v1"]:
deployments[actual_name] = {"name": actual_name, "type": "Deployment"} deployments[actual_name] = {"name": actual_name, "type": "Deployment"}
# D3.js Baumhierarchie aufbauen
root_node = { root_node = {
"name": f"Repository: {repo_name}", "name": f"Consul Storage: {repo_name}",
"type": "Root", "type": "Root",
"children": [] "children": []
} }
@ -92,20 +81,7 @@ class StatePushReceiverView(View):
ing_node["children"].append(svc_node) ing_node["children"].append(svc_node)
root_node["children"].append(ing_node) root_node["children"].append(ing_node)
CLUSTER_STATES[repo_name] = root_node return JsonResponse(root_node)
return JsonResponse({"status": "success", "message": f"State für {repo_name} erfolgreich verarbeitet!"})
except Exception as e: except Exception as e:
logger.error(f"Push-Verarbeitung fehlgeschlagen: {str(e)}") return JsonResponse({"error": str(e)}, status=500)
return JsonResponse({"error": str(e)}, status=400)
class ClusterGraphDataView(View):
def get(self, request, *args, **kwargs):
# Holt das spezifische Repo aus dem Query-Parameter, Fallback auf boday_tf
repo_name = request.GET.get("repo", "bast/boday_tf")
data = CLUSTER_STATES.get(repo_name, {
"name": f"Warte auf Push für '{repo_name}'...",
"type": "Root",
"children": []
})
return JsonResponse(data)