Merge "Allow to override cloud name in openscap pipeline"
diff --git a/aptly-promote-pipeline.groovy b/aptly-promote-pipeline.groovy
index bf73bec..7c7f492 100644
--- a/aptly-promote-pipeline.groovy
+++ b/aptly-promote-pipeline.groovy
@@ -30,15 +30,19 @@
         try {
             stage("promote") {
                 // promote is restricted to users in aptly-promote-users LDAP group
-                lock("aptly-api") {
-                    for (storage in storages) {
-                        if (storage == "local") {
-                            storage = ""
-                        }
-                        retry(2) {
-                            aptly.promotePublish(APTLY_URL, SOURCE, TARGET, RECREATE, components, packages, DIFF_ONLY, '-d --timeout 600', DUMP_PUBLISH.toBoolean(), storage)
-                        }
-                    }
+                if(jenkinsUtils.currentUserInGroups(["mcp-cicd-admins", "release-engineering", "opencontrail-all"])){
+                  lock("aptly-api") {
+                      for (storage in storages) {
+                          if (storage == "local") {
+                              storage = ""
+                          }
+                          retry(2) {
+                              aptly.promotePublish(APTLY_URL, SOURCE, TARGET, RECREATE, components, packages, DIFF_ONLY, '-d --timeout 600', DUMP_PUBLISH.toBoolean(), storage)
+                          }
+                      }
+                  }
+                }else{
+                  throw new Exception(String.format("You don't have permissions to make aptly promote from source:%s to target:%s! Only CI/CD and QA team can perform aptly promote.", SOURCE, TARGET))
                 }
             }
         } catch (Throwable e) {
@@ -60,4 +64,3 @@
         }
     }
 }
-
diff --git a/galera-cluster-verify-restore.groovy b/galera-cluster-verify-restore.groovy
new file mode 100644
index 0000000..b8826ec
--- /dev/null
+++ b/galera-cluster-verify-restore.groovy
@@ -0,0 +1,54 @@
+/**
+ * Verify and restore Galera cluster
+ *
+ * Expected parameters:
+ *   SALT_MASTER_CREDENTIALS    Credentials to the Salt API.
+ *   SALT_MASTER_URL            Full Salt API address [http://10.10.10.1:8000].
+ *
+**/
+
+def common = new com.mirantis.mk.Common()
+def salt = new com.mirantis.mk.Salt()
+def openstack = new com.mirantis.mk.Openstack()
+def python = new com.mirantis.mk.Python()
+
+def pepperEnv = "pepperEnv"
+def resultCode = 99
+
+timeout(time: 12, unit: 'HOURS') {
+    node() {
+        stage('Setup virtualenv for Pepper') {
+            python.setupPepperVirtualenv(pepperEnv, SALT_MASTER_URL, SALT_MASTER_CREDENTIALS)
+        }
+        stage('Verify status')
+            resultCode = openstack.verifyGaleraStatus(pepperEnv, false)
+        stage('Restore') {
+            if (resultCode == 128) {
+                common.errorMsg("Unable to connect to Galera Master. Trying slaves...")
+                resultCode = openstack.verifyGaleraStatus(pepperEnv, true)
+                if (resultCode == 129) {
+                    common.errorMsg("Unable to obtain Galera slave minions list". "Without fixing this issue, pipeline cannot continue in verification and restoration.")
+                    currentBuild.result = "FAILURE"
+                    return
+                } else if (resultCode == 130) {
+                    common.errorMsg("Neither master or slaves are reachable. Without fixing this issue, pipeline cannot continue in verification and restoration.")
+                    currentBuild.result = "FAILURE"
+                    return
+                }
+            }
+            if (resultCode == 1) {
+                common.warningMsg("There was a problem with parsing the status output or with determining it. Do you want to run a restore?")
+            } else if (resultCode > 1) {
+                common.warningMsg("There's something wrong with the cluster, do you want to run a restore?")
+            } else {
+                common.warningMsg("There seems to be everything alright with the cluster, do you still want to run a restore?")
+            }
+            input message: "Are you sure you want to run a restore? Click to confirm"
+            try {
+                openstack.restoreGaleraDb(pepperEnv)
+            } catch (Exception e) {
+                common.errorMsg("Restoration process has failed.")
+            }
+        }
+    }
+}
diff --git a/generate-repo-snapshot-context.groovy b/generate-repo-snapshot-context.groovy
index e51dbc4..c36aeae 100644
--- a/generate-repo-snapshot-context.groovy
+++ b/generate-repo-snapshot-context.groovy
@@ -69,6 +69,8 @@
             }
         }
 
