How to use failFast in dynamic pipeline in Jenkins - jenkins

I have pipeline which has dynamic parallel stages and I want my pipeline to fail fast, if any of the stage fail. I tried to add failFast: true but my pipeline is stuck at "Failed at Stage ABC".
stage("Deploy") {
steps {
script {
def stages = createStages("Name", "Project")
fastFail: true
for (stage in stages) {
parallel stage
}
}
}
}

Solution: Use failFast flag on Jenkins pipeline.
From Documentation: You can force your parallel stages to all be aborted when one of them fails, by adding failFast true to the stage containing the parallel.
Pay attention that all jobs would be triggered and quit (if one fails) if the agent node was started in each one of them (if job 'a' in pipeline fails but job 'b' is still looking for node and not started yet, it will continue - [this is an edge case]).
Examples - The options are :
1.Use parallelsAlwaysFailFast method in your options pipeline:
pipeline {
agent any
options {
parallelsAlwaysFailFast()
}
stages {
stage('Non-Parallel Stage') {
steps {
echo 'This stage will be executed first.'
}
}
stage('Parallel Stage') {
when {
branch 'master'
}
parallel {
stage('Branch A') {
agent {
label "for-branch-a"
}
steps {
echo "On Branch A"
}
}
stage('Branch B') {
agent {
label "for-branch-b"
}
steps {
echo "On Branch B"
}
}
stage('Branch C') {
agent {
label "for-branch-c"
}
stages {
stage('Nested 1') {
steps {
echo "In stage Nested 1 within Branch C"
}
}
stage('Nested 2') {
steps {
echo "In stage Nested 2 within Branch C"
}
}
}
}
}
}
}
2.Use before parallel using failFast true
stage('Parallel Stage') {
when {
branch 'master'
}
failFast true
parallel {
3.Configure jobs in map and execute with failFast attribute on.
jobsList = [
{job: 'jobA', parameters: [booleanParam(name: 'flag', value: true)]},
{job: 'jobB', parameters: [booleanParam(name: 'flag', value: true)]}
]
jobsList.failFast = true
parallel(jobsList)

I couldn't reply to the answer provided by #avivamg but I wasn't able to use his/her solution directly.
This worked for me:
stages.failFast = true
parallel stages
Or in your case:
stage("Deploy") {
steps {
script {
def stages = createStages("Name", "Project")
stages.fastFail = true
// I'm not sure if the for loop will work as failFast is on the map
// so if that doesn't work then you could use this instead:
// parallel stages
for (stage in stages) {
parallel stage
}
}
}
}

If you're using a scripted pipeline then you need to add the failFast into the parallel step like so -
stage('SomeStage') {
parallel (
"Process1" : { //do something },
"Process2" : { //do something else },
failFast: true
)
}

Related

Trigger pipeline job from other and wait for it on next stage

I need to execute pipeline B from pipeline A , do some work and than come back and wait until B is finished.
something like this:
pipeline
{
stages {
stage ('Init') {
steps {
job_b = build (job:"my_name", wait: false)
}
}
stage ('step 2')
{
steps
{
....do some work
}
stage ('step3'){
steps
{
job_b.waitUtilFinish()
}
}
}
I familiar with parallel but I don't want to use it because blue Ocean view in parallel and I have the entire pipeline to do until checking the other job
You can merge 'Init' and 'Step 3' stages into a unique a stage and use parallel directive:
pipeline {
stages {
parallel {
stage ('step 1') {
steps {
job_b = build (job:"my_name", wait: true)
}
}
stage ('step 2') {
steps {
....do some work
}
} ​
​}
​ }
}

Quicker syntax for Jenkins identical parallel stages

I have some parallel stages in my Jenkins pipeline. They are all identical, except that they run on different agents:
stage {
parallel {
stage {
agent {
label 'agent-1'
}
steps {
sh 'do task number 468'
}
}
stage {
agent {
label 'agent-2'
}
steps {
sh 'do task number 468'
}
}
stage {
agent {
label 'agent-3'
}
steps {
sh 'do task number 468'
}
}
}
}
I want to add more parallel stages on more nodes, but the script is long and repetetive. What's the best way to rewrite this to tell jenkins to parallelize the same steps across agents 1, 2, 3, 4...etc?
Please see below code which will create and run the stage on multiple agents:
// Define your agents
def agents = ['agent-1','agent-2','agent-3']
def createStage(label) {
return {
stage("Runs on ${label}") {
node(label) {
// build steps that should happen on all nodes go here
echo "Running on ${label}"
sh 'do task number 468'
}
}
}
}
def parallelStagesMap = agents.collectEntries {
["${it}" : createStage(it)]
}
pipeline {
agent none
stages {
stage('parallel stage') {
steps {
script {
parallel parallelStagesMap
}
}
}
}
}
More information is available at : Jenkins examples

Jenkins Pipeline Make a Stage as a Variable?

stages {
stage('Setup') {
}
stage('Parallel Stage') {
parallel {
stage('Executor 1') {
}
stage('Executor 2') {
}
stage('Executor 3') {
}
stage('Executor 4') {
}
}
}
}
Above is a skeleton of my Jenkins pipeline that has a setup stage and then a parallel stage that does the same thing four times for faster execution time.
Is there a way to define a stage as a variable to reduce the 4x code repetition and to reduce the number of edits I would have to make?
Yes, best way is to defined a function which generates stage and can be called in parallel.
Presuming that you are executing the stages into 1 agent in parallel.
In below sample pipeline generateStage is a function which replaces nested stages with function.
def jobs = ["Executor1", "Executor2", "Executor3"]
def parallelStagesMap = jobs.collectEntries {
["${it}" : generateStage(it)]
}
def generateStage(job) {
return {
stage("${job}") {
echo "Running stage ${job}."
}
}
}
pipeline {
agent any
stages {
stage('setup') {
steps {
echo 'This stage will be executed first.'
}
}
stage('parallel stage') {
steps {
script {
parallel parallelStagesMap
}
}
}
}
}
Output of the pipeline is as below:
For more details please see my answer LINK
Only drawback is that you can not execute this pipeline arrangement directly after stages thats why parallelStageMap is called inside the script.

BlueOcean not showing input before parallel stages

In a pipeline script of mine, I have the following:
pipeline {
agent any
options {
skipDefaultCheckout(true)
}
stages {
stage('Checkout') {
//Checkout steps
}
stage('Clean') {
when {
expression {
def result = input(message: 'Clean?', ok: 'Go for it!')
return true
}
beforeAgent true
}
parallel {
stage("Clean Project 1") {
// Clean steps
}
stage("Clean Project 2") {
// Clean steps
}
}
}
}
}
I'm expecting there to be a waiting step before the parallel stage "Clean" begins to run however the pipeline ends up looking like this:
I have even tried to add another step between checkout and clean with just an input as a step but that hasn't worked either. I could put the input st the end of the checkout steps but that is not desired.

Use a lightweight executor for a declarative pipeline stage (agent none)

I'm using Jenkins Pipeline with the declarative syntax, currently with the following stages:
Prepare
Build (two parallel sets of steps)
Test (also two parallel sets of steps)
Ask if/where to deploy
Deploy
For steps 1, 2, 3, and 5 I need and agent (an executor) because they do actual work on the workspace. For step 4, I don't need one, and I would like to not block my available executors while waiting for user input. This seem to be referred to as either a "flyweight" or "lightweight" executor for the classic, scripted syntax, but I cannot find any information on how to achieve this with the declarative syntax.
So far I've tried:
Setting an agent directly in the pipeline options, and then setting agent none on the stage. This has no effect, and the pipeline runs as normalt, blocking the executor while waiting for input. It is also mentioned in the documentation that it will have no effect, but I thought I'd give it a shot anyway.
Setting agent none in the pipeline options, and then setting an agent for each stage except #4. Unfortunately, but expectedly, this allocates a new workspace for every stage, which in turn requires me to stash and unstash. This is both messy and gives me further problems in the parallel stages (2 and 3) because I cannot have code outside the parallel construct. I assume the parallel steps run in the same workspace, so stashing/unstashing in both would have unfortunate results.
Here is an outline of my Jenkinsfile:
pipeline {
agent {
label 'build-slave'
}
stages {
stage("Prepare build") {
steps {
// ...
}
}
stage("Build") {
steps {
parallel(
frontend: {
// ...
},
backend: {
// ...
}
)
}
}
stage("Test") {
steps {
parallel(
jslint: {
// ...
},
phpcs: {
// ...
},
)
}
post {
// ...
}
}
stage("Select deploy target") {
steps {
script {
// ... code that determines choiceParameterDefinition based on branch name ...
try {
timeout(time: 5, unit: 'MINUTES') {
deployEnvironment = input message: 'Deploy target', parameters: [choiceParameterDefinition]
}
} catch(ex) {
deployEnvironment = null
}
}
}
}
stage("Deploy") {
when {
expression {
return binding.variables.get("deployEnvironment")
}
}
steps {
// ...
}
}
}
post {
// ...
}
}
Am I missing something here, or is it just not possible in the current version?
Setting agent none at the top level, then agent { label 'foo' } on every stage, with agent none again on the input stage seems to work as expected for me.
i.e. Every stage that does some work runs on the same agent, while the input stage does not consume an executor on any agent.
pipeline {
agent none
stages {
stage("Prepare build") {
agent { label 'some-agent' }
steps {
echo "prepare: ${pwd()}"
}
}
stage("Build") {
agent { label 'some-agent' }
steps {
parallel(
frontend: {
echo "frontend: ${pwd()}"
},
backend: {
echo "backend: ${pwd()}"
}
)
}
}
stage("Test") {
agent { label 'some-agent' }
steps {
parallel(
jslint: {
echo "jslint: ${pwd()}"
},
phpcs: {
echo "phpcs: ${pwd()}"
},
)
}
}
stage("Select deploy target") {
agent none
steps {
input message: 'Deploy?'
}
}
stage("Deploy") {
agent { label 'some-agent' }
steps {
echo "deploy: ${pwd()}"
}
}
}
}
However, there are no guarantee that using the same agent label within a Pipeline will always end up using the same workspace, e.g. as another build of the same job while the first build is waiting on the input.
You would have to use stash after the build steps. As you note, this cannot be done normally with parallel at the moment, so you'd have to additionally use a script block, in order to write a snippet of Scripted Pipeline for the stashing/unstashing after/before the parallel steps.
There is a workaround to use the same build slave in the other stages.
You can set a variable with the node name and use it in the others.
ie:
pipeline {
agent none
stages {
stage('First Stage Gets Agent Dynamically') {
agent {
node {
label "some-agent"
}
}
steps {
echo "first stage running on ${NODE_NAME}"
script {
BUILD_AGENT = NODE_NAME
}
}
}
stage('Second Stage Setting Node by Name') {
agent {
node {
label "${BUILD_AGENT}"
}
}
steps {
echo "Second stage using ${NODE_NAME}"
}
}
}
}
As of today (2021), you can use nested stages (https://www.jenkins.io/doc/book/pipeline/syntax/#sequential-stages) to group all the stages that must run in the same workspace before the input step, and all the stages that must be run in the same workspace after the input step. Of course, you need to stash or to store artifacts in some external repository before the input step, because the second workspace may not be the same than the first one:
pipeline {
agent none
stages {
stage('Deployment to Preproduction') {
agent any
stages {
stage('Stage PRE.1') {
steps {
echo "StagePRE.1"
sleep(10)
}
}
stage('Stage PRE.2') {
steps {
echo "Stage PRE.2"
sleep(10)
}
}
}
}
stage('Stage Ask Deploy') {
steps {
input message: 'Deploy to production?'
}
}
stage('Deployment to Production') {
agent any
stages {
stage('Stage PRO.1') {
steps {
echo "Stage PRO.1"
sleep(10)
}
}
stage('Stage PRO.2') {
steps {
echo "Stage PRO.2"
sleep(10)
}
}
}
}
}
}

Resources