Jenkins error message

Разбор ошибок появляющихся при работе с Jenkins
Содержание

Spread load evenly by using
jenkins doesn’t have label XXXXX
Pipeline Debug
groovy.lang.MissingPropertyException: No such property: XXX for class: groovy.lang.Binding
Статьи про Jenkins

Spread load evenly

Spread load evenly by using ‘H/5 * * * *’ rather than ‘*/5 * * * *’

Это рекомендация не запускать задания одновременно, а дать Jenkins распределить нагрузку
более равномерно. Подробнее

здесь

jenkins doesn’t have label XXXXX

jenkins doesn’t have label XXXXX

Это сообщение очень часто можно увидеть при ошибке в конфигурации.

Сообщение часто не соответсвует действительности!

label может сущестововать но при этом
где-то забыта или неправильно дана какая-то настройка.

Это яркий пример плохой работы с пользовательским опытом. Проблема известа давно, но
разработчики Jenkins считают, что это нормально.

Посмотрите какой лог выдаёт Jenkins если просто забыть указать
Remote File System Root
в настройках агента.

jenkins | 2023-01-12 10:56:40.308+0000 [id=3120] WARNING c.n.j.p.d.u.PortUtils$ConnectionCheck#execute: Could not connect to 10.15.253.223 port 49276. Are you sure this location is contactable from Jenkins?
jenkins | 2023-01-12 10:56:41.943+0000 [id=3120] SEVERE c.n.j.p.docker.DockerCloud$1#run: Error in provisioning; template=’DockerTemplate{configVersion=2, labelString=’docker_slave_ssh’, connector=DockerComputerSSHConnector{sshKeyStrategy=ManuallyConfiguredSSHKey{credentialsId=’fbe72464-8935-4a5c-966c-8e96c76a82fc’, sshHostKeyVerificationStrategy=hudson.plugins.sshslaves.verifiers.NonVerifyingKeyVerificationStrategy@38e4341e}, port=22, maxNumRetries=10, retryWaitTime=15}, instanceCap=2147483647, mode=NORMAL, retentionStrategy=com.nirima.jenkins.plugins.docker.strategy.DockerOnceRetentionStrategy@2c, dockerTemplateBase=DockerTemplateBase{image=’andreissh/jenkins-docker-slave:latest’, bindAllPorts=false, cpuPeriod=0, cpuQuota=0, privileged=false, tty=false}, removeVolumes=false, stopTimeout=10, pullStrategy=PULL_ALWAYS, pullTimeout=300, disabled=BySystem,0 ms,4 min 59 sec,Template provisioning failed., name=’docker_slave_ssh’}’ for cloud=’docker_ubuntu_esxi2′
jenkins | java.io.IOException: SSH service hadn’t started after 150 seconds and 15 milliseconds.Try increasing the number of retries (currently 10) and/or the retry wait time (currently 15) to allow for containers taking longer to start.
jenkins | at io.jenkins.docker.connector.DockerComputerSSHConnector.createLauncher(DockerComputerSSHConnector.java:326)
jenkins | at io.jenkins.docker.connector.DockerComputerConnector.createLauncher(DockerComputerConnector.java:176)
jenkins | at com.nirima.jenkins.plugins.docker.DockerTemplate.doProvisionNode(DockerTemplate.java:746)
jenkins | at com.nirima.jenkins.plugins.docker.DockerTemplate.provisionNode(DockerTemplate.java:683)
jenkins | at com.nirima.jenkins.plugins.docker.DockerCloud$1.run(DockerCloud.java:376)
jenkins | at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:30)
jenkins | at jenkins.security.ImpersonatingExecutorService$1.run(ImpersonatingExecutorService.java:70)
jenkins | at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
jenkins | at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
jenkins | at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
jenkins | at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
jenkins | at java.base/java.lang.Thread.run(Thread.java:829)
jenkins | 2023-01-12 10:56:46.120+0000 [id=53] WARNING hudson.slaves.NodeProvisioner#update: Unexpected exception encountered while provisioning agent Image of andreissh/jenkins-docker-slave:latest
jenkins | java.io.IOException: SSH service hadn’t started after 150 seconds and 15 milliseconds.Try increasing the number of retries (currently 10) and/or the retry wait time (currently 15) to allow for containers taking longer to start.
jenkins | at io.jenkins.docker.connector.DockerComputerSSHConnector.createLauncher(DockerComputerSSHConnector.java:326)
jenkins | at io.jenkins.docker.connector.DockerComputerConnector.createLauncher(DockerComputerConnector.java:176)
jenkins | at com.nirima.jenkins.plugins.docker.DockerTemplate.doProvisionNode(DockerTemplate.java:746)
jenkins | at com.nirima.jenkins.plugins.docker.DockerTemplate.provisionNode(DockerTemplate.java:683)
jenkins | at com.nirima.jenkins.plugins.docker.DockerCloud$1.run(DockerCloud.java:376)
jenkins | at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:30)
jenkins | at jenkins.security.ImpersonatingExecutorService$1.run(ImpersonatingExecutorService.java:70)
jenkins | at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
jenkins | at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
jenkins | at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
jenkins | at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
jenkins | at java.base/java.lang.Thread.run(Thread.java:829)

jenkins | 2023-01-12 11:56:16.124+0000 [id=51] INFO c.n.j.plugins.docker.DockerCloud#canAddProvisionedAgent: Provisioning ‘andreissh/jenkins-docker-slave:latest’ on ‘docker_ubuntu_esxi2’; Total containers: 0 (of 100)
jenkins | 2023-01-12 11:56:16.124+0000 [id=51] INFO c.n.j.plugins.docker.DockerCloud#provision: Will provision ‘andreissh/jenkins-docker-slave:latest’, for label: ‘docker_slave_ssh’, in cloud: ‘docker_ubuntu_esxi2’
jenkins | 2023-01-12 11:56:16.124+0000 [id=51] INFO h.s.NodeProvisioner$StandardStrategyImpl#apply: Started provisioning Image of andreissh/jenkins-docker-slave:latest from docker_ubuntu_esxi2 with 1 executors. Remaining excess workload: 0
jenkins | 2023-01-12 11:56:16.125+0000 [id=3264] INFO c.n.j.p.docker.DockerTemplate#pullImage: Pulling image ‘andreissh/jenkins-docker-slave:latest’. This may take awhile…
jenkins | 2023-01-12 11:56:17.460+0000 [id=3264] INFO c.n.j.p.docker.DockerTemplate#pullImage: Finished pulling image ‘andreissh/jenkins-docker-slave:latest’, took 1335 ms
jenkins | 2023-01-12 11:56:17.464+0000 [id=3264] INFO c.n.j.p.docker.DockerTemplate#doProvisionNode: Trying to run container for image «andreissh/jenkins-docker-slave:latest»
jenkins | 2023-01-12 11:56:17.464+0000 [id=3264] INFO c.n.j.p.docker.DockerTemplate#doProvisionNode: Trying to run container for node docker_slave_ssh-000hxyehdkxzs from image: andreissh/jenkins-docker-slave:latest
jenkins | 2023-01-12 11:56:18.518+0000 [id=3264] INFO c.n.j.p.docker.DockerTemplate#doProvisionNode: Started container ID 9773e98eb12b5b6b7e24a52f734465242949ab563b3c927dbe05627a3dda615b for node docker_slave_ssh-000hxyehdkxzs from image: andreissh/jenkins-docker-slave:latest

На докер облаке

docker ps -a

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9773e98eb12b andreissh/jenkins-docker-slave:latest «/usr/sbin/sshd -D -…» About a minute ago Up About a minute 0.0.0.0:49284->22/tcp, :::49283->22/tcp mystifying_johnson

Jenkins logs

