In this set of exercises, we will see how you can capture interactive input in your Jenkins Pipeline while it is running, get an introduction to the Declarative post
sections and use a post-condition block to send a notification. We will also see how CloudBees Core enables easy simultaneous updates of all of our Team Masters and will use this capability to add the Slack plugin and necessary configuration to send a Slack notification from our Pipeline job.
For this exercise we are going to add a new stage after the Build and Push Image stage that will demonstrate how to pause a Pipeline job and prompt for interactive input.
NOTE: The Declarative
input
directive blocks thestage
from acquiring an agent and that is why it is configured outside thesteps
block as a directive. You could use the pre-exsitinginput
step directly in thesteps
block but that would hold whateveragent
is assigned to thatstage
for as long it takes for theinput
to be submitted.
- Use the GitHub file editor to update the
nodejs-app/Jenkinsfile.template
file in your forked custom-marker-pipelines repository - adding the followingstage
to your Pipeline after the Build and Push Imagestage
and commit the change:
stage('Deploy') {
when {
beforeAgent true
branch 'master'
}
input {
message "Should we continue?"
}
steps {
echo "Continuing with deployment"
}
}
-
Run your updated Pipeline job in Blue Ocean and note the
input
prompt during theDeploy
stage. Thisinput
prompt is also available in the Console log and classic Stage View. -
Your Team Master will wait indefinitely for a user response to an
input
step. Let's fix that by setting a timeout. Earlier we usedoptions
at the globalpipeline
level to set the Discard old builds strategy for your Team Master with thebuildDiscarder
option
. Now we will configureoptions
at thestage
level. We will add atimeout
option
for the Deploystage
using thestage
options
directive. Update the Deploystage
to match the following and then commit the changes:
stage('Deploy') {
when {
beforeAgent true
branch 'master'
}
options {
timeout(time: 30, unit: 'SECONDS')
}
input {
message "Should we continue?"
}
steps {
echo "Continuing with deployment"
}
}
- Run your updated Pipeline job in Blue Ocean and wait at least 30 seconds once it reaches the 'Deploy'
stage
. Your pipeline will be automatically aborted 30 seconds after the 'Deploy'stage
starts.Run it again if you would like - but this time approving it before 30 seconds expires - the job will complete successfully.
The input
directive supports a number of interesting configuration options. In this exercise we are going to use the submitter
option to control what Team Master member is allowed to submit the input
directive. But first you need to add another member to your CloudBees Team Master. Team Masters provide an easy to use authorization model right out-of-the-box. The following roles are available (there is a CLI to add or modify roles):
- Team Admin: administrator of the Team Master.
- Team Member: read, write and execute permission on the pipelines.
- Team Guest: read only.
We want to add a Team Guest to our Team Masters and then set that Team member as the submitter
for our input
directive. Before you begin, pick a person near you to pair up with. The two of you will share each other's Jenkins account names. You will use that account name when adding a new member to your Team Master below:
- On your Team Master, navigate to the Team list by clicking on the Administration link on the top right (this link is available on all Blue Ocean pages except for the Pipeline Run Details view).
- Next, click on the cog icon for your team.
- Click on the Members link in the left menu and then click on the Add a user or group link.
- Select Team Guest from the role drop-down, enter the account name for the person next to you in the Add user or group input (I will use beedemo-ops), press your enter/return key, and then click the Save changes button.
- Click on the Pipelines link in the top menu.
Now that we all have a new team member, you can add them as a submitter
for the input
directive in your nodejs-app/Jenkinsfile.template
Pipeline script.
- Use the GitHub file editor to update your
nodejs-app/Jenkinsfile.template
Pipeline script in your forked custom-marker-pipelines repository - updating theinput
directive of the Deploystage
with the following changes (replacing beedemo-ops with Jenkins username of your new Team Guest member). Also, update thetimeout
duration to give your approver plenty of time to submit theinput
:
options {
timeout(time: 60, unit: 'SECONDS')
}
input {
message "Should we deploy?"
submitter "beedemo-ops"
submitterParameter "APPROVER"
}
- So, we added one additonal configuration option for our
input
directive:submitterParameter
. Setting thesubmitterParameter
option will result in a Pipeline environmental variable namedAPPROVER
being set with the value being the username of the user that submitted theinput
. In the example above it will either be beedemo-ops. Update thesteps
section so theecho
step in yournodejs-app/Jenkinsfile.template
Pipeline script will print theAPPROVER
environmental variable and then commit the changes:
steps {
echo "Continuing with deployment - approved by ${APPROVER}"
}
- Navigate to the master branch of your helloworld-nodejs job in Blue Ocean on your Team Master and run the job. If you attempt to approve the
input
you will get an error: - The submitter needs to navigate to the master branch of your helloworld-nodejs job on your Team Master to approve the
input
of your helloworld-nodejs Pipeline. You can use the Team switcher to quickly navigate to another Team Master that you are a member. The Team switcher drop-down will appear in the top right of your screen once you have been added as a member to another Team Master. The submitter needs to switch to the Team where they are a Team Guest member by selecting that team from the Team switcher drop-down. - As the submitter navigate to the helloworld-nodejs job on your new team and approve the
input
. Note the output of theecho
step.
NOTE: If you select a Pipeline job as a favorite you will be able to see things like jobs awaiting
input
submission in the Blue Ocean Dashboard.
What happens if your input
step times out or if the approver clicks the Abort button? There is a special post
section for Delcarative Pipelines that allows you to define one or more additional steps that are run upon the completion of the entire pipeline
or an individual stage
execution and are designed to handle a variety of conditions (not only aborted) that could occur outside the standard Pipeline flow.
In this example we will add a post
section to our Deploy stage to handle a timeout or disapproval by our submitter (aborted run).
- Add the following
post
section just below theoptions
directive a the root of your Pipeline using the GitHub editor and commit your changes:
pipeline {
agent { label 'nodejs-app' }
options {
buildDiscarder(logRotator(numToKeepStr: '2'))
}
post {
aborted {
echo "Why didn't you push my button?"
}
}
NOTE: Even though we are putting the
post
section near the top of our Pipeline it will still run after all thestages
are complete.
- Run your pipeline from the Branches view of the Blue Ocean Activity View for your pipeline.
- Let the job timeout or have your
submitter
click the Abort button. You will see the following output: - In order to speed up the rest of the workshop, remove the the
submitter
option for theinput
directive by editing thenodejs-app/Jenkinsfile.template
file in your forked custom-marker-pipelines repository and then commit the changes. Your Deploystage
should match the following and you will now be able to approve your own job:
stage('Deploy') {
when {
beforeAgent true
branch 'master'
}
options {
timeout(time: 60, unit: 'SECONDS')
}
input {
message "Should we deploy?"
submitterParameter "APPROVER"
}
steps {
echo "Continuing with deployment - approved by ${APPROVER}"
}
}
By default, when a global agent
- that is an agent
at the pipeline
level - is used and there aren't any agents defined at the individual stage
levels, then that same agent
is shared across all the stages
and the source code repository associated with the Jenkins job is automatically checked out only once. But you will typically want to use different agents for different stages. And sometimes you don't need to checkout the source code for every stage
. That is the case for our Pipeline for the helloworld-nodejs repository - we will eventually have different Kubernetes Pod Template based agents for each stage
. So we are going to revisit the automatic code checkout for Declarative Pipelines that was mentioned in the Basic Declarative Syntax Structure lesson. Declarative Pipeline checks out source code by default as part of the agent
directive. However, we don't need all of the files in the helloworld-nodejs repository in all of the stages. The skipDefaultCheckout
option is a global level options
to disable automatic checkouts.
- First, update the global
options
directive by adding theskipDefaultCheckout
job setting below thebuildDiscarder
setting:
pipeline {
agent none
options {
buildDiscarder(logRotator(numToKeepStr: '2'))
skipDefaultCheckout true
}
- Next, we need to add a checkout step -
checkout scm
to the Test stage, we don't want to do a full checkout in any of the other stages but we do need a checkout in thisstage
:
stage('Test') {
agent { label 'nodejs-app' }
steps {
checkout scm
container('nodejs') {
echo 'Hello World!'
sh 'node --version'
}
}
}
- Navigate to the master branch of your helloworld-nodejs job in Blue Ocean on your Team Master and run the job.
NOTE: The
scm
part of thecheckout scm
step is a special environment variable that is created for all Pipelines configured to load their Pipeline script from source control such as our helloworld-nodejs Multibranch Pipeline project.
Typically if you are using the input
step with your Jenkins Pipeline you will want to send out a notification to the targeted approvers before the input
step pauses the job. In this exercise we will send a notification using the Slack plugin slackSend
step. But before that, we must update everyone's Team Master by installing and configuring the Slack plugin. Rather than have everyone do that manually on their own, we will take advantage of the CloudBees Core Operations Center Cluster Operations to bulk upgrade everyone's Team Master.
For the first part of this exercise everyone will just follow along as it is the Operations Center administrator that would perform this task for all the Teams across your organization. Most of the tasks required to complete this task have already been done, but we will review all of the components of the bulk-upgrade to enable Slack notifications across all Team Masters.
- For this workshop we have created a custom container (Docker) image for our Team Masters. Among other things, this custom image allows us to manage the automatic installation of additional plugins. So the first thing we will need to do is add the Slack plugin to this custom image. To do that, we just have to add a text entry to the
plugin.txt
file which is utilized by theplugin.sh
script to install every plugin in the list and their dependencies:
configuration-as-code:1.3
configuration-as-code-support:1.3
notification-api:1.1
operations-center-notification:1.0
aws-credentials:1.23
artifact-manager-s3:1.1
aws-global-configuration:1.0
devoptics:1.1561
slack:2.4
- Next we want to add the necessary configuration for the Slack plugin so that every Team can start using it right away. Fot that, we turn to the Jenkins Configuration as Code plugin. The CasC plugin allows us to define configuration for all the Team Masters in a simple yaml file that we copy into the custom container image. Here is the configuration snippet for the Slack plugin:
slackNotifier:
teamDomain: beedemo-team
tokenCredentialId: beedemo-slack
room: "#ci"
- After those changes are made for our custom container image, we need to build the image and push it to a container registry. We have already done that and the image has been pushed to an AWS Elastic Container Registry (ECR) as
946759952272.dkr.ecr.us-east-1.amazonaws.com/kypseli/cb-core-mm:2.138.3.1-kube-workshop-slack-2
. - Next, we need to update what Docker Image is the default for our Team Masters on Operations Center:
- Now all we have to do is run a Cluster Operation job on CloudBees Core Operations Center that has been configured to reprovision all of the Team Masters resulting in each Team Master using the new container image. Once your Team Master has been restarted the Slack plugin will be installed and cofigured:
That's it, once everyone's Team Master is restarted they will have the updated plugins and configuration provided by the updated container image.
Now all you have to do to send a Slack message is add the slackSend
step to your Pipeline. We will add it to the success
post
block of the Build and Push Image stage
.
- Use the GitHub file editor to update your
nodejs-app/Jenkinsfile.template
Pipeline script in your forked custom-marker-pipelines repository and add the followingpost
block after thesteps
block of the Build and Push Imagestage
and then commit the changes:
stage('Build and Push Image') {
agent any
when {
beforeAgent true
branch 'master'
}
steps {
echo "TODO - build and push image"
}
post {
success {
slackSend "${JOB_NAME} pipeline job is awaiting approval at: ${RUN_DISPLAY_URL}"
}
}
}
NOTE: The global environmental variables -
JOB_NAME
andRUN_DISPLAY_URL
that we are including in our Slack message are very handy for including in messages, providing a link to navigate directly to the job.
- Navigate to the master branch of your helloworld-nodejs job in Blue Ocean on your Team Master and run the job.
- After your Pipeline job completes the
steps
in the Build and Push Imagestage
a message from your Team Master in the beedemo-team #ci Slack channel as below:
Before moving on to the next lesson you can make sure that your nodejs-app/Jenkinsfile.template Pipeline script is correct by comparing to or copying from the after-approvals branch of your forked custom-marker-pipelines repository.
You may proceed to the next set of exercises - Pipeline Artifacts and Restartable, Parallel and Sequential Stages with CloudBees Core - when your instructor tells you.