Maîtrise de la Console de Scripts Groovy Jenkins pour l'Administration Avancée du Système

Débloquez la puissance cachée de l'administration Jenkins en utilisant la Console de Scripts Groovy. Ce guide complet fournit des scripts Groovy exploitables de niveau expert pour les administrateurs système afin d'effectuer des tâches complexes instantanément, telles que les mises à jour de configuration en masse, la gestion immédiate des agents (déconnexion/reconnexion) et l'arrêt forcé des builds en cours. Apprenez à interagir directement avec le modèle objet Jenkins pour une efficacité et des capacités de dépannage inégalées.

Maîtrise de la Console de Scripts Groovy Jenkins pour l'Administration Avancée du Système

La Console de Scripts Groovy Jenkins est utile pour les tâches que vous ne pouvez pas effectuer proprement depuis l'interface utilisateur : trouver un build bloqué, vérifier l'état d'un agent, inspecter la configuration d'un job ou effectuer une modification en masse soigneusement ciblée. C'est aussi l'un des moyens les plus simples d'endommager un contrôleur Jenkins si vous collez un script que vous ne comprenez pas.

Traitez la console comme un accès root sur un serveur de production. Lisez d'abord, imprimez ce que vous allez modifier, testez sur un contrôleur non productif si possible, et ensuite seulement écrivez.


Comprendre la Console de Scripts Jenkins

La Console de Scripts Jenkins (Gérer Jenkins -> Console de Scripts) fournit un accès direct au modèle objet du contrôleur Jenkins en cours d'exécution en utilisant Groovy. Vous pouvez inspecter les jobs, les builds, les nœuds, les vues, les métadonnées des identifiants, l'état des plugins et de nombreux autres objets d'exécution.

Pourquoi utiliser la Console de Scripts ?

  • Exécution Immédiate : Exécutez des scripts instantanément sans attendre le déclenchement d'un job ou le démarrage d'un pipeline.
  • Débogage Système : Accédez à l'état interne, aux journaux et aux détails de configuration non exposés via l'interface graphique.
  • Opérations en Masse : Modifiez plusieurs jobs, reconfigurez des agents ou effacez rapidement d'anciennes données sur l'ensemble de l'instance.
  • Prototypes de Scripts : Testez la logique Groovy avant de l'intégrer dans des bibliothèques partagées ou des pipelines déclaratifs.

Précaution de Sécurité : Le Pouvoir de l'Accès Direct

ATTENTION : Les scripts exécutés dans la console le sont avec les privilèges d'administration complets sur le maître Jenkins. Un script mal écrit peut corrompre des configurations, supprimer des builds ou planter l'instance Jenkins. Testez toujours minutieusement les scripts complexes d'abord dans un environnement non productif.


Objets Groovy Essentiels et Accès à l'API

La puissance de la console vient de l'accès direct aux objets centraux de Jenkins. Ces objets sont implicitement disponibles dans l'environnement d'exécution Groovy :

  • Jenkins.instance : L'objet singleton central de Jenkins, représentant le contrôleur en cours d'exécution.
  • Hudson : Un alias pour Jenkins.
  • Jenkins.instance.getItemByFullName('NomDuJob') : Accède à un job spécifique.
  • Jenkins.instance.getComputer('NomAgent') : Accède à un agent (nœud) spécifique.

Accéder à l'Instance Jenkins

Pour vérifier que vous avez accès, la commande la plus simple est d'imprimer la version de Jenkins :

println "Version Jenkins : ${Jenkins.instance.version}"
println "Exécuté en tant qu'utilisateur : ${Jenkins.instance.getAuthentication().getName()}"

Sur les versions actuelles de Jenkins, vous pouvez voir des exemples utilisant Jenkins.get() au lieu de Jenkins.instance. Les deux modèles apparaissent dans les scripts réels. Pour les nouveaux scripts, Jenkins.get() est généralement plus clair :

