feature/integracion-panel-restore-targets
This commit is contained in:
197
INTEGRACION_PANEL.md
Normal file
197
INTEGRACION_PANEL.md
Normal file
@@ -0,0 +1,197 @@
|
||||
# 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=<esta instancia>` — 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 <CLOUDRESTORE_API_TOKEN>`.
|
||||
|
||||
### 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=<zip>&instance=<nombre>`
|
||||
|
||||
**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=<db_name>&instance=<nombre>`
|
||||
|
||||
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**.
|
||||
Reference in New Issue
Block a user