Files
CloudRecoveryAS/CHANGELOG.md
hreyes f02cd1f4c3 feat(install): --update-in-place, actualización sin privilegios y reversible
Hay entornos donde no se usa root en absoluto, así que ni `sudo -n` ni una cuenta
root son opciones. Este modo actualiza una instalación existente dejando su unit
de systemd intacto, que es lo único que una actualización necesita de verdad:
reemplazar el binario y reiniciar el proceso.

Se apoya en dos hechos, uno de ellos contrario a lo que decía el propio repo:

- `install` NO sufre ETXTBSY. A diferencia de `cp` —que abre con O_TRUNC—,
  desvincula el destino antes de crearlo, y por eso `make install` funciona sobre
  binarios en ejecución. Comprobado: `cp` sobre un ELF corriendo da "Text file
  busy" y `install` no. La consecuencia es la que importa: reemplazar el binario
  exige escritura en el DIRECTORIO, no en el archivo. El comentario de install.sh,
  BUILD.md y el CHANGELOG afirmaban lo contrario y mandaban al operador a
  diagnosticar un archivo en uso cuando lo que tenía era un EACCES.
- El unit corre como el usuario que instaló (cadena SUDO_USER) y trae
  Restart=always, así que esa cuenta puede señalizar el proceso y systemd lo
  relevanta con el binario nuevo. No hace falta systemctl ni tocar /etc.

Robustez, que es donde estaba el trabajo real:

- **Reversible.** Respalda el binario antes de reemplazarlo y, si el nuevo no
  arranca, lo restaura y confirma que el proceso volvió. Sin esto, una
  actualización fallida deja el servidor sin agente. Si tampoco puede revertir,
  conserva el respaldo y lo dice en vez de fingir éxito.
- **No interrumpe restauraciones.** El agente no atiende SIGTERM: matarlo a media
  restauración deja ese respaldo vetado para siempre (has_blocking_job_by_hash) y
  puede dejar la base en SINGLE_USER. Se comprueba Temp/ dos veces —antes de
  copiar y otra vez justo antes de señalizar, para cerrar la ventana— y sale con
  75 (EX_TEMPFAIL), que el panel traduce a "reintenta luego" y no a un fallo.
- **Diagnostica por qué no volvió**: distingue un unit sin Restart=always de un
  StartLimitBurst agotado, con el comando de recuperación.
- Omite el bootstrap de 20 s: es redundante en una actualización
  (ensure_runtime_layout corre en cada arranque) y una segunda instancia junto a
  la viva purgaría el Temp de la que está trabajando.

Un bug que solo aparecía fuera del camino feliz: con `set -euo pipefail`, un
`$(pgrep ... | head -1)` sin resultados hace fallar la sustitución y `set -e`
mataba el script en silencio — justo en el caso "el proceso no volvió", que es el
que había que manejar. Por eso el rollback no se ejecutaba nunca.
2026-07-30 15:40:37 -06:00

166 lines
7.0 KiB
Markdown

