Change Jeninks build status on specific error - jenkins

i've got a Jenkins job that should simply start a docker container using the Docker plugin.
If the container is stopped, the job runs correctly, but if the container is already running, the build step returns a failure due to an
com.github.dockerjava.api.exception.NotModifiedException
error.
This is basically the expected behavior of Jenkins but in my case, i want to set it to unstable to have a more meaningful response for the user.
I tried to add a conditional build step afterwards using TextFinder that scans the console output for the error, but it seems that it isn't executed after the docker build step fails.
Is there a way to change the build status just for this error?

In Jenkins, you can add a Groovy PostBuild Script for that job:
exceptionTextRegex = '.*com.github.dockerjava.api.exception.NotModifiedException.*'
if(manager.logContains(exceptionTextRegex)) {
manager.buildUnstable()
}

Thank you for pointing me in the right direction. Groovy PoistBuild was indeed the answer, but the script was a little bit bigger:
errpattern = ~/com.github.dockerjava.api.exception.NotModifiedException.*/;
manager.build.logFile.eachLine{ line ->
errmatcher=errpattern.matcher(line)
if (errmatcher.find()) {
manager.build.#result = hudson.model.Result.UNSTABLE
}
}

Related

Jenkinsfile: Create a stage with an agent that only conditionally runs

I have a Jenkinsfile where I am trying to:
Conditionally build a docker image to allow for testing
Conditionally run the tests using that docker image as my agent
The conditional build is working without a problem. It builds an image that I have assigned to the variable MYIMAGE shown below.
But the conditional running of the tests does not work because it tries to find an agent before it tests for the expression, but the agent is not there because the image has not been pushed.
In this case, I am triggering it with a PR comment of "test". But I cannot even get that far, because I cannot get the initial build to pass because it reaches the stage shown below -- which should be skipped since the trigger text is not present -- and it pauses there because it is trying to find a non-existent Docker image with which to create an agent. So, even though this step should be skipped entirely, it hangs here.
Here is that snippet of code:
stage('Test image') {
when {
expression {
return getTriggerText() == 'test'
}
}
agent {
docker {
image MYIMAGE
label MYLABEL
}
}
steps {
script {
sh 'python -m pytest tests/test_toyexample.py'
pullRequest.comment("Ran tests on image: $MYIMAGE")
}
}
}
And I am quite confident it is the agent portion that is messing things up: I have a very similar structure for skipping the image build except that it uses the standard agent, and that runs fine... it gets skipped.
Question
Is there a way to use a when expression like what I have above, even with an agent that does not exist? Keep in mind, this agent does exist if the step is not being skipped... it is only missing when the step is supposed to be skipped.

Jenkins Script Console vs Build Agent

I'm experiencing some odd behavior with a Jenkins build (Jenkins project is a multi-branch pipeline with the Jenkinsfile provided by the source repository). The last step is to deploy the application which involves replacing an artifact on a remote host and then restarting the process that runs it.
Everything works perfectly except for one problem - the service is no longer running after the build completes. I even added some debugging messages after the restart script to prove with the build output that it really was working. But for some reason, after the build exits the service is no longer running. I've done extensive testing to ensure Jenkins connects to the remote host as the correct user, has the right env vars set, etc. Plus, the restart script output is very detailed in the first place - there would be no way to get the successful output if it didn't actually work. So I am assuming the process that runs the deploy steps on the remote host is doing something else after the build completes execution.
Here is where it gets weird: if I run the same exact deploy commands using the Script Console for the same exact remote host, it works. And the service isn't stopped after successfully starting up.
By "same exact" I mean the script is the same, but the DSL is different between the Script Console and the pipeline. For example, in the Script Console, I use
println "deployscript.sh <args>".execute().text
Whereas in the pipeline I use
pipeline {
agent {
node 'mynode'
}
stages {
/*other stages commented out for testing*/
stage('Deploy') {
steps {
script {
sh 'deployscript.sh <args>'
}
}
}
}
}
I also don't have any issues running the commands manually via SSH.
Does anyone know what is going on here? Is there a difference in how the Script Console vs the Build Agent connects to the remote host? Do either of these processes run other commands? I understand that the SSH session is controlled by a Java process, but I don't know much else about the Jenkins implementation.
If anyone is curious about the application itself, it is a Progress Application Server for OpenEdge (PASOE) instance. The deploy process involves un-deploying the old WAR file, deploying the new one, and then stopping/starting the instance.
UPDATE:
I added 60-second sleep to the end of the deploy script to give me time to test the service before the Jenkins process ended. This was successful, so I am certain that when the Jenkins build process exits is when it causes the service to go down. I am not sure if this is an issue with Jenkins owning a process, but again the Script Console handles this fine...
Found the issue. It's buried away in some low-level Jenkins documentation, but Jenkins builds have a default behavior of killing any processes spawned by the build. This confirms that Jenkins was the culprit and the build indeed was running correctly. It was just being killed after the build completed.
The fix is to set the value of the BUILD_ID environment variable (JENKINS_NODE_COOKIE for pipeline, like in my situation) to "dontKillMe".
For example:
pipeline {
agent { /*set agent*/ }
environment {
JENKINS_NODE_COOKIE="dontKillMe"
}
stages { /*set build stages*/ }
}
See here for more details: https://wiki.jenkins.io/display/JENKINS/ProcessTreeKiller

