Move Calico test/build/publish stuff to library

Since we use the same stages by different Calico
pipelines, moved them to library in order to
make DRY jobs.

Change-Id: Ibf4dc7712e463cb0e137f1de87289e30dff46fa1
diff --git a/src/com/mirantis/mcp/Calico.groovy b/src/com/mirantis/mcp/Calico.groovy
index c73fa10..5ab92d1 100644
--- a/src/com/mirantis/mcp/Calico.groovy
+++ b/src/com/mirantis/mcp/Calico.groovy
@@ -1,12 +1,483 @@
 package com.mirantis.mcp
 
+@Grab(group='org.yaml', module='snakeyaml', version='1.17')
+import org.yaml.snakeyaml.Yaml
+
+
+@NonCPS
+def loadYaml(String rawYaml) {
+  def yaml = new Yaml()
+  return yaml.load(rawYaml)
+}
+
+@NonCPS
+def dumpYaml(Map yamlMap) {
+  def yaml = new Yaml()
+  return yaml.dump(yamlMap)
+}
+
+
 /**
- * Build Calico containers
+ * Checkout Calico repository stage
  *
- * @param body Closure
- *        body includes next parameters:
- *          - dockerRepo String, repo with docker images
- *          - artifactoryUrl String, URL to repo with calico-binaries
+ * @param config LinkedHashMap
+ *        config includes next parameters:
+ *          - project_name String, Calico project to clone
+ *          - projectNamespace String, gerrit namespace (optional)
+ *          - commit String, Git commit to checkout
+ *          - credentialsId String, gerrit credentials ID (optional)
+ *          - host String, gerrit host
+ *
+ * Usage example:
+ *
+ * def calico = new com.mirantis.mcp.Calico()
+ * calico.checkoutCalico([
+ *     project_name : 'cni-plugin',
+ *     commit : 'mcp',
+ *     host : 'gerrit.mcp.mirantis.net',
+ * ])
+ *
+ */
+def checkoutCalico(LinkedHashMap config) {
+
+  def git = new com.mirantis.mcp.Git()
+
+  def project_name = config.get('project_name')
+  def projectNamespace = config.get('projectNamespace', 'projectcalico')
+  def commit = config.get('commit')
+  def host = config.get('host')
+  def credentialsId = config.get('credentialsId', 'gerrit')
+
+  if (!project_name) {
+    throw new RuntimeException("Parameter 'project_name' must be set for checkoutCalico() !")
+  }
+  if (!commit) {
+    throw new RuntimeException("Parameter 'commit' must be set for checkoutCalico() !")
+  }
+
+  stage ("Checkout ${project_name}"){
+    git.gitSSHCheckout([
+      credentialsId : credentialsId,
+      branch : commit,
+      host : host,
+      project : "${projectNamespace}/${project_name}",
+      withWipeOut : true,
+    ])
+  }
+}
+
+
+/**
+ * Build bird binaries stage
+ *
+ * Usage example:
+ *
+ * def calico = new com.mirantis.mcp.Calico()
+ * calico.buildCalicoBird()
+ *
+ */
+def buildCalicoBird() {
+  stage ('Build bird binaries'){
+    sh "/bin/sh -x build.sh"
+  }
+}
+
+
+/**
+ * Publish bird binaries stage
+ *
+ * @param config LinkedHashMap
+ *        config includes next parameters:
+ *          - artifactoryServerName String, artifactory server name
+ *          - binaryRepo String, repository (artifactory) for binary files
+ *          - projectNamespace String, artifactory server namespace (optional)
+ *          - publishInfo Boolean, whether publish a build-info object to Artifactory (optional)
+ *
+ * Usage example:
+ *
+ * def calico = new com.mirantis.mcp.Calico()
+ * calico.publishCalicoBird([
+ *     artifactoryServerName : 'mcp-ci',
+ *     binaryRepo : 'sandbox-binary-dev-local',
+ * ])
+ *
+ */
+def publishCalicoBird(LinkedHashMap config) {
+
+  def common = new com.mirantis.mcp.Common()
+  def git = new com.mirantis.mcp.Git()
+  def artifactory = new com.mirantis.mcp.MCPArtifactory()
+
+  def artifactoryServerName = config.get('artifactoryServerName')
+  def binaryRepo = config.get('binaryRepo')
+  def projectNamespace = config.get('projectNamespace', 'mirantis/projectcalico')
+  def publishInfo = config.get('publishInfo', true)
+
+  if (!artifactoryServerName) {
+    throw new RuntimeException("Parameter 'artifactoryServerName' must be set for publishCalicoBird() !")
+  }
+  if (!binaryRepo) {
+    throw new RuntimeException("Parameter 'binaryRepo' must be set for publishCalicoBird() !")
+  }
+
+  def artifactoryServer = Artifactory.server(artifactoryServerName)
+  def buildInfo = Artifactory.newBuildInfo()
+
+  stage('Publishing bird artifacts') {
+    dir("artifacts"){
+      // define tag for bird
+      binaryTag = git.getGitDescribe(true) + "-" + common.getDatetime()
+      sh """
+        cp ../dist/bird bird-${binaryTag}
+        cp ../dist/bird6 bird6-${binaryTag}
+        cp ../dist/birdcl birdcl-${binaryTag}
+      """
+      writeFile file: "latest", text: "${binaryTag}"
+      // define mandatory properties for binary artifacts
+      // and some additional
+      def properties = artifactory.getBinaryBuildProperties([
+        "tag=${binaryTag}",
+        "project=bird"
+        ])
+
+      def uploadSpec = """{
+          "files": [
+                  {
+                      "pattern": "**",
+                      "target": "${binaryRepo}/${projectNamespace}/bird/",
+                      "props": "${properties}"
+                  }
+              ]
+          }"""
+
+      // Upload to Artifactory.
+      artifactory.uploadBinariesToArtifactory(artifactoryServer, buildInfo, uploadSpec, publishInfo)
+    }// dir
+  }
+  return binaryTag
+}
+
+
+/**
+ * Test confd stage
+ *
+ *
+ * Usage example:
+ *
+ * def calico = new com.mirantis.mcp.Calico()
+ * calico.testCalicoConfd()
+ *
+ */
+def testCalicoConfd() {
+  stage ('Run unittest for confd'){
+    sh """
+    docker run --rm \
+      -v \$(pwd):/usr/src/confd \
+      -w /usr/src/confd \
+      golang:1.7 \
+      bash -c \
+      \"go get github.com/constabulary/gb/...; gb test -v\"
+    """
+  }
+}
+
+
+/**
+ * Build confd binaries stage
+ *
+ *
+ * Usage example:
+ *
+ * def calico = new com.mirantis.mcp.Calico()
+ * calico.buildCalicoConfd()
+ *
+ */
+def buildCalicoConfd() {
+  def container_src_dir = "/usr/src/confd"
+  def src_suffix = "src/github.com/kelseyhightower/confd"
+  def container_workdir = "${container_src_dir}/${src_suffix}"
+  def container_gopath = "${container_src_dir}/vendor:${container_src_dir}"
+
+  stage ('Build confd binary'){
+    sh """
+      docker run --rm \
+        -v \$(pwd):${container_src_dir} \
+        -w ${container_workdir} \
+        -e GOPATH=${container_gopath} \
+        golang:1.7 \
+        bash -c \
+        \"go build -a -installsuffix cgo -ldflags '-extld ld -extldflags -static' -a -x .\"
+    """
+  }
+}
+
+
+/**
+ * Publish confd binaries stage
+ *
+ * @param config LinkedHashMap
+ *        config includes next parameters:
+ *          - artifactoryServerName String, artifactory server name
+ *          - binaryRepo String, repository (artifactory) for binary files
+ *          - projectNamespace String, artifactory server namespace (optional)
+ *          - publishInfo Boolean, whether publish a build-info object to Artifactory (optional)
+ *
+ * Usage example:
+ *
+ * def calico = new com.mirantis.mcp.Calico()
+ * calico.publishCalicoConfd([
+ *     artifactoryServerName : 'mcp-ci',
+ *     binaryRepo : 'sandbox-binary-dev-local',
+ * ])
+ *
+ */
+def publishCalicoConfd(LinkedHashMap config) {
+
+  def common = new com.mirantis.mcp.Common()
+  def git = new com.mirantis.mcp.Git()
+  def artifactory = new com.mirantis.mcp.MCPArtifactory()
+
+  def artifactoryServerName = config.get('artifactoryServerName')
+  def binaryRepo = config.get('binaryRepo')
+  def projectNamespace = config.get('projectNamespace', 'mirantis/projectcalico')
+  def publishInfo = config.get('publishInfo', true)
+  def src_suffix = "src/github.com/kelseyhightower/confd"
+
+  if (!artifactoryServerName) {
+    throw new RuntimeException("Parameter 'artifactoryServerName' must be set for publishCalicoConfd() !")
+  }
+  if (!binaryRepo) {
+    throw new RuntimeException("Parameter 'binaryRepo' must be set for publishCalicoConfd() !")
+  }
+
+  def artifactoryServer = Artifactory.server(artifactoryServerName)
+  def buildInfo = Artifactory.newBuildInfo()
+
+  stage('Publishing confd artifacts') {
+
+    dir("artifacts"){
+      // define tag for confd
+      binaryTag = git.getGitDescribe(true) + "-" + common.getDatetime()
+      // create two files confd and confd+tag
+      sh "cp ../${src_suffix}/confd confd-${binaryTag}"
+      writeFile file: "latest", text: "${binaryTag}"
+
+      // define mandatory properties for binary artifacts
+      // and some additional
+      def properties = artifactory.getBinaryBuildProperties([
+        "tag=${binaryTag}",
+        "project=confd"
+        ])
+
+      def uploadSpec = """{
+          "files": [
+                  {
+                      "pattern": "**",
+                      "target": "${binaryRepo}/${projectNamespace}/confd/",
+                      "props": "${properties}"
+                  }
+              ]
+          }"""
+
+      // Upload to Artifactory.
+      artifactory.uploadBinariesToArtifactory(artifactoryServer, buildInfo, uploadSpec, publishInfo)
+    }// dir
+  }
+  return binaryTag
+}
+
+
+/**
+ * Test libcalico stage
+ *
+ * Usage example:
+ *
+ * def calico = new com.mirantis.mcp.Calico()
+ * calico.testLibcalico()
+ *
+ */
+def testLibcalico() {
+  stage ('Run libcalico unittests'){
+    sh "make test"
+  }
+}
+
+
+/**
+ * Build calico/build image stage
+ *
+ * @param config LinkedHashMap
+ *        config includes next parameters:
+ *          - dockerRegistry String, Docker registry host to push image to (optional)
+ *          - projectNamespace String, artifactory server namespace (optional)
+ *          - buildImageTag String, calico/build image name (optional)
+ *          - imageTag String, tag of docker image (optional)
+ *
+ * Usage example:
+ *
+ * def calicoFunc = new com.mirantis.mcp.Calico()
+ * calicoFunc.buildLibcalico([
+ *     dockerRegistry : 'sandbox-docker-dev-virtual.docker.mirantis.net',
+ * ])
+ *
+ */
+def buildLibcalico(LinkedHashMap config) {
+
+  def common = new com.mirantis.mcp.Common()
+  def docker = new com.mirantis.mcp.Docker()
+  def git = new com.mirantis.mcp.Git()
+
+  def dockerRegistry = config.get('dockerRegistry')
+  def projectNamespace = config.get('projectNamespace', 'mirantis/projectcalico')
+
+  def buildImage = config.get('buildImage', "calico/build")
+  def buildImageTag = config.get('buildImageTag', git.getGitDescribe(true) + "-" + common.getDatetime())
+
+  def buildContainerName = dockerRegistry ?  "${dockerRegistry}/${projectNamespace}/${buildImage}:${buildImageTag}" : "${buildImage}:${buildImageTag}"
+
+  stage ('Build calico/build image') {
+    docker.setDockerfileLabels("./Dockerfile", ["docker.imgTag=${buildImageTag}"])
+    sh """
+       make calico/build BUILD_CONTAINER_NAME=${buildContainerName}
+       """
+  }
+  return [buildImage : buildImage,
+          buildImageTag : buildImageTag]
+}
+
+
+/**
+ * Switch Calico to use dowstream libcalico-go repository stage
+ *
+ * @param libCalicoGoCommit String, libcalico-go repository commit to checkout to
+ * @param host String, gerrit host
+ * @param glideLockFilePath String, relative path to glide.lock file
+ *
+ * Usage example:
+ *
+ * def calico = new com.mirantis.mcp.Calico()
+ * // Checkout calico code using calico.checkoutCalico() and then call this method from the same dir
+ * calico.switchCalicoToDownstreamLibcalicoGo('mcp', 'gerrit.mcp.mirantis.net', './glide.lock')
+ *
+ */
+def switchCalicoToDownstreamLibcalicoGo(String libCalicoGoCommit, String host, String glideLockFilePath) {
+  def git = new com.mirantis.mcp.Git()
+
+  stage ('Switch to downstream libcalico-go') {
+    def libcalicogo_path = "${env.WORKSPACE}/tmp_libcalico-go"
+
+    git.gitSSHCheckout([
+      credentialsId : "apanchenko",
+      branch : libCalicoGoCommit,
+      host : host,
+      project : "projectcalico/libcalico-go",
+      targetDir : libcalicogo_path,
+      withWipeOut : true,
+    ])
+
+    sh "cp ${glideLockFilePath} ${glideLockFilePath}.bak"
+    def glideLockFileContent = readFile file: glideLockFilePath
+    def glideMap = loadYaml(glideLockFileContent)
+
+    for (goImport in glideMap['imports']) {
+      if (goImport['name'].contains('libcalico-go')) {
+        goImport['repo'] = 'file:///go/src/github.com/projectcalico/libcalico-go'
+        goImport['vcs'] = 'git'
+      }
+    }
+
+    writeFile file: glideLockFilePath, text: dumpYaml(glideMap)
+
+    sh "LIBCALICOGO_PATH=${libcalicogo_path} make vendor"
+  }
+}
+
+
+/**
+ * Test Felix stage
+ *
+ * Usage example:
+ *
+ * def calico = new com.mirantis.mcp.Calico()
+ * calico.testFelix()
+ *
+ */
+def testFelix() {
+  stage ('Run felix unittests'){
+    // inject COMPARE_BRANCH variable for felix tests coverage (python code) check
+    def COMPARE_BRANCH = env.GERRIT_BRANCH ? "gerrit/${env.GERRIT_BRANCH}" : "origin/mcp"
+    sh "make ut UT_COMPARE_BRANCH=${COMPARE_BRANCH}"
+  }
+}
+
+
+/**
+ * Build calico/felix image stage
+ *
+ * @param config LinkedHashMap
+ *        config includes next parameters:
+ *          - dockerRegistry String, Docker registry host to push image to (optional)
+ *          - projectNamespace String, artifactory server namespace (optional)
+ *          - felixImage String, calico/felix image name (optional)
+ *          - felixImageTag String, tag of docker image (optional)
+ *
+ * Usage example:
+ *
+ * def calicoFunc = new com.mirantis.mcp.Calico()
+ * calicoFunc.buildFelix([
+ *     dockerRegistry : 'sandbox-docker-dev-virtual.docker.mirantis.net',
+ * ])
+ *
+ */
+def buildFelix(LinkedHashMap config) {
+
+  def common = new com.mirantis.mcp.Common()
+  def docker = new com.mirantis.mcp.Docker()
+  def git = new com.mirantis.mcp.Git()
+
+  def dockerRegistry = config.get('dockerRegistry')
+  def projectNamespace = config.get('projectNamespace', 'mirantis/projectcalico')
+
+  def felixImage = config.get('felixImage', "calico/felix")
+  def felixImageTag = config.get('felixImageTag', git.getGitDescribe(true) + "-" + common.getDatetime())
+
+  def felixContainerName = dockerRegistry ?  "${dockerRegistry}/${projectNamespace}/${felixImage}:${felixImageTag}" : "${felixImage}:${felixImageTag}"
+
+  stage ('Build calico/felix image') {
+    docker.setDockerfileLabels("./Dockerfile", ["docker.imgTag=${felixImageTag}"])
+    sh """
+       make calico/felix
+       docker tag calico/felix ${felixContainerName}
+       """
+  }
+  return [felixImage : felixImage,
+          felixImageTag : felixImageTag]
+}
+
+/**
+ * Test Calicoctl stage
+ *
+ * Usage example:
+ *
+ * def calico = new com.mirantis.mcp.Calico()
+ * calico.testCalicoctl()
+ *
+ */
+def testCalicoctl() {
+  stage ('Run calicoctl unittests'){
+    sh "make test-containerized"
+  }
+}
+
+
+/**
+ * Build Calico containers stages
+ *
+ * @param config LinkedHashMap
+ *        config includes next parameters:
+ *          - dockerRegistry String, repo with docker images
+ *          - projectNamespace String, artifactory server namespace
+ *          - artifactoryURL String, URL to repo with calico-binaries
  *          - imageTag String, tag of images
  *          - nodeImage String, Calico Node image name
  *          - ctlImage String, Calico CTL image name
@@ -22,57 +493,54 @@
  * Usage example:
  *
  * def calicoFunc = new com.mirantis.mcp.Calico()
- * calicoFunc.buildCalicoContainers {
- *     dockerRepo = 'mcp-k8s-ci.docker.mirantis.net'
- *     artifactoryURL = 'https://artifactory.mcp.mirantis.net/artifactory/sandbox'
- *     nodeImage = 'mcp-k8s-ci.docker.mirantis.net/calico/node'
- *     ctlImage = 'mcp-k8s-ci.docker.mirantis.net/calico/ctl'
- * }
+ * calicoFunc.buildCalicoContainers([
+ *     dockerRegistry : 'sandbox-docker-dev-virtual.docker.mirantis.net',
+ *     artifactoryURL : 'https://artifactory.mcp.mirantis.net/artifactory/sandbox',
+ * ])
  *
  */
