Dominando la Consola de Scripts Groovy de Jenkins para Administración Avanzada del Sistema

Desbloquee el poder oculto de la administración de Jenkins utilizando la Consola de Scripts Groovy. Esta guía completa proporciona scripts Groovy de nivel experto y procesables para que los administradores de sistemas realicen tareas complejas al instante, como actualizaciones de configuración masivas, gestión inmediata de agentes (desconexión/reconexión) y cancelación forzosa de compilaciones en ejecución. Aprenda a interactuar directamente con el modelo de objetos de Jenkins para obtener una eficiencia y capacidad de resolución de problemas inigualables.

Dominando la Consola de Scripts Groovy de Jenkins para Administración Avanzada del Sistema

La Consola de Scripts Groovy de Jenkins es útil para trabajos que no se pueden realizar de forma limpia desde la interfaz de usuario: encontrar una compilación atascada, verificar el estado del agente, inspeccionar la configuración de un trabajo o realizar un cambio masivo cuidadosamente delimitado. También es una de las formas más fáciles de dañar un controlador de Jenkins si pega un script que no comprende.

Trate la consola como acceso root en un servidor de producción. Lea primero, imprima lo que está a punto de cambiar, pruebe en un controlador que no sea de producción cuando sea posible, y solo entonces escriba.


Entendiendo la Consola de Scripts de Jenkins

La Consola de Scripts de Jenkins (Manage Jenkins -> Script Console) proporciona acceso directo al modelo de objetos del controlador de Jenkins en ejecución utilizando Groovy. Puede inspeccionar trabajos, compilaciones, nodos, vistas, metadatos de credenciales, estado de complementos y muchos otros objetos en tiempo de ejecución.

¿Por qué usar la Consola de Scripts?

  • Ejecución Inmediata: Ejecute scripts al instante sin esperar a que se active un trabajo o se inicie una canalización.
  • Depuración del Sistema: Acceda al estado interno, registros y detalles de configuración no expuestos a través de la GUI.
  • Operaciones Masivas: Modifique múltiples trabajos, reconfigure agentes o borre datos antiguos en toda la instancia rápidamente.
  • Prototipos de Scripts: Pruebe la lógica Groovy antes de incrustarla en bibliotecas compartidas o canalizaciones declarativas.

Precauciones de Seguridad: El Poder del Acceso Directo

ADVERTENCIA: Los scripts ejecutados en la consola se ejecutan con privilegios administrativos completos en el maestro de Jenkins. Un script mal escrito puede corromper configuraciones, eliminar compilaciones o bloquear la instancia de Jenkins. Siempre pruebe los scripts complejos a fondo en un entorno que no sea de producción primero.


Objetos Groovy Esenciales y Acceso a la API

El poder de la consola proviene del acceso directo a los objetos centrales de Jenkins. Estos objetos están implícitamente disponibles dentro del entorno de ejecución de Groovy:

  • Jenkins.instance: El objeto singleton central de Jenkins, que representa el controlador en ejecución.
  • Hudson: Un alias para Jenkins.
  • Jenkins.instance.getItemByFullName('JobName'): Accede a un trabajo específico.
  • Jenkins.instance.getComputer('AgentName'): Accede a un agente (nodo) específico.

Accediendo a la Instancia de Jenkins

Para verificar que tiene acceso, el comando más simple es imprimir la versión de Jenkins:

println "Versión de Jenkins: ${Jenkins.instance.version}"
println "Ejecutando como usuario: ${Jenkins.instance.getAuthentication().getName()}"

En versiones actuales de Jenkins, puede ver ejemplos que usan Jenkins.get() en lugar de Jenkins.instance. Ambos patrones aparecen en scripts del mundo real. Para scripts nuevos, Jenkins.get() suele ser más claro:

import jenkins.model.Jenkins

def jenkins = Jenkins.get()
println "URL raíz: ${jenkins.getRootUrl()}"

Scripts Administrativos Prácticos

Aquí hay varios scripts procesables que demuestran el control administrativo avanzado a través de la Consola de Scripts.

1. Actualización de Configuraciones de Trabajos en Masa

Este script itera a través de trabajos Freestyle existentes y agrega un sufijo a la descripción. Observe el manejo seguro de nulos; muchos trabajos no tienen descripción.

import hudson.model.FreeStyleProject

final String SUFFIX = " [Actualización Automatizada]"

