Jenkins Pipeline Slack Two Way Step Interaction - jenkins

I'm building a declarative Jenkins Pipeline and after I have completed a few testing steps, I would like to have a step that notifies a slack channel that a build is ready to proceed to production. If that slack post is not responded to for a fixed amount of time, I would like Slack to notify Jenkins Pipeline to continue to the next step. If a fixed reply "ABORT" replies to the Slack post, I would like for Slack to communicate back to the Jenkins pipeline to abort the build. Any ideas on how to accomplish this two way interaction between Slack and Jenkins Pipeline?
node {
stage('build'){
echo "building"
}
}
stage('Deploy approval'){
input "Deploy to prod?"
}
node {
stage('deploy to prod'){
echo "deploying"
}
}

There is no way to do it directly . What you can do it is you can divide your jobs into two or three jobs and send notification at the end of first job using a function like this :
def notifySlack(text, channel) {
def slackURL = ' https://hooks.slack.com/services/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'
def payload = JsonOutput.toJson([text : text,
channel : channel,
username : "jenkins",
icon_emoji: ":jenkins:"])
sh "curl -X POST --data-urlencode \'payload=${payload}\' ${slackURL}"
}
then in slack you can write a script to build another part of your job (which is actually a new job) using slash commands :https://github.com/auth0/slash#inputs-and-outputs
This could be accomplished writing a php or any server side code and sending it paramaters where you can send ABORT and in the job you have to build , have a parameter to check the value of this passed parameter and have a condition according to it .

Related

Jenkins simple pipeline not triggered by github push

