Освоение Groovy Script Console в Jenkins для продвинутого администрирования системы
Раскройте скрытые возможности администрирования Jenkins с помощью Groovy Script Console. Это подробное руководство предоставляет экспертные, готовые к использованию Groovy-скрипты для системных администраторов, позволяющие мгновенно выполнять сложные задачи, такие как массовое обновление конфигураций, оперативное управление агентами (отключение/подключение) и принудительная остановка выполняющихся сборок. Узнайте, как напрямую взаимодействовать с объектной моделью Jenkins для достижения непревзойденной эффективности и возможностей устранения неполадок.
Освоение Groovy Script Console в Jenkins для продвинутого администрирования системы
Groovy Script Console в Jenkins полезна для задач, которые невозможно чисто выполнить через интерфейс: поиск зависшей сборки, проверка состояния агента, просмотр конфигурации задания или выполнение тщательно ограниченного массового изменения. Это также один из самых простых способов повредить контроллер Jenkins, если вставить скрипт, который вы не понимаете.
Относитесь к консоли как к root-доступу на production-сервере. Сначала читайте, выводите то, что собираетесь изменить, по возможности тестируйте на непродуктивном контроллере и только потом записывайте.
Понимание Script Console в Jenkins
Script Console (Manage Jenkins -> Script Console) предоставляет прямой доступ к объектной модели работающего контроллера Jenkins с использованием Groovy. Вы можете просматривать задания, сборки, узлы, представления, метаданные учетных данных, состояние плагинов и многие другие объекты времени выполнения.
Зачем использовать Script Console?
- Немедленное выполнение: Запускайте скрипты мгновенно, не дожидаясь запуска задания или начала пайплайна.
- Отладка системы: Получайте доступ к внутреннему состоянию, журналам и деталям конфигурации, не отображаемым через GUI.
- Массовые операции: Быстро изменяйте несколько заданий, перенастраивайте агентов или удаляйте старые данные во всем экземпляре.
- Прототипирование скриптов: Тестируйте логику Groovy перед встраиванием ее в общие библиотеки или декларативные пайплайны.
Мера предосторожности: Мощь прямого доступа
ПРЕДУПРЕЖДЕНИЕ: Скрипты, выполняемые в консоли, запускаются с полными правами администратора на master-узле Jenkins. Плохо написанный скрипт может повредить конфигурации, удалить сборки или привести к сбою экземпляра Jenkins. Всегда тщательно тестируйте сложные скрипты сначала в непродуктивной среде.
Основные объекты Groovy и доступ к API
Мощь консоли заключается в прямом доступе к основным объектам Jenkins. Эти объекты неявно доступны в среде выполнения Groovy:
Jenkins.instance: Основной объект-одиночка Jenkins, представляющий работающий контроллер.Hudson: Псевдоним дляJenkins.Jenkins.instance.getItemByFullName('JobName'): Доступ к конкретному заданию.Jenkins.instance.getComputer('AgentName'): Доступ к конкретному агенту (узлу).
Доступ к экземпляру Jenkins
Чтобы убедиться, что у вас есть доступ, самая простая команда — вывести версию Jenkins:
println "Версия Jenkins: ${Jenkins.instance.version}"
println "Запущен от имени пользователя: ${Jenkins.instance.getAuthentication().getName()}"
В текущих версиях Jenkins вы можете увидеть примеры использования Jenkins.get() вместо Jenkins.instance. Оба шаблона встречаются в реальных скриптах. Для новых скриптов Jenkins.get() обычно понятнее:
import jenkins.model.Jenkins
def jenkins = Jenkins.get()
println "Корневой URL: ${jenkins.getRootUrl()}"
Практические административные скрипты
Вот несколько готовых к использованию скриптов, демонстрирующих расширенное административное управление через Script Console.
1. Массовое обновление конфигураций заданий
Этот скрипт перебирает существующие задания Freestyle и добавляет суффикс к описанию. Обратите внимание на безопасную обработку null; у многих заданий нет описания.
import hudson.model.FreeStyleProject
final String SUFFIX = " [Автоматическое обновление]"
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 "Обновлено описание для: ${job.getName()}"
count++
}
}
println "\nЗавершено. Всего обновлено заданий: ${count}"
2. Управление агентами Jenkins (узлами)
Администраторам часто требуется выводить агенты из эксплуатации для обслуживания или вручную отключать некорректно работающие узлы.
Временное отключение агента
Этот скрипт отключает агент, предотвращая запуск на нем новых сборок, но позволяя завершиться выполняющимся.
import hudson.model.Computer
final String AGENT_NAME = "my-specific-agent"
def agent = Jenkins.get().getComputer(AGENT_NAME)
if (agent) {
// Установить временно офлайн
agent.setTemporarilyOffline(true, "Обслуживание запущено административным скриптом.")
println "Агент '${AGENT_NAME}' переведен в режим временно офлайн."
} else {
println "Агент '${AGENT_NAME}' не найден."
}
Принудительный вывод агента из эксплуатации и отключение выполняющихся задач
Если агента необходимо немедленно остановить, вы можете принудительно вывести его из эксплуатации и отключить все выполняющиеся сборки, что приведет к их пометке как неудачных или отмененных в зависимости от конфигурации.
import hudson.model.Computer
final String AGENT_NAME = "unresponsive-node-01"
def agent = Jenkins.get().getComputer(AGENT_NAME)
if (agent) {
// Принудительно отключить и немедленно прервать выполняющиеся задачи
agent.doDoDisconnect()
println "Агент '${AGENT_NAME}' принудительно отключен."
} else {
println "Агент '${AGENT_NAME}' не найден."
}
3. Управление выполняющимися сборками
Когда критическая сборка зависает или требует немедленной отмены, Script Console предоставляет самый быстрый путь.
Отмена конкретной выполняющейся сборки
Чтобы отменить сборку, идентифицированную по ее полному пути (например, PipelineJob/BuildNumber):
// Пример: Отмена сборки #5 задания с именем 'CriticalDeploy'
final String JOB_NAME = "CriticalDeploy"
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 "Сборка ${JOB_NAME}#${BUILD_NUMBER} отменена."
} else {
println "Сборка ${JOB_NAME}#${BUILD_NUMBER} не выполняется или не существует."
}
4. Очистка старых записей сборок
Управление дисковым пространством часто требует агрессивного удаления старых сборок. Этот скрипт находит и удаляет все сборки старше 30 дней для указанного задания.
import hudson.model.Job
import java.util.concurrent.TimeUnit
final String TARGET_JOB = "LegacyArchivingJob"
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 "Удаление старой сборки: ${build.getDisplayName()}"
build.delete()
deletedCount++
}
}
println "\nОчистка завершена. Удалено ${deletedCount} сборок для ${TARGET_JOB}."
} else {
println "Задание '${TARGET_JOB}' не найдено или не является стандартным типом задания."
}
Лучшие практики написания скриптов в консоли
При выполнении изменений на уровне системы придерживайтесь следующих лучших практик для поддержания стабильности:
- Используйте
.save(): Каждый раз, когда вы изменяете объект конфигурации (например, задание или представление), вы обязаны вызвать.save()для этого объекта, чтобы изменение сохранилось после перезапуска Jenkins. Конфигурации хранятся в памяти только до сохранения. - Проверяйте существование объекта: Всегда оборачивайте вызовы API проверками (
if (object)илиtry-catch), чтобы предотвратить сбой консоли, если вы ошиблись в имени задания или агента. - Избегайте постоянных циклов: Скрипты выполняются синхронно. Не выполняйте длительные циклы или процессы непосредственно в консоли, если вы не уверены, что они завершатся быстро, так как это блокирует интерфейс консоли.
- Используйте встроенные методы: Объекты Groovy в Jenkins часто имеют специальные вспомогательные методы (например,
doCancel()илиdoDoDisconnect()). Используйте их вместо попыток вручную манипулировать внутренним состоянием, где это возможно. - Используйте тихий режим (если применимо): При выполнении массовых операций, генерирующих чрезмерные обновления статуса сборок, рассмотрите возможность временного отключения функций уведомлений о событиях, хотя обычно это требует более глубокого доступа к системе, чем стандартное администрирование.
Более безопасный шаблон "пробного запуска"
Для любого массового изменения сначала добавьте флаг пробного запуска:
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 ? 'Будет обновлено' : 'Обновляется'} ${job.fullName}"
if (!DRY_RUN) {
job.setDescription((job.getDescription() ?: "") + "\nПроверено во время очистки.")
job.save()
}
}
Запустите его один раз с DRY_RUN = true, скопируйте вывод в свой тикет на изменение и только потом запустите с false. Эта небольшая привычка предотвращает большинство случайных массовых изменений.
Чтение конфигурации задания без ее изменения
Иногда консоль лучше всего использовать как инструмент поиска. Например, чтобы найти задания Pipeline, которые все еще ссылаются на старый 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 "Найден ${NEEDLE} в ${job.fullName}"
}
}
Этот пример работает только для встроенных скриптов Pipeline. Если задание использует Jenkinsfile из SCM, Jenkins хранит определение SCM, а не содержимое файла. Это различие имеет значение: консоль может проверять конфигурацию Jenkins, но она не может волшебным образом прочитать каждую ветку каждого удаленного репозитория, если ваш скрипт явно этого не делает.
Поиск зависших сборок без гадания
Во время инцидента первый вопрос часто звучит так: "что сейчас выполняется?" Этот скрипт выводит выполняющиеся сборки с их длительностью и исполнителем:
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}"
}
}
}
Используйте это сначала как скрипт для проверки. Если вам нужно что-то отменить, нацельтесь на одну известную сборку, а не отменяйте все, что выглядит старым. Долгие миграции баз данных, задания на релиз и пайплайны с ручным утверждением могут выглядеть "зависшими" со стороны.
Для заданий Pipeline вы также можете проверить, приостановлена ли сборка для ввода данных:
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 "Ожидание ввода: ${run.fullDisplayName}"
}
}
}
Это предотвращает распространенную ошибку: отмену развертывания, которое намеренно ожидает утверждения.
Проверка плагинов и версий
Консоль удобна, когда интерфейс медленный или вам нужна быстрая инвентаризация. Это выводит установленные плагины и версии:
import jenkins.model.Jenkins
Jenkins.get().pluginManager.plugins
.sort { it.shortName }
.each { plugin ->
println "${plugin.shortName}:${plugin.version}"
}
Не используйте Script Console в качестве замены управляемому процессу обновления плагинов. Обновления плагинов могут повлиять на загрузку заданий, поведение Pipeline, привязки учетных данных и подключения агентов. Консоль лучше всего подходит для проверки, экстренной диагностики или небольших целенаправленных исправлений.
Создавайте резервную копию перед скриптами записи
Перед запуском любого скрипта, который вызывает .save(), удаляет сборки, отключает агентов или изменяет определения заданий, убедитесь, что у вас есть актуальная резервная копия $JENKINS_HOME или управляемого источника конфигурации вашего контроллера. Если ваш экземпляр Jenkins настроен с помощью JCasC, Job DSL, значений Helm или другой системы на основе Git, помните, что правка в консоли может быть перезаписана при следующей синхронизации.
В таких средах используйте консоль для подтверждения проблемы, затем исправьте источник истины. Исправление только через консоль приемлемо в экстренной ситуации, но запишите его, чтобы долговременная конфигурация могла быть обновлена впоследствии.
Удаленный доступ к Script Console
Многие администраторы знают о консоли в браузере, но Jenkins также может запускать Groovy через CLI, если этот доступ включен и разрешен:
java -jar jenkins-cli.jar -s https://jenkins.example.com/ groovy = < script.groovy
Это полезно для проверенных скриптов, потому что вы можете хранить Groovy-файл в системе контроля версий, проводить его через рецензирование и выполнять точное содержимое, которое было одобрено. Это также упрощает захват вывода в тикете инцидента.
Не включайте CLI или удаленное выполнение скриптов без необходимости. Разрешение, необходимое для доступа к Script Console, является высокопривилегированным. Ограничьте его доверенными администраторами, используйте аудит журналов, где это возможно, и предпочитайте короткие административные сессии. Если ваша организация использует управление доступом на основе ролей, проверьте, кто на самом деле имеет права Overall/Administer или эквивалентные, прежде чем предполагать, что консоль заблокирована.
Для повторяющегося обслуживания задание Jenkins, которое запускает проверенный скрипт с контролируемыми параметрами, часто лучше, чем ad-hoc работа в браузерной консоли. Консоль остается инструментом для экстренных случаев; автоматизация под контролем версий должна обрабатывать задачи, которые вы ожидаете повторять.
Перед запуском удаленного скрипта выведите URL Jenkins и текущее имя аутентификации в начале вывода. Это звучит элементарно, но это ловит самую страшную ошибку: запуск производственного исправления на неправильном контроллере или под неправильной учетной записью.
import jenkins.model.Jenkins
def j = Jenkins.get()
println "Контроллер: ${j.getRootUrl()}"
println "Пользователь: ${j.getAuthentication().getName()}"
Что не следует помещать в консоль
Избегайте скриптов, которые долго спят, опрашивают бесконечно, загружают большие удаленные файлы или выполняют широкое удаление файловой системы. Консоль работает внутри процесса контроллера. Если скрипт нагружает процессор, блокирует потоки или заполняет память, это влияет на саму систему CI.
Также избегайте вывода секретов. Объекты учетных данных Jenkins намеренно защищены, но администраторы все равно могут написать скрипты, раскрывающие конфиденциальные материалы. Если вам нужно проверить учетные данные, выводите ID, описания, домены и ссылки на использование. Не выводите секретные значения в браузер, журналы сборок или чат.
Лучшие скрипты для консоли — короткие, скучные и обратимые. Используйте их для проверки состояния, выполнения узкого исправления или автоматизации известной административной задачи. Когда скрипт становится достаточно длинным, чтобы потребовать тестов, переместите его в общий административный репозиторий или задание управления Jenkins, где его можно будет рецензировать как обычный код.