jenkins | 2023-01-12 11:59:30.280+0000 [id=3267] INFO c.n.j.p.d.DockerContainerWatchdog#execute: Docker Container Watchdog has been triggered
jenkins | 2023-01-12 11:59:30.280+0000 [id=3267] INFO c.n.j.p.d.DockerContainerWatchdog$Statistics#writeStatisticsToLog: Watchdog Statistics: Number of overall executions: 239, Executions with processing timeout: 0, Containers removed gracefully: 10, Containers removed with force: 0, Containers removal failed: 0, Nodes removed successfully: 0, Nodes removal failed: 0, Container removal average duration (gracefully): 1153 ms, Container removal average duration (force): 0 ms, Average overall runtime of watchdog: 50 ms, Average runtime of container retrieval: 15 ms
jenkins | 2023-01-12 11:59:30.280+0000 [id=3267] INFO c.n.j.p.d.DockerContainerWatchdog#loadNodeMap: We currently have 0 nodes assigned to this Jenkins instance, which we will check
jenkins | 2023-01-12 11:59:30.281+0000 [id=3267] INFO c.n.j.p.d.DockerContainerWatchdog#execute: Checking Docker Cloud docker_ubuntu_esxi2 at tcp://10.15.253.223:2375
jenkins | 2023-01-12 11:59:30.288+0000 [id=3267] INFO c.n.j.p.d.DockerContainerWatchdog#cleanUpSuperfluousContainers: Container 9773e98eb12b5b6b7e24a52f734465242949ab563b3c927dbe05627a3dda615b, which is reported to be assigned to node docker_slave_ssh-000hxyehdkxzs, is no longer associated (node might be gone already?). The container’s last status is Up 3 minutes; it was created on 1673524577
jenkins | 2023-01-12 11:59:32.041+0000 [id=3267] INFO i.j.docker.DockerTransientNode$2#println: Stopped container ‘9773e98eb12b5b6b7e24a52f734465242949ab563b3c927dbe05627a3dda615b’ (orphaned container found by DockerContainerWatchdog).
jenkins | 2023-01-12 11:59:32.206+0000 [id=3267] INFO i.j.docker.DockerTransientNode$2#println: Removed container ‘9773e98eb12b5b6b7e24a52f734465242949ab563b3c927dbe05627a3dda615b’ (orphaned container found by DockerContainerWatchdog).
jenkins | 2023-01-12 11:59:32.207+0000 [id=3267] INFO c.n.j.p.d.DockerContainerWatchdog#terminateContainerGracefully: Successfully terminated orphaned container 9773e98eb12b5b6b7e24a52f734465242949ab563b3c927dbe05627a3dda615b
jenkins | 2023-01-12 11:59:32.207+0000 [id=3267] INFO c.n.j.p.d.DockerContainerWatchdog#execute: Docker Container Watchdog check has been completed
jenkins | 2023-01-12 11:59:49.803+0000 [id=3264] WARNING c.n.j.p.d.u.PortUtils$ConnectionCheck#execute: Could not connect to 10.15.253.223 port 49283. Are you sure this location is contactable from Jenkins?
jenkins | 2023-01-12 11:59:49.808+0000 [id=485] SEVERE c.g.d.a.a.ResultCallbackTemplate#onError: Error during callback
jenkins | com.github.dockerjava.api.exception.NotFoundException: Status 404: {«message»:»No such container: 9773e98eb12b5b6b7e24a52f734465242949ab563b3c927dbe05627a3dda615b»}
jenkins |
jenkins | at com.github.dockerjava.netty.handler.HttpResponseHandler.channelRead0(HttpResponseHandler.java:97)
jenkins | at com.github.dockerjava.netty.handler.HttpResponseHandler.channelRead0(HttpResponseHandler.java:32)
jenkins | at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99)
jenkins | at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
jenkins | at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
jenkins | at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:355)
jenkins | at io.netty.handler.logging.LoggingHandler.channelRead(LoggingHandler.java:271)
jenkins | at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
jenkins | at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
jenkins | at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:355)
jenkins | at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
jenkins | at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
jenkins | at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
jenkins | at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:355)
jenkins | at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
jenkins | at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:321)
jenkins | at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:295)
jenkins | at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
jenkins | at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
jenkins | at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
jenkins | at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:355)
jenkins | at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:286)
jenkins | at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
jenkins | at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
jenkins | at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:355)
jenkins | at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
jenkins | at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
jenkins | at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
jenkins | at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
jenkins | at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
jenkins | at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714)
jenkins | at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650)
jenkins | at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576)
jenkins | at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
jenkins | at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
jenkins | at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
jenkins | at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
jenkins | at java.base/java.lang.Thread.run(Thread.java:829)
jenkins | 2023-01-12 11:59:49.809+0000 [id=3264] INFO c.n.j.p.docker.DockerTemplate#doProvisionNode: Unable to remove container ‘9773e98eb12b5b6b7e24a52f734465242949ab563b3c927dbe05627a3dda615b’ as it had already gone.
jenkins | 2023-01-12 11:59:49.810+0000 [id=3264] SEVERE c.n.j.p.docker.DockerCloud$1#run: Error in provisioning; template=’DockerTemplate{configVersion=2, labelString=’docker_slave_ssh’, connector=DockerComputerSSHConnector{sshKeyStrategy=ManuallyConfiguredSSHKey{credentialsId=’fbe72464-8935-4a5c-966c-8e96c76a82fc’, sshHostKeyVerificationStrategy=hudson.plugins.sshslaves.verifiers.NonVerifyingKeyVerificationStrategy@4b94c769}, port=22, maxNumRetries=10, retryWaitTime=21}, instanceCap=2147483647, mode=NORMAL, retentionStrategy=com.nirima.jenkins.plugins.docker.strategy.DockerOnceRetentionStrategy@2c, dockerTemplateBase=DockerTemplateBase{image=’andreissh/jenkins-docker-slave:latest’, bindAllPorts=false, cpuPeriod=0, cpuQuota=0, privileged=false, tty=false}, removeVolumes=false, stopTimeout=10, pullStrategy=PULL_ALWAYS, pullTimeout=300, disabled=BySystem,0 ms,4 min 59 sec,Template provisioning failed., name=’docker_slave_ssh’}’ for cloud=’docker_ubuntu_esxi2′
jenkins | java.io.IOException: SSH service hadn’t started after 210 seconds and 15 milliseconds.Try increasing the number of retries (currently 10) and/or the retry wait time (currently 21) to allow for containers taking longer to start.
jenkins | at io.jenkins.docker.connector.DockerComputerSSHConnector.createLauncher(DockerComputerSSHConnector.java:326)
jenkins | at io.jenkins.docker.connector.DockerComputerConnector.createLauncher(DockerComputerConnector.java:176)
jenkins | at com.nirima.jenkins.plugins.docker.DockerTemplate.doProvisionNode(DockerTemplate.java:746)
jenkins | at com.nirima.jenkins.plugins.docker.DockerTemplate.provisionNode(DockerTemplate.java:683)
jenkins | at com.nirima.jenkins.plugins.docker.DockerCloud$1.run(DockerCloud.java:376)
jenkins | at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:30)
jenkins | at jenkins.security.ImpersonatingExecutorService$1.run(ImpersonatingExecutorService.java:70)
jenkins | at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
jenkins | at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
jenkins | at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
jenkins | at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
jenkins | at java.base/java.lang.Thread.run(Thread.java:829)
jenkins | 2023-01-12 11:59:56.120+0000 [id=50] WARNING hudson.slaves.NodeProvisioner#update: Unexpected exception encountered while provisioning agent Image of andreissh/jenkins-docker-slave:latest
jenkins | java.io.IOException: SSH service hadn’t started after 210 seconds and 15 milliseconds.Try increasing the number of retries (currently 10) and/or the retry wait time (currently 21) to allow for containers taking longer to start.
jenkins | at io.jenkins.docker.connector.DockerComputerSSHConnector.createLauncher(DockerComputerSSHConnector.java:326)
jenkins | at io.jenkins.docker.connector.DockerComputerConnector.createLauncher(DockerComputerConnector.java:176)
jenkins | at com.nirima.jenkins.plugins.docker.DockerTemplate.doProvisionNode(DockerTemplate.java:746)
jenkins | at com.nirima.jenkins.plugins.docker.DockerTemplate.provisionNode(DockerTemplate.java:683)
jenkins | at com.nirima.jenkins.plugins.docker.DockerCloud$1.run(DockerCloud.java:376)
jenkins | at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:30)
jenkins | at jenkins.security.ImpersonatingExecutorService$1.run(ImpersonatingExecutorService.java:70)
jenkins | at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
jenkins | at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
jenkins | at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
jenkins | at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
jenkins | at java.base/java.lang.Thread.run(Thread.java:829)
jenkins | 2023-01-12 12:04:30.280+0000 [id=3276] INFO c.n.j.p.d.DockerContainerWatchdog#execute: Docker Container Watchdog has been triggered
jenkins | 2023-01-12 12:04:30.280+0000 [id=3276] INFO c.n.j.p.d.DockerContainerWatchdog$Statistics#writeStatisticsToLog: Watchdog Statistics: Number of overall executions: 240, Executions with processing timeout: 0, Containers removed gracefully: 11, Containers removed with force: 0, Containers removal failed: 0, Nodes removed successfully: 0, Nodes removal failed: 0, Container removal average duration (gracefully): 1223 ms, Container removal average duration (force): 0 ms, Average overall runtime of watchdog: 57 ms, Average runtime of container retrieval: 15 ms
jenkins | 2023-01-12 12:04:30.280+0000 [id=3276] INFO c.n.j.p.d.DockerContainerWatchdog#loadNodeMap: We currently have 0 nodes assigned to this Jenkins instance, which we will check
jenkins | 2023-01-12 12:04:30.280+0000 [id=3276] INFO c.n.j.p.d.DockerContainerWatchdog#execute: Checking Docker Cloud docker_ubuntu_esxi2 at tcp://10.15.253.223:2375
jenkins | 2023-01-12 12:04:30.285+0000 [id=3276] INFO i.j.docker.client.DockerAPI$1#entryDroppedFromCache: Dropped connection io.jenkins.docker.client.DockerAPI$SharableDockerClient@6d93f1c6 to DockerClientParameters{dockerUri=’tcp://10.15.253.223:2375′, credentialsId=’null’, readTimeoutInMsOrNull=300000, connectTimeoutInMsOrNull=60000}
jenkins | 2023-01-12 12:04:30.293+0000 [id=3276] INFO c.n.j.p.d.DockerContainerWatchdog#execute: Docker Container Watchdog check has been completed

Failed to capture container inspection data: No serializer found for class java.lang.Object and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.github.dockerjava.api.command.InspectContainerResponse[«Config»]->com.github.dockerjava.api.model.ContainerConfig[«ExposedPorts»]->java.util.HashMap[«22/tcp»])

Pipeline Debug

Создайте файл

Jenkinsfile.template

и скопируйте его содержание в Pipeline → Definition → Pipeline script

В нём содержится ошибка, которую мы обнаружим в процессе

pipeline {
agent {
node {
label ‘jenkins-agent-goes-here’
}
}
stages {
stage(‘Build’) {
steps {
echo «Building..»
sh »’
echo «doing build stuff..»
»’
}
}
stage(‘Test’) {
steps {
echo «Testing..»
sh »’
echo «doing test stuff..
»’
}
}
stage(‘Deliver’) {
steps {
echo ‘Deliver….’
sh »’
echo «doing delivery stuff..»
»’
}
}
}
}

Jenkins Pipeline script изображение с сайта www.andreyolegovich.ru

Declarative Pipeline


www.andreyolegovich.ru

label нужно заменить на label вашего агента, который подходит для данного задания. В прошлом примере
это был demo-docker-slave, сейчас я переименовал его в docker_slave_ssh

