Unable to test BaselinePipelineTest withCredentialInterceptor - groovy

I'm trying to test a function in my Jenkins Script Pipeline.
void doSomeDockerThings(){
withCredentials([[$class: 'UsernamePasswordMultiBinding', creditialsId: 'my_creds', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD']]) {
sh "docker login -u $USERNAME -p '$PASSWORD' $DTR"
}
}
From a Groovy Unit Test that extends BasePipelineTest, I have the following test method.
#Test
void testDoSomeDockerThings(){
helper.registerAllowedMethod( "withCredentials", [LinkedHasMap.class, Closure.class], null );
helper.registerAllowedMethod( "sh", [String.class], {c -> return c; })
binding.setVariable( "USERNAME", "user" );
binding.setVariable( "PASSWORD", "password" );
binding.setVariable( "DTR", "Docker_Trusted_Registry" );
}
What I want to do is now write an assert that this command executed with what I expected. Since that is in a Closer of withCredentials how can I verify this?
sh "docker login -u $USERNAME -p '$PASSWORD' $DTR"
I've also tried using the withCredentialsInterceptor and I can't seem to get the syntax right for what it expects. If anyone has an example of that I would appreciate it.
helper.registerAllowedMethod( "withCredentials", [LinkedHasMap.class, Closure.class], withCredentialsInterceptor );
I'm really struggling to find documentation or examples are how to do this.

Related

how to write the correct pipline jenkins docker grovy node

I am rewriting my pipline in node, I need to understand how to perform a step with a gait in node now an error is coming from stage('Deploy')
node {
checkout scm
def customImage = docker.build("python-web-tests:${env.BUILD_ID}")
customImage.inside {
sh "python ${env.CMD_PARAMS}"
}
stage('Deploy') {
post {
always {
allure([
includeProperties: false,
jdk: '',
properties: [],
reportBuildPolicy: 'ALWAYS',
results: [[path: 'report']]
])
cleanWs()
}
}
}
and this is the old pipeline
pipeline {
agent {label "slave_first"}
stages {
stage("Создание контейнера image") {
steps {
catchError {
script {
docker.build("python-web-tests:${env.BUILD_ID}", "-f Dockerfile .")
}
}
}
}
stage("Running and debugging the test") {
steps {
sh 'ls'
sh 'docker run --rm -e REGION=${REGION} -e DATA=${DATA} -e BUILD_DESCRIPTION=${BUILD_URL} -v ${WORKSPACE}:/tmp python-web-tests:${BUILD_ID} /bin/bash -c "python ${CMD_PARAMS} || exit_code=$?; chmod -R 777 /tmp; exit $exit_code"'
}
}
}
post {
always {
allure([
includeProperties: false,
jdk: '',
properties: [],
reportBuildPolicy: 'ALWAYS',
results: [[path: 'report']]
])
cleanWs()
}
}
}
I tried to transfer the method of creating an allure report, but nothing worked, I use the version above, almost everything turned out, you can still add environment variables to the build, for example, those that are specified -e DATA=${DATA} how do I add it
I don't recommend to switch from declarative to scriptive pipeline.
You are losing possibility to use multiple tooling connected with declarative approach like syntax checkers.
If you still want to use scriptive approach try this:
node('slave_first') {
stage('Build') {
checkout scm
def customImage = docker.build("python-web-tests:${env.BUILD_ID}")
customImage.inside {
sh "python ${env.CMD_PARAMS}"
}
}
stage('Deploy') {
allure([
includeProperties: false,
jdk: '',
properties: [],
reportBuildPolicy: 'ALWAYS',
results: [[path: 'report']]])
cleanWs()
}
}
There is no post and always directive in scriptive pipelines. It's on your head to catch all exceptions and set status of the job. I guess you were using this page: https://www.jenkins.io/doc/book/pipeline/syntax/, but it's a mistake.
This page only refers to declarative approach and in few cases you have hidden scriptive code as examples.
Also i don't know if you have default agent label set in your Jenkins config, but by looking at your declarative one I think you missed 'slave_first' arg in node object.
those that are specified -e DATA=${DATA} how do I add it
That's a docker question not a Jenkins. If you want to launch docker image and then also have access to some reports located in this container you should mount workspace/file where those output files landed. You should also pass location of those files to allure.
I suggest you to try this:
mount some subfolder in workspace to docker container
cat test report file if it's visible
add allure report with passing this file location to allure step

How to define a test stage in Jenkins pipeline which makes use of curl to check if the server is up or not?

I am using latest Jenkins in my Linux box.
I would like to implement a Test stage like below:
pipeline {
agent any
stages {
stage('Test') {
HTTP_CODE = sh (
script: 'echo $(curl --write-out \\"%{http_code}\\" --silent --output /dev/null http://localhost/)',
returnStdout: true
).trim()
}
}
}
In this stage, I want to execute a bash script to check whether the web server is up or not. HTTP_CODE variable will have the value 200 if everything is fine, and if there is any other value, then it can be treated as error.
How can I implement this logic as a testing stage in my Jenkins pipeline?
Thanks.
You should update your pipeline as follow:
pipeline {
agent any
stages {
stage('Test') {
HTTP_CODE = sh (
script: 'echo $(curl --write-out \\"%{http_code}\\" --silent --output /dev/null http://localhost/)',
returnStdout: true
).trim()
if ('200' != HTTP_CODE) {
currentBuild.result = "FAILURE"
error('Test stage failed!)
}
}
}
}
Regards.

Unable to interpolate sensitive environment variables

I have a piece of code that runs like this
package core.jenkins
class Utils implements Serializable {
def script
Utils(script) {
this.script = script
}
def func() {
script.withCredentials([script.usernamePassword(credentialsId: 'chartmuseum-basic-auth', usernameVariable: 'USER', passwordVariable: 'PASSWORD')]) {
script.sh "helm repo add --username script.USER} --password ${script.PASSWORD} chartmuseum \"http://${chartmuseumHostname}:8080\""
}
}
The above works perfectly fine but I do not a warning
Warning: A secret was passed to "sh" using Groovy String interpolation, which is insecure.
Affected argument(s) used the following variable(s): [PASSWORD, USER]
See https://jenkins.io/redirect/groovy-string-interpolation for details.
+ helm repo add --username **** --password **** chartmuseum http://apps-chartmuseum.apps.svc.cluster.local:8080
So following the guide, Im doing the following
script.withCredentials([script.usernamePassword(credentialsId: 'chartmuseum-basic-auth', usernameVariable: 'USER', passwordVariable: 'PASSWORD')]) {
script.sh 'helm repo add --username $script.USER --password $script.PASSWORD chartmuseum "http://$chartmuseumHostname:8080"'
}
But running the variable values are not be properly substitured and I get
+ helm repo add --username .USER --password .PASSWORD chartmuseum http://:8080
Error: Looks like "http://:8080" is not a valid chart repository or cannot be reached: Get http://:8080/index.yaml: dial tcp :8080: connect: connection refused
So neither the credentials nor the value of the chartmuseumHostname variable is being substituted correctly. What am I missing here ?
Actuall withCredentials() creates a environment variable which you can access it from shell scripts.
See here: https://www.jenkins.io/doc/pipeline/steps/credentials-binding/
Try using directly the shell variables:
script.sh 'helm repo add --username $USER --password $PASSWORD chartmuseum "http://$chartmuseumHostname:8080"'
Just binding together the answers already on this post, the withCredentials makes it so that you should be able to use the variables directly (answer by #catalin), the single quotes make it so that jenkins should stop complaining about security and if you want to be extra careful, you can double quote the variable values as suggested in the docs for withCredentials.
This should give you something like this:
script.withCredentials([script.usernamePassword(credentialsId: 'chartmuseum-basic-auth',
usernameVariable: 'USER',
passwordVariable: 'PASSWORD')]) {
script.sh 'helm repo add --username "$USER" --password "$PASSWORD" chartmuseum "http://$chartmuseumHostname:8080"'
}
which still leaves us with the question of why you are calling things with the script. prefix as mentioned in the comments by #matt-schuchard.
I try using the suggestion by #Catalin (https://www.jenkins.io/doc/pipeline/steps/credentials-binding/ using directly the shell variables)
But for me adding double quotes inside single quotes doesn't work.
The only solution I found is taking the variables out of the single quotes like:
'myscript $secretvariable' + notsecretvariable
Examples:
Test1: Try using recommended solution (jenkins/#catalin)
Code:
sh label: 'Test1', script: 'echo this is a secret $docker_pwd this is not "$dockerRegistry"'
Result: variable dockerRegistry is not interpolated/resolved
15:50:43 [Pipeline] sh (Test1)
15:50:43 + echo this is a secret **** this is not ''
15:50:43 this is a secret **** this is not
Test2: Take non-sensitive variable out of the single quotes:
sh label: 'Test2', script: 'echo this is a secret $docker_pwd this is not' + dockerRegistry
Result: variable dockerRegistry is properlly resolved
15:50:44 [Pipeline] sh (Test2)
15:50:44 + echo this is a secret **** this is not my.repositories.xx
15:50:44 this is a secret **** this is not my.repositories.xx

Linux screen dissapears after Jenkins job is done

I have made a Jenkins pipeline for my Angular application.
This Angular application uses SSR, so you have to run it in the background.
Thus I decided to use a screen for this, here is my JenkinsFile:
pipeline {
agent any
environment {
HOME = '.'
}
stages {
stage('build') {
steps {
sh 'npm i'
sh 'npm run build:ssr'
}
}
stage('move') {
steps {
script {
if (BRANCH_NAME == 'master') {
sh 'rm -R /var/www/AngularJenkinsTest_Master/client || true'
sh 'mkdir /var/www/AngularJenkinsTest_Master/client || true'
sh 'cp -R $WORKSPACE/dist/AngularJenkinsTest/* /var/www/AngularJenkinsTest_Master/client'
}
}
}
}
stage('publish') {
steps {
script {
if (BRANCH_NAME == 'master') {
sh 'screen -X -S AngularJenkinsTest_Master kill | true'
sh 'screen -dmS AngularJenkinsTest_Master'
sh 'screen -S AngularJenkinsTest_Master -X stuff "node /var/www/AngularJenkinsTest_Master/client/server/main.js\n"'
}
}
}
}
}
}
As you can see in "publish", I kill the screen (as it is running a node application), I then create a new screen and send a command to it.
I added a screen -ls to the end of it, and it did show that it existed, but when I go to my linux console.
jenkins#server:/root$ screen -ls
No Sockets found in /run/screen/S-jenkins.
This is the output that jenkins gives me:
Jenkins Output
I am new to Jenkins, so maybe I am just being dumb, but is there any reason for this to happen?

Groovy: Seems like a scope issue but cannot find where, can you?

I wrote some functions to help me writing Jenkins pipelines.
The following functions, are responsible to returning a shell command output:
def gen_uuid(){
randomUUID() as String
}
def sh_out(cmd){
String uuid = gen_uuid()
sh """( ${cmd} )> ${uuid}"""
String out = readFile(uuid).trim()
sh "set +x ; rm ${uuid}"
return out
}
That shown, here's another function:
Map get_started_by(){
withCredentials([ // Use Jenkins credentials ID of artifactory
[$class: 'UsernamePasswordMultiBinding', credentialsId: '0b8d591a-f4ce-XXXX-XXXX-faecb504d3d0', usernameVariable: 'J_USER', passwordVariable: 'J_PASS'],
]){
List startedBy = sh_out("""
set +x; curl -u ${J_USER}:${J_PASS} '${env.BUILD_URL}api/json' 2>/dev/null | \
python -mjson.tool | \
awk -F'"' '/(userId|userName)/{print \$4}'
""").split(/(\n)/)
return [
userId: startedBy[0],
userName: startedBy[1]
]
}
}
Which returns the userId and userName of the user who issue the job run.
Then, my problem is in this function:
def run_in_stage_func(String stage_name, Closure command, String sendTo){
String started_by = get_started_by()
String ulink = "<#${started_by['userId']}>"
String jlink = "(<${env.BUILD_URL}|Open>)"
println "============================================================"
stage (stage_name) {
try {
command()
if (currentBuild.result == 'FAILURE') {
error "Build failed, see log for further details."
}
println "============================================================"
} catch (Exception ex) {
def except = "${ex}"
slackSend channel: channel, color: 'danger', teamDomain: null, token: null,
message: " :${ulink} *Failed to build ${env.JOB_NAME}*! :x: ${jlink} (<!here|here>)"
echo "Pipeline failed at stage: ${stage_name}"
throw ex
}
}
}
When I run the job, I get the following error:
groovy.lang.MissingPropertyException: No such property: userId for class: java.lang.String
What could be the reason that the line ' String ulink = "<#${started_by['userId']}>" ' - is not working as intended?
You cast the result of get_started_by() to String explicitly. To fix it, change your code to
def started_by = get_started_by()
or
Map started_by = get_started_by()

Resources