Jenkins Publish Over SSh pipeline parameterized - jenkins

I am using Publish over SSH plugin in Jenkins to deploy the jar file which is created from the build process. I have created a pipeline like this
node {
{
stage('Checkout') {
git([url: '.............', branch: 'myBranch', credentialsId: 'mycredentials'])
}
stage('Build') {
script{
sh 'chmod a+x mvnw'
sh './mvnw clean package'
}
}
stage('Deploy to Server'){
def pom = readMavenPom file: 'pom.xml'
script {
sshPublisher(publishers: [sshPublisherDesc(configName: 'server-instance1',
transfers: [sshTransfer(cleanRemote:true,
sourceFiles: "target/${env.PROJECT_NAME}-${pom.version}.jar",
removePrefix: "target",
remoteDirectory: "${env.PROJECT_NAME}",
execCommand: "mv ${env.PROJECT_NAME}/${env.PROJECT_NAME}-${pom.version}.jar ${env.PROJECT_NAME}/${env.PROJECT_NAME}.jar"),
sshTransfer(
execCommand: "/etc/init.d/${env.PROJECT_NAME} restart -Dspring.profiles.active=${PROFILE}"
)
])
])
}
}
}
}
This works. I have a SSH Server configured under Manage Jenkins >> Configure System >> Publish Over SSH.
Now I want to deploy on multiple servers. Lets say I create multiple ssh configurations by name server-instance1, server-instance2. How do I make this Jenkins job parameterized ? I tried with checking the checkbox and selecting a Choice Parameter. But I am not able to figure out how to make the values for this dropdown come from the SSH server list(instead of hardcoding)
I tried few things as mentioned here(How to Control Parametrized publishing in Jenkins using Publish over SSH plugin's Label field). Unfortunately none of the articles talks about doing this from a pipeline.
Any help is much appreciated.

If you want to select the SSH server name dynamically, you can use the Extended Choice Parameter plugin which allows you to execute groovy code that will create the options for the parameter.
In the plugin you can use the following code to get the values:
import jenkins.model.*
def publish_ssh = Jenkins.instance.getDescriptor("jenkins.plugins.publish_over_ssh.BapSshPublisherPlugin")
configurations = publish_ssh.getHostConfigurations() // get all server configurations
return configurations.collect { it.name } // return the list of all servers
To configure this parameter in you pipeline you can use the following code for scripted pipeline:
properties([
parameters([
extendedChoice(name: 'SERVER', type: 'PT_SINGLE_SELECT', description: 'Server for publishing', visibleItemCount: 10,
groovyScript: '''
import jenkins.model.*
def publish_ssh = Jenkins.instance.getDescriptor("jenkins.plugins.publish_over_ssh.BapSshPublisherPlugin")
return publish_ssh.getHostConfigurations() .collect { it.name }
''')
])
])
Or the following code for declarative pipeline:
pipeline {
agent any
parameters {
extendedChoice(name: 'SERVER', type: 'PT_SINGLE_SELECT', description: 'Server for publishing', visibleItemCount: 10,
groovyScript: '''
import jenkins.model.*
def publish_ssh = Jenkins.instance.getDescriptor("jenkins.plugins.publish_over_ssh.BapSshPublisherPlugin")
return publish_ssh.getHostConfigurations() .collect { it.name }
''')
}
...
}
Once the parameter is defined just use it in your sshPublisher step:
sshPublisher(publishers: [sshPublisherDesc(configName: SERVER, transfers: ...
Another option you can have when using the Extended Choice Parameter is to configure it as Multi-Select instead of Single-Select so a user can then select multiple severs, and you can use the parallel option to publish over all selected servers in parallel.

Related

set pipelineTriggers in Jenkinsfile to set 'Trigger builds remotely (e.g., from scripts)'

I have a Jenkinsfile and I want to set a pipelineTrigger property for my stage 'setup parameters'
#! /usr/bin/env groovy
pipeline {
agent any
stages {
stage('setup parameters'){
steps{
script{
properties([
parameters([
string(name: 'payload', defaultValue: '')
]),
pipelineTriggers(])
])
}
}
}
What i'm trying to do is after the first attempted run of the Job, the following checkbox should be checked with token filled out.
When I have looked for the pipeline syntax, it does not list this as one of the trigger options.
Thanks!
It's authenticationToken in the pipelineJob:
pipelineJob('project-name') {
definition {
...
}
parameters {
...
}
authenticationToken('TOKENHERE')
}
https://jenkinsci.github.io/job-dsl-plugin/#method/javaposse.jobdsl.dsl.jobs.WorkflowJob.authenticationToken

Scripts not permitted to use staticMethod org.codehaus.groovy.runtime.DefaultGroovyMethods write java.io.File java.lang.String

I'm trying to create vault-deployment using Jenkins. Here's a link to my repo.
When running the script I'm getting
"Scripts not permitted to use staticMethod org.codehaus.groovy.runtime.DefaultGroovyMethods write java.io.File java.lang.String. Administrators can decide whether to approve or reject this signature." issue.
I got this issue after adding a stage "Generate Vars".
If I remove this stage in the code the other stages works, but they don't complete the job. This is because it needs to get token for vault deployment and it needs to get it from .tfvars file.
It's not a good idea to share my variables on GitHub, that's why I`m trying to create vault.tfvars through Jenkins and provide any token before running a pipeline job.
Does anyone know how to fix this???
If some part is not clear please feel free to ask questions!
If I find the solution for this issue I will share it here with the link to my GitHub.
Thanks
Here is my code Jenkinsfile.groovy
node('master') {
properties([parameters([
string(defaultValue: 'plan', description: 'Please provide what action you want? (plan,apply,destroy)', name: 'terraformPlan', trim: true),
string(defaultValue: 'default_token_add_here', description: 'Please provide a token for vault', name: 'vault_token', trim: true)
]
)])
checkout scm
stage('Generate Vars') {
def file = new File("${WORKSPACE}/vaultDeployment/vault.tfvars")
file.write """
vault_token = "${vault_token}"
"""
}
stage("Terraform init") {
dir("${workspace}/vaultDeployment/") {
sh 'ls'
sh 'pwd'
sh "terraform init"
}
stage("Terraform Plan/Apply/Destroy"){
if (params.terraformPlan.toLowerCase() == 'plan') {
dir("${workspace}/vaultDeployment/") {
sh "terraform plan -var-file=variables.tfvars"
}
}
if (params.terraformPlan.toLowerCase() == 'apply') {
dir("${workspace}/vaultDeployment/") {
sh "terraform apply --auto-approve"
}
}
if (params.terraformPlan.toLowerCase() == 'destroy') {
dir("${workspace}/vaultDeployment/") {
sh "terraform destroy --auto-approve"
}
}
}
}
}
Generally, we choose pipeline to execute in Groovy sandbox which has restriction in some aspects for security considering. Like using new keyword, using static method.
But you need Jenkins admin to add the restriction to whitelist in jenkins > Manage jenkins > In-process Script Approval
To write file, Jenkins pipeline supply alternative writeFile which has no such restriction.
writeFile file: '<file path>', text: """
vault_token = "${vault_token}"
"""
As #yong already pointed out the right way to achieve this and avoid eventual restrictions in environments where we don't have admin control is to use writeFile
i.e.:
writeFile file: 'tmp/query.sql', text: "SELECT * FROM table"
Advantage of this is that migrating from fully managed to restricted environment will be painless.
Subfolders, like 'tmp' in example, will be automatically created and code itself is pretty verbose

Using Jenkins to run SonarQube against any Project and choice of branche(s)

I am working on creating a single Jenkins job that allows you to pick the GitHub project and then select the branch you would like to run your SonarQube tests on.
So far I have been able to create a job that ONLY runs against the Master build of each project.
Does anyone have any experience creating something like this?
Thanks!
You need to parametrize your build.
You will have to make gitproject and gitBranch as a parameter this will make you select the project you want to run and select the branch too. Here is an example
pipeline {
agent {
node {
label any
}
}
parameters {
choice(
name: 'PLATFORM',
choices:"Test\nArt19-Data-Pipeline\nBrightcove-Report\nBrightcove-Video\nData-Delivery\nGlobal_Facebook_Engagement_Score\nGoogle-Analytics-Data-Pipeline\nInstagram-Data-Pipeline\nTwitter-Analytics\nTwitter-Data-Pipeline\nYoutube-Data",
description: "Choose the lambda function to deploy or rollback")
choice(
name: 'STAGE',
choices:"dev\nstag",
description: "Choose the lambda function to deploy or rollback")
}
stages {
stage("Git CheckOut") {
steps {
//CheckOut from the repository
//git credentialsId: 'svc.gitlab',branch:'master', url: 'git#git.yourProjectURL/yourProjectName.git'
echo " Parameters are ${PLATFORM}"
echo " STAGE IS ${STAGE}"
}
}
}
}
All you need is replace the 'master' with a a paramter and the 'yourProjectName' with another paramter instead of the one i used as example

How can I rename Jenkins' pull request builder's "status check" display name on GitHub

We have a project on GitHub which has two Jenkins Multibranch Pipeline jobs - one builds the project and the other runs tests. The only difference between these two pipelines is that they have different JenkinsFiles.
I have two problems that I suspect are related to one another:
In the GitHub status check section I only see one check with the following title:
continuous-integration/jenkins/pr-merge — This commit looks good,
which directs me to the test Jenkins pipeline. This means that our build pipeline is not being picked up by GitHub even though it is visible on Jenkins. I suspect this is because both the checks have the same name (i.e. continuous-integration/jenkins/pr-merge).
I have not been able to figure out how to rename the status check message for each Jenkins job (i.e. test and build). I've been through this similar question, but its solution wasn't applicable to us as Build Triggers aren't available in Multibranch Pipelines
If anyone knows how to change this message on a per-job basis for Jenkins Multibranch Pipelines that'd be super helpful. Thanks!
Edit (just some more info):
We've setup GitHub/Jenkins webhooks on the repository and builds do get started for both our build and test jobs, it's just that the status check/message doesn't get displayed on GitHub for both (only for test it seems).
Here is our JenkinsFile for for the build job:
#!/usr/bin/env groovy
properties([[$class: 'BuildConfigProjectProperty', name: '', namespace: '', resourceVersion: '', uid: ''], buildDiscarder(logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '', daysToKeepStr: '', numToKeepStr: '5')), [$class: 'ScannerJobProperty', doNotScan: false]])
node {
stage('Initialize') {
echo 'Initializing...'
def node = tool name: 'node-lts', type: 'jenkins.plugins.nodejs.tools.NodeJSInstallation'
env.PATH = "${node}/bin:${env.PATH}"
}
stage('Checkout') {
echo 'Getting out source code...'
checkout scm
}
stage('Install Dependencies') {
echo 'Retrieving tooling versions...'
sh 'node --version'
sh 'npm --version'
sh 'yarn --version'
echo 'Installing node dependencies...'
sh 'yarn install'
}
stage('Build') {
echo 'Running build...'
sh 'npm run build'
}
stage('Build Image and Deploy') {
echo 'Building and deploying image across pods...'
echo "This is the build number: ${env.BUILD_NUMBER}"
// sh './build-openshift.sh'
}
stage('Upload to s3') {
if(env.BRANCH_NAME == "master"){
withAWS(region:'eu-west-1',credentials:'****') {
def identity=awsIdentity();
s3Upload(bucket:"****", workingDir:'build', includePathPattern:'**/*');
cfInvalidate(distribution:'EBAX8TMG6XHCK', paths:['/*']);
}
};
if(env.BRANCH_NAME == "PRODUCTION"){
withAWS(region:'eu-west-1',credentials:'****') {
def identity=awsIdentity();
s3Upload(bucket:"****", workingDir:'build', includePathPattern:'**/*');
cfInvalidate(distribution:'E6JRLLPORMHNH', paths:['/*']);
}
};
}
}
Try to use GitHubCommitStatusSetter (see this answer for declarative pipeline syntax). You're using a scripted pipeline syntax, so in your case it will be something like this (note: this is just prototype, and it definitely must be changed to match your project specific):
#!/usr/bin/env groovy
properties([[$class: 'BuildConfigProjectProperty', name: '', namespace: '', resourceVersion: '', uid: ''], buildDiscarder(logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '', daysToKeepStr: '', numToKeepStr: '5')), [$class: 'ScannerJobProperty', doNotScan: false]])
node {
// ...
stage('Upload to s3') {
try {
setBuildStatus(context, "In progress...", "PENDING");
if(env.BRANCH_NAME == "master"){
withAWS(region:'eu-west-1',credentials:'****') {
def identity=awsIdentity();
s3Upload(bucket:"****", workingDir:'build', includePathPattern:'**/*');
cfInvalidate(distribution:'EBAX8TMG6XHCK', paths:['/*']);
}
};
// ...
} catch (Exception e) {
setBuildStatus(context, "Failure", "FAILURE");
}
setBuildStatus(context, "Success", "SUCCESS");
}
}
void setBuildStatus(context, message, state) {
step([
$class: "GitHubCommitStatusSetter",
contextSource: [$class: "ManuallyEnteredCommitContextSource", context: context],
reposSource: [$class: "ManuallyEnteredRepositorySource", url: "https://github.com/my-org/my-repo"],
errorHandlers: [[$class: "ChangingBuildStatusErrorHandler", result: "UNSTABLE"]],
statusResultSource: [ $class: "ConditionalStatusResultSource", results: [[$class: "AnyBuildResult", message: message, state: state]] ]
]);
}
Please check this and this links for more details.
You can use the Github Custom Notification Context SCM Behaviour plugin https://plugins.jenkins.io/github-scm-trait-notification-context/
After installing go to the job configuration. Under "Branch sources" -> "GitHub" -> "Behaviors" click "Add" and select "Custom Github Notification Context" from the dropdown menu. Then you can type your custom context name into the "Label" field.
This answer is pretty much like #biruk1230's answer. But if you don't want to downgrade your github plugin to work around the bug, then you could call the API directly.
void setBuildStatus(String message, String state)
{
env.COMMIT_JOB_NAME = "continuous-integration/jenkins/pr-merge/sanity-test"
withCredentials([string(credentialsId: 'github-token', variable: 'TOKEN')])
{
// 'set -x' for debugging. Don't worry the access token won't be actually logged
// Also, the sh command actually executed is not properly logged, it will be further escaped when written to the log
sh """
set -x
curl \"https://api.github.com/repos/thanhlelgg/brain-and-brawn/statuses/$GIT_COMMIT?access_token=$TOKEN\" \
-H \"Content-Type: application/json\" \
-X POST \
-d \"{\\\"description\\\": \\\"$message\\\", \\\"state\\\": \\\"$state\\\", \
\\\"context\\\": \\\"${env.COMMIT_JOB_NAME}\\\", \\\"target_url\\\": \\\"$BUILD_URL\\\"}\"
"""
}
}
The problem with both methods is that continuous-integration/jenkins/pr-merge will be displayed no matter what.
This will be helpful with #biruk1230's answer.
You can remove Jenkins' status check which named continuous-integration/jenkins/something and add custom status check with GitHubCommitStatusSetter. It could be similar effects with renaming context of status check.
Install Disable GitHub Multibranch Status plugin on Jenkins.
This can be applied by setting behavior option of Multibranch Pipeline Job on Jenkins.
Thanks for your question and other answers!

How to use Jenkins String Parameter in pipeline

We am using Jenkins Pipeline to configure jobs in jenkins. For a bunch of jobs we need user input for which we use parameterised build where user can input parameter values and later we use the values in our .jenkinsfile in sh like
sh "./build-apply.sh ${accountnumber} ${volumename} ${vpcname} services ${snapshotid}"
This used to work with
Jenkins 2.16
Pipeline 2.3
Groovy 2.15
However, when I rebuild Jenkins to:
2.16 or latest 2.26
Pipeline 2.5
Pipeline: Groovy 2.19
The above sh stopped working. Error being
groovy.lang.MissingPropertyException: No such property: accountnumber for class: groovy.lang.Binding
Any idea what I am missing? Is the syntax not correct?
For reference full Jenkinsfile for reference
node {
// Mark the code checkout 'stage'....
stage 'Checkout'
git branch: '****', credentialsId: '***', url: '****'
stage 'Provision Volume'
withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', accessKeyVariable: '*****',
credentialsId: '****',
secretKeyVariable: '*****']]) {
// Run the terraform build
env.PATH = "${env.PATH}:/jenkins/terraform"
sh "./build-apply.sh ${accountnumber} ${volumename} ${vpcname} services ${snapshotid}"
}
}
Copy and paste the below code in the pipeline script
node: {
stage ('BCCdlVsLib') {
build job: 'BCCdlVsLib', parameters:
[
[$class: 'StringParameterValue', name: 'BINPATH', value: 'BINPATH'],
[$class: 'StringParameterValue', name: 'SOURCEFILE', value: 'SOURCEFILE']
]
}
In the jobs (BCCdlVsLib) enable the option "this project is parametrized" and enter 2 string parameters job_binpath,job_sourcefile.
Print the variables in the pipeline jobs
echo job_binpath
echo job_sourcefile
After run the pipeline job,will get the below output.
BINPATH
SOURCEFILE

Resources