def count = 0

Jenkins.instance.getAllItems(FreeStyleProject.class).each { job ->
    def current = job.getDescription() ?: ""
    if (!current.endsWith(SUFFIX)) {
        job.setDescription(current + SUFFIX)
        job.save()
        println "Descripción actualizada para: ${job.getName()}"
        count++
    }
}
println "\nFinalizado. Total de trabajos actualizados: ${count}"

2. Gestión de Agentes (Nodos) de Jenkins

Los administradores a menudo necesitan poner agentes fuera de línea para mantenimiento o desconectar manualmente nodos con mal comportamiento.

Desconectar un Agente Temporalmente

Este script desconecta un agente, evitando que se inicien nuevas compilaciones en él, pero permitiendo que las compilaciones en ejecución finalicen.

import hudson.model.Computer

final String AGENT_NAME = "mi-agente-específico"

def agent = Jenkins.get().getComputer(AGENT_NAME)

if (agent) {
    // Establecer temporalmente fuera de línea
    agent.setTemporarilyOffline(true, "Mantenimiento iniciado por Script de Administrador.")
    println "Agente '${AGENT_NAME}' establecido como temporalmente fuera de línea."
} else {
    println "Agente '${AGENT_NAME}' no encontrado."
}

Forzar un Agente Fuera de Línea y Desconectar Tareas en Ejecución

Si un agente debe ser dado de baja inmediatamente, puede forzarlo a estar fuera de línea y desconectar cualquier compilación en ejecución, lo que las marcará como fallidas o abortadas dependiendo de la configuración.

import hudson.model.Computer

final String AGENT_NAME = "nodo-sin-respuesta-01"

def agent = Jenkins.get().getComputer(AGENT_NAME)

if (agent) {
    // Forzar fuera de línea y desconectar tareas en ejecución inmediatamente
    agent.doDoDisconnect()
    println "Agente '${AGENT_NAME}' desconectado forzosamente."
} else {
    println "Agente '${AGENT_NAME}' no encontrado."
}

3. Manipulación de Compilaciones en Ejecución

Cuando una compilación crítica se atasca o necesita cancelación inmediata, la Consola de Scripts proporciona la ruta más rápida.

Abortar una Compilación Específica en Ejecución

Para abortar una compilación identificada por su ruta completa (por ejemplo, PipelineJob/BuildNumber):

// Ejemplo: Abortar la compilación #5 del trabajo llamado 'DespliegueCrítico'
final String JOB_NAME = "DespliegueCrítico"
final int BUILD_NUMBER = 5

def job = Jenkins.get().getItemByFullName(JOB_NAME)

def build = job?.getBuild(BUILD_NUMBER)

if (build && build.isBuilding()) {
    build.doCancel()
    println "Compilación ${JOB_NAME}#${BUILD_NUMBER} ha sido cancelada."
} else {
    println "Compilación ${JOB_NAME}#${BUILD_NUMBER} no está en ejecución o no existe."
}

4. Limpieza de Registros de Compilaciones Antiguas

La gestión del espacio en disco a menudo requiere podar agresivamente las compilaciones antiguas. Este script identifica y elimina todas las compilaciones con más de 30 días de antigüedad para un trabajo especificado.

import hudson.model.Job
import java.util.concurrent.TimeUnit

final String TARGET_JOB = "TrabajoArchivoLegado"
final int DAYS_TO_KEEP = 30

def job = Jenkins.get().getItemByFullName(TARGET_JOB)

if (job instanceof Job) {
    long cutoffTime = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(DAYS_TO_KEEP)
    int deletedCount = 0

    job.getBuilds().each { build ->
        if (build.getTimeInMillis() < cutoffTime) {
            println "Eliminando compilación antigua: ${build.getDisplayName()}"
            build.delete()
            deletedCount++
        }
    }
    println "\nLimpieza completada. Eliminadas ${deletedCount} compilaciones para ${TARGET_JOB}."
} else {
    println "Trabajo '${TARGET_JOB}' no encontrado o no es un tipo de Trabajo estándar."
}

Mejores Prácticas para Scripts en Consola

