Jenkins: Creating Multijob/Matrix Jobs for Simplifying Committed Jenkins Jobs

Creating a multijob

Reference: Multijob Plugin – Jenkins – Jenkins Wiki

Why and when to use it?

  • If you’d like to stop the mess with downstream / upstream jobs chains definitions
  • When you want to add full hierarchy of Jenkins jobs that will be executed in sequence or in parallel
  • Add context to your buildflow implementing parameter inheritance from the MultiJob to all its Phases and Jobs. Phases are sequential, whilst jobs inside each Phase are parallel

Example:

Screenshot+from+2016-06-08+13-47-37

Screenshot+from+2016-06-08+13-48-05

Jenkins Job Builder and Multijob

MultiJob Project — Jenkins Job Builder documentation

Builders — Jenkins Job Builder documentation

Note: Install Jenkins Job Builder 1.6.0 or higher.  I added a feature for the copy artifact plugin that will allow you to copy artifacts from a current multijob build

Example:

#######################################
## MULTI-JOB TO WRAP AROUND ALL JOBS ##
#######################################

- job-template:
    name: '{ocname}-0-multijob'
    defaults: openshift-defaults
    concurrent: false
    node: master
    project-type: multijob
    scm:
        - openshift-ansible-master-scm
    triggers:
        - timed: "H */6 * * *"
    wrappers:
      - openshift-wrappers
    builders:
      - multijob:
          name: JslaveSetup
          condition: SUCCESSFUL
          projects:
            - name: '{ocname}-1-provision-jslave'
              kill-phase-on: FAILURE
              abort-all-job: true
              current-parameters: true
      - multijob:
          name: UnitTests
          condition: SUCCESSFUL
          projects:
            - name: '{ocname}-2-unit-tests'
              kill-phase-on: FAILURE
              abort-all-job: true
              current-parameters: true
      - multijob:
          name: Provision-Deploy-e2etests-upgrade
          condition: SUCCESSFUL
          projects:
            - name: '{ocname}-3-test-matrix'
              kill-phase-on: FAILURE
              abort-all-job: true
              current-parameters: true

Each multijob has phases that can have jobs that run in parallel in the example above these are all separate phases that run serially.  I also reference defaults that are in other files.  I will link to all the files at the bottom for you to inspect, but I just wanted to show the basic JJB I have for a multijob.  The trigger can be anything like in other Jenkins Jobs.  The other key that makes it a multijob besides these “-multijob” sections is the “project-type: multijob” at the top.


Creating a Matrix Job

Building a matrix project – Jenkins – Jenkins Wiki

Why and when to use it?

Often we have build steps in our projects that are identical, but we want to run these same steps on just different components.  Maybe it is a topology, slave, version of Python, etc.

The matrix plugin allows you to do that with ease.  You can create one job but have multiple backend test executions and results with one job definition.  It also allows you restrict combinations of which axes can and can’t run together with the combination filter.

Configuration matrix

The Configuration Matrix allows you to specify what steps to duplicate, and create a multiple-axis graph of the type of builds to create.

You can define a User Defined Axis to create your matrix of combinations.

Features

The matrix project module handles creating Jenkins matrix projects. To create a matrix project specify matrix in the project-type attribute to the Job definition.

Axes:

Currently it supports four axes which share the same internal YAML structure:

  • label expressions (label-expression)
  • user-defined values (user-defined)
  • slave name or label (slave)
  • JDK name (jdk)

Requires the Jenkins Matrix Project Plugin.

The module also supports additional, plugin-defined axes:

The module supports also ShiningPanda axes:
Example:

name: matrix-test003
project-type: matrix
axes:
    - axis:
        type: python
        values:
        - python-2.6
        - python-2.7
        - python-3.4
    - axis:
        type: tox
        values:
        - py26
        - py27
        - py34

Requires the Jenkins ShiningPanda Plugin.

Combination-filter:

This allows jobs to be restrictive on what axes run together.

Example:

combo-filter: >
  ((OSE_VER =~ "^3.[1-9]" 
&& TOPOLOGY == "openshift-cluster-containerized" 
&& CONTAINERIZED == "_containerized") 
|| (OSE_VER =~ "^3.[1-9]" && TOPOLOGY == "openshift-cluster" 
&& CONTAINERIZED == "_NOT_containerized"))

This says when environment variables OSE_VER is 3.1 to 3.9 we run TOPOLOGY “openshift-cluster-containerized “with CONTAINERIZED set to “_containerized” or we run a NON containerized combination.

Example:

Screenshot+from+2016-06-08+14-01-55

Screenshot+from+2016-06-08+15-32-45

Screenshot+from+2016-06-08+15-33-03

Jenkins Job Builder and Matrix

Matrix Project – Jenkins Job Builder Documentation

Simple Example:

########################
## MATRIX JOB TESTING ##
## TOPOLOGY           ##
## SLAVE              ##
########################

