Issue
Our project uses Jenkins pipeline for the automation tests and packaging. The pipeline is defined in a Jenkinsfile
script having multiple stages. Multiple jobs (triggered by the push events from different dev branches) might be running in parallel.
Now that we need to test a function against an external system which has limited resources.
Let's say, that system has 10 resource "slots" for tests: #1, #2, ..., #10. When each pipeline job wants to test that function, it needs to "reserve" a slot number (just an integer will suffice) and then the test program talks to the external system using the slot number (like a token or something). When the job finishes, it releases the number.
Is it possible in Jenkins? In other words, the Jenkins needs to maintain a small integer array for all parallel jobs. Whenever a job asks for a "slot" number, it finds a free number in the array and lock it up.
I Googled it and found a Jenkins plugin called "lockable resource plugin" (Jenkins - How to handle concurrent jobs that use a limited resource pool?), but it can only do "semaphore-like" resource management, not enough for my case. I not only need to know if the resource is used up or not, but also need to know which one is available at the moment.
Thank you guys!!
Solution
In my experience the "lockable resources" plugin is quite suitable for something like this. You would define one numbered resource per "slot" but give them all the same label. When you want to acquire a "slot", you pass that label to the pipeline lock
step, which waits until a slot is available and gives you the name of that slot. Then it's just a simple matter of extracting the number from the resource name.
I'm using a similar scheme to acquire test VMs, where it works reliably.
Details:
- Install the lockable resources plugin
- Go to Manage Jenkins > Configure System > Scroll down to "Lockable Resources"
- Add one lockable resource per slot. Name them like "slot-1", "slot-2" and so on (the dash makes it easy to extract the number later on). Assign the same label to all of them, e. g. "slots". This is how you logically group the resources.
- Use the
lock
step in your pipeline code to acquire a slot. The key here is to use thequantity: 1
argument to acquire only a single slot (by default it would try to acquire all resources that match the given label). It will be released automatically when the code block of thelock
step ends. When all slots are in use, thelock
step waits until the next slot becomes available.
pipeline { agent any stages { stage('Stage 1') { steps { script { // Acquire a single slot lock(label: 'slots', quantity: 1, variable: 'slotName') { // Extract the slot number from the resource name def slotNumber = slotName.split('-')[1] as int // Code that uses the slot echo "Acquired slot $slotNumber" // Slot gets released automatically } } } } } }
Answered By - zett42