import jenkins.model.Jenkins

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

Scripts Administratifs Pratiques

Voici plusieurs scripts exploitables qui démontrent un contrôle administratif avancé via la Console de Scripts.

1. Mise à Jour des Configurations de Job en Masse

Ce script parcourt les jobs Freestyle existants et ajoute un suffixe à la description. Notez la gestion sécurisée des valeurs nulles ; de nombreux jobs n'ont pas de description.

import hudson.model.FreeStyleProject

final String SUFFIX = " [Mise à Jour Automatisée]"

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 "Description mise à jour pour : ${job.getName()}"
        count++
    }
}
println "\nTerminé. Nombre total de jobs mis à jour : ${count}"

2. Gestion des Agents Jenkins (Nœuds)

Les administrateurs ont souvent besoin de mettre des agents hors ligne pour maintenance ou de déconnecter manuellement des nœuds défaillants.

Déconnexion Temporaire d'un Agent

Ce script déconnecte un agent, empêchant le démarrage de nouveaux builds sur celui-ci, mais permettant aux builds en cours de se terminer.

import hudson.model.Computer

final String AGENT_NAME = "mon-agent-spécifique"

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

if (agent) {
    // Mettre temporairement hors ligne
    agent.setTemporarilyOffline(true, "Maintenance démarrée par script Admin.")
    println "Agent '${AGENT_NAME}' mis temporairement hors ligne."
} else {
    println "Agent '${AGENT_NAME}' non trouvé."
}

Forcer la Mise Hors Ligne d'un Agent et Déconnecter les Tâches en Cours

Si un agent doit être immédiatement arrêté, vous pouvez le forcer hors ligne et déconnecter tous les builds en cours, ce qui les marquera comme échoués ou annulés selon la configuration.

import hudson.model.Computer

final String AGENT_NAME = "nœud-non-réactif-01"

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

if (agent) {
    // Forcer la mise hors ligne et déconnecter immédiatement les tâches en cours
    agent.doDoDisconnect()
    println "Agent '${AGENT_NAME}' déconnecté de force."
} else {
    println "Agent '${AGENT_NAME}' non trouvé."
}

3. Manipulation des Builds en Cours

Lorsqu'un build critique est bloqué ou nécessite une annulation immédiate, la Console de Scripts offre le chemin le plus rapide.

Annulation d'un Build Spécifique en Cours

Pour annuler un build identifié par son chemin complet (par exemple, PipelineJob/NuméroBuild) :

// Exemple : Annulation du build #5 du job nommé 'DéploiementCritique'
final String JOB_NAME = "DéploiementCritique"
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 "Le build ${JOB_NAME}#${BUILD_NUMBER} a été annulé."
} else {
    println "Le build ${JOB_NAME}#${BUILD_NUMBER} n'est pas en cours ou n'existe pas."
}

4. Nettoyage des Anciens Enregistrements de Build

La gestion de l'espace disque nécessite souvent un élagage agressif des anciens builds. Ce script identifie et supprime tous les builds de plus de 30 jours pour un job spécifié.

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

final String TARGET_JOB = "JobArchivageHérité"
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 "Suppression de l'ancien build : ${build.getDisplayName()}"
            build.delete()
            deletedCount++
        }
    }
    println "\nNettoyage terminé. ${deletedCount} builds supprimés pour ${TARGET_JOB}."
} else {
    println "Le job '${TARGET_JOB}' est introuvable ou n'est pas un type de Job standard."
}

Bonnes Pratiques pour les Scripts Console

