feat(ucepsa): add Shop Floor context health dashboard
This commit is contained in:
parent
e5cb98e349
commit
dbc45bccd4
@ -0,0 +1,102 @@
|
|||||||
|
# UCEPSA — Dashboard Salud y contexto Shop Floor v0.3.6
|
||||||
|
|
||||||
|
## Decisión de despliegue
|
||||||
|
|
||||||
|
Grafana solo monta:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/srv/mesavault/edge-oee-ucepsa/grafana/data
|
||||||
|
→ /var/lib/grafana
|
||||||
|
```
|
||||||
|
|
||||||
|
Los JSON del repositorio no están provisionados automáticamente. Por eso el
|
||||||
|
dashboard se versiona en Git y se despliega mediante la API local de Grafana.
|
||||||
|
|
||||||
|
No se modifica el dashboard operativo existente.
|
||||||
|
|
||||||
|
## Identidad
|
||||||
|
|
||||||
|
```text
|
||||||
|
Dashboard UID:
|
||||||
|
ucepsa-shopfloor-context-health
|
||||||
|
|
||||||
|
Carpeta UID:
|
||||||
|
ucepsa-mesavault
|
||||||
|
|
||||||
|
Carpeta:
|
||||||
|
MESAVAULT — UCEPSA
|
||||||
|
|
||||||
|
Datasource PostgreSQL:
|
||||||
|
bfnbcasbm6hhca
|
||||||
|
```
|
||||||
|
|
||||||
|
## Paneles
|
||||||
|
|
||||||
|
1. Salud general.
|
||||||
|
2. Salud del sincronizador.
|
||||||
|
3. Segundos desde la última sincronización.
|
||||||
|
4. Sesiones abiertas.
|
||||||
|
5. Incidencias WARNING.
|
||||||
|
6. Incidencias CRITICAL.
|
||||||
|
7. Estado vivo por máquina.
|
||||||
|
8. Incidencias activas.
|
||||||
|
9. Sesiones abiertas.
|
||||||
|
10. Calidad de sesiones.
|
||||||
|
|
||||||
|
## Credenciales
|
||||||
|
|
||||||
|
El script no guarda secretos en Git.
|
||||||
|
|
||||||
|
Prioridad:
|
||||||
|
|
||||||
|
1. `GRAFANA_API_TOKEN`.
|
||||||
|
2. `GRAFANA_USER` + `GRAFANA_PASSWORD`.
|
||||||
|
3. Variables `GF_SECURITY_ADMIN_USER` y `GF_SECURITY_ADMIN_PASSWORD` del
|
||||||
|
contenedor.
|
||||||
|
|
||||||
|
No se muestran contraseñas en la salida.
|
||||||
|
|
||||||
|
## Despliegue
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /srv/mesavault/edge-oee-ucepsa
|
||||||
|
|
||||||
|
/srv/mesavault/40-clients/ucepsa/edge-oee-demo/ops/deploy_shopfloor_context_health_dashboard_v036.sh deploy
|
||||||
|
```
|
||||||
|
|
||||||
|
## Validación
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/srv/mesavault/40-clients/ucepsa/edge-oee-demo/ops/deploy_shopfloor_context_health_dashboard_v036.sh validate
|
||||||
|
```
|
||||||
|
|
||||||
|
Debe devolver:
|
||||||
|
|
||||||
|
```text
|
||||||
|
status = ok
|
||||||
|
dashboard_uid = ucepsa-shopfloor-context-health
|
||||||
|
folder_uid = ucepsa-mesavault
|
||||||
|
panel_count = 10
|
||||||
|
datasource_uids = [bfnbcasbm6hhca]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Exportación posterior
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/srv/mesavault/40-clients/ucepsa/edge-oee-demo/ops/deploy_shopfloor_context_health_dashboard_v036.sh export \
|
||||||
|
> /tmp/ucepsa-shopfloor-context-health.export.json
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rollback
|
||||||
|
|
||||||
|
La importación usa un UID propio y no sobrescribe otros dashboards.
|
||||||
|
|
||||||
|
Para retirarlo, usar la API:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X DELETE \
|
||||||
|
-H "Authorization: Bearer $GRAFANA_API_TOKEN" \
|
||||||
|
http://127.0.0.1:3000/api/dashboards/uid/ucepsa-shopfloor-context-health
|
||||||
|
```
|
||||||
|
|
||||||
|
No se recomienda borrar la carpeta si contiene otros dashboards.
|
||||||
@ -0,0 +1,984 @@
|
|||||||
|
{
|
||||||
|
"annotations": {
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"builtIn": 1,
|
||||||
|
"datasource": {
|
||||||
|
"type": "grafana",
|
||||||
|
"uid": "-- Grafana --"
|
||||||
|
},
|
||||||
|
"enable": true,
|
||||||
|
"hide": true,
|
||||||
|
"iconColor": "rgba(0, 211, 255, 1)",
|
||||||
|
"name": "Annotations & Alerts",
|
||||||
|
"type": "dashboard"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"description": "Supervisión SHADOW de máquina física, orden Odoo, sesión Shop Floor, sincronizador y calidad temporal. No alimenta el Ledger oficial.",
|
||||||
|
"editable": true,
|
||||||
|
"fiscalYearStartMonth": 0,
|
||||||
|
"graphTooltip": 1,
|
||||||
|
"id": null,
|
||||||
|
"links": [],
|
||||||
|
"liveNow": false,
|
||||||
|
"panels": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "postgres",
|
||||||
|
"uid": "bfnbcasbm6hhca"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "thresholds"
|
||||||
|
},
|
||||||
|
"mappings": [
|
||||||
|
{
|
||||||
|
"options": {
|
||||||
|
"HEALTHY": {
|
||||||
|
"color": "green",
|
||||||
|
"index": 0,
|
||||||
|
"text": "HEALTHY"
|
||||||
|
},
|
||||||
|
"WARNING": {
|
||||||
|
"color": "orange",
|
||||||
|
"index": 1,
|
||||||
|
"text": "WARNING"
|
||||||
|
},
|
||||||
|
"CRITICAL": {
|
||||||
|
"color": "red",
|
||||||
|
"index": 2,
|
||||||
|
"text": "CRITICAL"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "value"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "short"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 4,
|
||||||
|
"w": 4,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"id": 1,
|
||||||
|
"options": {
|
||||||
|
"colorMode": "background",
|
||||||
|
"graphMode": "none",
|
||||||
|
"justifyMode": "auto",
|
||||||
|
"orientation": "auto",
|
||||||
|
"percentChangeColorMode": "standard",
|
||||||
|
"reduceOptions": {
|
||||||
|
"calcs": [
|
||||||
|
"lastNotNull"
|
||||||
|
],
|
||||||
|
"fields": "",
|
||||||
|
"values": false
|
||||||
|
},
|
||||||
|
"showPercentChange": false,
|
||||||
|
"textMode": "auto",
|
||||||
|
"wideLayout": true
|
||||||
|
},
|
||||||
|
"pluginVersion": "11.0.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "postgres",
|
||||||
|
"uid": "bfnbcasbm6hhca"
|
||||||
|
},
|
||||||
|
"editorMode": "code",
|
||||||
|
"format": "table",
|
||||||
|
"rawQuery": true,
|
||||||
|
"rawSql": "SELECT overall_health_status AS \"Estado\"\n FROM mv_reports_ucepsa_prod.li_shopfloor_context_health_summary_v1",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Salud general",
|
||||||
|
"type": "stat"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "postgres",
|
||||||
|
"uid": "bfnbcasbm6hhca"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "thresholds"
|
||||||
|
},
|
||||||
|
"mappings": [
|
||||||
|
{
|
||||||
|
"options": {
|
||||||
|
"HEALTHY": {
|
||||||
|
"color": "green",
|
||||||
|
"index": 0,
|
||||||
|
"text": "HEALTHY"
|
||||||
|
},
|
||||||
|
"DELAYED": {
|
||||||
|
"color": "orange",
|
||||||
|
"index": 1,
|
||||||
|
"text": "DELAYED"
|
||||||
|
},
|
||||||
|
"STALE": {
|
||||||
|
"color": "red",
|
||||||
|
"index": 2,
|
||||||
|
"text": "STALE"
|
||||||
|
},
|
||||||
|
"ERROR": {
|
||||||
|
"color": "red",
|
||||||
|
"index": 3,
|
||||||
|
"text": "ERROR"
|
||||||
|
},
|
||||||
|
"NOT_INITIALIZED": {
|
||||||
|
"color": "red",
|
||||||
|
"index": 4,
|
||||||
|
"text": "NOT INITIALIZED"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "value"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "short"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 4,
|
||||||
|
"w": 4,
|
||||||
|
"x": 4,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"id": 2,
|
||||||
|
"options": {
|
||||||
|
"colorMode": "background",
|
||||||
|
"graphMode": "none",
|
||||||
|
"justifyMode": "auto",
|
||||||
|
"orientation": "auto",
|
||||||
|
"percentChangeColorMode": "standard",
|
||||||
|
"reduceOptions": {
|
||||||
|
"calcs": [
|
||||||
|
"lastNotNull"
|
||||||
|
],
|
||||||
|
"fields": "",
|
||||||
|
"values": false
|
||||||
|
},
|
||||||
|
"showPercentChange": false,
|
||||||
|
"textMode": "auto",
|
||||||
|
"wideLayout": true
|
||||||
|
},
|
||||||
|
"pluginVersion": "11.0.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "postgres",
|
||||||
|
"uid": "bfnbcasbm6hhca"
|
||||||
|
},
|
||||||
|
"editorMode": "code",
|
||||||
|
"format": "table",
|
||||||
|
"rawQuery": true,
|
||||||
|
"rawSql": "SELECT sync_health_status AS \"Estado\"\n FROM mv_reports_ucepsa_prod.li_shopfloor_context_health_summary_v1",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Sincronizador",
|
||||||
|
"type": "stat"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "postgres",
|
||||||
|
"uid": "bfnbcasbm6hhca"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "thresholds"
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "s"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 4,
|
||||||
|
"w": 4,
|
||||||
|
"x": 8,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"id": 3,
|
||||||
|
"options": {
|
||||||
|
"colorMode": "value",
|
||||||
|
"graphMode": "none",
|
||||||
|
"justifyMode": "auto",
|
||||||
|
"orientation": "auto",
|
||||||
|
"percentChangeColorMode": "standard",
|
||||||
|
"reduceOptions": {
|
||||||
|
"calcs": [
|
||||||
|
"lastNotNull"
|
||||||
|
],
|
||||||
|
"fields": "",
|
||||||
|
"values": false
|
||||||
|
},
|
||||||
|
"showPercentChange": false,
|
||||||
|
"textMode": "auto",
|
||||||
|
"wideLayout": true
|
||||||
|
},
|
||||||
|
"pluginVersion": "11.0.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "postgres",
|
||||||
|
"uid": "bfnbcasbm6hhca"
|
||||||
|
},
|
||||||
|
"editorMode": "code",
|
||||||
|
"format": "table",
|
||||||
|
"rawQuery": true,
|
||||||
|
"rawSql": "SELECT seconds_since_sync_success AS \"Segundos\"\n FROM mv_reports_ucepsa_prod.li_shopfloor_context_health_summary_v1",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Segundos desde sync",
|
||||||
|
"type": "stat"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "postgres",
|
||||||
|
"uid": "bfnbcasbm6hhca"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "thresholds"
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "short"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 4,
|
||||||
|
"w": 4,
|
||||||
|
"x": 12,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"id": 4,
|
||||||
|
"options": {
|
||||||
|
"colorMode": "value",
|
||||||
|
"graphMode": "none",
|
||||||
|
"justifyMode": "auto",
|
||||||
|
"orientation": "auto",
|
||||||
|
"percentChangeColorMode": "standard",
|
||||||
|
"reduceOptions": {
|
||||||
|
"calcs": [
|
||||||
|
"lastNotNull"
|
||||||
|
],
|
||||||
|
"fields": "",
|
||||||
|
"values": false
|
||||||
|
},
|
||||||
|
"showPercentChange": false,
|
||||||
|
"textMode": "auto",
|
||||||
|
"wideLayout": true
|
||||||
|
},
|
||||||
|
"pluginVersion": "11.0.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "postgres",
|
||||||
|
"uid": "bfnbcasbm6hhca"
|
||||||
|
},
|
||||||
|
"editorMode": "code",
|
||||||
|
"format": "table",
|
||||||
|
"rawQuery": true,
|
||||||
|
"rawSql": "SELECT open_session_count AS \"Sesiones\"\n FROM mv_reports_ucepsa_prod.li_shopfloor_context_health_summary_v1",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Sesiones abiertas",
|
||||||
|
"type": "stat"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "postgres",
|
||||||
|
"uid": "bfnbcasbm6hhca"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "thresholds"
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "short"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 4,
|
||||||
|
"w": 4,
|
||||||
|
"x": 16,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"id": 5,
|
||||||
|
"options": {
|
||||||
|
"colorMode": "value",
|
||||||
|
"graphMode": "none",
|
||||||
|
"justifyMode": "auto",
|
||||||
|
"orientation": "auto",
|
||||||
|
"percentChangeColorMode": "standard",
|
||||||
|
"reduceOptions": {
|
||||||
|
"calcs": [
|
||||||
|
"lastNotNull"
|
||||||
|
],
|
||||||
|
"fields": "",
|
||||||
|
"values": false
|
||||||
|
},
|
||||||
|
"showPercentChange": false,
|
||||||
|
"textMode": "auto",
|
||||||
|
"wideLayout": true
|
||||||
|
},
|
||||||
|
"pluginVersion": "11.0.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "postgres",
|
||||||
|
"uid": "bfnbcasbm6hhca"
|
||||||
|
},
|
||||||
|
"editorMode": "code",
|
||||||
|
"format": "table",
|
||||||
|
"rawQuery": true,
|
||||||
|
"rawSql": "SELECT warning_incident_count AS \"Incidencias\"\n FROM mv_reports_ucepsa_prod.li_shopfloor_context_health_summary_v1",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Advertencias",
|
||||||
|
"type": "stat"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "postgres",
|
||||||
|
"uid": "bfnbcasbm6hhca"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "thresholds"
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "short"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 4,
|
||||||
|
"w": 4,
|
||||||
|
"x": 20,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"id": 6,
|
||||||
|
"options": {
|
||||||
|
"colorMode": "value",
|
||||||
|
"graphMode": "none",
|
||||||
|
"justifyMode": "auto",
|
||||||
|
"orientation": "auto",
|
||||||
|
"percentChangeColorMode": "standard",
|
||||||
|
"reduceOptions": {
|
||||||
|
"calcs": [
|
||||||
|
"lastNotNull"
|
||||||
|
],
|
||||||
|
"fields": "",
|
||||||
|
"values": false
|
||||||
|
},
|
||||||
|
"showPercentChange": false,
|
||||||
|
"textMode": "auto",
|
||||||
|
"wideLayout": true
|
||||||
|
},
|
||||||
|
"pluginVersion": "11.0.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "postgres",
|
||||||
|
"uid": "bfnbcasbm6hhca"
|
||||||
|
},
|
||||||
|
"editorMode": "code",
|
||||||
|
"format": "table",
|
||||||
|
"rawQuery": true,
|
||||||
|
"rawSql": "SELECT critical_incident_count AS \"Incidencias\"\n FROM mv_reports_ucepsa_prod.li_shopfloor_context_health_summary_v1",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Críticas",
|
||||||
|
"type": "stat"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "postgres",
|
||||||
|
"uid": "bfnbcasbm6hhca"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "thresholds"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"align": "auto",
|
||||||
|
"cellOptions": {
|
||||||
|
"type": "auto"
|
||||||
|
},
|
||||||
|
"filterable": true,
|
||||||
|
"inspect": false
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"matcher": {
|
||||||
|
"id": "byName",
|
||||||
|
"options": "Estado"
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": "custom.width",
|
||||||
|
"value": 260
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matcher": {
|
||||||
|
"id": "byName",
|
||||||
|
"options": "Acción"
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": "custom.width",
|
||||||
|
"value": 420
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matcher": {
|
||||||
|
"id": "byName",
|
||||||
|
"options": "Operario"
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": "custom.width",
|
||||||
|
"value": 220
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matcher": {
|
||||||
|
"id": "byName",
|
||||||
|
"options": "Severidad"
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": "mappings",
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
|
"options": {
|
||||||
|
"OK": {
|
||||||
|
"color": "green",
|
||||||
|
"index": 0,
|
||||||
|
"text": "OK"
|
||||||
|
},
|
||||||
|
"INFO": {
|
||||||
|
"color": "blue",
|
||||||
|
"index": 1,
|
||||||
|
"text": "INFO"
|
||||||
|
},
|
||||||
|
"WARNING": {
|
||||||
|
"color": "orange",
|
||||||
|
"index": 2,
|
||||||
|
"text": "WARNING"
|
||||||
|
},
|
||||||
|
"CRITICAL": {
|
||||||
|
"color": "red",
|
||||||
|
"index": 3,
|
||||||
|
"text": "CRITICAL"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "value"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "custom.cellOptions",
|
||||||
|
"value": {
|
||||||
|
"type": "color-text"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "custom.width",
|
||||||
|
"value": 110
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 9,
|
||||||
|
"w": 24,
|
||||||
|
"x": 0,
|
||||||
|
"y": 4
|
||||||
|
},
|
||||||
|
"id": 7,
|
||||||
|
"options": {
|
||||||
|
"cellHeight": "sm",
|
||||||
|
"footer": {
|
||||||
|
"countRows": false,
|
||||||
|
"fields": "",
|
||||||
|
"reducer": [
|
||||||
|
"sum"
|
||||||
|
],
|
||||||
|
"show": false
|
||||||
|
},
|
||||||
|
"showHeader": true,
|
||||||
|
"sortBy": [
|
||||||
|
{
|
||||||
|
"desc": false,
|
||||||
|
"displayName": "Máquina"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"pluginVersion": "11.0.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "postgres",
|
||||||
|
"uid": "bfnbcasbm6hhca"
|
||||||
|
},
|
||||||
|
"editorMode": "code",
|
||||||
|
"format": "table",
|
||||||
|
"rawQuery": true,
|
||||||
|
"rawSql": "SELECT\n machine_id AS \"Máquina\",\n machine_running AS \"Marcha\",\n telemetry_fresh AS \"Telemetría fresca\",\n COALESCE(published_production_order, '—') AS \"Orden publicada\",\n COALESCE(published_workorder_id, '—') AS \"WO publicado\",\n COALESCE(odoo_workorder_id::text, '—') AS \"WO sesión\",\n COALESCE(operator_name, operator_candidate_name, '—') AS \"Operario\",\n sync_health_status AS \"Sync\",\n live_context_status AS \"Estado\",\n live_severity AS \"Severidad\",\n recommended_action AS \"Acción\"\nFROM mv_reports_ucepsa_prod.li_shopfloor_machine_live_context_v1\nORDER BY machine_id",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Estado vivo por máquina",
|
||||||
|
"type": "table"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "postgres",
|
||||||
|
"uid": "bfnbcasbm6hhca"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"custom": {
|
||||||
|
"align": "auto",
|
||||||
|
"cellOptions": {
|
||||||
|
"type": "auto"
|
||||||
|
},
|
||||||
|
"filterable": true,
|
||||||
|
"inspect": false
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"matcher": {
|
||||||
|
"id": "byName",
|
||||||
|
"options": "Severidad"
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": "mappings",
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
|
"options": {
|
||||||
|
"WARNING": {
|
||||||
|
"color": "orange",
|
||||||
|
"index": 0,
|
||||||
|
"text": "WARNING"
|
||||||
|
},
|
||||||
|
"CRITICAL": {
|
||||||
|
"color": "red",
|
||||||
|
"index": 1,
|
||||||
|
"text": "CRITICAL"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "value"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "custom.cellOptions",
|
||||||
|
"value": {
|
||||||
|
"type": "color-background"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "custom.width",
|
||||||
|
"value": 110
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matcher": {
|
||||||
|
"id": "byName",
|
||||||
|
"options": "Situación"
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": "custom.width",
|
||||||
|
"value": 420
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matcher": {
|
||||||
|
"id": "byName",
|
||||||
|
"options": "Acción"
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": "custom.width",
|
||||||
|
"value": 460
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 10,
|
||||||
|
"w": 24,
|
||||||
|
"x": 0,
|
||||||
|
"y": 13
|
||||||
|
},
|
||||||
|
"id": 8,
|
||||||
|
"options": {
|
||||||
|
"cellHeight": "sm",
|
||||||
|
"footer": {
|
||||||
|
"countRows": false,
|
||||||
|
"fields": "",
|
||||||
|
"reducer": [
|
||||||
|
"sum"
|
||||||
|
],
|
||||||
|
"show": false
|
||||||
|
},
|
||||||
|
"showHeader": true,
|
||||||
|
"sortBy": []
|
||||||
|
},
|
||||||
|
"pluginVersion": "11.0.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "postgres",
|
||||||
|
"uid": "bfnbcasbm6hhca"
|
||||||
|
},
|
||||||
|
"editorMode": "code",
|
||||||
|
"format": "table",
|
||||||
|
"rawQuery": true,
|
||||||
|
"rawSql": "SELECT\n observed_at AS \"Hora\",\n severity AS \"Severidad\",\n COALESCE(machine_id, '—') AS \"Máquina\",\n incident_scope AS \"Ámbito\",\n incident_code AS \"Código\",\n COALESCE(production_order, '—') AS \"Orden\",\n COALESCE(odoo_workorder_id::text, '—') AS \"Workorder\",\n COALESCE(operator_name, '—') AS \"Operario\",\n detail AS \"Situación\",\n recommended_action AS \"Acción\"\nFROM mv_reports_ucepsa_prod.li_shopfloor_context_incidents_v1\nORDER BY\n CASE severity\n WHEN 'CRITICAL' THEN 1\n WHEN 'WARNING' THEN 2\n ELSE 3\n END,\n machine_id NULLS FIRST,\n incident_code",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Incidencias activas",
|
||||||
|
"type": "table"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "postgres",
|
||||||
|
"uid": "bfnbcasbm6hhca"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"custom": {
|
||||||
|
"align": "auto",
|
||||||
|
"cellOptions": {
|
||||||
|
"type": "auto"
|
||||||
|
},
|
||||||
|
"filterable": true,
|
||||||
|
"inspect": false
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"matcher": {
|
||||||
|
"id": "byName",
|
||||||
|
"options": "Minutos abierta"
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": "unit",
|
||||||
|
"value": "m"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matcher": {
|
||||||
|
"id": "byName",
|
||||||
|
"options": "Paro abierto min"
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": "unit",
|
||||||
|
"value": "m"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matcher": {
|
||||||
|
"id": "byName",
|
||||||
|
"options": "Acción"
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": "custom.width",
|
||||||
|
"value": 420
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 9,
|
||||||
|
"w": 24,
|
||||||
|
"x": 0,
|
||||||
|
"y": 23
|
||||||
|
},
|
||||||
|
"id": 9,
|
||||||
|
"options": {
|
||||||
|
"cellHeight": "sm",
|
||||||
|
"footer": {
|
||||||
|
"countRows": false,
|
||||||
|
"fields": "",
|
||||||
|
"reducer": [
|
||||||
|
"sum"
|
||||||
|
],
|
||||||
|
"show": false
|
||||||
|
},
|
||||||
|
"showHeader": true,
|
||||||
|
"sortBy": []
|
||||||
|
},
|
||||||
|
"pluginVersion": "11.0.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "postgres",
|
||||||
|
"uid": "bfnbcasbm6hhca"
|
||||||
|
},
|
||||||
|
"editorMode": "code",
|
||||||
|
"format": "table",
|
||||||
|
"rawQuery": true,
|
||||||
|
"rawSql": "SELECT\n machine_id AS \"Máquina\",\n production_order AS \"Orden\",\n odoo_workorder_id AS \"Workorder\",\n COALESCE(operator_name, operator_candidate_name, '—') AS \"Operario\",\n session_started_at AS \"Inicio\",\n session_age_min AS \"Minutos abierta\",\n machine_running AS \"Marcha\",\n telemetry_fresh AS \"Telemetría fresca\",\n open_stop_duration_min AS \"Paro abierto min\",\n watch_status AS \"Estado\",\n watch_severity AS \"Severidad\",\n recommended_action AS \"Acción\"\nFROM mv_reports_ucepsa_prod.li_shopfloor_open_session_watch_v1\nORDER BY machine_id, session_started_at",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Sesiones abiertas",
|
||||||
|
"type": "table"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "postgres",
|
||||||
|
"uid": "bfnbcasbm6hhca"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"custom": {
|
||||||
|
"align": "auto",
|
||||||
|
"cellOptions": {
|
||||||
|
"type": "auto"
|
||||||
|
},
|
||||||
|
"filterable": true,
|
||||||
|
"inspect": false
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"matcher": {
|
||||||
|
"id": "byName",
|
||||||
|
"options": "DQ"
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": "mappings",
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
|
"options": {
|
||||||
|
"OK": {
|
||||||
|
"color": "green",
|
||||||
|
"index": 0,
|
||||||
|
"text": "OK"
|
||||||
|
},
|
||||||
|
"WARNING": {
|
||||||
|
"color": "orange",
|
||||||
|
"index": 1,
|
||||||
|
"text": "WARNING"
|
||||||
|
},
|
||||||
|
"CRITICAL": {
|
||||||
|
"color": "red",
|
||||||
|
"index": 2,
|
||||||
|
"text": "CRITICAL"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "value"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "custom.cellOptions",
|
||||||
|
"value": {
|
||||||
|
"type": "color-text"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 10,
|
||||||
|
"w": 24,
|
||||||
|
"x": 0,
|
||||||
|
"y": 32
|
||||||
|
},
|
||||||
|
"id": 10,
|
||||||
|
"options": {
|
||||||
|
"cellHeight": "sm",
|
||||||
|
"footer": {
|
||||||
|
"countRows": false,
|
||||||
|
"fields": "",
|
||||||
|
"reducer": [
|
||||||
|
"sum"
|
||||||
|
],
|
||||||
|
"show": false
|
||||||
|
},
|
||||||
|
"showHeader": true,
|
||||||
|
"sortBy": []
|
||||||
|
},
|
||||||
|
"pluginVersion": "11.0.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "postgres",
|
||||||
|
"uid": "bfnbcasbm6hhca"
|
||||||
|
},
|
||||||
|
"editorMode": "code",
|
||||||
|
"format": "table",
|
||||||
|
"rawQuery": true,
|
||||||
|
"rawSql": "SELECT\n machine_id AS \"Máquina\",\n production_order AS \"Orden\",\n odoo_workorder_id AS \"Workorder\",\n session_status AS \"Sesión\",\n workorder_state AS \"Estado Odoo\",\n COALESCE(operator_name, operator_candidate_name, '—') AS \"Operario\",\n operator_confirmation_status AS \"Operario\",\n quantity_confirmation_status AS \"Cantidad\",\n confidence AS \"Confianza\",\n dq_status AS \"DQ\",\n array_to_string(issue_codes, ', ') AS \"Incidencias DQ\",\n started_at AS \"Inicio\",\n ended_at AS \"Fin\"\nFROM mv_reports_ucepsa_prod.li_shopfloor_session_data_quality_v1\nORDER BY\n CASE dq_status\n WHEN 'CRITICAL' THEN 1\n WHEN 'WARNING' THEN 2\n ELSE 3\n END,\n COALESCE(ended_at, started_at) DESC NULLS LAST,\n odoo_workorder_id DESC\nLIMIT 50",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Calidad de sesiones",
|
||||||
|
"type": "table"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"refresh": "5s",
|
||||||
|
"schemaVersion": 42,
|
||||||
|
"tags": [
|
||||||
|
"mesavault",
|
||||||
|
"ucepsa",
|
||||||
|
"shop-floor",
|
||||||
|
"context-health",
|
||||||
|
"shadow"
|
||||||
|
],
|
||||||
|
"templating": {
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"time": {
|
||||||
|
"from": "now-12h",
|
||||||
|
"to": "now"
|
||||||
|
},
|
||||||
|
"timepicker": {},
|
||||||
|
"timezone": "browser",
|
||||||
|
"title": "MESAVAULT — UCEPSA · Salud y contexto Shop Floor",
|
||||||
|
"uid": "ucepsa-shopfloor-context-health",
|
||||||
|
"version": 1,
|
||||||
|
"weekStart": ""
|
||||||
|
}
|
||||||
239
ucepsa/edge-oee-demo/ops/deploy_shopfloor_context_health_dashboard_v036.sh
Executable file
239
ucepsa/edge-oee-demo/ops/deploy_shopfloor_context_health_dashboard_v036.sh
Executable file
@ -0,0 +1,239 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ACTION="${1:-deploy}"
|
||||||
|
|
||||||
|
ROOT="${SHOPFLOOR_DASHBOARD_ROOT:-/srv/mesavault/edge-oee-ucepsa}"
|
||||||
|
REPO_ROOT="${SHOPFLOOR_DASHBOARD_REPO_ROOT:-/srv/mesavault/40-clients/ucepsa/edge-oee-demo}"
|
||||||
|
GRAFANA_CONTAINER="${GRAFANA_CONTAINER:-mv_ucepsa_grafana}"
|
||||||
|
DASHBOARD_FILE="${SHOPFLOOR_DASHBOARD_FILE:-$REPO_ROOT/grafana/dashboards/ucepsa-shopfloor-context-health.dashboard.json}"
|
||||||
|
FOLDER_UID="${SHOPFLOOR_DASHBOARD_FOLDER_UID:-ucepsa-mesavault}"
|
||||||
|
FOLDER_TITLE="${SHOPFLOOR_DASHBOARD_FOLDER_TITLE:-MESAVAULT — UCEPSA}"
|
||||||
|
DASHBOARD_UID="ucepsa-shopfloor-context-health"
|
||||||
|
|
||||||
|
resolve_url() {
|
||||||
|
if [[ -n "${GRAFANA_URL:-}" ]]; then
|
||||||
|
printf '%s' "$GRAFANA_URL"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
local port_line host_port container_ip
|
||||||
|
port_line="$(
|
||||||
|
docker port "$GRAFANA_CONTAINER" 3000/tcp 2>/dev/null \
|
||||||
|
| head -n 1 || true
|
||||||
|
)"
|
||||||
|
|
||||||
|
if [[ -n "$port_line" ]]; then
|
||||||
|
host_port="${port_line##*:}"
|
||||||
|
printf 'http://127.0.0.1:%s' "$host_port"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
container_ip="$(
|
||||||
|
docker inspect "$GRAFANA_CONTAINER" \
|
||||||
|
--format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'
|
||||||
|
)"
|
||||||
|
|
||||||
|
if [[ -z "$container_ip" ]]; then
|
||||||
|
echo "ERROR: no se pudo resolver la URL de Grafana." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf 'http://%s:3000' "$container_ip"
|
||||||
|
}
|
||||||
|
|
||||||
|
read_container_env() {
|
||||||
|
local key="$1"
|
||||||
|
docker inspect "$GRAFANA_CONTAINER" \
|
||||||
|
--format '{{range .Config.Env}}{{println .}}{{end}}' \
|
||||||
|
| sed -n "s/^${key}=//p" \
|
||||||
|
| head -n 1
|
||||||
|
}
|
||||||
|
|
||||||
|
export GRAFANA_URL_RESOLVED
|
||||||
|
GRAFANA_URL_RESOLVED="$(resolve_url)"
|
||||||
|
|
||||||
|
if [[ -z "${GRAFANA_API_TOKEN:-}" ]]; then
|
||||||
|
export GRAFANA_USER_RESOLVED="${GRAFANA_USER:-$(read_container_env GF_SECURITY_ADMIN_USER)}"
|
||||||
|
export GRAFANA_PASSWORD_RESOLVED="${GRAFANA_PASSWORD:-$(read_container_env GF_SECURITY_ADMIN_PASSWORD)}"
|
||||||
|
|
||||||
|
if [[ -z "$GRAFANA_USER_RESOLVED" ]]; then
|
||||||
|
GRAFANA_USER_RESOLVED="admin"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$GRAFANA_PASSWORD_RESOLVED" ]]; then
|
||||||
|
cat >&2 <<'MSG'
|
||||||
|
ERROR: no se encontró una credencial de escritura de Grafana.
|
||||||
|
Defina una de estas opciones sin guardarla en Git:
|
||||||
|
|
||||||
|
export GRAFANA_API_TOKEN='...'
|
||||||
|
|
||||||
|
o:
|
||||||
|
|
||||||
|
export GRAFANA_USER='admin'
|
||||||
|
export GRAFANA_PASSWORD='...'
|
||||||
|
MSG
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
python3 - "$ACTION" "$DASHBOARD_FILE" "$FOLDER_UID" "$FOLDER_TITLE" "$DASHBOARD_UID" <<'PY'
|
||||||
|
import base64
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import urllib.error
|
||||||
|
import urllib.parse
|
||||||
|
import urllib.request
|
||||||
|
|
||||||
|
action, dashboard_file, folder_uid, folder_title, dashboard_uid = sys.argv[1:]
|
||||||
|
base_url = os.environ["GRAFANA_URL_RESOLVED"].rstrip("/")
|
||||||
|
|
||||||
|
token = os.environ.get("GRAFANA_API_TOKEN")
|
||||||
|
user = os.environ.get("GRAFANA_USER_RESOLVED")
|
||||||
|
password = os.environ.get("GRAFANA_PASSWORD_RESOLVED")
|
||||||
|
|
||||||
|
|
||||||
|
def request(method, path, payload=None, allow_404=False):
|
||||||
|
url = base_url + path
|
||||||
|
body = None
|
||||||
|
headers = {"Accept": "application/json"}
|
||||||
|
|
||||||
|
if payload is not None:
|
||||||
|
body = json.dumps(payload, ensure_ascii=False).encode("utf-8")
|
||||||
|
headers["Content-Type"] = "application/json"
|
||||||
|
|
||||||
|
if token:
|
||||||
|
headers["Authorization"] = f"Bearer {token}"
|
||||||
|
elif user and password:
|
||||||
|
raw = f"{user}:{password}".encode("utf-8")
|
||||||
|
headers["Authorization"] = (
|
||||||
|
"Basic " + base64.b64encode(raw).decode("ascii")
|
||||||
|
)
|
||||||
|
|
||||||
|
req = urllib.request.Request(
|
||||||
|
url,
|
||||||
|
data=body,
|
||||||
|
headers=headers,
|
||||||
|
method=method,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with urllib.request.urlopen(req, timeout=15) as response:
|
||||||
|
data = response.read()
|
||||||
|
if not data:
|
||||||
|
return None
|
||||||
|
return json.loads(data.decode("utf-8"))
|
||||||
|
except urllib.error.HTTPError as exc:
|
||||||
|
detail = exc.read().decode("utf-8", errors="replace")
|
||||||
|
if allow_404 and exc.code == 404:
|
||||||
|
return None
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Grafana API {method} {path}: HTTP {exc.code}: {detail}"
|
||||||
|
) from exc
|
||||||
|
|
||||||
|
|
||||||
|
health = request("GET", "/api/health")
|
||||||
|
if not health or health.get("database") != "ok":
|
||||||
|
raise RuntimeError(f"Grafana no está saludable: {health!r}")
|
||||||
|
|
||||||
|
if action in {"deploy", "validate"}:
|
||||||
|
folder = request(
|
||||||
|
"GET",
|
||||||
|
f"/api/folders/{urllib.parse.quote(folder_uid)}",
|
||||||
|
allow_404=True,
|
||||||
|
)
|
||||||
|
if folder is None and action == "deploy":
|
||||||
|
folder = request(
|
||||||
|
"POST",
|
||||||
|
"/api/folders",
|
||||||
|
{"uid": folder_uid, "title": folder_title},
|
||||||
|
)
|
||||||
|
|
||||||
|
if action == "deploy":
|
||||||
|
with open(dashboard_file, encoding="utf-8") as handle:
|
||||||
|
dashboard = json.load(handle)
|
||||||
|
|
||||||
|
result = request(
|
||||||
|
"POST",
|
||||||
|
"/api/dashboards/db",
|
||||||
|
{
|
||||||
|
"dashboard": dashboard,
|
||||||
|
"folderUid": folder_uid,
|
||||||
|
"overwrite": True,
|
||||||
|
"message": "Deploy reproducible MESAVAULT Shop Floor Context Health v0.3.6",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
print(json.dumps(
|
||||||
|
{
|
||||||
|
"status": "deployed",
|
||||||
|
"grafana_url": base_url,
|
||||||
|
"folder_uid": folder_uid,
|
||||||
|
"dashboard_uid": dashboard_uid,
|
||||||
|
"response": result,
|
||||||
|
},
|
||||||
|
ensure_ascii=False,
|
||||||
|
indent=2,
|
||||||
|
))
|
||||||
|
|
||||||
|
elif action == "validate":
|
||||||
|
result = request(
|
||||||
|
"GET",
|
||||||
|
f"/api/dashboards/uid/{urllib.parse.quote(dashboard_uid)}",
|
||||||
|
)
|
||||||
|
dashboard = result["dashboard"]
|
||||||
|
datasource_uids = sorted({
|
||||||
|
panel.get("datasource", {}).get("uid")
|
||||||
|
for panel in dashboard.get("panels", [])
|
||||||
|
if isinstance(panel.get("datasource"), dict)
|
||||||
|
and panel.get("datasource", {}).get("uid")
|
||||||
|
})
|
||||||
|
|
||||||
|
expected_datasource = "bfnbcasbm6hhca"
|
||||||
|
errors = []
|
||||||
|
|
||||||
|
if dashboard.get("uid") != dashboard_uid:
|
||||||
|
errors.append("UID de dashboard inesperado")
|
||||||
|
if result.get("meta", {}).get("folderUid") != folder_uid:
|
||||||
|
errors.append("El dashboard no está en la carpeta prevista")
|
||||||
|
if len(dashboard.get("panels", [])) != 10:
|
||||||
|
errors.append("El dashboard no tiene 10 paneles")
|
||||||
|
if datasource_uids != [expected_datasource]:
|
||||||
|
errors.append(
|
||||||
|
f"Datasource inesperado: {datasource_uids!r}"
|
||||||
|
)
|
||||||
|
|
||||||
|
output = {
|
||||||
|
"status": "ok" if not errors else "error",
|
||||||
|
"grafana_url": base_url,
|
||||||
|
"dashboard_uid": dashboard.get("uid"),
|
||||||
|
"title": dashboard.get("title"),
|
||||||
|
"folder_uid": result.get("meta", {}).get("folderUid"),
|
||||||
|
"panel_count": len(dashboard.get("panels", [])),
|
||||||
|
"datasource_uids": datasource_uids,
|
||||||
|
"version": dashboard.get("version"),
|
||||||
|
"url": result.get("meta", {}).get("url"),
|
||||||
|
"errors": errors,
|
||||||
|
}
|
||||||
|
print(json.dumps(output, ensure_ascii=False, indent=2))
|
||||||
|
|
||||||
|
if errors:
|
||||||
|
raise SystemExit(1)
|
||||||
|
|
||||||
|
elif action == "export":
|
||||||
|
result = request(
|
||||||
|
"GET",
|
||||||
|
f"/api/dashboards/uid/{urllib.parse.quote(dashboard_uid)}",
|
||||||
|
)
|
||||||
|
print(json.dumps(
|
||||||
|
result["dashboard"],
|
||||||
|
ensure_ascii=False,
|
||||||
|
indent=2,
|
||||||
|
))
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise SystemExit(
|
||||||
|
"Uso: deploy_shopfloor_context_health_dashboard_v036.sh "
|
||||||
|
"{deploy|validate|export}"
|
||||||
|
)
|
||||||
|
PY
|
||||||
Loading…
x
Reference in New Issue
Block a user