#!/usr/bin/env python3 import base64 import json import sys import urllib.error import urllib.request from pathlib import Path BASE_URL = "http://127.0.0.1:3000" DASHBOARD_UID = "ucepsa-edge-oee-machine" def read_env(path=".env"): env = {} p = Path(path) if not p.exists(): return env for raw in p.read_text().splitlines(): line = raw.strip() if not line or line.startswith("#") or "=" not in line: continue key, value = line.split("=", 1) env[key.strip()] = value.strip().strip('"').strip("'") return env env = read_env() user = env.get("GRAFANA_ADMIN_USER", "admin") password = env.get("GRAFANA_ADMIN_PASSWORD") if not password: print("ERROR: no encuentro GRAFANA_ADMIN_PASSWORD en .env", file=sys.stderr) sys.exit(1) token = base64.b64encode(f"{user}:{password}".encode()).decode() def api(method, path, payload=None): data = None headers = { "Authorization": f"Basic {token}", "Content-Type": "application/json", "Accept": "application/json", } if payload is not None: data = json.dumps(payload).encode("utf-8") req = urllib.request.Request( BASE_URL + path, data=data, headers=headers, method=method, ) try: with urllib.request.urlopen(req, timeout=30) as resp: body = resp.read().decode("utf-8") return json.loads(body) if body else {} except urllib.error.HTTPError as e: print("HTTP ERROR:", e.code, e.read().decode("utf-8"), file=sys.stderr) raise def walk_panels(panels): for p in panels or []: yield p for child in walk_panels(p.get("panels", [])): yield child doc = api("GET", f"/api/dashboards/uid/{DASHBOARD_UID}") dashboard = doc["dashboard"] meta = doc.get("meta", {}) changed = 0 for panel in walk_panels(dashboard.get("panels", [])): if panel.get("title") in ("Pareto causas de paro", "Pareto causas clasificadas"): panel["title"] = "Pareto causas clasificadas por minutos" for target in panel.get("targets", []): target["rawSql"] = """ SELECT cause_name AS "Causa", ROUND(SUM(duration_min)::numeric, 2) AS "Minutos" FROM mv_reports_ucepsa_demo.machine_stops_grafana WHERE machine_id = '$machine_id' AND classification_status = 'CLASSIFIED' AND status = 'CLOSED' GROUP BY cause_name ORDER BY SUM(duration_min) DESC LIMIT 10 """ target["format"] = "table" panel.setdefault("fieldConfig", {}).setdefault("defaults", {})["unit"] = "min" changed += 1 payload = { "dashboard": dashboard, "overwrite": True, "message": "Clean stop cause pareto panel", } if meta.get("folderUid"): payload["folderUid"] = meta["folderUid"] result = api("POST", "/api/dashboards/db", payload) print(f"Paneles modificados: {changed}") print("Dashboard actualizado:") print(BASE_URL + result.get("url", f"/d/{DASHBOARD_UID}"))