Sustituye a 1.1.3, cuyo artefacto publicado se genero antes de los arreglos: su install.ps1 no traia -UpdateInPlace y su binario llevaba el runner.py que ignora --headless en Windows. Actualizar con el mataba el agente, cambiaba la tarea programada a SYSTEM y la dejaba sin arrancar, porque Qt no puede crear su plataforma como SYSTEM en la sesion 0 sin offscreen. Se quema el numero en lugar de reemplazar 1.1.3 con --force: los paquetes genericos de Gitea son inmutables, y dos contenidos distintos con la misma version fue exactamente lo que hizo caro el diagnostico. Hay que reconstruir los binarios aunque el codigo ya estuviera arreglado, porque __version__ va compilado dentro del ejecutable y el PANEL compara el sello config/.version contra la version que creia estar instalando. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
242 lines
12 KiB
Markdown
242 lines
12 KiB
Markdown
# Changelog
|
|
|
|
## [1.1.4] - 2026-07-31
|
|
|
|
Recoge todo lo que sigue de esta sección y **sustituye a 1.1.3**, cuyo artefacto publicado se generó
|
|
antes de los arreglos: su `install.ps1` no traía `-UpdateInPlace` y su binario llevaba el `runner.py`
|
|
que ignoraba `--headless` en Windows. Actualizar con él mataba el agente, cambiaba la tarea
|
|
programada a SYSTEM y la dejaba sin arrancar, porque Qt no puede crear su plataforma como SYSTEM en
|
|
la sesión 0 sin `offscreen`.
|
|
|
|
Los paquetes genéricos de Gitea son inmutables, así que se quema el número en lugar de reemplazar
|
|
1.1.3: dos contenidos distintos con la misma versión fue exactamente lo que hizo caro el
|
|
diagnóstico. Hay que reconstruir los binarios aunque el código ya estuviera arreglado, porque
|
|
`__version__` va compilado dentro del ejecutable y el PANEL compara el sello `config/.version`
|
|
contra la versión que creía estar instalando.
|
|
|
|
## [Sin publicar]
|
|
|
|
### La actualización de Windows decía que funcionó y no cambiaba nada
|
|
|
|
Actualizar sobre un servidor con el agente en una carpeta **no estándar** terminaba en verde y
|
|
dejaba el servidor con la versión anterior. La causa: todo el camino de Windows identificaba al
|
|
agente por **nombre**, mientras que lo único que se actualiza se identifica por **ruta**.
|
|
|
|
- **`install.ps1` alinea la tarea programada con el binario instalado.** `Start-ScheduledTask`
|
|
ejecuta la ruta registrada en la acción de la tarea, no el `-Prefix`: si difieren, se copiaba el
|
|
binario nuevo en un sitio y se arrancaba el viejo del otro. Ahora se reapunta la tarea
|
|
conservando disparador, principal, ajustes y argumentos; si no se puede corregir, **falla**.
|
|
- **La confirmación de arranque mira la ruta del proceso**, no solo su nombre. Un agente viejo que
|
|
nunca se detuvo satisfacía igual de bien un `Get-Process -Name CloudRestoreAS`. Si la ruta no es
|
|
legible —un proceso de SYSTEM no la expone a una cuenta sin elevación— se acepta por nombre y se
|
|
avisa, en vez de revertir una actualización correcta por falta de información.
|
|
- **Nuevo `scripts/emular-actualizacion-windows.ps1`**: reproduce el escenario completo con un
|
|
agente falso, sin elevación y sin tocar la instalación real de la máquina. Es lo que destapó este
|
|
defecto y el siguiente.
|
|
- **Corregido `Merge-EnvFile` con un `config\.env` de una sola línea.** Al asignar la salida de un
|
|
`if`, PowerShell desenrolla un array de un elemento a escalar, así que `$lines.Count` reventaba
|
|
bajo `Set-StrictMode` y la siembra de credenciales abortaba la instalación.
|
|
|
|
### Instalación y actualización desatendidas en Windows
|
|
|
|
El instalador de Windows nunca recibió la maquinaria de actualización segura que sí tiene
|
|
`install.sh`, y la asimetría se notaba en producción: actualizar desde el PANEL dejaba el
|
|
servidor sin agente, o fallaba con un error que no correspondía.
|
|
|
|
- **`install.ps1 -UpdateInPlace`**: actualiza una instalación existente conservando su tarea
|
|
programada y su configuración, y sin correr el bootstrap (una segunda instancia purgaría el
|
|
`Temp\` de la que está viva). Es el modo que usa el PANEL para actualizar.
|
|
- **No se interrumpe una restauración en curso** (`Temp\` no vacío): sale con **75**
|
|
(`EX_TEMPFAIL`), que el PANEL traduce a "reintenta luego". Windows no tenía esta guarda y una
|
|
reinstalación a destiempo se llevaba por delante el respaldo que se estuviera restaurando,
|
|
dejándolo vetado y la base en `SINGLE_USER`.
|
|
- **Respaldo y reversión automática**: si el binario nuevo no arranca, se vuelve al anterior.
|
|
El respaldo solo se descarta tras confirmar que la versión nueva corre.
|
|
- **Rearranque garantizado en todos los modos.** La detención corría siempre, pero solo
|
|
`-Service` volvía a arrancar algo: actualizar con `desktop` o `none` mataba el agente y se iba
|
|
sin dejar señal.
|
|
- La espera a que el SO libere el `.exe` pasa de 5 s a 30 s con reintentos de la copia: con un
|
|
antivirus escaneando un onefile de ~270 MB, 5 s se quedaban cortos y la copia abortaba.
|
|
- Se distingue **"no es administrador"** de **"es administrador con el token filtrado por UAC"**,
|
|
que es lo que recibe una sesión de OpenSSH. Se veían idénticos y el remedio es el opuesto: el
|
|
segundo no se arregla cambiando de cuenta sino con `LocalAccountTokenFilterPolicy`.
|
|
|
|
### `--headless` ahora funciona en Windows
|
|
|
|
`_ensure_qt_platform()` salía de inmediato en `win32`, así que la bandera no hacía nada ahí. La
|
|
tarea ONSTART corre como SYSTEM en la sesión 0, sin escritorio interactivo, y arrancaba con el
|
|
plugin Qt `windows` intentando crear una ventana real. En Linux el mismo modo funcionaba porque
|
|
el unit de systemd fija `QT_QPA_PLATFORM=offscreen` por fuera, y esa asimetría escondió el
|
|
defecto. Ahora `--headless` fuerza `offscreen` en todas las plataformas y no se muestra ventana.
|
|
|
|
### Documentación
|
|
|
|
- `README.md` afirmaba que la app no puede correr como servicio de Windows y sugería NSSM, lo
|
|
que contradecía a `install.ps1` desde que existe. Corregido.
|
|
- `packaging/LEEME.txt` solo documentaba el camino manual para Windows; ahora incluye el
|
|
instalador, igual que ya hacía para Linux.
|
|
|
|
## [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.
|