feat(infra): auto-commit con 56 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
---
|
||||
name: render_glance_config
|
||||
kind: function
|
||||
lang: py
|
||||
domain: infra
|
||||
version: "1.1.0"
|
||||
purity: pure
|
||||
signature: "render_glance_config(services: list[dict], title: str = \"Procesos locales\", host_suffix: str = \"localhost\") -> str"
|
||||
description: "Transforma una lista de servicios normalizados en el YAML de configuración de Glance (dashboard self-hosted). Genera una página con un widget monitor por categoría que hace health-check de cada servicio y lo pinta verde/rojo. Función pura y determinista. Parte del sistema local_hub."
|
||||
tags: [local-hub, infra, glance, dashboard, yaml, config]
|
||||
uses_functions: []
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: ""
|
||||
imports: [pyyaml]
|
||||
params:
|
||||
- name: services
|
||||
desc: "Lista de dicts de servicio normalizados. Cada uno requiere 'subdomain' (si falta, el servicio se ignora sin lanzar) y 'title'; opcional 'category' (default 'General'), 'icon' (se omite del site si está vacío o ausente) y 'health_path' (ruta de salud del servicio: si es distinta de '/', el site emite 'check-url' = url+health_path para que Glance haga el health-check ahí; si es '/' o falta, no se emite check-url)."
|
||||
- name: title
|
||||
desc: "Nombre de la página de Glance (campo 'name' de la página). Default 'Procesos locales'."
|
||||
- name: host_suffix
|
||||
desc: "Sufijo de host para las URLs de los sites. Default 'localhost' -> 'http://<subdomain>.localhost'."
|
||||
output: "String con el YAML completo de configuración de Glance (cabecera de comentario + pages/columns/widgets), terminado en '\\n'. Parseable con yaml.safe_load. Cada site lleva 'title' y 'url' (raíz del subdominio); además 'check-url' (url+health_path) cuando el servicio trae un health_path distinto de '/', e 'icon' cuando no está vacío."
|
||||
tested: true
|
||||
tests:
|
||||
- "test_golden_dos_categorias_dos_widgets"
|
||||
- "test_yaml_parseable_y_estructura"
|
||||
- "test_icon_omitido_cuando_vacio"
|
||||
- "test_host_suffix_custom"
|
||||
- "test_title_es_name_de_pagina"
|
||||
- "test_servicios_sin_subdomain_se_ignoran"
|
||||
- "test_determinismo"
|
||||
- "test_orden_sites_por_title"
|
||||
- "test_categoria_default_general"
|
||||
- "test_check_url_se_emite_cuando_health_path_no_es_raiz"
|
||||
test_file_path: "python/functions/infra/render_glance_config_test.py"
|
||||
file_path: "python/functions/infra/render_glance_config.py"
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```python
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.join("python", "functions"))
|
||||
from infra.render_glance_config import render_glance_config
|
||||
|
||||
services = [
|
||||
{"subdomain": "metabase", "title": "Metabase", "icon": "si:metabase", "category": "Datos"},
|
||||
{"subdomain": "jupyter", "title": "Jupyter Lab", "icon": "si:jupyter", "category": "Datos"},
|
||||
{"subdomain": "portainer","title": "Portainer", "icon": "si:portainer", "category": "Infra"},
|
||||
]
|
||||
|
||||
yaml_text = render_glance_config(services, title="Inicio")
|
||||
print(yaml_text)
|
||||
# pages:
|
||||
# - name: Inicio
|
||||
# columns:
|
||||
# - size: full
|
||||
# widgets:
|
||||
# - type: monitor
|
||||
# title: Datos
|
||||
# cache: 1m
|
||||
# sites:
|
||||
# - title: Jupyter Lab # ordenado por title dentro de la categoría
|
||||
# url: http://jupyter.localhost
|
||||
# icon: si:jupyter
|
||||
# - title: Metabase
|
||||
# url: http://metabase.localhost
|
||||
# icon: si:metabase
|
||||
# - type: monitor
|
||||
# title: Infra
|
||||
# cache: 1m
|
||||
# sites:
|
||||
# - title: Portainer
|
||||
# url: http://portainer.localhost
|
||||
# icon: si:portainer
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Cuando necesites regenerar el `glance.yml` del dashboard local a partir de
|
||||
`apps/local_hub/local_services.yaml`: tras añadir/quitar un servicio local, o
|
||||
en el pipeline `refresh_local_hub` que corre diario via dag_engine. La salida se
|
||||
escribe al archivo de config de Glance (el borde impuro: I/O lo hace el caller).
|
||||
|
||||
## Notas
|
||||
|
||||
- **Decisión `title` -> `name`:** el parámetro `title` se usa como el campo `name`
|
||||
de la (única) página de Glance. No es un comentario de cabecera ni se ignora.
|
||||
Default `"Procesos locales"`. Así la firma queda útil sin añadir un parámetro
|
||||
extra para el nombre de página.
|
||||
- **Determinismo:** las categorías se ordenan alfabéticamente y los servicios de
|
||||
cada categoría por `title` (desempate por `subdomain`). Se serializa con
|
||||
`yaml.safe_dump(sort_keys=False)` sobre estructuras ya ordenadas, por lo que la
|
||||
misma entrada (en cualquier orden) produce siempre la misma salida byte a byte.
|
||||
- **Robustez:** los servicios sin `subdomain` se ignoran silenciosamente (no se
|
||||
lanza). El `icon` se omite del site cuando está vacío o ausente. Cada categoría
|
||||
produce un widget `type: monitor` con `cache: 1m`; todos los widgets van en una
|
||||
sola columna `size: full`.
|
||||
- **Función pura:** sin I/O, sin estado, determinista. El health-check real lo
|
||||
hace Glance en runtime (GET a `check-url` si existe, si no a `url`); esta
|
||||
función solo genera el texto.
|
||||
- **`check-url` vs `url`:** `url` es siempre la raíz del subdominio (lo que abre
|
||||
el usuario al clicar). `check-url` solo aparece cuando el servicio trae un
|
||||
`health_path` distinto de `/`, y vale `url + health_path`. Sirve para APIs que
|
||||
devuelven 404 en `/` pero 200 en su ruta de salud (ej. `/api/health`), de modo
|
||||
que Glance las pinta verde sin cambiar el enlace navegable.
|
||||
|
||||
## Capability growth log
|
||||
|
||||
- v1.1.0 (2026-06-20) — añade check-url (health_path) por site para health-check preciso de APIs sin ruta raíz
|
||||
Reference in New Issue
Block a user