Initial commit
Add infrastructure jobs for sandbox

Related-PROD: RE-336

Change-Id: I2140d47e3fc360ab05f92175b29b31e69b2ec10b
diff --git a/common/pipelines/update-jenkins-jobs.groovy b/common/pipelines/update-jenkins-jobs.groovy
new file mode 100644
index 0000000..4bb3702
--- /dev/null
+++ b/common/pipelines/update-jenkins-jobs.groovy
@@ -0,0 +1,202 @@
+#!groovy
+
+def main(String cacheHome = 'output/cache') {
+    String gitUrl = "${env.GERRIT_SCHEME}://${env.GERRIT_HOST}:${env.GERRIT_PORT}/${env.GERRIT_PROJECT}"
+    String gitRef = env.GERRIT_BRANCH ?: env.GERRIT_REFNAME
+    String artInfraNamespace = 'binary-dev-local/infra'
+    String artCacheFile = "${env.CI_NAME}.jjb.zip"
+    String artCacheUrl = "${env.ARTIFACTORY_URL}/artifactory/${artInfraNamespace}/${artCacheFile}"
+    String artCredential = env.ART_CREDENTIALS_ID
+    String jenkinsCredential = env.JENKINS_CREDENTIALS_ID
+    def response
+
+    def jenkinsJobs
+    def jjbJobs
+    def jobsToRemove
+
+    currentBuild.description = ''
+
+    // Set current build description
+    if (env.GERRIT_CHANGE_URL) {
+        currentBuild.description = """
+        <p>
+          Triggered by change: <a href="${env.GERRIT_CHANGE_URL}">${env.GERRIT_CHANGE_NUMBER},${env.GERRIT_PATCHSET_NUMBER}</a><br/>
+          Project: <b>${env.GERRIT_PROJECT}</b><br/>
+          Branch: <b>${env.GERRIT_BRANCH}</b><br/>
+          Subject: <b>${env.GERRIT_CHANGE_SUBJECT}</b><br/>
+        </p>
+        """
+    }
+
+    stage('SCM checkout') {
+        if (env.MAINTAIN_MODE.toLowerCase() == 'false') {
+            checkout([
+                $class: 'GitSCM',
+                branches: [[
+                    name: 'FETCH_HEAD'
+                ]],
+                userRemoteConfigs: [[
+                    url: gitUrl,
+                    refspec: gitRef,
+                    credentialsId: env.GIT_CREDENTIALS_ID
+                ]],
+                extensions: [[
+                    $class: 'WipeWorkspace'
+                ]],
+            ])
+        }
+    }
+
+    stage('Get JJB cache') {
+        dir(cacheHome) {
+            response = httpRequest \
+                url: artCacheUrl,
+                authentication: artCredential,
+                httpMode: 'GET',
+                outputFile: artCacheFile,
+                validResponseCodes: '100:399,404'
+            if (response.status != 404) {
+               unzip \
+                   zipFile: artCacheFile,
+                   dir: '.cache'
+            }
+        }
+    }
+
+    stage('Update JJB jobs') {
+        if (env.MAINTAIN_MODE.toLowerCase() == 'false') {
+            withCredentials([
+                usernamePassword(
+                    credentialsId: env.JENKINS_CREDENTIALS_ID,
+                    usernameVariable: 'JJB_USER',
+                    passwordVariable: 'JJB_PASSWORD')
+                ]) {
+                    withEnv([
+                        "HOME=${cacheHome}"
+                    ]) {
+                        sh 'tox -v -e update $JOBS_LIST'
+                }
+            }
+        } else {
+            input \
+                message: 'Sleeping for maintainance'
+        }
+    }
+
+    stage('Get deployed jobs list') {
+        response = httpRequest \
+            url: "${JENKINS_URL}/crumbIssuer/api/json",
+            authentication: jenkinsCredential
+        def crumb = readJSON text: response.getContent()
+
+        response = httpRequest \
+            url: "${JENKINS_URL}/api/json?tree=jobs[name,description]",
+            authentication: jenkinsCredential,
+            customHeaders: [[
+                name: crumb.crumbRequestField,
+                value: crumb.crumb,
+                maskValue: true
+            ]]
+        def jobs = readJSON text: response.getContent()
+
+        jenkinsJobs = jobs.jobs.findAll {
+                // Filter jenkins jobs deployed by JJB
+                it.description.toString().contains('Managed by Jenkins Job Builder')
+            }.collect{ it.name }
+    }
+
+    stage('Get JJB jobs list') {
+        withEnv([
+            "HOME=${cacheHome}"
+        ]) {
+            sh 'tox -v -e jobs'
+        }
+        dir("output/${env.CI_NAME}") {
+            jjbJobs = sh(
+                script: "grep -rl actions | sed 's|/config.xml\$||g'",
+                returnStdout: true
+            ).trim().readLines()
+        }
+
+        if (jjbJobs.size() == 0) {
+            error 'ERROR: Unexpected JJB output. No generated jobs found'
+        }
+    }
+
+    stage('Remove undefined jobs') {
+        jobsToRemove = jenkinsJobs.findAll { ! jjbJobs.contains(it) }
+
+        if (jobsToRemove.size() > 0) {
+            withCredentials([
+                usernamePassword(
+                    credentialsId: jenkinsCredential,
+                    usernameVariable: 'JJB_USER',
+                    passwordVariable: 'JJB_PASSWORD')
+            ]) {
+                withEnv([
+                    "HOME=${cacheHome}"
+                ]) {
+                    sh "tox -v -e delete ${jobsToRemove.join(' ')}"
+                }
+            }
+
+            String description = '<b>DELETED</b><ul>'
+            jobsToRemove.each { description += "<li>${it}</li>" }
+            description += '</ul>'
+            currentBuild.description += description
+        } else {
+            currentBuild.description += 'No jobs to remove'
+        }
+    }
+
+    stage('Save JJB cache') {
+        dir(cacheHome) {
+            sh "rm -f ${artCacheFile}"
+            zip \
+                zipFile: artCacheFile,
+                dir: '.cache',
+                glob: 'jenkins_jobs/**'
+            response = httpRequest \
+                url: artCacheUrl,
+                authentication: artCredential,
+                httpMode: 'PUT',
+                multipartName: 'file',
+                uploadFile: artCacheFile
+        }
+    }
+}
+
+String podTpl = """
+    apiVersion: "v1"
+    kind: "Pod"
+    spec:
+      securityContext:
+          runAsUser: 1000
+      containers:
+      - name: "tox"
+        image: "${env.DOCKER_IMAGE}"
+        command:
+        - "cat"
+        securityContext:
+          privileged: false
+        tty: true
+"""
+
+if (env.K8S_CLUSTER == 'unset') {
+    node(env.SLAVE_LABEL ?: 'docker') {
+        main(env.WORKSPACE)
+    }
+} else {
+    podTemplate(
+            cloud: env.K8S_CLUSTER,
+            yaml: podTpl,
+            showRawYaml: false
+    ) {
+        node(POD_LABEL) {
+            container('tox') {
+                main()
+            }
+        }
+    }
+}
+