Lorsque vous effectuez des modifications au niveau du système, respectez ces bonnes pratiques pour maintenir la stabilité :

  1. Utilisez .save() : Chaque fois que vous modifiez un objet de configuration (comme un Job ou une Vue), vous devez appeler .save() sur cet objet pour que la modification persiste après le redémarrage de Jenkins. Les configurations ne sont conservées en mémoire que jusqu'à leur sauvegarde.
  2. Vérifiez l'Existence de l'Objet : Entourez toujours les appels API de vérifications (if (objet) ou try-catch) pour éviter que la console ne plante si vous faites une faute de frappe sur un nom de job ou d'agent.
  3. Évitez les Boucles Persistantes : Les scripts s'exécutent de manière synchrone. N'exécutez pas de longues boucles ou de processus directement dans la console à moins d'être certain qu'ils se termineront rapidement, car cela bloque l'interface utilisateur de la console.
  4. Tirez Parti des Méthodes Intégrées : Les objets Groovy de Jenkins ont souvent des méthodes d'aide spécifiques (comme doCancel() ou doDoDisconnect()). Utilisez-les plutôt que d'essayer de manipuler manuellement l'état interne lorsque c'est possible.
  5. Utilisez le Mode Silencieux (si applicable) : Lorsque vous effectuez des opérations en masse qui génèrent des mises à jour excessives de statut de build, envisagez si la désactivation temporaire des fonctionnalités de notification d'événements est justifiée, bien que cela nécessite généralement un accès système plus profond que l'administration standard.

Modèle de Simulation Plus Sûr (Dry-Run)

Pour toute modification en masse, ajoutez d'abord un indicateur de simulation :

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

final boolean DRY_RUN = true
final String MATCH = "hérité-"

Jenkins.get().getAllItems(Job.class).findAll { job ->
    job.fullName.contains(MATCH)
}.each { job ->
    println "${DRY_RUN ? 'Mettrait à jour' : 'Mise à jour'} ${job.fullName}"

    if (!DRY_RUN) {
        job.setDescription((job.getDescription() ?: "") + "\nRévisé lors du nettoyage.")
        job.save()
    }
}

Exécutez-le une fois avec DRY_RUN = true, copiez la sortie dans votre ticket de modification, et ensuite seulement exécutez-le avec false. Cette petite habitude évite la plupart des modifications accidentelles à grande échelle.

Lecture de la Configuration d'un Job Sans la Modifier

Parfois, la console est mieux utilisée comme outil de recherche. Par exemple, pour trouver les jobs Pipeline qui référencent encore un ancien hôte Git :

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 "Trouvé ${NEEDLE} dans ${job.fullName}"
    }
}

Cet exemple ne fonctionne que pour les scripts Pipeline en ligne. Si le job utilise Jenkinsfile depuis le SCM, Jenkins stocke la définition SCM plutôt que le contenu du fichier. Cette distinction est importante : la console peut inspecter la configuration Jenkins, mais elle ne peut pas lire magiquement chaque branche de chaque dépôt distant à moins que votre script ne le fasse explicitement.

Trouver les Builds Bloqués Sans Deviner

Lors d'un incident, la première question est souvent "qu'est-ce qui s'exécute en ce moment ?". Ce script imprime les builds en cours avec leur durée et leur exécuteur :

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}"
        }
    }
}

Utilisez ceci d'abord comme script d'inspection. Si vous devez annuler quelque chose, ciblez un build connu plutôt que d'annuler tout ce qui semble ancien. Les migrations de base de données de longue durée, les jobs de release et les pipelines d'approbation manuelle peuvent sembler "bloqués" de l'extérieur.

Pour les jobs Pipeline, vous pouvez également inspecter si un build est en pause pour une entrée :

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 "En attente d'entrée : ${run.fullDisplayName}"
        }
    }
}

Cela évite une erreur courante : annuler un déploiement qui attend intentionnellement une approbation.

Inspection des Plugins et des Versions

La console est pratique lorsque l'interface utilisateur est lente ou que vous avez besoin d'un inventaire rapide. Ceci imprime les plugins installés et leurs versions :

import jenkins.model.Jenkins

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