Al realizar cambios a nivel de sistema, adhiera a estas mejores prácticas para mantener la estabilidad:

  1. Use .save(): Cada vez que modifique un objeto de configuración (como un Trabajo o Vista), debe llamar a .save() en ese objeto para que el cambio persista después de reiniciar Jenkins. Las configuraciones solo se mantienen en memoria hasta que se guardan.
  2. Verifique la Existencia del Objeto: Siempre envuelva las llamadas a la API con comprobaciones (if (object) o try-catch) para evitar que la consola se bloquee si escribe mal el nombre de un trabajo o agente.
  3. Evite Bucles Persistentes: Los scripts se ejecutan de forma síncrona. No ejecute bucles o procesos de larga duración directamente en la consola a menos que esté seguro de que se completarán rápidamente, ya que esto bloquea la interfaz de usuario de la consola.
  4. Aproveche los Métodos Incorporados: Los objetos Groovy de Jenkins a menudo tienen métodos auxiliares específicos (como doCancel() o doDoDisconnect()). Úselos en lugar de intentar manipular manualmente el estado interno cuando sea posible.
  5. Use el Modo Silencioso (si corresponde): Al realizar operaciones masivas que generan actualizaciones excesivas de estado de compilación, considere si deshabilitar temporalmente las funciones de notificación de eventos está justificado, aunque esto generalmente requiere un acceso más profundo al sistema que la administración estándar.

Patrón de Simulación Más Seguro

Para cualquier cambio masivo, agregue un indicador de simulación primero:

import jenkins.model.Jenkins
import hudson.model.Job

final boolean DRY_RUN = true
final String MATCH = "legacy-"

Jenkins.get().getAllItems(Job.class).findAll { job ->
    job.fullName.contains(MATCH)
}.each { job ->
    println "${DRY_RUN ? 'Actualizaría' : 'Actualizando'} ${job.fullName}"

    if (!DRY_RUN) {
        job.setDescription((job.getDescription() ?: "") + "\nRevisado durante la limpieza.")
        job.save()
    }
}

Ejecútelo una vez con DRY_RUN = true, copie la salida en su ticket de cambio, y solo entonces ejecútelo con false. Ese pequeño hábito previene la mayoría de los cambios amplios accidentales.

Lectura de la Configuración del Trabajo Sin Cambiarla

A veces, la consola se usa mejor como una herramienta de búsqueda. Por ejemplo, para encontrar trabajos de Pipeline que aún hacen referencia a un host Git antiguo:

import jenkins.model.Jenkins
import org.jenkinsci.plugins.workflow.job.WorkflowJob

final String NEEDLE = "git.old.example.com"

Jenkins.get().getAllItems(WorkflowJob.class).each { job ->
    def definition = job.getDefinition()
    def text = definition?.getScript()
    if (text?.contains(NEEDLE)) {
        println "Encontrado ${NEEDLE} en ${job.fullName}"
    }
}

Este ejemplo solo funciona para scripts de Pipeline en línea. Si el trabajo usa Jenkinsfile desde SCM, Jenkins almacena la definición de SCM en lugar del contenido del archivo. Esa distinción importa: la consola puede inspeccionar la configuración de Jenkins, pero no puede leer mágicamente cada rama de cada repositorio remoto a menos que su script lo haga explícitamente.

Encontrar Compilaciones Atascadas Sin Adivinar

Durante un incidente, la primera pregunta suele ser "¿qué se está ejecutando ahora?". Este script imprime las compilaciones en ejecución con su duración y ejecutor:

import jenkins.model.Jenkins

Jenkins.get().getComputers().each { computer ->
    computer.executors.each { executor ->
        def executable = executor.currentExecutable
        if (executable) {
            def build = executable
            println "${computer.displayName} :: ${build.fullDisplayName} :: ${build.durationString}"
        }
    }
}

Use esto como un script de inspección primero. Si necesita abortar algo, apunte a una compilación conocida en lugar de cancelar todo lo que parezca antiguo. Las migraciones de bases de datos de larga duración, los trabajos de lanzamiento y las canalizaciones de aprobación manual pueden parecer "atascadas" desde el exterior.

Para trabajos de Pipeline, también puede inspeccionar si una compilación está en pausa esperando entrada:

import jenkins.model.Jenkins
import org.jenkinsci.plugins.workflow.job.WorkflowRun
import org.jenkinsci.plugins.workflow.support.steps.input.InputAction

Jenkins.get().getAllItems().each { job ->
    job.builds?.findAll { it instanceof WorkflowRun && it.isBuilding() }?.each { run ->
        def input = run.getAction(InputAction)
        if (input) {
            println "Esperando entrada: ${run.fullDisplayName}"
        }
    }
}

