Jenkins input on declarative pipeline - jenkins

may I ask if it is do-able if I can get the user input and run a script based on what was chosen by the user? the logic whould be
IF User choose Proceed THEN run a script (in my case promote or Blue/Green deployment)
IF User choose Abort THEN don't terminate the jenkins job, run a script (in my case rollback)
This is the script I'm using however I have no idea how to apply after validate stage
pipeline {
agent any
stages {
stage('Deploy') {
steps {
sh """#!/bin/bash +x
echo "performing sts assume role"
//SCRIPT-HERE//
echo "performing ansible deploy"
//SCRIPT-HERE//
"""
}
}
stage('validate') {
steps {
timeout(30) {
script {
input(message: 'Please validate, this job will automatically ABORTED after 30 minutes even if no user input provided', ok: 'Proceed')
}
}
}
}
}
}
One more issue I'm seeing is, although this pipeline script is running, The Proceed / Abort is not clickable on the jenkins job Console output, is it a bug? I'm referring to the image shown below
I was able to add nandilov's suggestion however it seems that the logic is still not applying, please advise on what is missed here
pipeline {
agent any
stages {
stage('Deploy') {
steps {
sh """#!/bin/bash +x
echo "performing sts assume role"
echo "performing ansible deploy"
"""
}
}
stage('validate') {
steps {
script {
env.flagError = "false"
try {
input(message: 'Please validate, this job will automatically ABORTED after 30 minutes even if no user input provided', ok: 'Proceed')
}catch(e){
println "input aborted or timeout expired, will try to rollback."
env.flagError = "true"
}
}
}
}
stage("If user selects Proceed"){
when{
expression { env.inputValue == "value1" }
}
steps{
sh """#!/bin/bash +x
echo "User selected proceed"
"""
}
}
stage("rollback if flag error true"){
when{
expression { env.inputValue == "value2" }
}
steps{
sh """#!/bin/bash +x
echo "User selected Abort"
"""
}
}
}
}
from the pipeline view it never triggered either one of the last two stages when choosing "Abort" or "Proceed"
These are the logs when choosing Abort or Proceed
ABORT
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] Start of Pipeline
[Pipeline] node
Running on Jenkins in /var/lib/jenkins/workspace/test-job-lagot
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Deploy)
[Pipeline] sh
performing sts assume role
performing ansible deploy
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (validate)
[Pipeline] script
[Pipeline] {
[Pipeline] input
Please validate, this job will automatically ABORTED after 30 minutes even if no user input provided
Proceed or Abort
[Pipeline] echo
input aborted or timeout expired, will try to rollback.
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (If user selects Proceed)
Stage "If user selects Proceed" skipped due to when conditional
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (rollback if flag error true)
Stage "rollback if flag error true" skipped due to when conditional
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
PROCEED
Started by user lagot
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] Start of Pipeline
[Pipeline] node
Running on Jenkins in /var/lib/jenkins/workspace/test-job-lagot
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Deploy)
[Pipeline] sh
performing sts assume role
performing ansible deploy
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (validate)
[Pipeline] script
[Pipeline] {
[Pipeline] input
Please validate, this job will automatically ABORTED after 30 minutes even if no user input provided
Proceed or Abort
Approved by lagot
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (If user selects Proceed)
Stage "If user selects Proceed" skipped due to when conditional
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (rollback if flag error true)
Stage "rollback if flag error true" skipped due to when conditional
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS

If you want to have the job aborted and do something, you can try/catch it:
try{
input(message: 'Please validate, this job will automatically ABORTED after 30 minutes even if no user input provided', ok: 'Proceed')
}catch(e){
println "input aborted or timeout expired, will try to rollback."
// execute rollback
}
You also can do it in another stage:
pipeline {
agent any
stages {
stage('Deploy') {
steps {
sh """#!/bin/bash +x
echo "performing sts assume role"
echo "performing ansible deploy"
"""
}
}
stage('validate') {
steps {
script {
env.flagError = "false"
try {
input(message: 'Please validate, this job will automatically ABORTED after 30 minutes even if no user input provided', ok: 'Proceed')
}catch(e){
println "input aborted or timeout expired, will try to rollback."
env.flagError = "true"
}
}
}
}
stage("If user selects Proceed"){
when{
expression { env.flagError == "false" }
}
steps{
sh """#!/bin/bash +x
echo "User selected proceed"
"""
}
}
stage("rollback if flag error true"){
when{
expression { env.flagError == "true" }
}
steps{
sh """#!/bin/bash +x
echo "User selected Abort"
"""
}
}
}

Try with this, you will need to click on Proceed and then to choose between "deploy" and "rollback". The result we'll be store in an environment variable and you can use it as a condition on the next stages
stage('validate') {
steps {
timeout(30) {
script {
CHOICES = ["deploy", "rollback"];
env.yourChoice = input message: 'Please validate, this job will automatically ABORTED after 30 minutes even if no user input provided', ok : 'Proceed',id :'choice_id',
parameters: [choice(choices: CHOICES, description: 'Do you want to deploy or to rollback?', name: 'CHOICE'),
string(defaultValue: 'rollback', description: '', name: 'rollback value')]
}
}
}
}
}
stage('Deploy') {
when {
expression { env.yourChoice == 'deploy' }
}
steps {
...
}
}
stage('Rollback') {
when {
expression { env.yourChoice == 'rollback' }
}
steps {
...
}
}

Related

Use exit code in if statement in Jenkins pipeline

Here's my Jenkins pipeline where I'm trying to to run a conditional statement on the basis of previous command's exit code.
pipeline{
agent any
stages{
stage('Test exitcode'){
steps{
script{
EX_CODE = sh(
script: 'echo hello-world',
returnStatus: true
)
if( env.EX_CODE == 0 ){
echo "Code is good with $EX_CODE"
}else{
echo "Code is Bad with $EX_CODE"
}
}
}
}
}
}
Here's its output
Started by user Yatharth Sharma
[Pipeline] Start of Pipeline
[Pipeline] node
Running on Jenkins in /var/lib/jenkins/workspace/devops/syntax-testing-pipeline
[Pipeline] { (hide)
[Pipeline] stage
[Pipeline] { (Test exitcode)
[Pipeline] script
[Pipeline] {
[Pipeline] sh
+ echo hello-world
hello-world
[Pipeline] echo
Code is Bad with 0
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
I was expecting this to return Code is good but this prints out Code is Bad. Can someone help me here with a why?
You are assigning the int return of the exit code from the shell interpreter command from the sh step method to a variable EX_CODE. You then attempt to access the value from the env object member in the conditional as if it were an environment variable instead of a variable. You can either modify the variable to be an environment variable, or access the variable directly (simpler).
EX_CODE = sh(script: 'echo hello-world', returnStatus: true)
if (EX_CODE == 0) {
echo "Code is good with ${EX_CODE}"
}
else{
echo "Code is Bad with ${EX_CODE}"
}

Jenkins Declarative Piplines- Script is unable to pickup parameter as varible

I am New to Jenkins. Trying to create one basic Pipeline which is using choicebased parameters. Following is my script.
Code ----
pipeline{
agent {
label 'agent'
}
parameters {
choice choices: ['John', 'Stacy'], description: 'Choose one', name: 'Person'
}
stages {
stage('Print') {
steps {
echo "Hello ${params.Person}"
sh """if (${params.Person} = "John")
then
echo "Person is male."
else
echo "Person is female."
fi"""
}
}
}
}
Now my build complete successfully regardless of whatever option I choose. It always display result "Person is female.
Following is result of one of my build.
Started by user ****
[Pipeline] Start of Pipeline
[Pipeline] node
Running on agent in
/home/temp/jenkins_agent/workspace/ChoiceBased PL
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Print)
[Pipeline] echo
Hello John
[Pipeline] sh
+ John = John
/home/temp/jenkins_agent/workspace/ChoiceBased PL#tmp/durable-
b7e98c46/script.sh: 1: John: not found
+ echo Person is female.
Person is female.
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: Success
Please suggest what I am missing ?
I would change this just to be in Groovy rather than doing the compare in sh
stage('Print') {
steps {
echo "Hello ${params.Person}"
script {
if (params.Person == "John") {
echo "Person is male."
} else {
echo "Person is female."
}
}
}
}
Then when you choose Stacey you will get
[Pipeline] echo
Hello Stacy
[Pipeline] script
[Pipeline] {
[Pipeline] echo
Person is female.
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS

Jenkins assign input to environment variable

Trying to assign user input from 1 stage to use in another stage , thought to do it with env variables but cant figure it out
code so far :
environment {
access_key =''
}
stages {
stage('User input for Auth'){
input {
message 'enter access_key'
parameters {
string 'access_key_input'
string 'secret_key_input'
}
}
environment {
access_key = sh(script:"echo ${access_key_input}", returnStdout: true).trim()
}
steps{
sh "echo ${env.access_key}"
}
}
stage("Build") {
steps {
sh "echo ${env.access_key}"
}
}
}
logs :
+ echo XXX
+ echo XXX
XXX
+ echo null
null
You can assign the input to a global variable and then access that wherever you want.
def INPUT_PARAMS = null
pipeline {
agent {
node {
label 'any'
}
}
options {
timestamps()
}
stages {
stage('User input for Auth') {
steps{
script {
INPUT_PARAMS = input message: "enter access_key", parameters: [
string(description: 'Access key', defaultValue: '', name: 'access_key_input'),
string(description: 'Secret access key', defaultValue: '', name: 'secret_key_input')
]
}
sh "echo ${INPUT_PARAMS.access_key_input}"
}
}
stage("Build") {
steps {
sh "echo ${INPUT_PARAMS.access_key_input}"
}
}
}
}
Input request
Output
Started by user Praveen Premaratne
Replayed #152
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] Start of Pipeline
[Pipeline] node
Running on devops-jenkins in /home/jenkins/workspace/Test
[Pipeline] {
[Pipeline] timestamps
[Pipeline] {
[Pipeline] stage
[Pipeline] { (User input for Auth)
[Pipeline] script
[Pipeline] {
[Pipeline] input
[2021-07-15T22:35:33.625Z] Input requested
[2021-07-15T22:35:43.540Z] Approved by Praveen Premaratne
[Pipeline] }
[Pipeline] // script
[Pipeline] sh
[2021-07-15T22:35:43.886Z] + echo a
[2021-07-15T22:35:43.886Z] a
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Build)
[Pipeline] sh
[2021-07-15T22:35:44.230Z] + echo a
[2021-07-15T22:35:44.230Z] a
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // timestamps
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS

Jenkins Pipeline with conditional "When" expression of choice parameters

I'm new to Groovy. I'm not able to figure out what's wrong here.
Depends on the choice of input, I expect the script to execute either Step 'Hello' or 'Bye' but it skips both. I mostly orientated to this Jenkins pipeline conditional stage using "When" for choice parameters, but still can't figure it out.
How can I use those choice parameters correctly?
pipeline {
agent any
stages {
stage('Init') {
steps('Log-in'){
echo 'Log-in'
}
}
stage('Manual Step') {
input {
message "Hello or Goodbye?"
ok "Say!"
parameters{choice(choices:['Hello','Bye'], description: 'Users Choice', name: 'CHOICE')}
}
steps('Input'){
echo "choice: ${CHOICE}"
echo "choice params.: " + params.CHOICE //null
echo "choice env: " + env.CHOICE //Hello
}
}
stage('Hello') {
when{ expression {env.CHOICE == 'Hello'}}
steps('Execute'){
echo 'Say Hello'
}
}
stage('Bye') {
when{ expression {env.CHOICE == 'Bye'}}
steps('Execute'){
echo 'Say Bye'
}
}
}
}
Output:
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Init)
[Pipeline] echo
Log-in
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Manual Step)
[Pipeline] input
Input requested
Approved by Admin
[Pipeline] withEnv
[Pipeline] {
[Pipeline] echo
choice: Hello
[Pipeline] echo
choice params.: null
[Pipeline] echo
choice env: Hello
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Hello)
Stage "Hello" skipped due to when conditional
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Bye)
Stage "Bye" skipped due to when conditional
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
From the docs:
Any parameters provided as part of the input submission will be available in the environment for the rest of the stage.
This means that your parameter CHOICE does not exist in the other stages. If you want to have a parameter that's available on all the stages, you can define a parameter outside of the stage, i.e.:
pipeline {
agent any
parameters {
choice(choices:['Hello','Bye'], description: 'Users Choice', name: 'CHOICE')
}
stages {
stage('Init') {
steps('Log-in') {
echo 'Log-in'
}
}
stage('Manual Step') {
steps('Input') {
echo "choice: ${CHOICE}"
echo "choice params.: " + params.CHOICE
echo "choice env: " + env.CHOICE
}
}
stage('Hello') {
when {
expression { env.CHOICE == 'Hello' }
}
steps('Execute') {
echo 'Say Hello'
}
}
stage('Bye') {
when {
expression {env.CHOICE == 'Bye'}
}
steps('Execute'){
echo 'Say Bye'
}
}
}
}
This will behave as expected. The difference is that the job won't ask you for input, instead, you will provide the wanted parameters before pressing build.

can not create file via Groovy code(or java code) in jenkinsfile of a pipeline job on Jenkins

pipeline {
agent any
stages {
stage('Build') {
steps {
echo 'Building..'
echo "whoami".execute().text
script {
File f = new File('/home/jenkins/test2.txt');
f.createNewFile();
}
}
}
stage('Test') {
steps {
echo 'Testing..'
}
}
stage('Deploy') {
steps {
echo 'Deploying....'
}
}
}
}
Jenkins console log: (got exception: Started by user Edgar Yu Running
in Durability level: MAX_SURVIVABILITY [Pipeline] node Running on
Jenkins in /var/jenkins_home/workspace/test2 [Pipeline] { [Pipeline]
stage [Pipeline] { (Build) [Pipeline] echo Building.. [Pipeline] echo
jenkins
[Pipeline] script [Pipeline] { [Pipeline] } [Pipeline] // script
[Pipeline] } [Pipeline] // stage [Pipeline] stage [Pipeline] { (Test)
Stage 'Test' skipped due to earlier failure(s) [Pipeline] } [Pipeline]
// stage [Pipeline] stage [Pipeline] { (Deploy) Stage 'Deploy' skipped
due to earlier failure(s) [Pipeline] } [Pipeline] // stage [Pipeline]
} [Pipeline] // node [Pipeline] End of Pipeline
java.io.IOException: Permission denied at java.io.UnixFileSystem.createFileExclusively(Native Method) at
java.io.File.createNewFile(File.java:1012)
This is due to Jenkins not implementing Groovy itself but an interpreter (CPS) - https://github.com/cloudbees/groovy-cps
To help deal with the complexities introduced, there are some common Steps implemented to take the trouble out of tasks such as creating a file.
To use Jenkins pipeline steps out of the box, use writeFile:
https://jenkins.io/doc/pipeline/steps/workflow-basic-steps/#code-writefile-code-write-file-to-workspace
writeFile([file: 'file.txt', text: filetxt])
If your deadset on writing your own, I suggest splitting it out into a Shared library, note this will probably cause ScriptSecurity alerts that will require approval:
final class PipelineUtils implements Serializable {
private script=null
private static final PipelineUtils instance = new PipelineUtils()
#NonCPS
String saveFile(String filename, String text) {
String PWD = script.pwd()
String filePath = "${PWD}/${filename}"
File file = new File(filePath)
file.text = text
}
}
See https://github.com/jenkinsci/pipeline-plugin/blob/master/TUTORIAL.md for information regarding #NonCPS and nonserializable objects.

Resources