pipeline {
agent {
node {
label ‘docker_slave_ssh
}
}

Запустим Pipeline и изучим статус

Jenkins Pipeline script изображение с сайта www.andreyolegovich.ru

Pipeline завалилась на тестах


www.andreyolegovich.ru

Jenkins Pipeline test logs изображение с сайта www.andreyolegovich.ru
Pipeline Test Logs


www.andreyolegovich.ru

/home/jenkins/workspace/my_first_build_pipeline@tmp/durable-9a278627/script.sh: 3: Syntax error: Unterminated quoted string

В скрипте забыта закрывающая кавычка в стадии Test

groovy.lang.MissingPropertyException: No such property: XXX for class: groovy.lang.Binding

groovy.lang.MissingPropertyException: No such property: USER_NAME for class: groovy.lang.Binding

Эта ошибка может возникнуть, когда вы забыли взять какое-либо значение в кавычки

withCredentials([
usernamePassword(credentialsId: ‘my_credentials’,
usernameVariable: USER_NAME,
passwordVariable: ‘MY_PWD’)])
{
echo «USER: ${MY_USER} PWD: ${MY_PWD}»
}

Нужно добавить кавычки.

withCredentials([
usernamePassword(credentialsId: ‘my_credentials’,
usernameVariable: ‘USER_NAME’,
passwordVariable: ‘MY_PWD’)])
{
echo «USER: ${MY_USER} PWD: ${MY_PWD}»
}

Я видел на Youtube ролик с полумиллионом просмотров, где девушка показывает переменные без кавычек
и не запускает джобу, возможно ваша проблема родом оттуда.

Статьи про Jenkins

Jenkins
Установка Jenkins
Основы Jenkins
Jenkins Pipeline
Задания по расписанию
Разбор ошибок
DevOps
Docker
Make

Contents

  • 1 External
  • 2 Internal
  • 3 Scripted Pipeline
    • 3.1 Scripted Pipeline at Runtime
    • 3.2 Scripted Pipeline Failure Handling
  • 4 Declarative Pipeline
    • 4.1 Declarative Pipeline Directives
      • 4.1.1 environment
      • 4.1.2 parameters
    • 4.2 Declarative Pipeline Failure Handling
  • 5 Parameters
  • 6 Environment Variables
  • 7 Pipeline Steps
    • 7.1 node
    • 7.2 stage
    • 7.3 parallel
    • 7.4 sh
      • 7.4.1 sh — Script Return Status
      • 7.4.2 sh — Script stdout
      • 7.4.3 sh — Obtaining both the Return Status and stdout
      • 7.4.4 sh — Obtaining stdout and Preventing the Pipeline to Fail on Error
      • 7.4.5 sh — Label
    • 7.5 ws
    • 7.6 build
    • 7.7 junit
    • 7.8 checkout
      • 7.8.1 Git Plugin
    • 7.9 withCredentials
    • 7.10 Basic Steps
      • 7.10.1 echo
      • 7.10.2 error
      • 7.10.3 stash
      • 7.10.4 input
      • 7.10.5 timeout
      • 7.10.6 withEnv
      • 7.10.7 catchError
    • 7.11 Basic Steps that Deal with Files
      • 7.11.1 dir
      • 7.11.2 deleteDir
      • 7.11.3 pwd
      • 7.11.4 readFile
      • 7.11.5 writeFile
      • 7.11.6 fileExists
      • 7.11.7 findFiles
    • 7.12 Core
      • 7.12.1 archiveArtifacts
      • 7.12.2 fingerprint
  • 8 Obtaining the Current Pipeline Build Number
  • 9 FlowInterruptedException
  • 10 Navigating the Project Model Hierarchy
  • 11 Passing an Environment Variable from Downstream Build to Upstream Build
  • 12 @NonCPS
  • 13 Build Summary
  • 14 Dynamically Loaded Classes and Constructors
  • 15 Fail a Build
  • 16 Dynamically Loading Groovy Code from Repository into a Pipeline
  • 17 Groovy on Jenkins Idiosyncrasies
    • 17.1 Prefix Static Method Invocations with Declaring Class Name when Calling from Subclass

External

  • https://jenkins.io/doc/book/pipeline/syntax/
  • https://jenkins.io/doc/pipeline/steps/
  • https://jenkins.io/doc/pipeline/steps/core/

Internal

  • Jenkins Concepts
  • Writing a Jenkins Pipeline
  • Simple Pipeline Configuration

Scripted Pipeline

https://www.jenkins.io/doc/book/pipeline/syntax/#scripted-pipeline

Scripted Pipeline is classical way of declaring Jenkins Pipeline, preceding Declarative Pipeline. Unlike the Declarative Pipeline, the Scripted Pipeline is a general-purpose DSL built with Groovy. The pipelines are declared in Jenkinsfiles and executed from the top of the Jenkinsfile downwards, like most traditional scripts in Groovy. Groovy syntax is available directly in the Scripted Pipeline declaration. The flow control can be declared with if/else conditionals or via Groovy’s exception handling support with try/catch/finally.

The simplest pipeline declaration:

A more complex one:

node('some-worker-label') {
 
  echo 'Pipeline logic starts'
 
  stage('Build') {
    if (env.BRANCH_NAME == 'master') {
      echo 'this is only executed on master'
    }
    else {
       echo 'this is executed elsewhere'
    }
  }
  stage('Test') {
    // ...
  }
  stage('Deploy') {
    // ...
  }
  stage('Example') {
    try {
      sh 'exit 1'
    }
    catch(ex) {
      echo 'something failed'
      throw
    }
  }
}

The basic building block of the Scripted Pipeline syntax is the step. The Scripted Pipeline does not introduce any steps that are specific to its syntax. The generic pipeline steps, such as node, stage, parallel, etc. are available here: Pipeline Steps.

Scripted Pipeline at Runtime

When the Jenkins server starts to execute the pipeline, it pulls the Jenkinsfile either from a repository, following a checkout sequence similar to the one shown here, or from the pipeline configuration, if it is specified in-line. Then the Jenkins instance instantiates a WorkflowScript (org.jenkinsci.plugins.workflow.cps.CpsScript.java) instance. The «script» instance can be used to access the following state elements:

  • pipeline parameters, with this.params, which is a Map.

Scripted Pipeline Failure Handling

Scripted pipeline fail when an exception is thrown and reached the pipeline layer. The pipeline code can use try/catch/finally semantics to control this behavior, by catching the exceptions and preventing them from reaching the pipeline layer.

stage('Some Stage') {
  try {
    throw new Exception ("the build has failed")
  }
  catch(Exception e) {
    // squelch the exception, the pipeline will not fail
  }
}

The pipeline also fails when a command invoked with sh exits with a non-zero exit code. The underlying implementation throws an exception and that makes the build fail. It is possible to configure sh to not fail the build automatically on non-zero exit code, with its returnStatus option.
The first failure in a sequential execution will stop the build, no subsequent stages will be executed. The stage that caused the failure will be shown in red in Blue Ocean (in the example below, there were three sequential stages but stage3 did not get executed):

Failed Jenkins Stage.png

In this case the corresponding stage and the entire build will be marked as ‘FAILURE’.

A build can be programmatically marked as fail by setting the value of the currentBuild.result variable:

currentBuild.result = 'FAILURE'

The entire build will be marked as failed (‘FAILURE’, ‘red’ build), but the stage in which the variable assignment was done, stage2 in this case, will not show as failed:

Programmatic Jenkins Red Build.png

The opposite behavior of marking a specific stage as failed (‘FAILURE’), but allowing the overall build to be successful can be obtained by using the catchError basic step:

stage('stage2') {
  catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
    throw new RuntimeException("synthetic")
  }
}

The result is a failed ‘stage2’ but a successful build:

Programmatic Jenkins Red Stage.png

A stage result and the entire build result may be also influenced by the JUnit test report produced for the stage, if any. If the test report exists and it is processed by the junit step, and if the report contains test errors and failures, they’re both handled as «instability» of the build and the corresponding stage and the entire build will be marked as UNSTABLE. The classic view and Blue ocean will render a yellow stage and build:

Unstable and Stable Jenkins Stages.png

Also see junit below and:

currentBuild.result
currentBuild.currentResult

Declarative Pipeline

https://www.jenkins.io/doc/book/pipeline/syntax/#declarative-pipeline

Declarative Pipeline is a new way of declaring Jenkins pipelines, and consists in a more simplified and opinionated syntax. Declarative Pipeline is an alternative to Scripted Pipeline.

 pipeline { 
     agent any 
     options {
         skipStagesAfterUnstable()
     }
     stages {
         stage('Build') { 
             steps { 
                 sh 'make' 
             }
         }
         stage('Test'){
             steps {
                 sh 'make check'
                 junit 'reports/**/*.xml' 
             }
         }
         stage('Deploy') {
             steps {
                 sh 'make publish'
             }
         }
     }
 }

Declarative Pipeline Directives

environment

https://jenkins.io/doc/book/pipeline/syntax/#environment

See:

Jenkins Pipeline Environment Variables

parameters

https://jenkins.io/doc/book/pipeline/syntax/#parameters

See:

Jenkins Pipeline Parameters

Declarative Pipeline Failure Handling

TODO: https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#handling-failure

Parameters

Jenkins Pipeline Parameters

Environment Variables

Jenkins Pipeline Environment Variables

Pipeline Steps

https://jenkins.io/doc/pipeline/steps/

node

https://jenkins.io/doc/pipeline/steps/workflow-durable-task-step/#-node-allocate-node

Allocates an executor or a node, typically a worker, and runs the enclosed code in the context of the workspace of that worker. Node may take a label name, computer name or an expression. The labels are declared on workers when they are defined in the master configuration, in their respective «clouds».

String NODE_LABEL = 'infra-worker'

node(NODE_LABEL) {
  sh 'uname -a'
}

stage

https://www.jenkins.io/doc/pipeline/steps/pipeline-stage-step/#stage-stage

The stage step defines a logical stage of the pipeline. The stage creates a labeled block in the pipeline and allows executing a closure in the context of that block:

stage('stage A') {
  print 'pipeline> in stage A'
}
stage('stage B') {
  print 'pipeline> in stage B'
}

Jenkins Pipeline Stages.png

Embedded stages as in this example are possible, and they will execute correctly, but they do not render well in Blue Ocean (Stage A.1 and Stage A.2 are not represented, just Stage A and B):

stage('stage A') {
  print('pipeline> in stage A')
    stage('stage A.1') {
      print('pipeline> in stage A.1')
    }
    stage('stage A.2') {
      print('pipeline> in stage A.1')
    }
  }
  stage('stage B') {
    print('pipeline> in stage B')
  }
}

To control failure behavior at stage level, use catchError step, described below.

parallel

https://www.jenkins.io/doc/pipeline/steps/workflow-cps/#parallel-execute-in-parallel

Takes a map from branch names to closures and an optional argument failFast, and executes the closure code in parallel.

parallel firstBranch: {
  // do something
}, secondBranch: {
  // do something else
},
failFast: true|false
stage("tests") {
  parallel(
    "unit tests": {
      // run unit tests 
    },
    "coverage tests": {
      // run coverage tests
    }
  )
}

Allocation to different nodes can be performed inside the closure:

def tasks = [:]
tasks["branch-1"] = {
  stage("task-1") {
    node('node_1') {
       sh 'echo $NODE_NAME'
    }
  }
}
tasks["branch-2"] = {
  stage("task-2") {
    node('node_1') {
       sh 'echo $NODE_NAME'
    }
  }
}
parallel tasks

sh

https://www.jenkins.io/doc/pipeline/steps/workflow-durable-task-step/#sh-shell-script
Playground sh

Execute a shell script command, or multiple commands, on multiple lines. It can be specified in-line or it can refer to a file available on the filesystem exposed to the Jenkins node. It needs to be enclosed by a node to work.

The metacharacter $ must be escaped: ${LOGDIR}, unless it refers to a variable form the Groovy context.

Example:

  stage.sh """
    LOGDIR=${fileName}-logs
    mkdir -p ${LOGDIR}/something
  """.stripIndent()
  stage.sh '''
    LOGDIR=some-logs
    mkdir -p ${LOGDIR}/something
  '''.stripIndent()

