Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scripted jenkinsfile parallel stage

I am attempting to write a scripted Jenkinsfile using the groovy DSL which will have parallel steps within a set of stages.

Here is my jenkinsfile:

node {   
stage('Build') {
    sh 'echo "Build stage"'
}

stage('API Integration Tests') {
    parallel Database1APIIntegrationTest: {
        try {
            sh 'echo "Build Database1APIIntegrationTest parallel stage"'
        }
        finally {
            sh 'echo "Finished this stage"'
        }               

    }, Database2APIIntegrationTest: {
        try {
            sh 'echo "Build Database2APIIntegrationTest parallel stage"'
        }
        finally {
            sh 'echo "Finished this stage"'
        }

    }, Database3APIIntegrationTest: {
        try {
            sh 'echo "Build Database3APIIntegrationTest parallel stage"'
        }
        finally {
            sh 'echo "Finished this stage"'
        }
    }
}

stage('System Tests') {
    parallel Database1APIIntegrationTest: {
        try {
            sh 'echo "Build Database1APIIntegrationTest parallel stage"'
        }
        finally {
            sh 'echo "Finished this stage"'
        }               

    }, Database2APIIntegrationTest: {
        try {
            sh 'echo "Build Database2APIIntegrationTest parallel stage"'
        }
        finally {
            sh 'echo "Finished this stage"'
        }

    }, Database3APIIntegrationTest: {
        try {
            sh 'echo "Build Database3APIIntegrationTest parallel stage"'
        }
        finally {
            sh 'echo "Finished this stage"'
        }
    }
}
}

I want to have 3 stages: Build; Integration Tests and System Tests. Within the two test stages, I want to have 3 sets of the tests executed in parallel, each one against a different database.

I have 3 available executors. One on the master, and 2 agents and I want each parallel step to run on any available executor.

What I've noticed is that after running my pipeline, I only see the 3 stages, each marked out as green. I don't want to have to view the logs for that stage to determine whether any of the parallel steps within that stage were successful/unstable/failed.

I want to be seeing the 3 steps within my test stages - marked as either green, yellow or red (Success, unstable or failed).

I've considered expanding the tests out into their own stages, but have realised that parallel stages are not supported (Does anyone know whether this will ever be supported?), so I cannot do this as the pipeline would take far too long to complete.

Any insight would be much appreciated, thanks

like image 683
Ryan Jones Avatar asked Oct 19 '17 16:10

Ryan Jones


People also ask

What is parallel in Jenkinsfile?

This means that one stage could run on a certain machine, and another stage of the same pipeline could run on another machine. Thus having a Jenkins distributed build and not just a Jenkins parallel build.

Can Jenkins run parallel jobs?

Parallel Job Execution in Jenkins In Jenkins, there are several ways to implement parallel job execution. One of the common approaches is the parent-child build model. In this model – a parent (upstream) job is triggering child (downstream) jobs.

What is the use of parallel stages in Jenkins?

In declarative pipelines, Jenkins allows the definition of parallel stages. It further allows scripted pipeline general purpose scripts to create and manipulate the artifacts of the declarative pipeline. For example, it can create stages dynamically.

Is there a jenkinsfile that adds stages dynamically?

Below is a simple Jenkinsfile that dynamically adds stages using groovy code. These stages are sequential. I would like a Jenkinsfile that adds stages dynamically as below, but uses the parallel construct at the stage level. As a result, three stages that run parallel should be generated by the program.

How to run parallel stages in a scripted pipeline?

Scripted pipelines use groovy threads to run parallel stages. To run parallel stages, an array of stage objects has to be created and passed as an argument to parallel keyword. Common pitfalls when running parallel stages will be discussed in this article.

How to build a declarative pipeline in Jenkins using Cmake?

The essential part is the Jenkinsfile where we define the declarative pipeline. Jenkins allows us to define sets of steps and stages. && cmake -DCMAKE_BUILD_TYPE=Release /var/lib/jenkins/workspace/$ {env.JOB_NAME} && cmake --build .


Video Answer


3 Answers

In Jenkins scripted pipeline, parallel(...) takes a Map describing each stage to be built. Therefore you can programatically construct your build stages up-front, a pattern which allows flexible serial/parallel switching.
I've used code similar to this where the prepareBuildStages returns a List of Maps, each List element is executed in sequence whilst the Map describes the parallel stages at that point.

// main script block
// could use eg. params.parallel build parameter to choose parallel/serial 
def runParallel = true
def buildStages

node('master') {
  stage('Initialise') {
    // Set up List<Map<String,Closure>> describing the builds
    buildStages = prepareBuildStages()
    println("Initialised pipeline.")
  }

  for (builds in buildStages) {
    if (runParallel) {
      parallel(builds)
    } else {
      // run serially (nb. Map is unordered! )
      for (build in builds.values()) {
        build.call()
      }
    }
  }

  stage('Finish') {
      println('Build complete.')
  }
}

// Create List of build stages to suit
def prepareBuildStages() {
  def buildStagesList = []

  for (i=1; i<5; i++) {
    def buildParallelMap = [:]
    for (name in [ 'one', 'two', 'three' ] ) {
      def n = "${name} ${i}"
      buildParallelMap.put(n, prepareOneBuildStage(n))
    }
    buildStagesList.add(buildParallelMap)
  }
  return buildStagesList
}

def prepareOneBuildStage(String name) {
  return {
    stage("Build stage:${name}") {
      println("Building ${name}")
      sh(script:'sleep 5', returnStatus:true)
    }
  }
}

The resulting pipeline appears as: Jenkins Blue Ocean parallel pipeline

There are certain restrictions on what can be nested within a parallel block, refer to the pipeline documentation for exact details. Unfortunately much of the reference seems biased towards declarative pipeline, despite it being rather less flexible than scripted (IMHO). The pipeline examples page was the most helpful.

like image 76
Ed Randall Avatar answered Oct 18 '22 21:10

Ed Randall


Here's a simple example without loops or functions based on @Ed Randall's post:

node('docker') {
    stage('unit test') {
        parallel([
            hello: {
                echo "hello"
            },
            world: {
                echo "world"
            }
        ])
    }

    stage('build') {
        def stages = [:]

        stages["mac"] = {
            echo "build for mac"
        }
        stages["linux"] = {
            echo "build for linux"
        }

        parallel(stages)
    }
}

...which yields this:

blue-ocean-view

Note that the values of the Map don't need to be stages. You can give the steps directly.

like image 40
adanilev Avatar answered Oct 18 '22 21:10

adanilev


Here is an example from their docs:

Parallel execution

The example in the section above runs tests across two different platforms in a linear series. In practice, if the make check execution takes 30 minutes to complete, the "Test" stage would now take 60 minutes to complete!

Fortunately, Pipeline has built-in functionality for executing portions of Scripted Pipeline in parallel, implemented in the aptly named parallel step.

Refactoring the example above to use the parallel step:

// Jenkinsfile (Scripted Pipeline)


stage('Build') {
    /* .. snip .. */
}

stage('Test') {
    parallel linux: {
        node('linux') {
            checkout scm
            try {
                unstash 'app'
                sh 'make check'
            }
            finally {
                junit '**/target/*.xml'
            }
        }
    },
    windows: {
        node('windows') {
            /* .. snip .. */
        }
    }
}
like image 14
Behrang Avatar answered Oct 18 '22 21:10

Behrang