Advanced if else statements with grep in Groovy - jenkins

I have following Jenkinsfile which will grep for a string from URL, it will send a notification to Slack depends upon the output.
stage('Check if present') {
steps {
script{
sh """
if curl -s http://example.foo.com:9000 | grep -q "ERROR"
then
slackSend channel: '#team', message: "Pipeline has been failed due to due to an error, please investigate:${env.BUILD_URL} : http://example.foo.com:9000", teamDomain: 'example', tokenCredentialId: 'foo'
echo "Scan result: ERROR" && exit 1
elif curl -s http://example.foo.com:9000 | grep -q "WARN"
then
slackSend channel: '#team', message: "Pipeline is in WARN state due to a warning, please investigate:${env.BUILD_URL} : http://example.foo.com:9000", teamDomain: 'example', tokenCredentialId: 'foo'
fi"""
}
}
}
Absolutely the slackSend notification won't work, as it is a plugin.
I am looking for ways to do the same in Groovy so that I can implement slackNotification.
I tried the following logic in Groovy, as an example.
But it didn't work, as even if the line is not present is is printing line is found.
stage('test logic'){
steps{
script{
if ('curl -s http://example.foo.com:9000'.execute() | 'grep foo'.execute())
println("The line is found")
else {
println("The line is not found")
exit 1
}
}
}}

You can just use Groovy's (to be more accurate Java's) .contains(String) method to check if some string contains other string. Also when you execute command in pipeline you can capture stdout of that command.
Code:
stage('test logic'){
steps{
script{
def commandStdout = sh(returnStdout: true, script: "curl -s http://example.foo.com:9000"
if (commandStdout.contains("foo")) {
println("The line is found")
}else {
println("The line is not found")
exit 1
}
}
}
}

Related

Jenkins script how to compare two string variables

def pname = "netstat -ntlp|grep 8080|awk '{printf \$7}'|cut -d/ -f2"
sh "echo $pname" \ java
if ("java".equals(pname)) { sh "echo 1111" }
The process corresponding to port 8080 is a java process, and the 2nd line print "java". But the body of the if statement just doesn't execute.
You seem to be not executing the command correctly. Please refer to the following sample. Please note the returnStdout: true to return output of the command.
pipeline {
agent any
stages {
stage('Test') {
steps {
script {
def pname = sh(returnStdout: true, script: "netstat -ntlp|grep 8080|awk '{printf \$7}'|cut -d/ -f2").trim()
if (pname == "java") {
echo "echo 1111"
}
}
}
}
}
}
try
"==" for equal
or you can read doc.
https://groovy-lang.org/operators.html#_relational_operators

Cannot retrieve shell script status in the catch block of groovy/jenkins docker file

I am trying to populate a global variable with the exit code status and use that in the catch block to avoid certain exceptions. Not able to store the exit code value to the variable in groovy docker file. Should I take a different approach here? Please suggest.
Scenario: I'm looking to make sure if docker command fails, it should not fail the build, but if the python command inside the sh""" inside docker.image.inside fails as shown below, only then it should fail the build. That's why I started looking for exit code of python script to just fail the build when python cmd is failed and not otherwise.
def scriptStatus = 0
stages {
stage('Call Update) {
steps {
script {
try {
def image = docker.image("${repo}:${tag}")
image.pull()
image.inside("--env-file ${PWD}/cc.env -v /work/user.ssh") {
scriptStatus = sh(script: """
python -u /config/env-python/abc.py
""", returnStdout: true)
}
} catch(Exception e) {
echo "scriptStatus = ${scriptStatus}" --> not showing any result
if (scriptStatus == 0){
currentBuild.result = 'SUCCESS'
} else {
currentBuild.result = 'FAILURE'
}
}
}
}
}
}
I have tried couple options here:
returnStatus: true -> but it doesn't export any result outside the try block, hence I can't check whether the returned value is 0 or non-zero.
then I also tried exitCode=$? -> this also doesn't get stored in the global variable which can be further used in the catch block for if/else condition.
Use returnStatus: true instead returnStdout: true
scriptStatus = sh(script: """
python -u /config/env-python/abc.py
""", returnStatus: true)
returnStatus : returns the status code either 0 or 1.
returnStdout: returns the output.

Jenkins Pipeline waitUntil bash command returns certain string

I have a pipeline stage where I wait to get a certain string back from a sh script, and only when the strings match, continue to next stage, however, it doesn't work as expected:
node('master') {
stage("wait for bash completion") {
waitUntil {
def output = sh returnStdout: true, script: 'cat /tmp/test.txt'
output == "hello"
}
}
stage("execute after bash completed") {
echo "the file says hello!!!"
}
}
The execution is something like that:
+ cat /tmp/test.txt
[Pipeline] }
Will try again after 0.25 sec
[Pipeline] {
[Pipeline] sh
[workspace] Running shell script
+ cat /tmp/test.txt
[Pipeline] }
Will try again after 0.3 sec
[Pipeline] {
[Pipeline] sh
[workspace] Running shell script
+ cat /tmp/test.txt
[Pipeline] }
Will try again after 0.36 sec
...
(so on and so forth)
What am I missing?
From waitUntil's help:
Runs its body repeatedly until it returns true. If it returns false, waits a while and tries again. --
Your execution output looks exactly like that it is waiting for output == "hello" to match. Maybe the content of file /tmp/test.txt is not exactly hello. You might have some whitespace in it, e.g. new line as the last character.
You probably need to add .trim() shell stdout to work, ie
def output = sh(returnStdout: true, script: 'cat /tmp/test.txt').trim()
Otherwise you end up with output showing a newline character at the end.
but probably, the better solution would be to use groovy script:
steps {
sh "echo something > statusfile" // do something in the shell
waitUntil(initialRecurrencePeriod: 15000) {
script {
def status = readFile(file: "statusfile")
if ( status =~ "hello") {
return true
}else {
println("no hello yet!")
return false
}
}
}
}

