How do I add a lockableResources lock to a pipelineJob in Jenkins?

78 Views Asked by At

I am trying to add a lock to my Jenkins pipeline so that multiple instances of the pipeline will not run at the same time.

I installed the lockable-resources plugin in plugins.txt and declared the resources in my casc.yaml

 lockableResourcesManager:
    declaredResources:
      - name: "host-1-lock"
        description: "Lock to run jobs on host 1

I have the following pipelineJob that I am trying to add the lock to such that the lock will be held for the duration of the pipelineJob and then released after

pipelineJob('Test_Job-2') {
    quietPeriod(0)
    triggers {
        cron('H 6 * * *')
    }
    lockableResources('host-1-lock')
    parameters {
        labelParam('Node_Select') {
            defaultValue('host1')
            allNodes('allCases', 'IgnoreOfflineNodeEligibility')
        }
    }
    definition {
        cps {
            script(readFileFromWorkspace('scripts/mypipeline.jenkinsfile'))
        }
    }
}

However I get the error

ERROR: (script, line 6) No signature of method: javaposse.jobdsl.dsl.jobs.WorkflowJob.lockableResources() is applicable for argument types: (java.lang.String) values: [host-1-lock]

I have tried using the syntax lock("host-1-lock") as specified in the docs https://github.com/jenkinsci/lockable-resources-plugin however this yields a similar error.

I have also tried including the lock() within definition { cp { ...}} both before script() and within script() without any luck.

Can anyone provide an example of how to achieve this?

UPDATE:

It looks like I am using lock in the wrong place, instead I have tried adding it to the script itself.

i.e. scripts/mypipeline.jenkinsfile:

pipeline {
    options {
        ansiColor('xterm')
    }
    agent any
    stages {
        lock('host-1-lock')
        stage ('Build 1') {
            when {
                allOf {
                    expression { return params.RUN_BUILD }
                }
            }
            steps {
                catchError(stageResult: 'FAILURE') {
                    retry(count: 7) {
                        timeout(time: 180, unit: 'MINUTES') {
                            script {
                                def result = buildLabJob(STAGE_BUILD)
                                sh "exit $result"
                            }
                        }
                    }
                }
            }
            post {
                failure {
                    log("warn", "Build failed, skipping remaining stages")
                    script {
                        skipRemainingStages = true
                    }
                }
            }
        }
        stage ('Build Cluster DPU') {
            when {
                allOf {
                    expression { return params.RUN_BUILD }
                }
            }
            steps {
                catchError(stageResult: 'FAILURE') {
                    retry(count: 7) {
                        timeout(time: 360, unit: 'MINUTES') {
                            script {
                                def result = buildLabJob(STAGE_BUILD_JOBS)
                                sh "exit $result"
                            }
                        }
                    }
                }
            }
            post {
                failure {
                    log("warn", "Build failed, skipping remaining stages")
                    script {
                        skipRemainingStages = true
                    }
                }
            }
        }

        stage ('Deploy Custom') {
            when { 
                allOf {
                    expression { !skipRemainingStages }
                    expression { return params.RUN_CUSTOM }
                }
            }
            steps {
                catchError(stageResult: 'FAILURE') {
                    script {
                        def result = buildLabJob(STAGE_CUSTOM_JOBS)
                        sh "exit $result"
                    }
                }
            }
            post {
                failure {
                    script {
                        skipRemainingStages = true
                    }
                }
            }        
        }
}

However this gives an error as well, saying that lock is undefined. I see the docs show lock being used within a stage, but I need to hold the lock throughout multiple stages. Is this possible?

UPDATE 2:

I found a way to do this would be to add actual stages to take and return the lock

    stage('Acquire Lock') {
        steps {
            lock(resource: 'Lab240-lock') {
                echo 'Lock acquired'
            }
        }
    }
...other stages...
    stage('Release Lock') {
        steps {
            lock(resource: 'Lab240_lock', inversePrecedence: true) {
                echo 'Lock released'
            }
        }
    }

However, I am not seeing the desired behavior. Pipeline 1 is started, takes the lock, and starts running jos. Pipeline 2 is started (running the same script) while pipeline1 is still running various stages, and immediately gets the lock and starts running its stages. Since these jobs use the same executor, the pipelines take turns running stages, however I need the lock to prevent pipeline2 from running anything until pipeline1 completes.

2

There are 2 best solutions below

1
blackbuild On

You have put it in the wrong place. The usage of the lock should not be part of the jobdsl (aka the Job definition), but in the actual pipeline, in your case in scripts/mypipeline.jenkinsfile`.

Take close look at the example in https://github.com/jenkinsci/lockable-resources-plugin#using-a-resource-in-a-pipeline-job

0
user21113865 On