-def buildCalicoContainers = { body ->
-  // evaluate the body block, and collect configuration into the object
-  def config = [:]
-  body.resolveStrategy = Closure.DELEGATE_FIRST
-  body.delegate = config
-  body()
+def buildCalicoContainers(LinkedHashMap config) {
 
+  def common = new com.mirantis.mcp.Common()
+  def docker = new com.mirantis.mcp.Docker()
+  def git = new com.mirantis.mcp.Git()
 
-  def dockerRepo = config.dockerRepo
-  def projectNamespace = "mirantis/projectcalico"
-  def artifactoryUrl = config.artifactoryURL
+  def dockerRegistry = config.get('dockerRegistry')
+  def projectNamespace = config.get('projectNamespace', 'mirantis/projectcalico')
+  def artifactoryURL = config.get('artifactoryURL')
 
-  if (! dockerRepo ) {
-      error('dockerRepo parameter have to be set.')
+  if (! dockerRegistry ) {
+      error('dockerRegistry parameter has to be set.')
   }
 
-  if (! artifactoryUrl ) {
-      error('artifactoryUrl parameter have to be set.')
+  if (! artifactoryURL ) {
+      error('artifactoryURL parameter has to be set.')
   }
 
-  def imgTag = config.imageTag ?: getGitDescribe(true) + "-" + getDatetime()
+  def imgTag = config.get('imageTag', git.getGitDescribe(true) + "-" + common.getDatetime())
 
-  def nodeImage = config.nodeImage ?: "${dockerRepo}/${projectNamespace}/calico/node"
-  def nodeName = "${nodeImage}:${imgTag}"
+  def nodeImage = config.get('nodeImage', "calico/node")
+  def nodeRepo = "${dockerRegistry}/${projectNamespace}/${nodeImage}"
+  def nodeName = "${nodeRepo}:${imgTag}"
 
-  def ctlImage = config.ctlImage ?: "${dockerRepo}/${projectNamespace}/calico/ctl"
-  def ctlName = "${ctlImage}:${imgTag}"
+  def ctlImage = config.get('ctlImage', "calico/ctl")
+  def ctlRepo = "${dockerRegistry}/${projectNamespace}/${ctlImage}"
+  def ctlName = "${ctlRepo}:${imgTag}"
 
    // calico/build goes from libcalico
-  def buildImage = config.buildImage ?: "${dockerRepo}/${projectNamespace}/calico/build:latest"
+  def buildImage = config.get('buildImage',"${dockerRegistry}/${projectNamespace}/calico/build:latest")
   // calico/felix goes from felix
-  def felixImage = config.felixImage ?: "${dockerRepo}/${projectNamespace}/calico/felix:latest"
+  def felixImage = config.get('felixImage', "${dockerRegistry}/${projectNamespace}/calico/felix:latest")
 
-  def confdBuildId = config.confdBuildId ?: "${artifactoryUrl}/${projectNamespace}/confd/latest".toURL().text.trim()
-  def confdUrl = config.confdUrl ?: "${artifactoryUrl}/${projectNamespace}/confd/confd-${confdBuildId}"
+  def confdBuildId = config.get('confdBuildId', "${artifactoryURL}/${projectNamespace}/confd/latest".toURL().text.trim())
+  def confdUrl = config.get('confdUrl', "${artifactoryURL}/${projectNamespace}/confd/confd-${confdBuildId}")
 
-  def birdBuildId = config.birdBuildId ?: "${artifactoryUrl}/${projectNamespace}/bird/latest".toURL().text.trim()
-  def birdUrl = config.birdUrl ?: "${artifactoryUrl}/${projectNamespace}/bird/bird-${birdBuildId}"
-  def bird6Url = config.bird6Url ?: "${artifactoryUrl}/${projectNamespace}/bird/bird6-${birdBuildId}"
-  def birdclUrl = config.birdclUrl ?: "${artifactoryUrl}/${projectNamespace}/bird/birdcl-${birdBuildId}"
+  def birdBuildId = config.get('birdBuildId', "${artifactoryURL}/${projectNamespace}/bird/latest".toURL().text.trim())
+  def birdUrl = config.get('birdUrl', "${artifactoryURL}/${projectNamespace}/bird/bird-${birdBuildId}")
+  def bird6Url = config.get('bird6Url', "${artifactoryURL}/${projectNamespace}/bird/bird6-${birdBuildId}")
+  def birdclUrl = config.get('birdclUrl', "${artifactoryURL}/${projectNamespace}/bird/birdcl-${birdBuildId}")
 
   // add LABELs to dockerfiles
-  def docker = new com.mirantis.mcp.Docker()
   docker.setDockerfileLabels("./calicoctl/Dockerfile.calicoctl",
                              ["docker.imgTag=${imgTag}",
                               "calico.buildImage=${buildImage}",
@@ -113,11 +581,256 @@
 
 
   return [
-    CTL_CONTAINER_NAME:"${ctlName}",
-    NODE_CONTAINER_NAME:"${nodeName}",
-    CALICO_NODE_IMAGE_REPO:"${nodeImage}",
-    CALICOCTL_IMAGE_REPO:"${ctlImage}",
+    CTL_CONTAINER_NAME:"${ctlImage}",
+    NODE_CONTAINER_NAME:"${nodeImage}",
+    CALICO_NODE_IMAGE_REPO:"${nodeRepo}",
+    CALICOCTL_IMAGE_REPO:"${ctlRepo}",
     CALICO_VERSION: "${imgTag}"
   ]
 
 }
+
+
+/**
+ * Test Calico CNI plugin stage
+ *
+ * Usage example:
+ *
+ * def calico = new com.mirantis.mcp.Calico()
+ * calico.testCniPlugin()
+ *
+ */
+def testCniPlugin() {
+  stage ('Run cni-plugin unittests'){
+    // 'static-checks-containerized' target is removed from master
+    // and kept here only for backward compatibility
+    sh "make static-checks || make static-checks-containerized"
+    sh "make stop-etcd stop-kubernetes-master"
+    // 'stop-k8s-apiserver' target doesn't exist in Calico v2.0.0,
+    // so do not fail the stage if it's not found
+    sh "make stop-k8s-apiserver || true"
+    sh "make test-containerized"
+  }
+}
+
+
+/**
+ * Build calico/cni image stage
+ *
+ * @param config LinkedHashMap
+ *        config includes next parameters:
+ *          - dockerRegistry String, Docker registry host to push image to (optional)
+ *          - projectNamespace String, artifactory server namespace (optional)
+ *          - cniImage String, calico/cni image name (optional)
+ *          - cniImageTag String, tag of docker image (optional)
+ *
+ * Usage example:
+ *
+ * def calicoFunc = new com.mirantis.mcp.Calico()
+ * calicoFunc.buildFelix([
+ *     dockerRegistry : 'sandbox-docker-dev-virtual.docker.mirantis.net',
+ * ])
+ *
+ */
+def buildCniPlugin(LinkedHashMap config) {
+
+  def common = new com.mirantis.mcp.Common()
+  def docker = new com.mirantis.mcp.Docker()
+  def git = new com.mirantis.mcp.Git()
+
+  def dockerRegistry = config.get('dockerRegistry')
+  def projectNamespace = config.get('projectNamespace', 'mirantis/projectcalico')
+
+  def cniImage = config.get('cniImage', "calico/cni")
+  def cniImageTag = config.get('cniImageTag', git.getGitDescribe(true) + "-" + common.getDatetime())
+
+  def cniContainerName = dockerRegistry ?  "${dockerRegistry}/${projectNamespace}/${cniImage}:${cniImageTag}" : "${cniImage}:${cniImageTag}"
+
+  stage ('Build calico/cni image') {
+    docker.setDockerfileLabels("./Dockerfile", ["docker.imgTag=${cniImageTag}"])
+    sh """
+       make docker-image
+       docker tag calico/cni ${cniContainerName}
+       """
+  }
+  return [cniImage : cniImage,
+          cniImageTag : cniImageTag]
+}
+
+
+/**
+ * Publish calico docker image stage
+ *
+ * @param config LinkedHashMap
+ *        config includes next parameters:
+ *          - artifactoryServerName String, artifactory server name
+ *          - dockerRegistry String, Docker registry host to push image to
+ *          - dockerRepo String, repository (artifactory) for docker images
+ *          - imageName String, Docker image name
+ *          - imageTag String, Docker image tag
+ *          - projectNamespace String, artifactory server namespace (optional)
+ *          - publishInfo Boolean, whether publish a build-info object to Artifactory (optional)
+ *
+ * Usage example:
+ *
+ * def calico = new com.mirantis.mcp.Calico()
+ * calico.publishCalicoImage([
+ *     artifactoryServerName : 'mcp-ci',
+ *     dockerRegistry : 'sandbox-docker-dev-local.docker.mirantis.net'
+ *     dockerRepo : 'sandbox-docker-dev-local',
+ *     imageName : 'calico/node',
+ *     imageTag : 'v.1.0.0',
+ * ])
+ *
+ */
+def publishCalicoImage(config) {
+  def artifactory = new com.mirantis.mcp.MCPArtifactory()
+
+  def artifactoryServerName = config.get('artifactoryServerName')
+  def dockerRegistry = config.get('dockerRegistry')
+  def dockerRepo = config.get('dockerRepo')
+  def imageName = config.get('imageName')
+  def imageTag = config.get('imageTag')
+  def projectNamespace = config.get('projectNamespace', 'mirantis/projectcalico')
+  def publishInfo = config.get('publishInfo', true)
+
+  if (!artifactoryServerName) {
+    throw new RuntimeException("Parameter 'artifactoryServerName' must be set for publishCalicoImage() !")
+  }
+  if (!dockerRegistry) {
+    throw new RuntimeException("Parameter 'dockerRegistry' must be set for publishCalicoImage() !")
+  }
+  if (!dockerRepo) {
+    if (dockerRegistry) {
+      //Try to extract dockerRepo from dockerRegistry host/domain name
+      dockerRepo = dockerRegistry.split('\\.')[0]
+    }
+    else {
+      throw new RuntimeException("Parameter 'dockerRepo' must be set for publishCalicoImage() !")
+    }
+  }
+  if (!imageName) {
+    throw new RuntimeException("Parameter 'imageName' must be set for publishCalicoImage() !")
+  }
+  if (!imageTag) {
+    throw new RuntimeException("Parameter 'imageTag' must be set for publishCalicoImage() !")
+  }
+
+  def artifactoryServer = Artifactory.server(artifactoryServerName)
+  def buildInfo = publishInfo ? Artifactory.newBuildInfo() : null
+
+  stage("Publishing ${imageName}") {
+    artifactory.uploadImageToArtifactory(artifactoryServer,
+                                         dockerRegistry,
+                                         "${projectNamespace}/${imageName}",
+                                         imageTag,
+                                         dockerRepo,
+                                         buildInfo)
+  }
+  return "${dockerRegistry}/${projectNamespace}/${imageName}:${imageTag}"
+}
+
+
+/**
+ * Promote calico docker image stage
+ *
+ * @param config LinkedHashMap
+ *        config includes next parameters:
+ *          - imageProperties Map, docker image search properties in artifactory
+ *          - artifactoryServerName String, artifactory server name
+ *          - dockerLookupRepo String, docker repository (artifactory) to take image from
+ *          - dockerPromoteRepo String, docker repository (artifactory) to promote image to
+ *          - imageName String, Docker image name to promote with
+ *          - imageTag String, Docker image tag to promote with
+ *          - projectNamespace String, artifactory server namespace (optional)
+ *          - defineLatest Boolean, promote with latest tag if true, default false (optional)
+ *
+ * Usage example:
+ *
+ * def calico = new com.mirantis.mcp.Calico()
+ * calico.promoteCalicoImage([
+ *     imageProperties: [
+ *       'com.mirantis.targetImg': 'mirantis/projectcalico/calico/node',
+ *       'com.mirantis.targetTag': 'v1.0.0-2017010100000',
+ *     ]
+ *     artifactoryServerName : 'mcp-ci',
+ *     dockerLookupRepo : 'sandbox-docker-dev-local',
+ *     dockerPromoteRepo: 'sandbox-docker-prod-local',
+ *     imageName: 'calico/node',
+ *     imageTag: 'v1.0.0',
+ *     defineLatest: true
+ * ])
+ *
+ */
+def promoteCalicoImage (LinkedHashMap config) {
+  def common = new com.mirantis.mcp.Common()
+  def git = new com.mirantis.mcp.Git()
+  def artifactory = new com.mirantis.mcp.MCPArtifactory()
+
+  def imageProperties = config.get('imageProperties')
+  def artifactoryServerName = config.get('artifactoryServerName')
+  def dockerLookupRepo = config.get('dockerLookupRepo')
+  def dockerPromoteRepo = config.get('dockerPromoteRepo')
+  def imageName = config.get('imageName')
+  def imageTag = config.get('imageTag')
+  def projectNamespace = config.get('projectNamespace', 'mirantis/projectcalico')
+  def defineLatest = config.get('defineLatest', false)
+
+if (!imageProperties) {
+    throw new RuntimeException("Parameter 'imageProperties' must be set for promoteCalicoImage() !")
+  }
+  if (!artifactoryServerName) {
+    throw new RuntimeException("Parameter 'artifactoryServerName' must be set for promoteCalicoImage() !")
+  }
+  if (!dockerLookupRepo) {
+    throw new RuntimeException("Parameter 'dockerLookupRepo' must be set for promoteCalicoImage() !")
+  }
+  if (!dockerPromoteRepo) {
+    throw new RuntimeException("Parameter 'dockerPromoteRepo' must be set for promoteCalicoImage() !")
+  }
+  if (!imageName) {
+    throw new RuntimeException("Parameter 'imageName' must be set for promoteCalicoImage() !")
+  }
+  if (!imageTag) {
+    throw new RuntimeException("Parameter 'imageTag' must be set for promoteCalicoImage() !")
+  }
+
+  def artifactoryServer = Artifactory.server(artifactoryServerName)
+  def artifactURI = artifactory.uriByProperties(artifactoryServer.getUrl(), imageProperties)
+
+  stage("Promote ${imageName}") {
+    if ( artifactURI ) {
+      def buildProperties = artifactory.getPropertiesForArtifact(artifactURI)
+      if (defineLatest) {
+        artifactory.promoteDockerArtifact(
+          artifactoryServer.getUrl(),
+          dockerLookupRepo,
+          dockerPromoteRepo,
+          "${projectNamespace}/${imageName}",
+          buildProperties.get('com.mirantis.targetTag').join(','),
+          'latest',
+          true
+        )
+      }
+      artifactory.promoteDockerArtifact(
+        artifactoryServer.getUrl(),
+        dockerLookupRepo,
+        dockerPromoteRepo,
+        "${projectNamespace}/${imageName}",
+        buildProperties.get('com.mirantis.targetTag').join(','),
+        "${imageTag}",
+        false
+      )
+    }
+    else {
+      throw new RuntimeException("Artifacts were not found, nothing to promote! "
+                                 +"Given image properties: ${imageProperties}")
+    }
+  }
+}
+
+
+def calicoFixOwnership() {
+  // files created inside container could be owned by root, fixing that
+  sh "sudo chown -R \$(id -u):\$(id -g) ${env.WORKSPACE} ${env.HOME}/.glide || true"
+}
diff --git a/vars/buildCalicoContainers.groovy b/vars/buildCalicoContainers.groovy
deleted file mode 100644
index 1613120..0000000
--- a/vars/buildCalicoContainers.groovy
+++ /dev/null
@@ -1,93 +0,0 @@
-def call(body) {
-  // evaluate the body block, and collect configuration into the object
-  def config = [:]
-  body.resolveStrategy = Closure.DELEGATE_FIRST
-  body.delegate = config
-  body()
-
-
-  def dockerRepo = config.dockerRepo
-  def projectNamespace = "mirantis/projectcalico"
-  def artifactoryUrl = config.artifactoryURL
-
-  if (! dockerRepo ) {
-      error('dockerRepo parameter have to be set.')
-  }
-
-  if (! artifactoryUrl ) {
-      error('artifactoryUrl parameter have to be set.')
-  }
-
-  def git = new com.mirantis.mcp.Git()
-  def common = new com.mirantis.mcp.Common()
-  def imgTag = config.imageTag ?: git.getGitDescribe(true) + "-" + common.getDatetime()
-
-  def nodeImage = config.nodeImage ?: "${dockerRepo}/${projectNamespace}/calico/node"
-  def nodeName = "${nodeImage}:${imgTag}"
-
-  def ctlImage = config.ctlImage ?: "${dockerRepo}/${projectNamespace}/calico/ctl"
-  def ctlName = "${ctlImage}:${imgTag}"
-
-   // calico/build goes from libcalico
-  def buildImage = config.buildImage ?: "${dockerRepo}/${projectNamespace}/calico/build:latest"
-  // calico/felix goes from felix
-  def felixImage = config.felixImage ?: "${dockerRepo}/${projectNamespace}/calico/felix:latest"
-
-  def confdBuildId = config.confdBuildId ?: "${artifactoryUrl}/${projectNamespace}/confd/latest".toURL().text.trim()
-  def confdUrl = config.confdUrl ?: "${artifactoryUrl}/${projectNamespace}/confd/confd-${confdBuildId}"
-
-  def birdBuildId = config.birdBuildId ?: "${artifactoryUrl}/${projectNamespace}/bird/latest".toURL().text.trim()
-  def birdUrl = config.birdUrl ?: "${artifactoryUrl}/${projectNamespace}/bird/bird-${birdBuildId}"
-  def bird6Url = config.bird6Url ?: "${artifactoryUrl}/${projectNamespace}/bird/bird6-${birdBuildId}"
-  def birdclUrl = config.birdclUrl ?: "${artifactoryUrl}/${projectNamespace}/bird/birdcl-${birdBuildId}"
-
-  // add LABELs to dockerfiles
-  def docker = new com.mirantis.mcp.Docker()
-  docker.setDockerfileLabels("./calicoctl/Dockerfile.calicoctl",
-                            ["docker.imgTag=${imgTag}",
-                             "calico.buildImage=${buildImage}",
-                             "calico.birdclUrl=${birdclUrl}"])
-
-  docker.setDockerfileLabels("./calico_node/Dockerfile",
-                            ["docker.imgTag=${imgTag}",
-                             "calico.buildImage=${buildImage}",
-                             "calico.felixImage=${felixImage}",
-                             "calico.confdUrl=${confdUrl}",
-                             "calico.birdUrl=${birdUrl}",
-                             "calico.bird6Url=${bird6Url}",
-                             "calico.birdclUrl=${birdclUrl}"])
-
-  // Start build section
-  stage ('Build calico/ctl image'){
-    sh """
-      make calico/ctl \
-        CTL_CONTAINER_NAME=${ctlName} \
-        PYTHON_BUILD_CONTAINER_NAME=${buildImage} \
-        BIRDCL_URL=${birdclUrl}
-    """
-  }
-
-
-  stage('Build calico/node'){
-    sh """
-      make calico/node \
-        NODE_CONTAINER_NAME=${nodeName} \
-        PYTHON_BUILD_CONTAINER_NAME=${buildImage} \
-        FELIX_CONTAINER_NAME=${felixImage} \
-        CONFD_URL=${confdUrl} \
-        BIRD_URL=${birdUrl} \
-        BIRD6_URL=${bird6Url} \
-        BIRDCL_URL=${birdclUrl}
-    """
-  }
-
-
-  return [
-    CTL_CONTAINER_NAME:"${ctlName}",
-    NODE_CONTAINER_NAME:"${nodeName}",
-    CALICO_NODE_IMAGE_REPO:"${nodeImage}",
-    CALICOCTL_IMAGE_REPO:"${ctlImage}",
-    CALICO_VERSION: "${imgTag}"
-  ]
-
-}
diff --git a/vars/buildCalicoContainers.txt b/vars/buildCalicoContainers.txt
deleted file mode 100644
index ce54270..0000000
--- a/vars/buildCalicoContainers.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-// Usage example
-// List of parameters with the default values
-  def dockerRepo = config.dockerRepo ?: "mcp-k8s-ci.docker.mirantis.net"
-  def artifactoryUrl = config.artifactoryURL ?: "https://artifactory.mcp.mirantis.net/artifactory/projectcalico"
-  def nodeImage = config.nodeImage ?: "calico/node"
-  def nodeImageTag = config.nodeImageTag ?: "v1.0.0-beta"
-  def ctlImage = config.ctlImage ?: "calico/ctl"
-  def ctlImageTag = config.ctlImageTag ?: "v1.0.0-beta"
-  def buildImage = config.buildImage ?: "${artifactoryURL}/mcp/libcalico/lastbuild".toURL().text.trim()
-  def felixImage = config.felixImage ?: "${artifactoryURL}/mcp/felix/lastbuild".toURL().text.trim()
-  def confdBuildId = config.confdBuildId ?: "${artifactoryURL}/mcp/confd/lastbuild".toURL().text.trim()
-  def confdUrl = config.confdUrl ?: "${artifactoryURL}/mcp/confd/confd-${confdBuildId}"
-  def birdBuildId = config.birdBuildId ?: "${artifactoryURL}/mcp/calico-bird/lastbuild".toURL().text.trim()
-  def birdUrl = config.birdUrl ?: "${artifactoryURL}/mcp/calico-bird/bird-${birdBuildId}"
-  def bird6Url = config.bird6Url ?: "${artifactoryURL}/mcp/calico-bird/bird6-${birdBuildId}"
-  def birdclUrl = config.birdclUrl ?: "${artifactoryURL}/mcp/calico-bird/birdcl-${birdBuildId}"
-  def build = "${config.containersBuildId}-${gitCommit}"
-
-// *** Examples 1:
-// we still use old schema and want to publish to GERRIT_CHANGE_NUMBER
-def buildId = ${GERRIT_CHANGE_NUMBER}
-// we want to store in artifacts from gate then
-def buildId = "mcp"
-node {
-    buildCalicoContainers {
-      dockerRepo = "mcp-k8s-ci.docker.mirantis.net"
-      artifactoryURL = "https://artifactory.mcp.mirantis.net/artifactory/sandbox"
-      containersBuildId = buildId
-    }
-}