# Integración CloudRestoreAS ↔ PANEL_BASES_ANEXO24 ## Variables de entorno y configuración | Panel (`.env`) | CloudRestoreAS (pestaña Config → PANEL) | Debe coincidir | |----------------|-------------------------------------------|----------------| | `CLOUDRESTORE_API_TOKEN` | `panel.api_token` | **Sí** — mismo valor en todas las instalaciones | | `ENCRYPTION_KEY` | — | Solo panel (cifra credenciales de `restore_targets`) | | URL del panel (ej. `https://panel:3000`) | `panel.api_url` | **Sí** — base URL sin barra final | | — | `panel.instance_key` | Nombre de **este** servidor en el panel (`restore_targets.name`) | Generar token: ```bash node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" ``` Generar clave de cifrado (panel): ```bash node -e "console.log(require('crypto').randomBytes(32).toString('base64'))" ``` `BACKUP_PATH` del panel es independiente: lista respaldos en el dashboard. Cada CloudRestoreAS reporta su carpeta local vía `instance-config` (clave = nombre del servidor). --- ## Enrutamiento automático (todos los CRA) No hay modos que configurar. **Todo CRA con panel** hace lo mismo: 1. Llega un ZIP a la carpeta de entrada. 2. `GET resolve-route?filename=X&instance=` — el panel identifica el nodo y el servidor asignado. 3. Si `action=restore_local` → extract + RESTORE aquí (credenciales SQL de este servidor en el panel). 4. Si `action=forward` → SFTP del ZIP al `input_folder` del destino (credenciales SSH del destino). 5. Mover ZIP a `processed`; reportar `completed` o `forwarded`. ```mermaid flowchart TB ZIP[ZIP en carpeta local] CRA[Any CRA con instance_key] Panel["resolve-route"] SFTP[SFTP al destino] SQL[RESTORE local] ZIP --> CRA --> Panel Panel -->|restore_local| SQL Panel -->|forward| SFTP ``` Aplica igual en Alfa, Omega o un hub donde llegan todos los ZIP: | Situación | Qué hace el CRA | |-----------|-----------------| | Nodo asignado a **esta** instancia | RESTORE local | | Nodo asignado a **otro** servidor | SFTP ZIP al destino | La decisión la toma el **panel** (nodo + asignación en Gestión BD), no el operador. ### Qué configura cada instalación | Campo | Para qué | |-------|----------| | URL + token del panel | Conectar al panel | | **Instancia** | Identidad de este servidor (`restore_targets.name`) | | Carpeta entrada | Dónde vigila ZIPs esta máquina | El selector de instancia se llena desde `GET /api/restore/target-catalog`. No hay límite de servidores. ### Hub donde llegan todos los ZIP Ejemplo: máquina **Alfa** recibe todos los archivos y también tiene bases propias: 1. Panel: servidor Alfa registrado; bases de Alfa/Omega/Gamma asignadas en Gestión BD. 2. CRA en Alfa: instancia **Alfa**, misma URL/token que el resto. 3. ZIP de base Alfa → RESTORE local. 4. ZIP de base Omega → SFTP a carpeta de Omega (card **Reportada**). 5. CRA Omega detecta el ZIP y restaura localmente. No hay paso extra ni modo especial. ### Sin panel (legacy local) Si `panel.api_url` está vacío, CloudRestoreAS usa nodos SQLite locales y SQL de la pestaña Config (sin reparto automático). ### Config legacy `panel.mode` Valores antiguos (`orchestrator`, `hub_restore`, `colocated`) se **ignoran**. Se registra un aviso en log y se usa siempre `resolve-route`. El modo hub que subía `.bak` por SFTP ya no aplica. --- ## Contrato API (`/api/restore/*`) Autenticación: `Authorization: Bearer `. ### GET `/api/restore/target-catalog` **Cliente:** `panel_client.list_restore_target_names()` | Respuesta 200 | Descripción | |---------------|-------------| | `targets[]` | `{ "id", "name" }` — sin credenciales | ### GET `/api/restore/resolve-route?filename=&instance=` **Cliente:** `panel_client.resolve_route()` | Query | Obligatorio | Descripción | |-------|-------------|-------------| | `filename` | Sí | Nombre del ZIP (panel resuelve nodo desde el stem) | | `instance` | Sí | Instancia de este CRA (`restore_targets.name`) | | Respuesta 200 | Descripción | |---------------|-------------| | `action` | `restore_local` o `forward` | | `db_name` | Base resuelta | | `node_key` | Nodo en panel | | `target` | Servidor destino (SQL/SSH + `input_folder`) | | Código | Significado | |--------|-------------| | 404 | Sin nodo/base o sin servidor asignado | | 503 | Destino sin `input_folder` reportado | ### GET `/api/restore/target-for?database=&instance=` Usado por utilidades legacy; el flujo principal de jobs usa `resolve-route`. ### POST `/api/restore/job-result` `status`: `completed` | `failed` | `forwarded`. ### POST `/api/restore/instance-config` Reporte de carpeta de entrada (`instance_key` = nombre del servidor). --- ## Agregar servidores adicionales 1. Panel → **Servidores de Restauración → + Nuevo servidor** 2. **Gestión de Bases de Datos** → dropdown servidor por base 3. Instalar CRA → Config → instancia → Guardar (card **Reportada**) --- ## Despliegue inicial ### Orden de arranque (migraciones automáticas) 1. **a24c-postgres** — volumen Postgres. 2. **a24c-backend** — aplica `alembic upgrade head` al iniciar (incluye tablas CRA: `restore_targets`, `restore_job_logs`, `cloudrestore_status`, `restore_target_id`). 3. **Panel** (`docker compose up`) — espera el esquema CRA en Postgres antes de abrir el puerto 3000. No hace falta ejecutar `database/migrations/*.sql` a mano: la fuente de verdad es Alembic en **a24c**. ### Panel ```bash cd ~/dev/PANEL_BASES_ANEXO24 cp .env.example .env docker compose up -d ``` Servidores de restauración + asignación de bases en Gestión BD. ### Cada Windows con CloudRestoreAS | Config | Valor | |--------|--------| | URL PANEL | misma en todos | | API Token | mismo en todos | | **Instancia** | nombre de **este** servidor en panel | | Carpeta Entrada | local de esta máquina | ### Verificaciones | Paso | Qué comprobar | |------|----------------| | Cards en panel | **Reportada** con carpeta | | ZIP propio | RESTORE local | | ZIP ajeno en esta carpeta | SFTP al destino; bitácora `forwarded` | | Destino recibe ZIP | RESTORE local allí | ### Troubleshooting - **Sin reportar**: CRA destino no guardó config o no alcanza el panel. - **503 en forward**: destino sin `input_folder` reportado. - **Job diferido**: panel caído, sin `instance_key`, o base sin asignación. - **401**: token distinto entre panel y CRA. --- ## Prueba local Un CRA con `instance_key` igual al nombre en panel. El panel muestra una card por servidor; las no reportadas aparecen como **Sin reportar**.