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,77 @@
|
||||
# Capability: local-hub
|
||||
|
||||
Exponer los procesos locales de la maquina como subdominios `*.localhost` (via Caddy) y reunirlos
|
||||
en una pantalla principal (Glance) con estado online/offline en vivo, refrescada a diario por
|
||||
`dag_engine`. Cubre el ciclo: descubrir servicios -> renderizar config de proxy -> renderizar
|
||||
config de dashboard -> recargar y reiniciar (pipeline `refresh_local_hub`).
|
||||
|
||||
Fuente de verdad de los servicios: `apps/local_hub/local_services.yaml`.
|
||||
|
||||
## Por que existe
|
||||
|
||||
Una maquina con muchos procesos locales (Metabase :3030, Portainer :9000, Grafana, Jupyter,
|
||||
dag_engine, registry_api...) obliga a recordar puerto por puerto. Este grupo los pone detras de
|
||||
nombres legibles (`metabase.localhost`, `portainer.localhost`) sin tocar DNS ni `/etc/hosts`
|
||||
(systemd-resolved resuelve `*.localhost` a 127.0.0.1 por defecto, RFC 6761) y los lista en una
|
||||
sola pagina con su salud en vivo.
|
||||
|
||||
## Funciones
|
||||
|
||||
| ID | Firma | Que hace |
|
||||
|---|---|---|
|
||||
| `discover_local_services_py_infra` | `discover_local_services(manifest_path, include_registry=True) -> list[dict]` | Lee el manifiesto `local_services.yaml`, normaliza cada servicio (name, subdomain, port, health_path, title, icon, category) y resuelve `up` por chequeo TCP. Con `include_registry` anade los servicios del registry (via `fn doctor services-spec`) deduplicados. |
|
||||
| `render_caddyfile_py_infra` | `render_caddyfile(services, dashboard=None) -> str` | PURA. Convierte la lista de servicios en el texto de un fragmento de Caddyfile (`http://<sub>.localhost { reverse_proxy 127.0.0.1:<port> }`), ordenado y determinista. El dashboard va primero. |
|
||||
| `render_glance_config_py_infra` | `render_glance_config(services, title="Procesos locales", host_suffix="localhost") -> str` | PURA. Convierte la lista en YAML de Glance: una pagina con un widget `monitor` por categoria, cada site apuntando a `http://<sub>.localhost`. |
|
||||
| `refresh_local_hub_py_pipelines` | `refresh_local_hub(manifest_path=..., reload=True) -> dict` | PIPELINE. Compone las 3 anteriores: descubre, renderiza Caddyfile + Glance, los escribe (`/etc/caddy/conf.d/local_hub.caddy` via ACL + `apps/local_hub/glance/glance.yml`), recarga Caddy (admin API :2019, sin sudo) y reinicia la user-unit `glance`. |
|
||||
|
||||
## Ejemplo canonico
|
||||
|
||||
```bash
|
||||
# Refrescar todo el hub (descubrir + regenerar configs + recargar):
|
||||
./fn run refresh_local_hub
|
||||
|
||||
# Acceder a un servicio por su subdominio (cualquier navegador del host):
|
||||
# http://metabase.localhost
|
||||
# http://portainer.localhost
|
||||
# http://home.localhost <- la pantalla principal (Glance)
|
||||
|
||||
# Anadir un servicio nuevo: editar el manifiesto y refrescar
|
||||
$EDITOR apps/local_hub/local_services.yaml # name, subdomain, port, health_path, title, icon, category
|
||||
./fn run refresh_local_hub
|
||||
```
|
||||
|
||||
Composicion ad-hoc (heredoc) si se necesita solo una parte:
|
||||
|
||||
```python
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.join("python", "functions"))
|
||||
from infra.discover_local_services import discover_local_services
|
||||
from infra.render_caddyfile import render_caddyfile
|
||||
|
||||
services = discover_local_services("apps/local_hub/local_services.yaml")
|
||||
print(render_caddyfile(services, dashboard={"subdomain": "home", "port": 8585}))
|
||||
```
|
||||
|
||||
## Infraestructura (one-time, ya provisionada)
|
||||
|
||||
- **Caddy** (`apt`, systemd system service, puerto 80): `/etc/caddy/Caddyfile` hace
|
||||
`import /etc/caddy/conf.d/*.caddy`. El usuario tiene ACL de escritura sobre `conf.d/` para que
|
||||
el pipeline regenere sin sudo. Reload via admin API en `localhost:2019`.
|
||||
- **Glance** (binario nativo en `~/.local/bin/glance`, systemd user service `glance.service`,
|
||||
`127.0.0.1:8585`). Corre como binario del host —no contenedor— para que `*.localhost` resuelva
|
||||
igual que en el resto del sistema.
|
||||
- **dag_engine**: DAG `refresh_local_hub` diario que ejecuta el pipeline.
|
||||
|
||||
## Fronteras
|
||||
|
||||
- **NO gestiona TLS**: sirve HTTP plano (`http://`) porque es trafico loopback. Para HTTPS con CA
|
||||
interna habria que quitar el prefijo `http://` en `render_caddyfile` y dejar que Caddy emita
|
||||
certs internos.
|
||||
- **NO arranca ni para los servicios** que expone: asume que ya corren. Solo crea el mapeo de
|
||||
subdominio y los lista. Encender/apagar un servicio es trabajo de su propia unit / `systemd`.
|
||||
- **NO hace el health-check en vivo**: eso lo hace Glance client-side. El pipeline solo resuelve
|
||||
un `up/down` puntual al regenerar (snapshot del momento).
|
||||
- **Servicios no-HTTP** (Postgres :5433, etc.) quedan fuera del proxy y del dashboard: Caddy y el
|
||||
widget `monitor` de Glance son HTTP.
|
||||
- **Solo loopback / un PC**: el manifiesto y los subdominios son locales a la maquina. No expone
|
||||
nada a la red. Para acceso remoto se usa SSH port-forward o el grupo `ssh`/`wireguard`.
|
||||
Reference in New Issue
Block a user