I'm trying to move some functions from a Jenkins Pipeline to a shared jenkins library. But I get errors when using the Credentials Binding Plugin (withCredentials)
For example I have this block of code:
withCredentials([usernamePassword(credentialsId: 'foobar', usernameVariable: 'fooUser', passwordVariable: 'fooPassword')]) {
// do something with credentials
}
When I move this block to a static library function I get the following error:
hudson.remoting.ProxyException:
groovy.lang.MissingMethodException:
No signature of method: static mylib.MyClass.usernamePassword() is applicable for argument types:
(java.util.LinkedHashMap) values: [[credentialsId:foobar, usernameVariable:fooUser, ...]]
Library Code:
package mylib;
class MyClass {
def static String doSomething() {
withCredentials([usernamePassword(credentialsId: 'foobar', usernameVariable: 'fooUser', passwordVariable: 'fooPassword')]) {
// some code
}
}
}
Usage in Jenkins Pipeline:
#Library('my-pipeline-library')
import mypackage.MyClass
...
MyClass.doSomething();
How can I use withCredentials/usernamePassword in my Jenkins Library? Do I need to qualify the functions with some package? Do I need extra imports? Is there any documentation about this?
I found a possible solution, not sure if i really like it:
I can pass the current script (this) from the pipeline script to the library. Then I can use this script variable to use functions in my pipeline library.
Looks like this:
Library Code:
package mylib;
class MyClass {
def static String doSomething(script) {
script.withCredentials([script.usernamePassword(credentialsId: 'foobar', usernameVariable: 'fooUser', passwordVariable: 'fooPassword')]) {
// some code
}
}
}
Usage in Jenkins Pipeline:
#Library('my-pipeline-library')
import mypackage.MyClass
...
MyClass.doSomething(this);
Myabe not the best method, but you can use the credential in the pipeline and pass what you extract from it as a parameter to the class:
jenkinsfile:
import com.mydomain.gcp
Gcp gcp = new Gcp()
Pipeline{
environment {
gcpCredentialId = 'YOUR-CREDENTIAL-ID'
}
stages {
stage('Authenticate') {
steps {
script {
withCredentials([file(credentialsId: env.gcpCredentialId, variable: 'gcpAuthFile')]) {
gcp.authenticate("${gcpAuthFile}")
}
}
}
}
}
}
then in the src\com\mydomain\Gcp.groovy file:
package com.mydomain.gcp
def authenticate(final String keyFile) {
sh "gcloud auth activate-service-account --key-file=${keyFile}"
}
return this
Related
Actually my Jenkinsfile looks like this:
#Library('my-libs') _
myPipeline{
my_build_stage(project: 'projectvalue', tag: '1.0' )
my_deploy_stage()
}
I am trying to pass these two variables (project and tag) to my build_stage.groovy, but it is not working.
What is the correct syntax to be able to use $params.project or $params.tag in my_build_stage.groovy?
Please see the below code which will pass parameters.
In your Jenkinsfile write below code:
// Global variable is used to get data from groovy file(shared library file)
def mylibrary
def PROJECT_VALUE= "projectvalue"
def TAG = 1
pipeline{
agent{}
stages{
stage('Build') {
steps {
script {
// Load Shared library Groovy file mylibs.Give your path of mylibs file which will contain all your function definitions
mylibrary= load 'C:\\Jenkins\\mylibs'
// Call function my_build stage and pass parameters
mylibrary.my_build_stage(PROJECT_VALUE, TAG )
}
}
}
stage('Deploy') {
steps {
script {
// Call function my_deploy_stage
mylibrary.my_deploy_stage()
}
}
}
}
}
Create a file named : mylibs(groovy file)
#!groovy
// Write or add Functions(definations of stages) which will be called from your jenkins file
def my_build_stage(PROJECT_VALUE,TAG_VALUE)
{
echo "${PROJECT_VALUE} : ${TAG_VALUE}"
}
def my_deploy_stage()
{
echo "In deploy stage"
}
return this
I have a jenkins pipeline which is written using a scripted syntax and I need to make this into a new pipeline using a declarative style.
This is my fist project with jenkins and I am stuck at how to translate the withCredentials syntax in declarative jenkins.
The original(scripted) pipeline looks something like this:
stage('stage1') {
steps {
script {
withCredentials([usernamePassword(credentialsId: CredentialsAWS, passwordVariable: 'AWS_SECRET_ACCESS_KEY', usernameVariable: 'AWS_ACCESS_KEY_ID')]) {
parallel (
something: {
sh 'some commands where there is no reference to the above credentials'
}
)
}
}
}
}
So far, I have set the credentials in question as an environment variable but since in the original pipeline these are not referenced in the command but they just wrap around the command as 'withCredentials', I am not sure how to achieve the same result. Any idea how to do this?
First of all take a look at official documentation
For your case pipeline will look like:
pipeline {
agent any
environment {
YOUR_CRED = credentials('CredentialsAWS')
}
stages {
stage('Call username and password from YOUR_CRED') {
steps {
echo "To call username use ${YOUR_CRED_USR}"
echo "To call password use ${YOUR_CRED_PSW}"
}
}
}
}
Jenkinsfile (Declarative Pipeline)
pipeline {
agent any
parameters {
string(name: 'STATEMENT', defaultValue: 'hello; ls /', description: 'What should I say?')
}
stages {
stage('Example') {
steps {
/* CORRECT */
sh('echo ${STATEMENT}')
}
}
}
}
visit here
I have created a pipeline that takes an array of JSON objects and will call a shared library which will iterate over the JSON objects
When trying to run the Jenkins job to test that I can forward the objects but I'm seeing the following error:
hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: imageBuild.call() is applicable for argument types: (java.lang.String) values: [[{"dockerConfig":"home/pipelines/conf/journeys/dockerbuild.yaml","aquaConfig":"home/pipelines/conf/journeys/aquascan.yaml","gtag": "v1.0.1","preFixName": "journey1"},{"dockerConfig":"home/pipelines/conf/if.com/dockerbuild.yaml","aquaConfig":"home/pipelines/conf/if.com/aquascan.yaml","gtag": "v2.0.2","preFixName": "journey2"},{"dockerConfig":"home/pipelines/conf/colleague/dockerbuild.yaml","aquaConfig":"home/pipelines/conf/colleague/aquascan.yaml","gtag": "v3.0.3","preFixName": "journey2"}]]
Possible solutions: call(), call(java.util.Map), wait(), any(), wait(long), main([Ljava.lang.String;)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:58)
Code:
library identifier: 'jenkins-sharedlib-cooking#BB-3611', retriever: modernSCM([$class: 'GitSCMSource',
remote: 'https://github.com/lbg-gcp-foundation/jenkins-sharedlib-cooking-lifecycle.git',
credentialsId: 'jenkinsPAT'])
def configList = '[{"dockerConfig":"home/pipelines/conf/journeys/dockerbuild.yaml","aquaConfig":"home/pipelines/conf/journeys/aquascan.yaml","gtag": "v1.0.1","preFixName": "journey1"},{"dockerConfig":"home/pipelines/conf/if.com/dockerbuild.yaml","aquaConfig":"home/pipelines/conf/if.com/aquascan.yaml","gtag": "v2.0.2","preFixName": "journey2"},{"dockerConfig":"home/pipelines/conf/colleague/dockerbuild.yaml","aquaConfig":"home/pipelines/conf/colleague/aquascan.yaml","gtag": "v3.0.3","preFixName": "journey2"}]'
pipeline {
environment {
def config =
brand =
environmentName =
CLUSTER_NAME =
CLUSTER_PROJECT =
VERSION = '1.0.0'
}
options {
ansiColor('xterm')
timeout(time: 150, unit: 'MINUTES')
disableConcurrentBuilds()
buildDiscarder(logRotator(numToKeepStr: '100'))
}
agent {
kubernetes {
label "jrn-${UUID.randomUUID().toString()}"
yamlFile "pipelines/conf/podTemplate.yaml"
}
}
stages {
stage('Stage 6 - Docker Image ') {
parallel {
stage ('Docker Image - Journeys') {
steps {
echo "*********************** Docker Journeys ***********************************"
container('docker') {
echo "Building the docker image..."
imageBuild(configList)
}
archiveArtifacts artifacts: "*.html", allowEmptyArchive: true
}
}
}enter code here
}
}
Looks like the groovy method or global variable imageBuild in the shared library Jenkins-shared lib-cooking#BB-3611 does not expecting any parameter but you are trying to pass a string, that's the reason you are getting MissingMethodException.
with the details
hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: imageBuild.call() is applicable for argument types: (java.lang.String) values
To fix the issue, you have to change the shared library method or global variable imageBuild from imageBuild() to imageBuild(String param) or imageBuild(def param)
I will try to illustrate with an example similar to your example for your reference.
Assuming you have a shared library in a git repository named - jenkins-sharedlib-cooking-lifecycle and you are following the folder structure suggested by Jenkins shared library documentation
// vars/imageBuild.groovy
import groovy.json.JsonSlurper
def call(def imagebuildParameter) {
def jsonSlurper = new JsonSlurper()
def object = jsonSlurper.parseText(imagebuildParameter)
// use loop on object to retrive the value like below
println object[0].name
}
//Jenkinsfile
node {
stage('stageName') {
def x = '[{"name": "foo"},{"name": "bar"}]'
imageBuild(x)
}
}
I want to have this code with exactly this syntax in my pipeline script:
withXCredentials(id: 'some-cred-id', usernameVar: 'USER', passwordVar: 'PASS') {
//do some stuff with $USER and $PASS
echo "${env.USER} - ${env.PASS}"
}
Note that you can put any code within withXCredenitals to be executed. withXCredentials.groovy resides in my Jenkins shared library under vars folder and it will use
Jenkins original withCredentials:
//withXCredentials.groovy
def userVar = params.usernameVar
def passwordVar = params.passwordVar
def credentialsId = params.credentialsId
withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: credentialsId, usernameVariable: usernameVar, passwordVariable: passwordVar]]) {
body()
}
I am still learning advanced groovy stuff but I can't work out how to do this.
Please note:
My question is more about the syntax in groovy and using Closure and the answer here is not what I am after. With that solution, I need to instantiate the class first and then call the method. So I'm trying to avoid doing something like this:
new WithXCredentials(this).doSomthing(credentialsId, userVar, passwordVar)
In Jenkins documentation it has an example of using closure:
// vars/windows.groovy
def call(Closure body) {
node('windows') {
body()
}
}
//the above can be called like this:
windows {
bat "cmd /?"
}
But it doesn't explain how to pass parameters like this
windows(param1, param2) {
bat "cmd /?"
}
See here
So after digging internet I finally found the answer. In case anyone needs the same thing. The following code will work:
// filename in shared lib: /vars/withXCredentials.groovy
def call(map, Closure body) {
def credentialsId = map.credentialsId
def passwordVariable = map.passwordVariable
def usernameVariable = map.usernameVariable
withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: credentialsId, usernameVariable: usernameVariable, passwordVariable: passwordVariable]]) {
echo 'INSIDE withXCredentials'
echo env."${passwordVariable}"
echo env."${usernameVariable}"
body()
}
}
With this you can have the following in your pipeline:
node('name') {
withXCredentials([credentialsId: 'some-credential', passwordVariable: 'my_password',
usernameVariable: 'my_username']) {
echo 'Outside withXCredenitals'
checkout_some_code username: "$env.my_username", password: "$env.my_password"
}
}
I'd like to use a withCredentials() block in a shared-variable ("vars/") script rather than directly in the Jenkins pipeline because this is a lower-level semantic of a particular library, and also may or may not be required depending on the situation. However, withCredentials (or, at least, that signature of it) doesn't appear to be in scope.
script:
def credentials = [
[$class: 'UsernamePasswordMultiBinding', credentialsId: '6a55c310-aaf9-4822-bf41-5500cd82af4e', passwordVariable: 'GERRIT_PASSWORD', usernameVariable: 'GERRIT_USERNAME'],
[$class: 'StringBinding', credentialsId: 'SVC_SWREGISTRY_PASSWORD', variable: 'SVC_SWREGISTRY_PASSWORD']
]
withCredentials(credentials) {
// ...
}
Console:
hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: BuildagentInstallAndRun.withCredentials() is applicable for argument types: (java.util.ArrayList, org.jenkinsci.plugins.workflow.cps.CpsClosure2) values: [[[$class:UsernamePasswordMultiBinding, credentialsId:6a55c310-aaf9-4822-bf41-5500cd82af4e, ...], ...], ...]
Has anyone had any success with this?
I'm using a shared library rather than a shared variable, but I guess it is a similar situation.
I'm not using the $class parameter, but i'm calling directly one of the functions suggested by the pipeline snippet generator. You can have a list here. In the example below, I use the usernameColonPassword binding.
In the pipeline, I instantiate the class utilities and I pass this to the constructor. Then, in the library, I use the step object to access the pipeline steps (such as withCredentials or usernameColonPassword).
class Utilities implements Serializable {
def steps
Utilities(steps) {
this.steps = steps
}
def doArchiveToNexus(String credentials, String artifact, String artifact_registry_path){
try {
this.steps.withCredentials([steps.usernameColonPassword(credentialsId: credentials, variable: 'JENKINS_USER')]) {
this.steps.sh "curl --user " + '${JENKINS_USER}' + " --upload-file ${artifact} ${artifact_registry_path}"
}
} catch (error){
this.steps.echo error.getMessage()
throw error
}
}
}
You can try following:
import jenkins.model.*
credentialsId = '6a55c310-aaf9-4822-bf41-5500cd82af4e'
def creds = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
com.cloudbees.plugins.credentials.common.StandardUsernameCredentials.class, Jenkins.instance, null, null ).find{
it.id == credentialsId}
println creds.username
println creds.password
But it is not secure, everything will be in console log
I was able to obtain credentials inside the shared library with proper passwords masking with such code:
class Utilities implements Serializable {
def steps
Utilities(steps) {
this.steps = steps
}
def execute() {
this.steps.withCredentials(
bindings: [
this.steps.usernameColonPassword(
credentialsId: this.credentialsId,
variable: "unameColonPwd")
]) {
this.steps.sh "echo {this.steps.env.unameColonPwd}"
}
}