I am trying to add the ability to dynamically lock a resource on a multi-branch pipeline before having an agent assigned.
I have multiple stages running in parallel and this is the only stage that requires to have only one instance running per branch. I do not want the stage to take up an agent while it is waiting for the locked resource to become available.
I can hard code the label for my resource but this solution does not work across the multibranch pipeline.
As far as I know, it is possible to lock a resource in a Jenkins multi-branch pipeline dynamically.
You could use the lock step from the Lockable Resources Plugin.
This plugin allows you to lock a resource before the agent is assigned, and it will not take up an agent while it is waiting for the locked resource to become available if I understood correctly.
However, the lock step should be inside the steps block, not in the options block.
The options block is evaluated at the start of the stage, before the when directive, and it doesn’t support variable substitution.
Here is a modified version of your pipeline that could maybe work:
In this code, the lock step is used inside the steps block. It locks the resource named with the branch name before executing the steps inside the lock block. The inversePrecedence option is set to true to prioritize older builds waiting for the lock.
I have attempted to specify the lock step within the steps of the stage unfortunately this does not behave how I want where the agent is not assigned if the lock is unavailable. In my testing the agent gets assigned and is then blocked from use by other pipelines while it is waiting for the locked resource to become available.
Is it possible to wrap the lock step around the stage?
Or use a different agent while it is waiting for the locked resource? As an example can I have two stages in running sequentially where the first stage checks for the locked resource running on a lower-end agent? Something along the lines of this?
I think you could use a different agent while waiting for the locked resource.
You could use a low-end agent to check for the locked resource and then use a high-end agent to perform the actual tasks.
However, the lock step should be used inside the steps block of the stage where the actual tasks are performed.
The lock should be released automatically at the end of the steps block where it is defined, so you wouldn’t need to unlock the resource manually.
In this code, the first stage (“stage 1”) uses a low-end agent to check if the resource is locked.
If it is locked, Jenkins should throw an error and stop the pipeline.
If the resource is not locked, Jenkins should proceed to the next stage (“stage 2”), where it will lock the resource and perform the actual tasks using a high-end agent.
The lock should be released automatically at the end of the “stage 2” steps block.
Thank you this does produce the desired output where the agent is not assigned until the resource becomes available. This did however bring up a consequence of doing it this way where I was performing some actions in the post block. The post block no longer has an agent to execute on.
pipeline {
agent none
stages {
stage('build') {
steps {
lock(resource: "${env.BRANCH_NAME}") {
node("XYZ") {
sh "sleep 60"
}
}
}
post {
success {
// do something
}
failure {
// do something
}
}
}
}
}
I assume I can achieve something similar to this using try-catch inside the node block and check the status of the build in order to determine what actions to perform?
You would need a node in each of the post conditions though.
Certain steps don’t need an agent to run, probably sending an email as long as you don’t want to attach a file from the workspace (just guessing here haven’t tried this out).
So best to try out if you really need an agent in your post steps