N'utilisez pas la Console de Scripts comme un remplacement d'un processus de mise à jour de plugins géré. Les mises à niveau de plugins peuvent affecter le chargement des jobs, le comportement des pipelines, les liaisons d'identifiants et les connexions des agents. La console est préférable pour l'inspection, le diagnostic d'urgence ou les petites réparations ciblées.

Sauvegardez Avant les Scripts d'Écriture

Avant d'exécuter tout script qui appelle .save(), supprime des builds, déconnecte des agents ou modifie des définitions de jobs, assurez-vous d'avoir une sauvegarde actuelle de $JENKINS_HOME ou de la source de configuration gérée de votre contrôleur. Si votre instance Jenkins est configurée par JCasC, Job DSL, valeurs Helm ou un autre système basé sur Git, rappelez-vous qu'une modification via la console peut être écrasée par la prochaine réconciliation.

Dans ces environnements, utilisez la console pour confirmer le problème, puis corrigez la source de vérité. Une correction uniquement via la console est acceptable pour une urgence, mais enregistrez-la afin que la configuration durable puisse être mise à jour par la suite.

Accès à Distance à la Console de Scripts

De nombreux administrateurs connaissent la console du navigateur, mais Jenkins peut également exécuter Groovy via l'interface CLI lorsque cet accès est activé et autorisé :

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

Ceci est utile pour les scripts révisés car vous pouvez conserver le fichier Groovy dans le contrôle de version, le soumettre à une révision par les pairs et exécuter le contenu exact qui a été approuvé. Cela facilite également la capture de la sortie dans un ticket d'incident.

N'activez pas l'interface CLI ou l'exécution de scripts à distance à la légère. L'autorisation requise pour l'accès à la Console de Scripts est hautement privilégiée. Limitez-la aux administrateurs de confiance, utilisez la journalisation d'audit lorsque disponible et préférez les sessions d'administration de courte durée. Si votre organisation utilise un contrôle d'accès basé sur les rôles, vérifiez qui a réellement les droits Overall/Administer ou équivalents avant de supposer que la console est verrouillée.

Pour une maintenance répétable, un job Jenkins qui exécute un script révisé avec des paramètres contrôlés est souvent meilleur qu'un travail ad hoc via la console du navigateur. La console reste l'outil d'urgence ; l'automatisation sous contrôle de version devrait gérer les tâches que vous prévoyez de répéter.

Avant d'exécuter un script à distance, imprimez l'URL Jenkins et le nom d'authentification actuel en haut de la sortie. Cela semble basique, mais cela permet d'éviter la pire erreur : exécuter une réparation de production sur le mauvais contrôleur ou sous le mauvais compte.

import jenkins.model.Jenkins

def j = Jenkins.get()
println "Contrôleur : ${j.getRootUrl()}"
println "Utilisateur : ${j.getAuthentication().getName()}"

Ce Qu'il ne Faut Pas Mettre dans la Console

Évitez les scripts qui dorment longtemps, sondent indéfiniment, téléchargent de gros fichiers distants ou effectuent une suppression généralisée de fichiers. La console s'exécute à l'intérieur du processus du contrôleur. Si le script consomme du CPU, bloque des threads ou remplit la mémoire, cela affecte le système CI lui-même.

Évitez également d'imprimer des secrets. Les objets d'identifiants Jenkins sont intentionnellement protégés, mais les administrateurs peuvent toujours écrire des scripts qui exposent des informations sensibles. Si vous devez auditer des identifiants, imprimez les ID, descriptions, domaines et références d'utilisation. N'imprimez pas les valeurs secrètes dans le navigateur, les journaux de build ou le chat.

Les meilleurs scripts de console sont courts, ennuyeux et réversibles. Utilisez-les pour inspecter l'état, effectuer une réparation ciblée ou automatiser une tâche administrative connue. Lorsqu'un script devient suffisamment long pour nécessiter des tests, déplacez-le dans un dépôt d'administration partagé ou un job de gestion Jenkins où il peut être révisé comme du code normal.