|
|
2 saat önce | |
|---|---|---|
| etc | 2 saat önce | |
| logs | 2 saat önce | |
| smf | 2 saat önce | |
| src | 2 saat önce | |
| tests | 2 saat önce | |
| .gitignore | 2 saat önce | |
| CHANGELOG.md | 2 saat önce | |
| CHECKPOINT.md | 2 saat önce | |
| Makefile | 2 saat önce | |
| README.md | 2 saat önce | |
| SHA256SUMS | 2 saat önce | |
| VALIDATION.md | 2 saat önce | |
| install.sh | 2 saat önce | |
Primera implementación para SmartOS global zone: daemon C de 64 bits, libkstat,
/proc, identidad UUID + generación de zona + PID + instante de creación,
configuración separada y servicio SMF. Entrega de código fuente; no contiene
un binario nativo validado en SmartOS. Véase VALIDATION.md.
Arranca en dry-run. El manifiesto añade --force-dry-run, por lo que cambiar
sólo ACTION_MODE no arma el servicio. No se entrega ninguna zona autorizada.
No se ha desplegado ni se han enviado señales reales durante la preparación.
README.md: instalación, semántica, política, operación y rollback.VALIDATION.md: validación local realizada al construir esta entrega y
comprobaciones nativas que en ese momento quedaban pendientes.CHECKPOINT.md: checkpoint operativo posterior, incorporado sin cambios,
con la evidencia acumulada de compilación, ejecución y logging de v1.0.2 en
SmartOS real, además del estado exacto y los requisitos antes de armed.CHANGELOG.md: evolución de versiones y revisión documental del paquete.El checkpoint es cronológicamente posterior a VALIDATION.md; por ello amplía
sus resultados de campo sin cambiar el código ni autorizar el modo armed.
Los comandos siguientes se ejecutan por el operador, como root en la global
zone. Requieren gcc de 64 bits, cabeceras nativas y GNU make (gmake) en PATH.
Si no hay herramientas de desarrollo, compilar en una zona nativa SmartOS
de la misma plataforma (no LX), ejecutar allí gmake test, y copiar el binario
junto a este árbol al host. No instalar un compilador en un nodo bajo presión.
Copiar el archivo distribuido a /var/tmp/o6h-memory-guard-1.0.2.tar.gz:
mkdir -p /opt/custom/src
cd /opt/custom/src
gzip -dc /var/tmp/o6h-memory-guard-1.0.2.tar.gz | tar -xf -
cd /opt/custom/src/o6h-memory-guard
gmake CC=gcc
gmake test CC=gcc
file ./o6h-memory-guard
ldd ./o6h-memory-guard
sh ./install.sh
file debe identificar un ELF nativo de 64 bits. ldd no debe mostrar
dependencias ausentes. El instalador sólo copia archivos y valida el manifiesto;
no importa ni inicia servicios, y rechaza sobrescribir una instalación existente.
Si ya se copió un binario compilado en una zona nativa, omitir gmake CC=gcc en
la global zone; conservar los resultados de compilación y pruebas.
Inventariar UUID y alias fuera del daemon:
vmadm list -o uuid,alias
vi /opt/custom/etc/o6h-memory-guard.conf
Añadir una línea por zona, con UUID real y alias sin espacios:
zone <UUID-real-de-web5> web5 allow
zone <UUID-real-de-base-de-datos> database protect
zone <UUID-real-de-monitorizacion> monitoring protect
Esos marcadores no son valores válidos: sustituirlos, incluidos los signos
< >. allow hace elegible una zona para las simulaciones; no habilita señales
mientras el servicio esté en dry-run. protect, observe o la ausencia de una
regla excluyen la zona de toda acción. Sin reglas allow el monitor funciona y
registra métricas/top de procesos, pero informa no_authorized_candidate.
/opt/custom/bin/o6h-memory-guard --check-config --force-dry-run
/opt/custom/bin/o6h-memory-guard --probe --force-dry-run
svccfg validate /opt/custom/smf/o6h-memory-guard.xml
svccfg import /opt/custom/smf/o6h-memory-guard.xml
svcadm enable -s svc:/site/o6h-memory-guard:default
svcs -xv svc:/site/o6h-memory-guard:default
svcprop -p start/exec svc:/site/o6h-memory-guard:default
tail -f /opt/custom/var/log/o6h-memory-guard/guard.log
Verificar mode=dry-run en event=start, --force-dry-run en start/exec,
arc_ok=1, swap_committed_ok=1, swap_physical_used_ok=1,
anon_pageout_ok=1 y
proc_scan complete=1. No generar presión artificial
en producción. Para comprobar selección y UUID, revisar candidate, zone y
top_process durante carga natural; WOULD_ACTION sólo aparece si se alcanzan
los umbrales y hay candidato autorizado. --probe lee una muestra y sale sin
locks, logs ni acciones; --check-config sólo valida configuración y permisos.
Para que se active automáticamente tras un reinicio de SmartOS, después de
validar este arranque editar únicamente create_default_instance a
enabled="true" en el manifiesto persistente y volver a importarlo:
vi /opt/custom/smf/o6h-memory-guard.xml
svccfg validate /opt/custom/smf/o6h-memory-guard.xml
svccfg import /opt/custom/smf/o6h-memory-guard.xml
Mantener --force-dry-run. La ubicación /opt/custom/smf se utiliza para
servicios personalizados persistentes de SmartOS; no depender exclusivamente
del estado habilitado de la instancia en el repositorio del arranque actual.
Cada segundo se leen unix:0:system_pages:{freemem,lotsfree,desfree,minfree,nscan, pp_kernel,pageslocked}, cpu:*:vm:anonpgout y zfs:0:arcstats:size mediante
libkstat. swapctl(SC_AINFO) proporciona asignación, reserva y disponibilidad
de swap virtual, equivalente a swap -s. La métrica inequívoca es
swap_committed_pages = allocated + reserved, e incluye compromiso anónimo que
puede seguir residente en RAM; no representa pageout ni bytes escritos en el
zvol. La reserva aún no asignada es
ani_resv - (ani_max - ani_free).
Por separado, swapctl(SC_LIST) obtiene las mismas entradas que swap -l.
swap_physical_used_bytes suma (blocks - free) * 512 de todos los dispositivos;
los campos nativos de la API están en páginas y se convierten primero a los
bloques de 512 bytes que muestra la utilidad. Esta cifra sí representa ocupación
física del swap configurado. Con la validación observada: swap -s indicó unos
28,5 GiB comprometidos, mientras swap -l indicó sólo 8.093.064 bloques usados,
es decir 4.143.648.768 bytes (unos 3,86 GiB). No deben compararse como si fueran
la misma magnitud.
El log conserva unidades: páginas para VM/compromiso virtual/pageout, bytes para
ARC y swap físico, KiB para RSS.
page_bytes se obtiene de sysconf, nunca se presupone 4096. nscan es una
medida del scanner, no un contador acumulativo; su delta se registra como
cambio de la medida y no se interpreta como tasa de pageout.
Historias circulares con timestamps monotónicos, deltas 5/15/60 s para libre,
kernel, locked, ARC, compromiso/disponibilidad virtual, ocupación física de swap,
pageout anónimo y nscan. Los deltas incluyen la edad
real (-100@5.02s). Se exige una muestra a ±1,25 s de la ventana; si falta,
sale NA, sin inventar ceros. /proc se recorre cada 5 s en NORMAL y cada 1 s
bajo lotsfree; RSS y crecimiento de procesos/zonas usan las mismas ventanas.
El contrato de cada event=sample expone los tres pares inequívocos
swap_committed_ok/swap_committed_pages,
swap_physical_used_ok/swap_physical_used_bytes y
anon_pageout_ok/anon_pageout_pages. Cada muestra va seguida por líneas
event=delta con esos tres nombres exactos y d5, d15 y d60.
swap_used_pages no es un nombre válido. Se conservan como diagnóstico auxiliar
swap_alloc_pages, swap_reserved_pages y swap_available_pages: son los
componentes de compromiso virtual de SC_AINFO, todos en páginas, y ninguno
representa bytes escritos en el dispositivo swap.
En los datos originales, 425950 > 130875 páginas y nscan=0 corresponden a
NORMAL. Los valores de 130875/65437/49077 páginas no están codificados como
umbrales: se vuelven a leer del kernel. ARC y pp_kernel son diagnóstico, nunca
una prueba de que un proceso concreto causó la presión.
| Estado/condición de entrada | Comportamiento predeterminado |
|---|---|
| NORMAL | Sin intervención; muestreo VM de 1 s. |
| PRE-PRESSURE | free < lotsfree continuo durante 3 s; atribución de 1 s. |
| PRESSURE | Bajo lotsfree durante 10 s y scanner activo o libre descendiendo. |
| CRITICAL | Bajo desfree con presión corroborada continua durante 2 s; TERM. |
| EMERGENCY | free < minfree; entrada en la misma muestra, sin confirmación. TERM a nuevo candidato; KILL tras 1 s al pendiente. |
| Floor | free < minfree/2; KILL directo o escalada inmediata al pendiente. |
| RECOVERY | Al recuperar lotsfree se cancela la escalada. NORMAL requiere 15 s con free >= lotsfree*1.10 y nscan=0. |
La presión se corrobora con nscan > 0, caída respecto a la muestra anterior o
delta libre de 5 s negativo. Además, bajo lotsfree, el crecimiento simultáneo
en 5 s de swap_physical_used_bytes y anon_pageout_pages corrobora presión.
La ocupación física jamás es un trigger único: sin pageout creciente y memoria
bajo lotsfree no cambia el estado. El compromiso virtual tampoco se interpreta
como pageout.
Los tiempos son segundos monotónicos transcurridos, no número de filas leídas.
Un hueco de más de 2,5 s reinicia las confirmaciones. La gravedad se retiene
hasta recuperación; action_pressure indica si la condición actual permite
actuar. Por eso un estado retenido CRITICAL no autoriza una señal por sí solo.
TERM tiene 5 s de gracia en CRITICAL. Sólo se escala si la condición crítica
sigue confirmada y la lectura fresca sigue bajo desfree. Por encima de
desfree se suspenden señales; alcanzar lotsfree cancela el pendiente. Tras
KILL se puede elegir otro candidato si sigue la presión. EMERGENCY evita la
espera normal entre víctimas de 10 s. Se mantiene como máximo una decisión de
señal por tick; un pendiente desaparecido puede sustituirse en ese mismo tick.
Hay un máximo predeterminado de 4 víctimas por episodio y 4 por ventana móvil de 60 s, tanto en simulación como en armed. TERM+KILL del mismo proceso cuentan como una víctima. El presupuesto del episodio sólo se reinicia al volver a NORMAL; el de 60 s sobrevive a ese cambio. En armed, un arranque o reinicio tiene 60 s de inhibición obligatoria de señales (también en EMERGENCY), para evitar eludir el límite por minuto mediante reinicios repetidos. Los contadores son en memoria; el presupuesto por episodio sí se reinicia al reiniciar el daemon. Revisar esta elección antes de usarlo como mecanismo de rescate. No hay garantía de evitar un panic.
Se suma RSS por UUID/generación de zona y se puntúa como
RSS + 2*max(crecimiento,0), usando preferentemente 60 s, después 15 s y 5 s.
Se elige la zona elegible con mayor puntuación y dentro de ella el proceso
elegible con mayor puntuación. Sin historia se usa RSS. Empates conservan el
primer candidato encontrado. La suma de RSS puede contar memoria compartida
varias veces: es una aproximación de atribución, no memoria física exclusiva
ni memoria garantizada que se recuperará al terminar un proceso.
El UUID es el nombre de zona devuelto por el kernel, validado como UUID canónico
en minúscula (convención SmartOS). Se conserva además ZONE_ATTR_UNIQID; se
consulta ZONE_ATTR_INITPID. Los alias son etiquetas del catálogo del operador,
no se obtienen mediante comandos ni se usan para autorizar señales. Un alias
renombrado debe actualizarse manualmente. En illumos con nombres de zona que no
sean UUID, el muestreo funciona pero esas zonas quedan excluidas de acciones.
Protecciones obligatorias: global zone completa; PID 0/1 y proceso propio;
padre 0; procesos sin LWPs; init de cada zona; identidades no resueltas o sin
generación; zonas sin regla allow; RSS menor de 64 MiB por defecto. También
se excluyen los nombres init, systemd, svc.startd, svc.configd, sshd,
zoneadmd, vminfod, vmadmd, qemu, qemu-system-x86, bhyve y el guard.
Las protecciones se aplican incluso al floor y prevalecen sobre toda autorización.
protect_process añade nombres exactos pr_fname de hasta 15 caracteres,
sin comodines ni argumentos; protect_pid añade PID global, no PID visto
dentro de LX. La config entregada añade PostgreSQL, MySQL/MariaDB, Redis y
Zabbix. Las zonas de base de datos/infraestructura deben figurar como protect.
Los nombres pueden cambiar/truncarse y no constituyen una frontera contra un
proceso malicioso: la protección por UUID completo es la más robusta.
Antes de actuar se comprueban UUID, generación, PID, inicio, nombre, UID/EUID,
init, RSS y reglas. Se abren psinfo/ctl respecto al mismo descriptor de directorio
/proc y se envía PCKILL al descriptor, no a un número PID mediante kill(2).
El inicio de un PID reutilizado invalida el candidato. Cambios de nombre/UID ya
visibles también lo invalidan. Queda la carrera inherente de un exec ordinario
entre la última lectura de psinfo y la escritura: no se detiene el proceso para
eliminarla. No se tocan flags de tracing, no se usa kill-on-close ni señales a
grupos. La integración de esta ruta todavía necesita validación nativa de laboratorio.
En dry-run nunca se abre ctl: se revalida con lecturas, se escribe
WOULD_ACTION=SIGTERM/SIGKILL y se actualiza sólo el estado simulado. Los
presupuestos evitan repetir infinitamente el mismo sacrificio hipotético.
En armed se escribe ACTION_INTENT antes y action_result=... después
(el campo real es event=action_result result=sent|failed). Los errores de
escritura de señal consumen presupuesto para evitar reintentos ambiguos.
Almacenamiento de trabajo fijo para 4096 procesos y 256 zonas, prefaulted por
inicialización; el tamaño se registra al arrancar. No hay malloc de la aplicación
en la ruta de acción, ni system, popen, exec, vmadm, ps o vmstat en
el daemon. libkstat/libc sí pueden reservar memoria internamente al actualizar
su cadena. No se promete cero asignaciones ni tiempo real estricto.
El recorrido /proc tiene presupuesto cooperativo de 200 ms (hasta 500 ms por configuración). Si faltan permisos, se excede capacidad/plazo o hay errores, el scan se marca incompleto y bloquea acciones. La desaparición normal de un proceso no se trata como fallo total. Se usa caché completa de como máximo 2 s en emergencias y siempre se revalida. Si no hay caché válida se intenta el recorrido antes de actuar. Una llamada del kernel bloqueada puede exceder el presupuesto; no es un límite duro. Los overruns quedan registrados.
Muestras obligatorias ausentes/invalidas o demasiado lentas inhiben señales;
ARC/swap/pageout opcionales ausentes se marcan con *_ok=0 y no bloquean por sí
solos. Un fallo de
log inhibe las acciones hasta reiniciar y también se anuncia en stderr/SMF.
Los logs se escriben síncronamente al archivo sin fsync por muestra; el I/O o
ZFS bloqueado puede retrasar este daemon. Tampoco garantiza que las últimas
líneas sobrevivan a pérdida de alimentación o panic. Es persistencia en disco,
no un journal de transacciones de señales. No se cambia swap, ARC ni caps de zona.
La enumeración física admite hasta 64 dispositivos swap con almacenamiento fijo;
si el nodo supera ese límite, swap_physical_used_ok=0 y esa señal diagnóstica se
omite sin autorizar acciones.
Un lock fcntl evita dos instancias (incluso una manual y otra SMF); el PID guardado es diagnóstico, nunca se usa para señalizar. Config/locks/logs exigen propietario root, archivo regular de un enlace, destino sin symlink y directorios resueltos sin escritura para grupo/otros. Directorios /opt con symlinks legítimos de root se admiten al resolver su destino. SIGHUP sólo reabre el log; la configuración se recarga reiniciando el servicio. SIGTERM/SIGINT al daemon solicitan salida limpia.
/opt/custom/bin/o6h-memory-guard
/opt/custom/etc/o6h-memory-guard.conf
/opt/custom/smf/o6h-memory-guard.xml
/opt/custom/var/run/o6h-memory-guard.lock
/opt/custom/var/log/o6h-memory-guard/guard.log
/opt/custom/var/log/o6h-memory-guard/guard.log.1 ... guard.log.5
Rotación interna: 10 MiB por archivo y 5 copias, aproximadamente 60 MiB máximos.
El volumen de líneas por segundo puede hacer que la retención sea inferior a
un día; aumentar LOG_MAX_MIB/LOG_KEEP o recoger logs externamente si se necesita
un estudio de varios días. No configurar copytruncate/logadm simultáneamente.
Snapshots de todas las zonas y top 20 procesos cada 60 s normal / 5 s en presión.
Las muestras de 1 s posteriores a las acciones permiten revisar la recuperación
en 1/2/5/10 s, siempre que no haya overruns. No se registran argumentos de procesos.
logs/policy-tests.log y logs/runtime-tests.log proceden de pruebas locales;
no son datos del nodo. logs/example.log es un ejemplo sintético de formato.
Se necesitan deliberadamente dos cambios: ACTION_MODE armed en la config y
retirar --force-dry-run del método start del manifiesto. Mantener las reglas
UUID allow mínimas y verificar antes las protecciones y el laboratorio nativo.
Después de esos cambios, validar config/manifiesto, importar, refrescar y
reiniciar el servicio. Verificar event=start mode=armed; comienza la inhibición
de 60 s. No se proporciona un script que arme automáticamente el servicio.
Para volver a dry-run, restaurar ACTION_MODE dry-run y --force-dry-run en
el manifiesto; importar, svcadm refresh y svcadm restart la instancia.
Parar el guard sin borrar evidencia:
svcadm disable -s svc:/site/o6h-memory-guard:default
svcs -p svc:/site/o6h-memory-guard:default
Si se habilitó el arranque persistente, volver a enabled="false" e importar
el manifiesto para mantenerlo deshabilitado en próximos arranques. Para retirar
el servicio conservando los archivos y logs:
mkdir -p /opt/custom/var/backups/o6h-memory-guard
mv /opt/custom/smf/o6h-memory-guard.xml /opt/custom/var/backups/o6h-memory-guard/o6h-memory-guard.xml.disabled
svccfg delete svc:/site/o6h-memory-guard:default
Comprobar antes que el destino de backup no exista y elegir un nombre distinto si ya se utilizó. El manifiesto sale del directorio de importación automática; binario/config/logs permanecen recuperables. No eliminar ni truncar el lock de una instancia viva. Restaurar el manifiesto e importarlo permite reinstalar SMF.
Para actualizar: deshabilitar primero, conservar copias del binario, config y manifiesto en un directorio de backup nuevo, reemplazar el binario estando parado y validar los tres archivos. No reemplazar automáticamente la config ni perder las protecciones. El instalador inicial se niega a hacerlo por ese motivo.
Las interfaces de atributos de zona dependen de la plataforma: confirmar con la versión exacta de SmartOS. La documentación revisada no sustituye la prueba de compilación/ejecución en ese host.