+        // remove file if exists
+        sh "rm -rf ${fileName}"
         writeYaml file: fileName, data: ['parameters': meta ]
         archiveArtifacts artifacts: fileName
     }
diff --git a/opencontrail40-upgrade.groovy b/opencontrail40-upgrade.groovy
index 93db009..180ed85 100644
--- a/opencontrail40-upgrade.groovy
+++ b/opencontrail40-upgrade.groovy
@@ -108,8 +108,8 @@
             stage('Opencontrail controllers upgrade') {
 
                 // Sync data on minions
-                salt.runSaltProcessStep(pepperEnv, 'I@opencontrail:database or I@neutron:server or I@horizon:server', 'saltutil.refresh_pillar', [], null, true)
-                salt.runSaltProcessStep(pepperEnv, 'I@opencontrail:database or I@neutron:server or I@horizon:server', 'saltutil.sync_all', [], null, true)
+                salt.runSaltProcessStep(pepperEnv, 'I@keystone:server:role:primary or I@opencontrail:database or I@neutron:server or I@horizon:server', 'saltutil.refresh_pillar', [], null, true)
+                salt.runSaltProcessStep(pepperEnv, 'I@keystone:server:role:primary or I@opencontrail:database or I@neutron:server or I@horizon:server', 'saltutil.sync_all', [], null, true)
 
                 // Verify specified target OpenContrail version before upgrade
                 def targetOcVersion = getValueForPillarKey(pepperEnv, "I@opencontrail:control:role:primary", "_param:opencontrail_version")
@@ -127,6 +127,9 @@
                     throw er
                 }
 
+                // Make sure that dedicated opencontrail user is created
+                salt.enforceState(pepperEnv, 'I@keystone:server:role:primary', 'keystone.client.server')
+
                 try {
                     controllerImage = getValueForPillarKey(pepperEnv, "I@opencontrail:control:role:primary", "docker:client:compose:opencontrail:service:controller:image")
                     analyticsImage = getValueForPillarKey(pepperEnv, "I@opencontrail:collector:role:primary", "docker:client:compose:opencontrail:service:analytics:image")
diff --git a/openstack-compute-install.groovy b/openstack-compute-install.groovy
index 2b37fba..581168a 100644
--- a/openstack-compute-install.groovy
+++ b/openstack-compute-install.groovy
@@ -57,6 +57,10 @@
                 salt.runSaltProcessStep(pepperEnv, targetLiveAll, 'pkg.upgrade', [], null, true)
             }
 
+            stage("Update Hosts file") {
+                salt.enforceState(pepperEnv, "I@linux:system", 'linux.network.host', true)
+            }
+
             stage("Setup networking") {
                 // Sync all of the modules from the salt master.
                 salt.syncAll(pepperEnv, targetLiveAll)
diff --git a/test-cookiecutter-reclass.groovy b/test-cookiecutter-reclass.groovy
index 27313c7..b839a6d 100644
--- a/test-cookiecutter-reclass.groovy
+++ b/test-cookiecutter-reclass.groovy
@@ -196,8 +196,10 @@
         testDistribRevision = testDistribRevision.split('/')[-1]
     }
     // Check if we are going to test bleeding-edge release, which doesn't have binary release yet
