2

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!!

Gerold Broser
  • 14,080
  • 5
  • 48
  • 107
Zhou
  • 633
  • 5
  • 16
  • 1
    I've just fixed a bug in my answer - missed argument `quantity: 1` for the `lock` step. Have tested the sample code successfully now. – zett42 Oct 26 '21 at 11:23
  • @zett42 Your answer looks great! Thank you. I'll try it out a couple of days later and will update my result here. – Zhou Oct 26 '21 at 16:22

1 Answers1

3

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:

  1. Install the lockable resources plugin
  2. Go to Manage Jenkins > Configure System > Scroll down to "Lockable Resources"
  3. 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.

    Jenkins Configuration - Lockable Resources
  4. Use the lock step in your pipeline code to acquire a slot. The key here is to use the quantity: 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 the lock step ends. When all slots are in use, the lock 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
                        }
                    }
                }
            }
        }
    }
    
zett42
  • 25,437
  • 3
  • 35
  • 72
  • 1
    Wow! It's a shame that I can only give you one thumb-up. Thank you man! The explanation of your idea and the steps are all very clear. But because other parts of my project aren't ready yet, I have try it out a few days later. Will let you know the result. Thank you! – Zhou Oct 26 '21 at 16:21