I have created a jenkins pipeline job called "pipelinejob" with the below script:
pipeline {
agent any
stages {
stage ('Setup'){
steps{
//echo "${BRANCH_NAME}"
echo "${env.BRANCH_NAME}"
//echo "${GIT_BRANCH}"
echo "${env.GIT_BRANCH}"
}
}
}
}
Under General, I have selected "GitHub project" and inserted my company's github in the form:
https://github.mycompany.com/MYPROJECTNAME/MY_REPOSITORY_NAME/
Under Build Triggers, i have checked "GitHub hook trigger for GITScm polling
I have created a simple job called "simplejob" with same configuration as 1) and 2)
In my company's Github, i have created a webhook like "jenkins_url/jenkins/github-webhook/"
I commit a change in "mybranch" in "MY_REPOSITORY_NAME"
My simple job "simplejob" is triggered and built successfully
My pipeline job "pipelinejob" is not triggered
In Jenkins log i see the below:
Sep 12, 2019 2:42:45 PM INFO org.jenkinsci.plugins.github.webhook.subscriber.DefaultPushGHEventSubscriber$1 run
Poked simplejob
Nothing regarding my "pipelinejob".
Could you please point me to the right directions as to what to check next?
P.S. I have manually executed my "pipelinejob" successfully
I wasted two days of work on this, as none of the previous solutions worked for me. :-(
Eventually I found the solution on another forum:
The problem is that if you use a Jenkinsfile that is stored in GitHub, along with your project sources, then this trigger must be configured in the Jenkinsfile itself, not in the Jenkins or project configuration.
So add a triggers {} block like this to your Jenkinsfile:
pipeline {
agent any
triggers {
githubPush()
}
stages {
...
}
}
Then...
Push your Jenkinsfile into GitHub
Run one build manually, to let Jenkins know about your will to use this trigger.
You'll notice that the "GitHub hook trigger for GITScm polling" checkbox will be checked at last!
Restart Jenkins.
The next push should trigger an automated build at last!
On the left side-pane of your pipeline job, click GitHub Hook log. If it says 'Polling has not run yet', you will need to manually trigger the pipeline job once before Jenkins registers it to poke on receiving hooks.
Henceforth, the job should automatically trigger on GitHub push events.
I found an answer to this question with scripted pipeline file. We need to declare the Github push event trigger in Jenkins file as follows.
properties([pipelineTriggers([githubPush()])])
node {
git url: 'https://github.com/sebin-vincent/Treasure_Hunt.git',branch: 'master'
stage ('Compile Stage') {
echo "compiling"
echo "compilation completed"
}
stage ('Testing Stage') {
echo "testing completed"
echo "testing completed"
}
stage("Deploy") {
echo "deployment completed"
}
}
}
The declaration should be in the first line.
git url: The URL on which pipeline should be triggered.
branch: The branch on which pipeline should be triggered. When you specify the branch as master and make changes to other branches like develop or QA, that won't trigger the pipeline.
Hope this could help someone who comes here for an answer for the same problem with Jenkins scripted pipeline :-(.
The thing is whenever you create a pipeline job for git push which is to be triggered by github-webhook, first you need to build the pipeline job manually for one time. If it builds successfully, then Jenkins registers it to poke on receiving hooks. And from the next git push, your pipeline job will trigger automatically.
Note: Also make sure that the pipeline job built manually for the first time should be built successfully, otherwise Jenkins will not poke it. If it fails to build, you can never trigger the job again.

How to control downstream pipeline's interactive input in upstream pipeline

I have an upstream pipeline which is calling another downstream pipeline
build job: "/org/projectA/master",
parameters: [[$class: 'StringParameterValue', name: 'variable', value: 'value']],
wait: true
In my downstream pipeline, there is a step to ask for approve
input "Deploy to prod?"
Currently the job is paused in the downstream pipeline waiting for approve, but in my main job (upstream pipeline), it is just waiting for sub pipeline to finish, doesn't show any message for approver. So is it possible to display the interactive input in my main pipeline? then the approver doesn't need to click to the sub pipeline to check the status.
BTW, I cannot move the input to main pipeline, cause there are other steps after it in the sub pipeline.
Thanks in advance for any suggestion
I really wouldn't recommend it, but there's a way via Jenkins Remote API -
Jenkins input pipeline step filled via POST with CSRF - howto?
curl -X POST -H "Jenkins-Crumb:${JENKINS_CRUMB}" -d json='{"parameter": {"name": "${PARAMETER_NAME}", "value": "${PARAMETER_VALUE}"}}' -d proceed='${SUBMIT_CAPTION}' 'http://j${JENKINS_URL}/job/${JOB_NAME}/${BUILD_ID}/input/${INPUT_ID}/submit'
The question would be how would you run this? A new input in the upstream job? Run when?
It might be more useful to divide the downstream job into two and run the actual deploy only when user accepts the input in the upstream job.

How to build with parameters in Jenkins from Gitlab push?

I have GitLab Community Edition 8.15.2 successfully trigger pipeline projects in Jenkins 2.32.1 using a webhook. I want the gitlab push to trigger a build with parameters but the parameter value is null when it comes through so the build fails.
The gitlab webhook looks like:
http://jenkins.server:8080/project/project-a/buildWithParameters?MYPARAM=foo
In my pipeline project I echo the parameter value out with
echo "MYPARAM: ${MYPARAM}"
and it's not set to anything. Any ideas on where I've gone wrong?
UPDATE
The actual code I'm using in the pipeline is:
node {
try {
echo "VM_HOST: ${VM_HOST}"
echo "VM_NAME: ${VM_NAME}"
stage('checkout') {
deleteDir()
git 'http://git-server/project/automated-build.git'
}
stage('build') {
bat 'powershell -nologo -file Remove-MyVM.ps1 -VMHostName %VM_HOST% -VMName "%VM_NAME%" -Verbose'
}
...
}
}
The parameter VM_HOST has a default value but VM_NAME doesn't. In my Console output in Jenkins I can see:
[Pipeline] echo
VM_HOST: HyperVHost
[Pipeline] echo
VM_NAME:
I have been struggling with this for weeks. I had it working once, but I couldn't get it to work again, untill today. And the solution was mindblowingly obvious ofcourse...
Automatically for each pipeline job I ticked the following box:
Build when a change is pushed to GitLab. GitLab CI Service URL:
http://jenkins.dev:8080/project/MyProject
Then from GitLab I used the webhook to trigger the above.
Like you I tried to add /buildWithParameters and tried many other things that didn't work.
The problem was, I ticked the wrong checkbox!
Since I trigger the build from a GitLab webhook, the above checkbox (build when a...) does not have to be checked at all.
What needs to be checked is:
Trigger builds remotely (e.g., from scripts)
That checkbox provides you with a new URL:
Use the following URL to trigger build remotely:
JENKINS_URL/job/MyProject/build?token=TOKEN_NAME or
/buildWithParameters?token=TOKEN_NAME
Like all the documentation I came along states and as you can see, the URL now no longer starts with /project, but with /job instead!
So tick that box and change your URL accordingly:
http://jenkins.server:8080/**job**/project-a/buildWithParameters?token=TOKEN_NAME&MYPARAM=foo
Least I want to mention the token:
In the GitLab webhook there is a seperate field for "token", which states:
Use this token to validate received payloads. It will be sent with the request in the X-Gitlab-Token HTTP header.
So, the token provided there will be sent along the request as a HTTP header.
This is the token which can be provided globally in the Jenkins setup.
The token you must provide in the Jenkins job when ticking the box Use the following URL to trigger build remotely must be send in the URL as GET parameter, just like the example shows.
Final note: personally I have never got this working completely, because I don't get the Jenkins CSRF protection off my back. Disabling it gives me another error. However, hopefully the above does fix the problem for you and others.
GitLab plugin does not allow you to pass arbitrary parameters. In their project there is an open issue for it that deserves to be upvoted.
My convoluted solution was to use the desired values for the push trigger as the default parameters of the job. Then I used the Parameterized Scheduler plugin to use other values in the scheduled executions.
The problem is that I got a bad usability for the job when it was manually run, since the default parameters were appropriate for the push hook.
I found the solution here https://www.jittagornp.me/blog/jenkins-gitlab-webhook/
I verified it with Jenkins 2.263.1 and GitLab Community Edition 13.6.1
Your webhook url will look like
https://hunter:11a403302a4f01b9b4975c0ac27441a5cc#jenkinsservername.com/job/yourjenkinsproject/buildWithParameters?token=Aju9ryHUu6t7W8wLSeCWtY2bWjzQduYNPyY7B3gs&yourparam=yourvalue
"hunter" ist your username in Jenkins.
The following is the Jenkins API Token you have to create in your Jenkins User Managment independent of the project.
The last Token is the one you specify in the jenkins project options under "Trigger builds remotely (e.g., from scripts)"
The last thing is to add your Parameter and value to the url with &param=value

Jenkins - How to get and use upstream info in downstream

Executing upstream job called "A". On success of A executing test cases which is downstream project "B". But while sending mail from B we have to incorporate upstream project details (upstream project name, build no) in mail. So we can easily map / corelate the test run with respective upstream job.
In downstream project dashboard below details are displaying.
Started by upstream project Dev_RM_3.0_CI_Test build number 10
originally caused by:
I checked in https://wiki.jenkins-ci.org/display/JENKINS/Building+a+software+project. but couldnt find anything to inherit in downstream.
Created sample job with below details to display the current job details.
echo $BUILD_NUMBER
echo $JOB_NAME
echo $BUILD_ID
But the output is
Building on master in workspace /var/lib/jenkins/workspace/env
[env] $ /bin/sh -xe /tmp/hudson970280339057643719.sh
+ echo 1
1
+ echo env
env
+ echo 1
1
Finished: SUCCESS
Any help to inherit upstream details in downstream job?
How to get current job details?
The message that you refer to your question "Started by upstream project "Chained/1-First" build number 34" for example, is available in the jenkins Cause.
Jenkins keeps the upstream build info in it's cause object. If your are using build DSL or Pipelines you may get it in groovy. Alternatively you can curl the job url and use jq to get the Cause
For example curl http://localhost:8080/job/Chained/job/2-Second/17/api/json
"_class": "org.jenkinsci.plugins.workflow.job.WorkflowRun",
"actions": [{
"_class": "hudson.model.CauseAction",
"causes": [{
"_class": "hudson.model.Cause$UpstreamCause",
"shortDescription": "Started by upstream project \"Chained/1-First\" build number 34",
"upstreamBuild": 34,
"upstreamProject": "Chained/1-First",
"upstreamUrl": "job/Chained/job/1-First/"
}]
}
Or from the pipeline for example:
node() {
stage('downstream') {
def upstream = currentBuild.rawBuild.getCause(hudson.model.Cause$UpstreamCause)
echo upstream?.shortDescription
}
}
You can get a bunch of information out of Cause, pending all the script approvals or a global shared step. You will get a null if a different cause triggers this build, eg commit, or user.
You can pass in the upstream variables via build parameters to the downstream job and then you can access them (in the downstream job) using things such as ${MyParameter1} and ${MyParameter2}.
You would need to:
Add build parameters to the downstream job. For example, a string parameter named "ParentJobName".
Add a post build "Trigger downstream parameterized builds on other projects" to the upstream job.
Add something like "Current Build parameters" or "Predefined parameters" to the #2 and pass in whatever you need. For example:
ParentJobName=${JOB_NAME}
Access the parameters as you would other build variables. e.g. ${ParentJobName}
You should be able to pass in the basic stuff that way. Anything more complicated than that and you will probably be better off using a plugin like Copy Artifacts Plugin to copy files or using the Jenkins API in a system groovy step to get/modify the upstream build, etc.
You can simply use params.variableName in your downstream job to retrieve the parameters passed from your upstream parameter job. Your downstream job need not necessarily be a parameterized job.
Extending #razboy answer:
this is good way if Cause cannot be whitelisted in sandbox. I forgot about Jenkins API and used current build console to look for string about trigger cause. You can try to fetch data from API as #razboy or get current console and grep it if you need simple stuff. Jenkins API is more flexible for more complex logic. To get API help,append /api to your build url: <jenkins_url>/job/<buildUrl>/<buildNumber>/api
def buildUrl = env.BUILD_URL
sh "wget $buildUrl -O currentConsole.txt"
statusCode = sh returnStatus: true,script: 'cat currentConsole.txt | grep -q "Started by upstream project"'
boolean startedByUpstream= statusCode==0
MeowRude's answer helped me. To repcap it, in upstream job:
build job: 'mail-test', parameters: [[$class: 'StringParameterValue', name: 'VERSION_NUMBER', value: '1.0.0.0']]
And in downstream job:
echo "${params.VERSION_NUMBER}"
You may have to have certain plugins installed, but
def causes = currentBuild.getBuildCauses()
will return an ArrayList of objects that will most likely provide the necessary details, for example upstreamProject for the full project name and upstreamBuild for the build number. Then you can correlate results between up- and downstream builds easily.
Source: link to pipeline-examples in razboy's comment above

Jenkins Slack integration

I want to use the Slack plugin in Jenkins to ping notifications to a Slack channel.
Jenkins says success when I test the connection, but I don't receive any notifications in my Slack channel.
Are there any known problems?
How can I get Jenkins to send notifications to Slack?
I think that you should add post-build action "Slack Notification" in your Jenkins. Please see the image below
And are you sure that you have a correct configuration.
In Build Configuration (Do not forget # character)
In General Configuration
There are two steps to configure a Jenkins job to be posting on a slack channel.
Go to jenkins job configurations and add a post-build action on each job that you wish to ping the slack channel.
Next, again under the job configurations, you have to configure on each job on which cases you wish to send slack notifications: (true - false)
f.e.
In the case that you have to configure a great number of Jenkins jobs, you could configure only one of them manually and verify it is working fine. Then check the config.xml of this Jenkins job to find the auto-generated xml elements for the slack plugin preferences and apply those configs on all Jenkins jobs by using regex or xslt. In this case, you will have to reload the Jenkins configs for the job configurations updates to be applied. ("Manage Jenkins" / "Reload Configuration from Disk")
Prerequisites:
Install slack plugin in Jenkins.
Obtain a Jenkins CI integration token in your slack domain.
Go in Jenkins "Manage Jenkins" / "Configure System". There you have to configure the "Global Slack Notifier Setting".
I didn't use the Slack Notification because I wanna customize style/state/message, etc. So I wrote a job called send_slack_notification instead. Every time I want to notify slack API I just call this job after build.
Here's the code in "Execute Shell", I used curl, sed and jsawk to do the job:
# URL to get the built info json
# will get "http://JENKINS_PATH/job/JOB_NAME/97/api/json"
NEW_URL="http://jks_username:jks_password#"$(echo ${BUILD_URL} | sed -r 's/http:\/\///g')"/api/json"
# Cut the JOB_NAME part from BUILD_URL
JOB_NAME=$(echo ${BUILD_URL} | sed -n 's/.*\/job\/\(.*\)\/[0-9].*/\1/p' | sed "s#+# #g;s#%#\\\\x#g" | xargs -0 printf "%b")
# Get the built info json
JSON=$(curl $NEW_URL)
STATUS=$(echo $JSON | /usr/local/bin/jsawk "return this.result")
BUILD_INFO=$(echo $JSON | /usr/local/bin/jsawk "return this.displayName")
TIME=$(echo $JSON | /usr/local/bin/jsawk "return this.duration")
TIME=$(echo "scale=4; $TIME/1000" | bc -l)
# Cut the username
USER=$(echo $JSON | /usr/local/bin/jsawk "return this" | sed -n "s/.*Started\ by\ \([^\"]*\).*/\1/p")
# Customize the message sending to slack
TEXT=$JOB_NAME" Built by "$USER", it took "$TIME" seconds."
# Send notification using Slack API
# will send to https://hooks.slack.com/services/BLABLABLA/BLABLABLA
curl -X POST -H 'Content-type: application/json' --data '{"channel": "#production_info","username": "jenkins-bot","icon_emoji": ":lol:","text": "'"$TEXT"' (<'"$BUILD_URL"'|Open>)", "attachments": [{"color": "#36a64f", "fields": [{"title":"UPDATE INFO","value":"'"$BUILD_INFO"'","short":true},{"title":"RESULT","value":"'"$STATUS"'","short":true}]}]}' https://hooks.slack.com/services/BLABLABLA/BLABLABLA/BLABLABLABLABLABLA
I though of adding it here for the greater good of the community. This is how you get the integration token
Jenkins Instructions
Get a Slack account: https://slack.com/
Configure the Jenkins integration: https://my.slack.com/services/new/jenkins-ci
Install this plugin on your Jenkins server
Configure it in your Jenkins job and add it as a Post-build action.
https://github.com/jenkinsci/slack-plugin
import os
import sys
from slacker import Slacker
import base64
def main():
myPass=sys.argv[1]
msgStr= sys.argv[2]
channel = sys.argv[3]
slack = Slacker(myPass)
slack.chat.post_message(channel, msgStr)
print msgStr
if __name__ == '__main__':
main()
python slack.py <token> < message str > <#channel>
I couldn't get anything but 'failure' from the slack connection test in the config. I can use python from the same box so I don't know what the issue is so I may just use this simple script.
If you want to receive notifications using Jenkins declarative pipelines, you can install the Slack plugin, and then use it in the pipeline in this way:
stage('Clone sources') {
steps {
slackSend (channel: "#mychannel", color: '#FFFF00', message: "STARTED: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})")
git credentialsId: 'git_credentials', poll: false, branch: 'develop', url: 'https://mysource.com/mysimplenodejsexample.git'
}
}
Result:
You can customize your message of course. Full example at:
https://pillsfromtheweb.blogspot.com/2020/05/send-notifications-to-slack-from.html
I had similar issues.
It worked for me when i unchecked "is Bot User?"
starting Jenkins in console with 'jenkins' not with brew demon, though.
Maybe that helps :)
Greetings ^__^

Resources