-    if (!common.checkRemoteBinary([mcp_version: testDistribRevision]).linux_system_repo_url) {
-        common.errorMsg("Binary release: ${testDistribRevision} not exist. Fallback to 'proposed'! ")
+    // After 2018q4 releases, need to also check 'static' repo, for example ubuntu.
+    binTest = common.checkRemoteBinary(['mcp_version' : testDistribRevision])
+    if (!binTest.linux_system_repo_url || !binTest.linux_system_repo_ubuntu_url) {
+        common.errorMsg("Binary release: ${testDistribRevision} not exist or not full. Fallback to 'proposed'! ")
         testDistribRevision = 'proposed'
         messages.add("DISTRIB_REVISION => ${testDistribRevision}")
     }
diff --git a/test-operations-ui.groovy b/test-operations-ui.groovy
new file mode 100644
index 0000000..b6c8b27
--- /dev/null
+++ b/test-operations-ui.groovy
@@ -0,0 +1,79 @@
+/**
+ * Tests model manager UI
+ * DEFAULT_GIT_REF
+ * DEFAULT_GIT_URL
+ * NPM_DOCKER_IMG
+ */
+
+def common = new com.mirantis.mk.Common()
+def gerrit = new com.mirantis.mk.Gerrit()
+def dockerLib = new com.mirantis.mk.Docker()
+
+def gerritCredentials = env.CREDENTIALS_ID ?: 'gerrit'
+def slaveNode = env.SLAVE_NODE ?: 'python&&docker'
+def gerritRef = env.GERRIT_REFSPEC ?: null
+def defaultGitRef = env.DEFAULT_GIT_REF ?: null
+def defaultGitUrl = env.DEFAULT_GIT_URL ?: null
+
+def checkouted = false
+def testReportFile = 'test-report.html'
+
+timeout(time: 30, unit: 'MINUTES') {
+    node(slaveNode) {
+        def img = dockerLib.getImage(env.NPM_DOCKER_IMG, "npm:8.12.0")
+        try {
+            if (fileExists("build/")) {
+                common.infoMsg('Cleaning test env')
+                sh("rm -rf build/")
+            }
+            stage("checkout") {
+                if (gerritRef) {
+                    // job is triggered by Gerrit
+                    def gerritChange = gerrit.getGerritChange(GERRIT_NAME, GERRIT_HOST, GERRIT_CHANGE_NUMBER, gerritCredentials, true)
+                    if (gerritChange.commitMessage.contains("WIP")) {
+                        common.successMsg("Commit message contains WIP, skipping tests") // do nothing
+                    } else {
+                        // test if change aren't already merged
+                        def merged = gerritChange.status == "MERGED"
+                        if (!merged) {
+                            checkouted = gerrit.gerritPatchsetCheckout([
+                                    credentialsId: gerritCredentials
+                            ])
+                        } else {
+                            common.successMsg("Change ${GERRIT_CHANGE_NUMBER} is already merged, no need to test them")
+                        }
+                    }
+                } else if (defaultGitRef && defaultGitUrl) {
+                    checkouted = gerrit.gerritPatchsetCheckout(defaultGitUrl, defaultGitRef, "HEAD", gerritCredentials)
+                } else {
+                    throw new Exception("Cannot checkout gerrit patchset, GERRIT_REFSPEC and DEFAULT_GIT_REF are null")
+                }
+            }
+
+            if (checkouted) {
+                stage("test") {
+                    img.inside("-u root:root -v ${env.WORKSPACE}/:/operations-ui/ -e npm_config_cache=/operations-ui/.npm -e CI=true") {
+                        sh('''#!/bin/bash -xe
+                          cd /operations-ui
+                          npm install
+                          npm test
+                          ''')
+                    }
+                }
+            }
+        } catch (Throwable e) {
+            // If there was an error or exception thrown, the build failed
+            currentBuild.result = "FAILURE"
+            throw e
+        } finally {
+            if (fileExists(testReportFile)) {
+                archiveArtifacts artifacts: testReportFile
+            }
+            stage("Cleanup"){
+                img.inside("-u root:root -v ${env.WORKSPACE}/:/operations-ui/") {
+                    sh("rm -rf /operations-ui/*")
+                }
+            }
+        }
+    }
+}
diff --git a/test-salt-formulas-pipeline.groovy b/test-salt-formulas-pipeline.groovy
index 404c0d0..e537ee1 100644
--- a/test-salt-formulas-pipeline.groovy
+++ b/test-salt-formulas-pipeline.groovy
@@ -16,7 +16,6 @@
 def slaveNode = env.SLAVE_NODE ?: 'python&&docker'
 def saltVersion = env.SALT_VERSION ?: ""
 def dockerLib = new com.mirantis.mk.Docker()
-def img = dockerLib.getImage(env.SMOKE_TEST_DOCKER_IMG, "ubuntu:16.04")
 
 def checkouted = false
 
@@ -64,6 +63,7 @@
 
 timeout(time: 4, unit: 'HOURS') {
   node(slaveNode) {
+    def img = dockerLib.getImage(env.SMOKE_TEST_DOCKER_IMG, "ubuntu:16.04")
     try {
       if (fileExists("tests/build")) {
         common.infoMsg('Cleaning test env')
diff --git a/test-salt-model-wrapper.groovy b/test-salt-model-wrapper.groovy
index f49b7fc..cb16cf3 100644
--- a/test-salt-model-wrapper.groovy
+++ b/test-salt-model-wrapper.groovy
@@ -167,7 +167,7 @@
             }
 
             def branches = [:]
-            branches.failFast = true
+            branches.failFast = false
             String branchJobName = ''
 
             if (gerritProject == reclassSystemRepo && gerritBranch == 'master') {
diff --git a/upgrade-mcp-release.groovy b/upgrade-mcp-release.groovy
index 5bc0ab2..aa8b076 100644
--- a/upgrade-mcp-release.groovy
+++ b/upgrade-mcp-release.groovy
@@ -89,8 +89,12 @@
     }
 }
 
-if (common.validInputParam('PIPELINE_TIMEOUT') && env.PIPELINE_TIMEOUT.isInteger()) {
-    pipelineTimeout = env.PIPELINE_TIMEOUT.toInteger()
+if (common.validInputParam('PIPELINE_TIMEOUT')) {
+    try {
+        pipelineTimeout = env.PIPELINE_TIMEOUT.toInteger()
+    } catch(Exception e) {
+        common.warningMsg("Provided PIPELINE_TIMEOUT parameter has invalid value: ${env.PIPELINE_TIMEOUT} - should be interger")
+    }
 }
 
 timeout(time: pipelineTimeout, unit: 'HOURS') {
@@ -139,10 +143,10 @@
                 // backward compatibility for 2018.11.0
                 saltMastURL = env.getProperty('SALT_MASTER_URL')
                 saltMastCreds = env.getProperty('SALT_MASTER_CREDENTIALS')
-                upgradeSaltStack = env.getProperty('UPGRADE_SALTSTACK', false).toBoolean()
-                updateClusterModel = env.getProperty('UPDATE_CLUSTER_MODEL', false).toBoolean()
-                updatePipelines = env.getProperty('UPDATE_PIPELINES', false).toBoolean()
-                updateLocalRepos = env.getProperty('UPDATE_LOCAL_REPOS', false).toBoolean()
+                upgradeSaltStack = env.getProperty('UPGRADE_SALTSTACK').toBoolean()
+                updateClusterModel = env.getProperty('UPDATE_CLUSTER_MODEL').toBoolean()
+                updatePipelines = env.getProperty('UPDATE_PIPELINES').toBoolean()
+                updateLocalRepos = env.getProperty('UPDATE_LOCAL_REPOS').toBoolean()
                 reclassSystemBranch = gitTargetMcpVersion
             }