catch exception on jenkins pipeline - jenkins

I'm using Jenkins pipeline to orchestrate some binaries. My Jenkins slave host has "open-ssh" with full access to the servers in the dev environment.
Is there a way to catch ssh exception using Jenkins pipeline? Here is my code:
//exe remote command on server
stages {
stage('Links') {
steps {
sh '''#!/bin/bash
ssh user1#server1 command1
ssh user2#server2 command2
'''
}
}
}

Something like this might work for you:
stages {
stage('Links') {
steps {
script {
try {
sh "ssh user1#server1 command1"
}
catch (err) {
// do something about it, or simply
throw err
}
try {
sh "ssh user2#server2 command2"
}
catch (err) {
// do something about it, or simply
throw err
}
}
}
}
}

Im using this to wrap my pipeline jobs:
#!groovy
node ('node1') {
currentBuild.result = "SUCCESS"
try {
stage('stg-1') {
...
}
stage('stg-2') {
...
}
} catch (err) {
print('err: ' + err.toString() )
currentBuild.result = "FAILURE"
} finally {
stage('stg-final') {
...
}
}
}

Related

Show a Jenkins pipeline build job stage as failed without failing the whole job

I have a Jenkins pipeline with some parallel stages that should not fail the job if they fail.
Those stages start a build job.
I started from https://stackoverflow.com/a/56975220/1817610.
The original sample works, but not if my stage builds another pipeline.
pipeline {
agent any
stages {
stage('1') {
steps {
sh 'exit 0'
}
}
stage('2') {
parallel {
stage('2.1') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
build job: 'Failing pipeline'
}
}
}
stage('2.2') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
build job: 'Succesful pipeline'
}
}
}
}
}
stage('3') {
steps {
sh 'exit 0'
}
}
}
}
See build 7 in screenshot
If I changed the stage to
stage('2.1') {
steps {
build job: 'Failing pipeline', propagate: false
}
}
The job does not fail, but also the stage does not fail, see build 8.
I'd like to have the global state as successful but still showing that one of the builds failed.
you could make use of pure groovy try..catch block and control your SUCCESS and FAILURE with some condition.
Below is an example:
pipeline {
agent any;
stages {
stage('01') {
steps {
sh "echo Hello"
}
}
stage('02') {
parallel {
stage('02.1') {
steps {
script {
try {
def v = 10/0
println v
}catch(Exception e) {
println e
}
}
}
}
stage('02.2') {
steps {
script {
try {
def v = 10 % 2
println v
}catch(Exception e) {
println e
}
}
}
}
}
}
}
}
In my example, my parallel stage 02.1 will fail with java.lang.ArithmeticException: Division by zero but catch block will handle it by catching the exception.
if you want to fail the build with some condition, you can put if..else condition inside catch {} and fail by throwing back the exception to Jenkins like
...
stage('02.1') {
steps {
script {
try {
def v = 10/0
println v
}catch(Exception e) {
if(someCondition) {
println e
} else {
throw e;
}
}
}
}

How to include pipeline errors in email (Email-ext plugin)

I am trying to have the reason as it is printed on the console of my Jenkins instance why a build failed through email. I did the following
node {
try
{
stage('checkout') {
checkout scm
}
stage('restore') {
sh 'dotnetge restore test.sln'
}
}
catch (err) {
cause=err
emailext body:"Error: $cause ",
to: 'myemail#gmail.com'
}
}
The result on the console is something like "dotnetge command not found" and i will like to have this same type of error through email. This is what i get through email
Error: hudson.AbortException: script returned exit code 127
Since the shell script failed, it will give the exception you are currently getting. You can have a workaround to handle this:
node {
try
{
stage('checkout') {
checkout scm
}
stage('restore') {
try{
sh 'dotnetge restore test.sln'}
catch(exc){
error "dotnetge command failed"
}
}
}
catch (err) {
cause=err
emailext body:"Error: $cause ",
to: 'myemail#gmail.com'
}
}
This way you can at least know which command failed. What else I did was that I created another variable called curr_stage and assigned its value to the current stage:
node{
def curr_stage
try {
stage("stage1") {
curr_stage = "stage1"
}
stage("stage2") {
curr_stage = "stage2"
}
stage("stage3") {
curr_stage = "stage3"
}
}catch(exception){
//notify that the the build failed at ${curr_stage}
}
}

Setting the build status to failed when failingFast

In a declarative jenkins pipeline, when failFast is used within a set of parallel stages. How do you set the build status to 'FAILED' instead of 'ABORTED'?
Assuming something fails, this will exit with 'ABORTED'
pipeline {
agent any
stages {
stage('Parallel') {
failFast true
parallel {
stage('Branch A') {
steps {
sh "foo"
}
}
stage('Branch B') {
steps {
sh "bar"
}
}
stage('Branch C') {
steps {
sh "baz"
}
}
}
}
}
}
If FailFast is removed the build will eventually fail with 'FAILED'. But I need the FailFast behaviour as well.
OK, after a bit of investigation this appears to an issue with Jenkins: https://issues.jenkins-ci.org/browse/JENKINS-55459
I was able to get by this by adding a script with a try/catch to those steps within the parallel stages.
steps {
script {
try {
MyCode()
}
catch (Exception err) {
if (currentBuild.result == null) {
error "The stage '${env.STAGE_NAME}' has failed."
} else {
echo "Exiting stage early."
}
}
}
}

Declarative pipeline to check the build step = Failure then trigger next build step, but not fail the job.

I am trying to fail a build step in Jenkinsfile with failed results = failure. Once the step is failed it triggers my rollback job. Tried many different things, but had no luck. Any help would be greatly appreciated.
pipeline {
agent any
stages {
stage('Git Checkout') {
steps {
script {
git 'somegit-repo'
sh'''
mvn package
'''
echo currentBuild.result
catchError {
build 'rollback'
}
}
}
}
}
One way is to use a shell script and with exit 1 statement
e.g.
sh "exit 1"
Or you can use error step
error('Failing build because...')
See https://jenkins.io/doc/pipeline/steps/workflow-basic-steps/#error-error-signal
Use a try catch block
node {
stage("Run scripts") {
try {
<some command/script>
} catch (error) {
<rollback command/script>
}
}
}
Thank you so much. This seems to work!
stages {
stage("some test") {
steps{
script {
git 'mygitrepo.git'
try {
sh''' mvn test '''
} catch (error) {
script {
def job = build job: 'rollback-job'
}
}
}
}
}
If you check the cleaning and notifications page
You can do a post step and get rid of all the try/catch stuff and get a cleaner Jenkinsfile
pipeline {
agent any
stages {
stage('No-op') {
steps {
sh 'ls'
}
}
}
post {
always {
echo 'One way or another, I have finished'
deleteDir() /* clean up our workspace */
}
success {
echo 'I succeeeded!'
}
unstable {
echo 'I am unstable :/'
}
failure {
echo 'I failed :('
}
changed {
echo 'Things were different before...'
}
}
}

How to exit from the Jenkins pipeline if a stage sets build fail/unstable status?

I have a declarative Jenkins pipeline with stage1, stage2, stage3 and so on. I want to stop stage2 from running if stage1 sets the build unstable/fail.
I know I can stop the steps in stage1 from running using return when the build is not success but couldn't find a way where I can just exit the pipeline without running the stages below stage1
Here is what I have:
stage('stage1') {
steps {
script{
//somesteps
if ("${stdout}" == "1"){
currentBuild.result = 'UNSTABLE'
return
} //if
//somesteps
} //script
} //steps
} //stage
// run only when stage1 is success
stage('stage2'){
when {
expression {
params.name ==~ /x|y/
}
}
steps {
script{
//stage2 steps
}
}
}
If params.name ==~ /z/ stage 3 will be executed skippping stage2
Note: I cannot include the steps in stage2/3/.. in stage1. It should be that way. Based on the build paramters stage2/3/4... will be called after stage1
The easiest way to skip remaining pipeline stages is to set up a variable which will control if following stages should be skipped or not. Something like this:
def skipRemainingStages = false
pipeline {
agent any
stages {
stage("Stage 1") {
steps {
script {
skipRemainingStages = true
println "skipRemainingStages = ${skipRemainingStages}"
}
}
}
stage("Stage 2") {
when {
expression {
!skipRemainingStages
}
}
steps {
script {
println "This text wont show up...."
}
}
}
stage("Stage 3") {
when {
expression {
!skipRemainingStages
}
}
steps {
script {
println "This text wont show up...."
}
}
}
}
}
This is very simple example that sets skipRemainingStages to true at Stage 1 and Stage 2 and Stage 3 get skipped because expression in the when block does not evaluates to true.
Alternatively you can call error(String message) step to stop the pipeline and set its status to FAILED. For example, if your stage 1 calls error(msg) step like:
stage("Stage 1") {
steps {
script {
error "This pipeline stops here!"
}
}
}
In this case pipeline stops whenever error(msg) step is found and all remaining stages are ignored (when blocks are not even checked).
Of course you can call error(msg) depending on some condition to make it FAILED only if specific conditions are met.
You can use post in a stage to exit as follows:
pipeline {
stages {
stage('stage 1') {
steps {
//step 1
}
}
stage('stage 2') {
steps {
script{
//step 2
}
}
post{
success {
}
failure {
script{
sh "exit 1"
//or
error "Failed, exiting now..."
}
}
aborted {
}
unstable {
script{
sh "exit 1"
//or
error "Unstable, exiting now..."
}
}
}
}
}
}
This will abort the build and job wouldn't run further.
You can also simply throw an Exception. That will abort the build.
In fact simply setting the build status in a catch clause works pretty well.
You can also then add custom logic in the finally block for sending notifications for build status changes (email, Slack message etc)
So perhaps something like the following. NOTE: I have copied some of this from an existing Jenkinsfile. So not 100% sure this is the same syntax as you were using:
pipeline {
try {
stages {
stage("stage1") {
if (something) {
throw new RuntimeException("Something went wrong")
}
}
stage("stage2") {
}
}
} catch (e) {
currentBuild.result = "FAILED"
throw e
}
}
You can try:
stage('Set skipRemainingStages variable which decides, whether to run next stages or not') {
steps {
script {
skipRemainingStages = true
try {
println("In if block")
skipRemainingStages = true
}
catch (Exception exc) {
println("Exception block: ${exc}")
skipRemainingStages = false
}
if (skipRemainingStages) {
currentBuild.result = 'FAILURE'
error("Stopping early!")
}
}
}
}
stage('This will not execute if skipRemainingStages=true')
{.
.
.
}
You can use mark the build as failed and then use sh "exit 1" to interrupt its execution in your Jenkins pipelines like below:
pipeline {
stages {
stage('stage 1') {
steps {
}
}
stage('stage 2') {
steps {
script{
if (something) {
currentBuild.result = "FAILURE"
sh "exit 1"
}
}
}
}
}
}

Resources