Both """...""" and '''...''' Groovy constructs can be used. For more details on enclosing representing multi-line strings with """ or ''', see:

Groovy | Multi-Line_Strings
sh — Script Return Status

By default, a script exits with a non-zero return code will cause the step and the pipeline to fail with an exception:

ERROR: script returned exit code 1

To prevent that, configure returnStatus to be equal with true, and the step will return the exit value of the script, instead of failing on non-zero exit value. You may then compare to zero and decide whether to fail the pipeline (throw an exception) or not from the Groovy layer that invoked sh.

int exitCode = sh(returnStatus: true, script: './bin/do-something')
if (exitCode != 0) throw new RuntimeException('my script failed')

The pipeline log result on failure looks similar to:

[Pipeline] End of Pipeline
java.lang.RuntimeException: my script failed
	at WorkflowScript.run(WorkflowScript:17)
...

Also see Scripted Pipeline Failure Handling section above.

sh — Script stdout

By default, the standard output of the script is send to the log. If returnStdout is set to true, the script standard output is returned as String as the step value. Call trim() to strip off the trailing newline.

The script’s stderr is always sent to the log.

String result = sh(returnStdout: true, script: './bin/do-something').trim()
sh — Obtaining both the Return Status and stdout

If both returnStatus and returnStdout are turned on, returnStatus takes priority and the function returns the exit code. ⚠️ The stdout is discarded.

sh — Obtaining stdout and Preventing the Pipeline to Fail on Error

In case you want to use the external shell command to return a result to the pipeline, but not fail the pipeline when the external command fails, use this pattern:

try {
  String stdout = sh(returnStdout: true, returnStatus: false, script: 'my-script')
  // use the content returned by stdout in the pipeline
  print "we got this as result of sh invocation: ${stdout.trim()}"
}
catch(Exception e) {
  // catching the error will prevent pipeline failure, both stdout and stderr are captured in the pipeline log
  print "the invocation failed"
}

If the command fails, both its stdout and stderr are captured in the pipeline log.

sh — Label

If a «label» argument is specified, the stage will render that label in the Jenkins and Blue Ocean logs:

sh(script: './bin/do-something', label: 'this will show in logs')

ws

https://jenkins.io/doc/pipeline/steps/workflow-durable-task-step/#-ws-allocate-workspace

Allocate workspace.

build

https://jenkins.io/doc/pipeline/steps/pipeline-build-step/

This is how a main pipeline launches in execution a subordinate pipeline.

This is how we may be able to return the result: https://support.cloudbees.com/hc/en-us/articles/218554077-How-to-set-current-build-result-in-Pipeline

junit

https://jenkins.io/doc/pipeline/steps/junit/#-junit-archive-junit-formatted-test-results

Jenkins understands the JUnit test report XML format (which is also used by TestNG). To use this feature, set up the build to run tests, which will generate their test reports into a local agent directory, then specify the path to the test reports in Ant glob syntax to the JUnit plugin pipeline step junit:

stage.junit '**/target/*-report/TEST-*.xml'

⚠️ Do not specify the path to a single test report file. The junit step will not load the file, even if it exists and it is a valid report, and will print an error message similar to:

[Pipeline] junit
Recording test results
No test report files were found. Configuration error?

Always use Ant glob syntax to specify how the report(s) are to be located:

Jenkins uses this step to ingest the test results, process them and provide historical test result trends, a web UI for viewing test reports, tracking failures, etc.

Both JUnit errors and failures are reported by the junit step as «failures», even if the JUnit XML report indicates both errors and failures. The following JUnit report:

<testsuite name="testsuite1" tests="2" errors="1" failures="1">
  <testcase name="test1" classname="test1">
    <error message="I have errored out"></error>
  </testcase>
  <testcase name="test2" classname="test2">
    <failure message="I have failed"></failure>
  </testcase>
</testsuite>

produces this Jenkins report:

Jenkins JUnit Errors and Failures.png

The presence of at least one JUnit failure marks the corresponding stage, and the entire build as «UNSTABLE». The stage is rendered in the classical view and also in Blue Ocean in yellow:

Unstable Jenkins Stage.png

Also see: Scripted Pipeline Failure Handling above.

checkout

https://www.jenkins.io/doc/pipeline/steps/workflow-scm-step/

The «checkout» step is provided by the pipeline «SCM» plugin.

Git Plugin
https://plugins.jenkins.io/git/
checkout([
  $class: 'GitSCM',
  branches: [[name: 'develop']],
  doGenerateSubmoduleConfigurations: false,
  extensions: [
    [$class: 'GitLFSPull'],
    [$class: 'CloneOption', noTags: true, reference: '', timeout: 40, depth: 1],
    [$class: 'PruneStaleBranch']
  ],
  submoduleCfg: [],
  userRemoteConfigs: [
    [url: 'git@github.com:some-org/some-project.git',
     credentialsId: 'someCredId']
  ]
])

The simplest configuration that works:

checkout([
        $class: 'GitSCM',
        branches: [[name: 'master']],
        userRemoteConfigs: [
                [url: 'https://github.com/ovidiuf/playground.git']
        ]
])

The step checks out the repository into the current directory, in does not create a top-level directory (‘some-project’ in this case). .git will be created in the current directory. If the current directory is the workspace, .git will be created in the workspace root.

withCredentials

A step that allows using credentials defined in the Jenkins server. See:

Jenkins Credentials Binding Plugin

Basic Steps

These basic steps are used invoking on stage.. In a Jenkinsfile, and inside a stage, invoke on this. or simply invoking directly, without qualifying.

echo

echo "pod memory limit: ${params.POD_MEMORY_LIMIT_Gi}"
                      echo """
Run Configuration:

    something: ${SOMETHING}
    something else:         ${SOMETHING_ELSE}
