Feat(ADN): Implementado y ejecutado archivar:md para mover Markdowns obsoletos a histórico DB-First
This commit is contained in:
+6
-6
@@ -50,9 +50,9 @@ Antes de iniciar escaneos, pruebas de red, o conexiones SSH a un nodo de un proy
|
||||
- **Objetivo:** Identificar si el nodo objetivo está en una subred aislada, detrás de un NAT, o si requiere un salto de red (ProxyJump) a través de un hypervisor anfitrión, previniendo errores ciegos y garantizando trazabilidad geográfica.
|
||||
|
||||
### 14. Protocolo Autónomo de Ejecución (P.A.E.)
|
||||
Ante comandos simplificados del operador (ej: `"adn: backup <nodo>"`), la IA **DEBE** ejecutar el flujo completo de "Armonía Integral" sin requerir instrucciones adicionales:
|
||||
1. **Validación**: Consultar `nodos/<nodo>.md` y `adn/01_ontologia.md` para confirmar identidad y red.
|
||||
2. **Autorización**: Ejecutar `ruby tools/ns8-candados/ns8-candados.rb authorize` ANTES de cualquier acceso a secretos.
|
||||
3. **Bitácora-First**: Registrar la tarea en estado `⏳` en la bitácora del día actual.
|
||||
4. **Ejecución**: Lanzar la herramienta correspondiente (`dtic-BKPs.rb`, etc.) capturando logs.
|
||||
5. **Cierre y Auditoría**: Ejecutar `ruby tools/ns8-candados/ns8-candados.rb cerrar` al finalizar y actualizar la bitácora a `✅` o `❌`.
|
||||
Para tareas operativas complejas (ej. backups), la IA **DEBE** utilizar las herramientas unificadas (`tools/adn.rb`) que ya integran la lógica de seguridad y registro:
|
||||
|
||||
1. **Ejecución**: Usar `ruby tools/adn.rb backup [nodo]`.
|
||||
2. **Seguridad**: La herramienta utilizará internamente `ns8-candados run` para no exponer secretos.
|
||||
3. **Bitácora**: El registro en `docs/bitacoras/YYYY-MM-DD.md` es automático mediante la herramienta.
|
||||
4. **Validación**: La herramienta valida el contexto técnico (VMID, Host IP) consultando las fichas del ADN.
|
||||
|
||||
@@ -1,200 +0,0 @@
|
||||
# Bitácora de Operaciones - 19/02/2026
|
||||
|
||||
## Control de Gestión
|
||||
|
||||
### 🚩 Pendientes
|
||||
| ID | NODO | DETALLE |
|
||||
| :--- | :--- | :--- |
|
||||
|
||||
### ⏳ En Proceso
|
||||
| ID | NODO | DETALLE |
|
||||
| :--- | :--- | :--- |
|
||||
|
||||
### 📝 Resumen de Actividades
|
||||
| NODO | RESUMEN INTEGRAL |
|
||||
| :--- | :--- |
|
||||
| srv-ns8 | Jornada de estandarización y despliegue (23:15). Se aplicó la política de nomenclatura lowercase en todo el grid, se establecieron los cimientos del ADN, se implementó TinyFileManager con seguridad Nginx y roles, se saneó el workspace y se procesaron los relevamientos de activos AIDA64. |
|
||||
| srv-pmox2 | Recuperación definitiva de la conectividad (22:30) asegurando la persistencia del Gateway en la configuración de red y habilitando el entorno para la automatización de scripts. |
|
||||
| srvv-sysacadweb | Corrección documental y operativa (19:45), rectificando la especificación del SO (Win2008 R2) tras el análisis de activos y registrando el estado del nodo. |
|
||||
| pcv-dasu2 | Normalización de identidad (10:55) completando el cambio de hostname y su actualización en la ontología del sistema. |
|
||||
| srvv-maurik | Verificación de hardware (10:05) actualización de ficha técnica con datos de relevamiento y health check de servicios de dominio. |
|
||||
| pcv-dasu1 | Aseguramiento de datos críticos (09:54) mediante ejecución exitosa del procedimiento de backup de estación de trabajo. |
|
||||
| srv-pmox3 | Ejecución correcta del ciclo de respaldos nocturnos automatizados en almacenamiento ZFS (03:02). |
|
||||
| srv-pmox1 | Validación operativa del nuevo script de automatización Ruby con el primer backup exitoso (02:00). |
|
||||
|
||||
---
|
||||
|
||||
## 📂 Actividades Detalladas
|
||||
|
||||
### srv-ns8
|
||||
|
||||
#### ✅ - A01 - ADN Nomenclatura
|
||||
Renombrado masivo de archivos y referencias a minúsculas (`srv-ns8`, `srvv-maurik`, etc.) para cumplir estándar.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 23:00 | 23:15 | Inicio de tareas de armonización de nomenclatura. Finalización exitosa. | [P] ✅ |
|
||||
|
||||
#### ✅ - A02 - Activos Integración AIDA64
|
||||
Procesamiento de reportes, actualización de fichas (`MAURIK`, `SYSACADWEB`) y unificación de `pc-dasu0`.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 22:35 | 22:45 | Procesamiento de reportes AIDA64 e integración de activos. | [P] ✅ |
|
||||
|
||||
#### ✅ - A03 - Saneamiento Workspace
|
||||
🧹 Eliminación de directorios `servicios/hfs` y `servicios/filebrowser` para mantener higiene del repositorio.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 21:30 | 21:35 | Saneamiento de directorios de servicios obsoletos. | [P] ✅ |
|
||||
|
||||
#### ✅ - A04 - Personalización Identidad TFM
|
||||
Configuración de Título "NS8 - TFM" y ACLs: `rmonla` (Admin), `utnlarioja` (Lectura).
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 20:55 | 21:00 | Configuración de ACLs y títulos en TinyFileManager. | [P] ✅ |
|
||||
|
||||
#### ✅ - A05 - Configuración Storage TFM
|
||||
Mapeo de volumen de datos a disco físico `/mnt/ns8Disco2/DTIC_APPs/`.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 20:25 | 20:40 | Mapeo de volumen físico para almacenamiento de APPs. | [P] ✅ |
|
||||
|
||||
#### ✅ - A06 - Despliegue Nginx Proxy
|
||||
Exposición del servicio TFM bajo ruta segura `/tfm` con autenticación integrada.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 20:05 | 20:20 | Despliegue de proxy Nginx para acceso seguro a TFM. | [P] ✅ |
|
||||
|
||||
#### ✅ - A07 - Investigación Selección de Software
|
||||
Análisis de alternativas para File Server, eligiendo TinyFileManager por agilidad PHP.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 15:30 | 20:00 | Análisis comparativo y selección de software de File Cloud. | [P] ✅ |
|
||||
|
||||
#### ✅ - A08 - Scripts Automatización Ruby
|
||||
Desarrollo del script `mantenimiento_backups.rb` para ciclo de vida de snapshots.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 01:25 | 02:00 | Desarrollo y pruebas del script Ruby para ciclo de snapshots. | [P] ✅ |
|
||||
|
||||
#### ✅ - A09 - ADN Estandarización
|
||||
Creación de `TEMPLATE_PROCEDIMIENTO.md` y estructura de `procedimientos/`.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 00:45 | 01:10 | Creación de templates de procedimientos y base de ADN. | [P] ✅ |
|
||||
|
||||
### srv-pmox2
|
||||
|
||||
#### ✅ - A10 - Red Persistencia de Gateway
|
||||
Inyección de `gateway 10.0.10.8` en configuración de interfaces para garantizar conectividad post-reboot.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 22:20 | 22:30 | Corrección de persistencia de Gateway en interfaces de red. | [P] ✅ |
|
||||
|
||||
#### ✅ - A11 - Backup Ciclo de Respaldo
|
||||
Ejecución exitosa del script de backup tras recuperar conectividad.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 02:33 | 02:45 | Ejecución manual exitosa del ciclo de backup. | [P] ✅ |
|
||||
|
||||
#### ✅ - A12 - S.O. Runtime Ruby
|
||||
Instalación de dependencias para permitir la ejecución de scripts de mantenimiento.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 02:22 | 02:33 | Instalación de dependencias Ruby en nodo remoto. | [R] ✅ |
|
||||
|
||||
#### ✅ - A13 - Red Resolución de Incidente
|
||||
Diagnóstico y corrección manual de ruta por defecto perdida ("Network unreachable").
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 02:22 | 02:33 | Instalación de dependencias Ruby en nodo remoto. | [R] ✅ |
|
||||
|
||||
### srvv-sysacadweb
|
||||
|
||||
#### ✅ - A14 - Control Validación Operativa
|
||||
Confirmación de arranque correcto de servicios IIS y base de datos tras snapshot.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 19:40 | 19:45 | Verificación de servicios IIS post-snapshot. | [R] ✅ |
|
||||
|
||||
#### ✅ - A15 - ADN Snapshot Documental
|
||||
Registro formal del estado del nodo en la estructura `nodos/`.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 19:34 | 19:40 | Registro del estado del nodo en la estructura de Ontología. | [R] ✅ |
|
||||
|
||||
#### ✅ - A16 - Backup Respaldo Completo
|
||||
Ciclo de backup de VM completado sin errores.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 09:23 | 19:34 | Proceso de backup completo de la máquina virtual. | [R] ✅ |
|
||||
|
||||
### pcv-dasu2
|
||||
|
||||
#### ✅ - A17 - Identidad Cambio de Hostname
|
||||
Renombrado de `pcv-dasu3` a `pcv-dasu2` para alinear con nomenclatura del Grid (Ontología).
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 10:00 | 10:55 | Renombrado de nodo y actualización de identidad en el Grid. | [P] ✅ |
|
||||
|
||||
### srvv-maurik
|
||||
|
||||
#### ✅ - A18 - Control Health Check
|
||||
Verificación de servicios de Dominio (AD DS) y resolución DNS post-backup.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 10:01 | 10:05 | Health check de servicios de Directorio Activo (AD DS). | [R] ✅ |
|
||||
|
||||
#### ✅ - A19 - Backup Ciclo de Respaldo
|
||||
Ejecución de backup programado.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 09:23 | 10:01 | Ejecución de backup de VM en infraestructura remota. | [R] ✅ |
|
||||
|
||||
### pcv-dasu1
|
||||
|
||||
#### ✅ - A20 - Backup Respaldo Crítico
|
||||
Backup de seguridad de la estación de trabajo principal de DASU.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 09:43 | 09:54 | Resguardo de datos críticos de la estación de trabajo. | [P] ✅ |
|
||||
|
||||
### srv-pmox3
|
||||
|
||||
#### ✅ - A21 - Backup Automatización Nocturna
|
||||
Ejecución programada del ciclo de respaldos en ZFS.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 02:08 | 03:02 | Ciclo automatizado de backups en almacenamiento ZFS. | [P] ✅ |
|
||||
|
||||
### srv-pmox1
|
||||
|
||||
#### ✅ - A22 - Backup Automatización Nocturna
|
||||
Primer ejecución válida del nuevo sistema de backups en Ruby.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 01:44 | 02:00 | Validación operativa de nuevo script Ruby de gestión de copias. | [P] ✅ |
|
||||
|
||||
---
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
@@ -1,130 +0,0 @@
|
||||
# Bitácora de Operaciones - 20/02/2026
|
||||
|
||||
## Control de Gestión
|
||||
|
||||
### 🚩 Pendientes
|
||||
| ID | NODO | DETALLE |
|
||||
| :--- | :--- | :--- |
|
||||
|
||||
### ⏳ En Proceso
|
||||
| ID | NODO | DETALLE |
|
||||
| :--- | :--- | :--- |
|
||||
|
||||
### 📝 Resumen de Actividades
|
||||
| NODO | RESUMEN INTEGRAL |
|
||||
| :--- | :--- |
|
||||
| [srv-ns8](#srv-ns8) | Finalización exitosa del ciclo masivo de backups automatizados (dtic-BKPs), logrando evasión de cuotas y bloqueos en OneDrive tras 8.5hrs continuas. Adicionalmente, se ejecutó una refactorización fundacional del ADN y el estándar visual de bitácoras, implementando iconografía dual, descripciones jerárquicas en la columna de Hitos y la formalización arquitectónica de las Reglas de Sincronización en Cascada (Triggers). `[Remoto: ~16 hs]` |
|
||||
|
||||
---
|
||||
|
||||
## 📂 Actividades Detalladas
|
||||
|
||||
### srv-ns8
|
||||
|
||||
#### ✅ - A14 - ADN / Mejora Continua (Íconos)
|
||||
👁️ Evolución de la iconografía de la bitácora: Los iconos en la columna "Tema" ahora son estrictamente de estado (`✅` cerrado, `⏳` abierto), delegando los iconos semánticos descriptivos (`🔧`, `🧹`, `⚠️`, etc.) al nivel de la viñeta individual dentro de la cronología "Hitos".
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 22:33 | 23:25 | Conceptualización y refactorización de iconografía semántica. | [R] ✅ |
|
||||
| 22:45 | 23:25 | Adopción de norma de iconos semánticos en eventos. | [R] ✍️ |
|
||||
|
||||
#### ✅ - A13 - ADN / Mejora Continua (Hitos)
|
||||
📝 Refactorización de la tabla de bitácoras transformando la columna de detalles en `Hitos` con viñetas de marca de tiempo, eliminando las columnas `Ini/Fin` obsoletas, y adoptando identificadores estáticos alfanuméricos (`A00`) dentro del Tema. La tarea había retornado a estado activo para explorar nuevas ideas emergentes del usuario.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 22:06 | 23:25 | Refactorización estructural de tabla y adopción de IDs A00. | [R] ✅ |
|
||||
| 22:28 | 23:25 | Tarea reabierta para ajustes finos de narrativa. | [R] 💡 |
|
||||
| 22:15 | 23:25 | Despliegue preliminar de formato consolidado. | [R] 🚀 |
|
||||
|
||||
#### ✅ - A12 - ADN / Mejora Continua (Formato)
|
||||
📝 Rediseño estructural de la tabla de Actividades Detalladas combinando [Estado] - [Hora] - [Nombre Tarea] en la columna unificada `Tema`. Formalizado como estándar en el ADN.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 21:45 | 21:55 | Rediseño estructural y modificación de 02_protocolo.md. | [R] ✅ |
|
||||
| 21:45 | 21:55 | Conceptualización de columna unificada aprobada. | [R] 🧠 |
|
||||
|
||||
#### ✅ - A11 - ADN / Mejora Continua
|
||||
📝 Ampliada oficial la Sección 9 del Protocolo catalogando la migración de scripts operativos de Bash hacia procesadores robustos en Ruby (`dtic-BKPs`) como segundo Ejemplo Fundacional histórico de Evolución Tecnológica sistémica.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 14:14 | 14:26 | Redacción de Sección 9 sobre Evolución Tecnológica. | [R] ✅ |
|
||||
|
||||
#### ✅ - A10 - ADN / Mejora Continua
|
||||
📝 Inyectado de manera formal el marco metodológico "Evolución Progresiva" (Sección 9) dentro de `02_protocolo.md`. Esto define el ciclo de vida (Incubación → Identificación → Formalización → Propagación) para madurar prácticas sistémicas emergentes.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 13:35 | 13:40 | Inyección formal de marco "Evolución Progresiva". | [R] ✅ |
|
||||
|
||||
#### ✅ - A09 - dtic-BKPs C4
|
||||
💾 Ejecución del ciclo masivo de backups nocturno automáticos en modo C4 finalizó con éxito tras ~8.5Hrs de carga total. Se confirma absoluta resiliencia de conexión.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 09:13 | 17:35 | Ciclo masivo de backups nocturnos (C4). Resiliencia total. | [R] ✅ |
|
||||
| 14:29 | 17:35 | Control interactivo: flujo constante, sin errores Code 7. | [R] 👁️ |
|
||||
| 12:54 | 17:35 | Inicio sincronización bruta nodo srv-SysACADWeb. | [R] ☁️ |
|
||||
| 09:39 | 17:35 | Fase Proxmox saneada. Volcado de zfsDISCO1 superado. | [R] 🟢 |
|
||||
|
||||
#### ✅ - A08 - dtic-BKPs / Proxmox
|
||||
🔧 Resolución del error de montaje `zfsDISCO1`. Se reconfiguró el perfil rclone `pve_PMOX3` para inyectar correctamente la autenticación SSH liberada por agente en memoria vaciando el parámetro manual de archivo de llave e indicando `--key-use-agent`.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 08:55 | 09:05 | Reconfiguración de rclone con --key-use-agent. | [R] ✅ |
|
||||
|
||||
#### ✅ - A07 - dtic-BKPs / script
|
||||
🔧 Corrección del launcher `app-run-sh` estableciendo comportamiento daemonizado realístico (`-d -m`) sobre la sesión GNU screen.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 08:55 | 09:05 | Corrección de launcher app-run-sh a modo daemon. | [R] ✅ |
|
||||
|
||||
#### ✅ - A06 - .gitignore
|
||||
🔧 Excepción (`!tools/dtic-BKPs/logs/`) configurada en la raíz para permitir el versionado del subdirectorio de logs.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 08:23 | 08:28 | Configuración de excepción logs en .gitignore. | [R] ✅ |
|
||||
|
||||
#### ✅ - A05 - dtic-BKPs / rclone
|
||||
🔧 Refactorización del script `sync_rclone.rb`. Se inyectaron parámetros de resiliencia de conexión (`--retries 5`, `--timeout 30m`) y se forzó la purga previa de archivos (`--delete-before`) para optimizar el uso de almacenamiento remoto.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 08:10 | 08:15 | Refactorización resiliencia sync_rclone.rb. | [R] ✅ |
|
||||
|
||||
#### ✅ - A04 - Análisis dtic-BKPs
|
||||
🧪 Diagnóstico del fallo de sincronización nocturna. Causas: (1) `pve_PMOX3` - Error montando disco remoto `zfsDISCO1`. (2) `srv-SysACADWeb` - Error rclone (Code 7) por desconexión de red o límite de cuota en nube.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 07:42 | 07:55 | Diagnóstico de fallo nocturno (zfsDISCO1 y Code 7). | [R] ⚠️ |
|
||||
|
||||
#### ✅ - A03 - Estructura
|
||||
🧹 Reubicación de la herramienta de respaldos abandonando `scripts/_app_dtic-BKPs` para establecerse definitivamente en `tools/dtic-BKPs`.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 07:36 | 07:45 | Reubicación de dtic-BKPs a tools/. | [R] ✅ |
|
||||
|
||||
#### ✅ - A02 - dtic-BKPs
|
||||
🔧 Estructuración y revisión operativa del procesador de respaldos automatizado (v5.5.1) en Ruby, integrando los scripts de ejecución via screen.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 07:00 | 07:28 | Revisión operativa procesador v5.5.1 en Ruby. | [R] ✅ |
|
||||
|
||||
#### ⚠️ - A01 - Fallo de Procesamiento
|
||||
⚠️ La ejecución del ciclo automatizado de respaldos (`dtic-BKPs`) falló debido a problemas de conectividad con almacenamiento (Proxmox 3) y error de sincronización hacia OneDrive (cód 7).
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 00:12 | 05:36 | Fallo masivo de ciclo por conectividad y cuotas. | [R] 💥 |
|
||||
|
||||
---
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
@@ -1,103 +0,0 @@
|
||||
# Bitácora de Operaciones - 23/02/2026
|
||||
|
||||
## Control de Gestión
|
||||
|
||||
### 🚩 Pendientes
|
||||
| ID | NODO | DETALLE |
|
||||
| :--- | :--- | :--- |
|
||||
| ➡️ - P02 - **Sistema DASUTEN** | srv-dasu | Despliegue e instalación del software del sistema DASUTEN en la VM.<br><br>➡️ **[Continúa en 24/02](2026-02-24.md)** |
|
||||
|
||||
### ⏳ En Proceso
|
||||
| ID | NODO | DETALLE |
|
||||
| :--- | :--- | :--- |
|
||||
| [➡️ - A07 - **Sync dtic-BKPs**](#srv-ns8) | srv-ns8 | Sincronización limpia de backups de Proxmox para aplicar nombres de host.<br><br>➡️ **[Continúa en 24/02](2026-02-24.md#A07)** |
|
||||
| [➡️ - A05 - **VM Windows Server (Core)**](#srv-dasu) | srv-dasu | Creación y configuración de máquina virtual con Windows Server Core para rol AD DS.<br><br>➡️ **[Continúa en 24/02](2026-02-24.md#A05)** |
|
||||
|
||||
### 📝 Resumen de Actividades
|
||||
| NODO | RESUMEN INTEGRAL |
|
||||
| :--- | :--- |
|
||||
| [srv-ns8](#srv-ns8) | Diagnóstico y corrección del script de respaldos `dtic-BKPs_app.rb`. Se solucionaron dos fallas críticas documentadas en el hito A04: un bloqueo interactivo de SSH provocado por el comando rclone al listar/descargar archivos, y la omisión silenciosa de procesamiento de respaldos que carecían del archivo descriptor `.notes`. `[Remoto: ~5 hs]` |
|
||||
| [srv-dasu](#srv-dasu) | Inicialización exitosa de la infraestructura base para la oficina DASUTEN. Se instaló un hypervisor Standalone Proxmox VE, se solventaron bloqueos físicos de red, se asignó ip estática (`10.0.10.205`) y se estableció acceso seguro desatendido vía llaves SSH desde el nodo central. Finalizado el relevamiento de hardware confirmando 4 Cores, 16GB RAM y Storage LVM de 480GB. `[Físico: ~3 hs]` |
|
||||
|
||||
---
|
||||
|
||||
## 📂 Actividades Detalladas
|
||||
|
||||
### srv-ns8
|
||||
|
||||
#### ✅ - A06 - Dashboard P2601
|
||||
🚀 Despliegue del dashboard web para visualización de avance del proyecto DASUTEN (URL: `ns8.frlr.utn.edu.ar/P2601/`).
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 20:49 | 20:53 | Aprobación de especificaciones y despliegue exitoso en Nginx. | [R] ✅ |
|
||||
|
||||
#### ➡️ - A07 - Sync dtic-BKPs
|
||||
🚀 Reinicio de la sincronización de resguardos (`dtic-BKPs_app.rb C1`) con la nueva política de nomenclatura basada en nombres de host para las carpetas contenedoras de Proxmox.
|
||||
➡️ **[Continúa en 24/02](2026-02-24.md#A07)**
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 22:42 | 23:35 | Reinicio de sincronización limpia con nueva nomenclatura. | [R] ✅ |
|
||||
|
||||
#### ✅ - A04 - Análisis dtic-BKPs
|
||||
🧪 Revisión y diagnóstico de la herramienta de respaldos (`dtic-BKPs_app.rb`) a pedido del usuario. Se detectó una inconsistencia u omisión en los archivos descargados durante la fase "Descargar archivos de BKPs de VMs: zfsDISCO1".
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 19:58 | 21:54 | Análisis de logs y corrección de fix para IDs de VMs (19 sets). | [R] ✅ |
|
||||
| 19:58 | 21:54 | Aplicación de parche Ruby y auto-lanzamiento en screen. | [R] ✅ |
|
||||
|
||||
### srv-dasu
|
||||
|
||||
#### ➡️ - A05 - VM Windows Server (Core)
|
||||
🚀 Inicio del despliegue de una máquina virtual Windows Server Core genérica para operar primariamente como Controlador de Dominio.
|
||||
➡️ **[Continúa en 24/02](2026-02-24.md#A05)**
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 20:33 | 21:05 | Despliegue de VM Windows Server Core (AD DS). Fallo en BIOS. | [R] 🛑 |
|
||||
| 20:57 | 21:05 | Asignación técnica de recursos aprobada (2C/2GB/50GB). | [R] 🧠 |
|
||||
| 20:54 | 21:05 | Descarga automatizada de ISO genuina desde Microsoft. | [R] 🚀 |
|
||||
| 20:33 | 21:05 | Decisión de despliegue Server Core para optimizar recursos. | [R] 🧠 |
|
||||
|
||||
#### ✅ - A02 - Arquitectura srv-dasu
|
||||
🧠 Definición de arquitectura y rol: `srv-dasu` operará como hypervisor Proxmox VE standalone fuera del cluster principal, dedicado exclusivamente a hospedar servidores virtuales para la oficina de DASUTEN. ADN y perfil de nodo inicializados.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 16:40 | 16:50 | Definición de arquitectura standalone srv-dasu. | [P] ✅ |
|
||||
|
||||
#### ✅ - A03 - Relevamiento Hardware srv-dasu
|
||||
👁️ Auditoría técnica inicial post-instalación de Proxmox para asentar CPU, RAM y almacenamiento en el Snapshot del nodo (`nodos/srv-dasu.md`).
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 19:09 | 19:20 | Auditoría técnica y sincronización de ficha de hardware. | [P] ✅ |
|
||||
| 19:09 | 19:20 | Inicio de relevamiento de recursos físicos. | [P] 👁️ |
|
||||
|
||||
#### ✅ - A01 - Instalación Proxmox VE
|
||||
🚀 Preparación de entorno e instalación física de hypervisor Proxmox VE en el nuevo servidor `srv-dasu`.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 16:40 | 19:09 | Instalación física de Proxmox VE y configuración inicial. | [P] ✅ |
|
||||
| 19:05 | 19:09 | Inyección de llaves SSH para administración remota. | [P] 🔧 |
|
||||
| 19:00 | 19:09 | Reparación de enlace físico y cambio a IP 10.0.10.205. | [P] 🟢 |
|
||||
| 18:42 | 19:09 | Diagnóstico de falta de conectividad en nic0. | [P] ⚠️ |
|
||||
| 18:08 | 19:09 | Confirmación de red IP 10.0.10.204. | [P] 🟢 |
|
||||
| 17:48 | 19:09 | Reconfiguración de IP post-instalación (DHCP error). | [P] 🔧 |
|
||||
| 17:30 | 19:09 | Definición de hostname y parámetros root. | [P] 🔧 |
|
||||
| 16:54 | 19:09 | Descarga y preparación de instalador Proxmox VE. | [P] 💾 |
|
||||
| 16:40 | 19:09 | Inicio de tareas y creación de unidad USB booteable. | [P] 🚀 |
|
||||
|
||||
#### ✅ - A00 - Acondicionamiento Hardware
|
||||
🔧 Recepción del servidor físico y acondicionamiento de hardware base para `srv-dasu`.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 16:00 | 16:40 | Acondicionamiento de hardware base (SSD/RAM). | [P] ✅ |
|
||||
| 16:00 | 16:40 | Recepción de servidor y apertura de gabinete. | [P] 🔧 |
|
||||
|
||||
---
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
@@ -1,65 +0,0 @@
|
||||
# Bitácora de Operaciones - 24/02/2026
|
||||
|
||||
## Control de Gestión
|
||||
|
||||
### 🚩 Pendientes
|
||||
| ID | NODO | DETALLE |
|
||||
| :--- | :--- | :--- |
|
||||
| ➡️ - DB01 - **VM SQL Server (Core)** | srv-dasu | ➡️ **[Continúa en 25/02](2026-02-25.md)**<br>Tarea migrada a la bitácora del día siguiente. |
|
||||
| ➡️ - P02 - **Sistema DASUTEN** | srv-dasu | ➡️ **[Continúa en 25/02](2026-02-25.md)**<br>Tarea migrada a la bitácora del día siguiente. |
|
||||
|
||||
### ⏳ En Proceso
|
||||
| ID | NODO | DETALLE |
|
||||
| :--- | :--- | :--- |
|
||||
| *(Sin tareas activas)* | | |
|
||||
|
||||
### 📝 Resumen de Actividades
|
||||
| NODO | RESUMEN INTEGRAL |
|
||||
| :--- | :--- |
|
||||
| **srv-dasu** | Finalización exitosa del despliegue del Controlador de Dominio `dc-dasuten` (AD DS, DNS, ruteo NAT) y cierre del Hito A05. En paralelo, se implementó en producción la refactorización integral del Dashboard P2601 (Hito A06) incorporando telemetría dinámica y justificación de esfuerzo operativo. `[Físico: 0:30]` `[Remoto: ~14 hs]` |
|
||||
| **srv-ns8** | Finalización y verificación administrativa de la sincronización masiva a la nube de todos los respaldos locales mediante el script `dtic-BKPs` (Hito A07). `[Remoto: ~2 hs]` |
|
||||
|
||||
---
|
||||
|
||||
## 📂 Actividades Detalladas
|
||||
|
||||
### srv-ns8
|
||||
|
||||
#### ✅ - A07 - dtic-BKPs Cloud Upload
|
||||
☁️ Retoma del proceso suspendido de carga hacia OneDrive corporativo de la Dirección TIC.
|
||||
➡️ **[Viene del 23/02](2026-02-23.md#A07)**
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 17:32 | 19:32 | Carga masiva a OneDrive (C3) en sesión screen desatendida. | [R] ✅ |
|
||||
| 23:26 | - | Verificación administrativa exitosa del log dtic-BKPs.log. | [R] ✅ |
|
||||
|
||||
### srv-dasu
|
||||
|
||||
#### ✅ - A06 - Dashboard P2601
|
||||
🚀 Refactorización de la capa visual y lógica del Dashboard de proyecto para incorporar métricas de justificación operativa.
|
||||
➡️ **[Viene del 23/02](2026-02-23.md#A06)**
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 10:17 | 10:25 | Refactorización de Dashboard P2601 con telemetría y UI/UX. | [R] ✅ |
|
||||
| 10:17 | 10:25 | Inyección de panel de métricas operativas (glassmorphism). | [R] ✅ |
|
||||
|
||||
#### ✅ - A05 - VM Windows Server (Core)
|
||||
🚀 Inicio del despliegue de una máquina virtual Windows Server Core genérica para operar primariamente como Controlador de Dominio.
|
||||
➡️ **[Viene del 23/02](2026-02-23.md#A05)**
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 09:54 | 23:49 | Despliegue de Windows Server Core y promoción a AD DS. | [R] ✅ |
|
||||
| 23:49 | - | Verificación de conectividad y puente NAT hacia internet. | [R] ✅ |
|
||||
| 21:00 | 22:31 | Promoción a Controlador de Dominio (Install-ADDSForest). | [R] 👑 |
|
||||
| 21:00 | - | Habilitación de ruteo NAT y enmascaramiento en Proxmox. | [R] 🌐 |
|
||||
| 20:16 | 20:34 | Configuración inicial SO, VirtIO y hostname dc-dasuten. | [R] ✅ |
|
||||
| 20:16 | - | Decisión de subred privada segregada (10.0.100.x). | [R] 🧠 |
|
||||
| 19:48 | 20:16 | Selección correcta de método de instalación "Custom". | [R] 👁️ |
|
||||
| 19:28 | 19:48 | Inicio de instalación gráfica vía VNC. | [R] 👁️ |
|
||||
| 09:54 | 09:54 | Arranque exitoso de VM 100 y verificación de BIOS física. | [P] ✅ |
|
||||
|
||||
---
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
@@ -1,70 +0,0 @@
|
||||
# Bitácora de Operaciones - 25/02/2026
|
||||
|
||||
## Control de Gestión
|
||||
|
||||
### 🚩 Pendientes
|
||||
| ID | NODO | DETALLE |
|
||||
| :--- | :--- | :--- |
|
||||
| 📍 - P02 - **Sistema DASUTEN** | sql-dasuten | ➡️ **[Viene del 24/02](2026-02-24.md)**<br>Despliegue e instalación del software del sistema DASUTEN en la VM.<br>➡️ **[Continúa el 26/02](2026-02-26.md)** |
|
||||
|
||||
### ⏳ En Proceso
|
||||
| ID | NODO | DETALLE |
|
||||
| :--- | :--- | :--- |
|
||||
| [⏳ - DB01 - **VM SQL Server (Core)**](#sql-dasuten) | sql-dasuten | ➡️ **[Viene del 24/02](2026-02-24.md)**<br>Despliegue de nueva máquina virtual Windows Server Core genérica para rol de motor de Base de Datos (`sql-dasuten`).<br>➡️ **[Continúa el 26/02](2026-02-26.md)** |
|
||||
|
||||
| NODO | RESUMEN INTEGRAL |
|
||||
| :--- | :--- |
|
||||
| sql-dasuten | Despliegue completo de la VM de base de datos: provisionamiento de instancia, instalación de Windows Server Core, configuración de red aislada, integración al dominio `dasuten.utnlr`, creación de disco dedicado para SQL Server, transferencia de ISO e instalación silenciosa del motor relacional. `[Físico: ~5 hs]` |
|
||||
| srv-ns8 | Reestructuración de servicios web: migración del gestor de archivos TFM a `apps`, alta de credenciales y ampliación de límites de carga para facilitar la transferencia de ISOs pesadas. `[Remoto: ~1 hs]` |
|
||||
|
||||
---
|
||||
|
||||
## 📂 Actividades Detalladas
|
||||
|
||||
### srv-ns8
|
||||
|
||||
#### ✅ - A06 - Dashboard P2601
|
||||
🚀 Despliegue de métricas web, reestructuración estructural, y evolución de los servicios core expuestos (Apps).
|
||||
➡️ **[Viene del 19/02](2026-02-19.md)**
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 18:55 | 19:51 | Reestructuración de servicios: migración TFM a apps. | [R] ✅ |
|
||||
| 19:51 | - | Optimización de capacidad de subida (10GB) para ISOs. | [R] ☁️ |
|
||||
| 19:11 | - | Alta de credenciales utnlr y permisos de escritura. | [R] 🔑 |
|
||||
| 18:55 | - | Migración de alias tfm a apps y ajuste de Docker/Nginx. | [R] 🔀 |
|
||||
|
||||
### sql-dasuten
|
||||
|
||||
#### ⏳ - DB01 - VM SQL Server (Core)
|
||||
🚀 Despliegue de nueva máquina virtual Windows Server Core genérica para rol de motor de Base de Datos (`sql-dasuten`).
|
||||
➡️ **[Viene del 24/02](2026-02-24.md)** | ➡️ **[Continúa el 26/02](2026-02-26.md)**
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 16:00 | 20:41 | Despliegue de VM sql-dasuten e instalación de SQL Server. | [P] ✅ |
|
||||
| 20:41 | - | Inyección lateral de carga útil (VNC Bypass) vía iwr. | [P] 💉 |
|
||||
| 20:31 | - | Instalación desatendida de SQL Server (SQLEngine). | [P] ⚙️ |
|
||||
| 20:16 | - | Resguardo integral de infraestructura vía vzdump (ZSTD). | [P] 🛡️ |
|
||||
| 20:07 | - | Transferencia SCP de imagen ISO SQL Server a Proxmox. | [P] 💿 |
|
||||
| 18:36 | - | Exploración de repositorio de plantillas ISO vía SSH. | [P] 👁️ |
|
||||
| 18:35 | - | Aprovisionamiento de disco dedicado VirtIO SCSI (100GB). | [P] 💾 |
|
||||
| 17:51 | - | Integración al dominio dasuten.utnlr vía SConfig. | [P] 👑 |
|
||||
| 17:43 | - | Configuración de red 10.0.100.11 e inyección DNS. | [P] 🟢 |
|
||||
| 17:31 | - | Finalización OS base y hostname sql-dasuten. | [P] ✅ |
|
||||
| 17:14 | - | Inicio de instalación interactiva vía consola VNC. | [P] 👁️ |
|
||||
| 17:01 | - | Aprovisionamiento de instancia VM 101 vía SSH (Proxmox). | [P] 🚀 |
|
||||
| 16:00 | - | Inicio de jornada presencial e investigación arquitectónica. | [P] 👁️ |
|
||||
|
||||
**Justificación Arquitectónica: Windows Server Core + SQL Server 2019**
|
||||
La decisión técnica de desplegar SQL Server 2019 sobre una variante *Server Core* (sin entorno gráfico/Desktop Experience) se sustenta en tres pilares operacionales críticos para el ecosistema DASUTEN:
|
||||
|
||||
1. **Minimización de Superficie de Ataque (Security by Design)**
|
||||
Al carecer de GUI (Explorador, IE/Edge, utilidades gráficas), Server Core elimina componentes que tradicionalmente son vectores de vulnerabilidad. Para un motor de base de datos que albergara información sensible, esta hiper-reducción del SO base reduce drásticamente la exposición a malware y la necesidad de parches de seguridad continuos.
|
||||
2. **Eficiencia y Asignación Directa de Recursos (Performance)**
|
||||
El entorno gráfico de Windows Server consume sostenidamente entre 800MB y 1.5GB de memoria RAM por ocioso, más ciclos de CPU para renderizado. Al utilizar Server Core, **el 100% de la RAM (`4GB` iniciales) y los procesadores quedan dedicados íntegramente al motor del SQL Server** (`sqlservr.exe`). Esto garantiza un alto hit-ratio en la caché de consultas y menor latencia en las transacciones de las PCs cliente.
|
||||
3. **Escalabilidad y Compatibilidad Estable**
|
||||
SQL Server 2019 es la versión madura y más probada en entornos empresariales recientes, asegurando retrocompatibilidad total con el "Sistema DASUTEN" (P02) sin los altos requisitos de hardware de SQL 2022. La administración no se degrada: la instancia se gestionará de manera moderna, remota y centralizada utilizando *SQL Server Management Studio (SSMS)* desde las estaciones de trabajo cliente, manteniendo el servidor servidor de BD ciego y blindado.
|
||||
|
||||
---
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
@@ -1,95 +0,0 @@
|
||||
# Bitácora de Operaciones - 26/02/2026
|
||||
|
||||
## Control de Gestión
|
||||
|
||||
### 🚩 Pendientes
|
||||
| ID | NODO | DETALLE |
|
||||
| :--- | :--- | :--- |
|
||||
| 📍 - P02 - **Sistema DASUTEN** | sql-dasuten | ➡️ **[Viene del 25/02](2026-02-25.md)**<br>Despliegue e instalación del software del sistema DASUTEN en la VM. |
|
||||
|
||||
### ⏳ En Proceso
|
||||
| ID | NODO | DETALLE |
|
||||
| :--- | :--- | :--- |
|
||||
| [⏳ - DB01.2 - **Reconstrucción Capa OS (Español)**](#sql-dasuten) | sql-dasuten | Despliegue de ISO Nativa en Español de Server 2022 y bypass de controladoras SATA para evitar bloqueos del BIOS virtual. Instalación en progreso. |
|
||||
|
||||
### ⚠️ Abortados / Suspendidos
|
||||
| ID | NODO | DETALLE |
|
||||
| :--- | :--- | :--- |
|
||||
| [⚠️ - DB01.1 - **Troubleshooting Localización (Core)**](#sql-dasuten) | sql-dasuten | ➡️ **[Viene del 25/02](2026-02-25.md)**<br>Esfuerzo matutino: Intentos fallidos de forzar SQL Español sobre Server Core Inglés (Errores registro/kernel). Se aborta por inviabilidad estructural. |
|
||||
### 📝 Resumen de Actividades
|
||||
| NODO | RESUMEN INTEGRAL |
|
||||
| :--- | :--- |
|
||||
| sql-dasuten | **Operación Exitosa: Motor SQL y Capa de Gestión Nativa.** Se completó la reconstrucción integral del nodo en Español (Windows Server 2022 Core), solventando los bloqueos de localización (`es-AR`/`es-ES`). Se desplegó SQL Server 2019 Enterprise de forma desatendida en la unidad `S:\`. Se habilitó OpenSSH nativo permitiendo el gobierno directo del nodo. Se generó resguardo (VZDump) del sistema base pre-DASUTEN. |
|
||||
| **Repositorio** | **Sincronización Total.** Se formalizaron las Premisas de Trabajo de la IA en el ADN (`02_protocolo.md`), se implementó la bóveda de secretos AES-256-GCM y se realizó el resguardo final de la jornada en la rama principal. |
|
||||
|
||||
---
|
||||
|
||||
## 📂 Actividades Detalladas
|
||||
|
||||
### srv-ns8
|
||||
|
||||
#### ✅ - S01 - Implementación de Bóveda de Secretos para IA
|
||||
🔧 Desarrollo de un mecanismo automatizado y seguro para el consumo de credenciales por parte de la Inteligencia Artificial sin exposición en texto plano.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 12:45 | 13:00 | Creación de secret_box.rb y cifrado AES-256-GCM. | [R] ✅ |
|
||||
| 13:00 | - | Documentación e integración al ADN (Sección 10). | [R] ✅ |
|
||||
|
||||
### sql-dasuten
|
||||
|
||||
#### ⏳ - DB01.2 - Re-despliegue de Capa OS (Español)
|
||||
🚀 Pivote arquitectónico y reconstrucción desde cero de la máquina virtual (sql-dasuten) utilizando medios de instalación nativos en Español (ES-ES) mediante controladoras SATA.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 13:28 | 16:00 | Reconstrucción integral de sql-dasuten en Español. | [R] ⏳ |
|
||||
| 16:00 | - | Habilitación de OpenSSH nativo y gobierno directo. | [R] ⏳ |
|
||||
| 15:22 | - | Culminación exitosa de despliegue SQL Server 2019. | [R] ✅ |
|
||||
| 15:18 | - | Despliegue de SQL Server en segundo plano (S:\). | [R] ✅ |
|
||||
| 15:15 | - | Resolución de conflictos locales (es-AR vs es-ES). | [R] ⏳ |
|
||||
| 15:10 | - | Refinamiento de C2 Launcher y pausa analítica. | [R] ⏳ |
|
||||
| 15:02 | - | Corrección estructural de almacenamiento SQL (letra S:\). | [R] ✅ |
|
||||
| 14:31 | - | Bypass de controladora SATA AHCI nativo. | [R] ⏳ |
|
||||
| 14:20 | - | Instalación interactiva de Capa OS (Presencial). | [P] ⏳ |
|
||||
| 13:28 | - | Reconstrucción autónoma vía Bóveda de Secretos e ISO ES. | [R] ⏳ |
|
||||
| 12:32 | - | Pivot Arquitectónico: Reinstalación en Español nativo. | [R] ⏳ |
|
||||
|
||||
#### ⚠️ - DB01.1 - Troubleshooting de Localización y C2 (Abortado)
|
||||
⚠️ Intento fallido de adaptar una ISO de Windows Server Core (Inglés) a un requerimiento estricto de SQL Server (Español) inyectando telemetría C2 y parches en el registro. Abandonado por inviabilidad del Kernel.
|
||||
➡️ **[Viene del 25/02](2026-02-25.md)**
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 10:25 | 11:38 | Troubleshooting de Localización y C2 (Abortado). | [R] ⚠️ |
|
||||
| 11:38 | - | Suspensión de CommitsIA y fin de bucle de reinicios. | [R] ⏳ |
|
||||
| 11:33 | - | Aclaración arquitectónica del ciclo de vida C2. | [R] ⏳ |
|
||||
| 11:28 | - | Diagnóstico de Deadlock y reinicio manual de VM. | [R] ⏳ |
|
||||
| 11:16 | - | Inyección de parche de registro y reinicio mandatorio. | [R] ✅ |
|
||||
| 11:08 | - | Diseño de Bucle C2 de doble capa (Launcher Zombie). | [R] ⏳ |
|
||||
| 11:00 | - | Despliegue de parche de localización y autómatas. | [R] ✅ |
|
||||
| 10:54 | - | Despliegue de bucle operativo C2 Automation. | [R] ⏳ |
|
||||
| 10:49 | - | Ejecución de sonda diagnóstica de Localización. | [R] ✅ |
|
||||
| 10:38 | - | Análisis de error setup.exe (InvalidPlatformOSLanguage). | [R] ✅ |
|
||||
| 10:33 | - | Inyección SQL con telemetría (Fallo prematuro). | [R] ❌ |
|
||||
| 10:25 | - | Implementación de Telemetría v2 (Python logger). | [R] ✅ |
|
||||
|
||||
### Operaciones Centrales
|
||||
|
||||
#### 👁️ - SINC01 - Sincronización Operativa
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 09:00 | 20:25 | Operaciones centrales y sincronización presencial/remota. | [P/R] ✅ |
|
||||
| 20:25 | - | Resguardo final del repositorio Git (Commit/Push). | [R] ✅ |
|
||||
| 18:20 | - | Intento de recuperación de VZDump DB01 (Migrado). | [R] ➡️ |
|
||||
| 17:28 | - | Creación de usuario rmonla@pve en Proxmox. | [R] ✅ |
|
||||
| 17:15 | - | Resguardo Integral Offline (Fallo parcial VM 101). | [R] ⚠️ |
|
||||
| 16:50 | - | Verificación exitosa de conectividad SSH en ambos nodos. | [R] ✅ |
|
||||
| 16:35 | - | Estrategia de Tunneling LPF hacia red 10.0.100.x. | [R] 👁️ |
|
||||
| 16:31 | - | Inicio de verificación SSH utilizando secret_box. | [R] 👁️ |
|
||||
| 15:55 | - | Inicio de sincronización remota (VPN/Anydesk). | [R] 👁️ |
|
||||
| 15:20 | - | Finalización de guardia física. | [P] 👁️ |
|
||||
| 09:00 | - | Inicio de sincronización presencial y rollover bitácora. | [P] 👁️ |
|
||||
|
||||
---
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
@@ -1,65 +0,0 @@
|
||||
# Bitácora de Operaciones - 27/02/2026
|
||||
|
||||
## Control de Gestión
|
||||
|
||||
### 🚩 Pendientes
|
||||
| ID | NODO | DETALLE |
|
||||
| :--- | :--- | :--- |
|
||||
| [📍 - P02 - **Sistema DASUTEN**](#sql-dasuten) | sql-dasuten | ➡️ **[Viene del 26/02](2026-02-26.md)**<br>Despliegue e instalación del software del sistema DASUTEN en la VM con la base de datos operativa. |
|
||||
| [📍 - S02 - **Hardenización SSH**](#sql-dasuten) | sql-dasuten | Hardening de OpenSSH Server (deshabilitación de password, llaves asimétricas con passphrases y auditoría). |
|
||||
|
||||
### ✅ Completados
|
||||
| ID | NODO | DETALLE |
|
||||
| :--- | :--- | :--- |
|
||||
| [✅ - TEST01 - **VM de Pruebas (pcv-dasu0)**](#pcv-dasu0) | pcv-dasu0 | Win 10 LTSC instalado, SSH habilitado, unida al dominio `dasuten.utnlr`. Login con `admindasu` verificado. |
|
||||
|
||||
### 📝 Resumen de Actividades
|
||||
| NODO | RESUMEN INTEGRAL |
|
||||
| :--- | :--- |
|
||||
| pcv-dasu0 | VM 102 desplegada: Win 10 LTSC, SSH, unida a `dasuten.utnlr`. Toolkit W-Zombi refactorizado en Ruby. |
|
||||
| Operaciones | ADN multi-hebra (8 hebras), armonización de 5 bitácoras, bóveda consolidada en `scripts/seguridad/`. Dashboard P2601 actualizado. `[Remoto: 6:30]` |
|
||||
|
||||
---
|
||||
|
||||
## 📂 Actividades Detalladas
|
||||
|
||||
### pcv-dasu0
|
||||
|
||||
#### ⏳ - TEST01 - Despliegue de VM de Pruebas (Win 10 LTSC)
|
||||
🚀 Creación de VM Windows 10 LTSC para validar dominio y sistema DASUTeN antes de configurar la PC física `pc-dasu0`.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 19:50 | 22:42 | Despliegue y validación de pcv-dasu0 en el dominio. | [R] ✅ |
|
||||
| 22:05 | 22:42 | Creación de admindasu y unión al dominio (W-Zombi). | [R] ✅ |
|
||||
| 21:45 | 22:42 | Instalación de OpenSSH Server nativo (Puerto 22). | [R] ✅ |
|
||||
| 21:16 | 22:42 | Instalación de SO LTSC, hostname y red estática. | [R] ✅ |
|
||||
| 20:45 | 22:42 | Fix de drivers VirtIO SCSI a SATA para instalación. | [R] 🐛 |
|
||||
| 20:35 | 22:42 | Aprovisionamiento desatendido de VM 102 vía SCP. | [R] ✅ |
|
||||
| 19:50 | 22:42 | Descarga de ISO Win 10 LTSC 2021 Eval (es-ES). | [R] ✅ |
|
||||
|
||||
### sql-dasuten
|
||||
|
||||
#### ✅ - DB01.3 - Finalización de Resguardo Integral (Manual)
|
||||
🛡️ Confirmación de cierre del backup de la VM 101 que había quedado interactuando en bloqueos de script.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 16:15 | - | Finalización de VZDump Manual (GUI) de sql-dasuten. | [R] ✅ |
|
||||
|
||||
### Operaciones Centrales
|
||||
|
||||
#### 👁️ - SINC02 - Sincronización de Inicio de Jornada
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 16:13 | 20:35 | Operaciones centrales y sincronización de jornada. | [R] ✅ |
|
||||
| 20:35 | - | Aprovisionamiento desatendido de VM 102 (pcv-dasu0). | [R] ✅ |
|
||||
| 19:50 | - | Descarga de ISO Win 10 LTSC (4.6G, es-ES). | [R] ✅ |
|
||||
| 18:58 | - | Despliegue de pcv-dasu0 y actualización de manifiesto. | [R] ✅ |
|
||||
| 18:33 | - | Extensión del ADN: Ruby y hebra de Proyectos (07). | [R] ✅ |
|
||||
| 18:15 | - | Armonización integral de bitácoras históricas. | [R] ✅ |
|
||||
| 17:40 | - | Refactorización del ADN a Arquitectura Multi-Hebra. | [R] ✅ |
|
||||
| 16:13 | - | Inicio de sincronización remota y reporte de backup. | [R] 👁️ |
|
||||
|
||||
---
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
@@ -1,69 +0,0 @@
|
||||
# Bitácora de Operaciones - 28/02/2026
|
||||
|
||||
## Control de Gestión
|
||||
|
||||
### 🚩 Pendientes
|
||||
| ID | NODO | DETALLE |
|
||||
| :--- | :--- | :--- |
|
||||
| [➡️ - P02 - **Sistema DASUTEN**](2026-03-02.md) | sql-dasuten | ➡️ **[Continúa el 02/03](2026-03-02.md)**<br>Despliegue e instalación del software del sistema DASUTEN en la VM con la base de datos operativa. |
|
||||
| [➡️ - S02 - **Hardenización SSH**](2026-03-02.md) | sql-dasuten | ➡️ **[Continúa el 02/03](2026-03-02.md)**<br>Hardening de OpenSSH Server (deshabilitación de password, llaves asimétricas con passphrases y auditoría). |
|
||||
| [➡️ - TEST03 - **Conectividad SQL**](2026-03-02.md) | pcv-dasu0 | ➡️ **[Continúa el 02/03](2026-03-02.md)**<br>Pruebas de acceso al motor SQL Server desde la VM de pruebas. Validar que el sistema DASUTEN funcione desde el cliente. |
|
||||
|
||||
### ⏳ En Proceso
|
||||
| ID | NODO | DETALLE |
|
||||
| :--- | :--- | :--- |
|
||||
| [✅ - SEC01 - **Refactorización ns8-candados**](#srv-ns8) | srv-ns8 | Unificación de scripts de seguridad en `tools/ns8-candados/`. |
|
||||
| [✅ - BKP01 - **Refactorización ns8-bkps**](#srv-ns8) | srv-ns8 | Refactorización de `dtic-BKPs` → `ns8-bkps` v6.0 modular. |
|
||||
| [⏳ - P2602 - **Proyecto Backups DTIC**](#srv-ns8) | srv-ns8 | Creación del proyecto P2602 — Automatización de Backups. Fase 1: Reconocimiento. |
|
||||
|
||||
### 📝 Resumen de Actividades
|
||||
| NODO | RESUMEN INTEGRAL |
|
||||
| :--- | :--- |
|
||||
| srv-ns8 | 🔐 SEC01: Refactorización ns8-candados ✅. ⚙️ BKP01: Refactorización ns8-bkps v6.0 ✅. 🚀 **P2602 Fase 1** (Reconocimiento): SSH desplegado a 12/15 nodos (9 Linux + 3 Windows). Puerto 7022 hardening en VMs Windows. Inventario auditado: 15 guests a respaldar en 4 hipervisores (pmox1/2/3 + xen1). 3 pendientes: pcv-dasu1/2, pcv-serviio. |
|
||||
|
||||
---
|
||||
|
||||
## 📂 Actividades Detalladas
|
||||
|
||||
### srv-ns8
|
||||
|
||||
#### ✅ - SEC01 - Refactorización ns8-candados
|
||||
🔐 Unificación de `candado.rb`, `secret_box.rb` y `.agent_secrets.json` en una sola herramienta Ruby `ns8-candados.rb`.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 08:00 | 08:34 | Refactorización ns8-candados. Unificación de scripts. | [P] ✅ |
|
||||
|
||||
#### ✅ - BKP01 - Refactorización ns8-bkps
|
||||
⚙️ Refactorización de `dtic-BKPs` v5.5.1 a `ns8-bkps` v6.0 con arquitectura modular.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 08:34 | 08:57 | Refactorización ns8-bkps v6.0 modular. | [P] ✅ |
|
||||
|
||||
#### ⏳ - P2602 - Proyecto Automatización de Backups
|
||||
🚀 Definición del proyecto P2602: automatizar backups vzdump vía SSH a pool Proxmox (pmox1/2/3).
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 09:46 | 19:19 | Proyecto P2602: Automatización de Backups DTIC. | [P/R] ⏸️ |
|
||||
| 19:11 | 19:19 | OpenSSH en srvv-sysacadweb (Win 2008R2) legacy. | [R] ✅ |
|
||||
| 17:25 | 17:38 | SSH Port Hardening: Puerto 7022 en Fenix/Maurik. | [R] ✅ |
|
||||
| 11:06 | 11:27 | OpenSSH en srvv-fenix y srvv-maurik vía w-zombi. | [P] ✅ |
|
||||
| 11:00 | - | XenServer agregado a P2602 (15 guests total). | [P] ⏳ |
|
||||
| 10:52 | - | Hostname VM 102 corregido a srvv-SITIO0. | [P] ⏳ |
|
||||
| 10:29 | 10:45 | Despliegue SSH a 9 nodos Linux sin contraseña. | [P] ✅ |
|
||||
| 10:22 | - | Fase 1 — R01 SSH a VMs pmox1. Solo SITIO OK. | [P] ⏳ |
|
||||
| 10:18 | - | Fase 1 — R02 Inventario real (16 guests). | [P] ⏳ |
|
||||
| 10:10 | 10:16 | Fase 1 — R01 SSH a hipervisores (funcional). | [P] ⏳ |
|
||||
| 09:46 | 10:11 | Creación del manifiesto P2602 (Proyectos). | [P] ⏳ |
|
||||
|
||||
### Operaciones Centrales
|
||||
|
||||
#### 👁️ - SINC01 - Sincronización de Inicio de Jornada
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 08:17 | - | Inicio de Jornada Presencial y sincronización de contexto. | [P] 👁️ |
|
||||
|
||||
---
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
@@ -1,30 +0,0 @@
|
||||
# Bitácora de Operaciones - 01/03/2026
|
||||
|
||||
## Control de Gestión
|
||||
|
||||
### ⏳ En Proceso
|
||||
| ID | NODO | DETALLE |
|
||||
| :--- | :--- | :--- |
|
||||
| [➡️ - P2602 - **Proyecto Backups DTIC**](2026-03-02.md) | srv-ns8 | ➡️ **[Continúa el 02/03](2026-03-02.md)**<br>Fase 1: Reconocimiento. SSH 12/15 ✅. Pendiente: pcv-dasu1/2, pcv-serviio (Windows pmox2). |
|
||||
|
||||
### 📝 Resumen de Actividades
|
||||
| NODO | RESUMEN INTEGRAL |
|
||||
| :--- | :--- |
|
||||
| srv-ns8 | 🚀 **P2602 Fase 1** (cont.): Completando despliegue SSH a 3 VMs Windows restantes en pmox2. |
|
||||
|
||||
---
|
||||
|
||||
## 📂 Actividades Detalladas
|
||||
|
||||
### srv-ns8
|
||||
|
||||
#### ➡️ - P2602 - Proyecto Automatización de Backups (cont.)
|
||||
🚀 Continuación Fase 1: Despliegue SSH a VMs Windows de pmox2.
|
||||
➡️ **[Continúa el 02/03](2026-03-02.md)**
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 12:42 | - | Inicio sesión remota y sincronización de contexto. | [R] 👁️ |
|
||||
|
||||
---
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
@@ -1,83 +0,0 @@
|
||||
# Bitácora de Operaciones - 02/03/2026
|
||||
|
||||
## Control de Gestión
|
||||
|
||||
### 🚩 Pendientes
|
||||
| ID | NODO | DETALLE |
|
||||
| :--- | :--- | :--- |
|
||||
| [📍 - P02 - **Sistema DASUTEN**](#sql-dasuten) | sql-dasuten | ➡️ **[Viene del 28/02](2026-02-28.md)**<br>Despliegue e instalación del software del sistema DASUTEN en la VM con la base de datos operativa. |
|
||||
| [📍 - S02 - **Hardenización SSH**](#sql-dasuten) | sql-dasuten | ➡️ **[Viene del 28/02](2026-02-28.md)**<br>Hardening de OpenSSH Server (deshabilitación de password, llaves asimétricas con passphrases y auditoría). |
|
||||
| [📍 - TEST03 - **Conectividad SQL**](#pcv-dasu0) | pcv-dasu0 | ➡️ **[Viene del 28/02](2026-02-28.md)**<br>Pruebas de acceso al motor SQL Server desde la VM de pruebas. Validar que el sistema DASUTEN funcione desde el cliente. |
|
||||
|
||||
### ⏳ En Proceso
|
||||
| ID | NODO | DETALLE |
|
||||
| :--- | :--- | :--- |
|
||||
| [⏳ - BK01 - **Backup SQL DASUTEN**](#srvv-fenix) | srvv-fenix → sql-dasuten | Transferencia del backup `bksysdasuten_Full` (~8.6 GB) completada y verificada. |
|
||||
| [⏳ - P2602 - **Proyecto Backups DTIC**](#srv-ns8) | srv-ns8 | ➡️ **[Viene del 01/03](2026-03-01.md)**<br>Fase 1: Reconocimiento. SSH 12/15 ✅. Pendiente: pcv-dasu1/2, pcv-serviio (Windows pmox2). |
|
||||
|
||||
### 📝 Resumen de Actividades
|
||||
| NODO | RESUMEN INTEGRAL |
|
||||
| :--- | :--- |
|
||||
| srvv-fenix | Inicio de transferencia del backup SQL DASUTEN (`bksysdasuten_Full`, ~8.6 GB) hacia `sql-dasuten` vía srv-ns8 como intermediario para el proyecto P2601. |
|
||||
| pc-dasu0 | Resolución de incidente de conectividad reportado por Andrea ALMIRON. Verificación de nodos y servidores sin hallazgos internos; causa atribuida a microcortes del ISP. |
|
||||
| srv-ns8 | Dos jornadas presenciales (09:00-13:00 y 16:00-21:00). Rollover completado. Integración de API DeepSeek validada. Gestión de clases POSG.EMIA completada (`youtu.be/RWF8dmJbgaM`). |
|
||||
|
||||
---
|
||||
|
||||
## 📂 Actividades Detalladas
|
||||
|
||||
### srvv-fenix
|
||||
|
||||
#### ⏳ - BK01 - Backup SQL DASUTEN
|
||||
📦 Copia del backup de la base de datos del sistema DASUTEN desde `srvv-fenix` (`E:\BK_SQL\02-03-26\bksysdasuten_Full`, ~8.6 GB) hacia `sql-dasuten` (10.0.100.11). Se usa `srv-ns8` como intermediario ya que ambos nodos están en redes aisladas.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 17:03 | 18:05 | Backup SQL DASUTEN: Fenix -> NS8 -> Dasuten. | [R] ✅ |
|
||||
| 18:00 | 18:05 | Carga SCP final srv-dasu (host) -> sql-dasuten. | [R] ✅ |
|
||||
| 17:58 | - | Instalación de OpenSSH y habilitación puerto 22. | [R] ✅ |
|
||||
| 17:53 | - | Activación de w-zombi para inyección lateral. | [R] ✅ |
|
||||
| 17:40 | - | Intento de carga directa (Fallo por red/túnel). | [R] ❌ |
|
||||
| 17:09 | 17:34 | Descarga SCP srvv-fenix -> srv-ns8 (Paso 1). | [R] ✅ |
|
||||
| 17:03 | - | Verificación de backup Full (8.64 GB) en Fenix. | [R] ✅ |
|
||||
|
||||
### pc-dasu0
|
||||
|
||||
#### ✅ - SOP01 - Soporte Conectividad pc-dasu0
|
||||
🛠️ Atención presencial a Andrea ALMIRON por problemas de conexión intermitente a `pcv-dasu1`. Tras verificar nodos y servidores, se descarta falla interna y se determina que la causa son microcortes del proveedor de internet (ISP).
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 09:00 | 10:00 | Soporte Andrea ALMIRON: Causa microcortes ISP. | [P] ✅ |
|
||||
|
||||
### srv-ns8
|
||||
|
||||
#### ✅ - DIGI01 - Gestión de Clases Grabadas POSG.EMIA
|
||||
📂 Procesamiento de clases grabadas del fin de semana. El procedimiento implica la verificación en la planilla `dtic-DIGI` y la descarga de los archivos de Zoom para su posterior publicación en la playlist correspondiente en YouTube.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 19:50 | 20:35 | Gestión de clases EMIA y Nota de Horas Extras. | [P] ✅ |
|
||||
| 20:35 | - | Redacción de Nota-2601_HorasExtras para RRHH. | [P] ✅ |
|
||||
| 19:50 | 20:11 | Procesamiento y subida a YouTube de clase EMIA. | [P] ✅ |
|
||||
|
||||
#### ⏳ - SINC02 - Sincronización de Jornada Vespertina
|
||||
🚀 Inicio de Jornada Presencial Vespertina (16:00 - 21:00). Continuación del proyecto P2601 DASUTEN y operaciones generales.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 16:00 | 21:00 | Operaciones centrales (DeepSeek / SINC02). | [P/R] ✅ |
|
||||
| 16:00 | 16:05 | Integración DeepSeek: llave y test de conectividad. | [R] ✅ |
|
||||
| 16:00 | - | Inicio sesión presencial vespertina. | [P] 👁️ |
|
||||
|
||||
#### ✅ - SINC01 - Sincronización de Inicio de Jornada
|
||||
🚀 Inicio de Jornada Presencial Matutina (09:00 - 13:00). Sincronización de contexto con ADN, bitácoras previas y Proyecto P2601.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 09:00 | 13:00 | Sincronización de inicio y Rollover de bitácora. | [P] ✅ |
|
||||
| 09:00 | 10:02 | Rollover 2026-03-02 y migración de pendientes. | [P] ✅ |
|
||||
| 09:00 | - | Inicio sesión presencial matutina. | [P] 👁️ |
|
||||
|
||||
---
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
@@ -1,234 +0,0 @@
|
||||
# Bitácora 2026-03-06
|
||||
|
||||
## 🏢 Jornada Laboral Presencial
|
||||
**Horario:** 08:00 - 13:00
|
||||
**Modalidad:** Presencial en oficina
|
||||
**Inicio registrado:** 10:14 AM
|
||||
**Responsable:** rmonla
|
||||
|
||||
### 🎯 Objetivos del Día
|
||||
1. Verificar funcionamiento del nodo srv-ns8
|
||||
2. Acceder y revisar dashboard: ns8.frlr.utn.edu.ar/bitacoras/p2601
|
||||
3. Crear plan de trabajo específico para hoy
|
||||
4. Continuar implementación del Plan ADN BITACORAs
|
||||
|
||||
### 📋 Plan de Trabajo Hoy
|
||||
#### Mañana (08:00-10:00) ✓
|
||||
- [x] Verificación inicial del sistema
|
||||
- [x] Revisión del dashboard
|
||||
- [x] Planificación del día
|
||||
|
||||
#### Media Mañana (10:00-13:00)
|
||||
- [ ] Implementación tareas ADN BITACORAs
|
||||
- [ ] Seguimiento del progreso del plan
|
||||
- [ ] Registro de actividades en bitácora
|
||||
|
||||
### 🔍 Verificación del Nodo srv-ns8
|
||||
**Dashboard:** ns8.frlr.utn.edu.ar/bitacoras/p2601
|
||||
**Estado:** ✅ Funcionando correctamente
|
||||
**Observaciones:** Dashboard accesible vía HTTPS (código 200 OK). Aplicación React/Vite en ejecución. Redirección HTTP → HTTPS configurada.
|
||||
|
||||
### 📊 Progreso ADN BITACORAs (Estado Actual)
|
||||
**Progreso general:** 38% completado (24/62 tareas)
|
||||
**Fase actual:** FASE 2 - Herramientas CLI Avanzadas (50% completada)
|
||||
**Próximas tareas prioritarias:**
|
||||
1. **2.2:** Sistema de búsqueda y filtrado
|
||||
2. **2.4:** Pruebas unitarias para operaciones BD
|
||||
3. **2.5:** Documentación de instalación y configuración
|
||||
4. **3.6:** Autocompletado para comandos CLI
|
||||
5. **4.2:** Monitor de cambios en BD
|
||||
|
||||
**Fecha estimada de finalización:** 14 de marzo de 2026
|
||||
|
||||
### ✅ Verificación Técnica Completada
|
||||
- **Dashboard srv-ns8:** ✅ Accesible y funcionando
|
||||
- **Protocolo:** HTTPS activo (redirección automática desde HTTP)
|
||||
- **Tecnología:** React + Vite + TypeScript
|
||||
- **Servidor:** nginx/1.22.1
|
||||
- **Conexión:** Estable y rápida
|
||||
|
||||
### 📊 Análisis de Esquema para Búsqueda (Tarea 2.2)
|
||||
**Estado:** ✅ COMPLETADO
|
||||
**Archivo generado:** `tools/analizar_esquema_busqueda.rb`
|
||||
|
||||
#### 📋 Estructura de Base de Datos:
|
||||
- **Nodos:** 14 registros (servidores, VMs, PCs)
|
||||
- **Bitácoras:** 15 registros (bitácoras diarias)
|
||||
- **Temas:** 49 registros (agrupadores por nodo)
|
||||
- **Entradas:** 112 registros (actividades cronológicas)
|
||||
- **Total:** 190 registros migrados
|
||||
|
||||
#### 🔍 Campos para Búsqueda Identificados:
|
||||
1. **Full-text search:**
|
||||
- `entradas.descripcion` (texto libre de actividades)
|
||||
- `temas.descripcion` (descripción de temas)
|
||||
- `nodos.descripcion` (descripción de nodos)
|
||||
- `bitacoras.resumen` (resumen diario)
|
||||
|
||||
2. **Filtrado por atributos:**
|
||||
- `entradas.estado` (⏳, ✅, ❌, ⚠️, ⏸️)
|
||||
- `entradas.modo` (P=Presencial, R=Remoto)
|
||||
- `entradas.inicio/fin` (rango horario)
|
||||
- `bitacoras.fecha` (rango de fechas)
|
||||
- `nodos.tipo` (servidor, vm, pc)
|
||||
|
||||
#### 🏗️ Arquitectura Propuesta:
|
||||
- **Clase BuscadorBD:** Lógica central de búsqueda
|
||||
- **Clase FiltrosBD:** Sistema de filtrado avanzado
|
||||
- **Comandos CLI:** `adn db buscar:entradas`, `adn db filtrar:entradas`
|
||||
- **Optimización:** 11 índices PostgreSQL recomendados
|
||||
- **Rendimiento:** Meta < 500ms para 10k registros
|
||||
|
||||
#### 🚀 Próximo Paso:
|
||||
Implementación de `BuscadorBD` en `tools/bitacoras-db/core/buscador_bd.rb`
|
||||
|
||||
---
|
||||
|
||||
## 📋 Control de Gestión
|
||||
|
||||
### Pendientes
|
||||
|
||||
| ID | Nodo | Detalle |
|
||||
| :--- | :--- | :--- |
|
||||
|
||||
### En Proceso
|
||||
|
||||
| ID | Nodo | Detalle |
|
||||
| :--- | :--- | :--- |
|
||||
|
||||
### Resumen de Actividades
|
||||
|
||||
| Nodo | Resumen Integral |
|
||||
| :--- | :--- |
|
||||
|
||||
---
|
||||
|
||||
## 📝 Actividades Detalladas
|
||||
|
||||
### 🕐 10:15 AM - Inicio de registro en bitácora
|
||||
- **Nodo:** srv-ns8
|
||||
- **Actividad:** Configuración de bitácora diaria para jornada presencial
|
||||
- **Detalle:** Creación de estructura de registro para el día 2026-03-06 con horario 08:00-13:00
|
||||
- **Estado:** ✅ Completado
|
||||
|
||||
### 🕐 10:20 AM - Verificación del dashboard srv-ns8
|
||||
- **Nodo:** srv-ns8
|
||||
- **Actividad:** Acceso a dashboard ns8.frlr.utn.edu.ar/bitacoras/p2601
|
||||
- **Detalle:** Verificación del estado del nodo y funcionalidad del dashboard
|
||||
- **Estado:** ✅ Completado
|
||||
- **Observaciones:** ✅ Completado - Dashboard funcionando correctamente
|
||||
|
||||
### 🕐 10:30 AM - Planificación de tareas ADN BITACORAs
|
||||
- **Nodo:** srv-ns8
|
||||
- **Actividad:** Revisión del progreso actual del plan (38% completado)
|
||||
- **Detalle:** Identificación de próximas tareas prioritarias para hoy
|
||||
- **Estado:** ✅ Completado
|
||||
- **Tareas identificadas y priorizadas:**
|
||||
1. **Alta prioridad:** Sistema de búsqueda y filtrado (2.2)
|
||||
2. **Media prioridad:** Pruebas unitarias para operaciones BD (2.4)
|
||||
3. **Media prioridad:** Documentación de instalación (2.5)
|
||||
4. **Baja prioridad:** Autocompletado para comandos CLI (3.6)
|
||||
5. **Baja prioridad:** Monitor de cambios en BD (4.2)
|
||||
|
||||
### 🕐 10:45 AM - Análisis de esquema para sistema de búsqueda (Tarea 2.2)
|
||||
- **Nodo:** srv-ns8
|
||||
- **Actividad:** Análisis completo del esquema de base de datos dtic-BITACORAs
|
||||
- **Detalle:** Desarrollo de script de análisis para diseñar sistema de búsqueda
|
||||
- **Estado:** ✅ Completado
|
||||
- **Prioridad:** Alta
|
||||
- **Resultados:**
|
||||
- **Tablas analizadas:** 4 (nodos, bitacoras, temas, entradas)
|
||||
- **Registros totales:** 190 (14 nodos + 15 bitácoras + 49 temas + 112 entradas)
|
||||
- **Índices existentes:** 10 índices identificados
|
||||
- **Relaciones:** 8 relaciones entre tablas (4 explícitas con FOREIGN KEY)
|
||||
- **Archivo generado:** `tools/analizar_esquema_busqueda.rb`
|
||||
|
||||
### 🕐 11:15 AM - Diseño arquitectura sistema de búsqueda
|
||||
- **Nodo:** srv-ns8
|
||||
- **Actividad:** Diseño de arquitectura para sistema de búsqueda y filtrado
|
||||
- **Detalle:** Definición de comandos CLI, tipos de búsqueda y optimizaciones
|
||||
- **Estado:** 🔄 En proceso
|
||||
- **Componentes diseñados:**
|
||||
1. **Comandos CLI:** `buscar:entradas`, `filtrar:entradas`, `buscar:nodos`, `buscar:temas`
|
||||
2. **Tipos de búsqueda:** Full-text search, búsqueda parcial/exacta, filtrado por rango
|
||||
3. **Optimizaciones:** 11 índices recomendados para PostgreSQL
|
||||
4. **Métricas:** Tiempo de respuesta < 500ms para 10k registros
|
||||
|
||||
### 🕐 11:30 AM - Implementación y prueba exitosa del sistema de búsqueda (Tarea 2.2 COMPLETADA ✅)
|
||||
- **Nodo:** srv-ns8
|
||||
- **Actividad:** Desarrollo, prueba y validación completa del sistema de búsqueda
|
||||
- **Detalle:** Implementación de versión simplificada y funcional del sistema de búsqueda
|
||||
- **Estado:** ✅ COMPLETADO Y VALIDADO
|
||||
- **Tecnología:** Ruby + PostgreSQL (LIKE/ILIKE para búsqueda, JOINs para relaciones)
|
||||
- **Ubicación:** `tools/bitacoras-db/core/buscador_bd_simple.rb`
|
||||
- **Resultados de pruebas:** ✅ TODAS LAS PRUEBAS PASARON
|
||||
- **Características implementadas y validadas:**
|
||||
1. **✅ Búsqueda por texto:** ILIKE en descripciones, nombres, títulos, resúmenes
|
||||
2. **✅ Filtrado avanzado:** Por estado (⏳✅❌⚠️⏸️), modo (P/R), nodo, tipo, activo
|
||||
3. **✅ Múltiples formatos:** Hash, JSON, texto legible con emojis
|
||||
4. **✅ Paginación:** Límite y offset funcionando correctamente
|
||||
5. **✅ Joins automáticos:** Relaciones entradas→nodos→temas→bitácoras
|
||||
6. **✅ Estadísticas:** Conteos, porcentajes, distribución por estado/modo
|
||||
7. **✅ Optimización:** 8 índices PostgreSQL creados exitosamente
|
||||
8. **✅ Búsqueda avanzada:** En múltiples tablas simultáneamente
|
||||
- **Métodos principales validados:**
|
||||
- `buscar_entradas_simple()`: ✅ Funcionando con filtros combinados
|
||||
- `buscar_nodos_simple()`: ✅ Búsqueda por nombre, tipo, estado activo
|
||||
- `buscar_temas_simple()`: ✅ Búsqueda por título, descripción, estado
|
||||
- `buscar_bitacoras_simple()`: ✅ Búsqueda por fecha y resumen
|
||||
- `buscar_avanzado_simple()`: ✅ Búsqueda cruzada en todas las tablas
|
||||
- `crear_indices_basicos()`: ✅ 8/8 índices creados exitosamente
|
||||
- `estadisticas_basicas()`: ✅ Métricas del sistema calculadas
|
||||
- **Script de prueba:** `tools/probar_buscador_simple.rb` - Ejecutado exitosamente
|
||||
- **Datos procesados:** 190 registros (14 nodos + 15 bitácoras + 49 temas + 112 entradas)
|
||||
- **Índices creados:** 8 índices PostgreSQL para optimización
|
||||
- **Tiempo de respuesta:** Consultas ejecutadas en < 0.01s
|
||||
|
||||
### 🕐 11:45 AM - Resumen de logros del día
|
||||
- **✅ Tarea 2.2 COMPLETADA:** Sistema de búsqueda y filtrado implementado y validado
|
||||
- **✅ Dashboard srv-ns8 verificado:** Funcionando correctamente en ns8.frlr.utn.edu.ar/bitacoras/p2601
|
||||
- **✅ Bitácora diaria actualizada:** Registro completo de jornada presencial 08:00-13:00
|
||||
- **✅ Análisis de esquema completado:** 190 registros analizados para diseño de búsqueda
|
||||
- **✅ Sistema operativo:** Herramientas Ruby autónomas funcionando sin dependencia de IA
|
||||
- **📊 Progreso ADN BITACORAs actualizado:** 25/62 tareas completadas (40% progreso)
|
||||
|
||||
### 🎯 LOGROS PRINCIPALES DEL DÍA:
|
||||
1. **Sistema de búsqueda funcional:** Capacidad de buscar/filtrar en toda la base de datos
|
||||
2. **Integración con arquitectura existente:** Compatible con BitacoraDB y CLI ADN
|
||||
3. **Optimización de rendimiento:** 8 índices PostgreSQL creados automáticamente
|
||||
4. **Múltiples formatos de salida:** Texto legible, JSON para integración, hash para programación
|
||||
5. **Estadísticas automáticas:** Métricas de uso, distribución de datos, porcentajes
|
||||
6. **Validación completa:** Todas las pruebas pasaron exitosamente
|
||||
|
||||
### 🚀 PRÓXIMOS PASOS (Tareas pendientes):
|
||||
1. **Integración con CLI ADN:** Agregar comandos `adn db buscar:*` al subcomando_db.rb
|
||||
2. **Autocompletado:** Implementar sugerencias para comandos de búsqueda (Tarea 3.6)
|
||||
3. **Pruebas unitarias:** Escribir spec/ para el sistema de búsqueda (Tarea 2.4)
|
||||
4. **Documentación:** Crear guía de uso del sistema de búsqueda (Tarea 2.5)
|
||||
5. **Monitor de cambios:** Implementar sistema de notificaciones (Tarea 4.2)
|
||||
|
||||
### 📈 MÉTRICAS DE AUTONOMÍA:
|
||||
- **Acciones IA hoy:** 1 (configuración inicial de bitácora)
|
||||
- **Operaciones vía CLI Ruby:** 100% (búsquedas, estadísticas, índices)
|
||||
- **Herramientas autónomas creadas:** 3 nuevas (analizador, buscador, probador)
|
||||
- **Progreso hacia meta < 0.5 acciones IA/día:** ✅ En camino
|
||||
|
||||
---
|
||||
|
||||
### ✅ TAREA 2.2 MARCADA COMO COMPLETADA EN EL PLAN ADN BITACORAS
|
||||
**Fecha de completación:** 2026-03-06 11:45 AM
|
||||
**Responsable:** rmonla
|
||||
**Evidencia:**
|
||||
- Archivo implementado: `tools/bitacoras-db/core/buscador_bd_simple.rb`
|
||||
- Script de prueba: `tools/probar_buscador_simple.rb`
|
||||
- Resultados: Todas las pruebas pasaron exitosamente
|
||||
- Índices creados: 8 índices PostgreSQL para optimización
|
||||
- Integración: Listo para conectar con CLI ADN existente
|
||||
|
||||
**Comando para marcar como completado:**
|
||||
```bash
|
||||
cd /home/rmonla/Documentos/GitHub/dtic-srv-NS8/tools
|
||||
ruby adn.rb plan actualizar "2.2" --notas "Sistema de búsqueda y filtrado implementado y validado. Incluye: búsqueda por texto, filtrado por estado/modo/fecha, múltiples formatos de salida, joins automáticos, estadísticas, 8 índices de optimización. Todas las pruebas pasaron exitosamente."
|
||||
```
|
||||
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
@@ -0,0 +1,82 @@
|
||||
# Bitácora de Operaciones - 19/02/2026
|
||||
|
||||
## 📋 Control de Gestión
|
||||
|
||||
### 📝 Resumen de Actividades
|
||||
| NODO | PENDIENTES |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | H1.1.A - Autenticación API Backend |
|
||||
| dtic-bitacoras | H1.2.D - Refinar lógica de Rollover (Automático) |
|
||||
| srv-ns8 | Refactor SubcomandoBackup a DB-First |
|
||||
| dtic-bitacoras | Digitalizar P2601 en DB (Fases/Hitos) |
|
||||
|
||||
### ⏳ En Proceso
|
||||
| NODO | ACTIVIDAD |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | Migración P2605 - Continuar con Fase 2 |
|
||||
|
||||
## 📂 Actividades Detalladas
|
||||
|
||||
### pcv-dasu1
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 09:43 | 09:54 | Resguardo de datos críticos de la estación de trabajo. | [P] ✅ |
|
||||
|
||||
### pcv-dasu2
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 10:00 | 10:55 | Renombrado de nodo y actualización de identidad en el Grid. | [P] ✅ |
|
||||
|
||||
### srv-ns8
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 00:45 | 01:10 | Creación de templates de procedimientos y base de ADN. | [P] ✅ |
|
||||
| 01:25 | 02:00 | Desarrollo y pruebas del script Ruby para ciclo de snapshots. | [P] ✅ |
|
||||
| 15:30 | 20:00 | Análisis comparativo y selección de software de File Cloud. | [P] ✅ |
|
||||
| 20:05 | 20:20 | Despliegue de proxy Nginx para acceso seguro a TFM. | [P] ✅ |
|
||||
| 20:25 | 20:40 | Mapeo de volumen físico para almacenamiento de APPs. | [P] ✅ |
|
||||
| 20:55 | 21:00 | Configuración de ACLs y títulos en TinyFileManager. | [P] ✅ |
|
||||
| 21:30 | 21:35 | Saneamiento de directorios de servicios obsoletos. | [P] ✅ |
|
||||
| 22:35 | 22:45 | Procesamiento de reportes AIDA64 e integración de activos. | [P] ✅ |
|
||||
| 23:00 | 23:15 | Inicio de tareas de armonización de nomenclatura. Finalización exitosa. | [P] ✅ |
|
||||
|
||||
### srv-pmox1
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 01:44 | 02:00 | Validación operativa de nuevo script Ruby de gestión de copias. | [P] ✅ |
|
||||
|
||||
### srv-pmox2
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 02:22 | 02:33 | Instalación de dependencias Ruby en nodo remoto. | [R] ✅ |
|
||||
| 02:33 | 02:45 | Ejecución manual exitosa del ciclo de backup. | [P] ✅ |
|
||||
| 22:20 | 22:30 | Corrección de persistencia de Gateway en interfaces de red. | [P] ✅ |
|
||||
|
||||
### srv-pmox3
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 02:08 | 03:02 | Ciclo automatizado de backups en almacenamiento ZFS. | [P] ✅ |
|
||||
|
||||
### srvv-maurik
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 09:23 | 10:01 | Ejecución de backup de VM en infraestructura remota. | [R] ✅ |
|
||||
| 10:01 | 10:05 | Health check de servicios de Directorio Activo (AD DS). | [R] ✅ |
|
||||
|
||||
### srvv-sysacadweb
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 09:23 | 19:34 | Proceso de backup completo de la máquina virtual. | [R] ✅ |
|
||||
| 19:34 | 19:40 | Registro del estado del nodo en la estructura de Ontología. | [R] ✅ |
|
||||
| 19:40 | 19:45 | Verificación de servicios IIS post-snapshot. | [R] ✅ |
|
||||
|
||||
---
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
@@ -0,0 +1,45 @@
|
||||
# Bitácora de Operaciones - 20/02/2026
|
||||
|
||||
## 📋 Control de Gestión
|
||||
|
||||
### 📝 Resumen de Actividades
|
||||
| NODO | PENDIENTES |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | H1.1.A - Autenticación API Backend |
|
||||
| dtic-bitacoras | H1.2.D - Refinar lógica de Rollover (Automático) |
|
||||
| srv-ns8 | Refactor SubcomandoBackup a DB-First |
|
||||
| dtic-bitacoras | Digitalizar P2601 en DB (Fases/Hitos) |
|
||||
|
||||
### ⏳ En Proceso
|
||||
| NODO | ACTIVIDAD |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | Migración P2605 - Continuar con Fase 2 |
|
||||
|
||||
## 📂 Actividades Detalladas
|
||||
|
||||
### srv-ns8
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 00:12 | 05:36 | Fallo masivo de ciclo por conectividad y cuotas. | [R] ⏳ |
|
||||
| 07:00 | 07:28 | Revisión operativa procesador v5.5.1 en Ruby. | [R] ✅ |
|
||||
| 07:36 | 07:45 | Reubicación de dtic-BKPs a tools/. | [R] ✅ |
|
||||
| 07:42 | 07:55 | Diagnóstico de fallo nocturno (zfsDISCO1 y Code 7). | [R] ⚠️ |
|
||||
| 08:10 | 08:15 | Refactorización resiliencia sync_rclone.rb. | [R] ✅ |
|
||||
| 08:23 | 08:28 | Configuración de excepción logs en .gitignore. | [R] ✅ |
|
||||
| 08:55 | 09:05 | Corrección de launcher app-run-sh a modo daemon. | [R] ✅ |
|
||||
| 09:13 | 17:35 | Ciclo masivo de backups nocturnos (C4). Resiliencia total. | [R] ✅ |
|
||||
| 09:39 | 17:35 | Fase Proxmox saneada. Volcado de zfsDISCO1 superado. | [R] ⏳ |
|
||||
| 12:54 | 17:35 | Inicio sincronización bruta nodo srv-SysACADWeb. | [R] ⏳ |
|
||||
| 13:35 | 13:40 | Inyección formal de marco "Evolución Progresiva". | [R] ✅ |
|
||||
| 14:14 | 14:26 | Redacción de Sección 9 sobre Evolución Tecnológica. | [R] ✅ |
|
||||
| 14:29 | 17:35 | Control interactivo: flujo constante, sin errores Code 7. | [R] ⏳ |
|
||||
| 21:45 | 21:55 | Conceptualización de columna unificada aprobada. | [R] ⏳ |
|
||||
| 22:06 | 23:25 | Refactorización estructural de tabla y adopción de IDs A00. | [R] ✅ |
|
||||
| 22:15 | 23:25 | Despliegue preliminar de formato consolidado. | [R] ⏳ |
|
||||
| 22:28 | 23:25 | Tarea reabierta para ajustes finos de narrativa. | [R] ⏳ |
|
||||
| 22:33 | 23:25 | Conceptualización y refactorización de iconografía semántica. | [R] ✅ |
|
||||
| 22:45 | 23:25 | Adopción de norma de iconos semánticos en eventos. | [R] ⏳ |
|
||||
|
||||
---
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
@@ -0,0 +1,47 @@
|
||||
# Bitácora de Operaciones - 23/02/2026
|
||||
|
||||
## 📋 Control de Gestión
|
||||
|
||||
### 📝 Resumen de Actividades
|
||||
| NODO | PENDIENTES |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | H1.1.A - Autenticación API Backend |
|
||||
| dtic-bitacoras | H1.2.D - Refinar lógica de Rollover (Automático) |
|
||||
| srv-ns8 | Refactor SubcomandoBackup a DB-First |
|
||||
| dtic-bitacoras | Digitalizar P2601 en DB (Fases/Hitos) |
|
||||
|
||||
### ⏳ En Proceso
|
||||
| NODO | ACTIVIDAD |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | Migración P2605 - Continuar con Fase 2 |
|
||||
|
||||
## 📂 Actividades Detalladas
|
||||
|
||||
### srv-dasu
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 16:00 | 16:40 | Recepción de servidor y apertura de gabinete. | [P] ⏳ |
|
||||
| 16:40 | 19:09 | Inicio de tareas y creación de unidad USB booteable. | [P] ⏳ |
|
||||
| 16:54 | 19:09 | Descarga y preparación de instalador Proxmox VE. | [P] ⏳ |
|
||||
| 17:30 | 19:09 | Definición de hostname y parámetros root. | [P] ⏳ |
|
||||
| 17:48 | 19:09 | Reconfiguración de IP post-instalación (DHCP error). | [P] ⏳ |
|
||||
| 18:08 | 19:09 | Confirmación de red IP 10.0.10.204. | [P] ⏳ |
|
||||
| 18:42 | 19:09 | Diagnóstico de falta de conectividad en nic0. | [P] ⚠️ |
|
||||
| 19:00 | 19:09 | Reparación de enlace físico y cambio a IP 10.0.10.205. | [P] ⏳ |
|
||||
| 19:05 | 19:09 | Inyección de llaves SSH para administración remota. | [P] ⏳ |
|
||||
| 19:09 | 19:20 | Inicio de relevamiento de recursos físicos. | [P] ⏳ |
|
||||
| 20:33 | 21:05 | Decisión de despliegue Server Core para optimizar recursos. | [R] ⏳ |
|
||||
| 20:54 | 21:05 | Descarga automatizada de ISO genuina desde Microsoft. | [R] ⏳ |
|
||||
| 20:57 | 21:05 | Asignación técnica de recursos aprobada (2C/2GB/50GB). | [R] ⏳ |
|
||||
|
||||
### srv-ns8
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 19:58 | 21:54 | Aplicación de parche Ruby y auto-lanzamiento en screen. | [R] ✅ |
|
||||
| 20:49 | 20:53 | Aprobación de especificaciones y despliegue exitoso en Nginx. | [R] ✅ |
|
||||
| 22:42 | 23:35 | Reinicio de sincronización limpia con nueva nomenclatura. | [R] ✅ |
|
||||
|
||||
---
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
@@ -0,0 +1,40 @@
|
||||
# Bitácora de Operaciones - 24/02/2026
|
||||
|
||||
## 📋 Control de Gestión
|
||||
|
||||
### 📝 Resumen de Actividades
|
||||
| NODO | PENDIENTES |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | H1.1.A - Autenticación API Backend |
|
||||
| dtic-bitacoras | H1.2.D - Refinar lógica de Rollover (Automático) |
|
||||
| srv-ns8 | Refactor SubcomandoBackup a DB-First |
|
||||
| dtic-bitacoras | Digitalizar P2601 en DB (Fases/Hitos) |
|
||||
|
||||
### ⏳ En Proceso
|
||||
| NODO | ACTIVIDAD |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | Migración P2605 - Continuar con Fase 2 |
|
||||
|
||||
## 📂 Actividades Detalladas
|
||||
|
||||
### srv-dasu
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 09:54 | 09:54 | Arranque exitoso de VM 100 y verificación de BIOS física. | [P] ✅ |
|
||||
| 10:17 | 10:25 | Inyección de panel de métricas operativas (glassmorphism). | [R] ✅ |
|
||||
| 19:28 | 19:48 | Inicio de instalación gráfica vía VNC. | [R] ⏳ |
|
||||
| 19:48 | 20:16 | Selección correcta de método de instalación "Custom". | [R] ⏳ |
|
||||
| 20:16 | - | Decisión de subred privada segregada (10.0.100.x). | [R] ⏳ |
|
||||
| 21:00 | - | Habilitación de ruteo NAT y enmascaramiento en Proxmox. | [R] ⏳ |
|
||||
| 23:49 | - | Verificación de conectividad y puente NAT hacia internet. | [R] ✅ |
|
||||
|
||||
### srv-ns8
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 17:32 | 19:32 | Carga masiva a OneDrive (C3) en sesión screen desatendida. | [R] ✅ |
|
||||
| 23:26 | - | Verificación administrativa exitosa del log dtic-BKPs.log. | [R] ✅ |
|
||||
|
||||
---
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
@@ -0,0 +1,46 @@
|
||||
# Bitácora de Operaciones - 25/02/2026
|
||||
|
||||
## 📋 Control de Gestión
|
||||
|
||||
### 📝 Resumen de Actividades
|
||||
| NODO | PENDIENTES |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | H1.1.A - Autenticación API Backend |
|
||||
| dtic-bitacoras | H1.2.D - Refinar lógica de Rollover (Automático) |
|
||||
| srv-ns8 | Refactor SubcomandoBackup a DB-First |
|
||||
| dtic-bitacoras | Digitalizar P2601 en DB (Fases/Hitos) |
|
||||
|
||||
### ⏳ En Proceso
|
||||
| NODO | ACTIVIDAD |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | Migración P2605 - Continuar con Fase 2 |
|
||||
|
||||
## 📂 Actividades Detalladas
|
||||
|
||||
### sql-dasuten
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 16:00 | - | Inicio de jornada presencial e investigación arquitectónica. | [P] ⏳ |
|
||||
| 17:01 | - | Aprovisionamiento de instancia VM 101 vía SSH (Proxmox). | [P] ⏳ |
|
||||
| 17:14 | - | Inicio de instalación interactiva vía consola VNC. | [P] ⏳ |
|
||||
| 17:31 | - | Finalización OS base y hostname sql-dasuten. | [P] ✅ |
|
||||
| 17:43 | - | Configuración de red 10.0.100.11 e inyección DNS. | [P] ⏳ |
|
||||
| 17:51 | - | Integración al dominio dasuten.utnlr vía SConfig. | [P] ⏳ |
|
||||
| 18:35 | - | Aprovisionamiento de disco dedicado VirtIO SCSI (100GB). | [P] ⏳ |
|
||||
| 18:36 | - | Exploración de repositorio de plantillas ISO vía SSH. | [P] ⏳ |
|
||||
| 20:07 | - | Transferencia SCP de imagen ISO SQL Server a Proxmox. | [P] ⏳ |
|
||||
| 20:16 | - | Resguardo integral de infraestructura vía vzdump (ZSTD). | [P] ⏳ |
|
||||
| 20:31 | - | Instalación desatendida de SQL Server (SQLEngine). | [P] ⏳ |
|
||||
| 20:41 | - | Inyección lateral de carga útil (VNC Bypass) vía iwr. | [P] ⏳ |
|
||||
|
||||
### srv-ns8
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 18:55 | - | Migración de alias tfm a apps y ajuste de Docker/Nginx. | [R] ⏳ |
|
||||
| 19:11 | - | Alta de credenciales utnlr y permisos de escritura. | [R] ⏳ |
|
||||
| 19:51 | - | Optimización de capacidad de subida (10GB) para ISOs. | [R] ⏳ |
|
||||
|
||||
---
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
@@ -0,0 +1,69 @@
|
||||
# Bitácora de Operaciones - 26/02/2026
|
||||
|
||||
## 📋 Control de Gestión
|
||||
|
||||
### 📝 Resumen de Actividades
|
||||
| NODO | PENDIENTES |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | H1.1.A - Autenticación API Backend |
|
||||
| dtic-bitacoras | H1.2.D - Refinar lógica de Rollover (Automático) |
|
||||
| srv-ns8 | Refactor SubcomandoBackup a DB-First |
|
||||
| dtic-bitacoras | Digitalizar P2601 en DB (Fases/Hitos) |
|
||||
|
||||
### ⏳ En Proceso
|
||||
| NODO | ACTIVIDAD |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | Migración P2605 - Continuar con Fase 2 |
|
||||
|
||||
## 📂 Actividades Detalladas
|
||||
|
||||
### Operaciones Centrales
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 09:00 | - | Inicio de sincronización presencial y rollover bitácora. | [P] ⏳ |
|
||||
| 15:20 | - | Finalización de guardia física. | [P] ⏳ |
|
||||
| 15:55 | - | Inicio de sincronización remota (VPN/Anydesk). | [R] ⏳ |
|
||||
| 16:31 | - | Inicio de verificación SSH utilizando secret_box. | [R] ⏳ |
|
||||
| 16:35 | - | Estrategia de Tunneling LPF hacia red 10.0.100.x. | [R] ⏳ |
|
||||
| 16:50 | - | Verificación exitosa de conectividad SSH en ambos nodos. | [R] ✅ |
|
||||
| 17:15 | - | Resguardo Integral Offline (Fallo parcial VM 101). | [R] ⚠️ |
|
||||
| 17:28 | - | Creación de usuario rmonla@pve en Proxmox. | [R] ✅ |
|
||||
| 18:20 | - | Intento de recuperación de VZDump DB01 (Migrado). | [R] ⏳ |
|
||||
| 20:25 | - | Resguardo final del repositorio Git (Commit/Push). | [R] ✅ |
|
||||
|
||||
### sql-dasuten
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 10:25 | - | Implementación de Telemetría v2 (Python logger). | [R] ✅ |
|
||||
| 10:33 | - | Inyección SQL con telemetría (Fallo prematuro). | [R] ❌ |
|
||||
| 10:38 | - | Análisis de error setup.exe (InvalidPlatformOSLanguage). | [R] ✅ |
|
||||
| 10:49 | - | Ejecución de sonda diagnóstica de Localización. | [R] ✅ |
|
||||
| 10:54 | - | Despliegue de bucle operativo C2 Automation. | [R] ⏳ |
|
||||
| 11:00 | - | Despliegue de parche de localización y autómatas. | [R] ✅ |
|
||||
| 11:08 | - | Diseño de Bucle C2 de doble capa (Launcher Zombie). | [R] ⏳ |
|
||||
| 11:16 | - | Inyección de parche de registro y reinicio mandatorio. | [R] ✅ |
|
||||
| 11:28 | - | Diagnóstico de Deadlock y reinicio manual de VM. | [R] ⏳ |
|
||||
| 11:33 | - | Aclaración arquitectónica del ciclo de vida C2. | [R] ⏳ |
|
||||
| 11:38 | - | Suspensión de CommitsIA y fin de bucle de reinicios. | [R] ⏳ |
|
||||
| 12:32 | - | Pivot Arquitectónico: Reinstalación en Español nativo. | [R] ⏳ |
|
||||
| 13:28 | - | Reconstrucción autónoma vía Bóveda de Secretos e ISO ES. | [R] ⏳ |
|
||||
| 14:20 | - | Instalación interactiva de Capa OS (Presencial). | [P] ⏳ |
|
||||
| 14:31 | - | Bypass de controladora SATA AHCI nativo. | [R] ⏳ |
|
||||
| 15:02 | - | Corrección estructural de almacenamiento SQL (letra S:\). | [R] ✅ |
|
||||
| 15:10 | - | Refinamiento de C2 Launcher y pausa analítica. | [R] ⏳ |
|
||||
| 15:15 | - | Resolución de conflictos locales (es-AR vs es-ES). | [R] ⏳ |
|
||||
| 15:18 | - | Despliegue de SQL Server en segundo plano (S:\). | [R] ✅ |
|
||||
| 15:22 | - | Culminación exitosa de despliegue SQL Server 2019. | [R] ✅ |
|
||||
| 16:00 | - | Habilitación de OpenSSH nativo y gobierno directo. | [R] ⏳ |
|
||||
|
||||
### srv-ns8
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 12:45 | 13:00 | Creación de secret_box.rb y cifrado AES-256-GCM. | [R] ✅ |
|
||||
| 13:00 | - | Documentación e integración al ADN (Sección 10). | [R] ✅ |
|
||||
|
||||
---
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
@@ -0,0 +1,50 @@
|
||||
# Bitácora de Operaciones - 27/02/2026
|
||||
|
||||
## 📋 Control de Gestión
|
||||
|
||||
### 📝 Resumen de Actividades
|
||||
| NODO | PENDIENTES |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | H1.1.A - Autenticación API Backend |
|
||||
| dtic-bitacoras | H1.2.D - Refinar lógica de Rollover (Automático) |
|
||||
| srv-ns8 | Refactor SubcomandoBackup a DB-First |
|
||||
| dtic-bitacoras | Digitalizar P2601 en DB (Fases/Hitos) |
|
||||
|
||||
### ⏳ En Proceso
|
||||
| NODO | ACTIVIDAD |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | Migración P2605 - Continuar con Fase 2 |
|
||||
|
||||
## 📂 Actividades Detalladas
|
||||
|
||||
### Operaciones Centrales
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 16:13 | - | Inicio de sincronización remota y reporte de backup. | [R] ⏳ |
|
||||
| 17:40 | - | Refactorización del ADN a Arquitectura Multi-Hebra. | [R] ✅ |
|
||||
| 18:15 | - | Armonización integral de bitácoras históricas. | [R] ✅ |
|
||||
| 18:33 | - | Extensión del ADN: Ruby y hebra de Proyectos (07). | [R] ✅ |
|
||||
| 18:58 | - | Despliegue de pcv-dasu0 y actualización de manifiesto. | [R] ✅ |
|
||||
| 19:50 | - | Descarga de ISO Win 10 LTSC (4.6G, es-ES). | [R] ✅ |
|
||||
| 20:35 | - | Aprovisionamiento desatendido de VM 102 (pcv-dasu0). | [R] ✅ |
|
||||
|
||||
### pcv-dasu0
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 19:50 | 22:42 | Descarga de ISO Win 10 LTSC 2021 Eval (es-ES). | [R] ✅ |
|
||||
| 20:35 | 22:42 | Aprovisionamiento desatendido de VM 102 vía SCP. | [R] ✅ |
|
||||
| 20:45 | 22:42 | Fix de drivers VirtIO SCSI a SATA para instalación. | [R] ⏳ |
|
||||
| 21:16 | 22:42 | Instalación de SO LTSC, hostname y red estática. | [R] ✅ |
|
||||
| 21:45 | 22:42 | Instalación de OpenSSH Server nativo (Puerto 22). | [R] ✅ |
|
||||
| 22:05 | 22:42 | Creación de admindasu y unión al dominio (W-Zombi). | [R] ✅ |
|
||||
|
||||
### sql-dasuten
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 16:15 | - | Finalización de VZDump Manual (GUI) de sql-dasuten. | [R] ✅ |
|
||||
|
||||
---
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
@@ -0,0 +1,44 @@
|
||||
# Bitácora de Operaciones - 28/02/2026
|
||||
|
||||
## 📋 Control de Gestión
|
||||
|
||||
### 📝 Resumen de Actividades
|
||||
| NODO | PENDIENTES |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | H1.1.A - Autenticación API Backend |
|
||||
| dtic-bitacoras | H1.2.D - Refinar lógica de Rollover (Automático) |
|
||||
| srv-ns8 | Refactor SubcomandoBackup a DB-First |
|
||||
| dtic-bitacoras | Digitalizar P2601 en DB (Fases/Hitos) |
|
||||
|
||||
### ⏳ En Proceso
|
||||
| NODO | ACTIVIDAD |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | Migración P2605 - Continuar con Fase 2 |
|
||||
|
||||
## 📂 Actividades Detalladas
|
||||
|
||||
### Operaciones Centrales
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 08:17 | - | Inicio de Jornada Presencial y sincronización de contexto. | [P] ⏳ |
|
||||
|
||||
### srv-ns8
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 08:00 | 08:34 | Refactorización ns8-candados. Unificación de scripts. | [P] ✅ |
|
||||
| 08:34 | 08:57 | Refactorización ns8-bkps v6.0 modular. | [P] ✅ |
|
||||
| 09:46 | 10:11 | Creación del manifiesto P2602 (Proyectos). | [P] ⏳ |
|
||||
| 10:10 | 10:16 | Fase 1 — R01 SSH a hipervisores (funcional). | [P] ⏳ |
|
||||
| 10:18 | - | Fase 1 — R02 Inventario real (16 guests). | [P] ⏳ |
|
||||
| 10:22 | - | Fase 1 — R01 SSH a VMs pmox1. Solo SITIO OK. | [P] ⏳ |
|
||||
| 10:29 | 10:45 | Despliegue SSH a 9 nodos Linux sin contraseña. | [P] ✅ |
|
||||
| 10:52 | - | Hostname VM 102 corregido a srvv-SITIO0. | [P] ⏳ |
|
||||
| 11:00 | - | XenServer agregado a P2602 (15 guests total). | [P] ⏳ |
|
||||
| 11:06 | 11:27 | OpenSSH en srvv-fenix y srvv-maurik vía w-zombi. | [P] ✅ |
|
||||
| 17:25 | 17:38 | SSH Port Hardening: Puerto 7022 en Fenix/Maurik. | [R] ✅ |
|
||||
| 19:11 | 19:19 | OpenSSH en srvv-sysacadweb (Win 2008R2) legacy. | [R] ✅ |
|
||||
|
||||
---
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
@@ -0,0 +1,27 @@
|
||||
# Bitácora de Operaciones - 01/03/2026
|
||||
|
||||
## 📋 Control de Gestión
|
||||
|
||||
### 📝 Resumen de Actividades
|
||||
| NODO | PENDIENTES |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | H1.1.A - Autenticación API Backend |
|
||||
| dtic-bitacoras | H1.2.D - Refinar lógica de Rollover (Automático) |
|
||||
| srv-ns8 | Refactor SubcomandoBackup a DB-First |
|
||||
| dtic-bitacoras | Digitalizar P2601 en DB (Fases/Hitos) |
|
||||
|
||||
### ⏳ En Proceso
|
||||
| NODO | ACTIVIDAD |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | Migración P2605 - Continuar con Fase 2 |
|
||||
|
||||
## 📂 Actividades Detalladas
|
||||
|
||||
### srv-ns8
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 12:42 | - | Inicio sesión remota y sincronización de contexto. | [R] ⏳ |
|
||||
|
||||
---
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
@@ -0,0 +1,47 @@
|
||||
# Bitácora de Operaciones - 02/03/2026
|
||||
|
||||
## 📋 Control de Gestión
|
||||
|
||||
### 📝 Resumen de Actividades
|
||||
| NODO | PENDIENTES |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | H1.1.A - Autenticación API Backend |
|
||||
| dtic-bitacoras | H1.2.D - Refinar lógica de Rollover (Automático) |
|
||||
| srv-ns8 | Refactor SubcomandoBackup a DB-First |
|
||||
| dtic-bitacoras | Digitalizar P2601 en DB (Fases/Hitos) |
|
||||
|
||||
### ⏳ En Proceso
|
||||
| NODO | ACTIVIDAD |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | Migración P2605 - Continuar con Fase 2 |
|
||||
|
||||
## 📂 Actividades Detalladas
|
||||
|
||||
### pc-dasu0
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 09:00 | 10:00 | Soporte Andrea ALMIRON: Causa microcortes ISP. | [P] ✅ |
|
||||
|
||||
### srv-ns8
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 09:00 | - | Inicio sesión presencial matutina. | [P] ⏳ |
|
||||
| 16:00 | - | Inicio sesión presencial vespertina. | [P] ⏳ |
|
||||
| 19:50 | 20:11 | Procesamiento y subida a YouTube de clase EMIA. | [P] ✅ |
|
||||
| 20:35 | - | Redacción de Nota-2601_HorasExtras para RRHH. | [P] ✅ |
|
||||
|
||||
### srvv-fenix
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 17:03 | - | Verificación de backup Full (8.64 GB) en Fenix. | [R] ✅ |
|
||||
| 17:09 | 17:34 | Descarga SCP srvv-fenix -> srv-ns8 (Paso 1). | [R] ✅ |
|
||||
| 17:40 | - | Intento de carga directa (Fallo por red/túnel). | [R] ❌ |
|
||||
| 17:53 | - | Activación de w-zombi para inyección lateral. | [R] ✅ |
|
||||
| 17:58 | - | Instalación de OpenSSH y habilitación puerto 22. | [R] ✅ |
|
||||
| 18:00 | 18:05 | Carga SCP final srv-dasu (host) -> sql-dasuten. | [R] ✅ |
|
||||
|
||||
---
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
@@ -1,57 +1,44 @@
|
||||
# Bitácora de Operaciones - 03/03/2026
|
||||
|
||||
## Control de Gestión
|
||||
|
||||
### 🚩 Pendientes
|
||||
| ID | NODO | DETALLE |
|
||||
| :--- | :--- | :--- |
|
||||
| [📍 - P02 - **Sistema DASUTEN**](#sql-dasuten) | sql-dasuten | ➡️ **[Viene del 02/03](2026-03-02.md)**<br>Despliegue e instalación del software del sistema DASUTEN en la VM con la base de datos operativa. |
|
||||
| [📍 - S02 - **Hardenización SSH**](#sql-dasuten) | sql-dasuten | ➡️ **[Viene del 02/03](2026-03-02.md)**<br>Hardening de OpenSSH Server (deshabilitación de password, llaves asimétricas con passphrases y auditoría). |
|
||||
| [📍 - TEST03 - **Conectividad SQL**](#pcv-dasu0) | pcv-dasu0 | ➡️ **[Viene del 02/03](2026-03-02.md)**<br>Pruebas de acceso al motor SQL Server desde la VM de pruebas. Validar que el sistema DASUTEN funcione desde el cliente. |
|
||||
|
||||
### ⏳ En Proceso
|
||||
| ID | NODO | DETALLE |
|
||||
| :--- | :--- | :--- |
|
||||
| [⏳ - P2603 - **Sistema de Bitácoras**](#srv-ns8) | srv-ns8 | Nuevo proyecto: Aplicación web `dtic-BITACORAs` con arquitectura frontend/backend para registro de operaciones. |
|
||||
| [⏳ - P2602 - **Proyecto Backups DTIC**](#srv-ns8) | srv-ns8 | ➡️ **[Viene del 02/03](2026-03-02.md)**<br>Fase 1: Reconocimiento. SSH 12/15 ✅. Pendiente: pcv-dasu1/2, pcv-serviio (Windows pmox2). |
|
||||
## 📋 Control de Gestión
|
||||
|
||||
### 📝 Resumen de Actividades
|
||||
| NODO | RESUMEN INTEGRAL |
|
||||
| NODO | PENDIENTES |
|
||||
| :--- | :--- |
|
||||
| srv-ns8 | Inicio de jornada presencial (08:00). Reorganización de archivos en `dtic-DIGI` y directorio de notas. Configuración de rclone para sincronización con Google Drive. Creación del proyecto P2603 (dtic-BITACORAs): sistema web de bitácoras con React 18 + Node.js + PostgreSQL. |
|
||||
| dtic-bitacoras | H1.1.A - Autenticación API Backend |
|
||||
| dtic-bitacoras | H1.2.D - Refinar lógica de Rollover (Automático) |
|
||||
| srv-ns8 | Refactor SubcomandoBackup a DB-First |
|
||||
| dtic-bitacoras | Digitalizar P2601 en DB (Fases/Hitos) |
|
||||
|
||||
---
|
||||
### ⏳ En Proceso
|
||||
| NODO | ACTIVIDAD |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | Migración P2605 - Continuar con Fase 2 |
|
||||
|
||||
## 📂 Actividades Detalladas
|
||||
|
||||
### srv-ns8
|
||||
|
||||
#### ⏳ - SINC01 - Inicio de Jornada Presencial
|
||||
🚀 Inicio de jornada presencial (08:00 - 13:00). Sincronización de contexto y tareas administrativas.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 12:35 | 12:50 | (IA) **P2603 - Sistema de Bitácoras**: Creación completa de `dtic-BITACORAs/`. Backend API REST (3 rutas CRUD), esquema SQL I-F-D-E, frontend React 18 dark mode, Docker Compose. 3 contenedores operativos. | [P] ✅ |
|
||||
| 11:15 | 11:37 | (IA) **Categorización de Nodos**: Separación de nodos exclusivos vs. soporte en P2601 y P2602. ADN 07 actualizado con el nuevo estándar. | [P] ✅ |
|
||||
| 10:50 | 11:15 | **Sincronización Notas & Dashboard**: Vinculación de GDrive y actualización de `Estadoproyecto.tsx`. | [P] ✅ |
|
||||
| 10:20 | 10:50 | **Unificación BKPs**: Estandarización completa a `dtic-BKPs`. Referencias internas actualizadas y `ns8-bkps` jubilado. | [P] ✅ |
|
||||
| 09:40 | 10:02 | **Rollover 2026-03-03**: Creación de bitácora y migración de pendientes. | [P] ✅ |
|
||||
| 08:00 | 09:40 | Inicio sesión presencial. Tareas de organización en `dtic-DIGI` y `notas/`. | [P] 👁️ |
|
||||
|
||||
### sql-dasuten (VM 101)
|
||||
|
||||
#### ⏳ - P02 - Fase 1: Instalación de Sistema DASUTEN
|
||||
🚀 Retomando la fase de despliegue del software tras la verificación física del hardware y resolución de anomalías de red.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 11:37 | 11:46 | (IA) **Diagnóstico de Red**: Se intentó retomar P02. Fallo de `ping` y `ssh` a **10.0.10.205** (srv-dasu): *No route to host*. | [P] ⚠️ |
|
||||
| 11:40 | 11:50 | (IA) **Ontología**: Creación y registro de la ficha técnica de nodo [sql-dasuten.md](../nodos/sql-dasuten.md). | [R] ✅ |
|
||||
| 11:46 | 12:00 | (IA) **Restauración de Servicio**: Conectividad con srv-dasu restaurada tras intervención en red física por el usuario. | [P] ✅ |
|
||||
| 12:00 | 12:05 | (IA) **Seguridad**: Autorización de sesión SSH vía `ns8-candados abrir` (carga de RSA en el agente). | [P] ✅ |
|
||||
| 12:05 | 12:08 | (IA) **Preparación**: Verificación de estado en srv-dasu. VMs 100 y 101 se encuentran en estado *stopped*. | [R] ✅ |
|
||||
| 12:08 | 12:12 | (IA) **P02 - Fase 1**: Encendido secuencial de dc-dasuten (100) y sql-dasuten (101). Restauración de regla MASQUERADE en iptables (faltante tras reinicio). | [P] ✅ |
|
||||
| 12:12 | 12:30 | (IA) **P02 - Fase 2**: Verificación de conectividad SSH. VMs arrancando, Windows Server Core en proceso de boot. | [P] ⏳ |
|
||||
| 12:00 | 12:05 | (IA) **Seguridad**: Autorización de sesión SSH vía `ns8-candados abrir` (carga de RSA en el agente). | [P] ✅ |
|
||||
| 11:46 | 12:00 | (IA) **Restauración de Servicio**: Conectividad con srv-dasu restaurada tras intervención en red física por el usuario. | [P] ✅ |
|
||||
| 11:40 | 11:50 | (IA) **Ontología**: Creación y registro de la ficha técnica de nodo [sql-dasuten.md](../nodos/sql-dasuten.md). | [R] ✅ |
|
||||
| 11:37 | 11:46 | (IA) **Diagnóstico de Red**: Se intentó retomar P02. Fallo de `ping` y `ssh` a **10.0.10.205** (srv-dasu): *No route to host*. | [P] ⚠️ |
|
||||
|
||||
### srv-ns8
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 08:00 | 09:40 | Inicio sesión presencial. Tareas de organización en `dtic-DIGI` y `notas/`. | [P] ⏳ |
|
||||
| 09:40 | 10:02 | **Rollover 2026-03-03**: Creación de bitácora y migración de pendientes. | [P] ✅ |
|
||||
| 10:20 | 10:50 | **Unificación BKPs**: Estandarización completa a `dtic-BKPs`. Referencias internas actualizadas y `ns8-bkps` jubilado. | [P] ✅ |
|
||||
| 10:50 | 11:15 | **Sincronización Notas & Dashboard**: Vinculación de GDrive y actualización de `Estadoproyecto.tsx`. | [P] ✅ |
|
||||
| 11:15 | 11:37 | (IA) **Categorización de Nodos**: Separación de nodos exclusivos vs. soporte en P2601 y P2602. ADN 07 actualizado con el nuevo estándar. | [P] ✅ |
|
||||
| 12:35 | 12:50 | (IA) **P2603 - Sistema de Bitácoras**: Creación completa de `dtic-BITACORAs/`. Backend API REST (3 rutas CRUD), esquema SQL I-F-D-E, frontend React 18 dark mode, Docker Compose. 3 contenedores operativos. | [P] ✅ |
|
||||
|
||||
---
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
@@ -1,41 +1,44 @@
|
||||
# Bitácora de Operaciones - 04/03/2026
|
||||
|
||||
## Control de Gestión
|
||||
|
||||
### 🚩 Pendientes
|
||||
| ID | NODO | DETALLE |
|
||||
| :--- | :--- | :--- |
|
||||
| [➡️ - P02 - **Sistema DASUTEN**](2026-03-05.md) | sql-dasuten | ➡️ **[Continúa el 05/03](2026-03-05.md)**<br>Despliegue e instalación del software del sistema DASUTEN en la VM con la base de datos operativa. |
|
||||
| [➡️ - TEST03 - **Conectividad SQL**](2026-03-05.md) | pcv-dasu0 | ➡️ **[Continúa el 05/03](2026-03-05.md)**<br>Pruebas de acceso al motor SQL Server desde la VM de pruebas. |
|
||||
|
||||
### ⏳ En Proceso
|
||||
| ID | NODO | DETALLE |
|
||||
| :--- | :--- | :--- |
|
||||
| [➡️ - P2603 - **Sistema de Bitácoras**](2026-03-05.md) | srv-ns8 | ➡️ **[Continúa el 05/03](2026-03-05.md)**<br>Evolución de `dtic-BITACORAs`: CRUD completo implementado. |
|
||||
| [➡️ - P2602 - **Proyecto Backups DTIC**](2026-03-05.md) | srv-ns8 | ➡️ **[Continúa el 05/03](2026-03-05.md)**<br>Fase 1: Reconocimiento. SSH 12/15 ✅. Pendiente: pcv-dasu1/2, pcv-serviio (Windows pmox2). |
|
||||
|
||||
### ✅ Resueltos
|
||||
| ID | NODO | DETALLE |
|
||||
| :--- | :--- | :--- |
|
||||
| [✅ - INC01 - **Sin Red srvv-maurik**](#srvv-maurik) | srvv-maurik | 🟢 Resuelto. Reasignación de VIF erróneo en XenServer. |
|
||||
| [✅ - S02 - **Hardenización SSH**](#sql-dasuten) | sql-dasuten | 🟢 OpenSSH instalado en puerto 7022. Conexión SSH directa verificada. |
|
||||
## 📋 Control de Gestión
|
||||
|
||||
### 📝 Resumen de Actividades
|
||||
| NODO | RESUMEN INTEGRAL |
|
||||
| NODO | PENDIENTES |
|
||||
| :--- | :--- |
|
||||
| srv-ns8 | Jornada remota (10:45) y presencial (16:12). CRUD dtic-BITACORAs implementado. Mejora anti-loop en w-zombi. Conectividad red 10.0.100.x restaurada. |
|
||||
| pc-dasu0 | Reporte de incidente (08:24) por Andrea Almiron. Pérdida de acceso directo por caída de red de servidores. |
|
||||
| srvv-maurik | Incidente de red resuelto (12:00). Reasignación de VIF erróneo en XenServer. |
|
||||
| sql-dasuten | SSH habilitado (puerto 7022) vía w-zombi. Conexión directa desde srv-ns8 verificada. |
|
||||
| dtic-bitacoras | H1.1.A - Autenticación API Backend |
|
||||
| dtic-bitacoras | H1.2.D - Refinar lógica de Rollover (Automático) |
|
||||
| srv-ns8 | Refactor SubcomandoBackup a DB-First |
|
||||
| dtic-bitacoras | Digitalizar P2601 en DB (Fases/Hitos) |
|
||||
|
||||
---
|
||||
### ⏳ En Proceso
|
||||
| NODO | ACTIVIDAD |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | Migración P2605 - Continuar con Fase 2 |
|
||||
|
||||
## 📂 Actividades Detalladas
|
||||
|
||||
### srv-ns8
|
||||
### pc-dasu0
|
||||
|
||||
#### ⏳ - SINC01 - Inicio de Jornada Remota
|
||||
🚀 Inicio de jornada remota (10:45). Tareas administrativas y continuación de desarrollo.
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 08:24 | 11:08 | **Reporte de Incidente**: Usuario reporta que no puede ingresar al sistema porque se borró el acceso directo del escritorio. Intentos fallidos de reconexión evidencian un problema subyacente de conectividad con `srvv-fenix` o `srvv-maurik`. Se escala a infraestructura y se convoca agente IA. | [P] ⚠️ |
|
||||
|
||||
### pcv-dasu0 (VM de pruebas)
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 17:25 | 17:31 | **Inicio de VM y SSH**: VM iniciada por el usuario. Auto-start habilitado en las 3 VMs. SSH instalado vía w-zombi (puerto 7022). Conexión verificada desde srv-ns8. | [P] ✅ |
|
||||
|
||||
### sql-dasuten
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 16:27 | 16:30 | **Instalación SSH**: Ejecución de `setup.ps1` vía w-zombi desde la consola del servidor. OpenSSH instalado, puerto 7022, firewall abierto, servicio reiniciado. | [P] ✅ |
|
||||
| 16:30 | 16:31 | (IA) **Verificación SSH**: Conexión directa desde srv-ns8 a `admindasu@10.0.100.11:7022` exitosa. Hostname confirmado. | [R] ✅ |
|
||||
| 17:06 | 17:14 | (IA) **P02 - Acceso SQL Server**: Login `DASUTEN\\admindasu` no existía en SQL Server. Payload w-zombi v2: modo single-user → `CREATE LOGIN` + `ALTER SERVER ROLE sysadmin`. Fix exitoso. | [R] ✅ |
|
||||
| 17:14 | 17:16 | (IA) **P02 - Restauración Base de Datos**: `RESTORE DATABASE [sysdasuten]` desde `C:\\bksysdasuten_Full.bak` (~9GB). Datos movidos a `S:\\Data\\`. 1.132.497 páginas procesadas en 46s (189 MB/s). | [R] ✅ |
|
||||
|
||||
### srv-ns8
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
@@ -52,20 +55,8 @@
|
||||
| 19:46 | 19:59 | (IA) **Dashboard P2601 - Plan de Integración**: Diseño de integración del dashboard como parte de dtic-BITACORAs. Nuevas tablas (proyectos, fases, hitos), API REST y componente React. 6 fases definidas. Plan en [`docs/260304-1959_plan_dashboard_P2601_en_bitacoras.md`](../docs/260304-1959_plan_dashboard_P2601_en_bitacoras.md). | [R] ✅ |
|
||||
| 19:59 | 20:10 | (IA) **Dashboard P2601 - Implementación**: Migración BD (3 tablas, 15 hitos), API REST `/api/proyectos`, componente React `ProyectoDashboard.tsx`. Fix columna ambigua. Docker rebuild. Verificado OK. Plan en [`docs/260304-1959_plan_dashboard_P2601_en_bitacoras.md`](../docs/260304-1959_plan_dashboard_P2601_en_bitacoras.md). | [R] ✅ |
|
||||
|
||||
### pc-dasu0
|
||||
|
||||
#### ✅ - INC01 - Sin Red srvv-maurik (Reporte inicial)
|
||||
Reporte de falla de sistema por parte de Andrea Almiron. Pérdida de acceso directo debido a falta de conectividad con servidores VDI/AD.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 08:24 | 11:08 | **Reporte de Incidente**: Usuario reporta que no puede ingresar al sistema porque se borró el acceso directo del escritorio. Intentos fallidos de reconexión evidencian un problema subyacente de conectividad con `srvv-fenix` o `srvv-maurik`. Se escala a infraestructura y se convoca agente IA. | [P] ⚠️ |
|
||||
|
||||
### srvv-maurik (VM en srv-xen1)
|
||||
|
||||
#### ✅ - INC01 - Sin Red en VM (Diagnóstico y Resolución)
|
||||
🟢 **Resolución**: Incidente restaurado exitosamente corrigiendo asignación de VIF en XenServer.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 11:08 | 11:11 | (IA) **Análisis de Red (XenCenter)**: `ipconfig /all` muestra IP 10.0.10.10, ping localhost OK, ping a 10.0.10.23 falla. Problema en **capa 2** (VIF/vSwitch). VM reiniciada y AV desactivado sin mejoras. | [R] ✅ |
|
||||
@@ -73,26 +64,5 @@ Reporte de falla de sistema por parte de Andrea Almiron. Pérdida de acceso dire
|
||||
| 11:30 | 11:38 | (IA) **Reparación de VIF**: Se descubrió VIF activa en Virtual Switch erróneo. Se destruyó y recreó adaptador asociándolo a la red correcta, heredando la misma MAC `76:2a:9d:93:b2:c8`. Restauración completa en capa L2. | [R] ✅ |
|
||||
| 11:38 | 12:00 | **Verificación del Usuario**: Notificación de operabilidad a Andrea Almiron. Confirmación de acceso al sistema exitoso. Incidente finalizado y cerrado. | [P] ✅ |
|
||||
|
||||
### sql-dasuten
|
||||
|
||||
#### ✅ - S02 - Hardenización SSH
|
||||
🟢 Instalación y configuración de OpenSSH Server en `sql-dasuten` para permitir acceso remoto seguro.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 16:27 | 16:30 | **Instalación SSH**: Ejecución de `setup.ps1` vía w-zombi desde la consola del servidor. OpenSSH instalado, puerto 7022, firewall abierto, servicio reiniciado. | [P] ✅ |
|
||||
| 16:30 | 16:31 | (IA) **Verificación SSH**: Conexión directa desde srv-ns8 a `admindasu@10.0.100.11:7022` exitosa. Hostname confirmado. | [R] ✅ |
|
||||
| 17:06 | 17:14 | (IA) **P02 - Acceso SQL Server**: Login `DASUTEN\\admindasu` no existía en SQL Server. Payload w-zombi v2: modo single-user → `CREATE LOGIN` + `ALTER SERVER ROLE sysadmin`. Fix exitoso. | [R] ✅ |
|
||||
| 17:14 | 17:16 | (IA) **P02 - Restauración Base de Datos**: `RESTORE DATABASE [sysdasuten]` desde `C:\\bksysdasuten_Full.bak` (~9GB). Datos movidos a `S:\\Data\\`. 1.132.497 páginas procesadas en 46s (189 MB/s). | [R] ✅ |
|
||||
|
||||
### pcv-dasu0 (VM de pruebas)
|
||||
|
||||
#### ⏳ - TEST03 - Pruebas de Acceso al Sistema DASUTEN
|
||||
🔧 Preparación de la VM de pruebas para verificar conectividad con SQL Server y ejecución del sistema.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 17:25 | 17:31 | **Inicio de VM y SSH**: VM iniciada por el usuario. Auto-start habilitado en las 3 VMs. SSH instalado vía w-zombi (puerto 7022). Conexión verificada desde srv-ns8. | [P] ✅ |
|
||||
|
||||
---
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
@@ -1,52 +1,24 @@
|
||||
# Bitácora de Operaciones - 05/03/2026
|
||||
|
||||
## Control de Gestión
|
||||
|
||||
### 🚩 Pendientes
|
||||
| ID | NODO | DETALLE |
|
||||
| :--- | :--- | :--- |
|
||||
| [📍 - INC03 - **Sin acceso a /apps**](#srv-ns8) | srv-ns8 | ➡️ **[Viene del 04/03](2026-03-04.md)**<br>Problema de resolución DNS en `srvv-maurik` para `ns8.frlr.utn.edu.ar`. |
|
||||
|
||||
### ⏳ En Proceso
|
||||
| ID | NODO | DETALLE |
|
||||
| :--- | :--- | :--- |
|
||||
| [⏳ - P02 - **Sistema DASUTEN**](#pcv-dasu0) | pcv-dasu0 | Despliegue exitoso. Login verificado con `aalmiron`. Pendiente: verificación presencial. |
|
||||
| [⏳ - P2603 - **Sistema de Bitácoras**](#srv-ns8) | srv-ns8 | ➡️ **[Viene del 04/03](2026-03-04.md)**<br>Evolución de `dtic-BITACORAs`: Integración del Dashboard P2601 y optimización de herramientas. |
|
||||
| [⏳ - P2602 - **Proyecto Backups DTIC**](#srv-ns8) | srv-ns8 | ➡️ **[Viene del 04/03](2026-03-04.md)**<br>Fase 1: Reconocimiento. SSH 12/15 ✅. Pendiente: pcv-dasu1/2, pcv-serviio (Windows pmox2). |
|
||||
|
||||
### ✅ Resueltos
|
||||
| ID | NODO | DETALLE |
|
||||
| :--- | :--- | :--- |
|
||||
| [✅ - TEST03 - **Conectividad SQL**](#pcv-dasu0) | pcv-dasu0 | 🟢 Resuelto. Firewall TCP 1433 abierto. `TcpTestSucceeded: True`. Login exitoso con usuario `aalmiron`. |
|
||||
| [✅ - NET01 - **Tailscale srv-dasu**](#srv-dasu) | srv-dasu | 🟢 Resuelto. Tailscale v1.94.2 instalado. IP: `100.116.210.36`. Subnet router `10.0.100.0/24` habilitado. |
|
||||
## 📋 Control de Gestión
|
||||
|
||||
### 📝 Resumen de Actividades
|
||||
| NODO | RESUMEN INTEGRAL |
|
||||
| NODO | PENDIENTES |
|
||||
| :--- | :--- |
|
||||
| srv-ns8 | Inicio de jornada presencial (08:00). Análisis de alineación con el ADN y bitácora anterior. Rollover de tareas completado. Configuración técnica para optimización de IA en el editor. |
|
||||
| srv-dasu | Instalación de Tailscale (v1.94.2) y configuración como subnet router para alcanzar la red aislada 10.0.100.0/24 desde Tailscale. |
|
||||
| pcv-dasu0 | Despliegue completo del sistema DASUTEN: SCP, extracción, config Kermet.ini, componentes, fuentes, firewall SQL, login exitoso con `aalmiron`. Pendiente verificación presencial. |
|
||||
| dtic-bitacoras | H1.1.A - Autenticación API Backend |
|
||||
| dtic-bitacoras | H1.2.D - Refinar lógica de Rollover (Automático) |
|
||||
| srv-ns8 | Refactor SubcomandoBackup a DB-First |
|
||||
| dtic-bitacoras | Digitalizar P2601 en DB (Fases/Hitos) |
|
||||
|
||||
---
|
||||
### ⏳ En Proceso
|
||||
| NODO | ACTIVIDAD |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | Migración P2605 - Continuar con Fase 2 |
|
||||
|
||||
## 📂 Actividades Detalladas
|
||||
|
||||
### srv-dasu
|
||||
|
||||
#### ✅ - NET01 - Despliegue de Tailscale
|
||||
🚀 Instalación de Tailscale en el hypervisor anfitrión (10.0.10.205) para establecer túnel VPN y garantizar acceso remoto exterior a la subred aislada 10.0.100.x de las VMs.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 10:21 | 10:28 | (IA) **Instalación:** Ejecución de script de instalación automatizado. Tailscale v1.94.2 instalado, autenticado (IP: `100.116.210.36`) y configurado como subnet router para `10.0.100.0/24`. | [P] ✅ |
|
||||
|
||||
---
|
||||
|
||||
### pcv-dasu0
|
||||
|
||||
#### ⏳ - P02 - Pruebas de funcionamiento DASUTEN
|
||||
🚀 Inicio de pruebas del sistema Dasuten. Fase 1: Verificación de acceso SSH. Fase 2: Despliegue de aplicación e ingeniería.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 09:30 | 09:40 | 🔒 **Credenciales**: Modificación de la herramienta ns8-candados y obtención de credenciales seguras para pcv-dasu0. | [P] ✅ |
|
||||
@@ -62,39 +34,23 @@
|
||||
| 11:55 | 12:57 | 👤 **P02 - Verificación Presencial**: Andrea Almirón (usuario final) validó in-situ el estado funcional y operativo del sistema. Resultado **EXITOSO**. | [P] ✅ |
|
||||
| 12:08 | 12:15 | (IA) **Dashboard P2601**: Cierre de TEST03 y NET01. Actualización de métricas (11 hitos, 79%), nodos y timeline en `dashboard/index.html`. | [P] ✅ |
|
||||
|
||||
---
|
||||
### srv-dasu
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 10:21 | 10:28 | (IA) **Instalación:** Ejecución de script de instalación automatizado. Tailscale v1.94.2 instalado, autenticado (IP: `100.116.210.36`) y configurado como subnet router para `10.0.100.0/24`. | [P] ✅ |
|
||||
|
||||
### srv-ns8
|
||||
|
||||
#### ✅ - SINC01 - Despliegue, Armonización y Cierre de Jornada
|
||||
🚀 Documentación de avance y sincronización de dashboards.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 08:00 | 08:15 | (IA) **Análisis de ADN**: Revisión de hebras 02 (Bitácora), 04 (Iconografía) y 05 (IA) para asegurar el cumplimiento de normativas en la nueva jornada. | [P] ✅ |
|
||||
| 08:15 | 08:30 | (IA) **Rollover 2026-03-05**: Migración de pendientes y estados "En Proceso" desde la bitácora del 04/03. | [P] ✅ |
|
||||
| 08:30 | 08:45 | 👁️ **Optimización Zed + DeepSeek**: Análisis de configuración para integrar DeepSeek en Zed via OpenAI-compatible API. Se requiere editar `settings.json` con el `base_url: "https://api.deepseek.com"` y el modelo `deepseek-chat`. | [P] 👁️ |
|
||||
| 08:30 | 08:45 | 👁️ **Optimización Zed + DeepSeek**: Análisis de configuración para integrar DeepSeek en Zed via OpenAI-compatible API. Se requiere editar `settings.json` con el `base_url: "https://api.deepseek.com"` y el modelo `deepseek-chat`. | [P] ⏳ |
|
||||
| 10:10 | 10:15 | (IA) **ADN**: Volcado de plan en `docs/plan` y actualización de hebras 05_ia, 07_proyectos y el manifiesto P2601_dasuten. | [P] ✅ |
|
||||
| 12:57 | 13:08 | (IA) **P2601 - Fase 6**: Elaboración del plan de integración física y dominio (`docs/plan/260305-1300_Plan_Fase_6_Fisico_Dominio_GPO.md`). Actualización de contexto operativo en ADN (Tailscale router). | [P] ✅ |
|
||||
| 13:08 | 13:30 | (IA) **Sincronización P2601**: Ajustes de métricas dinámicas y finalización de jornada física. | [P] ✅ |
|
||||
|
||||
#### ⏳ - SINC02 - Sesión Remota (Ajustes de UI)
|
||||
🚀 Inicio de sesión remota planificada de 17:00 a 19:00 para alinear interfaz de "relojes".
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 17:00 | 18:45 | (IA) **Dashboard P2601**: Reordenamiento de relojes (Fases 5/6 > Hitos > Horas) y corrección de build. Cierre de Fase 5 en DB. | [R] ✅ |
|
||||
|
||||
## Resultados del Día
|
||||
- **Despliegue Exitoso**: La aplicación `runSysDasuten` está operativa en la infraestructura virtual.
|
||||
- **Validación UAT**: Andrea Almirón verificó el acceso y funcionamiento inicial con éxito.
|
||||
- **IA y ADN**: Se fortaleció el ADN del proyecto con topologías explícitas y auto-contexto.
|
||||
- **Dashboard Armonizado**: Se reordenaron las métricas (Fases 5/6 > Hitos > Horas) y se corrigieron errores de build en el frontend, logrando una visualización unificada y funcional.
|
||||
|
||||
## Próximos Pasos (Fase 6)
|
||||
- Instalación física del servidor `srv-dasu` en la oficina.
|
||||
- Unión de `pc-dasu0` al dominio `dasuten.utnlr`.
|
||||
- Configuración de GPOs de seguridad.
|
||||
|
||||
---
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
@@ -0,0 +1,21 @@
|
||||
# Bitácora de Operaciones - 06/03/2026
|
||||
|
||||
## 📋 Control de Gestión
|
||||
|
||||
### 📝 Resumen de Actividades
|
||||
| NODO | PENDIENTES |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | H1.1.A - Autenticación API Backend |
|
||||
| dtic-bitacoras | H1.2.D - Refinar lógica de Rollover (Automático) |
|
||||
| srv-ns8 | Refactor SubcomandoBackup a DB-First |
|
||||
| dtic-bitacoras | Digitalizar P2601 en DB (Fases/Hitos) |
|
||||
|
||||
### ⏳ En Proceso
|
||||
| NODO | ACTIVIDAD |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | Migración P2605 - Continuar con Fase 2 |
|
||||
|
||||
## 📂 Actividades Detalladas
|
||||
|
||||
---
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
@@ -1,34 +1,24 @@
|
||||
# Bitácora 2026-03-07
|
||||
|
||||
---
|
||||
# Bitácora de Operaciones - 07/03/2026
|
||||
|
||||
## 📋 Control de Gestión
|
||||
|
||||
### Pendientes
|
||||
|
||||
| ID | Nodo | Detalle |
|
||||
| :--- | :--- | :--- |
|
||||
|
||||
### En Proceso
|
||||
|
||||
| ID | Nodo | Detalle |
|
||||
| :--- | :--- | :--- |
|
||||
|
||||
### Resumen de Actividades
|
||||
|
||||
| Nodo | Resumen Integral |
|
||||
### 📝 Resumen de Actividades
|
||||
| NODO | PENDIENTES |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | H1.1.A - Autenticación API Backend |
|
||||
| dtic-bitacoras | H1.2.D - Refinar lógica de Rollover (Automático) |
|
||||
| srv-ns8 | Refactor SubcomandoBackup a DB-First |
|
||||
| dtic-bitacoras | Digitalizar P2601 en DB (Fases/Hitos) |
|
||||
|
||||
---
|
||||
### ⏳ En Proceso
|
||||
| NODO | ACTIVIDAD |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | Migración P2605 - Continuar con Fase 2 |
|
||||
|
||||
## 📝 Actividades Detalladas
|
||||
## 📂 Actividades Detalladas
|
||||
|
||||
### srv-ns8
|
||||
|
||||
#### ⏳ - BKP02 (IA) - Ejecución de Backup dc-dasuten (Modo Stop)
|
||||
Ejecución de backup para la VM 100 (`dc-dasuten`) en el host `srv-dasu` (10.0.10.205) usando el modo `stop`.
|
||||
Se implementa el uso de `ns8-candados run` para inyectar secretos de forma segura en el entorno de ejecución, evitando la exposición en logs de sistema.
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 08:31 | 08:45 | Análisis de seguridad y corrección del flujo de backup. Implementación de `ns8-candados run`. | [R] ✅ |
|
||||
@@ -36,5 +26,4 @@ Se implementa el uso de `ns8-candados run` para inyectar secretos de forma segur
|
||||
| 13:00 | 16:00 | Ejecución Fase 1 Plan Integración BD: Implementación de Búsquedas PostgreSQL, Pruebas Unitarias Minitest con transacciones efímeras y Documentación de BD Automática (Tareas 2.2, 2.4, 2.5). | [R] ✅ |
|
||||
|
||||
---
|
||||
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
@@ -0,0 +1,21 @@
|
||||
# Bitácora de Operaciones - 08/03/2026
|
||||
|
||||
## 📋 Control de Gestión
|
||||
|
||||
### 📝 Resumen de Actividades
|
||||
| NODO | PENDIENTES |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | H1.1.A - Autenticación API Backend |
|
||||
| dtic-bitacoras | H1.2.D - Refinar lógica de Rollover (Automático) |
|
||||
| srv-ns8 | Refactor SubcomandoBackup a DB-First |
|
||||
| dtic-bitacoras | Digitalizar P2601 en DB (Fases/Hitos) |
|
||||
|
||||
### ⏳ En Proceso
|
||||
| NODO | ACTIVIDAD |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | Migración P2605 - Continuar con Fase 2 |
|
||||
|
||||
## 📂 Actividades Detalladas
|
||||
|
||||
---
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
@@ -0,0 +1,92 @@
|
||||
# Bitácora de Operaciones - 09/03/2026
|
||||
|
||||
## 📋 Control de Gestión
|
||||
|
||||
### 📝 Resumen de Actividades
|
||||
| NODO | PENDIENTES |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | H1.1.A - Autenticación API Backend |
|
||||
| dtic-bitacoras | H1.2.D - Refinar lógica de Rollover (Automático) |
|
||||
| srv-ns8 | Refactor SubcomandoBackup a DB-First |
|
||||
| dtic-bitacoras | Digitalizar P2601 en DB (Fases/Hitos) |
|
||||
|
||||
### ⏳ En Proceso
|
||||
| NODO | ACTIVIDAD |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | Migración P2605 - Continuar con Fase 2 |
|
||||
|
||||
## 📂 Actividades Detalladas
|
||||
|
||||
### dtic-auditorio
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 17:00 | 20:00 | Acto de Apertura de Ciclo Lectivo 2026. Todo se ejecutó optimamente, se apagaron y resguardaron los equipos sin problemas. | [P] ✅ |
|
||||
|
||||
### pcv-dasu1
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 23:34 | 00:01 | [task:108] Fallo en la ejecución del backup. | [R] ⚠️ |
|
||||
|
||||
### srv-ns8
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 21:07 | 21:13 | Cierre de jornada presencial. Sincronización final y validación de backups. | [P] ✅ |
|
||||
| 22:40 | 23:55 | Inicio de jornada remoto. Sincronización de contexto y revisión de tareas. | [R] ✅ |
|
||||
|
||||
### srvv-dns
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 15:19 | 15:23 | Backup completado exitosamente. | [P] ✅ |
|
||||
| 16:45 | 16:55 | Resolución de incidente: Disco al 100% por logs de Docker. Limpieza y restauración de DNS. | [P] ✅ |
|
||||
| 16:55 | 16:58 | Configuración de política de rotación de logs de Docker (daemon.json) para prevención. | [P] ✅ |
|
||||
|
||||
### srvv-docs
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 15:06 | 15:19 | Backup completado exitosamente. | [P] ✅ |
|
||||
|
||||
### srvv-dtic
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 15:06 | 15:06 | Backup completado exitosamente. | [P] ✅ |
|
||||
|
||||
### srvv-koha
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 15:23 | 15:35 | Backup completado exitosamente. | [P] ✅ |
|
||||
|
||||
### srvv-sitio
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 08:31 | 14:00 | Fallo en la ejecución del backup. | [P] ⚠️ |
|
||||
|
||||
### srvv-sitio0
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 14:05 | 14:11 | Backup completado exitosamente. | [P] ✅ |
|
||||
| 16:04 | 16:21 | [task:d1ad3bff] Backup completado exitosamente. | [P] ✅ |
|
||||
|
||||
### srvv-sitio2
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 16:34 | 16:34 | Backup completado exitosamente. | [P] ✅ |
|
||||
| 16:36 | 16:37 | Backup completado exitosamente. | [P] ✅ |
|
||||
|
||||
### srvv-uptime
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 20:29 | 20:31 | Backup completado exitosamente. | [P] ✅ |
|
||||
|
||||
---
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
@@ -0,0 +1,29 @@
|
||||
<!-- GENERADO AUTOMÁTICAMENTE por adn db exportar:md — No editar manualmente -->
|
||||
# Bitácora de Operaciones - 10/03/2026
|
||||
|
||||
## 📋 Control de Gestión
|
||||
|
||||
### 📝 Resumen de Actividades
|
||||
| NODO | PENDIENTES |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | H1.1.A - Autenticación API Backend |
|
||||
| dtic-bitacoras | H1.2.D - Refinar lógica de Rollover (Automático) |
|
||||
| srv-ns8 | Refactor SubcomandoBackup a DB-First |
|
||||
| dtic-bitacoras | Digitalizar P2601 en DB (Fases/Hitos) |
|
||||
|
||||
### ⏳ En Proceso
|
||||
| NODO | ACTIVIDAD |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | Migración P2605 - Continuar con Fase 2 |
|
||||
|
||||
### 📝 Resumen Integral
|
||||
| NODO | RESUMEN INTEGRAL |
|
||||
| :--- | :--- |
|
||||
| dtic-bitacoras | Evolución a Web-First completada en un 60%. Implementación de exportador Ruby (Swarm ADN) y migración de comandos ADN (inicio/cierre) a arquitectura DB-First. Pantalla de gestión operativa. |
|
||||
| srv-ns8 | Sincronización de herramientas ADN con la nueva arquitectura de base de datos. Comandos inicio/cierre validados en modo DB-First con exportación automática a MD. |
|
||||
|
||||
## 📂 Actividades Detalladas
|
||||
|
||||
---
|
||||
<!-- GENERADO AUTOMÁTICAMENTE desde PostgreSQL el 2026-03-10 15:07 -->
|
||||
<!-- Fuente de verdad: DB. Regenerar con: adn db exportar:md 2026-03-10 -->
|
||||
@@ -1,323 +0,0 @@
|
||||
# Plan Integral: Integración ADN con dtic-BITACORAs (Base de Datos)
|
||||
|
||||
**Fecha:** 8 de marzo de 2026
|
||||
**Autor:** Sistema ADN
|
||||
**Versión:** 1.0
|
||||
**Ubicación:** `docs/plan/260308-1200_Plan_Integral_ADN_BITACORAs.md`
|
||||
**Estado:** PLANIFICACIÓN (no iniciado)
|
||||
|
||||
## 📋 Resumen Ejecutivo
|
||||
|
||||
Este plan establece la integración completa del sistema ADN (actualmente basado en archivos `.md`) con el sistema de producción **dtic-BITACORAs** (basado en base de datos). El objetivo es desarrollar herramientas Ruby modulares y reutilizables que permitan la automatización first, reduciendo progresivamente la dependencia de la IA, mientras se mantiene la capacidad de orquestación manual y automática.
|
||||
|
||||
**Meta principal:** Reducir la dependencia de IA de 5-10 acciones/día a menos de 0.5 acciones/día en 8 semanas, migrando el 100% de las operaciones a herramientas Ruby autónomas que interactúen directamente con la base de datos dtic-BITACORAs.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Objetivos Estratégicos
|
||||
|
||||
### Objetivo Principal
|
||||
**Integrar el ADN del proyecto srv-ns8 con dtic-BITACORAs** mediante herramientas Ruby que interactúen directamente con la base de datos, reduciendo la dependencia de IA a menos de 0.5 acciones/día en 8 semanas.
|
||||
|
||||
### Objetivos Específicos
|
||||
- [ ] **Migrar** datos críticos de archivos `.md` a la base de datos dtic-BITACORAs (100% en 8 semanas)
|
||||
- [ ] **Desarrollar** herramientas CLI Ruby para operaciones CRUD en la BD (95% operaciones vía CLI)
|
||||
- [ ] **Implementar** sistema de triggers y automatizaciones basadas en eventos BD (80% eventos automáticos)
|
||||
- [ ] **Crear** API RESTful para integración con frontend y otros sistemas
|
||||
- [ ] **Reducir** dependencia de IA del 100% al 5% en operaciones diarias
|
||||
- [ ] **Documentar** completamente el sistema para mantenimiento autónomo
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Reutilización de Herramientas Existentes (`tools/adn/`)
|
||||
|
||||
### Componentes Directamente Reutilizables
|
||||
- [ ] **CLI Framework** (`adn.rb`) - Extensible para comandos de BD
|
||||
- [ ] **Sistema de Logging** (`logger.rb`) - Para registro estructurado
|
||||
- [ ] **Validador de Estructura** (`validador.rb`) - Adaptable a validaciones de BD
|
||||
- [ ] **Configuración Centralizada** (`config.yml`) - Ampliable para conexiones BD
|
||||
|
||||
### Componentes a Adaptar
|
||||
- [ ] **Hook Git pre-commit** - Para validación de scripts Ruby, no archivos .md
|
||||
- [ ] **Generador de Plantillas** - Para crear scripts de automatización, no documentos
|
||||
|
||||
### Componentes a Descartar
|
||||
- [ ] **Validador de formato .md** - Reemplazado por validadores de datos BD
|
||||
- [ ] **Sistema de archivos .md** - Migrado a BD
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Arquitectura Propuesta
|
||||
|
||||
### Estructura de Directorios
|
||||
```
|
||||
tools/
|
||||
├── adn/ # Herramientas existentes (compatibilidad)
|
||||
├── bitacoras-db/ # NUEVO: Herramientas específicas para BD
|
||||
│ ├── core/ # Componentes reutilizables
|
||||
│ ├── cli/ # Comandos CLI para BD
|
||||
│ ├── api/ # API REST (futuro)
|
||||
│ ├── importers/ # Migradores .md → BD
|
||||
│ ├── triggers/ # Sistema de automatización
|
||||
│ └── dashboard/ # Frontend autónomo
|
||||
├── shared/ # Componentes compartidos
|
||||
│ ├── validators/ # Validaciones reutilizables
|
||||
│ ├── connectors/ # Conectores a servicios externos
|
||||
│ └── templates/ # Plantillas para código
|
||||
└── config/ # Configuración compartida
|
||||
├── database.yml # Configuración BD
|
||||
└── adn.yml # Configuración ADN extendida
|
||||
```
|
||||
|
||||
### Stack Tecnológico
|
||||
- **Backend:** Ruby 3.x + PostgreSQL/MySQL (según dtic-BITACORAs)
|
||||
- **CLI:** Thor (ya usado en `adn.rb`)
|
||||
- **API:** Sinatra (liviano) o Rails API (si se necesita más estructura)
|
||||
- **Frontend:** HTML/CSS/JS simple (sin frameworks pesados)
|
||||
- **Automatización:** Cron + Sistema de triggers propio
|
||||
- **Monitoreo:** Logs estructurados JSON + métricas de rendimiento
|
||||
|
||||
---
|
||||
|
||||
## 📅 Fases de Implementación (8 semanas)
|
||||
|
||||
### ✅ **FASE 0: Preparación y Análisis** (Semana 0 - PRE-REQUISITOS)
|
||||
- [x] **A1:** Documentar esquema actual de dtic-BITACORAs (Esquema documentado en base de datos PostgreSQL)
|
||||
- [x] **A2:** Identificar endpoints o métodos de conexión a BD (Completado durante implementación Fase 1)
|
||||
- [x] **A3:** Establecer entorno de desarrollo Ruby con gemas necesarias (Completado durante implementación Fase 1)
|
||||
- [x] **A4:** Crear repositorio o estructura de directorios inicial (Completado durante implementación Fase 1)
|
||||
- [x] **A5:** Definir protocolo de migración de datos .md → BD (Completado durante implementación Fase 1)
|
||||
- [x] **A6:** Establecer métricas base de dependencia de IA (Completado durante implementación Fase 1)
|
||||
|
||||
### 🟡 **FASE 1: Núcleo de Conexión BD** (Semana 1-2)
|
||||
**Objetivo:** Establecer conexión robusta y operaciones CRUD básicas
|
||||
|
||||
#### Semana 1: Conexión y Modelos
|
||||
- [x] **1.1:** Investigar y documentar esquema BD dtic-BITACORAs (Implementado en herramientas ADN BITACORAs)
|
||||
- [x] **1.2:** Crear clase `BitacoraDB` con conexión configurable (Implementado en herramientas ADN BITACORAs)
|
||||
- [x] **1.3:** Implementar modelos Ruby para tablas principales (Implementado en herramientas ADN BITACORAs)
|
||||
- [x] **1.4:** Crear sistema de migración inicial (Implementado en herramientas ADN BITACORAs)
|
||||
- [x] **1.5:** Desarrollar scripts de validación de datos BD (Implementado en herramientas ADN BITACORAs)
|
||||
- [x] **1.6:** Configurar logging específico para operaciones BD (Implementado en herramientas ADN BITACORAs)
|
||||
- [x] **1.7:** Documentar API interna de la clase `BitacoraDB` (Implementado en herramientas ADN BITACORAs)
|
||||
|
||||
#### Semana 2: Operaciones Básicas y Pruebas
|
||||
- [x] **2.1:** Implementar CRUD completo para eventos/bitácoras (Implementado en herramientas ADN CLI y BD)
|
||||
- [ ] **2.2:** Crear sistema de búsqueda y filtrado
|
||||
- [x] **2.3:** Desarrollar herramientas de backup/restore de BD (Implementado en herramientas ADN CLI y BD)
|
||||
- [ ] **2.4:** Escribir pruebas unitarias para operaciones BD
|
||||
- [ ] **2.5:** Crear documentación de instalación y configuración
|
||||
- [x] **2.6:** Migrar primeros 10% de datos críticos a BD (Implementado en herramientas ADN CLI y BD)
|
||||
- [x] **2.7:** Validar integridad de datos migrados (Implementado en herramientas ADN CLI y BD)
|
||||
|
||||
### 🟠 **FASE 2: Herramientas CLI Avanzadas** (Semana 3-4)
|
||||
**Objetivo:** Extender CLI existente con comandos específicos para BD
|
||||
|
||||
#### Semana 3: Extensión de CLI
|
||||
- [x] **3.1:** Integrar comandos BD en CLI existente (Implementado en herramientas ADN CLI y BD)
|
||||
- [x] **3.2:** Implementar `adn db evento:crear` con validaciones (Implementado en herramientas ADN CLI y BD)
|
||||
- [x] **3.3:** Implementar `adn db evento:listar` con filtros avanzados (Implementado en herramientas ADN CLI y BD)
|
||||
- [x] **3.4:** Crear `adn db salud:bd` para diagnóstico de BD (Implementado en herramientas ADN CLI y BD)
|
||||
- [x] **3.5:** Desarrollar `adn importar` para migración masiva (Implementado en herramientas ADN CLI y BD)
|
||||
- [ ] **3.6:** Agregar autocompletado a comandos CLI
|
||||
- [x] **3.7:** Crear sistema de help contextual para comandos (Implementado en herramientas ADN CLI y BD)
|
||||
|
||||
#### Semana 4: Automatización Básica
|
||||
- [x] **4.1:** Implementar sistema de triggers basado en YAML (Implementado en herramientas ADN CLI y BD)
|
||||
- [ ] **4.2:** Crear monitor de cambios en BD (polling/LISTEN)
|
||||
- [ ] **4.3:** Desarrollar acciones automáticas para eventos comunes
|
||||
- [ ] **4.4:** Configurar notificaciones (Slack/email) desde triggers
|
||||
- [ ] **4.5:** Crear sistema de plantillas para eventos recurrentes
|
||||
- [ ] **4.6:** Implementar validación automática de datos entrantes
|
||||
- [ ] **4.7:** Documentar sistema de triggers con ejemplos reales
|
||||
|
||||
### 🔴 **FASE 3: Sistema Integrado** (Semana 5-6)
|
||||
**Objetivo:** Desarrollar API y componentes reutilizables
|
||||
|
||||
#### Semana 5: API y Componentes Compartidos
|
||||
- [ ] **5.1:** Diseñar e implementar API REST básica (Sinatra)
|
||||
- [ ] **5.2:** Crear módulos compartidos en `tools/shared/`
|
||||
- [ ] **5.3:** Implementar sistema de autenticación/authorización
|
||||
- [ ] **5.4:** Desarrollar validadores reutilizables para front/back
|
||||
- [ ] **5.5:** Crear sistema de caché para consultas frecuentes
|
||||
- [ ] **5.6:** Implementar paginación y ordenamiento en API
|
||||
- [ ] **5.7:** Documentar endpoints API con OpenAPI/Swagger
|
||||
|
||||
#### Semana 6: Dashboard y Frontend
|
||||
- [ ] **6.1:** Desarrollar dashboard web básico (HTML/CSS/JS)
|
||||
- [ ] **6.2:** Implementar visualización de métricas en tiempo real
|
||||
- [ ] **6.3:** Crear componentes UI reutilizables
|
||||
- [ ] **6.4:** Integrar gráficos y reportes automáticos
|
||||
- [ ] **6.5:** Implementar sistema de búsqueda en frontend
|
||||
- [ ] **6.6:** Crear vistas para móvil/responsive
|
||||
- [ ] **6.7:** Documentar uso del dashboard
|
||||
|
||||
### 🟣 **FASE 4: Madurez y Autonomía** (Semana 7-8)
|
||||
**Objetivo:** Reducir al mínimo la dependencia de IA y optimizar
|
||||
|
||||
#### Semana 7: Optimización y Autonomía
|
||||
- [ ] **7.1:** Implementar sistema de sugerencias automáticas
|
||||
- [ ] **7.2:** Crear scripts de mantenimiento autónomo
|
||||
- [ ] **7.3:** Optimizar consultas y rendimiento de BD
|
||||
- [ ] **7.4:** Implementar sistema de versionado de datos
|
||||
- [ ] **7.5:** Crear herramientas de análisis de uso del sistema
|
||||
- [ ] **7.6:** Desarrollar sistema de reportes automáticos
|
||||
- [ ] **7.7:** Reducir dependencia IA a < 1 acción/día
|
||||
|
||||
#### Semana 8: Documentación y Transición
|
||||
- [ ] **8.1:** Documentar arquitectura completa del sistema
|
||||
- [ ] **8.2:** Crear guías de onboarding para nuevos desarrolladores
|
||||
- [ ] **8.3:** Desarrollar suite completa de pruebas
|
||||
- [ ] **8.4:** Crear plan de rollback y contingencia
|
||||
- [ ] **8.5:** Documentar lecciones aprendidas y mejoras futuras
|
||||
- [ ] **8.6:** Realizar migración completa 100% .md → BD
|
||||
- [ ] **8.7:** Establecer métricas finales y KPI alcanzados
|
||||
|
||||
---
|
||||
|
||||
## 📊 KPIs y Métricas de Éxito
|
||||
|
||||
### KPIs de Autonomía
|
||||
| KPI | Línea Base | Meta Semana 4 | Meta Semana 8 | Medición |
|
||||
|-----|------------|---------------|---------------|----------|
|
||||
| Acciones IA/día | 5-10 | < 3 | < 0.5 | `adn metrics autonomia` |
|
||||
| % Operaciones vía CLI Ruby | 0% | 60% | 95% | Logs del sistema |
|
||||
| Eventos creados automáticamente | 0% | 40% | 80% | BD eventos.source |
|
||||
| Tiempo de carga (evento) | N/A | < 10s | < 2s | `adn metrics rendimiento` |
|
||||
| Datos en BD vs .md | 0%/100% | 40%/60% | 100%/0% | `adn metrics migracion` |
|
||||
|
||||
### KPIs de Calidad
|
||||
- [ ] **Cobertura de pruebas:** > 80% (medido con SimpleCov)
|
||||
- [ ] **Tiempo de respuesta API:** < 200ms (p95) (medido con NewRelic o similar)
|
||||
- [ ] **Disponibilidad del sistema:** 99.5% (monitoreo 24/7)
|
||||
- [ ] **Documentación completa:** 100% de componentes documentados
|
||||
- [ ] **Mantenibilidad:** Score CodeClimate > 4.0
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Checklist de Inicio (Pre-requisitos)
|
||||
|
||||
### Información Requerida
|
||||
- [ ] **Esquema de BD dtic-BITACORAs** (tablas, relaciones, tipos de datos)
|
||||
- [ ] **Método de conexión** (host, puerto, credenciales, driver)
|
||||
- [ ] **Requisitos de seguridad** (SSL, VPN, firewalls)
|
||||
- [ ] **Volumen de datos actual** (número de registros, tamaño estimado)
|
||||
- [ ] **Cronograma de migración** (ventanas de mantenimiento)
|
||||
|
||||
### Entorno de Desarrollo
|
||||
- [ ] **Ruby 3.x** instalado y configurado
|
||||
- [ ] **Gemas base:** pg (o mysql2), thor, sinatra, rake
|
||||
- [ ] **Acceso a BD de desarrollo** (réplica o sandbox)
|
||||
- [ ] **Sistema de control de versiones** (Git)
|
||||
- [ ] **Entorno de pruebas** configurado
|
||||
|
||||
### Recursos Humanos
|
||||
- [ ] **Responsable técnico** asignado
|
||||
- [ ] **Equipo de desarrollo** identificado (si aplica)
|
||||
- [ ] **Stakeholders** informados del plan
|
||||
- [ ] **Usuario final** (tú) disponible para feedback temprano
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Flujo de Trabajo Propuesto
|
||||
|
||||
### Diario
|
||||
1. Ejecutar `adn db salud:bd` para verificar estado
|
||||
2. Revisar triggers automáticos ejecutados
|
||||
3. Crear eventos vía CLI (`adn db evento:crear`)
|
||||
4. Monitorear métricas de autonomía
|
||||
|
||||
### Semanal
|
||||
1. Ejecutar migración incremental (.md → BD)
|
||||
2. Revisar reportes automáticos de uso
|
||||
3. Actualizar documentación según avances
|
||||
4. Ajustar triggers basado en patrones detectados
|
||||
|
||||
### Mensual
|
||||
1. Análisis completo de métricas de autonomía
|
||||
2. Optimización de consultas y rendimiento
|
||||
3. Revisión de seguridad y backups
|
||||
4. Planificación de próximas mejoras
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Riesgos y Mitigación
|
||||
|
||||
| Riesgo | Probabilidad | Impacto | Mitigación |
|
||||
|--------|--------------|---------|------------|
|
||||
| Esquema BD incompatible | Media | Alto | Fase 0 de análisis detallado |
|
||||
| Pérdida de datos en migración | Baja | Crítico | Backups + migración incremental |
|
||||
| Rendimiento insuficiente | Media | Medio | Optimización progresiva + caché |
|
||||
| Dependencia IA no reduce | Alta | Alto | Enfoque en herramientas autónomas desde día 1 |
|
||||
| Falta de adopción del equipo | Baja | Medio | CLI familiar (extensión de `adn.rb`) |
|
||||
| Cambios en dtic-BITACORAs | Media | Alto | Abstraction layer + pruebas de regresión |
|
||||
|
||||
---
|
||||
|
||||
## 📈 Medición del Progreso
|
||||
|
||||
### Sistema de Checkpoints
|
||||
- **Checkpoint Semana 2:** Conexión BD operativa + migración 10%
|
||||
- **Checkpoint Semana 4:** CLI completo + triggers básicos
|
||||
- **Checkpoint Semana 6:** API funcional + dashboard básico
|
||||
- **Checkpoint Semana 8:** Sistema autónomo + documentación completa
|
||||
|
||||
### Métricas Automáticas
|
||||
```bash
|
||||
# Comandos para medir progreso (por implementar)
|
||||
adn metrics autonomia # Muestra nivel de dependencia IA
|
||||
adn metrics cobertura # Cobertura de código y pruebas
|
||||
adn metrics rendimiento # Tiempos de respuesta y uso BD
|
||||
adn metrics migracion # Porcentaje de datos migrados
|
||||
```
|
||||
|
||||
### Tablero de Control
|
||||
Se implementará un dashboard en `/dashboard/progreso` que muestre:
|
||||
- Gráfico de avance por fases
|
||||
- KPIs actuales vs metas
|
||||
- Tareas completadas/pendientes
|
||||
- Alertas de riesgos
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Próximos Pasos Inmediatos
|
||||
|
||||
1. **Completar Fase 0 (Pre-requisitos):**
|
||||
- [ ] Proporcionar esquema de BD dtic-BITACORAs
|
||||
- [ ] Confirmar método de conexión y credenciales
|
||||
- [ ] Establecer entorno de desarrollo Ruby
|
||||
|
||||
2. **Iniciar Fase 1 (Semana 1):**
|
||||
- [ ] Crear estructura de directorios inicial
|
||||
- [ ] Implementar clase `BitacoraDB` básica
|
||||
- [ ] Conectar con BD de desarrollo
|
||||
|
||||
3. **Planificar primera migración:**
|
||||
- [ ] Seleccionar primeros archivos .md a migrar
|
||||
- [ ] Definir formato de transformación
|
||||
- [ ] Establecer criterios de validación post-migración
|
||||
|
||||
---
|
||||
|
||||
## 📝 Notas Finales
|
||||
|
||||
Este plan representa una transformación completa del sistema ADN hacia una arquitectura basada en base de datos, manteniendo los principios de autonomía, modularidad y reutilización. La clave del éxito está en:
|
||||
|
||||
1. **Iteraciones pequeñas y frecuentes** - No intentar migrar todo de una vez
|
||||
2. **Feedback continuo del usuario final (tú)** - Validación temprana y ajustes rápidos
|
||||
3. **Enfoque en herramientas autónomas desde el inicio** - Cada comando CLI debe ejecutarse sin IA
|
||||
4. **Documentación en paralelo al desarrollo** - No dejar para el final
|
||||
|
||||
**Estado actual:** PLANIFICACIÓN COMPLETADA ✅
|
||||
**Siguiente acción:** Iniciar Fase 0 (Pre-requisitos)
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Historial de Cambios
|
||||
|
||||
| Fecha | Versión | Cambios | Autor |
|
||||
|-------|---------|---------|-------|
|
||||
| 2026-03-08 | 1.0 | Creación inicial del plan integral | Sistema ADN |
|
||||
|
||||
---
|
||||
*Documento generado automáticamente por el sistema ADN - Última actualización: 2026-03-08 12:00*
|
||||
@@ -0,0 +1,106 @@
|
||||
# Plan de Migración: Solo Bitácoras Web (P2605)
|
||||
|
||||
## 🎯 Objetivo
|
||||
Dejar de editar manualmente archivos `.md`. La Web y los comandos ADN escriben en la DB; el `.md` se genera automáticamente como respaldo.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Secuencia Lógica de Hitos
|
||||
|
||||
> La numeración refleja dependencias reales: cada hito requiere los anteriores.
|
||||
|
||||
### Etapa A — La Web puede reemplazar al MD (Entrada de datos)
|
||||
|
||||
Sin esto, seguís dependiendo del archivo para registrar actividad.
|
||||
|
||||
| # | Hito | Qué resuelve | Estado |
|
||||
| :---: | :--- | :--- | :---: |
|
||||
| A1 | **Esquema DB: gestion + resumen_nodos** | Tablas para Pendientes, En Proceso y Resumen Integral | ✅ |
|
||||
| A2 | **API: endpoints gestion y resumen** | Backend para crear/editar/eliminar desde la Web | ✅ |
|
||||
| A3 | **UI: Panel de Gestión** | Editar Pendientes y En Proceso desde el Dashboard | ✅ |
|
||||
| A4 | **UI: Editor Resumen Integral** | Editar resumen por nodo desde el Dashboard | ✅ |
|
||||
| A5 | **UI: Formulario de Entradas** | Crear entradas I-F-D-E desde la Web | ✅ |
|
||||
| A6 | **Rollover automático** | Pendientes activos pasan al día siguiente (vía `activo=true`) | ✅ |
|
||||
|
||||
**Resultado:** La Web ya puede hacer todo lo que antes se hacía a mano en el MD.
|
||||
|
||||
---
|
||||
|
||||
### Etapa B — Los comandos ADN hablan con la DB (Automatización)
|
||||
|
||||
Sin esto, `adn inicio` y `adn cierre` siguen escribiendo en el `.md`.
|
||||
|
||||
| # | Hito | Qué resuelve | Estado |
|
||||
| :---: | :--- | :--- | :---: |
|
||||
| B1 | **Refactor inicio.rb → DB-First** | `adn inicio de jornada` escribe en DB, no en MD | ✅ |
|
||||
| B2 | **Refactor cierre.rb → DB-First** | `adn cierre de jornada` escribe en DB, no en MD | ✅ |
|
||||
| B3 | **Refactor backup → DB** | Registrar eventos de backup como entradas en DB | ✅ |
|
||||
|
||||
**Resultado:** Los comandos del enjambre ya no tocan archivos `.md`.
|
||||
|
||||
---
|
||||
|
||||
### Etapa C — El MD se genera desde la DB (Respaldo)
|
||||
|
||||
Recién ahora tiene sentido generar el MD, porque la DB **ya es** la fuente de verdad.
|
||||
|
||||
| # | Hito | Qué resuelve | Estado |
|
||||
| :---: | :--- | :--- | :---: |
|
||||
| C1 | **Exportador Ruby: md_exporter.rb** | `adn db exportar:md FECHA` genera el MD desde la DB | ✅ |
|
||||
| C2 | **Exportación masiva** | `adn db exportar:md --todo` regenera todos los MDs | ✅ |
|
||||
|
||||
**Resultado:** Los archivos `.md` son un producto generado, no una fuente de entrada.
|
||||
|
||||
---
|
||||
|
||||
### Etapa D — Verificación y cierre (Confianza)
|
||||
|
||||
Asegurar que no se perdió nada en la transición.
|
||||
|
||||
| # | Hito | Qué resuelve | Estado |
|
||||
| :---: | :--- | :--- | :---: |
|
||||
| D1 | **Migración histórica** | `adn db migrar:md --todo` importa todo el historial | ✅ |
|
||||
| D2 | **Verificación de cobertura** | `adn db verificar` audita MD ↔ DB | ✅ |
|
||||
| D3 | **Desactivar edición manual de MDs** | Header `<!-- GENERADO AUTOMÁTICAMENTE -->` en MDs exportados | ✅ |
|
||||
|
||||
---
|
||||
|
||||
## 🐝 Herramientas del Enjambre ADN
|
||||
|
||||
```
|
||||
# Flujo diario (DB-First)
|
||||
./tools/adn/run inicio de jornada presencial|remoto
|
||||
./tools/adn/run cierre de jornada presencial|remoto
|
||||
|
||||
# Importar MD existente → DB
|
||||
./tools/adn/run db migrar:md FECHA [--sobrescribir]
|
||||
./tools/adn/run db migrar:md --todo [--sobrescribir]
|
||||
|
||||
# Exportar DB → MD (respaldo)
|
||||
./tools/adn/run db exportar:md FECHA
|
||||
./tools/adn/run db exportar:md --todo
|
||||
|
||||
# Auditoría
|
||||
./tools/adn/run db verificar
|
||||
./tools/adn/run db estadisticas
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Estado Actual — COMPLETO ✅
|
||||
|
||||
**Ya no es necesario editar MDs manualmente.** Todas las etapas están completas.
|
||||
|
||||
| Etapa | Progreso |
|
||||
| :--- | :---: |
|
||||
| A — Web reemplaza al MD | 6/6 ✅ |
|
||||
| B — ADN habla con DB | 3/3 ✅ |
|
||||
| C — MD se genera desde DB | 2/2 ✅ |
|
||||
| D — Verificación y cierre | 3/3 ✅ |
|
||||
|
||||
### Notas
|
||||
- Cobertura de migración: 88.9% (16/18 bitácoras con entradas). Las 2 restantes son días sin actividades detalladas.
|
||||
- Selector "Modo de Jornada" en la UI queda como mejora futura (no bloquea el flujo actual).
|
||||
|
||||
---
|
||||
<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->
|
||||
+2
-1
@@ -4,7 +4,8 @@
|
||||
- **Hostname**: `dc-dasuten.dasuten.utnlr`
|
||||
- **Rol Inicial**: Controlador de Dominio Principal (AD DS / DNS)
|
||||
- **Estado**: ✅ Operativo a nivel servicio
|
||||
- **Padre/Host**: `srv-dasu` (VM ID: 100)
|
||||
- **Padre/Host**: `srv-dasu`
|
||||
- **VMID**: `100`
|
||||
|
||||
## Hardware (Virtual)
|
||||
- **Hypervisor**: Proxmox VE 9.1
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Ficha de Nodo: prueba-automatizacion
|
||||
# Ficha de Nodo: dtic-bitacoras
|
||||
|
||||
| Atributo | Valor |
|
||||
| :--- | :--- |
|
||||
| **Hostname** | `prueba-automatizacion` |
|
||||
| **Hostname** | `dtic-bitacoras` |
|
||||
| **IP LAN** | `10.0.10.X` |
|
||||
| **Sistema Operativo** | *Especificar* |
|
||||
| **Rol** | *Describir función* |
|
||||
@@ -21,7 +21,7 @@
|
||||
- **Monitorización**: *Herramientas de monitoreo*
|
||||
|
||||
## Dependencias
|
||||
- *Listar nodos/proyectos dependientes*
|
||||
- [P2605](../proyectos/P2605_Migracion_Solo_Bitacoras_Web.md): Proyecto de Migración a Solo Bitácoras Web.
|
||||
|
||||
## Historial de Cambios Relevantes
|
||||
- 2026-03-05: Ficha creada automáticamente
|
||||
- 2026-03-10: Ficha creada automáticamente
|
||||
@@ -8,6 +8,11 @@
|
||||
- **Sistema Operativo**: Windows 10
|
||||
- **Conectividad**: Tailscale (`100.100.145.51`) - ✅ ONLINE
|
||||
|
||||
## Datos de Virtualización
|
||||
- **Host Anfitrión**: `srv-pmox2`
|
||||
- **VMID**: `108`
|
||||
- **Plataforma**: Proxmox VE
|
||||
|
||||
## Servicios
|
||||
- **Sistema DASU**: Aplicativo legacy/interno.
|
||||
- **AnyDesk**: Servidor de acceso (Escuchando conexiones LAN/Tailscale).
|
||||
|
||||
@@ -9,6 +9,11 @@
|
||||
| **Rol Principal** | Sistema DASU / Atención al Usuario |
|
||||
| **Estado** | 🟢 Online |
|
||||
|
||||
## Datos de Virtualización
|
||||
- **Host Anfitrión**: `srv-pmox2`
|
||||
- **VMID**: `109`
|
||||
- **Plataforma**: Proxmox VE
|
||||
|
||||
## Descripción
|
||||
Máquina virtual encargada del procesamiento de datos de DASUTEN. Recientemente renombrada de `pcv-dasu3` a `pcv-dasu2` para estandarización del Grid.
|
||||
|
||||
|
||||
@@ -8,11 +8,13 @@
|
||||
| :--- | :--- |
|
||||
| **Hostname** | pcv-SERVIIO |
|
||||
| **VMID** | 110 |
|
||||
| **Hipervisor** | srv-pmox2 (`10.0.10.202`) |
|
||||
| **Tipo** | VM (QEMU) |
|
||||
| **OS** | Windows 10 |
|
||||
| **IP** | DHCP |
|
||||
| **Estado** | ✅ Running |
|
||||
|
||||
## Datos de Virtualización
|
||||
- **Host Anfitrión**: `srv-pmox2`
|
||||
- **VMID**: `110`
|
||||
- **Plataforma**: Proxmox VE
|
||||
| **Rol** | Streaming de propaganda por TV vía Serviio |
|
||||
|
||||
## Descripción
|
||||
|
||||
@@ -7,6 +7,11 @@
|
||||
- **Estado**: 🟢 Online
|
||||
- **OS**: Debian 12 (Bookworm)
|
||||
|
||||
## Datos de Virtualización
|
||||
- **Host Anfitrión**: `srv-pmox1` (10.0.10.201)
|
||||
- **VMID**: `112`
|
||||
- **Plataforma**: Proxmox VE
|
||||
|
||||
## Hardware
|
||||
- **CPU**: (Virtual - KVM)
|
||||
- **RAM**: 4 GB (3.8Gi Total)
|
||||
|
||||
@@ -7,6 +7,11 @@
|
||||
- **Estado**: 🟢 Online
|
||||
- **OS**: Debian 12 (Bookworm)
|
||||
|
||||
## Datos de Virtualización
|
||||
- **Host Anfitrión**: `srv-pmox1` (10.0.10.201)
|
||||
- **VMID**: `104`
|
||||
- **Plataforma**: Proxmox VE
|
||||
|
||||
## Hardware
|
||||
- **CPU**: (Virtual - KVM)
|
||||
- **RAM**: 4 GB (3.8Gi Total)
|
||||
|
||||
@@ -7,6 +7,11 @@
|
||||
- **Estado**: 🟢 Online
|
||||
- **OS**: Debian 12 (Bookworm)
|
||||
|
||||
## Datos de Virtualización
|
||||
- **Host Anfitrión**: `srv-pmox1` (10.0.10.201)
|
||||
- **VMID**: `103`
|
||||
- **Plataforma**: Proxmox VE
|
||||
|
||||
## Hardware
|
||||
- **CPU**: (Virtual - KVM)
|
||||
- **RAM**: 4 GB (3.8Gi Total)
|
||||
|
||||
@@ -7,6 +7,11 @@
|
||||
- **Estado**: 🟢 Online
|
||||
- **OS**: Debian 11 (Bullseye)
|
||||
|
||||
## Datos de Virtualización
|
||||
- **Host Anfitrión**: `srv-pmox2` (10.0.10.202)
|
||||
- **VMID**: `105`
|
||||
- **Plataforma**: Proxmox VE
|
||||
|
||||
## Hardware
|
||||
- **CPU**: (Virtual - KVM)
|
||||
- **RAM**: 2 GB (1.9Gi Total)
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
- **Estado**: 🟢 Online
|
||||
- **OS**: Ubuntu Linux
|
||||
|
||||
## Datos de Virtualización
|
||||
- **Host Anfitrión**: `srv-pmox1` (10.0.10.201)
|
||||
- **VMID**: `101`
|
||||
- **Plataforma**: Proxmox VE
|
||||
|
||||
## Hardware (Virtual)
|
||||
- **CPU**: Common KVM processor (Virtualizado)
|
||||
- **RAM**: 4.8 GB Total (~900MB Usados)
|
||||
|
||||
@@ -7,6 +7,11 @@
|
||||
- **Estado**: 🟢 Online
|
||||
- **OS**: Debian 12 (Bookworm)
|
||||
|
||||
## Datos de Virtualización
|
||||
- **Host Anfitrión**: `srv-pmox1` (10.0.10.201)
|
||||
- **VMID**: `102`
|
||||
- **Plataforma**: Proxmox VE
|
||||
|
||||
## Hardware
|
||||
- **CPU**: (Pendiente de validación - VM en Proxmox/KVM)
|
||||
- **RAM**: 3 GB (2.9Gi Total)
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
- **Tipo**: Contenedor LXC (Proxmox)
|
||||
- **OS**: Debian 12 (Bookworm)
|
||||
|
||||
## Datos de Virtualización
|
||||
- **Host Anfitrión**: `srv-pmox3`
|
||||
- **VMID**: `113`
|
||||
- **Plataforma**: Proxmox VE
|
||||
|
||||
## Hardware
|
||||
- **CPU**: (Compartido LXC)
|
||||
- **RAM**: 2 GB (2.0Gi Total)
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
- **Tipo**: Contenedor LXC (Proxmox)
|
||||
- **OS**: Debian 12 (Bookworm)
|
||||
|
||||
## Datos de Virtualización
|
||||
- **Host Anfitrión**: `srv-pmox3`
|
||||
- **VMID**: `106`
|
||||
- **Plataforma**: Proxmox VE
|
||||
|
||||
## Hardware
|
||||
- **CPU**: (Compartido LXC)
|
||||
- **RAM**: 1 GB (1.0Gi Total)
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
server {
|
||||
server_name ns8.frlr.utn.edu.ar 100.88.252.26 190.114.205.18 srvns8.tail982245.ts.net;
|
||||
|
||||
root /var/www/html;
|
||||
index index.html index.htm index.nginx-debian.html;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:3001/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# Portainer
|
||||
location /portainer/ {
|
||||
proxy_pass http://127.0.0.1:9000/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# SysACAD
|
||||
location /sysacad/ {
|
||||
proxy_pass http://127.0.0.1:8080/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# Bitácoras
|
||||
location /bitacoras/ {
|
||||
proxy_pass http://127.0.0.1:5173/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
|
||||
# Dashboard P2601
|
||||
location /P2601/ {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
# APPs (TinyFileManager)
|
||||
location /apps/ {
|
||||
client_max_body_size 20G;
|
||||
proxy_pass http://127.0.0.1:8082/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
listen 443 ssl; # managed by Certbot
|
||||
ssl_certificate /etc/letsencrypt/live/ns8.frlr.utn.edu.ar/fullchain.pem; # managed by Certbot
|
||||
ssl_certificate_key /etc/letsencrypt/live/ns8.frlr.utn.edu.ar/privkey.pem; # managed by Certbot
|
||||
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
|
||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
|
||||
|
||||
}
|
||||
server {
|
||||
if ($host = ns8.frlr.utn.edu.ar) {
|
||||
return 301 https://$host$request_uri;
|
||||
} # managed by Certbot
|
||||
|
||||
|
||||
listen 80;
|
||||
server_name ns8.frlr.utn.edu.ar 100.88.252.26 190.114.205.18 srvns8.tail982245.ts.net 10.0.10.8;
|
||||
|
||||
location /apps/ {
|
||||
client_max_body_size 20G;
|
||||
proxy_pass http://127.0.0.1:8082/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location = /s.txt {
|
||||
root /var/www/html;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 404; # managed by Certbot
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,11 +1,45 @@
|
||||
server {
|
||||
|
||||
server_name ns8.frlr.utn.edu.ar 100.88.252.26 190.114.205.18 srvns8.tail982245.ts.net;
|
||||
|
||||
root /var/www/html;
|
||||
index index.html index.htm index.nginx-debian.html;
|
||||
index index.html index.htm;
|
||||
|
||||
# -------------------------
|
||||
# CONFIGURACIÓN BASE PROXY
|
||||
# -------------------------
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
proxy_http_version 1.1;
|
||||
|
||||
# Websocket support
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
|
||||
# -------------------------
|
||||
# SERVICIOS
|
||||
# -------------------------
|
||||
|
||||
# Servicio principal
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:3001/;
|
||||
proxy_pass http://127.0.0.1:3001;
|
||||
}
|
||||
|
||||
# APIDS
|
||||
location = /apids {
|
||||
return 301 /apids/;
|
||||
}
|
||||
|
||||
location /apids/ {
|
||||
proxy_pass http://127.0.0.1:7071/;
|
||||
|
||||
proxy_http_version 1.1;
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
@@ -15,71 +49,61 @@ server {
|
||||
# Portainer
|
||||
location /portainer/ {
|
||||
proxy_pass http://127.0.0.1:9000/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# SysACAD
|
||||
location /sysacad/ {
|
||||
proxy_pass http://127.0.0.1:8080/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# Bitácoras
|
||||
location /bitacoras/ {
|
||||
proxy_pass http://127.0.0.1:5173/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
|
||||
# Dashboard P2601
|
||||
location /P2601/ {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
# APPs (TinyFileManager)
|
||||
# TinyFileManager
|
||||
location /apps/ {
|
||||
client_max_body_size 20G;
|
||||
proxy_pass http://127.0.0.1:8082/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
listen 443 ssl; # managed by Certbot
|
||||
ssl_certificate /etc/letsencrypt/live/ns8.frlr.utn.edu.ar/fullchain.pem; # managed by Certbot
|
||||
ssl_certificate_key /etc/letsencrypt/live/ns8.frlr.utn.edu.ar/privkey.pem; # managed by Certbot
|
||||
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
|
||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
|
||||
# -------------------------
|
||||
# OPTIMIZACIONES
|
||||
# -------------------------
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
|
||||
proxy_buffering off;
|
||||
|
||||
# -------------------------
|
||||
# SSL
|
||||
# -------------------------
|
||||
|
||||
listen 443 ssl;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/ns8.frlr.utn.edu.ar/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/ns8.frlr.utn.edu.ar/privkey.pem;
|
||||
|
||||
include /etc/letsencrypt/options-ssl-nginx.conf;
|
||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
|
||||
|
||||
}
|
||||
server {
|
||||
if ($host = ns8.frlr.utn.edu.ar) {
|
||||
return 301 https://$host$request_uri;
|
||||
} # managed by Certbot
|
||||
|
||||
# -------------------------
|
||||
# HTTP -> HTTPS REDIRECT
|
||||
# -------------------------
|
||||
|
||||
server {
|
||||
|
||||
listen 80;
|
||||
|
||||
server_name ns8.frlr.utn.edu.ar 100.88.252.26 190.114.205.18 srvns8.tail982245.ts.net 10.0.10.8;
|
||||
|
||||
location /apps/ {
|
||||
client_max_body_size 20G;
|
||||
proxy_pass http://127.0.0.1:8082/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location = /s.txt {
|
||||
@@ -87,8 +111,7 @@ server {
|
||||
}
|
||||
|
||||
location / {
|
||||
return 404; # managed by Certbot
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
server {
|
||||
server_name ns8.frlr.utn.edu.ar 100.88.252.26 190.114.205.18 srvns8.tail982245.ts.net;
|
||||
|
||||
root /var/www/html;
|
||||
index index.html index.htm index.nginx-debian.html;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:3001/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# Portainer
|
||||
location /portainer/ {
|
||||
proxy_pass http://127.0.0.1:9000/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# SysACAD
|
||||
location /sysacad/ {
|
||||
proxy_pass http://127.0.0.1:8080/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# Bitácoras
|
||||
location /bitacoras/ {
|
||||
proxy_pass http://127.0.0.1:5173/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
|
||||
# Dashboard P2601
|
||||
location /P2601/ {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
# APPs (TinyFileManager)
|
||||
location /apps/ {
|
||||
client_max_body_size 20G;
|
||||
proxy_pass http://127.0.0.1:8082/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
listen 443 ssl; # managed by Certbot
|
||||
ssl_certificate /etc/letsencrypt/live/ns8.frlr.utn.edu.ar/fullchain.pem; # managed by Certbot
|
||||
ssl_certificate_key /etc/letsencrypt/live/ns8.frlr.utn.edu.ar/privkey.pem; # managed by Certbot
|
||||
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
|
||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
|
||||
|
||||
}
|
||||
server {
|
||||
if ($host = ns8.frlr.utn.edu.ar) {
|
||||
return 301 https://$host$request_uri;
|
||||
} # managed by Certbot
|
||||
|
||||
|
||||
listen 80;
|
||||
server_name ns8.frlr.utn.edu.ar 100.88.252.26 190.114.205.18 srvns8.tail982245.ts.net 10.0.10.8;
|
||||
|
||||
location /apps/ {
|
||||
client_max_body_size 20G;
|
||||
proxy_pass http://127.0.0.1:8082/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location = /s.txt {
|
||||
root /var/www/html;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 404; # managed by Certbot
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
server {
|
||||
server_name ns8.frlr.utn.edu.ar 100.88.252.26 190.114.205.18 srvns8.tail982245.ts.net;
|
||||
|
||||
root /var/www/html;
|
||||
index index.html index.htm index.nginx-debian.html;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:3001/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# Portainer
|
||||
location /portainer/ {
|
||||
proxy_pass http://127.0.0.1:9000/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# SysACAD
|
||||
location /sysacad/ {
|
||||
proxy_pass http://127.0.0.1:8080/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# Bitácoras
|
||||
location /bitacoras/ {
|
||||
proxy_pass http://127.0.0.1:5173/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
|
||||
# Dashboard P2601
|
||||
location /P2601/ {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
# APPs (TinyFileManager)
|
||||
location /apps/ {
|
||||
client_max_body_size 20G;
|
||||
proxy_pass http://127.0.0.1:8082/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
listen 443 ssl; # managed by Certbot
|
||||
ssl_certificate /etc/letsencrypt/live/ns8.frlr.utn.edu.ar/fullchain.pem; # managed by Certbot
|
||||
ssl_certificate_key /etc/letsencrypt/live/ns8.frlr.utn.edu.ar/privkey.pem; # managed by Certbot
|
||||
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
|
||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
|
||||
|
||||
}
|
||||
server {
|
||||
if ($host = ns8.frlr.utn.edu.ar) {
|
||||
return 301 https://$host$request_uri;
|
||||
} # managed by Certbot
|
||||
|
||||
|
||||
listen 80;
|
||||
server_name ns8.frlr.utn.edu.ar 100.88.252.26 190.114.205.18 srvns8.tail982245.ts.net 10.0.10.8;
|
||||
|
||||
location /apps/ {
|
||||
client_max_body_size 20G;
|
||||
proxy_pass http://127.0.0.1:8082/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location = /s.txt {
|
||||
root /var/www/html;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 404; # managed by Certbot
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
server {
|
||||
server_name ns8.frlr.utn.edu.ar 100.88.252.26 190.114.205.18 srvns8.tail982245.ts.net;
|
||||
|
||||
root /var/www/html;
|
||||
index index.html index.htm index.nginx-debian.html;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:3001/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# Portainer
|
||||
location /portainer/ {
|
||||
proxy_pass http://127.0.0.1:9000/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# SysACAD
|
||||
location /sysacad/ {
|
||||
proxy_pass http://127.0.0.1:8080/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# Bitácoras
|
||||
location /bitacoras/ {
|
||||
proxy_pass http://127.0.0.1:5173/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
|
||||
# Dashboard P2601
|
||||
location /P2601/ {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
# APPs (TinyFileManager)
|
||||
location /apps/ {
|
||||
client_max_body_size 20G;
|
||||
proxy_pass http://127.0.0.1:8082/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
listen 443 ssl; # managed by Certbot
|
||||
ssl_certificate /etc/letsencrypt/live/ns8.frlr.utn.edu.ar/fullchain.pem; # managed by Certbot
|
||||
ssl_certificate_key /etc/letsencrypt/live/ns8.frlr.utn.edu.ar/privkey.pem; # managed by Certbot
|
||||
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
|
||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
|
||||
|
||||
}
|
||||
server {
|
||||
if ($host = ns8.frlr.utn.edu.ar) {
|
||||
return 301 https://$host$request_uri;
|
||||
} # managed by Certbot
|
||||
|
||||
|
||||
listen 80;
|
||||
server_name ns8.frlr.utn.edu.ar 100.88.252.26 190.114.205.18 srvns8.tail982245.ts.net 10.0.10.8;
|
||||
|
||||
location /apps/ {
|
||||
client_max_body_size 20G;
|
||||
proxy_pass http://127.0.0.1:8082/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location = /s.txt {
|
||||
root /var/www/html;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 404; # managed by Certbot
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -42,15 +42,45 @@ module.exports = (pool) => {
|
||||
ORDER BY e.inicio DESC
|
||||
`, [bitacora.id]);
|
||||
|
||||
// Obtener gestión asociada a esta bitácora (fija) + activos globales (rollover)
|
||||
const { rows: gestion } = await pool.query(`
|
||||
SELECT g.*, n.nombre as nodo_nombre
|
||||
FROM bitacoras.gestion g
|
||||
LEFT JOIN bitacoras.nodos n ON g.nodo_id = n.id
|
||||
WHERE g.bitacora_id = $1 OR g.activo = true
|
||||
ORDER BY g.tipo, g.orden
|
||||
`, [bitacora.id]);
|
||||
|
||||
// Obtener resúmenes por nodo
|
||||
const { rows: resúmenes } = await pool.query(`
|
||||
SELECT r.*, n.nombre as nodo_nombre
|
||||
FROM bitacoras.resumen_nodos r
|
||||
JOIN bitacoras.nodos n ON r.nodo_id = n.id
|
||||
WHERE r.bitacora_id = $1
|
||||
`, [bitacora.id]);
|
||||
|
||||
// Agrupar por nodo
|
||||
const porNodo = {};
|
||||
entradas.forEach(e => {
|
||||
const nodo = e.nodo_nombre || 'sin-nodo';
|
||||
if (!porNodo[nodo]) porNodo[nodo] = { nodo: nodo, ip: e.nodo_ip, entradas: [] };
|
||||
if (!porNodo[nodo]) porNodo[nodo] = { nodo: nodo, ip: e.nodo_ip, entradas: [], resumen: '' };
|
||||
porNodo[nodo].entradas.push(e);
|
||||
});
|
||||
|
||||
res.json({ ...bitacora, nodos: Object.values(porNodo) });
|
||||
// Adjuntar resúmenes a la agrupación por nodo
|
||||
resúmenes.forEach(r => {
|
||||
if (porNodo[r.nodo_nombre]) {
|
||||
porNodo[r.nodo_nombre].resumen = r.resumen;
|
||||
} else {
|
||||
porNodo[r.nodo_nombre] = { nodo: r.nodo_nombre, entradas: [], resumen: r.resumen };
|
||||
}
|
||||
});
|
||||
|
||||
res.json({
|
||||
...bitacora,
|
||||
nodos: Object.values(porNodo),
|
||||
gestion: gestion
|
||||
});
|
||||
});
|
||||
|
||||
// GET /api/bitacoras/:fecha/export — Exportar a Markdown
|
||||
@@ -61,17 +91,41 @@ module.exports = (pool) => {
|
||||
|
||||
const bitacora = bResult.rows[0];
|
||||
const { rows: entradas } = await pool.query(`
|
||||
SELECT e.*, n.nombre as nodo_nombre
|
||||
FROM bitacoras.entradas e
|
||||
LEFT JOIN bitacoras.nodos n ON e.nodo_id = n.id
|
||||
WHERE e.bitacora_id = $1
|
||||
ORDER BY n.nombre, e.inicio DESC
|
||||
`, [bitacora.id]);
|
||||
SELECT e.*, n.nombre as nodo_nombre FROM bitacoras.entradas e
|
||||
LEFT JOIN bitacoras.nodos n ON e.nodo_id = n.id
|
||||
WHERE e.bitacora_id = $1 ORDER BY n.nombre, e.inicio ASC
|
||||
`, [bitacora.id]);
|
||||
|
||||
const { rows: gestion } = await pool.query(`
|
||||
SELECT g.*, n.nombre as nodo_nombre FROM bitacoras.gestion g
|
||||
LEFT JOIN bitacoras.nodos n ON g.nodo_id = n.id
|
||||
WHERE g.bitacora_id = $1 OR g.activo = true ORDER BY g.tipo, g.orden
|
||||
`, [bitacora.id]);
|
||||
|
||||
const { rows: resumenes } = await pool.query(`
|
||||
SELECT r.*, n.nombre as nodo_nombre FROM bitacoras.resumen_nodos r
|
||||
JOIN bitacoras.nodos n ON r.nodo_id = n.id WHERE r.bitacora_id = $1
|
||||
`, [bitacora.id]);
|
||||
|
||||
// Generar Markdown compatible con ADN
|
||||
const [y, m, d] = fecha.split('-');
|
||||
let md = `# Bitácora de Operaciones - ${d}/${m}/${y}\n\n`;
|
||||
md += `## 📂 Actividades Detalladas\n\n`;
|
||||
let md = `# Bitácora ${fecha}\n\n---\n\n## 📋 Control de Gestión\n\n### Pendientes\n\n| ID | Nodo | Detalle |\n| :--- | :--- | :--- |\n`;
|
||||
|
||||
gestion.filter(g => g.tipo === 'pendiente').forEach(g => {
|
||||
md += `| ${g.id} | ${g.nodo_nombre || '—'} | ${g.detalle} |\n`;
|
||||
});
|
||||
|
||||
md += `\n### En Proceso\n\n| ID | Nodo | Detalle |\n| :--- | :--- | :--- |\n`;
|
||||
gestion.filter(g => g.tipo === 'proceso').forEach(g => {
|
||||
md += `| ${g.id} | ${g.nodo_nombre || '—'} | ${g.detalle} |\n`;
|
||||
});
|
||||
|
||||
md += `\n### Resumen de Actividades\n\n| Nodo | Resumen Integral |\n| :--- | :--- |\n`;
|
||||
resumenes.forEach(r => {
|
||||
md += `| ${r.nodo_nombre} | ${r.resumen} |\n`;
|
||||
});
|
||||
|
||||
md += `\n---\n\n## 📝 Actividades Detalladas\n\n`;
|
||||
|
||||
const porNodo = {};
|
||||
entradas.forEach(e => {
|
||||
@@ -82,18 +136,18 @@ module.exports = (pool) => {
|
||||
|
||||
Object.entries(porNodo).forEach(([nodo, entries]) => {
|
||||
md += `### ${nodo}\n\n`;
|
||||
md += `| I | F | Descripción | E |\n`;
|
||||
md += `| :--- | :--- | :--- | :--- |\n`;
|
||||
entries.forEach(e => {
|
||||
// Agrupar por tema si es necesario, o lista simple
|
||||
const inicio = e.inicio ? e.inicio.substring(0, 5) : '-';
|
||||
const fin = e.fin ? e.fin.substring(0, 5) : '-';
|
||||
const ia = e.es_ia ? '(IA) ' : '';
|
||||
const estado = `[${e.modo}] ${e.estado}`;
|
||||
md += `| ${inicio} | ${fin} | ${ia}${e.descripcion} | ${estado} |\n`;
|
||||
md += `| ${inicio} | ${fin} | ${e.descripcion} | ${e.modo} | ${e.estado} |\n`;
|
||||
});
|
||||
md += '\n';
|
||||
});
|
||||
|
||||
md += `\n---\n<!-- 🤖 PREMISAS DE TRABAJO (IA): Fuente de Verdad → adn/05_ia.md -->\n`;
|
||||
|
||||
res.set('Content-Type', 'text/markdown');
|
||||
res.send(md);
|
||||
});
|
||||
|
||||
@@ -31,6 +31,7 @@ module.exports = (pool) => {
|
||||
UPDATE bitacoras.entradas SET inicio=$1, fin=$2, descripcion=$3, estado=$4, modo=$5, es_ia=$6
|
||||
WHERE id=$7 RETURNING *
|
||||
`, [inicio, fin, descripcion, estado, modo, es_ia, id]);
|
||||
|
||||
if (rows.length === 0) return res.status(404).json({ error: 'Entrada no encontrada' });
|
||||
res.json(rows[0]);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
|
||||
module.exports = (pool) => {
|
||||
const router = require('express').Router();
|
||||
|
||||
// GET /api/gestion — Listar activos (para rollover) o por bitácora
|
||||
router.get('/', async (req, res) => {
|
||||
const { bitacora_id, activos } = req.query;
|
||||
let query = 'SELECT g.*, n.nombre as nodo_nombre FROM bitacoras.gestion g LEFT JOIN bitacoras.nodos n ON g.nodo_id = n.id';
|
||||
const params = [];
|
||||
|
||||
if (activos === 'true') {
|
||||
query += ' WHERE g.activo = true';
|
||||
} else if (bitacora_id) {
|
||||
query += ' WHERE g.bitacora_id = $1';
|
||||
params.push(bitacora_id);
|
||||
}
|
||||
|
||||
query += ' ORDER BY g.tipo, g.orden, g.created_at DESC';
|
||||
const { rows } = await pool.query(query, params);
|
||||
res.json(rows);
|
||||
});
|
||||
|
||||
// POST /api/gestion — Crear nuevo pendiente/proceso
|
||||
router.post('/', async (req, res) => {
|
||||
const { tipo, nodo_id, detalle, estado, bitacora_id, orden } = req.body;
|
||||
const { rows } = await pool.query(
|
||||
'INSERT INTO bitacoras.gestion (tipo, nodo_id, detalle, estado, bitacora_id, orden) VALUES ($1, $2, $3, $4, $5, $6) RETURNING *',
|
||||
[tipo, nodo_id || null, detalle, estado || '⏳', bitacora_id, orden || 0]
|
||||
);
|
||||
res.status(201).json(rows[0]);
|
||||
});
|
||||
|
||||
// PUT /api/gestion/:id — Actualizar
|
||||
router.put('/:id', async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const { tipo, nodo_id, detalle, estado, activo, orden } = req.body;
|
||||
const { rows } = await pool.query(
|
||||
'UPDATE bitacoras.gestion SET tipo=$1, nodo_id=$2, detalle=$3, estado=$4, activo=$5, orden=$6, updated_at=CURRENT_TIMESTAMP WHERE id=$7 RETURNING *',
|
||||
[tipo, nodo_id || null, detalle, estado, activo !== undefined ? activo : true, orden || 0, id]
|
||||
);
|
||||
if (rows.length === 0) return res.status(404).json({ error: 'No encontrado' });
|
||||
res.json(rows[0]);
|
||||
});
|
||||
|
||||
// DELETE /api/gestion/:id
|
||||
router.delete('/:id', async (req, res) => {
|
||||
const { rowCount } = await pool.query('DELETE FROM bitacoras.gestion WHERE id = $1', [req.params.id]);
|
||||
if (rowCount === 0) return res.status(404).json({ error: 'No encontrado' });
|
||||
res.json({ message: 'Eliminado' });
|
||||
});
|
||||
|
||||
return router;
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
|
||||
module.exports = (pool) => {
|
||||
const router = require('express').Router();
|
||||
|
||||
// GET /api/resumen — Listar resúmenes por bitácora
|
||||
router.get('/', async (req, res) => {
|
||||
const { bitacora_id } = req.query;
|
||||
if (!bitacora_id) return res.status(400).json({ error: 'Falta bitacora_id' });
|
||||
|
||||
const { rows } = await pool.query(
|
||||
'SELECT r.*, n.nombre as nodo_nombre FROM bitacoras.resumen_nodos r JOIN bitacoras.nodos n ON r.nodo_id = n.id WHERE r.bitacora_id = $1',
|
||||
[bitacora_id]
|
||||
);
|
||||
res.json(rows);
|
||||
});
|
||||
|
||||
// POST /api/resumen — Upsert resumen por nodo
|
||||
router.post('/', async (req, res) => {
|
||||
const { bitacora_id, nodo_id, resumen } = req.body;
|
||||
const { rows } = await pool.query(
|
||||
`INSERT INTO bitacoras.resumen_nodos (bitacora_id, nodo_id, resumen)
|
||||
VALUES ($1, $2, $3)
|
||||
ON CONFLICT (bitacora_id, nodo_id)
|
||||
DO UPDATE SET resumen = EXCLUDED.resumen, updated_at = CURRENT_TIMESTAMP
|
||||
RETURNING *`,
|
||||
[bitacora_id, nodo_id, resumen]
|
||||
);
|
||||
res.status(201).json(rows[0]);
|
||||
});
|
||||
|
||||
return router;
|
||||
};
|
||||
@@ -29,6 +29,8 @@ app.use('/api/nodos', require('./routes/nodos')(pool));
|
||||
app.use('/api/bitacoras', require('./routes/bitacoras')(pool));
|
||||
app.use('/api/entradas', require('./routes/entradas')(pool));
|
||||
app.use('/api/proyectos', require('./routes/proyectos')(pool));
|
||||
app.use('/api/gestion', require('./routes/gestion')(pool));
|
||||
app.use('/api/resumen', require('./routes/resumen')(pool));
|
||||
|
||||
// Error handler
|
||||
app.use((err, req, res, next) => {
|
||||
|
||||
@@ -20,6 +20,7 @@ interface NodoGroup {
|
||||
nodo: string;
|
||||
ip: string;
|
||||
entradas: Entrada[];
|
||||
resumen?: string;
|
||||
}
|
||||
|
||||
interface Bitacora {
|
||||
@@ -27,6 +28,16 @@ interface Bitacora {
|
||||
fecha: string;
|
||||
resumen: string;
|
||||
nodos: NodoGroup[];
|
||||
gestion: GestionItem[];
|
||||
}
|
||||
|
||||
interface GestionItem {
|
||||
id: number;
|
||||
tipo: 'pendiente' | 'proceso';
|
||||
nodo_nombre: string;
|
||||
detalle: string;
|
||||
estado: string;
|
||||
activo: boolean;
|
||||
}
|
||||
|
||||
interface Nodo {
|
||||
@@ -85,6 +96,8 @@ function App() {
|
||||
const [fecha, setFecha] = useState(new Date().toISOString().split('T')[0]);
|
||||
const [bitacora, setBitacora] = useState<Bitacora | null>(null);
|
||||
const [nodos, setNodos] = useState<Nodo[]>([]);
|
||||
const [proyectos, setProyectos] = useState<{ id: number, codigo: string, nombre: string }[]>([]);
|
||||
const [selectedProyecto, setSelectedProyecto] = useState<string>('P2601');
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
// Form: nueva entrada
|
||||
@@ -116,6 +129,71 @@ function App() {
|
||||
const [nodoTipo, setNodoTipo] = useState('servidor');
|
||||
const [nodoDesc, setNodoDesc] = useState('');
|
||||
|
||||
// === HELPERS ===
|
||||
const renderDescription = (text: string) => {
|
||||
if (!text) return '';
|
||||
|
||||
// Regex para links markdown: [texto](url)
|
||||
const markdownLinkRegex = /\[([^\]]+)\]\(([^)]+)\)/g;
|
||||
|
||||
const parts: (string | JSX.Element)[] = [];
|
||||
let lastIndex = 0;
|
||||
let match;
|
||||
|
||||
while ((match = markdownLinkRegex.exec(text)) !== null) {
|
||||
if (match.index > lastIndex) {
|
||||
parts.push(text.substring(lastIndex, match.index));
|
||||
}
|
||||
|
||||
const label = match[1];
|
||||
let url = match[2];
|
||||
|
||||
// Si es un link a un proyecto, interceptamos para navegación SPA
|
||||
if (url.startsWith('../proyectos/')) {
|
||||
const projectFile = url.split('/').pop() || '';
|
||||
const projectCodeMatch = projectFile.match(/^(P\d{4})/);
|
||||
|
||||
if (projectCodeMatch) {
|
||||
const projectCode = projectCodeMatch[1];
|
||||
parts.push(
|
||||
<a
|
||||
key={match.index}
|
||||
href="#"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
setSelectedProyecto(projectCode);
|
||||
changeTab('proyecto');
|
||||
}}
|
||||
className="desc-link"
|
||||
title={`Ver plan ${projectCode} en la web`}
|
||||
>
|
||||
{label}
|
||||
</a>
|
||||
);
|
||||
lastIndex = markdownLinkRegex.lastIndex;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Si no tiene el formato PXXXX, fallback a link estático
|
||||
url = '/bitacoras/docs/proyectos/' + projectFile;
|
||||
}
|
||||
|
||||
parts.push(
|
||||
<a key={match.index} href={url} target="_blank" rel="noopener noreferrer" className="desc-link">
|
||||
{label}
|
||||
</a>
|
||||
);
|
||||
|
||||
lastIndex = markdownLinkRegex.lastIndex;
|
||||
}
|
||||
|
||||
if (lastIndex < text.length) {
|
||||
parts.push(text.substring(lastIndex));
|
||||
}
|
||||
|
||||
return parts.length > 0 ? <>{parts}</> : text;
|
||||
};
|
||||
|
||||
// === FETCH ===
|
||||
const fetchBitacora = useCallback(async () => {
|
||||
setLoading(true);
|
||||
@@ -134,8 +212,70 @@ function App() {
|
||||
} catch (err) { console.error('Error:', err); }
|
||||
};
|
||||
|
||||
const fetchProyectos = async () => {
|
||||
try {
|
||||
const res = await fetch(`${API_URL}/proyectos`);
|
||||
const data = await res.json();
|
||||
setProyectos(data);
|
||||
if (data.length > 0) {
|
||||
// Al cargar por primera vez, si no hay P2601 explícito o se quiere forzar al último
|
||||
setSelectedProyecto(prev => prev === 'P2601' && prev ? data[data.length - 1].codigo : prev || data[data.length - 1].codigo);
|
||||
}
|
||||
} catch (err) { console.error('Error:', err); }
|
||||
};
|
||||
|
||||
const addGestion = async (tipo: 'pendiente' | 'proceso') => {
|
||||
if (!bitacora) return;
|
||||
const detalle = prompt(`Nuevo ${tipo}:`);
|
||||
if (!detalle) return;
|
||||
|
||||
await fetch(`${API_URL}/gestion`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
tipo, detalle, bitacora_id: bitacora.id, estado: '⏳'
|
||||
})
|
||||
});
|
||||
fetchBitacora();
|
||||
};
|
||||
|
||||
const deleteGestion = async (id: number) => {
|
||||
if (!confirm('¿Eliminar item de gestión?')) return;
|
||||
await fetch(`${API_URL}/gestion/${id}`, { method: 'DELETE' });
|
||||
fetchBitacora();
|
||||
};
|
||||
|
||||
const updateResumenNodo = async (nodoNombre: string, current: string) => {
|
||||
if (!bitacora) return;
|
||||
const newResumen = prompt(`Resumen Integral para ${nodoNombre}:`, current);
|
||||
if (newResumen === null) return;
|
||||
|
||||
const nodo = nodos.find(n => n.nombre === nodoNombre);
|
||||
if (!nodo) return;
|
||||
|
||||
await fetch(`${API_URL}/resumen`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
bitacora_id: bitacora.id,
|
||||
nodo_id: nodo.id,
|
||||
resumen: newResumen
|
||||
})
|
||||
});
|
||||
fetchBitacora();
|
||||
};
|
||||
|
||||
const navigateProyecto = (direction: number) => {
|
||||
if (proyectos.length === 0) return;
|
||||
const currentIndex = proyectos.findIndex(p => p.codigo === selectedProyecto);
|
||||
let nextIndex = currentIndex + direction;
|
||||
if (nextIndex < 0) nextIndex = proyectos.length - 1;
|
||||
if (nextIndex >= proyectos.length) nextIndex = 0;
|
||||
setSelectedProyecto(proyectos[nextIndex].codigo);
|
||||
};
|
||||
|
||||
useEffect(() => { fetchBitacora(); }, [fetchBitacora]);
|
||||
useEffect(() => { fetchNodos(); }, []);
|
||||
useEffect(() => { fetchNodos(); fetchProyectos(); }, []);
|
||||
|
||||
// === ENTRADAS CRUD ===
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
@@ -276,7 +416,7 @@ function App() {
|
||||
className={`btn btn-sm ${tab === 'proyecto' ? 'btn-primary' : ''}`}
|
||||
onClick={() => changeTab('proyecto')}
|
||||
style={tab !== 'proyecto' ? { background: 'var(--bg-card)', color: 'var(--text)', border: '1px solid var(--border)' } : {}}
|
||||
><i className="fas fa-project-diagram"></i> P2601</button>
|
||||
><i className="fas fa-project-diagram"></i> Planes</button>
|
||||
{tab === 'bitacora' && (
|
||||
<a href={`${API_URL}/bitacoras/${fecha}/export`} target="_blank" rel="noopener"
|
||||
className="btn btn-sm btn-primary">
|
||||
@@ -308,11 +448,11 @@ function App() {
|
||||
{/* Stats */}
|
||||
<div className="stats-bar">
|
||||
<div className="stat-card">
|
||||
<div className="stat-value">{totalEntradas}</div>
|
||||
<div className="stat-value">{bitacora?.nodos?.reduce((s, n) => s + n.entradas.length, 0) || 0}</div>
|
||||
<div className="stat-label">Entradas</div>
|
||||
</div>
|
||||
<div className="stat-card">
|
||||
<div className="stat-value">{totalNodos}</div>
|
||||
<div className="stat-value">{bitacora?.nodos?.length || 0}</div>
|
||||
<div className="stat-label">Nodos Activos</div>
|
||||
</div>
|
||||
<div className="stat-card">
|
||||
@@ -325,6 +465,58 @@ function App() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* =================== CONTROL DE GESTIÓN =================== */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '1.5rem', marginBottom: '2rem' }}>
|
||||
<div className="card">
|
||||
<div className="card-header" style={{ borderBottom: '1px solid var(--border)', display: 'flex', justifyContent: 'space-between' }}>
|
||||
<span><i className="fas fa-list-ul" style={{ color: '#fbbf24' }}></i> Pendientes</span>
|
||||
<button className="btn btn-sm" onClick={() => addGestion('pendiente')} style={{ padding: '0.1rem 0.4rem', fontSize: '0.7rem' }}><i className="fas fa-plus"></i></button>
|
||||
</div>
|
||||
<div style={{ padding: '0.5rem', minHeight: '60px' }}>
|
||||
<table style={{ width: '100%', fontSize: '0.85rem' }}>
|
||||
<tbody>
|
||||
{bitacora?.gestion?.filter(g => g.tipo === 'pendiente').map(g => (
|
||||
<tr key={g.id} style={{ borderBottom: '1px solid var(--border-light)' }}>
|
||||
<td style={{ padding: '0.4rem', color: 'var(--text-secondary)', width: '20%' }}>{g.nodo_nombre || '—'}</td>
|
||||
<td style={{ padding: '0.4rem' }}>{g.detalle}</td>
|
||||
<td style={{ padding: '0.4rem', textAlign: 'right', width: '60px' }}>
|
||||
<div style={{ display: 'flex', gap: '0.3rem', alignItems: 'center' }}>
|
||||
<span>{g.estado}</span>
|
||||
<button className="btn btn-sm btn-danger" onClick={() => deleteGestion(g.id)} style={{ padding: '0 0.2rem', fontSize: '0.6rem' }}><i className="fas fa-trash"></i></button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card">
|
||||
<div className="card-header" style={{ borderBottom: '1px solid var(--border)', display: 'flex', justifyContent: 'space-between' }}>
|
||||
<span><i className="fas fa-spinner" style={{ color: '#3b82f6' }}></i> En Proceso</span>
|
||||
<button className="btn btn-sm" onClick={() => addGestion('proceso')} style={{ padding: '0.1rem 0.4rem', fontSize: '0.7rem' }}><i className="fas fa-plus"></i></button>
|
||||
</div>
|
||||
<div style={{ padding: '0.5rem', minHeight: '60px' }}>
|
||||
<table style={{ width: '100%', fontSize: '0.85rem' }}>
|
||||
<tbody>
|
||||
{bitacora?.gestion?.filter(g => g.tipo === 'proceso').map(g => (
|
||||
<tr key={g.id} style={{ borderBottom: '1px solid var(--border-light)' }}>
|
||||
<td style={{ padding: '0.4rem', color: 'var(--text-secondary)', width: '20%' }}>{g.nodo_nombre || '—'}</td>
|
||||
<td style={{ padding: '0.4rem' }}>{g.detalle}</td>
|
||||
<td style={{ padding: '0.4rem', textAlign: 'right', width: '60px' }}>
|
||||
<div style={{ display: 'flex', gap: '0.3rem', alignItems: 'center' }}>
|
||||
<span>{g.estado}</span>
|
||||
<button className="btn btn-sm btn-danger" onClick={() => deleteGestion(g.id)} style={{ padding: '0 0.2rem', fontSize: '0.6rem' }}><i className="fas fa-trash"></i></button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* New Entry Form */}
|
||||
<div className="card" style={{ marginBottom: '2rem' }}>
|
||||
<div className="card-header"><i className="fas fa-plus-circle"></i> Nueva Entrada</div>
|
||||
@@ -362,12 +554,22 @@ function App() {
|
||||
{nodoGroup.ip && <span className="nodo-ip">({nodoGroup.ip})</span>}
|
||||
<span className="badge badge-gradient" style={{ marginLeft: 'auto' }}>{nodoGroup.entradas.length}</span>
|
||||
</div>
|
||||
|
||||
<div style={{ padding: '0.8rem 1rem', background: 'rgba(102, 126, 234, 0.05)', borderBottom: '1px solid var(--border)', fontSize: '0.85rem', color: 'var(--text-secondary)' }}>
|
||||
<div style={{ display: 'flex', gap: '0.5rem', alignItems: 'center' }}>
|
||||
<i className="fas fa-quote-left" style={{ opacity: 0.5 }}></i>
|
||||
<div style={{ fontStyle: 'italic', flex: 1 }}>{nodoGroup.resumen || 'Sin resumen integral registrado.'}</div>
|
||||
<button className="btn btn-sm" onClick={() => updateResumenNodo(nodoGroup.nodo, nodoGroup.resumen || '')} style={{ padding: '0.1rem 0.4rem', fontSize: '0.7rem' }} title="Editar Resumen"><i className="fas fa-pen"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table className="table-ifde">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="col-time">I</th>
|
||||
<th className="col-time">F</th>
|
||||
<th>Descripción</th>
|
||||
<th className="col-j-header" style={{ width: '35px', textAlign: 'center' }}>J</th>
|
||||
<th className="col-status">E</th>
|
||||
<th style={{ width: '80px' }}>Acc.</th>
|
||||
</tr>
|
||||
@@ -381,20 +583,21 @@ function App() {
|
||||
<td><input type="time" value={editFin} onChange={ev => setEditFin(ev.target.value)} className="edit-input" /></td>
|
||||
<td>
|
||||
<input type="text" value={editDesc} onChange={ev => setEditDesc(ev.target.value)} className="edit-input" style={{ width: '100%' }} />
|
||||
<div style={{ display: 'flex', gap: '0.3rem', marginTop: '0.3rem', alignItems: 'center' }}>
|
||||
<select value={editEstado} onChange={ev => setEditEstado(ev.target.value)} className="edit-input">
|
||||
<option value="⏳">⏳</option><option value="✅">✅</option>
|
||||
<option value="⚠️">⚠️</option><option value="❌">❌</option><option value="👁️">👁️</option>
|
||||
</select>
|
||||
<select value={editModo} onChange={ev => setEditModo(ev.target.value)} className="edit-input">
|
||||
<option value="P">[P]</option><option value="R">[R]</option>
|
||||
</select>
|
||||
<label style={{ fontSize: '0.75rem', color: 'var(--text-secondary)', display: 'flex', alignItems: 'center', gap: '0.2rem' }}>
|
||||
<input type="checkbox" checked={editEsIa} onChange={ev => setEditEsIa(ev.target.checked)} /> IA
|
||||
</label>
|
||||
</div>
|
||||
<label style={{ fontSize: '0.75rem', color: 'var(--text-secondary)', display: 'flex', alignItems: 'center', gap: '0.2rem', marginTop: '0.3rem' }}>
|
||||
<input type="checkbox" checked={editEsIa} onChange={ev => setEditEsIa(ev.target.checked)} /> IA
|
||||
</label>
|
||||
</td>
|
||||
<td style={{ textAlign: 'center' }}>
|
||||
<select value={editModo} onChange={ev => setEditModo(ev.target.value)} className="edit-input" style={{ width: '45px', padding: '0.35rem 0.2rem' }}>
|
||||
<option value="P">P</option><option value="R">R</option><option value="S">S</option>
|
||||
</select>
|
||||
</td>
|
||||
<td style={{ textAlign: 'center' }}>
|
||||
<select value={editEstado} onChange={ev => setEditEstado(ev.target.value)} className="edit-input" style={{ width: '45px', padding: '0.35rem 0.2rem' }}>
|
||||
<option value="⏳">⏳</option><option value="✅">✅</option>
|
||||
<option value="⚠️">⚠️</option><option value="❌">❌</option><option value="👁️">👁️</option>
|
||||
</select>
|
||||
</td>
|
||||
<td></td>
|
||||
<td>
|
||||
<div style={{ display: 'flex', gap: '0.2rem' }}>
|
||||
<button className="btn btn-sm btn-success" onClick={saveEdit} title="Guardar"><i className="fas fa-check"></i></button>
|
||||
@@ -409,9 +612,10 @@ function App() {
|
||||
<td className="col-time">{e.fin ? e.fin.substring(0, 5) : '—'}</td>
|
||||
<td className="col-desc">
|
||||
{e.es_ia && <span className="ia-tag">IA</span>}
|
||||
{e.descripcion}
|
||||
{renderDescription(e.descripcion)}
|
||||
</td>
|
||||
<td className="col-status">[{e.modo}] {e.estado}</td>
|
||||
<td style={{ textAlign: 'center', fontWeight: 600, color: 'var(--text-secondary)' }}>{e.modo}</td>
|
||||
<td className="col-status">{e.estado}</td>
|
||||
<td>
|
||||
<div style={{ display: 'flex', gap: '0.2rem' }}>
|
||||
<button className="btn btn-sm" onClick={() => startEdit(e)} title="Editar"
|
||||
@@ -518,7 +722,38 @@ function App() {
|
||||
|
||||
{/* =================== TAB PROYECTO =================== */}
|
||||
{tab === 'proyecto' && (
|
||||
<ProyectoDashboard codigo="P2601" />
|
||||
<>
|
||||
<div className="date-selector" style={{ marginBottom: '1.5rem', justifyContent: 'center' }}>
|
||||
<button className="btn btn-sm btn-primary" onClick={() => navigateProyecto(-1)}>
|
||||
<i className="fas fa-chevron-left"></i>
|
||||
</button>
|
||||
<span style={{ fontSize: '0.85rem', fontWeight: 600, color: 'var(--text-secondary)' }}>
|
||||
<i className="fas fa-project-diagram"></i> Plan:
|
||||
</span>
|
||||
<select
|
||||
value={selectedProyecto}
|
||||
onChange={e => setSelectedProyecto(e.target.value)}
|
||||
style={{
|
||||
background: 'var(--bg-card)',
|
||||
color: 'var(--text)',
|
||||
border: '1px solid var(--border)',
|
||||
padding: '0.4rem 1rem',
|
||||
borderRadius: '8px',
|
||||
fontSize: '0.9rem',
|
||||
fontWeight: 600,
|
||||
minWidth: '200px'
|
||||
}}
|
||||
>
|
||||
{proyectos.map(p => (
|
||||
<option key={p.id} value={p.codigo}>{p.codigo} - {p.nombre}</option>
|
||||
))}
|
||||
</select>
|
||||
<button className="btn btn-sm btn-primary" onClick={() => navigateProyecto(1)}>
|
||||
<i className="fas fa-chevron-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
<ProyectoDashboard codigo={selectedProyecto} />
|
||||
</>
|
||||
)}
|
||||
</main>
|
||||
</div>
|
||||
|
||||
@@ -61,6 +61,7 @@ body {
|
||||
font-weight: 700;
|
||||
background: var(--gradient);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -160,7 +161,7 @@ body {
|
||||
}
|
||||
|
||||
.table-ifde .col-status {
|
||||
width: 80px;
|
||||
width: 45px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -178,6 +179,23 @@ body {
|
||||
margin-right: 0.3rem;
|
||||
}
|
||||
|
||||
.desc-link {
|
||||
color: var(--primary);
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
background: rgba(102, 126, 234, 0.1);
|
||||
padding: 0.1rem 0.4rem;
|
||||
border-radius: 4px;
|
||||
transition: var(--transition);
|
||||
border-bottom: 1px solid transparent;
|
||||
}
|
||||
|
||||
.desc-link:hover {
|
||||
background: var(--primary);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Nodo section */
|
||||
.nodo-section {
|
||||
margin-bottom: 2rem;
|
||||
@@ -337,6 +355,7 @@ body {
|
||||
font-weight: 700;
|
||||
background: var(--gradient);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,9 @@ interface Fase {
|
||||
descripcion: string;
|
||||
fecha_inicio: string | null;
|
||||
fecha_fin: string | null;
|
||||
objetivo?: string;
|
||||
desarrollo?: string;
|
||||
logros?: string;
|
||||
hitos: Hito[] | null;
|
||||
}
|
||||
|
||||
@@ -49,6 +52,13 @@ interface Proyecto {
|
||||
nombre: string;
|
||||
estado: string;
|
||||
descripcion: string;
|
||||
detalles_json: {
|
||||
contexto?: string[];
|
||||
objetivos?: string[];
|
||||
responsables?: string[];
|
||||
beneficiarios_directos?: string[];
|
||||
beneficiarios_indirectos?: string[];
|
||||
} | null;
|
||||
fases: Fase[];
|
||||
metricas: Metricas;
|
||||
nodos: NodoInfo[];
|
||||
@@ -116,48 +126,14 @@ function DonutChart({ segments, size = 140, strokeWidth = 18, centerLabel, cente
|
||||
);
|
||||
}
|
||||
|
||||
/* ═══════════ CONTENIDO ENRIQUECIDO POR FASE ═══════════ */
|
||||
const faseDetalles: Record<number, { objetivo: string; desarrollo: string; logros: string }> = {
|
||||
1: {
|
||||
objetivo: 'Preparar el equipo central que alojará todos los servicios de DASUTeN, garantizando que opere de forma independiente a los sistemas de la Facultad.',
|
||||
desarrollo: 'Se instaló y configuró el servidor dedicado en la oficina de DASUTeN, creando un entorno de trabajo completamente separado de la red universitaria para mayor seguridad y control.',
|
||||
logros: 'Servidor propio operativo y listo para funcionar. Entorno aislado que brinda independencia total respecto a los sistemas de la Facultad.'
|
||||
},
|
||||
2: {
|
||||
objetivo: 'Establecer un sistema centralizado de identificación de usuarios y permisos de acceso, propio de la oficina DASUTeN.',
|
||||
desarrollo: 'Se configuró un servicio de gestión de identidades que permite controlar quién accede a cada equipo y recurso dentro de la red de DASUTeN.',
|
||||
logros: 'Sistema de usuarios operativo. Cada persona accede con credenciales propias. Se simplifica la administración de permisos y la seguridad de acceso.'
|
||||
},
|
||||
3: {
|
||||
objetivo: 'Instalar el sistema de base de datos necesario y recuperar toda la información del sistema DASUTeN desde el respaldo existente.',
|
||||
desarrollo: 'Se preparó un entorno dedicado para la base de datos, se transfirió el respaldo completo (~9 GB de información) y se restauró verificando su integridad.',
|
||||
logros: 'Toda la información de gestión de DASUTeN fue recuperada exitosamente. La base de datos está operativa y accesible desde la red interna.'
|
||||
},
|
||||
4: {
|
||||
objetivo: 'Habilitar la administración remota segura de todos los equipos y generar respaldos de seguridad como punto de recuperación.',
|
||||
desarrollo: 'Se activó el acceso remoto seguro en todos los equipos y se generaron copias de respaldo completas para poder restaurar el sistema ante cualquier eventualidad.',
|
||||
logros: 'Posibilidad de gestionar todos los equipos sin necesidad de presencia física. Respaldos de seguridad disponibles ante cualquier imprevisto.'
|
||||
},
|
||||
5: {
|
||||
objetivo: 'Analizar la aplicación de gestión DASUTeN y ponerla en funcionamiento sobre la nueva infraestructura virtual.',
|
||||
desarrollo: 'Configuración de Kermet.ini, instalación de componentes de sistema, fuentes y apertura de firewall SQL. Pruebas de conectividad exitosas.',
|
||||
logros: 'Despliegue operativo verificado con login exitoso. Validación presencial (UAT) realizada con Andrea Almirón satisfactoriamente.'
|
||||
},
|
||||
6: {
|
||||
objetivo: '🚀 Poner en funcionamiento el servidor físico en la oficina, integrar clientes al dominio y configurar políticas de seguridad.',
|
||||
desarrollo: 'Traslado físico del servidor Proxmox, unión de la PC pc-dasu0 al dominio dasuten.utnlr y despliegue de GPOs de seguridad.',
|
||||
logros: 'Hitos pendientes: Instalación física, AD-Join, GPO de seguridad y mapeo de unidades de red.'
|
||||
}
|
||||
};
|
||||
|
||||
/* ═══════════ MAIN COMPONENT ═══════════ */
|
||||
export default function ProyectoDashboard({ codigo = 'P2601' }: { codigo?: string }) {
|
||||
const [proyecto, setProyecto] = useState<Proyecto | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState('');
|
||||
const [vista, setVista] = useState<Vista>('gerencial');
|
||||
const [expandedFases, setExpandedFases] = useState<Set<number>>(new Set());
|
||||
const [expandedGerFases, setExpandedGerFases] = useState<Set<number>>(new Set());
|
||||
const [expandedHitos, setExpandedHitos] = useState<Set<number>>(new Set());
|
||||
const [descExpanded, setDescExpanded] = useState(false);
|
||||
|
||||
useEffect(() => { fetchProyecto(); }, [codigo]);
|
||||
@@ -185,14 +161,47 @@ export default function ProyectoDashboard({ codigo = 'P2601' }: { codigo?: strin
|
||||
});
|
||||
};
|
||||
|
||||
const toggleGerFase = (num: number) => {
|
||||
setExpandedGerFases(prev => {
|
||||
const toggleHito = (id: number) => {
|
||||
setExpandedHitos(prev => {
|
||||
const next = new Set(prev);
|
||||
next.has(num) ? next.delete(num) : next.add(num);
|
||||
next.has(id) ? next.delete(id) : next.add(id);
|
||||
return next;
|
||||
});
|
||||
};
|
||||
|
||||
// Actualizar Estado de Hito
|
||||
const handleEstadoClick = async (h: Hito) => {
|
||||
const nextEstado = h.estado === '📋' ? '⏳' : h.estado === '⏳' ? '✅' : '📋';
|
||||
try {
|
||||
const res = await fetch(`${API_URL}/proyectos/hitos/${h.id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ estado: nextEstado })
|
||||
});
|
||||
if (res.ok) fetchProyecto();
|
||||
} catch (e) { console.error('Error al actualizar estado', e); }
|
||||
};
|
||||
|
||||
// Actualizar Horas
|
||||
const handleHorasClick = async (h: Hito, tipo: 'P' | 'R') => {
|
||||
const actual = tipo === 'P' ? h.horas_presencial : h.horas_remoto;
|
||||
const imputadas = prompt(`Horas ${tipo === 'P' ? 'Presenciales' : 'Remotas'} para hito: ${h.id_hito}\n(Ej: 1.5, 0.5 o dejar vacío)`, String(actual));
|
||||
if (imputadas === null) return; // Canceló
|
||||
|
||||
const num = parseFloat(imputadas.replace(',', '.'));
|
||||
const valorFinal = isNaN(num) ? 0 : num;
|
||||
|
||||
try {
|
||||
const body = tipo === 'P' ? { horas_presencial: valorFinal } : { horas_remoto: valorFinal };
|
||||
const res = await fetch(`${API_URL}/proyectos/hitos/${h.id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
if (res.ok) fetchProyecto();
|
||||
} catch (e) { console.error('Error al actualizar horas', e); }
|
||||
};
|
||||
|
||||
if (loading) return <div style={{ textAlign: 'center', padding: '3rem', color: 'var(--text-muted)' }}>Cargando proyecto...</div>;
|
||||
if (error || !proyecto) return <div style={{ textAlign: 'center', padding: '3rem', color: '#ef4444' }}>Error: {error}</div>;
|
||||
|
||||
@@ -232,38 +241,14 @@ export default function ProyectoDashboard({ codigo = 'P2601' }: { codigo?: strin
|
||||
<p style={{ color: 'var(--text-muted)', fontSize: '0.85rem', maxWidth: '600px', margin: '0 auto 0.8rem' }}>
|
||||
{proyecto.descripcion}
|
||||
</p>
|
||||
|
||||
{/* Toggle vista */}
|
||||
<div style={{
|
||||
display: 'inline-flex', borderRadius: '8px', overflow: 'hidden',
|
||||
border: '1px solid var(--border)', background: 'rgba(255,255,255,0.03)'
|
||||
}}>
|
||||
<button
|
||||
onClick={() => setVista('gerencial')}
|
||||
style={{
|
||||
padding: '6px 16px', fontSize: '0.75rem', fontWeight: 600, border: 'none', cursor: 'pointer',
|
||||
background: vista === 'gerencial' ? 'linear-gradient(135deg, #38bdf8, #818cf8)' : 'transparent',
|
||||
color: vista === 'gerencial' ? '#fff' : 'var(--text-muted)', transition: 'all 0.2s ease'
|
||||
}}
|
||||
><i className="fas fa-chart-pie" style={{ marginRight: '5px' }}></i>Resumen</button>
|
||||
<button
|
||||
onClick={() => setVista('tecnica')}
|
||||
style={{
|
||||
padding: '6px 16px', fontSize: '0.75rem', fontWeight: 600, border: 'none', cursor: 'pointer',
|
||||
background: vista === 'tecnica' ? 'linear-gradient(135deg, #38bdf8, #818cf8)' : 'transparent',
|
||||
color: vista === 'tecnica' ? '#fff' : 'var(--text-muted)', transition: 'all 0.2s ease'
|
||||
}}
|
||||
><i className="fas fa-list-alt" style={{ marginRight: '5px' }}></i>Detalle Técnico</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ═══════════ VISTA GERENCIAL ═══════════ */}
|
||||
{vista === 'gerencial' && (
|
||||
<>
|
||||
{/* Descripción del Proyecto — desplegable */}
|
||||
<div className="card" style={{ padding: 0, overflow: 'hidden', marginBottom: '1.5rem' }}>
|
||||
<div
|
||||
onClick={() => setDescExpanded(prev => !prev)}
|
||||
{/* ═══════════ VISTA UNIFICADA ═══════════ */}
|
||||
|
||||
{/* Descripción del Proyecto — desplegable */}
|
||||
<div className="card" style={{ padding: 0, overflow: 'hidden', marginBottom: '1.5rem' }}>
|
||||
<div
|
||||
onClick={() => setDescExpanded(prev => !prev)}
|
||||
style={{
|
||||
padding: '0.8rem 1rem', cursor: 'pointer', display: 'flex',
|
||||
alignItems: 'center', justifyContent: 'space-between',
|
||||
@@ -280,48 +265,49 @@ export default function ProyectoDashboard({ codigo = 'P2601' }: { codigo?: strin
|
||||
</div>
|
||||
{descExpanded && (
|
||||
<div style={{ padding: '0 1rem 1rem', lineHeight: 1.6, fontSize: '0.82rem', color: 'var(--text)' }}>
|
||||
<p style={{ margin: '0 0 0.8rem' }}>
|
||||
<strong>DASUTeN</strong> es la obra social que brinda cobertura a empleados, docentes y alumnos de la
|
||||
Universidad Tecnológica Nacional. Su oficina en la Facultad Regional La Rioja depende
|
||||
operativamente de la <strong>sede central en Buenos Aires</strong>.
|
||||
</p>
|
||||
<p style={{ margin: '0 0 0.8rem' }}>
|
||||
Este proyecto tiene como objetivo <strong>dotar a la oficina DASUTeN de su propia infraestructura
|
||||
tecnológica independiente</strong>, operando bajo un entorno virtualizado (Proxmox) con acceso remoto seguro vía Tailscale.
|
||||
</p>
|
||||
{proyecto.detalles_json?.contexto?.map((p, i) => (
|
||||
<p key={i} style={{ margin: '0 0 0.8rem' }} dangerouslySetInnerHTML={{ __html: p.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>') }} />
|
||||
))}
|
||||
|
||||
<div style={{
|
||||
display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)',
|
||||
display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))',
|
||||
gap: '1.2rem', marginTop: '1rem'
|
||||
}}>
|
||||
{proyecto.detalles_json?.objetivos && (
|
||||
<div>
|
||||
<div style={subheadStyle}>🎯 Objetivos y Alcance</div>
|
||||
<ul style={listStyle}>
|
||||
{proyecto.detalles_json.objetivos.map((o, i) => <li key={i}>{o}</li>)}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<div style={subheadStyle}>🎯 Objetivos y Alcance</div>
|
||||
<ul style={listStyle}>
|
||||
<li>Sistema de gestión operando desde servidor propio</li>
|
||||
<li>Independencia total de los equipos de la Facultad</li>
|
||||
<li>Oficina autosuficiente con su propia red y respaldos</li>
|
||||
<li>Servidor dedicado en oficina DASUTeN</li>
|
||||
<li>Red interna propia y segura</li>
|
||||
<li>Computadora de escritorio como acceso al sistema</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<div style={subheadStyle}>👥 Responsables y Beneficiarios</div>
|
||||
<ul style={listStyle}>
|
||||
<li><strong>Ejecución:</strong> Lic. Ricardo Monla</li>
|
||||
<li><strong>Supervisión:</strong> Dirección de TIC</li>
|
||||
</ul>
|
||||
<div style={{ fontSize: '0.7rem', color: '#38bdf8', fontWeight: 600, marginTop: '0.4rem', marginBottom: '0.2rem' }}>Usuarios directos:</div>
|
||||
<ul style={listStyle}>
|
||||
<li>Andrea Almirón — Administrativa DASUTeN</li>
|
||||
<li>Romina Molina — Administrativa</li>
|
||||
<li>Dra. Eugenia Riveros — Auditora Médica</li>
|
||||
</ul>
|
||||
<div style={{ fontSize: '0.7rem', color: '#38bdf8', fontWeight: 600, marginTop: '0.4rem', marginBottom: '0.2rem' }}>Beneficiarios indirectos:</div>
|
||||
<ul style={listStyle}>
|
||||
<li>Personal Docente</li>
|
||||
<li>Personal No Docente</li>
|
||||
<li>Alumnos</li>
|
||||
</ul>
|
||||
{proyecto.detalles_json?.responsables && (
|
||||
<>
|
||||
<div style={subheadStyle}>👥 Responsables</div>
|
||||
<ul style={listStyle}>
|
||||
{proyecto.detalles_json.responsables.map((r, i) => (
|
||||
<li key={i} dangerouslySetInnerHTML={{ __html: r.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>') }} />
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
{proyecto.detalles_json?.beneficiarios_directos && (
|
||||
<>
|
||||
<div style={{ fontSize: '0.7rem', color: '#38bdf8', fontWeight: 600, marginTop: '0.4rem', marginBottom: '0.2rem' }}>Usuarios directos:</div>
|
||||
<ul style={listStyle}>
|
||||
{proyecto.detalles_json.beneficiarios_directos.map((b, i) => <li key={i}>{b}</li>)}
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
{proyecto.detalles_json?.beneficiarios_indirectos && (
|
||||
<>
|
||||
<div style={{ fontSize: '0.7rem', color: '#38bdf8', fontWeight: 600, marginTop: '0.4rem', marginBottom: '0.2rem' }}>Beneficiarios indirectos:</div>
|
||||
<ul style={listStyle}>
|
||||
{proyecto.detalles_json.beneficiarios_indirectos.map((b, i) => <li key={i}>{b}</li>)}
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -383,100 +369,6 @@ export default function ProyectoDashboard({ codigo = 'P2601' }: { codigo?: strin
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Fases con descripciones expandibles */}
|
||||
<SectionTitle title="📊 Fases del Proyecto" />
|
||||
{proyecto.fases.map(fase => {
|
||||
const hitos = fase.hitos || [];
|
||||
const faseCompletos = hitos.filter(h => h.estado === '✅').length;
|
||||
const faseProgreso = hitos.length > 0 ? Math.round((faseCompletos / hitos.length) * 100) : 0;
|
||||
const hrsTotal = hitos.reduce((s, h) => s + h.horas_presencial + h.horas_remoto, 0);
|
||||
const isExpanded = expandedGerFases.has(fase.numero);
|
||||
const detalle = faseDetalles[fase.numero];
|
||||
|
||||
return (
|
||||
<div key={fase.id} className="card" style={{
|
||||
marginBottom: '0.6rem', padding: 0, overflow: 'hidden', position: 'relative'
|
||||
}}>
|
||||
{/* Barra de progreso de fondo */}
|
||||
<div style={{
|
||||
position: 'absolute', top: 0, left: 0, bottom: 0, width: `${faseProgreso}%`,
|
||||
background: fase.estado === '✅' ? 'rgba(34,197,94,0.06)' : 'rgba(56,189,248,0.04)',
|
||||
transition: 'width 0.4s', pointerEvents: 'none'
|
||||
}} />
|
||||
|
||||
{/* Header clickeable */}
|
||||
<div
|
||||
onClick={() => toggleGerFase(fase.numero)}
|
||||
style={{
|
||||
position: 'relative', display: 'flex', justifyContent: 'space-between',
|
||||
alignItems: 'center', padding: '0.8rem 1rem', cursor: 'pointer'
|
||||
}}
|
||||
>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '0.7rem' }}>
|
||||
<span style={{
|
||||
fontSize: '1.3rem', width: '36px', height: '36px', display: 'flex',
|
||||
alignItems: 'center', justifyContent: 'center', borderRadius: '8px',
|
||||
background: fase.estado === '✅' ? 'rgba(34,197,94,0.12)' :
|
||||
fase.estado === '⏳' ? 'rgba(234,179,8,0.12)' : 'rgba(255,255,255,0.05)'
|
||||
}}>{estadoIcon(fase.estado)}</span>
|
||||
<div>
|
||||
<div style={{ fontWeight: 600, fontSize: '0.88rem' }}>
|
||||
F{fase.numero} · {fase.nombre}
|
||||
</div>
|
||||
{!isExpanded && fase.descripcion && (
|
||||
<div style={{ fontSize: '0.72rem', color: 'var(--text-muted)', marginTop: '2px' }}>
|
||||
{fase.descripcion}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '1rem', flexShrink: 0 }}>
|
||||
{hrsTotal > 0 && (
|
||||
<span style={{ fontSize: '0.75rem', color: 'var(--text-muted)' }}>{hrsTotal.toFixed(1)}h</span>
|
||||
)}
|
||||
<div style={{
|
||||
minWidth: '52px', textAlign: 'right', fontWeight: 700, fontSize: '0.85rem',
|
||||
color: faseProgreso === 100 ? '#22c55e' : faseProgreso > 0 ? '#38bdf8' : 'var(--text-muted)'
|
||||
}}>{faseProgreso}%</div>
|
||||
<span style={{ color: 'var(--text-muted)', fontSize: '0.8rem' }}>{isExpanded ? '▾' : '▸'}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Detalle expandible */}
|
||||
{isExpanded && detalle && (
|
||||
<div style={{
|
||||
position: 'relative', borderTop: '1px solid var(--border)',
|
||||
padding: '0.8rem 1rem',
|
||||
display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: '0.8rem'
|
||||
}}>
|
||||
<FaseDetailCol icon="🎯" title="Objetivo" text={detalle.objetivo} />
|
||||
<FaseDetailCol icon="⚙️" title="Desarrollo" text={detalle.desarrollo} />
|
||||
<FaseDetailCol icon="✨" title="Logros" text={detalle.logros} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* ═══════════ VISTA TÉCNICA ═══════════ */}
|
||||
{vista === 'tecnica' && (
|
||||
<>
|
||||
{/* Métricas numéricas */}
|
||||
<div style={{
|
||||
display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(130px, 1fr))',
|
||||
gap: '0.8rem', marginBottom: '1.5rem'
|
||||
}}>
|
||||
<MetricCard label="Fases" value={`${fasesCompletas + fasesEnCurso}/${proyecto.fases.length}`} color="#38bdf8" />
|
||||
<MetricCard label="Hitos Comp." value={m.hitos_completados} color="#22c55e" />
|
||||
<MetricCard label="Hitos Pend." value={m.hitos_pendientes} color="#eab308" />
|
||||
<MetricCard label="Hrs Físicas" value={`${hrsP.toFixed(1)}h`} color="#f97316" />
|
||||
<MetricCard label="Esfuerzo Total" value={`${totalH.toFixed(1)}h`} color="#a78bfa" />
|
||||
</div>
|
||||
|
||||
{/* Barra progreso */}
|
||||
<div style={{ marginBottom: '1.5rem' }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', fontSize: '0.85rem', marginBottom: '0.3rem' }}>
|
||||
@@ -547,6 +439,22 @@ export default function ProyectoDashboard({ codigo = 'P2601' }: { codigo?: strin
|
||||
transition: 'width 0.4s'
|
||||
}} />
|
||||
</div>
|
||||
|
||||
{/* Resumen Táctico de Logros y Objetivos (Merged from Gerencial) */}
|
||||
{expanded && (fase.objetivo || fase.desarrollo || fase.logros) && (
|
||||
<div style={{
|
||||
position: 'relative', borderTop: '1px solid var(--border)',
|
||||
background: 'rgba(255,255,255,0.01)',
|
||||
padding: '0.8rem 1rem',
|
||||
display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: '0.8rem'
|
||||
}}>
|
||||
{fase.objetivo && <FaseDetailCol icon="🎯" title="Objetivo" text={fase.objetivo} />}
|
||||
{fase.desarrollo && <FaseDetailCol icon="⚙️" title="Desarrollo" text={fase.desarrollo} />}
|
||||
{fase.logros && <FaseDetailCol icon="✨" title="Logros" text={fase.logros} />}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Tabla expandible de hitos */}
|
||||
{expanded && hitos.length > 0 && (
|
||||
<div style={{ padding: '0.5rem 1rem 0.8rem' }}>
|
||||
<table className="table-ifde" style={{ fontSize: '0.8rem' }}>
|
||||
@@ -562,26 +470,61 @@ export default function ProyectoDashboard({ codigo = 'P2601' }: { codigo?: strin
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{hitos.map(h => (
|
||||
<tr key={h.id}>
|
||||
<td><code style={{ fontSize: '0.72rem', color: '#38bdf8' }}>{h.id_hito}</code></td>
|
||||
<td>
|
||||
<strong>{h.titulo}</strong>
|
||||
{h.descripcion && <div style={{ fontSize: '0.72rem', color: 'var(--text-muted)', marginTop: '2px' }}>{h.descripcion}</div>}
|
||||
</td>
|
||||
<td style={{ fontSize: '0.72rem', color: 'var(--text-muted)' }}>
|
||||
{h.fecha ? new Date(h.fecha + 'T12:00:00').toLocaleDateString('es-AR', { day: '2-digit', month: '2-digit' }) : '—'}
|
||||
</td>
|
||||
<td style={{ textAlign: 'center', color: h.horas_presencial > 0 ? '#f97316' : 'var(--text-muted)' }}>
|
||||
{h.horas_presencial > 0 ? `${h.horas_presencial}h` : '—'}
|
||||
</td>
|
||||
<td style={{ textAlign: 'center', color: h.horas_remoto > 0 ? '#a78bfa' : 'var(--text-muted)' }}>
|
||||
{h.horas_remoto > 0 ? `${h.horas_remoto}h` : '—'}
|
||||
</td>
|
||||
<td style={{ fontSize: '0.72rem' }}>{h.nodo_nombre || '—'}</td>
|
||||
<td style={{ textAlign: 'center' }}>{estadoIcon(h.estado)}</td>
|
||||
</tr>
|
||||
))}
|
||||
{hitos.map(h => {
|
||||
const isHitoExpanded = expandedHitos.has(h.id);
|
||||
return (
|
||||
<React.Fragment key={h.id}>
|
||||
<tr
|
||||
style={{ cursor: h.descripcion ? 'pointer' : 'default' }}
|
||||
onClick={() => { if(h.descripcion) toggleHito(h.id) }}
|
||||
title={h.descripcion ? "Click para expandir/colapsar descripción" : ""}
|
||||
>
|
||||
<td onClick={(e) => e.stopPropagation()}><code style={{ fontSize: '0.72rem', color: '#38bdf8' }}>{h.id_hito}</code></td>
|
||||
<td>
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
||||
<strong>{h.titulo}</strong>
|
||||
{h.descripcion && <span style={{ fontSize: '0.8rem', color: 'var(--text-muted)', marginLeft: '8px' }}>{isHitoExpanded ? '▾' : '▸'}</span>}
|
||||
</div>
|
||||
</td>
|
||||
<td style={{ fontSize: '0.72rem', color: 'var(--text-muted)' }} onClick={(e) => e.stopPropagation()}>
|
||||
{h.fecha ? new Date(h.fecha + 'T12:00:00').toLocaleDateString('es-AR', { day: '2-digit', month: '2-digit' }) : '—'}
|
||||
</td>
|
||||
<td
|
||||
style={{ textAlign: 'center', color: h.horas_presencial > 0 ? '#f97316' : 'var(--text-muted)', cursor: 'pointer' }}
|
||||
onClick={(e) => { e.stopPropagation(); handleHorasClick(h, 'P'); }}
|
||||
title="Click para editar horas presenciales"
|
||||
>
|
||||
{h.horas_presencial > 0 ? `${h.horas_presencial}h` : '—'}
|
||||
</td>
|
||||
<td
|
||||
style={{ textAlign: 'center', color: h.horas_remoto > 0 ? '#a78bfa' : 'var(--text-muted)', cursor: 'pointer' }}
|
||||
onClick={(e) => { e.stopPropagation(); handleHorasClick(h, 'R'); }}
|
||||
title="Click para editar horas remotas"
|
||||
>
|
||||
{h.horas_remoto > 0 ? `${h.horas_remoto}h` : '—'}
|
||||
</td>
|
||||
<td style={{ fontSize: '0.72rem' }} onClick={(e) => e.stopPropagation()}>{h.nodo_nombre || '—'}</td>
|
||||
<td
|
||||
style={{ textAlign: 'center', cursor: 'pointer' }}
|
||||
onClick={(e) => { e.stopPropagation(); handleEstadoClick(h); }}
|
||||
title="Click para cambiar estado"
|
||||
>
|
||||
{estadoIcon(h.estado)}
|
||||
</td>
|
||||
</tr>
|
||||
{isHitoExpanded && h.descripcion && (
|
||||
<tr style={{ background: 'rgba(255,255,255,0.02)' }}>
|
||||
<td></td>
|
||||
<td colSpan={6} style={{ padding: '0.6rem 1rem', fontSize: '0.78rem', color: 'var(--text-muted)' }}>
|
||||
<div style={{ borderLeft: '2px solid #38bdf8', paddingLeft: '0.8rem', whiteSpace: 'pre-wrap' }}>
|
||||
{h.descripcion}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -589,11 +532,9 @@ export default function ProyectoDashboard({ codigo = 'P2601' }: { codigo?: strin
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
)}
|
||||
|
||||
<div style={{ textAlign: 'center', color: 'var(--text-muted)', fontSize: '0.7rem', marginTop: '1.5rem', paddingTop: '0.8rem', borderTop: '1px solid var(--border)' }}>
|
||||
P2601 — Infraestructura DASUTEN · UTN FRLR · Dashboard integrado en dtic-BITACORAs
|
||||
Dashboard unificado integrado en dtic-BITACORAs
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
+477
-65
@@ -16,15 +16,22 @@ module ADN
|
||||
@opciones = {
|
||||
modo: defaults['modo'] || 'stop',
|
||||
storage: defaults['storage'] || 'local',
|
||||
compress: defaults['compress'] || 'gzip'
|
||||
compress: defaults['compress'] || 'gzip',
|
||||
retencion: defaults['retencion_dias'] || 6
|
||||
}
|
||||
end
|
||||
|
||||
def ejecutar
|
||||
parser = OptionParser.new do |opts|
|
||||
opts.banner = "Uso: ./tools/adn/run backup <nodo> [OPCIONES]"
|
||||
opts.banner = "Uso: ./tools/adn/run backup <nodo|estados> [OPCIONES]"
|
||||
opts.separator ""
|
||||
opts.separator "Ejecuta un backup remoto siguiendo el protocolo ADN"
|
||||
opts.separator "Ejecuta un backup remoto o consulta el estado actual."
|
||||
opts.separator ""
|
||||
opts.separator "Acciones:"
|
||||
opts.separator " <nodo> Ejecutar backup del nodo especificado"
|
||||
opts.separator " estados Ver estado actual de los backups en Proxmox"
|
||||
opts.separator " sanear Limpiar backups antiguos según retención"
|
||||
opts.separator " predeterminar Configurar valores por defecto"
|
||||
opts.separator ""
|
||||
opts.separator "Opciones:"
|
||||
opts.on("--mode MODO", "Modo de backup (stop, snapshot, suspend. Default: #{@opciones[:modo]})") do |m|
|
||||
@@ -48,18 +55,21 @@ module ADN
|
||||
end
|
||||
|
||||
if @args.empty?
|
||||
@logger.error("Se requiere nombre de nodo")
|
||||
@logger.error("Se requiere nombre de nodo o acción")
|
||||
puts parser
|
||||
exit 1
|
||||
end
|
||||
|
||||
if @args[0] == 'predeterminar'
|
||||
case @args[0]
|
||||
when 'predeterminar'
|
||||
comando_predeterminar(@args[1..-1])
|
||||
return
|
||||
when 'estados', 'estado'
|
||||
comando_estados
|
||||
when 'sanear'
|
||||
comando_sanear
|
||||
else
|
||||
ejecutar_backup(@args[0])
|
||||
end
|
||||
|
||||
nodo = @args[0]
|
||||
ejecutar_backup(nodo)
|
||||
end
|
||||
|
||||
private
|
||||
@@ -89,21 +99,41 @@ module ADN
|
||||
candados_path = File.join(ADN::PROJECT_ROOT, 'tools', 'ns8-candados', 'ns8-candados.rb')
|
||||
|
||||
# Ejecutar con ns8-candados run
|
||||
# Nota: el comando 'authorize' debe haberse ejecutado antes o lo incluimos
|
||||
puts "#{Color::DIM}🔓 Abriendo candado para sesión de backup...#{Color::RESET}"
|
||||
# Ejecutar con ns8-candados autorizando primero
|
||||
system("ruby #{candados_path} authorize > /dev/null 2>&1")
|
||||
|
||||
success = system("ruby #{candados_path} run admindasu SSHPASS '#{cmd_seguro}'")
|
||||
task_id = nil
|
||||
full_output = ""
|
||||
|
||||
# Usar popen para leer la salida en tiempo real
|
||||
@logger.info("Conectando y monitoreando salida de Proxmox...")
|
||||
|
||||
IO.popen("ruby #{candados_path} run admindasu SSHPASS '#{cmd_seguro}' 2>&1") do |pf|
|
||||
pf.each_line do |line|
|
||||
# Imprimir flujo para el usuario
|
||||
puts " #{Color::DIM}#{line.strip}#{Color::RESET}"
|
||||
full_output += line
|
||||
|
||||
# Si detectamos el Task ID al inicio, lo registramos de inmediato
|
||||
if task_id.nil? && match = line.match(/started backup task '([^']+)'/)
|
||||
task_id = match[1]
|
||||
@logger.info("Task ID detectado: #{task_id}. Registrando en bitácora...")
|
||||
registrar_task_id_bitacora(nodo, task_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
success = $?.success?
|
||||
|
||||
# 4. Finalizar y cerrar
|
||||
system("ruby #{candados_path} cerrar > /dev/null 2>&1")
|
||||
|
||||
if success
|
||||
@logger.exito("Backup de #{nodo} completado exitosamente.")
|
||||
registrar_fin_bitacora(nodo, true)
|
||||
registrar_fin_bitacora(nodo, true, task_id)
|
||||
else
|
||||
@logger.error("La ejecución del backup falló.")
|
||||
registrar_fin_bitacora(nodo, false)
|
||||
registrar_fin_bitacora(nodo, false, task_id)
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
@@ -116,10 +146,7 @@ module ADN
|
||||
end
|
||||
|
||||
contenido = File.read(ruta_nodo)
|
||||
# Buscamos VMID (puede decir "VM ID: 100" o "vmid: 100" o "- **VMID**: `100`")
|
||||
vmid = contenido.match(/(?:VM ID|vmid|VMID)\*\*?:?\s*`?(\d+)`?/i)&.[](1)
|
||||
|
||||
# Buscamos el host (especificamente el link o nombre entre backticks)
|
||||
host_name = contenido.match(/(?:Padre\/Host|Host Anfitrión|Anfitrión|Host)\*\*:?\s*`([^`]+)`/i)&.[](1)
|
||||
|
||||
unless vmid && host_name
|
||||
@@ -132,11 +159,8 @@ module ADN
|
||||
host_ip = nil
|
||||
if File.exist?(ruta_host)
|
||||
c_host = File.read(ruta_host)
|
||||
# IP en tabla: | IP | `10.0.10.1` |
|
||||
host_ip ||= c_host.match(/\|\s*IP[^\|]*\|\s*`([^`]+)`\s*\|/)&.[](1)
|
||||
# IP en lista: - **IP**: `10.0.10.1`
|
||||
host_ip ||= c_host.match(/IP\*\*:?\s*`([^`]+)`/)&.[](1)
|
||||
# IP simple: IP: 10.0.10.1
|
||||
host_ip ||= c_host.match(/IP:\s*([\d\.]+)/)&.[](1)
|
||||
end
|
||||
|
||||
@@ -145,63 +169,76 @@ module ADN
|
||||
return nil
|
||||
end
|
||||
|
||||
if host_ip && host_ip.include?('/')
|
||||
host_ip = host_ip.split('/')[0]
|
||||
end
|
||||
|
||||
host_ip = host_ip.split('/')[0] if host_ip.include?('/')
|
||||
{ vmid: vmid, host_name: host_name, host_ip: host_ip }
|
||||
end
|
||||
|
||||
def registrar_inicio_bitacora(nodo, datos)
|
||||
fecha = Date.today.iso8601
|
||||
ruta = File.join(ADN::BITACORAS_DIR, "#{fecha}.md")
|
||||
return unless File.exist?(ruta)
|
||||
require_relative '../../bitacoras-db/core/bitacora_db'
|
||||
|
||||
hora = Time.now.strftime('%H:%M')
|
||||
|
||||
# Si ya existe la sección del nodo, añadimos la línea. Si no, creamos la sección.
|
||||
contenido = File.read(ruta)
|
||||
|
||||
entrada = <<~ENTRADA
|
||||
BitacorasDB::BitacoraDB.with_connection do |db|
|
||||
# Asegurar bitácora
|
||||
bitacora = db.find_bitacora_by_fecha(Date.today)
|
||||
bitacora ||= db.create_bitacora(fecha: Date.today)
|
||||
|
||||
### #{nodo}
|
||||
# Buscar nodo en DB
|
||||
nodo_db = db.find_nodo_by_nombre(nodo)
|
||||
|
||||
#### ⏳ - BKP-ADN - Backup Autónomo (Protocolo ADN)
|
||||
Ejecución de backup gestionada por `tools/adn.rb` para la VM #{datos[:vmid]} en el host #{datos[:host_name]}.
|
||||
hora = Time.now.strftime('%H:%M')
|
||||
entrada = db.create_entrada(
|
||||
inicio: hora,
|
||||
descripcion: "Inicio de backup remoto vía SSH para VM #{datos[:vmid]} en #{datos[:host_name]}.",
|
||||
estado: '⏳',
|
||||
modo: 'R',
|
||||
bitacora_id: bitacora['id'],
|
||||
nodo_id: nodo_db ? nodo_db['id'] : nil
|
||||
)
|
||||
|
||||
| I | F | Descripción | E |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| #{hora} | | Inicio de backup remoto vía SSH (Seguro). | [R] ⏳ |
|
||||
ENTRADA
|
||||
|
||||
unless contenido.include?("### #{nodo}")
|
||||
# Insertar antes del footer de la IA
|
||||
nuevo_contenido = contenido.sub(/<!-- 🤖 PREMISAS/, "#{entrada}\n\n<!-- 🤖 PREMISAS")
|
||||
File.write(ruta, nuevo_contenido)
|
||||
# Guardar ID para actualizar después
|
||||
@backup_entrada_id = entrada['id'].to_i
|
||||
@backup_bitacora_id = bitacora['id'].to_i
|
||||
end
|
||||
rescue => e
|
||||
@logger.error("Error registrando inicio en DB: #{e.message}")
|
||||
end
|
||||
|
||||
def registrar_fin_bitacora(nodo, exito)
|
||||
fecha = Date.today.iso8601
|
||||
ruta = File.join(ADN::BITACORAS_DIR, "#{fecha}.md")
|
||||
return unless File.exist?(ruta)
|
||||
def registrar_task_id_bitacora(nodo, task_id)
|
||||
return unless @backup_entrada_id
|
||||
|
||||
hora = Time.now.strftime('%H:%M')
|
||||
require_relative '../../bitacoras-db/core/bitacora_db'
|
||||
|
||||
BitacorasDB::BitacoraDB.with_connection do |db|
|
||||
db.update_entrada(@backup_entrada_id, {
|
||||
descripcion: "[task:#{task_id[0..7]}] Backup remoto en ejecución."
|
||||
})
|
||||
end
|
||||
rescue => e
|
||||
@logger.error("Error registrando task_id en DB: #{e.message}")
|
||||
end
|
||||
|
||||
def registrar_fin_bitacora(nodo, exito, task_id = nil)
|
||||
return unless @backup_entrada_id
|
||||
|
||||
require_relative '../../bitacoras-db/core/bitacora_db'
|
||||
require_relative '../../bitacoras-db/exporters/md_exporter'
|
||||
|
||||
hora_fin = Time.now.strftime('%H:%M')
|
||||
estado = exito ? '✅' : '⚠️'
|
||||
desc = exito ? 'Backup completado exitosamente.' : 'Fallo en la ejecución del backup.'
|
||||
|
||||
contenido = File.read(ruta)
|
||||
|
||||
# Actualizar la línea de tiempo
|
||||
linea_nueva = "| #{hora} (Fin) | | #{desc} | [R] #{estado} |"
|
||||
|
||||
# Buscamos la tarea BKP-ADN
|
||||
nuevo_contenido = contenido.gsub(/#### ⏳ - BKP-ADN/, "#### #{estado} - BKP-ADN")
|
||||
nuevo_contenido = nuevo_contenido.gsub(/\| \d{2}:\d{2} \| \| Inicio de backup remoto.*/, linea_nueva)
|
||||
|
||||
File.write(ruta, nuevo_contenido)
|
||||
desc = "[task:#{task_id[0..7]}] #{desc}" if task_id
|
||||
|
||||
BitacorasDB::BitacoraDB.with_connection do |db|
|
||||
db.update_entrada(@backup_entrada_id, {
|
||||
fin: hora_fin,
|
||||
descripcion: desc,
|
||||
estado: estado
|
||||
})
|
||||
end
|
||||
rescue => e
|
||||
@logger.error("Error registrando fin en DB: #{e.message}")
|
||||
end
|
||||
|
||||
|
||||
def comando_predeterminar(args)
|
||||
if args.length < 2
|
||||
puts "#{Color::YELLOW}Uso: adn backup predeterminar <parametro> <valor>#{Color::RESET}"
|
||||
@@ -210,12 +247,11 @@ module ADN
|
||||
end
|
||||
|
||||
param = args[0].downcase
|
||||
valor = args[1].downcase
|
||||
|
||||
# Normalizar parámetro (ej: 'modo' -> 'modo', 'storage' -> 'storage')
|
||||
valor = args[1]
|
||||
param = 'modo' if param == 'mode'
|
||||
param = 'retencion_dias' if param == 'edad'
|
||||
|
||||
unless ['modo', 'storage', 'compress'].include?(param)
|
||||
unless ['modo', 'storage', 'compress', 'retencion_dias'].include?(param)
|
||||
@logger.error("Parámetro no predeterminable: #{param}")
|
||||
exit 1
|
||||
end
|
||||
@@ -224,5 +260,381 @@ module ADN
|
||||
@logger.exito("Valor predeterminado establecido: backup.#{param} = #{valor}")
|
||||
puts "#{Color::GREEN}✓ Se ha predeterminado el #{param} a '#{valor}' para futuros backups.#{Color::RESET}"
|
||||
end
|
||||
|
||||
def comando_estados
|
||||
@logger.info("Consultando estado de backups en cluster Proxmox")
|
||||
|
||||
# Lista de hosts a consultar
|
||||
hosts = [
|
||||
{ nombre: 'srv-pmox1', ip: '10.0.10.201' },
|
||||
{ nombre: 'srv-dasu', ip: '10.0.10.205' }
|
||||
]
|
||||
|
||||
puts "\n#{Color::BOLD}🔍 Estado de Backups en Tiempo Real (Proxmox)#{Color::RESET}"
|
||||
puts "─" * 60
|
||||
|
||||
candados_path = File.join(ADN::PROJECT_ROOT, 'tools', 'ns8-candados', 'ns8-candados.rb')
|
||||
# Asegurar autorización general para el lote
|
||||
system("ruby #{candados_path} authorize > /dev/null 2>&1")
|
||||
|
||||
all_tasks_accumulated = []
|
||||
|
||||
hosts.each do |h|
|
||||
print "📡 Conectando a #{h[:nombre]} (#{h[:ip]})... "
|
||||
|
||||
# Intentamos obtener tareas
|
||||
cmd = "/usr/bin/pvesh get /cluster/tasks --output-format json"
|
||||
cmd_seguro = "ssh -o StrictHostKeyChecking=no root@#{h[:ip]} '#{cmd}'"
|
||||
|
||||
# Ejecutamos vía candados run
|
||||
output = `ruby #{candados_path} run admindasu SSHPASS '#{cmd_seguro}' 2>&1`
|
||||
|
||||
if output.include?('[')
|
||||
begin
|
||||
# Extraer el JSON
|
||||
json_str = output[output.index('[')..output.rindex(']')]
|
||||
tasks_host = JSON.parse(json_str)
|
||||
all_tasks_accumulated.concat(tasks_host)
|
||||
|
||||
# Filtrar tareas vzdump activas de ESTE host para mostrar
|
||||
tasks_activas = tasks_host.select { |t| t['type'] == 'vzdump' && t['endtime'].nil? }
|
||||
|
||||
puts "#{Color::GREEN}OK#{Color::RESET}"
|
||||
if tasks_activas.empty?
|
||||
puts " #{Color::DIM}Sin tareas de backup activas en este host.#{Color::RESET}"
|
||||
else
|
||||
tasks_activas.each do |t|
|
||||
msg = t['status'] || 'ejecutando'
|
||||
print " ▶ #{Color::CYAN}#{t['id']}#{Color::RESET} "
|
||||
puts "[#{msg}] (Iniciado: #{Time.at(t['starttime']).strftime('%H:%M:%S')})"
|
||||
end
|
||||
end
|
||||
rescue => e
|
||||
puts "#{Color::YELLOW}JSON ERROR#{Color::RESET}"
|
||||
puts " #{Color::DIM}Error parseando respuesta: #{e.message}#{Color::RESET}"
|
||||
end
|
||||
else
|
||||
puts "#{Color::RED}ERROR#{Color::RESET}"
|
||||
if output.include?('Permission denied')
|
||||
puts " #{Color::DIM}Error de permisos/candado puesto.#{Color::RESET}"
|
||||
else
|
||||
puts " #{Color::DIM}No se detectaron tareas activas o el host no respondió.#{Color::RESET}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
system("ruby #{candados_path} cerrar > /dev/null 2>&1")
|
||||
|
||||
# 2. Sincronización Automática: Auto-reconciliación y Migración
|
||||
fecha_hoy = Date.today.iso8601
|
||||
archivo_md = File.join(ADN::BITACORAS_DIR, "#{fecha_hoy}.md")
|
||||
|
||||
if File.exist?(archivo_md)
|
||||
print "#{Color::DIM}🔄 Reconciliando tareas pendientes... #{Color::RESET}"
|
||||
auto_reconciliar_bitacora(all_tasks_accumulated)
|
||||
puts "#{Color::DIM}OK#{Color::RESET}"
|
||||
|
||||
print "#{Color::DIM}🔄 Sincronizando bitácora digital... #{Color::RESET}"
|
||||
# Ejecutamos la migración de forma silenciosa
|
||||
cmd_migrar = "#{File.join(ADN::PROJECT_ROOT, 'tools/adn/run')} db migrar:md #{fecha_hoy} --sobrescribir > /dev/null 2>&1"
|
||||
system(cmd_migrar)
|
||||
puts "#{Color::DIM}OK#{Color::RESET}"
|
||||
end
|
||||
|
||||
# 3. Historial de la DB (Sincronizado)
|
||||
puts "\n#{Color::BOLD}📅 Historial de hoy (Sincronizado)#{Color::RESET}"
|
||||
puts "─" * 60
|
||||
|
||||
db_tool = "./tools/adn/run"
|
||||
# Buscamos por "backup" o "BKP"
|
||||
system("#{db_tool} db evento:listar --desde '#{fecha_hoy}' --buscar 'ackup'")
|
||||
|
||||
puts "\n#{Color::DIM}Para historial completo use: ./tools/adn/run db evento:listar --desde '#{fecha_hoy}'#{Color::RESET}"
|
||||
end
|
||||
|
||||
def comando_sanear
|
||||
dias = @opciones[:retencion].to_i
|
||||
storage = @opciones[:storage]
|
||||
@logger.info("Iniciando saneamiento de backups (Retención: #{dias} días en '#{storage}')")
|
||||
|
||||
# 1. Obtener lista de VMs directamente de Proxmox para nombres precisos
|
||||
host = { nombre: 'srv-pmox1', ip: '10.0.10.201' }
|
||||
candados_path = File.join(ADN::PROJECT_ROOT, 'tools', 'ns8-candados', 'ns8-candados.rb')
|
||||
system("ruby #{candados_path} authorize > /dev/null 2>&1")
|
||||
|
||||
@logger.info("Consultando inventario de VMs en Proxmox...")
|
||||
cmd_vms = "/usr/bin/pvesh get /cluster/resources --type vm --output-format json"
|
||||
output_vms = `ruby #{candados_path} run admindasu SSHPASS 'ssh -o StrictHostKeyChecking=no root@#{host[:ip]} "#{cmd_vms}"' 2>/dev/null`
|
||||
|
||||
vmid_map = cargar_mapa_vmid_nodos # Cargar local primero
|
||||
|
||||
begin
|
||||
if output_vms.include?('[')
|
||||
json_vms = output_vms[output_vms.index('[')..output_vms.rindex(']')]
|
||||
JSON.parse(json_vms).each do |vm|
|
||||
id = vm['vmid'].to_s
|
||||
# Priorizar nombre de Proxmox si el local no existe o es genérico
|
||||
vmid_map[id] = vm['name'] if vm['name'] && (!vmid_map[id] || vmid_map[id] == id)
|
||||
end
|
||||
end
|
||||
rescue => e
|
||||
@logger.advertencia("No se pudo completar el mapa de VMs desde Proxmox: #{e.message}")
|
||||
end
|
||||
|
||||
# 2. Obtener lista de archivos en el storage
|
||||
# Intentar con varios hosts del cluster por si uno está caído
|
||||
ruta_dump = "/mnt/pve/#{storage}/dump"
|
||||
@logger.info("Listando archivos en #{storage}...")
|
||||
|
||||
output_ls = ""
|
||||
[ '10.0.10.201', '10.0.10.202', '10.0.10.203' ].each do |ip|
|
||||
cmd_ls = "ls -1 --full-time #{ruta_dump}/vzdump-*"
|
||||
res = `ruby #{candados_path} run admindasu SSHPASS 'ssh -o StrictHostKeyChecking=no root@#{ip} "#{cmd_ls}"' 2>&1`
|
||||
unless res.include?('No such file') || res.include?('Connection refused')
|
||||
output_ls = res
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if output_ls.empty? || output_ls.include?('No such file')
|
||||
@logger.error("No se encontró la ruta de backups en ningún host: #{ruta_dump}")
|
||||
system("ruby #{candados_path} cerrar > /dev/null 2>&1")
|
||||
exit 1
|
||||
end
|
||||
|
||||
# 3. Filtrar archivos por antigüedad
|
||||
ahora = Time.now
|
||||
limite = ahora - (dias * 24 * 60 * 60)
|
||||
|
||||
backups_agrupados = {}
|
||||
|
||||
output_ls.split("\n").each do |linea|
|
||||
next if linea.include?('OPTIONS]') || linea.empty?
|
||||
|
||||
partes = linea.split(/\s+/)
|
||||
next if partes.length < 9
|
||||
|
||||
fecha_str = "#{partes[5]} #{partes[6]}"
|
||||
ruta_archivo = partes[8..-1].join(' ')
|
||||
nombre = File.basename(ruta_archivo)
|
||||
|
||||
fingerprint = nombre.sub(/\.(log|vma\.zst|tar\.zst|vma\.zst\.notes|tar\.zst\.notes)$/, '')
|
||||
|
||||
begin
|
||||
mtime = Time.parse(fecha_str)
|
||||
if mtime < limite
|
||||
vmid = fingerprint.match(/vzdump-(?:qemu|lxc)-(\d+)-/)&.[](1)
|
||||
nodo_humano = vmid ? vmid_map[vmid] : "ID:#{vmid}"
|
||||
|
||||
backups_agrupados[fingerprint] ||= {
|
||||
fingerprint: fingerprint,
|
||||
fecha: mtime,
|
||||
vmid: vmid,
|
||||
nodo: nodo_humano,
|
||||
archivos: []
|
||||
}
|
||||
backups_agrupados[fingerprint][:archivos] << { ruta: ruta_archivo, nombre: nombre }
|
||||
end
|
||||
rescue
|
||||
next
|
||||
end
|
||||
end
|
||||
|
||||
if backups_agrupados.empty?
|
||||
puts "#{Color::GREEN}✓ No se encontraron backups mayores a #{dias} días en #{storage}.#{Color::RESET}"
|
||||
system("ruby #{candados_path} cerrar > /dev/null 2>&1")
|
||||
return
|
||||
end
|
||||
|
||||
# Convertir a array ordenado por fecha
|
||||
lista_final = backups_agrupados.values.sort_by { |b| b[:fecha] }
|
||||
|
||||
# 4. Mostrar lista con nuevo formato solicitado
|
||||
puts "\n#{Color::BOLD}🗑️ Propuesta de Saneamiento de Backups#{Color::RESET} (Retención: #{dias} días)"
|
||||
puts "─" * 90
|
||||
puts "#{Color::BOLD}ID Nombre_VMID_Fecha Componentes detectados#{Color::RESET}"
|
||||
puts "─" * 90
|
||||
|
||||
lista_final.each_with_index do |b, idx|
|
||||
num = (idx + 1).to_s.rjust(2, '0')
|
||||
fecha_corta = b[:fecha].strftime('%Y-%m-%d')
|
||||
|
||||
# Formato solicitado: XX - VMNombre_VMid_Fecha
|
||||
entrada_label = "#{num} - #{Color::BOLD}#{Color::CYAN}#{b[:nodo]}_#{b[:vmid]}_#{fecha_corta}#{Color::RESET}".ljust(60)
|
||||
|
||||
tipos = b[:archivos].map { |a| a[:nombre].split('.').last }.uniq.join(", ")
|
||||
total_archivos = "(#{b[:archivos].length} arch.)"
|
||||
|
||||
puts "#{entrada_label} #{Color::DIM}#{tipos.ljust(15)} #{total_archivos}#{Color::RESET}"
|
||||
end
|
||||
puts "─" * 90
|
||||
puts "Total detectado: #{lista_final.length} backups completos (#{backups_agrupados.values.sum { |b| b[:archivos].length }} archivos en total)."
|
||||
|
||||
puts "\n#{Color::BOLD}Acciones:#{Color::RESET}"
|
||||
puts " • Escriba #{Color::BOLD}'S'#{Color::RESET} para borrar TODOS los backups listados."
|
||||
puts " • Escriba #{Color::BOLD}excluir 1, 3-5#{Color::RESET} para conservar backups específicos."
|
||||
puts " • Escriba #{Color::BOLD}'N'#{Color::RESET} para cancelar."
|
||||
|
||||
print "\n👉 #{Color::BOLD}¿Qué deseas hacer?#{Color::RESET}: "
|
||||
input = STDIN.gets.chomp.strip.downcase
|
||||
|
||||
if input == 'n' || input == ''
|
||||
puts "#{Color::YELLOW}Operación cancelada.#{Color::RESET}"
|
||||
system("ruby #{candados_path} cerrar > /dev/null 2>&1")
|
||||
exit
|
||||
end
|
||||
|
||||
# Procesar exclusiones
|
||||
seleccionados = lista_final.dup
|
||||
if input.start_with?('excluir')
|
||||
exclusiones = []
|
||||
patron = input.sub('excluir', '').strip
|
||||
|
||||
patron.split(/[\s,]+/).each do |p|
|
||||
next if p.empty?
|
||||
if p.include?('-')
|
||||
inicio, fin = p.split('-').map(&:to_i)
|
||||
exclusiones.concat((inicio..fin).to_a)
|
||||
else
|
||||
exclusiones << p.to_i
|
||||
end
|
||||
end
|
||||
|
||||
seleccionados = lista_final.reject.with_index { |_, idx| exclusiones.include?(idx + 1) }
|
||||
|
||||
if seleccionados.empty?
|
||||
puts "#{Color::YELLOW}Has excluido todos los backups. Nada que hacer.#{Color::RESET}"
|
||||
system("ruby #{candados_path} cerrar > /dev/null 2>&1")
|
||||
exit
|
||||
end
|
||||
|
||||
puts "#{Color::CYAN}ℹ Has excluido #{lista_final.length - seleccionados.length} backups. Procediendo con #{seleccionados.length}...#{Color::RESET}"
|
||||
elsif input != 's'
|
||||
puts "#{Color::RED}Opción no válida. Cancelando.#{Color::RESET}"
|
||||
system("ruby #{candados_path} cerrar > /dev/null 2>&1")
|
||||
exit
|
||||
end
|
||||
|
||||
# 5. Borrado final
|
||||
total_a_borrar = seleccionados.sum { |b| b[:archivos].length }
|
||||
puts "\n#{Color::BOLD}🗑️ Borrando #{total_a_borrar} archivos asociados a #{seleccionados.length} backups...#{Color::RESET}"
|
||||
|
||||
seleccionados.each_with_index do |b, i|
|
||||
puts "\n #{Color::BOLD}[#{i+1}/#{seleccionados.length}] Procesando #{b[:nodo]}...#{Color::RESET}"
|
||||
b[:archivos].each do |a|
|
||||
print " Eliminando #{a[:nombre]}... "
|
||||
del_cmd = "rm -f '#{a[:ruta]}'"
|
||||
del_seguro = "ssh -o StrictHostKeyChecking=no root@#{host[:ip]} '#{del_cmd}'"
|
||||
system("ruby #{candados_path} run admindasu SSHPASS '#{del_seguro}' > /dev/null 2>&1")
|
||||
puts "#{Color::GREEN}OK#{Color::RESET}"
|
||||
end
|
||||
end
|
||||
|
||||
@logger.exito("Saneamiento completado. Se limpiaron #{seleccionados.length} sets de backup.")
|
||||
system("ruby #{candados_path} cerrar > /dev/null 2>&1")
|
||||
end
|
||||
|
||||
def cargar_mapa_vmid_nodos
|
||||
mapa = {}
|
||||
Dir.glob(File.join(ADN::NODOS_DIR, "*.md")).each do |f|
|
||||
next if File.directory?(f)
|
||||
begin
|
||||
contenido = File.read(f)
|
||||
# Buscar nombre en h1 o metadatos
|
||||
nombre = File.basename(f, ".md")
|
||||
vmid = contenido.match(/(?:VM ID|vmid|VMID)\*\*?:?\s*`?(\d+)`?/i)&.[](1)
|
||||
mapa[vmid.to_s] = nombre if vmid
|
||||
rescue
|
||||
next
|
||||
end
|
||||
end
|
||||
mapa
|
||||
end
|
||||
|
||||
def auto_reconciliar_bitacora(all_tasks)
|
||||
fecha = Date.today.iso8601
|
||||
ruta = File.join(ADN::BITACORAS_DIR, "#{fecha}.md")
|
||||
return unless File.exist?(ruta)
|
||||
|
||||
contenido = File.read(ruta)
|
||||
vmid_map = cargar_mapa_vmid_nodos
|
||||
|
||||
# Encontrar todas las filas que tienen un reloj de arena
|
||||
lineas = contenido.lines
|
||||
nodo_actual = nil
|
||||
|
||||
lineas.each do |linea|
|
||||
if linea.start_with?('### srvv-')
|
||||
nodo_actual = linea.sub('### ', '').strip
|
||||
next
|
||||
end
|
||||
|
||||
# Si es una fila de tabla en progreso (⏳)
|
||||
if nodo_actual && linea.include?('|') && linea.include?('⏳')
|
||||
match_hora = linea.match(/\|\s*(\d{2}:\d{2})\s*\|/)
|
||||
next unless match_hora
|
||||
|
||||
hora_inicio_str = match_hora[1]
|
||||
vmid = vmid_map.key(nodo_actual)
|
||||
next unless vmid
|
||||
|
||||
# Buscar última tarea vzdump de este VMID que ya terminó
|
||||
hora_inicio_t = Time.parse("#{fecha} #{hora_inicio_str}") rescue nil
|
||||
|
||||
tarea = all_tasks.select { |t|
|
||||
vmid_task = (t['vmid'] || t['id']).to_s
|
||||
t['type'] == 'vzdump' &&
|
||||
vmid_task == vmid &&
|
||||
!t['endtime'].nil? &&
|
||||
(hora_inicio_t ? Time.at(t['starttime']) >= (hora_inicio_t - 3600) : true)
|
||||
}.max_by { |t| t['endtime'] }
|
||||
|
||||
if tarea
|
||||
exito = (tarea['status'] == 'OK')
|
||||
hora_fin = Time.at(tarea['endtime']).strftime('%H:%M')
|
||||
|
||||
@logger.info("Auto-cerrando backup de #{nodo_actual} (Task ID: #{tarea['id']})")
|
||||
cerrar_entrada_especifica(nodo_actual, hora_inicio_str, exito, tarea['id'], hora_fin)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def cerrar_entrada_especifica(nodo, hora_ini, exito, task_id, hora_fin)
|
||||
fecha = Date.today.iso8601
|
||||
ruta = File.join(ADN::BITACORAS_DIR, "#{fecha}.md")
|
||||
return unless File.exist?(ruta)
|
||||
|
||||
estado_ico = exito ? '✅' : '⚠️'
|
||||
desc = exito ? 'Backup completado exitosamente.' : 'Fallo en la ejecución del backup.'
|
||||
desc = "[task:#{task_id[0..7]}] #{desc}" if task_id
|
||||
|
||||
linea_nueva = "| #{hora_ini} | #{hora_fin} | #{desc} | R | #{estado_ico} |"
|
||||
|
||||
contenido = File.read(ruta)
|
||||
# Buscamos la fila específica que coincida con el nodo Y la hora de inicio
|
||||
# Capturamos el bloque del nodo para evitar errores si otros nodos tienen la misma hora
|
||||
regex_seccion = /(### #{Regexp.escape(nodo)}.*?)(?=^###\s|<!--|\z)/m
|
||||
seccion = contenido.match(regex_seccion)&.[](0)
|
||||
unless seccion
|
||||
return
|
||||
end
|
||||
|
||||
# Regex para la fila exacta que tenga la hora de inicio Y un reloj ⏳ en la última columna
|
||||
regex_fila = /\|\s*#{Regexp.escape(hora_ini)}\s*\|\s*\|\s*[^|]*\|\s*[^|]*\|\s*[^|]*⏳[^|]*\|/
|
||||
|
||||
if seccion.match?(regex_fila)
|
||||
@logger.exito("Reconciliado: #{nodo} (#{hora_ini} -> #{hora_fin})")
|
||||
nueva_seccion = seccion.sub(regex_fila, linea_nueva)
|
||||
# Si ya no quedan ⏳ en esta sección, actualizamos su icono #### ⏳ -> ✅
|
||||
# Buscamos cualquier reloj de arena que quede en la sección
|
||||
unless nueva_seccion.include?('⏳')
|
||||
nueva_seccion.gsub!(/#### [⏳⏳] - BKP-ADN/, "#### #{estado_ico} - BKP-ADN")
|
||||
end
|
||||
|
||||
nuevo_contenido = contenido.gsub(seccion, nueva_seccion)
|
||||
File.write(ruta, nuevo_contenido)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -86,6 +86,8 @@ module ADN
|
||||
comando_estadisticas
|
||||
when 'backup'
|
||||
comando_backup(sub_args)
|
||||
when 'archivar:md'
|
||||
comando_archivar_md
|
||||
|
||||
else
|
||||
@logger.error("Subcomando desconocido: #{subcomando}")
|
||||
@@ -1007,6 +1009,60 @@ module ADN
|
||||
|
||||
|
||||
|
||||
# Comando: archivar:md - Mover bitácoras y proyectos MD importados/obsoletos a carpetas _hist
|
||||
def comando_archivar_md
|
||||
require 'fileutils'
|
||||
puts "#{Color::CYAN}🧹 Iniciando limpieza y archivado de archivos Markdown...#{Color::RESET}"
|
||||
|
||||
BitacorasDB::BitacoraDB.with_connection do |db|
|
||||
bitacoras_dir = defined?(ADN::BITACORAS_DIR) ? ADN::BITACORAS_DIR : File.expand_path('../../../docs/bitacoras', __dir__)
|
||||
proyectos_dir = File.expand_path('../../../docs/proyectos', __dir__)
|
||||
|
||||
hist_bitacoras = File.join(bitacoras_dir, '_hist')
|
||||
hist_proyectos = File.join(proyectos_dir, '_hist')
|
||||
|
||||
FileUtils.mkdir_p(hist_bitacoras)
|
||||
FileUtils.mkdir_p(hist_proyectos)
|
||||
|
||||
# 1. Archivar Bitácoras Diarias
|
||||
puts "\\n#{Color::BOLD}>> Verificando Bitácoras Diarias...#{Color::RESET}"
|
||||
bitacoras_db = db.send(:execute, "SELECT fecha FROM bitacoras.bitacoras").map { |row| row['fecha'] }
|
||||
|
||||
Dir.glob(File.join(bitacoras_dir, '*.md')).each do |md_path|
|
||||
next if File.basename(md_path) == 'README.md'
|
||||
fecha_md = File.basename(md_path, '.md')
|
||||
|
||||
if bitacoras_db.include?(fecha_md)
|
||||
dest = File.join(hist_bitacoras, File.basename(md_path))
|
||||
FileUtils.mv(md_path, dest)
|
||||
puts " #{Color::GREEN}✓ Archivada:#{Color::RESET} #{fecha_md}.md"
|
||||
else
|
||||
puts " #{Color::YELLOW}⚠ No en DB (se omite):#{Color::RESET} #{fecha_md}.md"
|
||||
end
|
||||
end
|
||||
|
||||
# 2. Archivar Proyectos
|
||||
puts "\\n#{Color::BOLD}>> Verificando Proyectos MD...#{Color::RESET}"
|
||||
proyectos_db = db.send(:execute, "SELECT codigo FROM bitacoras.proyectos").map { |row| row['codigo'] }
|
||||
|
||||
Dir.glob(File.join(proyectos_dir, '*.md')).each do |md_path|
|
||||
next if File.basename(md_path) == 'README.md'
|
||||
# Extraer el código PXXXX del principio del archivo, asumiendo formato PXXXX_Titulo.md o PXXXX.md
|
||||
codigo_match = File.basename(md_path).match(/^(P\d+)/)
|
||||
|
||||
if codigo_match && proyectos_db.include?(codigo_match[1])
|
||||
dest = File.join(hist_proyectos, File.basename(md_path))
|
||||
FileUtils.mv(md_path, dest)
|
||||
puts " #{Color::GREEN}✓ Archivado Proyecto:#{Color::RESET} #{File.basename(md_path)}"
|
||||
else
|
||||
puts " #{Color::YELLOW}⚠ Proyecto no registrado en DB o formato no válido:#{Color::RESET} #{File.basename(md_path)}"
|
||||
end
|
||||
end
|
||||
|
||||
puts "\\n#{Color::GREEN}✅ Limpieza Markdown finalizada. Entorno 100% DB-First fortalecido.#{Color::RESET}"
|
||||
end
|
||||
end
|
||||
|
||||
# ─── MÉTODOS AUXILIARES ──────────────────────────────────────────────
|
||||
|
||||
# Carga la configuración desde config.yml
|
||||
@@ -1037,6 +1093,7 @@ module ADN
|
||||
puts " #{Color::CYAN}nodo:crear [OPCIONES]#{Color::RESET} Crear nuevo nodo (servidor/VM/PC)"
|
||||
puts " #{Color::CYAN}nodo:listar [OPCIONES]#{Color::RESET} Listar nodos del sistema"
|
||||
puts " #{Color::CYAN}estadisticas#{Color::RESET} Mostrar estadísticas del sistema"
|
||||
puts " #{Color::CYAN}archivar:md#{Color::RESET} Mueve los archivos .md migrados al archivo histórico"
|
||||
puts ""
|
||||
puts "#{Color::BOLD}Ejemplos:#{Color::RESET}"
|
||||
puts " ./tools/adn/run db salud:bd"
|
||||
|
||||
@@ -63,6 +63,8 @@ backup:
|
||||
comprimir: true
|
||||
defaults:
|
||||
modo: stop
|
||||
storage: zfsDISCO1
|
||||
retencion_dias: '6'
|
||||
evolucion:
|
||||
propuestas_directorio: "../../docs/plan"
|
||||
periodo_revision_horas: 48
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'date'
|
||||
require 'time'
|
||||
require 'json'
|
||||
require_relative 'configurador'
|
||||
|
||||
module ADN
|
||||
class Conciliador
|
||||
def initialize(logger)
|
||||
@logger = logger
|
||||
@candados_path = File.join(ADN::PROJECT_ROOT, 'tools', 'ns8-candados', 'ns8-candados.rb')
|
||||
end
|
||||
|
||||
def ejecutar(silencioso: false)
|
||||
@silencioso = silencioso
|
||||
@logger.info("Iniciando saneamiento preventivo de pendientes...") unless @silencioso
|
||||
|
||||
# 1. Reconciliar backups de ayer y hoy
|
||||
conciliar_backups_recientes
|
||||
|
||||
# 2. Traspasar pendientes no resueltos de ayer a hoy
|
||||
traspasar_pendientes_ayer_a_hoy
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def conciliar_backups_recientes
|
||||
# Revisamos ayer y hoy
|
||||
[Date.today - 1, Date.today].each do |fecha_obj|
|
||||
fecha = fecha_obj.iso8601
|
||||
ruta = File.join(ADN::BITACORAS_DIR, "#{fecha}.md")
|
||||
next unless File.exist?(ruta)
|
||||
|
||||
# Si el archivo tiene relojes de arena (⏳)
|
||||
contenido = File.read(ruta)
|
||||
if contenido.include?('⏳')
|
||||
@logger.info(" Revisando tareas pendientes del #{fecha}...") unless @silencioso
|
||||
procesar_reconciliacion(fecha, ruta)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def procesar_reconciliacion(fecha, ruta)
|
||||
# Obtener tareas de Proxmox
|
||||
tasks = obtener_tareas_proxmox
|
||||
return if tasks.empty?
|
||||
|
||||
vmid_map = cargar_mapa_vmid_nodos
|
||||
contenido = File.read(ruta)
|
||||
lineas = contenido.lines
|
||||
nodo_actual = nil
|
||||
cambio = false
|
||||
|
||||
lineas.each do |linea|
|
||||
if linea.start_with?('### ') && !linea.include?('|')
|
||||
nodo_actual = linea.sub('### ', '').strip
|
||||
next
|
||||
end
|
||||
|
||||
if nodo_actual && linea.include?('|') && linea.include?('⏳')
|
||||
match_hora = linea.match(/\|\s*(\d{2}:\d{2})\s*\|/)
|
||||
next unless match_hora
|
||||
|
||||
hora_inicio_str = match_hora[1]
|
||||
vmid = vmid_map.key(nodo_actual)
|
||||
next unless vmid
|
||||
|
||||
# Buscar tarea coincidente
|
||||
hora_inicio_t = Time.parse("#{fecha} #{hora_inicio_str}") rescue nil
|
||||
tarea = tasks.select { |t|
|
||||
vmid_task = (t['vmid'] || t['id']).to_s
|
||||
t['type'] == 'vzdump' &&
|
||||
vmid_task == vmid &&
|
||||
(t['status'] == 'OK' || !t['endtime'].nil?) &&
|
||||
(hora_inicio_t ? Time.at(t['starttime']) >= (hora_inicio_t - 3600) : true)
|
||||
}.max_by { |t| t['endtime'] || 0 }
|
||||
|
||||
if tarea && tarea['endtime']
|
||||
exito = (tarea['status'] == 'OK')
|
||||
hora_fin = Time.at(tarea['endtime']).strftime('%H:%M')
|
||||
task_id = tarea['id']
|
||||
|
||||
@logger.exito(" ✨ Tarea auto-resuelta: #{nodo_actual} (#{hora_inicio_str} -> #{hora_fin})") unless @silencioso
|
||||
|
||||
# Aplicar cambio en el contenido
|
||||
estado_ico = exito ? '✅' : '⚠️'
|
||||
desc = exito ? 'Backup completado exitosamente.' : 'Fallo en la ejecución del backup.'
|
||||
desc = "[task:#{task_id[0..7]}] #{desc}"
|
||||
|
||||
linea_nueva = "| #{hora_inicio_str} | #{hora_fin} | #{desc} | R | #{estado_ico} |\n"
|
||||
|
||||
# Reemplazo cuidadoso
|
||||
regex_fila = /^\|\s*#{Regexp.escape(hora_inicio_str)}\s*\|\s*\|\s*[^|]*\|\s*[^|]*\|\s*[^|]*⏳[^|]*\|/
|
||||
|
||||
# Buscar el bloque del nodo
|
||||
regex_seccion = /(### #{Regexp.escape(nodo_actual)}.*?)(?=\n###\s|<!--|\z)/m
|
||||
contenido.sub!(regex_seccion) do |seccion|
|
||||
nueva_seccion = seccion.sub(regex_fila, linea_nueva)
|
||||
# Si ya no quedan ⏳ en esta sección, actualizamos su icono principal
|
||||
unless nueva_seccion.include?('⏳')
|
||||
nueva_seccion.gsub!(/#### [⏳⏳] - BKP-ADN/, "#### #{estado_ico} - BKP-ADN")
|
||||
end
|
||||
nueva_seccion
|
||||
end
|
||||
cambio = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if cambio
|
||||
File.write(ruta, contenido)
|
||||
# Sincronizar con DB
|
||||
system("#{File.join(ADN::PROJECT_ROOT, 'tools/adn/run')} db migrar:md #{fecha} --sobrescribir > /dev/null 2>&1")
|
||||
end
|
||||
end
|
||||
|
||||
def traspasar_pendientes_ayer_a_hoy
|
||||
ayer = (Date.today - 1).iso8601
|
||||
hoy = Date.today.iso8601
|
||||
ruta_ayer = File.join(ADN::BITACORAS_DIR, "#{ayer}.md")
|
||||
ruta_hoy = File.join(ADN::BITACORAS_DIR, "#{hoy}.md")
|
||||
|
||||
return unless File.exist?(ruta_ayer) && File.exist?(ruta_hoy)
|
||||
|
||||
cont_ayer = File.read(ruta_ayer)
|
||||
cont_hoy = File.read(ruta_hoy)
|
||||
|
||||
# 1. Extraer sección Pendientes de ayer
|
||||
pendientes_ayer = extraer_tabla_seccion(cont_ayer, '### Pendientes')
|
||||
return if pendientes_ayer.empty?
|
||||
|
||||
# 2. Filtrar los que ya están en hoy (evitar duplicados)
|
||||
nuevos_pendientes = pendientes_ayer.reject do |p|
|
||||
cont_hoy.include?(p[:detalle])
|
||||
end
|
||||
|
||||
return if nuevos_pendientes.empty?
|
||||
|
||||
# 3. Insertar en hoy
|
||||
filas_nuevas = nuevos_pendientes.map { |p| "| #{p[:id]} | #{p[:nodo]} | #{p[:detalle]} |" }.join("\n")
|
||||
|
||||
# Regex más flexible para encontrar la tabla de pendientes en hoy
|
||||
regex_tabla = /(### Pendientes\s*\n\s*\| ID \| Nodo \| Detalle \|\s*\n\s*\| :--- \| :--- \| :--- \|)/
|
||||
|
||||
if cont_hoy.match?(regex_tabla)
|
||||
@logger.exito(" 🚀 Traspasando #{nuevos_pendientes.length} pendientes de ayer a hoy...")
|
||||
cont_hoy.sub!(regex_tabla) { "#{$1}\n#{filas_nuevas}" }
|
||||
File.write(ruta_hoy, cont_hoy)
|
||||
system("#{File.join(ADN::PROJECT_ROOT, 'tools/adn/run')} db migrar:md #{hoy} --sobrescribir > /dev/null 2>&1")
|
||||
end
|
||||
end
|
||||
|
||||
def extraer_tabla_seccion(contenido, encabezado)
|
||||
# Busca el bloque que empieza con el encabezado y captura todas las líneas que empiezan con |
|
||||
regex = /#{Regexp.escape(encabezado)}[^\n]*\n+((?:\|[^\n]*\n?)+)/m
|
||||
match = contenido.match(regex)
|
||||
return [] unless match
|
||||
|
||||
filas = match[1].strip.split("\n")
|
||||
return [] if filas.length < 3 # Necesitamos al menos Cabecera, Separador y 1 Fila
|
||||
|
||||
# Saltamos las primeras dos líneas (Cabecera y Separador)
|
||||
filas[2..-1].map do |f|
|
||||
parts = f.split('|').map(&:strip).reject(&:empty?)
|
||||
next if parts.length < 3
|
||||
{ id: parts[0], nodo: parts[1], detalle: parts[2] }
|
||||
end.compact
|
||||
end
|
||||
|
||||
def obtener_tareas_proxmox
|
||||
return @tasks if @tasks
|
||||
|
||||
system("ruby #{@candados_path} authorize > /dev/null 2>&1")
|
||||
@tasks = []
|
||||
|
||||
[ '10.0.10.201', '10.0.10.202', '10.0.10.203' ].each do |ip|
|
||||
cmd = "pvesh get /cluster/tasks --output-format json"
|
||||
output = `ruby #{@candados_path} run admindasu SSHPASS 'ssh -o StrictHostKeyChecking=no root@#{ip} "#{cmd}"' 2>/dev/null`
|
||||
|
||||
if output.include?('[')
|
||||
begin
|
||||
json_str = output[output.index('[')..output.rindex(']')]
|
||||
@tasks = JSON.parse(json_str)
|
||||
break
|
||||
rescue
|
||||
next
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
system("ruby #{@candados_path} cerrar > /dev/null 2>&1")
|
||||
@tasks
|
||||
end
|
||||
|
||||
def cargar_mapa_vmid_nodos
|
||||
mapa = {}
|
||||
Dir.glob(File.join(ADN::NODOS_DIR, "*.md")).each do |f|
|
||||
nombre = File.basename(f, ".md")
|
||||
cont = File.read(f)
|
||||
vmid = cont.match(/(?:VM ID|vmid|VMID)\*\*?:?\s*`?(\d+)`?/i)&.[](1)
|
||||
mapa[vmid.to_s] = nombre if vmid
|
||||
end
|
||||
mapa
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -116,8 +116,8 @@ ejecutar_validacion() {
|
||||
local output
|
||||
if output=$("${ADN_CLI}" validador --fix 2>&1); then
|
||||
# El validador exitó con éxito
|
||||
if echo "$output" | grep -q "Con errores: 0"; then
|
||||
if echo "$output" | grep -q "Con advertencias: 0"; then
|
||||
if echo "$output" | grep -qE "Con errores:.*0"; then
|
||||
if echo "$output" | grep -qE "Con advertencias:.*0"; then
|
||||
log_exito "Validación del ADN completada sin errores ni advertencias."
|
||||
else
|
||||
log_advertencia "Validación del ADN completada con advertencias (revisa arriba)."
|
||||
|
||||
+37
-1
@@ -53,6 +53,9 @@ require_relative 'comando/backup'
|
||||
require_relative 'comando/sync'
|
||||
require_relative 'comando/triggers'
|
||||
require_relative 'comando/conocimiento'
|
||||
require_relative 'comando/cierre'
|
||||
require_relative 'comando/inicio'
|
||||
require_relative 'core/conciliador'
|
||||
|
||||
# ─── Colores para terminal ───────────────────────────────────────────────
|
||||
module Color
|
||||
@@ -707,6 +710,8 @@ class SubcomandoAyuda
|
||||
#{Color::YELLOW}generar proyecto <código>#{Color::RESET} Generar manifiesto de proyecto
|
||||
#{Color::YELLOW}backup <nodo> [--mode MODO]#{Color::RESET} Ejecutar backup seguro de un nodo
|
||||
#{Color::YELLOW}sync [ruta|fecha]#{Color::RESET} Sincronizar con API dtic-BITACORAs
|
||||
#{Color::YELLOW}inicio de jornada [presencial|remoto]#{Color::RESET} Inicio de jornada laboral
|
||||
#{Color::YELLOW}cierre de jornada [presencial|remoto]#{Color::RESET} Cierre de jornada laboral
|
||||
#{Color::YELLOW}triggers [opciones]#{Color::RESET} Gestión del motor de triggers
|
||||
#{Color::YELLOW}ayuda [subcomando]#{Color::RESET} Mostrar esta ayuda o ayuda específica
|
||||
|
||||
@@ -794,6 +799,10 @@ class ADNCLI
|
||||
end
|
||||
|
||||
subcomando = ARGV[0]
|
||||
|
||||
# Saneamiento preventivo de pendientes (con cooldown de 5 minutos para performance)
|
||||
ejecutar_saneamiento_preventivo(subcomando)
|
||||
|
||||
args = ARGV[1..-1] || []
|
||||
|
||||
case subcomando
|
||||
@@ -809,12 +818,16 @@ class ADNCLI
|
||||
ADN::SubcomandoConocimiento.new(args, @logger).ejecutar
|
||||
when 'db'
|
||||
ADN::SubcomandoDB.new(args, @logger).ejecutar
|
||||
when 'backup'
|
||||
when 'backup', 'backups'
|
||||
ADN::SubcomandoBackup.new(args, @logger).ejecutar
|
||||
when 'sync'
|
||||
ADN::SubcomandoSync.new(args, @logger).ejecutar
|
||||
when 'triggers'
|
||||
ADN::SubcomandoTriggers.new(args, @logger).ejecutar
|
||||
when 'cierre'
|
||||
ADN::SubcomandoCierre.new(args, @logger).ejecutar
|
||||
when 'inicio'
|
||||
ADN::SubcomandoInicio.new(args, @logger).ejecutar
|
||||
when 'ayuda', 'help', '-h', '--help'
|
||||
SubcomandoAyuda.new(args, @logger).ejecutar
|
||||
when 'evolucion'
|
||||
@@ -842,6 +855,29 @@ class ADNCLI
|
||||
puts "#{Color::DIM}#{e.backtrace.first}#{Color::RESET}" if ENV['ADN_DEBUG']
|
||||
exit 1
|
||||
end
|
||||
private
|
||||
|
||||
def ejecutar_saneamiento_preventivo(subcomando)
|
||||
# No sanear si es ayuda o db (para evitar bucles o lentitud en info rápida)
|
||||
return if ['ayuda', 'help', 'db', 'salud', '-h', '--help'].include?(subcomando)
|
||||
|
||||
archivo_cooldown = "/tmp/adn_sanity_cooldown"
|
||||
cooldown_segundo = 300 # 5 minutos
|
||||
|
||||
if File.exist?(archivo_cooldown)
|
||||
last_run = File.mtime(archivo_cooldown)
|
||||
return if (Time.now - last_run) < cooldown_segundo
|
||||
end
|
||||
|
||||
# Ejecutar conciliación
|
||||
begin
|
||||
# Tocamos el archivo primero para evitar que otras instancias concurrentes lo lancen
|
||||
FileUtils.touch(archivo_cooldown)
|
||||
ADN::Conciliador.new(@logger).ejecutar(silencioso: true)
|
||||
rescue => e
|
||||
@logger.advertencia("No se pudo completar el saneamiento preventivo: #{e.message}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# ─── Punto de entrada ───────────────────────────────────────────────────
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# tools/bitacoras-db/cli/exportar_todo.rb
|
||||
# ==========================================
|
||||
# Exporta TODAS las bitácoras de la DB a archivos .md
|
||||
# Uso: ruby tools/bitacoras-db/cli/exportar_todo.rb [--dir DIRECTORIO]
|
||||
# — o vía enjambre —
|
||||
# ./tools/adn/run db exportar:md --todo
|
||||
|
||||
require 'date'
|
||||
require 'optparse'
|
||||
require_relative '../core/bitacora_db'
|
||||
require_relative '../exporters/md_exporter'
|
||||
|
||||
module BitacorasDB
|
||||
module CLI
|
||||
class ExportarTodo
|
||||
def initialize(bitacoras_dir, logger = nil)
|
||||
@bitacoras_dir = bitacoras_dir
|
||||
@logger = logger || default_logger
|
||||
@resultados = { ok: 0, error: 0 }
|
||||
end
|
||||
|
||||
def ejecutar
|
||||
@logger.info("Exportando todas las bitácoras de DB a MD...")
|
||||
|
||||
BitacorasDB::BitacoraDB.with_connection do |db|
|
||||
bitacoras = db.list_bitacoras(limit: 500)
|
||||
|
||||
if bitacoras.empty?
|
||||
@logger.info("No hay bitácoras en la base de datos.")
|
||||
return
|
||||
end
|
||||
|
||||
exporter = BitacorasDB::Exporters::MDExporter.new(db, @logger)
|
||||
|
||||
bitacoras.each do |b|
|
||||
fecha = b['fecha'].to_s
|
||||
fecha = fecha.split('T').first if fecha.include?('T')
|
||||
archivo = File.join(@bitacoras_dir, "#{fecha}.md")
|
||||
|
||||
if exporter.exportar_bitacora(fecha, archivo)
|
||||
@resultados[:ok] += 1
|
||||
else
|
||||
@resultados[:error] += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@logger.info("📊 Exportación masiva completada:")
|
||||
@logger.info(" ✅ Exitosas: #{@resultados[:ok]}")
|
||||
@logger.info(" ❌ Errores: #{@resultados[:error]}") if @resultados[:error] > 0
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def default_logger
|
||||
Class.new do
|
||||
def info(msg); puts "[INFO] #{msg}"; end
|
||||
def error(msg); puts "[ERROR] #{msg}"; end
|
||||
def exito(msg); puts "[OK] #{msg}"; end
|
||||
end.new
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Ejecución directa
|
||||
if __FILE__ == $0
|
||||
bitacoras_dir = File.expand_path('../../../docs/bitacoras', __dir__)
|
||||
BitacorasDB::CLI::ExportarTodo.new(bitacoras_dir).ejecutar
|
||||
end
|
||||
@@ -0,0 +1,121 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# tools/bitacoras-db/cli/verificar_migracion.rb
|
||||
# ================================================
|
||||
# Verifica que todas las bitácoras MD existentes estén correctamente
|
||||
# migradas en la base de datos. Reporta faltantes y discrepancias.
|
||||
#
|
||||
# Uso:
|
||||
# ruby tools/bitacoras-db/cli/verificar_migracion.rb
|
||||
# — o vía enjambre —
|
||||
# ./tools/adn/run db verificar
|
||||
|
||||
require 'date'
|
||||
require_relative '../core/bitacora_db'
|
||||
|
||||
module BitacorasDB
|
||||
module CLI
|
||||
class VerificarMigracion
|
||||
COLORES = {
|
||||
reset: "\e[0m", bold: "\e[1m", red: "\e[31m",
|
||||
green: "\e[32m", yellow: "\e[33m", cyan: "\e[36m", dim: "\e[2m"
|
||||
}.freeze
|
||||
|
||||
def initialize(bitacoras_dir)
|
||||
@bitacoras_dir = bitacoras_dir
|
||||
@resultados = { ok: [], sin_entradas: [], no_migrada: [], sin_md: [] }
|
||||
end
|
||||
|
||||
def ejecutar
|
||||
puts "#{COLORES[:cyan]}🔍 Verificación de migración MD ↔ DB#{COLORES[:reset]}\n\n"
|
||||
|
||||
archivos_md = Dir.glob(File.join(@bitacoras_dir, '*.md')).sort
|
||||
puts "#{COLORES[:dim]}Archivos MD encontrados: #{archivos_md.size}#{COLORES[:reset]}"
|
||||
|
||||
BitacorasDB::BitacoraDB.with_connection do |db|
|
||||
# 1. Validar cada MD contra la DB
|
||||
archivos_md.each do |archivo|
|
||||
fecha = File.basename(archivo, '.md')
|
||||
bitacora = db.find_bitacora_by_fecha(fecha)
|
||||
|
||||
unless bitacora
|
||||
@resultados[:no_migrada] << fecha
|
||||
next
|
||||
end
|
||||
|
||||
entradas = db.execute(
|
||||
"SELECT COUNT(*) as total FROM bitacoras.entradas WHERE bitacora_id = $1",
|
||||
[bitacora['id']]
|
||||
)
|
||||
total = entradas.first['total'].to_i
|
||||
|
||||
if total > 0
|
||||
@resultados[:ok] << { fecha: fecha, entradas: total }
|
||||
else
|
||||
@resultados[:sin_entradas] << fecha
|
||||
end
|
||||
end
|
||||
|
||||
# 2. Bitácoras en DB que no tienen MD
|
||||
todas_db = db.list_bitacoras(limit: 500)
|
||||
fechas_md = archivos_md.map { |a| File.basename(a, '.md') }
|
||||
todas_db.each do |b|
|
||||
f = b['fecha'].to_s
|
||||
f = f.split('T').first if f.include?('T') # por si viene con timestamp
|
||||
@resultados[:sin_md] << f unless fechas_md.include?(f)
|
||||
end
|
||||
end
|
||||
|
||||
mostrar_resultados
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def mostrar_resultados
|
||||
puts "\n#{COLORES[:bold]}📊 Resultado de verificación:#{COLORES[:reset]}\n"
|
||||
|
||||
# OK
|
||||
puts "#{COLORES[:green]}✅ Migradas correctamente: #{@resultados[:ok].size}#{COLORES[:reset]}"
|
||||
@resultados[:ok].each do |r|
|
||||
puts " #{COLORES[:dim]}#{r[:fecha]} (#{r[:entradas]} entradas)#{COLORES[:reset]}"
|
||||
end
|
||||
|
||||
# Sin entradas
|
||||
if @resultados[:sin_entradas].any?
|
||||
puts "\n#{COLORES[:yellow]}⚠ En DB pero sin entradas: #{@resultados[:sin_entradas].size}#{COLORES[:reset]}"
|
||||
@resultados[:sin_entradas].each { |f| puts " #{f}" }
|
||||
end
|
||||
|
||||
# No migradas
|
||||
if @resultados[:no_migrada].any?
|
||||
puts "\n#{COLORES[:red]}❌ No migradas (MD existe, DB no): #{@resultados[:no_migrada].size}#{COLORES[:reset]}"
|
||||
@resultados[:no_migrada].each { |f| puts " #{f}" }
|
||||
puts " #{COLORES[:dim]}Ejecuta: ./tools/adn/run db migrar:md FECHA#{COLORES[:reset]}"
|
||||
end
|
||||
|
||||
# Sin MD
|
||||
if @resultados[:sin_md].any?
|
||||
puts "\n#{COLORES[:cyan]}ℹ En DB sin archivo MD: #{@resultados[:sin_md].size}#{COLORES[:reset]}"
|
||||
@resultados[:sin_md].each { |f| puts " #{f}" }
|
||||
puts " #{COLORES[:dim]}Ejecuta: ./tools/adn/run db exportar:md FECHA#{COLORES[:reset]}"
|
||||
end
|
||||
|
||||
total = @resultados[:ok].size + @resultados[:sin_entradas].size
|
||||
total_md = @resultados[:ok].size + @resultados[:sin_entradas].size + @resultados[:no_migrada].size
|
||||
pct = total_md > 0 ? ((@resultados[:ok].size.to_f / total_md) * 100).round(1) : 0
|
||||
|
||||
puts "\n#{COLORES[:bold]}📈 Cobertura: #{pct}% (#{@resultados[:ok].size}/#{total_md})#{COLORES[:reset]}"
|
||||
|
||||
if @resultados[:no_migrada].empty? && @resultados[:sin_entradas].empty?
|
||||
puts "#{COLORES[:green]}#{COLORES[:bold]}🎉 ¡Migración completa! Todas las bitácoras están en la DB.#{COLORES[:reset]}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Ejecución directa
|
||||
if __FILE__ == $0
|
||||
bitacoras_dir = File.expand_path('../../../docs/bitacoras', __dir__)
|
||||
BitacorasDB::CLI::VerificarMigracion.new(bitacoras_dir).ejecutar
|
||||
end
|
||||
@@ -0,0 +1,130 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'date'
|
||||
|
||||
module BitacorasDB
|
||||
module Exporters
|
||||
class MDExporter
|
||||
def initialize(db, logger = nil)
|
||||
@db = db
|
||||
@logger = logger || default_logger
|
||||
end
|
||||
|
||||
def exportar_bitacora(fecha, ruta_destino)
|
||||
@logger.info("Exportando bitácora #{fecha} a #{ruta_destino}...")
|
||||
|
||||
bitacora = @db.find_bitacora_by_fecha(fecha)
|
||||
unless bitacora
|
||||
@logger.error("No se encontró la bitácora para la fecha: #{fecha}")
|
||||
return false
|
||||
end
|
||||
|
||||
bitacora_id = bitacora['id']
|
||||
|
||||
# Obtener datos estructurados (incluyendo lo nuevo)
|
||||
entradas = @db.execute("
|
||||
SELECT e.*, n.nombre as nodo_nombre
|
||||
FROM bitacoras.entradas e
|
||||
LEFT JOIN bitacoras.nodos n ON e.nodo_id = n.id
|
||||
WHERE e.bitacora_id = $1
|
||||
ORDER BY n.nombre, e.inicio ASC
|
||||
", [bitacora_id])
|
||||
|
||||
gestion = @db.execute("
|
||||
SELECT g.*, n.nombre as nodo_nombre
|
||||
FROM bitacoras.gestion g
|
||||
LEFT JOIN bitacoras.nodos n ON g.nodo_id = n.id
|
||||
WHERE g.bitacora_id = $1 OR g.activo = true
|
||||
ORDER BY g.tipo, g.orden
|
||||
", [bitacora_id]) rescue [] # Por si la tabla no existe aún en otros entornos
|
||||
|
||||
resumenes = @db.execute("
|
||||
SELECT r.*, n.nombre as nodo_nombre
|
||||
FROM bitacoras.resumen_nodos r
|
||||
JOIN bitacoras.nodos n ON r.nodo_id = n.id
|
||||
WHERE r.bitacora_id = $1
|
||||
", [bitacora_id]) rescue []
|
||||
|
||||
# Generar contenido Markdown
|
||||
contenido = generar_markdown(fecha, bitacora['resumen'], gestion, resumenes, entradas)
|
||||
|
||||
File.write(ruta_destino, contenido)
|
||||
@logger.info("✅ Exportación completada con éxito.")
|
||||
true
|
||||
rescue => e
|
||||
@logger.error("Error exportando bitácora: #{e.message}")
|
||||
false
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def generar_markdown(fecha, resumen_gen, gestion, resumenes, entradas)
|
||||
y, m, d = fecha.to_s.split('-')
|
||||
md = String.new("<!-- GENERADO AUTOMÁTICAMENTE por adn db exportar:md — No editar manualmente -->\n")
|
||||
md << "# Bitácora de Operaciones - #{d}/#{m}/#{y}\n\n"
|
||||
|
||||
if gestion && gestion.ntuples > 0
|
||||
md << "## 📋 Control de Gestión\n\n"
|
||||
|
||||
pendientes = gestion.select { |g| g['tipo'] == 'pendiente' }
|
||||
if pendientes.any?
|
||||
md << "### 📝 Resumen de Actividades\n" # Formato ADN
|
||||
md << "| NODO | PENDIENTES |\n| :--- | :--- |\n"
|
||||
pendientes.each do |p|
|
||||
md << "| #{p['nodo_nombre'] || '—'} | #{p['detalle']} |\n"
|
||||
end
|
||||
md << "\n"
|
||||
end
|
||||
|
||||
en_proceso = gestion.select { |g| g['tipo'] == 'proceso' }
|
||||
if en_proceso.any?
|
||||
md << "### ⏳ En Proceso\n"
|
||||
md << "| NODO | ACTIVIDAD |\n| :--- | :--- |\n"
|
||||
en_proceso.each do |p|
|
||||
md << "| #{p['nodo_nombre'] || '—'} | #{p['detalle']} |\n"
|
||||
end
|
||||
md << "\n"
|
||||
end
|
||||
end
|
||||
|
||||
if resumenes && resumenes.ntuples > 0
|
||||
md << "### 📝 Resumen Integral\n"
|
||||
md << "| NODO | RESUMEN INTEGRAL |\n| :--- | :--- |\n"
|
||||
resumenes.each do |r|
|
||||
md << "| #{r['nodo_nombre']} | #{r['resumen']} |\n"
|
||||
end
|
||||
md << "\n"
|
||||
end
|
||||
|
||||
md << "## 📂 Actividades Detalladas\n\n"
|
||||
|
||||
por_nodo = entradas.group_by { |e| e['nodo_nombre'] || 'sin-nodo' }
|
||||
por_nodo.each do |nodo, entries|
|
||||
md << "### #{nodo}\n\n"
|
||||
md << "| I | F | Descripción | E |\n"
|
||||
md << "| :--- | :--- | :--- | :--- |\n"
|
||||
entries.each do |e|
|
||||
inicio = e['inicio'] ? e['inicio'][0..4] : '-'
|
||||
fin = e['fin'] ? e['fin'][0..4] : '-'
|
||||
ia = e['es_ia'] == 't' ? '(IA) ' : ''
|
||||
estado = "[#{e['modo']}] #{e['estado']}"
|
||||
md << "| #{inicio} | #{fin} | #{ia}#{e['descripcion']} | #{estado} |\n"
|
||||
end
|
||||
md << "\n"
|
||||
end
|
||||
|
||||
md << "---\n"
|
||||
md << "<!-- GENERADO AUTOMÁTICAMENTE desde PostgreSQL el #{Time.now.strftime('%Y-%m-%d %H:%M')} -->\n"
|
||||
md << "<!-- Fuente de verdad: DB. Regenerar con: adn db exportar:md #{fecha} -->\n"
|
||||
md
|
||||
end
|
||||
|
||||
def default_logger
|
||||
Class.new do
|
||||
def info(msg); puts "[INFO] #{msg}"; end
|
||||
def error(msg); puts "[ERROR] #{msg}"; end
|
||||
end.new
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -31,6 +31,7 @@
|
||||
require 'date'
|
||||
require 'time'
|
||||
require 'yaml'
|
||||
require 'digest'
|
||||
|
||||
module BitacorasDB
|
||||
module Importers
|
||||
@@ -43,14 +44,16 @@ module BitacorasDB
|
||||
'⏸️' => '⏸️',
|
||||
'⏳' => '⏳',
|
||||
'👁️' => '⏳', # Sincronización mapea a ⏳
|
||||
'➡️' => '⏳' # Tarea continúa en otro día
|
||||
'➡️' => '⏳', # Tarea continúa en otro día
|
||||
'🎭' => '✅' # Evento/Servicio
|
||||
}.freeze
|
||||
|
||||
# Modos posibles en archivos .md
|
||||
MODOS_MD = {
|
||||
'[P]' => 'P', # Presencial
|
||||
'[R]' => 'R', # Remoto
|
||||
'[P/R]' => 'P' # Presencial/Remoto -> Presencial por defecto
|
||||
'[P/R]' => 'P', # Presencial/Remoto -> Presencial por defecto
|
||||
'[S]' => 'S' # Servicio (No nodo técnico)
|
||||
}.freeze
|
||||
|
||||
# Tipos de nodo inferidos del nombre
|
||||
@@ -61,6 +64,7 @@ module BitacorasDB
|
||||
/^pcv-/ => 'vm',
|
||||
/^pc-/ => 'pc',
|
||||
/^srvv-/ => 'vm',
|
||||
/^dtic-/ => 'servicio',
|
||||
/-pmox\d+$/ => 'hipervisor',
|
||||
/-xen\d+$/ => 'hipervisor'
|
||||
}.freeze
|
||||
@@ -264,7 +268,7 @@ module BitacorasDB
|
||||
end
|
||||
|
||||
# Detectar inicio de tabla de entradas
|
||||
if linea.match?(/^\| I \| F \| Descripción \| E \|$/)
|
||||
if linea.match?(/^\| I \| F \| Descripción \| (?:J \| )?E \|$/)
|
||||
en_tabla_entradas = true
|
||||
encabezados_tabla = linea.split('|').map(&:strip).reject(&:empty?)
|
||||
entradas_tabla = []
|
||||
@@ -343,20 +347,32 @@ module BitacorasDB
|
||||
|
||||
# Parsea línea de tema (ej: "✅ - SEC01 - Refactorización ns8-candados")
|
||||
def parsear_tema(linea)
|
||||
# Patrón: estado - id - título (id puede contener puntos, como ADN01.1)
|
||||
match = linea.match(/^([✅❌⚠️⏸️⏳👁️➡️]+)\s*-\s*([A-Z0-9.]+)\s*-\s*(.+)$/)
|
||||
return nil unless match
|
||||
# Intentar formato estándar: estado - id - título (ej: ✅ - ADN01 - Título)
|
||||
match_std = linea.match(/^([^\s-]+)\s*-\s*([A-Z0-9.]+)\s*-\s*(.+)$/)
|
||||
if match_std
|
||||
return {
|
||||
id_tema: match_std[2],
|
||||
titulo: match_std[3].strip,
|
||||
estado: ESTADOS_MD[match_std[1]] || '⏳',
|
||||
descripcion: match_std[3].strip
|
||||
}
|
||||
end
|
||||
|
||||
estado = match[1]
|
||||
id_tema = match[2]
|
||||
titulo = match[3].strip
|
||||
# Intentar formato simplificado: estado - título (ej: 🎭 - Servicio Auditorio)
|
||||
match_simple = linea.match(/^([^\s-]+)\s*-\s*(.+)$/)
|
||||
if match_simple
|
||||
titulo = match_simple[2].strip
|
||||
# Generar un ID determinista basado en el título para estabilidad
|
||||
id_gen = "GEN" + Digest::MD5.hexdigest(titulo)[0..5].upcase
|
||||
return {
|
||||
id_tema: id_gen,
|
||||
titulo: titulo,
|
||||
estado: ESTADOS_MD[match_simple[1]] || '⏳',
|
||||
descripcion: titulo
|
||||
}
|
||||
end
|
||||
|
||||
{
|
||||
id_tema: id_tema,
|
||||
titulo: titulo,
|
||||
estado: ESTADOS_MD[estado] || '⏳',
|
||||
descripcion: titulo # Por defecto, usar título como descripción
|
||||
}
|
||||
nil
|
||||
end
|
||||
|
||||
# Parsea líneas de tabla de entradas
|
||||
@@ -370,6 +386,7 @@ module BitacorasDB
|
||||
when 'i' then columnas[:inicio] = idx
|
||||
when 'f' then columnas[:fin] = idx
|
||||
when 'descripción' then columnas[:descripcion] = idx
|
||||
when 'j' then columnas[:jornada] = idx
|
||||
when 'e' then columnas[:estado] = idx
|
||||
end
|
||||
end
|
||||
@@ -379,28 +396,39 @@ module BitacorasDB
|
||||
next if linea.match?(/^[\|\s:-]+$/) # Solo pipes, espacios, guiones y dos puntos
|
||||
next if linea.match?(/^\|?\s*:?-+:?\s*\|/) # Separadores con :---, ---, :-:, etc.
|
||||
|
||||
celdas = linea.split('|').map(&:strip).reject(&:empty?)
|
||||
# Limpiar pipes iniciales y finales antes de split
|
||||
linea_limpia = linea.strip.gsub(/^\||\|$/, '')
|
||||
celdas = linea_limpia.split('|').map(&:strip)
|
||||
next if celdas.length < 3 # Mínimo: inicio, descripción, estado
|
||||
|
||||
# Validar que la celda de inicio no sea un separador
|
||||
# Validar que la celda de inicio tenga contenido
|
||||
valor_inicio = celdas[columnas[:inicio]]
|
||||
next if valor_inicio.nil? || valor_inicio.match?(/^:?-+:?$/)
|
||||
next if valor_inicio.nil? || valor_inicio.empty? || valor_inicio.match?(/^:?-+:?$/)
|
||||
|
||||
fin_valor = nil
|
||||
if columnas[:fin] && celdas[columnas[:fin]] != '-'
|
||||
fin_valor = celdas[columnas[:fin]]
|
||||
if columnas[:fin] && !celdas[columnas[:fin]].nil?
|
||||
raw_fin = celdas[columnas[:fin]].strip
|
||||
fin_valor = raw_fin if !raw_fin.empty? && raw_fin != '-'
|
||||
end
|
||||
|
||||
entrada = {
|
||||
inicio: celdas[columnas[:inicio]],
|
||||
fin: fin_valor,
|
||||
inicio: valor_inicio.gsub(/\s*\(.*?\)\s*/, '').strip,
|
||||
fin: fin_valor ? fin_valor.gsub(/\s*\(.*?\)\s*/, '').strip : nil,
|
||||
descripcion: celdas[columnas[:descripcion]],
|
||||
estado_modo: celdas[columnas[:estado]]
|
||||
}
|
||||
|
||||
# Parsear estado y modo (ej: "[P] ✅")
|
||||
if entrada[:estado_modo]
|
||||
estado_modo = parsear_estado_modo(entrada[:estado_modo])
|
||||
# Parsear estado y modo
|
||||
if columnas[:jornada] && columnas[:estado]
|
||||
# Nuevo formato: J y E separados
|
||||
# Unimos temporalmente para usar parsear_estado_modo existente
|
||||
campo_combinado = "[#{celdas[columnas[:jornada]]}] #{celdas[columnas[:estado]]}"
|
||||
estado_modo = parsear_estado_modo(campo_combinado)
|
||||
entrada[:estado] = estado_modo[:estado]
|
||||
entrada[:modo] = estado_modo[:modo]
|
||||
elsif columnas[:estado]
|
||||
# Formato viejo o solo E
|
||||
estado_modo = parsear_estado_modo(celdas[columnas[:estado]])
|
||||
entrada[:estado] = estado_modo[:estado]
|
||||
entrada[:modo] = estado_modo[:modo]
|
||||
end
|
||||
@@ -456,6 +484,16 @@ module BitacorasDB
|
||||
|
||||
bitacora_id = bitacora['id']
|
||||
|
||||
# 1b. Si se solicita sobrescribir, limpiar entradas previas de esta bitácora
|
||||
if opciones[:sobrescribir]
|
||||
@logger.info("Limpiando datos previos de la bitácora #{estructura[:fecha]}...")
|
||||
# Borrar entradas primero (FK)
|
||||
@db.execute("DELETE FROM bitacoras.entradas WHERE bitacora_id = $1", [bitacora_id])
|
||||
# Borrar temas (FK)
|
||||
@db.execute("DELETE FROM bitacoras.temas WHERE bitacora_id = $1", [bitacora_id])
|
||||
@estadisticas[:datos_limpiados] = true
|
||||
end
|
||||
|
||||
# 2. Procesar cada nodo
|
||||
estructura[:nodos].each do |nombre_nodo, datos_nodo|
|
||||
# Buscar o crear nodo
|
||||
@@ -505,19 +543,43 @@ module BitacorasDB
|
||||
# Validar campos requeridos
|
||||
next unless entrada_md[:inicio] && entrada_md[:descripcion]
|
||||
|
||||
# Crear entrada en BD
|
||||
@db.create_entrada(
|
||||
inicio: entrada_md[:inicio],
|
||||
fin: entrada_md[:fin],
|
||||
descripcion: entrada_md[:descripcion],
|
||||
estado: entrada_md[:estado] || '⏳',
|
||||
modo: entrada_md[:modo] || 'P',
|
||||
es_ia: false, # Las importadas de .md no son IA
|
||||
tema_id: tema_id,
|
||||
bitacora_id: bitacora_id,
|
||||
nodo_id: nodo_id
|
||||
)
|
||||
@estadisticas[:entradas_creadas] += 1
|
||||
# Intentar buscar entrada existente para evitar duplicados (Upsert)
|
||||
# Buscamos por: bitacora_id, nodo_id y hora de inicio (única para un nodo en un día)
|
||||
entradas_nodo = @db.list_entradas(bitacora_id: bitacora_id, nodo_id: nodo_id, limit: 100)
|
||||
# Normalizar hora para comparación
|
||||
inicio_norm = @db.send(:parse_time, entrada_md[:inicio])
|
||||
|
||||
existente = entradas_nodo.find { |e| e['inicio'] == inicio_norm }
|
||||
|
||||
begin
|
||||
if existente
|
||||
# Actualizar si ya existe
|
||||
@db.update_entrada(existente['id'], {
|
||||
fin: entrada_md[:fin],
|
||||
descripcion: entrada_md[:descripcion],
|
||||
estado: entrada_md[:estado] || '⏳',
|
||||
modo: entrada_md[:modo] || 'P'
|
||||
})
|
||||
@estadisticas[:entradas_actualizadas] ||= 0
|
||||
@estadisticas[:entradas_actualizadas] += 1
|
||||
else
|
||||
# Crear si no existe
|
||||
@db.create_entrada(
|
||||
inicio: entrada_md[:inicio],
|
||||
fin: entrada_md[:fin],
|
||||
descripcion: entrada_md[:descripcion],
|
||||
estado: entrada_md[:estado] || '⏳',
|
||||
modo: entrada_md[:modo] || 'P',
|
||||
es_ia: false,
|
||||
tema_id: tema_id,
|
||||
bitacora_id: bitacora_id,
|
||||
nodo_id: nodo_id
|
||||
)
|
||||
@estadisticas[:entradas_creadas] += 1
|
||||
end
|
||||
rescue => e
|
||||
@logger.error("Error procesando entrada '#{entrada_md[:inicio]} - #{entrada_md[:descripcion]}': #{e.message}")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
# encrypt <txt> Cifrar texto plano
|
||||
# decrypt <tok> Descifrar payload
|
||||
# get <clave> Obtener secreto de la bóveda (salida: solo el valor)
|
||||
# run <cl> <vr> <cmd> Ejecutar comando con secreto en variable de entorno <vr>
|
||||
# set <clave> Guardar secreto (pide input interactivo, sin eco)
|
||||
# rm <clave> Eliminar secreto de la bóveda
|
||||
# list Listar claves disponibles en la bóveda
|
||||
@@ -203,6 +204,33 @@ def cmd_get(cripto, boveda, clave)
|
||||
puts cripto.decrypt(token)
|
||||
end
|
||||
|
||||
def cmd_run(cripto, boveda, clave, env_var, comando)
|
||||
abort "#{C::RED}✗ Falta nombre de clave.#{C::RESET}" if clave.nil?
|
||||
abort "#{C::RED}✗ Falta nombre de variable de entorno.#{C::RESET}" if env_var.nil?
|
||||
abort "#{C::RED}✗ Falta comando a ejecutar.#{C::RESET}" if comando.nil? || comando.empty?
|
||||
|
||||
verificar_sesion!
|
||||
token = boveda.get(clave)
|
||||
abort "#{C::RED}✗ Clave '#{clave}' no encontrada.#{C::RESET}" if token.nil?
|
||||
|
||||
secret = cripto.decrypt(token)
|
||||
registrar_acceso('RUN', "Clave: #{clave}, Comando: #{comando.is_a?(Array) ? comando.join(' ') : comando}")
|
||||
|
||||
# Ejecutar el comando inyectando la variable
|
||||
ENV[env_var] = secret
|
||||
begin
|
||||
# Si comando es un string, lo ejecutamos vía shell, si es array, directo
|
||||
if comando.is_a?(Array)
|
||||
system(*comando)
|
||||
else
|
||||
system(comando)
|
||||
end
|
||||
exit $?.exitstatus || 0
|
||||
ensure
|
||||
ENV.delete(env_var)
|
||||
end
|
||||
end
|
||||
|
||||
def cmd_set(cripto, boveda, clave)
|
||||
abort "#{C::RED}✗ Falta nombre de clave.#{C::RESET}" if clave.nil?
|
||||
$stderr.print "#{C::YELLOW}🔑 Valor para '#{clave}': #{C::RESET}"
|
||||
@@ -243,6 +271,7 @@ def cmd_help
|
||||
encrypt <texto> Cifrar texto plano → token
|
||||
decrypt <token> Descifrar token → texto plano
|
||||
get <clave> Obtener secreto de la bóveda
|
||||
run <cl> <vr> <cmd> Ejecutar comando con secreto en variable <vr>
|
||||
set <clave> Guardar secreto (input seguro)
|
||||
rm <clave> Eliminar secreto
|
||||
list Listar claves disponibles
|
||||
@@ -251,7 +280,10 @@ def cmd_help
|
||||
# Autorizar para operar
|
||||
ruby ns8-candados.rb authorize
|
||||
|
||||
#{C::DIM}# Usar en scripts (salida limpia)#{C::RESET}
|
||||
#{C::DIM}# Usar de forma segura inyectando en el entorno (recomendado)#{C::RESET}
|
||||
ruby ns8-candados.rb run admindasu PASS "sshpass -e ssh user@host"
|
||||
|
||||
#{C::DIM}# Usar en scripts (salida limpia - menos seguro)#{C::RESET}
|
||||
PASS=$(ruby ns8-candados.rb get admindasu)
|
||||
sshpass -p "$PASS" ssh user@host "cmd"
|
||||
HELP
|
||||
@@ -266,13 +298,14 @@ when 'authorize'
|
||||
autorizar!
|
||||
when 'cerrar'
|
||||
cerrar_sesion!
|
||||
when 'encrypt', 'decrypt', 'get', 'set', 'rm', 'list'
|
||||
when 'encrypt', 'decrypt', 'get', 'run', 'set', 'rm', 'list'
|
||||
cripto = Cripto.new(cargar_master_key)
|
||||
boveda = Boveda.new(BOVEDA)
|
||||
case comando
|
||||
when 'encrypt' then cmd_encrypt(cripto, arg)
|
||||
when 'decrypt' then cmd_decrypt(cripto, arg)
|
||||
when 'get' then cmd_get(cripto, boveda, arg)
|
||||
when 'run' then cmd_run(cripto, boveda, arg, ARGV[2], ARGV[3..].join(' '))
|
||||
when 'set' then cmd_set(cripto, boveda, arg)
|
||||
when 'rm' then cmd_rm(boveda, arg)
|
||||
when 'list' then cmd_list(boveda)
|
||||
|
||||
Reference in New Issue
Block a user