Declarative Jenkinsfile doens't exit even if shell-script return non-zero value

Consider this extract from my declarative syntax Jenkinsfile
stage("Test") {
steps {
sh "sh run-tests.sh"
}
}
Even though the run-tests.sh script exit with code 1, the Jenkins job execution continues to the next step. Does anyone know what may be causing this?
EDIT: Thanks for the replies so far. I believe the problem lies elsewhere - the tests being executes are initiated by Python's nose2 library, and if I'm not mistaking it's this command that exits with 0 regardless of the status of the tests. I'll follow that lead for now and see if that solves things.
I found the solution. I'm running the tests using docker-compose, and it turns out that docker-compose return 0 regardless of what my test script return. See this SO post for more info.
I added the --exit-code-from option to my docker-compose up command, and now my CI job aborts with the same exit code as my Jenkinsfile (and thus my test script).

Jenkins pipeline/docker :Jenkins does not seem to be running inside a container

I'm trying to execute the sample of code found in Jenkins Pipeline here : https://jenkins.io/doc/book/pipeline/docker/
node {
/* Requires the Docker Pipeline plugin to be installed */
docker.image('maven:3-alpine').inside('-v $HOME/.m2:/root/.m2') {
stage('Build') {
sh 'mvn -B'
}
}
}
And give me this error:
[Pipeline] withDockerContainer
Jenkins does not seem to be running inside a container
[Pipeline] // withDockerContainer
I don't know why is it stopping like that without doing anything.
I have already install docker, docker plugin/docker pipeline on the latest version.
In configuration tool, i add the installation root path.
Did I miss something ?
Thanks in advance
This message is a normal debug message, maybe a little confusing, but not an error. As the Jenkins Pipeline code is written, during initialization it checks whether the step is already running in a container. I think the message could be written better.
If you have more problems than this message, please provide the entire log. Sounds like maybe a node cannot be assigned, or the docker client is not installed, or the docker image cannot be pulled.
The issue is a bit old but I faced a similar situation and I want to share.
I noticed that Jenkins mentions the the cause of the issue at the end of the pipeline logs.
For example in my case, the issue states:
java.io.IOException: Failed to run top '0458e2cc8b4e09c53bb89f680026fc8d035d7e608ed0b60912d9a61ebb4fea4d'. Error: Error response from daemon: Container 0458e2cc8b4e09c53bb89f680026fc8d035d7e608ed0b60912d9a61ebb4fea4d is not running
When checking the stage where this happened it's similar to the above you mentioned when using dockerImage.inside(), the reason in my case is that my Dockefile already defines an entrypoint and when using the inside feature jenkins gets confused, so to avoid this try overriding the entrypoint by passing it as a parameter to the inside function as follows:
dockerImage.inside("--entrypoint=''") {
echo "Tests passed"
}
Another good way to find the issue is to access your jenkins server ans list the docker containers with docker ps -a you may find the build container failed, check the logs then you will get a hint, in my case the logs says cat: 1: ./entrypoint.sh: not found.

How can I use Groovy Postbuild to force a job to success?

I am trying to force a unit test job to success if the main build returned a failed exit code. Here is how I configured it and it is not working (see screenshot). Does anyone know any reason why this shouldn't work? In this example I just want to show that a failing job can be changed to a passing job by a groovy postbuild step. The plugin doc implies that this should work.
The main build runs a batch script with "EXIT 1" to fail the build.
A Groovy Postbuild step runs manager.buildSuccess() in an attempt to force the build to success (but it fails to do so with no error).
I found a discussion about that problem on jenkins-JIRA.
As a workaround it is proposed to use reflection to make the build successful:
manager.build.#result = hudson.model.Result.SUCCESS
This workaround doesn't work for me, but perhaps it can help you
Install Groovy Post Build Plug in.
Then add the below Groovy Script.
manager.build.#result = hudson.model.Result.SUCCESS
Uncheck the Use Groovy Sandbox. This worked for me.

Resources