I'm trying to use Groovy and curl to create a ServiceNow change ticket using their REST API. I get the below error every time I run the Jenkins pipeline
{"error":{"message":"Exception while reading request","detail":"Cannot decode: java.io.StringReader#90e4d8"},"status":"failure"}
What am I doing wrong here?
Jenkins version 2.150.2
{
node(){
stage ('Create Change Request') {
echo("Creating Change Request")
sh(script: """curl ${SERVICENOW_URL}/table/change_request \
--request POST \
--header 'Accept:application/json' \
--header 'Content-Type:application/json' \
--data '{"requested_by": "${params.requested_by}",
"u_verifier":"${params.u_verifier}",
"assigned_to":"${params.assigned_to}",
"reason":"${params.reason}",
"type":"${params.type}",
"start_date":"${params.start_date}",
"end_date":"${params.end_date}",
"change_plan":"${params.change_plan}",
"short_description":"${SHORT_DESCRIPTION}",
"description":"${DESCRIPTION}",
"backout_plan":"${BACKOUT_PLAN}",
"u_verification_plan":"${U_VERIFICATION_PLAN}",
"u_department_subsidiary":"${U_DEPARTMENT_SUBSIDIARY}",
"u_tested":"${U_TESTED}",
"u_have_verification_plan":"${U_HAVE_VERIFICATION_PLAN}",
"u_have_implementation_plan":"${U_HAVE_IMPLEMENTATION_PLAN}",
"u_have_backout_plan":"${U_HAVE_BACKOUT_PLAN}",
"assignment_group":"${U_ASSIGNMENT_GROUP}",
"category":"${CATEGORY}",
"cmdb_ci":"${CMDB_CI}",
"u_approval_group":"${U_APPROVAL_GROUP}",
"approval":"requested",
"state":"${_STATE}"
}' \
--user 'xxxx':'password' > CREATE_CHG_REQUEST_OUTPUT
""")
}
stage ('Parsing Change Result') {
def REQUEST_OUTPUT = ""
REQUEST_OUTPUT = readFile ('CREATE_CHG_REQUEST_OUTPUT').trim()
//var jsonStr = JSON.stringify(REQUEST_OUTPUT);
echo "REQUEST_OUTPUT:"
echo REQUEST_OUTPUT
def jsonSlurper = new JsonSlurper()
def object = jsonSlurper.parseText(REQUEST_OUTPUT)
NEW_CHANGE_NUMBER = object.result.number
NEW_SYS_ID = object.result.sys_id
echo("New Change Number is : " + NEW_CHANGE_NUMBER )
echo("New sys_id for Change Number : " + NEW_SYS_ID )
}
}
} catch(e) {
echo e.message
} finally {
}
The data has certain variables declared using . in the variable name. Groovy doesn't support the replacement of the variables declared inside the double quotes "". Replace all the variable names having . in them with single quotes ''.
Hope so this helps
Related
I am trying to replace value of a Yaml file with yq and global variable declared in my jenkins.groovy script. The Code does not throw any error but it is not replacing the values and Yaml remains unchanged.
stage('Clone abc repository and prepare abc-installer') {
agent { label LABEL_CICD }
steps {
sshagent(credentials:['jenkins-deploy-password']) {
sh 'whoami; PWD=$(pwd); SCRIPT_DIR=${PWD}/installer; \
yq -i \'.abc-server.image.tag = $IMAGE_TAG\' ${SCRIPT_DIR}/manifests/abc/values-single.yaml; \
cat ${SCRIPT_DIR}/manifests/abc/values-single.yaml; \
yq -i \'.spec.source.targetRevision = $ARGO_TARGETREVISION\' ${SCRIPT_DIR}/manifests/abc/abc.yaml; \
cat ${SCRIPT_DIR}/manifests/abc/abc.yaml; \
}
}
}
You should be using double quotes for String interpolation to work.
sh """
whoami; PWD=$(pwd); SCRIPT_DIR=${PWD}/installer; \
yq -i \'.abc-server.image.tag = $IMAGE_TAG\' ${SCRIPT_DIR}/manifests/abc/values-single.yaml; \
cat ${SCRIPT_DIR}/manifests/abc/values-single.yaml; \
yq -i \'.spec.source.targetRevision = $ARGO_TARGETREVISION\' ${SCRIPT_DIR}/manifests/abc/abc.yaml; \
cat ${SCRIPT_DIR}/manifests/abc/abc.yaml;
"""
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
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.
I am trying to set a environment variable to a http request header.
For example
""" --header 'Authorization: "${auth}"' """
But probaly due to the quote '...', the ${auth} is not correctly set.
A simple example:
job(jobName) {
wrappers {
environmentVariables {
env('auth', 'something I want to set')
}
}
steps {
shell(''' echo "${auth}" ''')
}
}
my test:
shell(''' echo "${auth}" ''') --> correctly echo
shell(''' echo '"${auth}"' ''') --> not echo correctly
shell(""" echo '"${auth}"' """) --> not echo correctly
per-character escaping: \"
~ auth="test"
~ echo "\"${auth}\""
"test"
concatenation: '"' ${auth} '"'
~ echo '"'${auth}'"'
"test"
Basically I can't pass build properties to Library var call without extra nonsense.
jenkinsfile relevant chunk:
tc_test{
repo = 'test1'
folder = 'test2'
submodules = true
refs = params.GitCheckout
}
That results in error
java.lang.NullPointerException: Cannot get property 'GitCheckout' on
null object
This, however, works:
def a1 = params.GitCheckout
tc_test{
repo = 'test1'
folder = 'test2'
submodules = true
refs = a1
}
The contents of the vars/tc_test.groovy in shared library :
def call ( body ) {
def config = [:]
body.resolveStrategy = Closure.DELEGATE_FIRST
body.delegate = config
try {
body()
} catch(e) {
currentBuild.result = "FAILURE";
throw e;
} finally {
config.each{ k, v -> println "${k}:${v}" }
}
}
I'm not really good with groovy, so it might be something obvious.
Got the answer from Jenkins JIRA.
Small workaround is using maps instead of closures:
tc_test ([
repo: 'test1',
folder: 'test2',
submodules: true,
refs = params.GitCheckout
])
May have drawbacks, but for me that worked perfectly.
Still have to transfer params as argument to have access to them, but at least the code makes more sense now.
Suppose you have a sharedLibrary to call a Rundeck Job,
Parameters:
1 runDeckJobId - Rundeck unique job id thats available in settings.
2 role - AD Group associated with Rundeck Job
3 runDeckProject - Name of the project configured in rundeck.
4 optional - All optional parameters as a Map.
- rundeckInstanceType - Rundeck instances are currently in UK or HK.
- retries - Number of retries for checking job status once started (Default value=100)
- timeout - Number of seconds to be waited before each retry (Default value=15)
- verbose - If verbose calls need to be made in the rundeck api calls (Default value=false)
- rundeckArgs - All rundeck parameters as a map. Eg: Name of the playBook, location of inventory file.
Example Usage in JenkinsFile:
if (isRundeckDeployment == "true") {
def optional = [
rundeckInstance : "UK",
timeout : 10,
rundeckArgs : [
artifactPack : "${artifactPath}",
DEPLOYMENT_ENVIRONMENT: "${deploymentEnvironment}",
EXTRA_ARGS : "-e deployment_serial=1"
]
]
triggerRundeckJob("job-id", "AD-group-id", "BitbucketKey", optional)
}
Shared Library Function with filename : triggerRundeckJob in vars folder
def call(String rundeckJobId, String role, String rundeckProject, Map optional) {
String jobUserId
wrap([$class: 'BuildUser']) {
jobUserId = "${BUILD_USER_ID}"
}
// Determine rundeck instance type, by default instance is UK (rundeckAuthToken)
String mainRundeckId = optional.rundeckInstance == "HK" ? "rundeckAuthTokenHK": "rundeckAuthToken"
String rundeckBaseURL = optional.rundeckInstance == "HK" ? "https://rundeckUrl/selfservice" : "https://rundeckUrl:9043/selfservice"
withCredentials([string(credentialsId: mainRundeckId, variable: 'mainRundeckIdVariable')]) {
int retries = optional.retries ?: 100
int timeout = optional.timeout ?: 15
String verbose = optional.verbose? "-v" : "-s"
String rundeckArgsString = optional.rundeckArgs.collect{ "-${it.key} \\\"${it.value}\\\"" }.join(" ")
def tokenResponse = sh(returnStdout: true, script: "curl -k ${verbose} -X POST -d '{\"user\": \"${jobUserId}\",\"roles\":\"${role}\",\"duration\":\"30m\"}' -H Accept:application/json -H 'Content-Type: application/json' -H X-Rundeck-Auth-Token:${mainRundeckIdVariable} ${rundeckBaseURL}/api/19/tokens")
def tokenResponseJson = readJSON text: tokenResponse
def rundeckResponse = sh(returnStdout: true, script: "curl -k ${verbose} --data-urlencode argString=\"${rundeckArgsString}\" -H Accept:application/json -H X-Rundeck-Auth-Token:${tokenResponseJson.token} ${rundeckBaseURL}/api/19/job/${rundeckJobId}/run")
def rundeckResponseJson = readJSON text: rundeckResponse
if(!rundeckResponseJson.error){
while(true){
if(retries==0) {
currentBuild.result = "FAILURE"
echo "Rundeck Job Timedout, See: ${rundeckBaseURL}/project/${rundeckProject}/job/show/${rundeckJobId}"
break;
}
def jobStateResponse = sh(returnStdout: true, script:"curl -k ${verbose} -H Accept:application/json -H X-Rundeck-Auth-Token:${tokenResponseJson.token} ${rundeckBaseURL}/api/19/execution/${rundeckResponseJson.id}/state")
def jobStateResponseJson = readJSON text: jobStateResponse
if(jobStateResponseJson.completed) {
if(jobStateResponseJson.executionState == "FAILED") {
currentBuild.result = "FAILURE"
echo "Rundeck Job FAILED, See: ${rundeckBaseURL}/project/${rundeckProject}/job/show/${rundeckJobId}"
break
}else{
currentBuild.result = "SUCCESS"
echo "Rundeck Job SUCCESS, See: ${rundeckBaseURL}/project/${rundeckProject}/job/show/${rundeckJobId}"
break
}
}
else{
sleep timeout
}
retries--
}
}else{
echo "******************Rundeck Job Error: ${rundeckResponseJson.message} ******************"
currentBuild.result = "FAILURE"
}
}
}