- job-template:
    name: '{ocname}-3-test-matrix'
    defaults: openshift-defaults
    concurrent: false
    node: '{jslave_name}'
    project-type: matrix
    axes:
      - axis:
          type: user-defined
          name: TOPOLOGY
          values:
            - openshift-cluster
            - openshift-cluster-containerized
      - axis:
          type: slave
          name: nodes
          values:
            - '{jslave_name}'
    scm:
      - openshift-ci-scms
      - openshift-ansible-master-scm
    wrappers:
      - openshift-wrappers
    builders:
        - shining-panda:
            build-environment: virtualenv
            python-version: System-CPython-2.7
            nature: shell
            command: |
              pip install ansible==1.9.6
              pip install taskrunner lxml configobj requests foreman python-foreman python-{{glanceclient,keystoneclient,neutronclient,novaclient}}
              export PYTHONPATH="$PYTHONPATH:/usr/lib/python2.7/site-packages/bkr"
              {provision-cluster}
            clear: true
        - shell: |
            #!/bin/bash
            set -xeuo pipefail

           # Run some shell stuff or ansible
           chmod 600 $WORKSPACE/{ssh_keyfile}
           ansible-playbook \
           -i $WORKSPACE/ci-factory/utils/central_ci_dynamic_hosts.py \
           --private-key=$WORKSPACE/{ssh_keyfile} \
           --extra-vars "topology=${{topology}}" \
           $WORKSPACE/setup.yml
    publishers:
        - archive:
            artifacts: '*.txt'
            allow-empty: 'false'

Complex Example:

combo-filter: >
  ((OSE_VER =~ "^3.[1-9]" 
&& TOPOLOGY == "openshift-cluster-containerized" 
&& CONTAINERIZED == "_containerized") 
|| (OSE_VER =~ "^3.[1-9]" && TOPOLOGY == "openshift-cluster" 
&& CONTAINERIZED == "_NOT_containerized"))
########################
## MATRIX JOB TESTING ##
## OSE_VER            ##
## CONTANERIZED       ##
## TOPOLOGY           ##
## SLAVE              ##
## PYTHON             ##
########################

- job-template:
    name: '{ocname}-3-test-matrix'
    defaults: openshift-defaults
    concurrent: false
    node: '{jslave_name}'
    project-type: matrix
    execution-strategy:
      combination-filter: |
        {combo-filter}
    axes:
      - axis:
          type: user-defined
          name: OSE_VER
          values:
            - 3.2
      - axis:
          type: user-defined
          name: CONTAINERIZED
          values:
            - _containerized
            - _NOT_containerized
      - axis:
          type: user-defined
          name: TOPOLOGY
          values:
            - openshift-cluster
            - openshift-cluster-containerized
      - axis:
         type: slave
         name: nodes
         values:
          - '{jslave_name}'
      - axis:
          type: python
          values:
          - System-CPython-2.7
    scm:
      - openshift-ci-scms
      - openshift-ansible-master-scm
    wrappers:
      - openshift-wrappers
    builders:
        - copyartifact:
            project: '{ocname}-1-provision-jslave'
            filter: '*.txt'
            target: $WORKSPACE
            which-build: multijob-build
        - inject:
            properties-file: $WORKSPACE/RESOURCES.txt
            properties-content: |
              TOPOLOGY_PATH={topology_path}
              PROJECT_DEFAULTS={project_defaults}
              SSH_KEYFILE={ssh_keyfile}
              JSLAVE_TOPOLOGY_PATH={jslave_topology_path}
              JSLAVE_TOPOLOGY={jslave_topology}
              JSLAVE_USERNAME={jslave_username}
              JSLAVE_TEARDOWN={jslave_teardown}
        - shining-panda:
            build-environment: virtualenv
            python-version: System-CPython-2.7
            nature: shell
            command: |
              pip install ansible==1.9.6
              pip install taskrunner lxml configobj requests foreman python-foreman python-{{glanceclient,keystoneclient,neutronclient,novaclient}}
              export PYTHONPATH="$PYTHONPATH:/usr/lib/python2.7/site-packages/bkr"
              {provision-cluster}
            clear: true
        - inject:
            properties-file: $WORKSPACE/RESOURCES.txt
        - shell: |
            {prep-cluster}
        - shell: |
            {run-install}
        - shell: |
            {run-e2e-tests}
    publishers:
        - archive:
            artifacts: '*.txt'
            allow-empty: 'false'
        - openshift-email
        - teardown-resources

Running Axes on a slave

Note: If you want the axes to run on a slave then you must specify that by a label or node name

Example:

- axis:
   type: slave
   name: nodes
   values:
    - '{jslave_name}'

Running in a python or shell virtual environment

Note: Using the Shiningpanda plugin for python virtual environments

- axis:
    type: python
    values:
    - System-CPython-2.7
builders:
  - shining-panda:
      build-environment: virtualenv
      python-version: System-CPython-2.7
      nature: shell
      command: |
        pip install ansible==1.9.6
        pip install taskrunner lxml configobj requests foreman python-foreman python-{{glanceclient,keystoneclient,neutronclient,novaclient}}
        export PYTHONPATH="$PYTHONPATH:/usr/lib/python2.7/site-packages/bkr"
        {provision-cluster}

Full Jenkins Job Builder file example

The openshift-defaults.yaml file contains all the defaults to use for the jobs. The openshift-committed.yaml contains the job templates and the project macros are defined in the openshift-ansible-committed.yaml.

Note: These could all be in one file but a separated them for clarity.

openshift-defaults.yaml
openshift-committed.yaml
openshift-ansible-committed.yaml

 

 

 

Leave a comment