Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jenkins lockable resource - lock without unlocking

I'm using the "Locable Resources Plugin" together with the Jenkins multipipeline functionality:

lock('my-resource-name') {

}

I have a situation where I need to lock a resource in one pipeline and unlock it in another. I have workarounds, but I would prefer using the lock plugin, if possible.

I imagagine something like this

lock("my-resource-name")
..... 
unlock("my-resource-name)

The why of it

I'm implementing canary releases, and there are three different paths through my pipeline (I considered other solutions, like pausing the pipeline with the input plugin - providing me with more is out of scope for this question). I would like to lock/halt the pipeline while the canary is evaluated, and then, when the promotion or rollback is done, unlock it again. Omitting the body for the lock statement just gives me java.lang.IllegalStateException: There is no body to invoke

like image 976
Markus T Avatar asked Jul 27 '18 06:07

Markus T


People also ask

What is lock in Jenkins pipeline?

The lock step limits the number of builds running concurrently in a section of your Pipeline while the milestone step ensures that older builds of a job will not overwrite a newer build. Concurrent builds of the same job do not always run at the same rate.


3 Answers

The lock can be done this way

import org.jenkins.plugins.lockableresources.LockableResource
import org.jenkins.plugins.lockableresources.LockableResourcesManager

...

LockableResourcesManager lockableResourcesManager = LockableResourcesManager.get()
LockableResource lockableResource = lockableResourcesManager.fromName(resourceName)
// if the resource doesn't exists, create it
if (lockableResource == null) {
    lockableResourcesManager.createResource(resourceName)
    lockableResource = lockableResourcesManager.fromName(resourceName)
}

// wait until lock is successful
waitUntil { lockableResourcesManager.lock([lockableResource].toSet(), currentBuild.rawBuild, null) }

The unlock is much simpler because you know the resource exists (if it doesn't there is no reason to try to unlock it)

LockableResourcesManager lockableResourcesManager = LockableResourcesManager.get()
LockableResource lockableResource = lockableResourcesManager.fromName(resourceName)
// do not pass currentBuild.rawBuild as in your case is not the build that locked this resource
// so I am passing null instead
lockableResourcesManager.unlock([lockableResource], null)

Note that I used to test this org.6wind.jenkins:lockable-resources:2.7, the implementation details may vary depending on the version used.

<dependency>
    <groupId>org.6wind.jenkins</groupId>
    <artifactId>lockable-resources</artifactId>
    <version>2.7</version>
    <scope>provided</scope>
</dependency>
like image 124
Daniel Puiu Avatar answered Nov 15 '22 23:11

Daniel Puiu


One way of doing it is this:

curl -XGET https://your-jenkins/lockable-resources/reserve?resource=myresource
curl -XGET https://your-jenkins/lockable-resources/unreserve?resource=myresource

The GET is not a mistake, it really is GET.

To wait for a lock

lock("my-resource-name") {}

I also know Jenkins support something called "milestones" apparently is something used to communicate between builds. But I have no idea if it can be used to solve this problem in any meaningful way.

like image 43
Markus T Avatar answered Nov 16 '22 01:11

Markus T


from LockableResourcesManager get each lock, then foreach lock do if lock.getName matches then do lock.reset() to release the lock

e.g. some groovy to find locked locks not owned by any builds and clean them up:

print "START\n"
def all_lockable_resources = org.jenkins.plugins.lockableresources.LockableResourcesManager.get().resources
all_lockable_resources.each { r->
   if (r.isLocked() || r.isReserved()) { 
        println "Lock " + r + " is locked or reserved by " + r.getBuild() + " B CARSE " + r.getLockCause()

        b = r.getBuild()

        if (b) {
           if (b.isBuilding()) { println "build:" + b + " is building" } 
           if (b.getResult().equals(null)) { println "build:" + b + " result is not in yet" }

           if ( ! b.isBuilding() && ! b.getResult().equals(null)) { 
              println "build:" + b + " is not building and result is " + b.getResult() + " yet the lock " + r + " is locked."
              println "ACTION RELEASE LOCK " + r

              println "getLockCause:" + r.getLockCause() 
              println "getDescription:" + r.getDescription() 
              println "getReservedBy:" + r.getReservedBy() 
              println "isReserved:" + r.isReserved() 
              println "isLocked:" + r.isLocked() 
              println "isQueued:" + r.isQueued() 

              //release the lock
              r.reset() 

              println "getLockCause:" + r.getLockCause() 
              println "getDescription:" + r.getDescription() 
              println "getReservedBy:" + r.getReservedBy() 
              println "isReserved:" + r.isReserved() 
              println "isLocked:" + r.isLocked() 
              println "isQueued:" + r.isQueued() 

           }
        }

   }
}

API: http://javadoc.jenkins.io/plugin/lockable-resources/org/jenkins/plugins/lockableresources/LockableResource.html

like image 32
gaoithe Avatar answered Nov 16 '22 01:11

gaoithe