Jenkins pipeline to SSH into an instance and call a function

How to create a function def test() which does some steps after sshing into an instance
I have something like this:
#!/usr/bin/env groovy
def test() {
cd $testPath
mv test*.txt archiveFiles
sh "someScript.sh"
}
pipeline {
agent java
parameters {
string(
name: 'testPath',
defaultValue: '/home/ubuntu/testFiles',
description: 'file directory'
)
}
stages {
stage(test) {
steps{
script{
sh "ssh ubuntu#IP 'test()'"
}
}
}
}
}
I am trying to ssh into an instance and do the steps in the function test() by calling it
I am getting an error like this:
bash: -c: line 1: syntax error: unexpected end of file
ERROR: script returned exit code 1
We use the SSH plugin as follows:
steps {
timeout(time: 2, unit: 'MINUTES') {
sshagent(credentials: ['local-dev-ssh']) {
sh "ssh -p 8022 -l app ${ENVIRONMENT_HOST_NAME} './run-apps.sh ${SERVICE_NAME} ${DOCKER_IMAGE_TAG_PREFIX}-${env.BUILD_NUMBER}'"
}
}
}

Retry a Jenkins pipeline job on a specific error message

So without Jenkins Pipeline the Naginator Plugin allows to restart a specific build on failure using regular expressions.
I like the retry option in Jenkins pipeline but I am not sure if I can catch an error from the build in the catch block and do a retry.
Is there a way to do so?
Eg: I have jenkins build which runs make. now make fails with an error: "pg_config.h missing". I want to catch this error and retry the build again a couple of times.
How can I do the above? Also, is it possible to catch multiple errors similar to regular expressions in Naginator somehow using pipelines?
retry("3"){
try {
sh "${cmd} 2>&1 > cmdOutput.txt"
sh "cat cmdOutput.txt"
} catch(FlowInterruptedException interruptEx) {
throw interruptEx
} catch(err) {
def cmdOutput = readFile('cmdOutput.txt').trim()
if (cmdOutput.contains("pg_config.h missing")) {
error "Command failed with error : ${err}. Retrying ...."
} else {
echo "Command failed with error other than `pg_config.h missing`"
}
}
}
I use the 'waitUntil' step and a counter to retry a shell command. I capture the output of the shell command so that I can run regex checks against the output and then continue or exit the loop.
// example pipeline
pipeline {
agent {
label ""
}
stages {
// stage('clone repo') {
// steps {
// git url: 'https://github.com/your-account/project.git'
// }
// }
// stage ('install') {
// steps {
// sh 'npm install'
// }
// }
stage('build') {
steps {
script {
// wrap with timeout so the job aborts if no activity
timeout(activity: true, time: 5, unit: 'MINUTES') {
// loop until the inner function returns true
waitUntil {
// setup or increment "count" counter and max value
count = (binding.hasVariable('count')) ? count + 1 : 1
countMax = 3
println "try: $count"
// Note: you must include the "|| true" after your command,
// so that the exit code always returns as 0. The "sh" command is
// actually running '/bin/sh -xe'. The '-e' option forces the script
// to exit on non-zero exit code. Prevent this by forcing a 0 exit code
// by adding "|| true"
// execute command and capture stdout
// Uncomment one of these 3 lines to test different conditions.
output = sh returnStdout: true, script: 'echo "Finished: SUCCESS" || true'
// output = sh returnStdout: true, script: 'echo "BUILD FAILED" || true'
// output = sh returnStdout: true, script: 'echo "something else happened" || true'
// show the output in the log
println output
// run different regex tests against the output to check the state of your build
buildOK = output ==~ /(?s).*Finished: SUCCESS.*/
buildERR = output ==~ /(?s).*BUILD FAILED.*/
// then check your conditions
if (buildOK) {
return true // success, so exit loop
} else if (buildERR) {
if (count >= countMax) {
// count exceeds threshold, so throw an error (exits pipeline)
error "Retried $count times. Giving up..."
}
// wait a bit before retrying
sleep time: 5, unit: 'SECONDS'
return false // repeat loop
} else {
// throw an error (exits pipeline)
error 'Unknown error - aborting build'
}
}
}
}
}
}
}
// post {
// always {
// cleanWs notFailBuild: true
// }
// }
}

Resources