# Changelog
## [1.1.0] - 2026-07-29
### Distribución e instalación automatizada vía Gitea + PANEL
#### Publicación de versiones
- Artefactos con versión en el nombre: `CloudRestoreAS-<version>-{linux,win}-<arch>.{tar.gz,zip}`,
más `SHA256SUMS` y `release.json` (manifiesto con sha256, tamaño y deps embebidas).
- `packaging/scripts/publish-release.sh`: publica en los paquetes genéricos de Gitea
(`ADUANASOFT/generic/cloudrestoreas/<version>`) y **verifica el sha256 contra la propia
API de Gitea** antes de dar la publicación por buena. Soporta `--dry-run`, `--force` y
`--notify-panel`.
- `build-all.sh --publish` encadena build → empaquetado → publicación. Se niega a publicar
si falta una plataforma: los paquetes genéricos son inmutables y corregirlo quemaría el
número de versión.
#### Contrato con el PANEL
- `POST /api/restore/instance-config` ahora reporta también `platform` y `arch`, para que
el PANEL sepa qué artefacto le corresponde a cada servidor.
- `processed_folder` ya se envía en ese mismo reporte (antes se calculaba, no se mandaba).
#### Instaladores
- **Nuevo `install.ps1`**: instalador de despliegue Windows, autocontenido. Registra una
tarea programada ONSTART como SYSTEM para el 24/7 headless — sin NSSM ni descargas en el
servidor destino. Detiene la instancia en ejecución antes de reemplazar el `.exe`.
- El antiguo `install.ps1` (preparación del entorno de desarrollo: Python, venv, pip) se
movió a `scripts/dev-setup.ps1`. **Se estaba empaquetando por error** en el zip del
ejecutable autocontenido, que no necesita nada de eso.
- `install.sh` e `install.ps1` aceptan `--panel-env-file` / `-PanelEnvFile`: fusionan las
claves `CLOUDRESTORE_PANEL_*` en `config/.env` (replace-or-append, idempotente, con lista
blanca) y borran el archivo. El token viaja por archivo 0600, nunca por argumentos, para
que no quede visible en `ps` ni en el historial del destino.
- `install.sh` detiene el servicio antes de reemplazar el binario y lo vuelve a levantar si
estaba activo. (La razón que se dio aquí —que un ELF en ejecución da `ETXTBSY`— era incorrecta:
eso le pasa a `cp`, no a `install`, que desvincula el destino antes de crearlo. Ver BUILD.md.)
#### Versionado
- `app/__init__.py` es la fuente única de la versión; el diálogo *Acerca de* ya no la trae
hardcodeada.
- Flag `--version` en el binario, y sello `config/.version` que escribe el bootstrap (el
instalador remoto lo lee por SFTP, porque el `.exe` se compila con `console=False`).
- El `.exe` ya lleva metadatos de versión de Windows (`VSVersionInfo`).
#### Correcciones
- `config/7zip` y `config/odbc` se re-despliegan cuando el build trae otras versiones
embebidas, comparando un sello con el sha256 de `bundled-versions.json`. Antes solo se
copiaban si la carpeta estaba vacía, así que una actualización con driver ODBC nuevo
conservaba el viejo indefinidamente.
## [1.0.0] - 2026-01-25
### Lanzamiento Inicial
#### Características Principales
- ✅ Interfaz gráfica completa con PySide6/Qt
- ✅ Motor de procesamiento concurrente con workers configurables
- ✅ Vigilancia automática de carpeta de entrada
- ✅ Soporte para archivos ZIP multipart (.zip.001, .zip.002, etc.)
- ✅ Extracción automática con 7-Zip
- ✅ Restauración automática de bases de datos SQL Server
- ✅ Sistema de mapeo de nodos (archivo → base de datos)
- ✅ Minimización a bandeja del sistema (system tray)
- ✅ Base de datos SQLite para métricas y auditoría
- ✅ Logging rotativo con múltiples niveles
- ✅ Cifrado de contraseñas con DPAPI
- ✅ Soporte Windows Auth y SQL Auth
- ✅ Modo Dry Run para pruebas
- ✅ Detección de estabilidad de archivos
- ✅ Soporte para marcador .ready
- ✅ Timeouts configurables
- ✅ Tolerancia a fallos y manejo de errores
#### Tabs de la Interfaz
- Dashboard: Estadísticas en tiempo real
- Jobs: Gestión y visualización de jobs con detalles
- Nodos: CRUD de mapeos nodo → base de datos
- Configuración: Configuración completa de la aplicación
- Logs: Visualización de eventos y logs
#### Base de Datos
- Tabla `jobs`: Registro completo de jobs
- Tabla `job_steps`: Pasos detallados de cada job
- Tabla `nodes`: Mapeos de nodos
- Tabla `events`: Log de eventos
- Tabla `config`: Configuración persistente
#### Documentación
- README.md: Documentación completa
- QUICKSTART.md: Guía rápida de inicio
- ADVANCED.md: Configuración avanzada
- SCRIPTS.md: Ejemplos de scripts de automatización
#### Scripts Incluidos
- `runner.py`: Punto de entrada principal
- `install.ps1`: Script de instalación automática
- `build.ps1`: Script para generar ejecutable con PyInstaller
- `test_installation.py`: Script de verificación de instalación
#### Requisitos del Sistema
- Windows 10/11 o Windows Server 2019/2022+
- Python 3.11+
- 7-Zip
- ODBC Driver 17 for SQL Server
- SQL Server 2016+ (destino de restauraciones)
#### Dependencias
- PySide6 >= 6.6.0
- pyodbc >= 5.0.0
- pywin32 >= 306
### Características Futuras Planificadas
#### v1.1.0 (Próximo Release)
- [ ] Reintentos automáticos configurables desde UI
- [ ] Notificaciones por email
- [ ] Verificación de espacio en disco antes de procesar
- [ ] Soporte para múltiples instancias SQL Server
- [ ] Importación/Exportación de nodos desde CSV
- [ ] Dashboard mejorado con gráficos
- [ ] Filtros avanzados en tabla de jobs
#### v1.2.0 (Futuro)
- [ ] API REST para integración externa
- [ ] Webhooks para notificaciones
- [ ] Programación de restauraciones (scheduling)
- [ ] Soporte para otros formatos de compresión (RAR, TAR)
- [ ] Modo cluster (múltiples instancias coordinadas)
- [ ] Soporte para Azure SQL Database
- [ ] Backup/Restore de configuración desde UI
#### v2.0.0 (Largo Plazo)
- [ ] Soporte multiplataforma (Linux)
- [ ] Interfaz web opcional
- [ ] Modo servicio de Windows
- [ ] Soporte para PostgreSQL y MySQL
- [ ] Machine learning para predicción de tiempos
- [ ] Dashboard en tiempo real con WebSockets
### Problemas Conocidos
#### Limitaciones Actuales
- Solo soporta una configuración SQL Server (no múltiples instancias)
- Reintentos automáticos no expuestos en UI (requiere edición manual)
- No hay verificación automática de espacio en disco
- System tray no muestra notificaciones toast
- No hay soporte nativo para archivos RAR
#### Workarounds Documentados
- Múltiples instancias SQL: Ver ADVANCED.md sección 7
- Notificaciones: Ver SCRIPTS.md para monitoreo externo
- Limpieza automática: Ver SCRIPTS.md para scripts de limpieza
### Notas de Seguridad
- Las contraseñas se cifran con DPAPI (vinculadas a usuario/máquina)
- Los logs pueden contener información sensible (rutas, nombres de DB)
- Se recomienda ejecutar con cuenta de servicio dedicada
- Asegurar permisos apropiados en carpetas de trabajo
### Agradecimientos
Desarrollado por el equipo de Aduanasoft para automatización de restauraciones de bases de datos SQL Server.
---
**Nota de Versión**: Esta es la versión inicial de CloudRestoreAS. Se agradecen comentarios y sugerencias para futuras versiones.