Son las 3:15 AM de una guardia de producción. Te conectas por SSH a un nodo de Oracle RAC en Oracle Linux porque ha saltado una alerta crítica. En cuestión de segundos tienes que:
- Comprobar si los demonios del cluster (
CRS,CSSD,EVMD,ASM) estánONLINEen todos los nodos (crsctl check cluster -allycrsctl status resource -t). - Cambiar del usuario
gridal usuariooraclepara abrirsqlplus / as sysdba. - Averiguar qué sesión está bloqueando una tabla crítica en
gv$session(enq: TX - row lock contention) o qué tablespace acaba de lanzar unORA-01654porque llegó al 93% sinAUTOEXTEND. - Si toca mantenimiento de sistema operativo en un nodo, reubicar todos los servicios RAC (
srvctl relocate service), parar la instancia local y detener la pila CRS sin provocar ni un segundo de caída en las aplicaciones.
Después de repetir este ritual cientos de veces, decidí construir ora-tui: una herramienta interactiva de terminal (TUI) escrita en Go, empaquetada como un único binario estático (CGO_ENABLED=0) e instalable vía dnf install ora-tui.
En este artículo te cuento cómo funciona por dentro, cómo resolví los retos de arquitectura en servidores Oracle y cómo puedes probar su modo simulador (--mock) en tu propio portátil.
🖥️ El Diseño: Marcos Unicode (┌─┐ y ╔═╗) y Navegación con Flechas
Uno de los objetivos principales era que la herramienta se sintiera rápida y clara sobre cualquier sesión SSH, utilizando una jerarquía visual de marcos Unicode:
-
Borde Simple (
┌ ─ ┐ │ └ ┘) para los paneles secundarios y tablas de datos. -
Borde Doble (
╔ ═ ╗ ║ ╚ ╝) para la cabecera principal, el panel que tiene el foco activo, las ventanas emergentes de mantenimiento y los diálogos de confirmación. -
Barras de progreso por bloques (
[█████████░] 93.0%) coloreadas según criticidad (verde $<80\%$, amarillo $80\text{–}90\%$, rojo $>90\%$).
Así se ve ora-tui en una sesión de terminal:
╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
║ ══ ORA-TUI :: ORACLE CLUSTER & DATABASE MANAGER ══ ║
╠══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╣
║ Modo: [ORACLE RAC] [MOCK DESIGN] │ Host: ora-rac01.corp.local │ Cluster: crs-prod-cluster │ Ver: 19.24.0.0.0 ║
║ ORACLE_HOME: /u01/app/oracle/product/19.0.0/dbhome_1 │ GRID_HOME: /u01/app/19.0.0/grid ║
║ Estado: 2 Inst OPEN │ 4 PDBs │ 3 Sesiones (1 Lock TX) │ 1 Tablespace >90% │ 3 Inválidos │ 1 Alerta Crítica ORA-01654 ║
╠═════════════════════════════╦════════════════════════════════════════════════════════════════════════════════════════╣
║ MENU [Flechas ↑↓ + Enter] ║ PANTALLA ACTIVA: VISTA INTEGRAL + VENTANA EMERGENTE (Borde Simple ┌─┐ y Doble ╔═╗) ║
╠═════════════════════════════╬════════════════════════════════════════════════════════════════════════════════════════╣
║ ▸ 1. Cluster & DB Estado ║ ┌─ NODOS DEL CLUSTER & INSTANCIAS (ORACLE RAC / SINGLE) ─────────────────────────────┐ ║
║ 2. Usuarios Conectados ║ │ NODO ESTADO CRS CSSD ASM INST MODO FRA_USO │ ║
║ 3. Tablespaces & Files ║ │ ora-rac01 ONLINE ONLINE ONLINE ONLINE(+ASM1) PRODCDB1 READ WRITE [████░░░░]│ ║
║ 4. Tablas & Objetos ║ │ ora-rac02 ONLINE ONLINE ONLINE ONLINE(+ASM2) PRODCDB2 READ WRITE [████░░░░]│ ║
║ 5. ASM & Red Listeners ║ └────────────────────────────────────────────────────────────────────────────────────┘ ║
║ 6. RMAN, Flashback & DG ║ ┌─ USUARIOS CONECTADOS (gv$session) ───────────┬─ TABLESPACES & BACKUPS RMAN ────────┐ ║
║ 7. Alert Log & Errores ║ │ SID,SER# USUARIO ESTADO EVENTO / LOCK │ RECURSO ESTADO / USO % │ ║
║ 8. Centro Mantenimiento ║ │ 142,48219 ERP_APP ACTIVE db file seq rd │ ERP_DATA_TBS [█████████░] 93.0% !! │ ║
║ b. Cambiar Marcos ┌─┐/╔═╗ ║ │ 289,11042 CRM_BATCH ACTIVE enq: TX lock │ SYSAUX [████████░░] 84.4% │ ║
║ t. Cambiar Topologia ║ │ 512,9931 CRM_ADMIN INACT BLOCKER (289) │ RMAN INCR L0 COMPLETED (498.4 GB) │ ║
║ q. Salir (Quit) ║ │ 604,33105 BI_REPORT ACTIVE ON CPU (512MB) │ GRP_RELEASE GUARANTEED (18.4 GB) │ ║
║ ║ └──────────────────────────────────────────────┴─────────────────────────────────────┘ ║
║ ║ ║
║ ║ ╔══════════════════════════════════════════════════════════════════════════╗ ║
║ ║ ║ ══ VENTANA DE MANTENIMIENTO [Seleccione con Flechas ↑↓ + Enter] ══ ║ ║
║ ║ ╠══════════════════════════════════════════════════════════════════════════╣ ║
║ ║ ║ ▸ [1] Drenar / Aislar Nodo Cluster (Relocate Services + Stop CRS) ║ ║
║ ║ ║ [2] Parar / Arrancar Instancia o Base de Datos (srvctl / sqlplus) ║ ║
║ ║ ║ [3] Ampliar Tablespace Crítico (+Datafile 32G a ERP_DATA_TBS 93%) ║ ║
║ ║ ║ [4] Matar Sesión Bloqueante (KILL SESSION '512,9931,@2' IMMEDIATE) ║ ║
║ ║ ║ [5] Actualizar Estadísticas (DBMS_STATS) & Shrink Tablas Online ║ ║
║ ║ ║ [6] Recompilar Objetos Inválidos (UTL_RECOMP / COMPILE_SCHEMA) ║ ║
║ ║ ║ [7] Backup RMAN Archivelog + Crear Punto Restauración Garantizado ║ ║
║ ║ ║ [8] Analizar Errores ORA- en Alert Log & Purgar Trazas ADRCI ║ ║
║ ║ ║ [Esc] Cancelar / Cerrar Ventana ║ ║
║ ║ ╚══════════════════════════════════════════════════════════════════════════╝ ║
╠═════════════════════════════╩════════════════════════════════════════════════════════════════════════════════════════╣
║ ┌─ CONSOLA DE EJECUCION & AUDITORIA EN VIVO ───────────────────────────────────────────────────────────────────────┐ ║
║ │ [08:05:01] Auto-Discovery: Modo=ORACLE RAC │ Cluster=crs-prod-cluster │ Release=19.24.0.0.0 │ ║
║ │ [08:05:02] ALERTA ORA-01654: Tablespace ERP_DATA_TBS al 93.0% │ Bloqueo TX detectado en SID 512 -> SID 289 │ ║
║ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ ║
╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝
⚙️ Decisiones Clave de Arquitectura
1. ¿Por qué CGO_ENABLED=0 y cero librerías de cliente C?
La mayoría de los drivers de Oracle requieren CGO y enlazar dinámicamente contra libclntsh.so (Oracle Instant Client). En entornos empresariales con RHEL / Oracle Linux 7, 8 y 9 y distintas versiones de glibc, distribuir binarios con dependencias dinámicas es una fuente constante de problemas.
En ora-tui, el binario se compila 100% estático (CGO_ENABLED=0 GOOS=linux GOARCH=amd64) y se comunica directamente con las herramientas nativas que ya residen en $ORACLE_HOME/bin y $GRID_HOME/bin (sqlplus -s / as sysdba, srvctl, crsctl, olsnodes, lsnrctl, rman, adrci).
2. Auto-Descubrimiento sin Archivos de Configuración
Nada más ejecutarse, ora-tui descubre qué tipo de instalación Oracle tiene delante sin pedir un solo archivo .yaml o .env:
-
Topología del Servidor:
Lee
/etc/oracle/ocr.locy/etc/oracle/olr.loc:-
local_only=false$\rightarrow$ ORACLE RAC -
local_only=true$\rightarrow$ ORACLE RESTART (Standalone Grid) - No existe $\rightarrow$ SINGLE INSTANCE
-
-
Homes e Instancias Vivas en
/proc: Además de leer/etc/oratabeinventory.xml, escanea/proc/[0-9]*/cmdlinepara localizar procesosora_pmon_<SID>,db_pmon_<SID>(Oracle 21c/23ai) yasm_pmon_+ASM*. Así detecta bases de datos levantadas aunque nadie las haya registrado en/etc/oratab.
func ExtractSIDFromPMON(cmdline string) (sid string, isASM bool) {
fields := strings.Fields(cmdline)
if len(fields) == 0 {
return "", false
}
proc := filepath.Base(fields[0])
switch {
case strings.HasPrefix(proc, "ora_pmon_"):
return strings.TrimPrefix(proc, "ora_pmon_"), false
case strings.HasPrefix(proc, "db_pmon_"):
return strings.TrimPrefix(proc, "db_pmon_"), false
case strings.HasPrefix(proc, "asm_pmon_"):
return strings.TrimPrefix(proc, "asm_pmon_"), true
}
return "", false
}
3. Cambio Dinámico de Usuario UNIX (root $\rightarrow$ oracle / grid)
En un cluster RAC con separación de roles, grid es dueño de $GRID_HOME y oracle es dueño de $ORACLE_HOME. Ejecutar sqlplus o srvctl como root falla o ensucia permisos.
ora-tui lee el uid y gid propietarios de cada directorio con os.Stat y lanza cada subproceso con las credenciales exactas de ese usuario mediante syscall.Credential, reservando root únicamente para crsctl start/stop crs:
if !asRoot && targetOwner != nil && targetOwner.UID != 0 && currentUID == 0 {
cmd.SysProcAttr = &syscall.SysProcAttr{
Credential: &syscall.Credential{
Uid: targetOwner.UID,
Gid: targetOwner.GID,
},
}
}
4. Marcos Simples (┌─┐) y Dobles (╔═╗) en tview
La librería rivo/tview permite definir globalmente los runas de dibujo de cajas, distinguiendo entre ventanas normales y ventanas con foco activo. Configurando tview.Borders, conseguimos que cualquier tabla o menú emergente resalte automáticamente con borde doble cuando el usuario lo selecciona con las flechas:
// Borde simple (┌ ─ ┐ │ └ ┘) para contenedores y tablas estándar
tview.Borders.Horizontal = '─'
tview.Borders.Vertical = '│'
tview.Borders.TopLeft = '┌'
tview.Borders.TopRight = '┐'
tview.Borders.BottomLeft = '└'
tview.Borders.BottomRight = '┘'
// Borde doble (╔ ═ ╗ ║ ╚ ╝) para la ventana con foco y modales emergentes
tview.Borders.HorizontalFocus = '═'
tview.Borders.VerticalFocus = '║'
tview.Borders.TopLeftFocus = '╔'
tview.Borders.TopRightFocus = '╗'
tview.Borders.BottomLeftFocus = '╚'
tview.Borders.BottomRightFocus = '╝'
Además, pulsando la tecla b en cualquier momento, puedes alternar en caliente entre el modo mixto (┌─┐ + ╔═╗), todo borde doble (╔═╗), todo borde simple (┌─┐) o ASCII clásico de 7 bits (+ - = |) si entras desde una consola serie antigua.
🛠️ Los 8 Módulos de Diagnóstico y Mantenimiento Guiado
En lugar de memorizar comandos, te mueves con las flechas del teclado (↑/↓) por las 8 vistas y pulsas Enter sobre cualquier fila para abrir su menú contextual de mantenimiento:
-
Cluster & DB Estado: Salud de demonios (
CRS,CSSD,EVMD,ASM), VIPs, instancias, PDBs y Drenado Seguro de Nodo (Graceful Node Drain) en 4 pasos:-
Paso 1: Pre-chequeo de nodos failover
ONLINE. -
Paso 2: Reubicación en caliente de servicios (
srvctl relocate service). -
Paso 3: Parada limpia de la instancia local (
srvctl stop instance -stopoption IMMEDIATE). -
Paso 4: Parada opcional de la pila de clusterware (
crsctl stop crs).
-
Paso 1: Pre-chequeo de nodos failover
-
Usuarios Conectados (
gv$session): Detección instantánea de bloqueosTX/TM,SQL_ID, evento de espera y texto SQL actual, con opción para ejecutarKILL SESSION IMMEDIATEoDISCONNECT SESSION POST_TRANSACTION. -
Tablespaces & Datafiles: Barras visuales de llenado y asistente para añadir datafiles en ASM (
+DATA), activarAUTOEXTEND ONo hacerCOALESCE. -
Tablas, Segmentos & Objetos Inválidos: Identificación de tablas con estadísticas
STALEo alta fragmentación para lanzarDBMS_STATS.GATHER_TABLE_STATS,SHRINK SPACE CASCADE,REBUILD ONLINEde índices o recompilar objetos inválidos conUTL_RECOMP. -
ASM & Red Listeners: Monitorización de diskgroups (
v$asm_diskgroup) y control de listeners locales y SCAN (lsnrctl start/stop/reload). - RMAN, Flashback & Data Guard: Estado de backups RMAN, creación de Guaranteed Restore Points (GRP) antes de un cambio crítico y verificación de lag en réplicas Data Guard Standby.
-
Alert Log & Errores
ORA-: Lectura directa sobrev$diag_alert_extcon salto automático al módulo que resuelve el error y purgado de trazas conadrci. - Centro de Mantenimiento: Catálogo guiado de operaciones DBA con confirmación de seguridad y consola de auditoría en tiempo real.
🚀 Pruébalo en 30 Segundos (Modo Simulación --mock)
No necesitas tener un cluster Oracle RAC instalado en tu máquina para probar la interfaz. ora-tui incluye un modo simulador (--mock) con datos realistas de un cluster RAC en producción (incluyendo sesiones bloqueadas, un tablespace al 93% y alertas ORA-01654):
git clone https://github.com/mario/ora-tui.git
cd ora-tui
# Compilar y lanzar el simulador interactivo en modo Oracle RAC:
make mock
# O ver la captura estática directamente en tu terminal:
make preview
¿Qué otra tarea repetitiva de administración Oracle te gustaría automatizar desde un menú de consola? ¡Te leo en los comentarios!