Eso evita un error común: abortar un despliegue que está esperando intencionalmente la aprobación.

Inspección de Complementos y Versiones

La consola es útil cuando la interfaz de usuario es lenta o necesita un inventario rápido. Esto imprime los complementos instalados y las versiones:

import jenkins.model.Jenkins

Jenkins.get().pluginManager.plugins
    .sort { it.shortName }
    .each { plugin ->
        println "${plugin.shortName}:${plugin.version}"
    }

No use la Consola de Scripts como un reemplazo para un proceso de actualización de complementos gestionado. Las actualizaciones de complementos pueden afectar la carga de trabajos, el comportamiento de Pipeline, los enlaces de credenciales y las conexiones de agentes. La consola es mejor para inspección, diagnóstico de emergencia o pequeñas reparaciones específicas.

Haga una Copia de Seguridad Antes de Scripts de Escritura

Antes de ejecutar cualquier script que llame a .save(), elimine compilaciones, desconecte agentes o cambie definiciones de trabajos, asegúrese de tener una copia de seguridad actual de $JENKINS_HOME o la fuente de configuración gestionada de su controlador. Si su instancia de Jenkins está configurada por JCasC, Job DSL, valores de Helm u otro sistema respaldado por Git, recuerde que una edición en la consola puede ser sobrescrita por la siguiente reconciliación.

En esos entornos, use la consola para confirmar el problema, luego corrija la fuente de verdad. Una solución solo de consola es aceptable para una emergencia, pero regístrela para que la configuración duradera pueda actualizarse después.

Acceso Remoto a la Consola de Scripts

Muchos administradores conocen la consola del navegador, pero Jenkins también puede ejecutar Groovy a través de la CLI cuando ese acceso está habilitado y permitido:

java -jar jenkins-cli.jar -s https://jenkins.example.com/ groovy = < script.groovy

Eso es útil para scripts revisados porque puede mantener el archivo Groovy en control de versiones, pasarlo por revisión de pares y ejecutar el contenido exacto que fue aprobado. También facilita la captura de la salida en un ticket de incidente.

No habilite la CLI o la ejecución remota de scripts a la ligera. El permiso requerido para el acceso a la Consola de Scripts es altamente privilegiado. Limítelo a administradores de confianza, use el registro de auditoría cuando esté disponible y prefiera sesiones administrativas de corta duración. Si su organización utiliza control de acceso basado en roles, verifique quién tiene realmente derechos de Overall/Administer o equivalentes antes de asumir que la consola está bloqueada.

Para el mantenimiento repetible, un trabajo de Jenkins que ejecuta un script revisado bajo parámetros controlados suele ser mejor que el trabajo ad hoc en la consola del navegador. La consola sigue siendo la herramienta de emergencia; la automatización controlada por versiones debe manejar las tareas que espera repetir.

Antes de ejecutar un script remoto, imprima la URL de Jenkins y el nombre de autenticación actual en la parte superior de la salida. Suena básico, pero detecta el peor error: ejecutar una reparación de producción contra el controlador equivocado o bajo la cuenta equivocada.

import jenkins.model.Jenkins

def j = Jenkins.get()
println "Controlador: ${j.getRootUrl()}"
println "Usuario: ${j.getAuthentication().getName()}"

Qué No Poner en la Consola

Evite scripts que duerman durante mucho tiempo, sondeen para siempre, descarguen archivos remotos grandes o realicen una eliminación amplia del sistema de archivos. La consola se ejecuta dentro del proceso del controlador. Si el script quema CPU, bloquea hilos o llena la memoria, afecta al propio sistema CI.

También evite imprimir secretos. Los objetos de credenciales de Jenkins están intencionalmente protegidos, pero los administradores aún pueden escribir scripts que expongan material sensible. Si necesita auditar credenciales, imprima IDs, descripciones, dominios y referencias de uso. No imprima valores secretos en el navegador, registros de compilación o chat.

Los mejores scripts de consola son cortos, aburridos y reversibles. Úselos para inspeccionar el estado, realizar una reparación específica o automatizar una tarea administrativa conocida. Cuando un script se vuelva lo suficientemente largo como para necesitar pruebas, muévalo a un repositorio de administración compartido o a un trabajo de gestión de Jenkins donde pueda ser revisado como código normal.