Jenkins approval stage in scripted pipelines - jenkins

I've setup a pipeline as code stack using jenkins groovy. For that I've coded some shared libraries to extend my CI/CD capabilities and avoid copy/paste some block code within all my pipelines code.
So I have a groovy function to add approval stage in pipelines, which I've tested using declarative pipeline in a Jenskins File successfully, but which fails when I try in my scripted pipeline function.
Here is the block code in a the declarative Jenkinsfile which works as you can see in the screenshots below.
stage('Approval') {
// no agent, so executors are not used up when waiting for approvals
when { changeset "vm-management/create-vm/**"}
agent none
steps {
script {
mail from: "$VM_EMAIL_FROM", to: "$VM_SUPPORT_EMAIL", subject: "APPROVAL REQUIRED FOR $JOB_NAME" , body: """Build $BUILD_NUMBER required an approval. Go to $BUILD_URL for more info."""
def deploymentDelay = input id: 'Deploy', message: 'Deploy to production?', parameters: [choice(choices: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24'], description: 'Hours to delay deployment?', name: 'deploymentDelay')]
sleep time: deploymentDelay.toInteger(), unit: 'HOURS'
}
}
}
But coming to try to add approval on the fly from my groovy function, it doesn't work.
def send(mail_from, mail_to, deploy_version) {
// no agent, so executors are not used up when waiting for approvals
/* when {
beforeAgent true
anyOf {
triggeredBy 'TimerTrigger'
}
}*/
script {
mail from: "${mail_from}", to: "${mail_to}", subject: "APPROVAL REQUIRED FOR $JOB_NAME" , body: """Build $BUILD_NUMBER from Deployment version ${deploy_version} required an approval. Go to $BUILD_URL for more info."""
def deploymentDelay = input id: 'Deploy', message: 'Deploy to production?', parameters: [choice(choices: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24'], description: 'Hours to delay deployment?', name: 'deploymentDelay')]
sleep time: deploymentDelay.toInteger(), unit: 'HOURS'
}
}
Jenkins keeps throwing exception like below :
groovy add manual approval using dshudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: script.call() is applicable for argument types: (org.jenkinsci.plugins.workflow.cps.CpsClosure2) values: [org.jenkinsci.plugins.workflow.cps.CpsClosure2#6097c139]
What Am I missing there please? How can I write my approval function in the groovy vars file so that I could have the expected behaviour like with the declarative pipeline stage above?

Just remove the script block, it's not needed (and isn't legal) in a scripted pipeline or a pipeline library global var

Related

Jenkins pipeline with userinput extendedChoice returns the values with [ ] at the beginning and end

I added the below to the pipeline so while the pipeline is running - at some stage I want the user to choose from the parameters but the output returns with parentheses at beginning and end.
def envs = input(id: 'Upgarde', message: 'On which customer do you want to apply the upgrade?', submitter: 'admin', ok: 'Submit', parameters: [extendedChoice(defaultValue: env.ENV.split().toString(), description: '', descriptionPropertyValue: env.ENV.split().toString(), multiSelectDelimiter: '', name: 'Customers to upgrade', quoteValue: false, saveJSONParameterToFile: false, type: 'PT_MULTI_SELECT', value: env.ENV.split().toString())]).split(',')
Screenshot from the Jenkins UI:
enter image description here
Fixed by added .replace("[", "").replace("]", "")

How to set default value Jenkins active choice parameter as a script

I have a Jenkins pipeline That has parameters defined via active choice parameter,
defining a default value is done by:
defaultValue: '',
you can put a string there or leave it empty which will give you the default result of the groovyScript.
I am trying to change the default parameter using a script so it will take the value using a groovy script.
This is the snippet of the relevant part of the pipeline:
parameters([
extendedChoice(
bindings: '',
defaultValue: '',
groovyClasspath: '',
groovyScript:"""
def proc = ["bash","-c","/usr/local/bin/aws s3 ls s3://Spark-Jenkins-Clusters/"].execute() | ["bash","-c","cut -c32-"].execute()
proc.waitForOrKill(10000)
return proc.text.tokenize()
""",
multiSelectDelimiter: ',',
name: 'Choose_Cluster',
description: 'This parameter is nice',
quoteValue: false,
saveJSONParameterToFile: false,
type: 'PT_SINGLE_SELECT',
visibleItemCount: 5
),
So The way to do that is to use "defaultGroovyScript",
I didn't find it in the documentation I just saw an option in the UI and tried it and luckily it worked:
This is what I finally did:
parameters([
extendedChoice(
bindings: '',
defaultGroovyScript: """
def proc = ["bash","-c","/usr/local/bin/aws s3 ls s3://Spark-Jenkins-Clusters/"].execute() | \
["bash","-c","sort"].execute() | \
["bash","-c","sed 's/PRE//g'"].execute() | \
["bash","-c","grep main"].execute() | \
["bash","-c","tail -n 1"].execute() | \
["bash","-c","tr -d '/'"].execute()
proc.waitForOrKill(10000)
return proc.text.tokenize().reverse()
""",
groovyClasspath: '',
groovyScript:"""
def proc = ["bash","-c","/usr/local/bin/aws s3 ls s3://Spark-Jenkins-Clusters/"].execute() | ["bash","-c","cut -c32-"].execute()
proc.waitForOrKill(10000)
return proc.text.tokenize()
""",
multiSelectDelimiter: ',',
name: 'Choose_Cluster',
description: 'This parameter is nice',
quoteValue: false,
saveJSONParameterToFile: false,
type: 'PT_SINGLE_SELECT',
visibleItemCount: 5
),

Create Okta user via Okta API in Jenkins

Question
I am running Jenkins for job automation and using Okta for authentication. I would like to create a Jenkins job that I can run on demand to create a user in Okta. The user will have the the attributes required by Okta: email, username, etc.
How can I accomplish this in Jenkins?
Initial Setup
I wrote a Jenkinsfile that will create an Okta user via the Okta API Documentation. Before you can run this script you need to install the following plugin's in Jenkins.
Credentials Binding
Pipeline Step Utilities
Http Request Plugin
After installing the aforementioned plugins you will need to create an Okta API Token and save it in Jenkin's Credential Manager of kind Secret Text ( and give it an ID of okta-api-token ).
Proof-of-Concept
The following is a proof-of-concept Jenkinsfile that will use the following plugins to create a user in Okta
pipeline {
agent {
label 'master'
}
options {
buildDiscarder( logRotator( numToKeepStr: "30" ) )
}
parameters {
string(name: 'firstName', description: 'New users first name')
string(name: 'lastName', description: 'New users last name')
string(name: 'email', description: 'New users email')
string(name: 'mobilePhone', description: 'New users phone')
password(name: 'password', description: 'Enter Password')
}
environment {
oktaDomain = "yourdomain.com"
}
stages {
stage('Execute') {
steps {
script {
// Create payload based on https://developer.okta.com/docs/reference/api/users/#request-example-3
def payload = """
{ "profile":{"firstname": "$firstName","lastNAme": "$lastName","email": "$email","login": "$email","mobilePhone": "$mobilePhone"}, "credentials": { "password:{ "value": "$password"}}}
"""
// Send HTTP Post request with API Token saved in credential manager
withCredentials([string(credentialsId: 'apiToken', variable: 'okta-api-token')]) {
def response = httpRequest(
acceptType: 'APPLICATION_JSON',
contentType: 'APPLICATION_JSON',
httpMode: 'POST',
requestBody: payload,
url: "https://${oktaDomain}/api/v1/users?activate=true",
customHeaders: [[Authentication: "SSWS ${apiToken}"]]
)
}
def json = readJSON text: response.content
echo json['id']
}
}
}
}
post {
changed {
emailext subject: 'Your Okta user has been created',
body: 'Your Okta user has been created',
replyTo: '$DEFAULT_REPLYTO',
to: "$email"
}
}
}
Assuming you followed the steps listed above you should only need to change the oktaDomain variable to your Okta domain.

Is it possible to have a Jenkins parameter's name with spaces in it?

I'm trying to make my Jenkins UI more clean.
My Jenkins file calls a function which in turn runs the following:
properties ([
[$class: 'GitLabConnectionProperty', gitLabConnection: 'GitlabConnection'],
[$class: 'ParametersDefinitionProperty', parameterDefinitions: [
[$class: 'BooleanParameterDefinition', defaultValue: false, description: '', name: 'activateInTest'],
[$class: 'ChoiceParameterDefinition', choices: 'false\ntrue\n', description: 'If running newBuild, skip unit tests', name: 'skipUnitTests']
]]
])
Currently, I can access these parameters like this:
if(activateInTest == 'true') {
//Do something
}
After going through other docs and examples. It looked as if I could also access parameters by doing something like params.activateInTest, which did not work. I also tried doing something like params["activateInTest"], but that didn't work either.
The reason I want to access it this way params["..."], is because I would like to have the name of my parameter be "Activate in Test" rather than "activateInTest".
In this example I see the person does use "BooleanParameterDefinition" with spaces in the name. But I can't seem to figure out how to use spaces in the name. Having spaces in the name is my only goal here.
yes, its possible, just use following notation:
${params['Name with space']}
tested on old Jenkins: 2.149
Indeed it is possible, user "string reference" to access it, i.e. params."Activate in Test"
For example:
properties([parameters([
string(name: 'Activate in Test', defaultValue: 'default value')
])])
echo params."Activate in Test"
In Java and Groovy space in a variable does not support! and it's not recommended but Jenkins supports it with 'String referencing'
But If you want to decorate the parameter Display Name it would be something like this
Jenkins Declarative Pipeline
pipeline {
agent any
parameters {
string(name: 'PERSON', defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?')
text(name: 'BIOGRAPHY', defaultValue: '', description: 'Enter some information about the person')
booleanParam(name: 'TOGGLE', defaultValue: true, description: 'Toggle this value')
choice(name: 'CHOICE', choices: ['One', 'Two', 'Three'], description: 'Pick something')
password(name: 'PASSWORD', defaultValue: 'SECRET', description: 'Enter a password')
}
stages {
stage('Example') {
steps {
echo "Hello ${params.PERSON}"
echo "Biography: ${params.BIOGRAPHY}"
echo "Toggle: ${params.TOGGLE}"
echo "Choice: ${params.CHOICE}"
echo "Password: ${params.PASSWORD}"
}
}
}
}
Scripted Pipeline
node {
properties(
[
parameters(
[string(defaultValue: '/data', name: 'Directory', description: "Directort Path"),
string(defaultValue: 'Dev', name: 'DEPLOY_ENV', description: "Deploy Environment")
]
)
]
)
stage('debug') {
echo "${params}"
}
}

When using a Jenkins pipeline, is there a way to get the user that responded to an input() action?

Consider the following example
node {
stage('Build') {
echo "do buildy things"
}
stage('Deploy') {
hipchatSend(
color: "PURPLE",
message: "Holding for deployment authorization: ${env.JOB_NAME}, job ${env.BUILD_NUMBER}. Authorize or cancel at ${env.BUILD_URL}",
)
input('Push to prod?') //Block here until okayed.
echo "Deployment authorized by ${some.hypothetical.env.var}"
echo "do deploy things"
}
}
When responding to the input, the user name that clicked the button is stored in the build log.
Is this username made available in a variable that I could use in, say, another hipChatSend?
Supply the field submitterParameter to input:
def userName = input message: '', submitterParameter: 'USER'
echo "Accepted by ${userName}"
The value of submitterParameter doesn't matter if you doesn't have any parameters. But if you have parameters, then it will specify the name of the array element which holds the value:
def ret = input message: '', parameters: [string(defaultValue: '', description: '', name: 'para1')], submitterParameter: 'USER'
echo "Accepted by ${ret['USER']}"

Resources