So guys, I was recently reviewing some pipelines in my work and found that we were making a big mistake when we used an input step.
It is currently possible to use this Jenkins input to pause the execution of a pipeline and ask the user if he wants to continue execution, or request any other user information as a parameter, however, the pipeline is paused to interaction with the user.
This strategy is used in some pipeline models, especially in the Trunk-Based Development.
Ok Júlio, but what is Trunk-Based Development?
Briefly (and very briefly) the Trunk-Based model advocates the use of only 1 branch and the constant integration of it to allow faster and more accurate feedbacks.
To read more about TBD, click here.
Following the Trunk-Based model, when we start a Job in Jenkins, the chosen (or pre-defined) branch will be applied in all environments (stage, qa, prod) however, in our pipeline there is a question if you really want to do deploy that branch in that particular environment (Input Step).
Generally, and for good practice, every input step has a timeout (for cases where there is no response from the user, Jenkins aborts the job execution automatically), and that time is generally used to perform some smoke testing to ensure approval.
Here’s an example of an input step with timeout.
timeout(time: 2, unit: “HOURS”) {
input message: ‘Approve Deploy?’, ok: ‘Yes’
}Example: Let’s say the set timeout is 2 hours. The job has started and when deploying to QA the team decides to do a test before approving for production. (Without thinking about the scenario where the user who started the job forgets to abort and the job is aborted by timeout).
There’s the problem.
When a Job is started in Jenkins, it starts an instance and all its integration is managed by an agent.
When an agent is active, Jenkins is consuming resources from our cluster, which can lead to “queuing” of jobs due to lack of resources.
Therefore, while we wait for the user’s response, there is an agent locking resources unnecessarily (which may disrupt other people who want to start their jobs).
But how to solve this?
It is currently advisable to use the Pipeline as Code (PaC) model to create pipelines.
This model allows our pipelines to be customized for each application in a very simple way, by simply changing the Jenkinsfile, and if a problem occurs on the Jenkins server and it loses its settings, we do not need to reconfigure anything (unlike the model Free-Style).
By Jenkins’s standard, for the agent to start the pipeline, the stages must be within the node block and knowing that, you can think of a strategy to optimize resource utilization by Jenkins.
To optimize the use of resources, just close the node running after the stage prior to the input step, and if the continuation of the execution is approved, just open another node. (simple like this \o/)
With this, when we enter in the input step,Jenkins will kill the current agent (releasing resource) and will start another agent if the pipeline continuation is approved.
Note: You can notice that it maintains the build id, ensuring that the pipeline is the same.
If you are not using any repository for images (Helm ChartMuseum for example) you will need to perform the checkout again when starting the other node, however this is not such a big problem since there are ways you can optimize the checkout by removing the tags and taking only the last commit.
For example:
def doCheckout(branchName, gitUrl){
checkout([$class: ‘GitSCM’,
branches: [[name: branchName]],
doGenerateSubmoduleConfigurations: false,
extensions:[[$class: ‘CloneOption’, noTags: true, reference: ‘’, shallow: true]],
userRemoteConfigs: [[credentialsId: ‘<Your credentials id>’, url: gitUrl]]])
}To conclude, see a pipeline model using the PaC strategy, with the approval stage following best practices.
def LABEL_ID = "yourappname-${UUID.randomUUID().toString()}"
def BRANCH_NAME = "<Your branch name>"
def GIT_URL = "<Your git url>"
// Start Agent
node(LABEL_ID) {
stage('Checkout') {
doCheckout(BRANCH_NAME, GIT_URL)
}
stage('Build') {
...
}
stage('Tests') {
...
}
}
// Kill Agent
// Input Step
timeout(time: 15, unit: "MINUTES") {
input message: 'Do you want to approve the deploy in production?', ok: 'Yes'
}
// Start Agent Again
node(LABEL_ID) {
doCheckout(BRANCH_NAME, GIT_URL)
stage('Deploy') {
...
}
}
def doCheckout(branchName, gitUrl){
checkout([$class: 'GitSCM',
branches: [[name: branchName]],
doGenerateSubmoduleConfigurations: false,
extensions:[[$class: 'CloneOption', noTags: true, reference: '', shallow: true]],
userRemoteConfigs: [[credentialsId: '<Your credentials id>', url: gitUrl]]])
}I hope this content helps you.
Best regards,
Join our community Slack and read our weekly Faun topics ⬇
Comments (4)
that does not help because the prompts do not show up in the console.
Hi dhruva chandra, thank you for your response.
I’m sorry, but I didn't understand your point. Can you explain, please?
following your tutorial these steps do not show the required prompt for the input directive ```node {
stage('build'){ echo "build app..." } stage('build :int'){ echo "deploy int" } } input message: 'Do you want to approve the deploy in qa?', ok: 'Yes' node { stage('build :qa'){ echo "build qa..." } }The following prompt does however show this
node { stage('build'){ echo "build app..." } stage('build :int'){ echo "deploy int" } } node { stage('checkpoint'){ input message: 'Do you want to approve the deploy in qa?', ok: 'Yes' } }however this means adding another tile in the build dashboard. I am not sure if this means I . will need to write a custom class or something to have the prompt w/o an extra tile in the dashboard.
Thank Dhruva, now I understood.
Correct, with my approach you really can’t see the question in the console, but you have a modal with the question in the pipeline (I think that it’s more elegant), but you are wrong when said that the approach not help, because you can response the question in the modal.