"""

error

https://jenkins.io/doc/pipeline/steps/workflow-basic-steps/#error-error-signal

This step signals an error and fails the pipeline.

Alternatively, you can simply:

throw new Exception("some message")

stash

https://jenkins.io/doc/pipeline/steps/workflow-basic-steps/#stash-stash-some-files-to-be-used-later-in-the-build

input

https://jenkins.io/doc/pipeline/steps/pipeline-input-step/

In its basic form, renders a «Proceed»/»Abort» input box with a custom message. Selecting «Proceed» passes the control to the next step in the pipeline. Selecting «Abort» throws a org.jenkinsci.plugins.workflow.steps.FlowInterruptedException, which produces «gray» pipelines.

input(
    id: 'Proceed1',
    message: 'If the manual test is successful, select 'Proceed'. Otherwise, you can abort the pipeline.'
)

timeout

https://jenkins.io/doc/pipeline/steps/workflow-basic-steps/#-timeout-enforce-time-limit

Upon timeout, an org.jenkinsci.plugins.workflow.steps.FlowInterruptedException is thrown from the closure that is being executed, and not from the timeout() invocation. The code shown below prints «A», «B», «D»:

timeout(time: 5, unit: 'SECONDS') {

     echo "A"

     try {

           echo "B"

           doSometing(); // this step takes a very long time and will time out

           echo "C"
     }
     catch(org.jenkinsci.plugins.workflow.steps.FlowInterruptedException e) {

            // if this exception propagates up without being caught, the pipeline gets aborted

           echo "D"
     }
}

withEnv

https://jenkins.io/doc/pipeline/steps/workflow-basic-steps/#withenv-set-environment-variables

Sets one more more environment variables within a block, making them available to any external process initiated within that scope. If a variable value contains spaces, it does need to be quoted inside the sequence, as shown below:

node {
  withEnv(['VAR_A=something', 'VAR_B=something else']) {
    sh 'echo "VAR_A: ${VAR_A}, VAR_B: ${VAR_B}"'
  }
}

catchError

https://www.jenkins.io/doc/pipeline/steps/workflow-basic-steps/#catcherror-catch-error-and-set-build-result-to-failure
catchError {
  sh 'some-command-that-might-fail'
}

If the body throws an exception, mark the build as a failure, but continue to execute the pipeline from the statement following catchError step. If an exception is thrown, the behavior can be configured to:

  • print a message
  • set the build result other than failure
  • change the stage result
  • ignore certain kinds of exceptions that are used to interrupt the build

If catchError is used, there’s no need for finally, as the exception is caught and does not propagates up.

The alternative is to use plain try/catch/finally blocks.
Configuration:

catchError(message: 'some message', stageResult: 'FAILURE'|'SUCCESS'|... , buildResult: 'FAILURE'|'SUCCESS'|..., catchInterruptions: true) {
  sh 'some-command-that-might-fail'
}
  • message an an optional String message that will be logged to the console. If the stage result is specified, the message will also be associated with that result and may be shown in visualizations.
  • stageResult an optional String that will set as stage result when an error is caught. Use SUCCESS or null to keep the stage result from being set when an error is caught.
  • buildResult an optional String that will be set as overall build result when an error is caught. Note that the build result can only get worse, so you cannot change the result to SUCCESS if the current result is UNSTABLE or worse. Use SUCCESS or null to keep the build result from being set when an error is caught.
  • catchInterruptions If true, certain types of exceptions that are used to interrupt the flow of execution for Pipelines will be caught and handled by the step. If false, those types of exceptions will be caught and immediately rethrown. Examples of these types of exceptions include those thrown when a build is manually aborted through the UI and those thrown by the timeout step.

The default behavior for catchInterruptions is «true»: the code executing inside catchError() will be interrupted, whether it is an external command or pipeline code, and the code immediately following catchError() closure is executed.

stage('stage1') {
  catchError() {
    sh 'jenkins/pipelines/failure/long-running'
  }
  print ">>>> post catchError()"
}
[Pipeline] stage
[Pipeline] { (stage1)
[Pipeline] catchError
[Pipeline] {
[Pipeline] sh
entering long running ....
sleeping for 60 secs
Aborted by ovidiu
Sending interrupt signal to process
jenkins/pipelines/failure/long-running: line 6:  5147 Terminated              sleep ${sleep_secs}
done sleeping, exiting long running ....
[Pipeline] }
[Pipeline] // catchError
[Pipeline] echo
>>>> post catchError()

However, it seems that the same behavior occurs if catchError() is invoked with catchInteruptions: true, so it’s not clear what is the difference..

Probably the safest way to invoke is to use this pattern, this way we’re sure that even some exceptions bubble up, the cleanup work will be performed:

stage('stage1') {
  try {
    catchError() {
      sh 'jenkins/pipelines/failure/long-running'
    }
  }
  finally {
    print ">>>> execute mandatory cleanup code"
  }
}

Also see Scripted Pipeline Failure Handling section above.

Basic Steps that Deal with Files

dir

https://www.jenkins.io/doc/pipeline/steps/workflow-basic-steps/#dir-change-current-directory

Change current directory, on the node, while the pipeline code runs on the master.

If the dir() argument is a relative directory, the new directory available to the code in the closure is relative to the current directory before the call, obtained with pwd():

dir("dirA") {
  // execute in the context of pwd()/dirA", where pwd() 
  // is the current directory before and a subdirectory of the workspace
}

If the dir() argument is an absolute directory, the new directory available to the code in the closure is the absolute directory specified as argument:

dir("/tmp") {
  // execute in /tmp
}

In both cases, the current directory is restored upon closure exit.

Also see:

Pipeline and Files

deleteDir

https://www.jenkins.io/doc/pipeline/steps/workflow-basic-steps/#deletedir-recursively-delete-the-current-directory-from-the-workspace

To recursively delete a directory and all its contents, step into the directory with dir() and then use deleteDir():

dir('tmp') {
  // ...
  deleteDir()
}

This will delete ./tmp content and the ./tmp directory itself.

pwd

https://www.jenkins.io/doc/pipeline/steps/workflow-basic-steps/#pwd-determine-current-directory

Return the current directory path on node as a string, while the pipeline code runs on the master.

Parameters:

tmp (boolean, optional) If selected, return a temporary directory associated with the workspace rather than the workspace itself. This is an appropriate place to put temporary files which should not clutter a source checkout; local repositories or caches; etc.

println "current directory: ${pwd()}"
println "temporary directory: ${pwd(tmp: true)}"

Also see:

Pipeline and Files

readFile

https://jenkins.io/doc/pipeline/steps/workflow-basic-steps/#readfile-read-file-from-workspace

Read a file from the workspace, on the node this operation is made in context of.

String versionFile = readFile("${stage.WORKSPACE}/terraform/my-module/VERSION")

If the file does not exist, the step throws java.nio.file.NoSuchFileException: /no/such/file.txt

writeFile

https://jenkins.io/doc/pipeline/steps/workflow-basic-steps/#writefile-write-file-to-workspace

writeFile will create any intermediate directory if necessary.

To create a directory, dir() into the inexistent directory then create a dummy file writeFile(file: '.dummy', text: ):

dir('tmp') {
  writeFile(file: '.dummy', text: '')
}

Alternatively, the directory can be created with a shell command:

Also see:

Pipeline and Files

fileExists

https://www.jenkins.io/doc/pipeline/steps/workflow-basic-steps/#fileexists-verify-if-file-exists-in-workspace

Also see:

Pipeline and Files

fileExists can be used on directories as well. This is how to check whether a directory exists:

dir('dirA') {
  if (fileExists('/')) {
     println "directory exists"
  }
  else {
     println "directory does not exist"
  }
}

fileExists('/'), fileExists('.') and fileExists('') are equivalent, they all check for the existence of a directory into which the last dir() stepped into. The last form fileExists('') issues a warning, so it’s not preferred:

The fileExists step was called with a null or empty string, so the current directory will be checked instead.

findFiles

https://www.jenkins.io/doc/pipeline/steps/pipeline-utility-steps/#findfiles-find-files-in-the-workspace

Find files in workspace:

def files = findFiles(glob: '**/Test-*.xml', excludes: '')

Uses Ant style pattern: https://ant.apache.org/manual/dirtasks.html#patterns
Returns an array of instance for which the following attributes are available:

  • name: the name of the file and extension, without any path component (e.g. «test1.bats»)
  • path: the relative path to the current directory set with dir(), including the name of the file (e.g. «dirA/subDirA/test1.bats»)
  • directory: a boolean which is true if the file is a directory, false otherwise.
  • length: length in bytes.
  • lastModified: 1617772442000

Example:

dir('test') {
  def files = findFiles(glob: '**/*.bats')
  for(def f: files) {
    print "name: ${f.name}, path: ${f.path}, directory: ${f.directory}, length: ${f.length}, lastModified: ${f.lastModified}"
  }
}

Playground:

playground/jenkins/pipelines/findFiles

Core

https://jenkins.io/doc/pipeline/steps/core/

archiveArtifacts

https://jenkins.io/doc/pipeline/steps/core/#-archiveartifacts-archive-the-artifacts

Archives the build artifacts (for example, distribution zip files or jar files) so that they can be downloaded later. Archived files will be accessible from the Jenkins webpage. Normally, Jenkins keeps artifacts for a build as long as a build log itself is kept. Note that the Maven job type automatically archives any produced Maven artifacts. Any artifacts configured here will be archived on top of that. Automatic artifact archiving can be disabled under the advanced Maven options.

fingerprint

Obtaining the Current Pipeline Build Number

def buildNumber = currentBuild.rawBuild.getNumber()

FlowInterruptedException

throw new FlowInterruptedException(Result.ABORTED)

Navigating the Project Model Hierarchy

String branch="..."
String projectName = JOB_NAME.substring(0, JOB_NAME.size() - JOB_BASE_NAME.size() - 1)
WorkflowMultiBranchProject project = Jenkins.instance.getItemByFullName("${projectName}")
if (project == null) {
  ...
}
WorkflowJob job = project.getBranch(branch)
if (job == null) {
  ...
}
WorkflowRun run = job.getLastSuccessfulBuild()
if (run == null) {
  ...
}
List<Run.Artifact> artifacts = run.getArtifacts()
...

Passing an Environment Variable from Downstream Build to Upstream Build

Upstream build:

...
def result = build(job: jobName,  parameters: params, quietPeriod: 0, propagate: true, wait: true);
result.getBuildVariables()["SOME_VAR"]
...

Downstream build:

env.SOME_VAR = "something"

@NonCPS

Jenkins Concepts | CPS

Build Summary

   //
   // write /tmp/summary-section-1.html
   // 

   def summarySection1 = util.catFile('/tmp/summary-section-1.html')
   if (summarySection1) {
     def summary = manager.createSummary('document.png')
     summary.appendText(summarySection1, false)
   }

   //
   // write /tmp/summary-section-2.html
   // 

   def summarySection2 = util.catFile('/tmp/summary-section-2.html')
   if (summarySection2) {
     def summary = manager.createSummary('document.png')
     summary.appendText(summarySection2, false)
   }

Dynamically Loaded Classes and Constructors

If classes are loaded dynamically in the Jenkinsfile, do not use constructors and new. Use MyClass.newInstance(…).

Fail a Build

See error above.

Dynamically Loading Groovy Code from Repository into a Pipeline

This playground example shows how to dynamically load Groovy classes stored in a GitHub repository into a pipeline.

The example is not complete, in that invocation of a static method from Jenkinsfile does not work yet.

https://github.com/ovidiuf/playground/tree/master/jenkins/pipelines/dynamic-groovy-loader

Groovy on Jenkins Idiosyncrasies

Prefix Static Method Invocations with Declaring Class Name when Calling from Subclass

Prefix the static method calls with the class name that declares them when calling from a subclass, otherwise you’ll get a:

hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: java.lang.Class.locateOverlay() is applicable for argument types: (WorkflowScript, playground.jenkins.kubernetes.KubernetesCluster, playground.jenkins.PlatformVersion, java.lang.String, java.lang.String) values: [WorkflowScript@1db9ab90, <playground.jenkins.kubernetes.KubernetesCluster@376dc438>, ...]

Jenkins is an automation server. It allows for all kinds of automations. It is primarily used for Build automation, Continuous Integration, and Continuous Deployment.

Installations

  1. Install Jenkins on Ubuntu (using Vagrant)
  2. Vagrant for Jenkins on Ubuntu
  3. Jenkins in Docker

Examples

  1. Jenkins Pipeline — Hello World (pipeline, agent, stages, stage, stpes, echo)
  2. Jenkins Pipeline: running external programs with sh or bat, returnStdout, trim
  3. Jenkins Pipeline: Send e-mail notifications
  4. Jenkins Pipeline: Add some text to the job using manager.addShortText
  5. Jenkins CLI: create node
  6. Jenkins Pipeline BuildUser plugin
  7. Jenkins Pipeline — set and use environment variables
  8. Jenkins Pipeline: git checkout using reference to speed up cloning large repositories
  9. Jenkins report the name of the stage that failed (STAGE_NAME)
  10. Jenkins Pipeline: triggers from Version Control Systems (pollSCM)
  11. How to set the job number and description for a Jenkinsfile in a Jenkins Pipeline? (currentBuild, displayName, description)
  12. Jenkins Pipeline: read a file, write a file — readFile, writeFile
  13. Separate jobs for development and production currentBuild, projectName
  14. Jenkins pipeline: get current user (currentBuild, getBuildCauses)
  15. Jenkins parameters
  16. Arbitrary code execution in the shell (sh, parameters)
  17. Jenkins pipeline: parallel stages
  18. Jenkins Pipeline: Collect exit code from external commands (sh, bat, returnStatus)
  19. Jenkins pipeline: Get previous build status — currentBuild, getPreviousBuild
  20. Jenkins pipeline: interactive input during process (input)
  21. Jenkins pipeline: List agents by name or by label
  22. Jenkins pipeline: add badges
  23. Report failures.
  24. Send alerts
  25. Collect test coverage data.
  26. Jenkins slides
  27. Jenkins printing Unicode characters

Run external code, capture output

script {
      v = sh(script: 'echo " 42"; echo', returnStdout: true).trim()
      echo v
      echo "a${v}b"
}

bat for windows.

catch and print error in jenkins

jenkins exception try — catch

Get a job’s console logfile from a Jenkins pipeline

pipeline {
   agent none
   stages {
       stage ('Catch crash') {
           agent { label 'master'}
           steps {
               echo "before crash"
               script {
                   try {
                       sh 'exit 1'
                   } catch (err) {
                       echo "exception caught, going on"
                       println err // java.lang.ClassCastException:
org.jenkinsci.plugins.workflow.steps.EchoStep.message expects class java.lang.String but received
class hudson.AbortException
                   }
               }
               echo "after crash"
           }
       }
       stage ('Continue after crash') {
           agent { label 'master'}
           steps {
               echo "stage after crash"
           }
       }
   }
}
                    try {
                        //sh "ls -l no_such"
                        a = 10
                        b = 0
                        c = a/b
                    }
                    catch(Exception ex) {
                         //currentBuild.result = 'FAILURE'
                        println("exception")
                        println(ex) // hudson.AbortException: script returned exit code 2
                        println(ex.toString())
                        println(ex.getMessage())
                        println(ex.getStackTrace())
                    }

dir and tmp are problematic

  stages {
       stage ('Run external exe') {
           agent { label 'master'}
           steps {
               sh 'pwd'
               dir('/tmp/gabor') {
                   echo "inside"
                   sh 'pwd'
                   //sh 'sudo ./do-something.py'
               }
               sh 'pwd'
               //sh "sudo sh -c 'cd /tmp; ./do-something.py; cd -'"
           }
       }

examples/jenkins/mkdir_exception.txt

java.io.IOException: Failed to mkdirs: /tmp@tmp/durable-e569697c
        at hudson.FilePath.mkdirs(FilePath.java:1170)
        at org.jenkinsci.plugins.durabletask.FileMonitoringTask$FileMonitoringController.<init>(FileMonitori
ngTask.java:156)
        at org.jenkinsci.plugins.durabletask.BourneShellScript$ShellController.<init>(BourneShellScript.java
:198)
        at org.jenkinsci.plugins.durabletask.BourneShellScript$ShellController.<init>(BourneShellScript.java
:190)
        at org.jenkinsci.plugins.durabletask.BourneShellScript.launchWithCookie(BourneShellScript.java:111)
        at org.jenkinsci.plugins.durabletask.FileMonitoringTask.launch(FileMonitoringTask.java:86)
        at org.jenkinsci.plugins.workflow.steps.durable_task.DurableTaskStep$Execution.start(DurableTaskStep
.java:182)
        at org.jenkinsci.plugins.workflow.cps.DSL.invokeStep(DSL.java:229)
        at org.jenkinsci.plugins.workflow.cps.DSL.invokeMethod(DSL.java:153)
        at org.jenkinsci.plugins.workflow.cps.CpsScript.invokeMethod(CpsScript.java:122)
        at sun.reflect.GeneratedMethodAccessor1989.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1213)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1022)
        at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:42)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
        at org.kohsuke.groovy.sandbox.impl.Checker$1.call(Checker.java:157)
        at org.kohsuke.groovy.sandbox.GroovyInterceptor.onMethodCall(GroovyInterceptor.java:23)
        at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onMethodCall(SandboxInterc
eptor.java:133)
        at org.kohsuke.groovy.sandbox.impl.Checker$1.call(Checker.java:155)
        at org.kohsuke.groovy.sandbox.impl.Checker.checkedCall(Checker.java:159)
        at org.kohsuke.groovy.sandbox.impl.Checker.checkedCall(Checker.java:129)
        at org.kohsuke.groovy.sandbox.impl.Checker.checkedCall(Checker.java:129)
        at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.methodCall(SandboxInvoker.java:17)
        at WorkflowScript.run(WorkflowScript:16)

Jenkins / Groovy — define functions and call them with parameters

def report(status) {
   println "status=${status}"
}

and call them

report("text")

Environment variables on Linux

sh 'printenv'
sh 'env'

git Backup

gist

Other

echo bat(returnStdout: true, script: 'set')

build(job: 'RevertServerAutomationCloud', parameters: [
     string(name: 'VM_SNAPSHOT', value: 'CleanDb')
])

how to include one jenkinsfile in another one?

how to avoid repetititon?

stage('Revert agent 100')
         {
             steps
                     {
                     }
         }

 stage('Revert agent 102')
         {
             steps
                     {

                     }
         }

how do try — catch and repeat interact?

vSphere buildStep: [$class: 'RevertToSnapshot', snapshotName: "${params.VM_SNAPSHOT}", vm: "${params.VM_NAME}"], serverName: '192.168.1.1'

httpRequest authentication: 'df8-b86d-3272', consoleLogResponseBody: true, httpMode: 'POST', ignoreSslErrors: true, responseHandle: 'NONE', url:
"http://192.168.1.1:8080/computer/${params.AGENT_NAME}/doDisconnect?offlineMessage=bye", validResponseCodes: '100:404'

Active Choices Parameter

examples/jenkins/array_list.txt

try {
   List<String> subnets = new ArrayList<String>()
   def subnetsRaw = "gcloud compute networks subnets list --project=${GCE_PROJECT} --network=corp-development --format=(NAME)".execute().text
   for (subnet in  subnetsRaw.split()) {
       subnets.add(subnet)
   }
   return subnets
} catch (Exception e) {
   print e
   print "There was a problem fetching the artifacts"
}

Options

   options {
       ansiColor('xterm')
       timestamps()
   }

Scripts

Scripts not permitted to use method groovy.lang.GroovyObject invokeMethod java.lang.String java.lang.Object
(org.jenkinsci.plugins.workflow.cps.EnvActionImpl keys). Administrators can decide whether to approve or reject this
signature.

archiveArtifacts can be called multiple times

archiveArtifacts artifacts: 'mydata.json', onlyIfSuccessful: true
writeJSON(file: 'otherfile.log', json: data, pretty: 4)
archiveArtifacts artifacts: '*.log', onlyIfSuccessful: true

Environment variable values must either be single quoted, double quoted, or function calls.

They cannot be earlier defined environment variables or parameter values.
We can however overcome this limitation by calling a function and passing the values to it.

examples/jenkins/exceptions.jenkinsfile

pipeline {
   agent none
   options {
       ansiColor('xterm')
       timestamps()
   }
   parameters {
       string(name: 'machine', defaultValue: 'asos', description: 'Some text input')
       string(name: 'size',   defaultValue: '23', description: 'Some number input')
   }
   environment {
       answer = 42
       // machine_name = params.machine  // -> Environment variable values must either be single quoted, double quoted, or function calls.
       machine_name = set_machine_name(params.machine)
   }
   stages {
       stage('try') {
           agent { label 'master' }
           steps {
               script {
                   sh "hostname"
                   print("params.machine=${params.machine}")
                   print("params.size=${params.size}")
                   print("env.answer=${env.answer}")
                   print("env.machine_name=${env.machine_name}")

               }
           }
       }
       stage('try-agent') {
           agent { label 'jenkins-simple-agent' }
           steps {
               script {
                   sh "hostname"
               }
           }
       }
   }
}

def set_machine_name(value) {
   return value
}


Jenkins environment

Even if there is an exception in the environment section Jenkins will still run the «success» part of the post section.
Same problem if there is an exception on one of the functions.

To overcome this we create an environment variable as the last step in the environment section
and then we check that variable using

if (! binding.hasVariable(‘environment_is_set’)) {
error(«Environment failed to set properly»)
}

That does not help in case there is an exception in the functions.

http_request

response = httpRequest discovery_url
println response
config_str = response.getContent()
for (item in config.sources) {
  item.value
  item.key

Sending e-mail problem fixed

https://stackoverflow.com/questions/20188456/how-to-change-the-security-type-from-ssl-to-tls-in-jenkins

* Sending e-mail
In Manage Jenkins — Configure System in the
Extended mail section set the
SMTP: smtp.office365.com
Domain name: @company.com
Advanced:
Use SMTP Authentication: +
User Name: cicdserver@company.com
Password: SMTP port: 587
E-mail notification section:
SMTP server: smtp.office365.com
Default user e-mail suffix: @company.com
Advanced
User Name: cicdserver@company.com
Password: SMTP port: 587

Shut down Jenkins (via the Windows services)
Open the file: C:Program Files (x86)Jenkinsjenkins.xml
and change the arguments line to be:

examples/jenkins/arguments.txt

<arguments>-Xrs -Xmx256m -Dhudson.lifecycle=hudson.lifecycle.WindowsServiceLifecycle  -Dmail.smtp.starttls.enable=true -jar
"%BASE%jenkins.war" --httpPort=8080 --webroot="%BASE%war"</arguments>

(specifically add: -Dmail.smtp.starttls.enable=true )
Then start Jenkins again.

Client was not authenticated to send anonymous mail
Error sending to the following VALID addresses

examples/jenkins/variables.Jenkinsfile

pipeline {
   agent none
   stages {
       stage('try') {
           agent { label 'master' }
           steps {
               script {
                   //some_strange_name = null
                   //print(some_strange_name)
                   if (true) {
                       print("creating variable")
                       some_strange_name = 1
                   }
                   print(some_strange_name)

                   if (binding.hasVariable('some_strange_name')) {
                       print("has some_strange_name")
                       print(some_strange_name)
                   } else {
                       print("DOES NOT have some_strange_name")
                   }
               }
           }
       }
       stage('try again') {
           agent { label 'master' }
           steps {
               script {
                   if (binding.hasVariable('some_strange_name')) {
                       print("has some_strange_name")
                       print(some_strange_name)
                   } else {
                       print("DOES NOT have some_strange_name")
                   }
               }
           }
       }
   }
}

Skip steps

Jenkins pipeline stop early with success
How to indicate that a job is successful
pipeline conditional step stage

examples/jenkins/skip_step.Jenkinsfile

pipeline {
   agent none
   options {
       ansiColor('xterm')
       timestamps()
   }
   parameters {
       booleanParam(defaultValue: false, description: 'Checkbox', name: 'yesno')
   }
   stages {
       stage('first') {
           agent { label 'master' }
           steps {
               script {
                   println("first before")
                   println(params.yesno)
                   done = true
                   return
                   println("first after")
               }
           }
       }
       stage('second') {
           agent { label 'master' }
           when {
               expression {
                  return ! done;
               }
           }
           steps {
               script {
                   println("second")
               }
           }
       }
   }
}

examples/jenkins/worker_job.Jenkinsfile

import java.text.SimpleDateFormat
pipeline {
   agent none
   options {
       ansiColor('xterm')
       timestamps()
   }
   parameters {
       string(name: 'machine', defaultValue: '', description: 'Name of the machine')
       string(name: 'size',   defaultValue: '23', description: 'The size')
       choice(choices: ['Mercury', 'Venus', 'Earth', 'Mars'], description:  'Pick a planet', name: 'planet')
   //}
   stages {
       stage('try') {
           agent { label 'master' }
           steps {
               script {
                   sh "hostname"

                   def data = readJSON text: '{}'
                   data.name = "test-529" as String
                   data.date = new java.text.SimpleDateFormat('yyyyMMddHHmmss').format(new Date())
                   writeJSON(file: 'mydata.json', json: data, pretty: 4)
                   archiveArtifacts artifacts: 'mydata.json', onlyIfSuccessful: true

                   //error("Fail after first artifact")

                   writeJSON(file: 'otherfile.log', json: data, pretty: 4)
                   archiveArtifacts artifacts: '*.log', onlyIfSuccessful: true
               }
           }
       }
   }
}

jenkins sh commnad fails — jenkins stops

examples/jenkins/sh_fails.jenkinsfile

pipeline {
   agent { label 'master' }
   stages {
       stage('only') {
           steps {
               println("one")
               sh "ls -l"
               println("two")
               sh "ls -l no_such"
               println("three")
           }
       }
   }
}

Repository branch filter for Git

It will start multiple jobs if more than one branch was pushed out.
It is triggered even if there were no new commits in the branch that was pushed out

By default it will run every branch matching the filter, even if that branch was last changed 2 years ago.
This can be a problem if for some reason your have hundreds or thousands of historical branches.

:^origin/(work|dev)-.*

You can limit this by selecting another option and setting the ancestry date to limit how many days
you are ready to go back in time.

  • Strategy for choosing what to build
  • Choosing strategy: Ancestry
  • Maximum Age of Commit: 1

In a pipeline

examples/jenkins/branch_filter_age_limit.jenkinsfile

checkout([
    $class: 'GitSCM',
    branches: [[name: '*/master']],
    doGenerateSubmoduleConfigurations: false,
    extensions: [[
        $class: 'BuildChooserSetting',
        buildChooser: [$class: 'AncestryBuildChooser', ancestorCommitSha1: '', maximumAgeInDays: 1]
    ]],
    submoduleCfg: [],
    userRemoteConfigs: [[]]
])

Jenkins Pipeline code reuse

https://cleverbuilder.com/articles/jenkins-shared-library/
https://jenkins.io/doc/book/pipeline/shared-libraries/

Exceptions

When you encounter one of those 40-lines long Java stack-traces, look for WorkflowScript to locate the source of the problem.

examples/jenkins/exception_catching.jenkinsfile

pipeline {
    agent { label 'master' }
    stages {
        stage('only') {
            steps {
                script {
                    println("one")
                    sh "ls -l"
                    println("two")

                    try {
                        //sh "ls -l no_such"
                        a = 10
                        b = 0
                        c = a/b

                    }
                    catch(Exception ex) {
                         //currentBuild.result = 'FAILURE'
                        println("exception")
                        println(ex) // hudson.AbortException: script returned exit code 2
                        println(ex.toString())
                        println(ex.getMessage())
                        println(ex.getStackTrace())
                    }

                    //} catch(ArrayIndexOutOfBoundsException ex) {
                    //println("Catching the Array out of Bounds exception");
                    //}catch(Exception ex) {

                    println("three")
                    is_it_the_answer(42)
                    echo "try again"
                    is_it_the_answer(23)
                }
            }
        }
        stage('second') {
            steps {
                script {
//                    if (manager.logContains("three")) {
//                        manager.addWarningBadge("tres")
//                    } else {
//                        manager.addWarningBadge("nem harom")
//                    }

                }
            }
        }
    }
}

def is_it_the_answer(n) {
    if (n == 42) {
        return 'yes'
    }
    throw new Exception('Nope')
}


                    try {
                        is_it_the_answer(23)
                    } catch (err) {
                        print(err)
                        print(err.getMessage())
                    }



Jenkins parse console output

The logContains can parse the log created be the previous stages (but not the current stage)
It can also be used in a post-action.

«manager» is org.jvnet.hudson.plugins.groovypostbuild.GroovyPostbuildRecorder$BadgeManager@41fe3861

Postbuild plugin

examples/jenkins/parse_console_output.jenkinsfile

        stage('second') {
            steps {
                script {
                    if (manager.logContains("three")) {
                        manager.addWarningBadge("drei")
                    } else {
                        manager.addWarningBadge("kein drei")
                    }
                }
            }
        }


         print("A disk image was created: zorg-1552278641")

         def matcher = manager.getLogMatcher(/.* (zorg-d+).*/)
         print(matcher)
         if (matcher?.matches()) {
             def image_name = matcher.group(1)
             print(image_name)
             manager.addShortText(image_name)
         }


readJSON

no such dsl method

jenkins build step

https://jenkins.io/doc/pipeline/steps/pipeline-build-step/

jenkins collect status from invoked jobs

examples/jenkins/status_from_build.Jenkinsfile

pipeline {
    agent { label 'master' }
    stages {
        stage('only') {
            steps {
                script {
                    println("BEFORE")
                    results = []
                    try {
                        def result = build job: "experiment-subproject", wait: true
                        println(result) // org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper
                        println(result.getId())
                    } catch(err) {
                        println("ERROR caught")
                        println(err) // hudson.AbortException: experiment-subproject #4 completed with status FAILURE (propagate: false to ignore)
                        // https://javadoc.jenkins-ci.org/hudson/AbortException.html
                        println(err.getMessage())
                        println(err.getStackTrace())
                        println(err.getCause())
                        println(err.getLocalizedMessage())
                        println(err.toString())
                    }
                    println("AFTER")

                    def res = build job: "experiment-subproject", wait: false
                    println(res) // null

                    rep = build job: "experiment-subproject", wait: true, propagate: false
                    println(rep) // org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper
                    println(rep.getId())
                    println(rep.getResult()) // FAILURE
                    println(rep.getDurationString())
                    results.push(rep)

                    //sh "ls -l"
                    //println("two")
                    //} catch(ArrayIndexOutOfBoundsException ex) {
                    //println("Catching the Array out of Bounds exception");
                    //}catch(Exception ex) {

                    //println("three")
                    //print("A disk image was created: jenkins-agent-1554 and then more")
                    //is_it_the_answer(42)
                    //echo "try again"
                    //try {
                    //    is_it_the_answer(23)
                    //} catch (err) {
                    //   print(err)
                    //    print(err.getMessage())
                    //}
                }
            }
        }
        stage('second') {
            steps {
                script {
                    echo "hi"
                    println(rep.getId())
                    println(rep.getResult()) // FAILURE
                    println(rep.getProjectName())
                    println(rep.getDisplayName())

                    def res = build job: "experiment-subproject", wait: true, propagate: false
                    results.push(res)

//                    if (manager.logContains("three")) {
//                        manager.addWarningBadge("tres")
//                    } else {
//                        manager.addWarningBadge("nem harom")
//                    }
                    //def image_name = ''
                    //def matcher = manager.getLogMatcher(/.* (jenkins-agent-(d+)).*/)
                    //print(matcher)
                    //if (matcher?.matches()) {
                    //    image_name = matcher.group(1)
                    //    println(image_name)
                    //    manager.addShortText(image_name)
                    //    println(image_name.getClass())
                    //}
                    //do_sg(image_name)
                }
            }
        }
        stage ('gitz') {
            agent { label 'build-small' }
            steps {
                script {
                    results.each {
                         println(it)
                         println(it.getId())
                         println(it.getResult()) // FAILURE
                         println(it.getProjectName())
                         println(it.getAbsoluteUrl())
                    }
                }
            }
        }
    }
}

def is_it_the_answer(n) {
    if (n == 42) {
        return 'yes'
    }
    throw new Exception('Nope')
}

def do_sg(name) {
    print("do_sg with $name")
}

links

https://jenkins.io/doc/pipeline/steps/

https://jenkins.io/doc/pipeline/steps/pipeline-build-step/#-build-%20build%20a%20job

https://jenkins.io/doc/pipeline/steps/pipeline-input-step/

               script {
                    manager.addShortText("n${params.cluserName}", "black", "yellow", "0px", "white")
                    manager.addShortText("${params.clusterId}-${params.command}", "black", "lightgreen", "0px", "white")
                    manager.addShortText("${params.services}", "black", "AliceBlue", "0px", "white")
                    if (params.usage) {
                        manager.addShortText("${params.usage}", "DimGray", "AliceBlue", "0px", "white")
                    }
                }

Elapsed time

examples/jenkins/elapsed_time.Jenkinsfile

import groovy.time.TimeCategory
import groovy.time.TimeDuration

pipeline {
    agent { label 'master' }
    stages {
        stage('first') {
            steps {
                script {
                    start = new Date()
                    echo "in first"
                }
            }
        }
        stage('second') {
            steps {
                script {
                    echo "in second"
                }
            }
        }
    }
    post {
        always {
            echo "in post always"
            script {
                def stop = new Date()
                TimeDuration td = TimeCategory.minus( stop, start )
                println("Elapsed time: $td")
            }

        }
        failure {
            echo "in post failure"
        }
    }
}

Serialize regex

After a regex matching Jenkins sometimes wants to serialize the object, but it cannot do it and thus is raises an
exception. (I have not yet figured out when does this happen.)

examples/jenkins/serialize_regex.Jenkinsfile

pipeline {
    agent { label 'master' }
    stages {
        stage('first') {
            steps {
                script {
                    echo "in first"
                    def text = """This is some long test
                    with more than 1
                    rows.
                    """
                    def match = (text =~ /bsomeb/)
                    println("still first")
                    check_me()
                }
            }
        }
        stage('second') {
            steps {
                script {
                    echo "in second"
                }
            }
        }
    }
    post {
        always {
            echo "in post always"
        }
        failure {
            echo "in post failure"
        }
    }
}

def check_me() {
    println("in check")
    def text = """This is some long test
        with more than 1
        rows.
    """
    def match = (text =~ /bsomeb/)
}


Send mail

emailext (
    subject: "Test by Gabor",
    body: "Test from Gabor",
    to: 'foo@bar.com',
    from: 'jenkins-noreply@example.com',
    listId: 'gabor-experimental',
)

Jenkins — check if host is accessible

examples/jenkins/ping_host.jenkinsfile

// catch exception
// stop process early reporting failure

pipeline {
    agent { label 'master' }
    parameters {
       string(name: 'hostname', defaultValue: 'gabor-dev', description: 'Hostname or IP address')
    }
    stages {
        stage('first') {
            steps {
                script {
                    echo "Checking $params.hostname"
                    try {
                        sh("ping -c 1 $params.hostname")
                    }  catch(Exception e) {
                       println("Exception: ${e}")
                       error("Could not find host $params.hostname, is it on?")
                       return
                    }
                    echo "still in first"
                }
            }
        }
        stage('second') {
            steps {
                script {
                    echo "in second"
                }
            }
        }
    }
    post {
        always {
            echo "in post always"
        }
        failure {
            echo "in post failure"
        }
    }
}


last started stage

//   last_started = env.STAGE_NAME

Early stop

jenkins — skip rest of the current stage, early end of current stage — stop the whole job reporting error

return  // skipping rest of the current stage, running next stage
error("Some error message")  // raise an exception stop the whole job

currentBuild

echo currentBuild.number  // failed expecting number
println(currentBuild.number)  // works

println("Number: ${currentBuild.number}")
println("Result: ${currentBuild.result}")
println("Display name: ${currentBuild.displayName}")

during the steps the result is null
in the post section it is already ‘SUCCESS’ or ‘FAILURE’

getting started

returnStatus instead of stopping the job

the exit code

def res2 = sh(script: "pwd", returnStatus: true)

Sample code

def errors = ''
def res = 'SUCCESS'
def res1 = sh(script: "xyz", returnStatus: true)
println("res1 ${res1}")
if (res1 !=0) {
    res = 'FAILURE'
    errors += "xyz"
}
def res2 = sh(script: "abc", returnStatus: true)
println("res2: ${res2}")
if (res2 !=0) {
    res = 'FAILURE'
    errors += "abc"
}
def res3 = sh(script: "pwd", returnStatus: true)
println("res3: ${res3}")
if (res3 !=0) {
    res = 'FAILURE'
    errors += "pwd"
}
//if (params.expected == 'Success') {
//    sh "pwd"
//} else {
//    sh "xyz"
//}
if (res == 'FAILURE') {
    error(errors)

jenkins error, we need to clean the regex variables

def output = sh(...)
def version = (output =~ /Versions*:s*([d.]+)/)
def build_number = (output =~ /Build numbers*:s*([d]+)/)
currentBuild.description = "${version[0][1]} - ${build_number[0][1]}<br>"
version = ""
build_number = ""

Optional artifacts

post {
    always {
        script {
            archiveArtifacts artifacts: 'screenshots/*', fingerprint: true, allowEmptyArchive: true
        }
    }
}

archiveArtifacts

schedule

multiple cron with parameter

examples/jenkins/multiple_cron.Jenkinsfile

// multiple cron with parameter

// There is a plugin and this experiment

    triggers {
        cron("35,36 * * * *")
    }

    stages {
        stage('Check disk usage') {
            steps {
                script {
                    echo "--------------"
                    echo "HELLO $BUILD_NUMBER"
                    echo "--------------"
                    String[] ENVS   = ["env1", "env3"]
                    def ENV_COUNT   = ENVS.length
                    def x           = BUILD_NUMBER.toInteger() % ENV_COUNT
                    echo x.toString()
                    echo ENVS[x]

Today we will learn how to send success, error notification to slack through the Jenkins CI job and from the Jenkinsfile(Declarative Pipeline).

While working on Jenkins sometimes, we need to send notifications to the Slack channel when the Jenkins CI Job run successfully or there was some error, so the team member can be known without checking the CI Job on the Jenkins UI.
it is very helpful to check the Jenkins CI staus on the slack channel.
For sending the notification to the Slack channel, we will use Slack Notification plugin.

Installation of Slack Notification Plugin

Install Instructions for the plugin

    1. In your Jenkins dashboard, click on Manage Jenkins from the left navigation.

manage-jenkins

    1. Navigate to Manage Plugins
    1. Click on the tab name as Available
    1. Search for Slack Notification

      slack-notification-plugin-manager-search

    1. Check the box next to install

Jenkins CI App installation in Slack

    1. Go to Slack App Directory and search for Jenkins CI
    1. Click on the Add to Slack button

slack-notification-plugin-manager-search

    1. Now select the channel and click on the Add Jenkins CI Integration

slack-notification-plugin-manager-search

    1. Copy the Token from the Jenkins CI Page and Click on the Save Setting button at the bottom

We have installed the Jenkins CI App on Slack and got the Token
Now we will configure the Token into the Slack Notification plugin

Slack notification plugin configuration in Jenkins

In the first step, we have installed the Slack notification plugin. now time to configure the plugin.

Please follow the below steps

    1. Click on Manage Jenkins again in the left navigation and then click to Configure system.
    1. Find the Global Slack notifier settings section and add the following values
    • a. Team subdomain: <Your team domain>
    • b. Integration token credential ID: <Paste the token which we got from step 2>
    • c. The other fields are optional. You can click on the question mark icons next to them for more information.
    • d. Press Save once you’ve finished.

      jenkins-ci-configuration

    1. Click on the Test connection button to test the notification in the slack channel.
      Below is the sample notification

    jenkins-with-slack-notification-example.png

Configuration for project

There are 2 ways to configure in project

1. Through the UI panel

  • a. For each project that you want to receive notifications for, choose Configure from the project’s menu.

    jenkins-ci-configuration-in-project

  • b. Then you’ll need to add Slack notifications to the Post-build actions for this project.

    jenkins-ci-configuration-in-project

  • c. In the Slack notifications section, choose the events you want to be notified about.

    jenkins-ci-configuration-in-project

2. Send notification through Jenkinsfile file

If you are using Jenkinsfile then you can use this code to send the notification to slack channel

slackSend "Build Started - ${env.JOB_NAME} ${env.BUILD_NUMBER} (<${env.BUILD_URL}|Open>)"

You can customize the message and can add more configurations like notify to a particular user, colour etc

  • attachments (optional)

    • Type: Object
  • baseUrl (optional)

    Allows overriding the Slack compatible app URL specified in the global configuration.

    • Type: String
  • blocks (optional)

    • Type: Object
  • botUser (optional)

    Bot user option indicates the token belongs to a custom Slack app bot user in Slack.

    If the notification will be sent to a user via direct message, the default integration sends it via @slackbot, use this option if you want to send messages via a bot user.

    • Type: boolean
  • channel (optional)

    Allows overriding the Slack Plugin channel specified in the global configuration. Multiple channels may be provided as a comma, semicolon, or space-delimited string.

     slackSend channel: "#channel-name", message: "Build Started: ${env.JOB_NAME} ${env.BUILD_NUMBER}"
    
    • Type: String
  • color (optional)

    An optional value that can either be one of good, warning, danger, or any hex color code (eg. #439FE0). This value is used to color the border along the left side of the message attachment.

    slackSend color: "#439FE0", message: "Build Started: ${env.JOB_NAME} ${env.BUILD_NUMBER}"`
    
    • Type: String
  • failOnError (optional)

    If set to true, then the step will abort the Workflow run if there is an error sending message.

    slackSend failOnError: true, message: "Build Started: ${env.JOB_NAME} ${env.BUILD_NUMBER}"`
    
    • Type: boolean
  • iconEmoji (optional)

    Choose a custom emoji to use as the bot’s icon in Slack, requires using a bot user

    • Type: String
  • message (optional)

    This is the main text in a message attachment and can contain standard message markup. The content will automatically collapse if it contains 700+ characters or 5+ linebreaks, and will display a «Show more…» link to expand the content. The message may include global variables, for example, environment and current build variables:

    slackSend "started ${env.JOB_NAME} ${env.BUILD_NUMBER} (<${env.BUILD_URL}|Open>)"`
    
    • Type: String
  • notifyCommitters (optional)

    Notify committers via direct message in addition to specified channels, requires using a bot user

    • Type: boolean
  • replyBroadcast (optional)

    • Type: boolean
  • sendAsText (optional)

    • Type: boolean
  • teamDomain (optional)

    Allows overriding the Slack Plugin Integration Team Domain specified in the global configuration.

    • Type: String
  • timestamp (optional)

    Allows updating an existing message instead of posting a new one.

    • Type: String
  • token (optional)

    Allows overriding the Slack Plugin Integration Token specified in the global configuration.

    • Type: String
  • tokenCredentialId (optional)

    The ID for the integration token from the Credentials plugin to be used to send notifications to Slack. The «Kind» of the credential must be «Secret text.» If both «Integration Token» and «Integration Token Credential ID» are set, the «Integration Token Credential ID» will take precedence for security reasons.

    This overrides the global setting.

    • Type: String
  • username (optional)

    Choose a custom username to use as the bot’s name, requires using a bot user

    • Type: String

Send success notification to slack

when the deployment is done or testing is done, you want to send the notification to slack, please use

post {
    success {
        slackSend "Build deployed successfully - ${env.JOB_NAME} ${env.BUILD_NUMBER} (<${env.BUILD_URL}|Open>)"
    }
}

Your Jenkinsfile will look like this

// Jenkinsfile (Declarative Pipeline)
pipeline {
    agent any

    stages {
        stage('Build') {
            steps {
                echo 'Building..'
            }
        }
        stage('Test') {
            steps {
                echo 'Testing..'
            }
        }
        stage('Deploy') {
            steps {
                echo 'Deploying....'
            }
        }
        post {
            success {
                slackSend "Build deployed successfully - ${env.JOB_NAME} ${env.BUILD_NUMBER} (<${env.BUILD_URL}|Open>)"
            }
        }
    }
}

Send notification to slack in case of failure

When the build is failed, you want to send notification to slack channel you need to set failOnError is to true

post {
    failure {
        slackSend failOnError:true message:"Build failed  - ${env.JOB_NAME} ${env.BUILD_NUMBER} (<${env.BUILD_URL}|Open>)"
    }
}

Your Jenkinsfile will look like this

// Jenkinsfile (Declarative Pipeline)
pipeline {
    agent any

    stages {
        stage('Build') {
            steps {
                echo 'Building..'
            }
        }
        stage('Test') {
            steps {
                echo 'Testing..'
            }
        }
        stage('Deploy') {
            steps {
                echo 'Deploying....'
            }
        }
        post {
            failure {
                slackSend failOnError:true message:"Build failed  - ${env.JOB_NAME} ${env.BUILD_NUMBER} (<${env.BUILD_URL}|Open>)"
            }
        }
    }
}

Conclusion

We learnt how to send notifications to the slack channel through the Jenkins CI, Jenkinsfile (Pipeline). Please give it a try and I will be happy to answer your queries on my Twitter handle Twitter

Introduction

Jenkins offers an open-source CI/CD automation solution for developers. One of the features Jenkins offers is automatically logging the performance of builds.

Reviewing Jenkins logs can offer a wealth of insight into how well your code works. This is particularly useful when identifying problems or looking for elements that can be better optimized.

In this tutorial, we will show you how to find, view, and edit Jenkins log files.

Jenkins logs - viewing and customizing

Prerequisites

  • A copy of Jenkins installed and ready to use.
  • Access to a web browser.
  • Access to a text editor, such as Nano, Vim, or Notepad.

Where are Jenkins Logs Stored?

Where Jenkins logs are stored depends on the underlying operating system.

  • Linux and macOS — Jenkins logs are stored along with other log files in the /var/log directory.
  • Windows — Jenkins log files are stored in the Jenkins home folder, which is determined during installation.

It is possible to change the Jenkins log location by modifying its service configuration file. The name and location of that file depends on the underlying OS:

  • Debian-based system /etc/default/Jenkins
  • Red Hat-based systems /etc/sysconfig/Jenkins
  • MacOS org.jenkins-ci.plist
  • Windows[JENKINS HOME]/jenkins.xml

How to View Jenkins Logs?

To view a Jenkins log file, open it with a text editor of your choice. Below are the default locations of Jenkins log files depending on the operating system.

Jenkins UI

By default, Jenkins keeps a constant log of all activity as a part of the Jenkins dashboard.

1. To access this log, click the Manage Jenkins link on the right-hand side of the dashboard.

Open Jenkins settings

2. Click the System Log button in the Status Information section.

Click the System Log button in the Status Information section

3. Click the All Jenkins Logs link to access the default log.

Open All Jenkins Logs

Each line of the log details the time and date of the action, the level of logging, the element of Jenkins performing the action, and the action being performed, followed by a brief description.

Jenkins log example

Linux

The default location for Jenkins logs on Linux is /var/log/jenkins/jenkins.log. To view the log file, open it using a text editor such as Nano:

sudo nano /var/log/jenkins/jenkins.log

Windows

On Windows, Jenkins log files are stored as jenkins.out (console output logs) and jenkins.err (error logs) in the Jenkins home folder.

Note: Jenkins logs may be stored in the Jenkins installation folder in Program Files on some Windows systems.

The location of the Jenkins home folder is specified during the installation. The default location is C:ProgramDataJenkins.jenkins.

Important: The ProgramData folder is hidden by default. Make sure you enable viewing hidden items before trying to view Jenkins logs.

If you are not sure which folder you set as the Jenkins home folder, click the Manage Jenkins link on the left-hand side of the Jenkins dashboard.

Open Jenkins settings

Under the System Configuration section, click the Configure System button.

Under the System Configuration section, click the Configure System button

The location of the Jenkins home folder is listed at the top of the page, under Home directory.

Location of the Jenkins home directory

MacOS

On MacOS, Jenkins logs are located at /var/log/jenkins/jenkins.log by default:

sudo nano /var/log/jenkins/jenkins.log

Docker

Viewing Jenkins logs in Docker requires running Jenkins inside a detached container. Open Jenkins logs using the Docker logs command and the ID for the detached container:

docker logs [container ID]

How to Enable Debug Logs in Jenkins?

Jenkins allows users to set up new log recorders when using the System Log page. These recorders collect and display information on specific elements of your code and you can fine-tune them to provide a more detailed output.

Having a more detailed log available makes it easier to spot and determine the cause of potential errors in the code. This is very helpful when debugging issues.

1. To set up a new log recorder, first click the Add new log recorder button in the Log Recorders section of the System Log page.

Click the Add new log recorder button in the Log Recorders section of the System Log page

2. Next, enter the name of the new log recorder and click the OK button. For this example, we will name our log recorder Dig Debug.

Enter the log recorder name and click OK

3. To customize the output the new log recorder collects and displays, click the Add button to add a new logger. Use the input field to search for an element and select the log level from the drop-down menu. It is generally best to use the ALL or FINE logging level for debugging purposes.

Add new loggers to the log recorder

Note: Selecting the ALL or FINE logging level tends to produce substantial levels of output. To increase performance, consider removing the log recorder once you are finished with debugging.

4. For our example, we want to debug plugins related to Git. To do this, we will add new loggers monitoring these plugins and set the logging level to ALL.

5. Once you are done adding new loggers, click the Save button to save the new Jenkins log recorder.

Click Save to finish adding loggers

6. Once you’ve set up the new log recorder, open it by clicking its name in the Log Recorders section. With the log recorder open, click the Log records link on the left-hand side to review the new log records.

Review the records for the new log recorder

What Jenkins Logs Should You Monitor?

Certain events in the Jenkins log can indicate issues with the code or the Jenkins application itself. Monitoring these events is an easy way to diagnose and prevent performance issues quickly.

Receiving an OutOfMemoryError message indicates that Jenkins has run out of system memory. To resolve this issue, use a smaller Java heap or check for old saved data at:

[Jenkins URL]/administrativeMonitor/OldData/manage

Note: The Jenkins URL is a combination of your system’s hostname and the port number Jenkins is running on. For instance, when logging into Jenkins on the host system, the default Jenkins URL is http://localhost:8080/.

A java.lang.OutOfMemoryError: GC overhead limit exceeded error happens when the Java Garbage Collector exceeds its memory limit. A quick solution is to clear old builds that may be taking up memory.

Another common issue is CPU consumption, indicated by an OutOfMemoryError: PermGen space error. You can avoid this by minimizing the number of builds running on the master node, limiting build history, ensuring all Jenkins plugins are updated, and monitoring how other applications use the CPU.

How to Customize Jenkins Logs?

The formatting of Jenkins logs can sometimes make them difficult to read, especially when using higher logging levels. Long pipelines with dozens or hundreds of lines of code also present a challenge.

Below is an example log for a simple pipeline that prints out the build version number:

Jenkins pipeline log example

In the output above, it isn’t easy to see where a stage starts and ends. The only indication is the stage output at the beginning and // stage at the end, both displayed in light gray.

Adding a message with the echo command at the beginning of a stage makes separating different stages when looking at the console output easier. This also allows users to add brief descriptions, making it even easier to understand the output.

Another method is to add an echo command without any message text. This creates a blank line and makes the output easier to read.

Jenkins pipeline log with banners and breaks

Conclusion

After reading this tutorial, you should be able to find and view Jenkins logs and use them to diagnose potential issues with your project build.

Понравилась статья? Поделить с друзьями:
  • Job for ospd openvas service failed because the control process exited with error code
  • Jenkins error could not find credentials entry with id
  • Job for networking service failed because the control process exited with error code ubuntu
  • Jenkins error cloning remote repo origin
  • Job for networking service failed because the control process exited with error code centos