#!groovy
def call(Map map) {
pipeline {
//agent{
// node{
// label 'jenkins-slave'
// }
//}
agent any
environment {
APP_NAME = "${map.app}"
K8S_NS = "${map.namespace}"
DEFAULT = "Running"
}
stages {
stage('Output Pod Log') {
steps {
sh '''for (( i=1;i<=5;i=i+1 ))
do
POD_STATUS=$(kubectl get pods -n ${K8S_NS} | grep "${APP_NAME}" | awk '{print $3}')
POD=$(kubectl get pod -o wide -n ${K8S_NS} |grep "${APP_NAME}" |grep "0/1" |awk '{print $1}'|head -n 1)
if [[ "$POD" == "" ]]; then
break
elif [[ "$POD_STATUS" != "$DEFAULT" ]]; then
kubectl get pod -o wide -n ${K8S_NS} |grep "${APP_NAME}"
sleep 5
continue
elif [[ "$POD" != "" ]] && [[ "$POD_STATUS" == "$DEFAULT" ]]; then
timeout 70 kubectl logs -f $POD -n ${K8S_NS}
timeout 10 kubectl rollout status deployment ${APP_NAME} -n ${K8S_NS}
break
else
break
fi
done'''
}
}
}
}
This is one of my jenkinsfile sections, which is trying to filter out the newly created pod containers by the script content. And output the corresponding logs to the Jenkins console, but currently Jenkins seems to have added escaped characters to the Default variable string I defined. Log content output:
enter image description here
I hope that you can help me.
Related
I'm trying to create a Jenkins pipeline with multi-stages, the first stage creates the image, the second stage create new pods from the newly created image and the third stage checks if each pods is alive.
In the third stage one of the commands is:
result = sh(returnStdout: true, script: "kubectl get pods --all-namespaces | grep -i <specific pod name> | wc -l").trim()
and the value I expect to receive is 1 or 0 but when the command return 0 there is an unexpected EOF error:
/var/jenkins_home/workspace/git-test#tmp/durable-c72ab15c/script.sh: line 1: unexpected EOF while looking for matching `''
after the run failed the location from the error doesn't exist.
How can I get the value I need?
The Stage looks like this:
def isDone = false
def response = ""
for (int i = 0; i < 10 && isDone == false; i++) {
timeout(time: 60, unit: 'SECONDS') {
waitUntil {
response = sh(returnStdout: true, script: "kubectl get pods -o=name --all-namespaces --field-selector status.phase=Running | grep -i $testCaseName | grep . | awk '{ print (\$1 == \"\") ? \"0\" : \"1\" }'").trim()
if (response != "") {
return true
}
}
}
if (response == '1') {
sh "echo '$testCaseName pod is running'"
isDone = true
} else {
sh "echo '$testCaseName pod isn't running yet'"
sleep(time:1,unit:"MINUTES")
}
I still don't know for sure the right cause for this problem but I'm assuming that it came from the readStdout flag from the Jenkins sh command.
The solution for this problem is to wrap with try catch the command that causes the unexpected EOF error which here is the if section and put the else section in the catch section. it looks like this:
def isDone = false
def response = ""
def state = ""
sh "mkdir -p ${workspace}/results/${currentBuildNumber}/$testCaseName"
for (int i = 0; i < 10 && isDone == false; i++) {
sh "kubectl get pods --all-namespaces | grep -i $testCaseName | awk '{ printf (\$4 == \"Running\") ? \"yes\" : \"'wait'\" }' > ${workspace}/results/${currentBuildNumber}/$testCaseName/commandResult.txt"
sh "kubectl get pods --all-namespaces | grep -i $testCaseName | awk '{ printf \$4 }' > ${workspace}/results/${currentBuildNumber}/$testCaseName/podState.txt"
timeout(time:30,unit:"SECONDS") {
waitUntil {
response = readFile "${workspace}/results/${currentBuildNumber}/$testCaseName/commandResult.txt"
return (response != "")
}
}
timeout(time:30,unit:"SECONDS") {
waitUntil {
state = readFile "${workspace}/results/${currentBuildNumber}/$testCaseName/podState.txt"
return (state != "")
}
}
try {
if ("$response" == "yes") {
println("$testCaseName pod is running")
isDone = true
} else {
println("$testCaseName pod state is: $state")
sleep(time:1,unit:"MINUTES")
}
} catch(Exception e) {
println("$testCaseName pod state is: $state")
if ((i == 9) && (isDone == true)) {
error("Build failed because $testCaseName pod couldn't start")
} else {
sleep(time:1,unit:"MINUTES")
}
}
}
I have a script like this [ code below ]
At the end of the stage block under node I get the desired result, but inside pipeline block I am not getting the changed value, instead it is giving me null. I tried all possible ways. Please let me know is there a way to get the changed value inside pipeline block.
def AGENT_LABEL
node('k8s-agent-large-mem-oci') {
stage('Checkout and set agent'){
sh '''
if [ ! -z "`echo ${ADE_LABEL} | grep "BRONZE"`" ]
then
AGENT_LABEL="DB_OCI"
fi
if [ ! -z "`echo ${ADE_LABEL} | grep "SILVER"`" ]
then
AGENT_LABEL="DB_OCI"
fi
if [ ! -z "`echo ${ADE_LABEL} | grep "FUSIONAPPS_11.13"`" ]
then
AGENT_LABEL="DB_ARU"
fi
echo "Final Agent Label is $AGENT_LABEL"
'''
}
}
pipeline {
agent {
label "${AGENT_LABEL}"
}
stages {
stage ('Git Copy to DB VM') {
steps {
echo "Running in ${AGENT_LABEL}"
build job: 'Git_Scripts_DB'
}
}
}
}
Before giving you a pipeline example, where do you set ${ADE_LABEL}?
Try this one:
pipeline {
agent none
environment {
AGENT_LABEL = """${sh(
returnStdout: true,
script: 'if [[ ! -z $(grep -E "BRONZE|SILVER" <<< "${ADE_LABEL}") ]]
then
AGENT_LABEL="DB_OCI"
fi
if [[ ! -z $(grep -E "FUSIONAPPS_11.13" <<< "${ADE_LABEL}") ]]
then
AGENT_LABEL="DB_ARU"
fi
echo "Final Agent Label is ${AGENT_LABEL}"'
).trim()}"""
}
stages {
stage ('Git Copy to DB VM') {
agent {
label "${AGENT_LABEL}"
}
steps {
echo "Running in ${AGENT_LABEL}"
build job: 'Git_Scripts_DB'
}
}
}
}
in the first stage, i've shell script to check directory in the remote server and the results will be sent to the next stage. I have tried the following way but it seems the variable is not read in the execute stage, is there another proper way?
pipeline {
agent any
stages
{
stage("validate")
{
steps
{
sh '''
dir_path="/home/servicenamedir"
ssh username#host bash -c "'
if [ -d "$dir" ]
then
checkdir="true"
else
checkdir="false"
fi
'"
'''
}
}
stage("execute")
{
steps
{
sh '''
if [ "$checkdir" == "true" ]
then
echo "directory already exist, please double check";
exit;
elif [ "$checkdir" == "false" ]
then
echo "execute ./install-service.sh"
fi
'''
}
}
}
create variable
def var
use options returnStdout: true. And parse output
Def var = sh ( script " ls -la", returnStdout: true).split("\n")
use var in stage 'execute'
If (var[0] =="true"){...} else {...}
https://www.jenkins.io/doc/pipeline/steps/workflow-durable-task-step/
Running one linux command and saving the ouput of the command as list and then reding the list item one by one.
stage('NAMESPACE Availability') {
node ('master'){
withEnv(["KUBECONFIG=${JENKINS_HOME}/.kube/config"]){
NS_list = sh (
script: '''kubectl get ns | awk '{print \$1}' | awk '{\$1=\$1; print "[\\x27" $0 "\\x27]"}' FS='\n' OFS="','" RS='' ''',
returnStdout: true
).trim()
echo "${NS_list}"
NS(NS_list)
}
}
}
def NS(list) {
for (i in list) {
echo "${i}"
if ( i == "${NAME_SPACE}" ) {
sh "kubectl delete all --all -n '${NAME_SPACE}' && kubectl delete '${NAME_SPACE}' "
break;
}
}
}
Rather then reading as Item its reading as character , Lets say if command output is ['NAME','b2','b6','b7','cert-manager','default'] its reading as below output.
[Pipeline] echo
[
[Pipeline] echo
'
[Pipeline] echo
N
[Pipeline] echo
A
[Pipeline] echo
M
[Pipeline] echo
E
[Pipeline] echo
[Pipeline] echo
'
[Pipeline] echo
,
[Pipeline] echo
'
I solved my problem as per below changes. Rather then using for(loop).. i used ".contains"
stage('NAMESPACE Availability') {
node ('master'){
withEnv(["KUBECONFIG=${JENKINS_HOME}/.kube/config"]){
NS_list = sh (
script: '''kubectl get ns | awk '{print \$1}' ''',
returnStdout: true
).trim()
def lst = "${NS_list}";
NS = (lst.contains( "${NAME_SPACE}" ));
echo "${NS}"
if ( NS == true ) {
sh "kubectl delete all --all -n ${NAME_SPACE} "
}
else {
sh "kubectl create ns ${NAME_SPACE}"
}
}
You haven't declared NS_list, that will store everything as a string. Add def NS_list = [] at the beginning of your pipeline
I have defined global variable in Jenkins pipeline
def BUILDNRO = '0'
pipeline { ...
Then i manipulate variable with shell script to enable running builds parallel by using job build number as identifier so we don't mix different docker swarms.
stage('Handle BUILD_NUMBER') {
steps {
script {
BUILDNRO = sh( script: '''#!/bin/bash
Build=`echo ${BUILD_NUMBER} | grep -o '..$'`
# Check if BUILD first character is 0
if [[ $Build:0:1 == "0" ]]; then
# replace BUILD first character from 0 to 5
Build=`echo $Build | sed s/./5/1`
fi
echo $Build
''',returnStdout: true).trim()
}
}
}
i get value out from previos stage and trying to get global variable on next stage
stage('DOCKER: Init docker swarm') {
steps {
echo "BUILDNRO is: ${BUILDNRO}" --> Value is here.
sh '''#!/bin/bash
echo Buildnro is: ${BUILDNRO} --> This is empty.
...
}
}
This will out give global variable empty. why? in previous stage there was value in it.
EDIT 1.
Modified code blocks to reflect current status.
I managed to figure it out. Here is solution how i managed to did it.
BUILDNRO is groovy variable and if wanting to used in bash variable it have to pass using withEnv. BUILD_NUMBER in first stage is bash variable hence it can be used directly script in first stage.
def BUILDNRO = '0'
pipeline {
....
stages {
stage('Handle BUILD_NUMBER') {
steps {
script {
BUILDNRO = sh( script: '''#!/bin/bash
Build=`echo ${BUILD_NUMBER} | grep -o '..$'`
''',returnStdout: true).trim()
}
}
}
stage('DOCKER: Init docker swarm') {
steps {
dir("prose_env/prose_api_dev_env") {
withEnv(["MYNRO=${BUILDNRO}"]) {
sh(returnStdout: false, script: '''#!/bin/bash
echo Buildnro is: ${MYNRO}`
'''.stripIndent())
}
}
}
}
}
}
If you are using single quotes(```) in the shell module, Jenkins treats every variable as a bash variable. The solution is using double quotes(""") but then if you made bash variable you have to escape it. Below an example with working your use case and escaped bash variable
pipeline {
agent any
stages {
stage('Handle BUILD_NUMBER') {
steps {
script {
BUILDNRO = sh(script: 'pwd', returnStdout: true).trim()
echo "BUILDNRO is: ${BUILDNRO}"
}
}
}
stage('DOCKER: Init docker swarm') {
steps {
sh """#!/bin/bash
echo Buildnro is: ${BUILDNRO}
variable=world
echo "hello \${variable}"
sh """
}
}
}
}
output of the second stage:
Buildnro is: /var/lib/jenkins/workspace/stack1
hello world