Merge "Switch valudate-cloud from hardcoded scenarios"
diff --git a/ceph-upgrade.groovy b/ceph-upgrade.groovy
index 5844f77..8323e41 100644
--- a/ceph-upgrade.groovy
+++ b/ceph-upgrade.groovy
@@ -46,37 +46,48 @@
 def backup(master, target) {
     stage("backup ${target}") {
 
-        def _pillar = salt.getGrain(master, 'I@salt:master', 'domain')
-        def domain = _pillar['return'][0].values()[0].values()[0]
-
-        def kvm_pillar = salt.getGrain(master, 'I@salt:control', 'id')
-        def kvm01 = kvm_pillar['return'][0].values()[0].values()[0]
-
-        def target_pillar = salt.getGrain(master, "I@ceph:${target}", 'host')
-        def minions = target_pillar['return'][0].values()
-        for (minion in minions) {
-            def minion_name = minion.values()[0]
-            def provider_pillar = salt.getPillar(master, "${kvm01}", "salt:control:cluster:internal:node:${minion_name}:provider")
-            def minionProvider = provider_pillar['return'][0].values()[0]
-
-            waitForHealthy(master)
+        if (target == 'osd') {
             try {
-                salt.cmdRun(master, "${minionProvider}", "[ ! -f /root/${minion_name}.${domain}.qcow2.bak ] && virsh destroy ${minion_name}.${domain}")
+                salt.enforceState(master, "I@ceph:${target}", "ceph.backup", true)
+                runCephCommand(master, "I@ceph:${target}", "su root -c '/usr/local/bin/ceph-backup-runner-call.sh'")
             } catch (Exception e) {
-                common.warningMsg('Backup already exists')
+                common.errorMsg(e)
+                common.errorMsg("Make sure Ceph backup on OSD nodes is enabled")
+                throw new InterruptedException()
             }
-            try {
-                salt.cmdRun(master, "${minionProvider}", "[ ! -f /root/${minion_name}.${domain}.qcow2.bak ] && cp /var/lib/libvirt/images/${minion_name}.${domain}/system.qcow2 /root/${minion_name}.${domain}.qcow2.bak")
-            } catch (Exception e) {
-                common.warningMsg('Backup already exists')
+        } else {
+            def _pillar = salt.getGrain(master, 'I@salt:master', 'domain')
+            def domain = _pillar['return'][0].values()[0].values()[0]
+
+            def kvm_pillar = salt.getGrain(master, 'I@salt:control', 'id')
+            def kvm01 = kvm_pillar['return'][0].values()[0].values()[0]
+
+            def target_pillar = salt.getGrain(master, "I@ceph:${target}", 'host')
+            def minions = target_pillar['return'][0].values()
+            for (minion in minions) {
+                def minion_name = minion.values()[0]
+                def provider_pillar = salt.getPillar(master, "${kvm01}", "salt:control:cluster:internal:node:${minion_name}:provider")
+                def minionProvider = provider_pillar['return'][0].values()[0]
+
+                waitForHealthy(master)
+                try {
+                    salt.cmdRun(master, "${minionProvider}", "[ ! -f /root/${minion_name}.${domain}.qcow2.bak ] && virsh destroy ${minion_name}.${domain}")
+                } catch (Exception e) {
+                    common.warningMsg('Backup already exists')
+                }
+                try {
+                    salt.cmdRun(master, "${minionProvider}", "[ ! -f /root/${minion_name}.${domain}.qcow2.bak ] && cp /var/lib/libvirt/images/${minion_name}.${domain}/system.qcow2 /root/${minion_name}.${domain}.qcow2.bak")
+                } catch (Exception e) {
+                    common.warningMsg('Backup already exists')
+                }
+                try {
+                    salt.cmdRun(master, "${minionProvider}", "virsh start ${minion_name}.${domain}")
+                } catch (Exception e) {
+                    common.warningMsg(e)
+                }
+                salt.minionsReachable(master, 'I@salt:master', "${minion_name}*")
+                waitForHealthy(master)
             }
-            try {
-                salt.cmdRun(master, "${minionProvider}", "virsh start ${minion_name}.${domain}")
-            } catch (Exception e) {
-                common.warningMsg(e)
-            }
-            salt.minionsReachable(master, 'I@salt:master', "${minion_name}*")
-            waitForHealthy(master)
         }
     }
     return
@@ -143,6 +154,9 @@
         if (STAGE_UPGRADE_RGW.toBoolean() == true) {
             backup(pepperEnv, 'radosgw')
         }
+        if (STAGE_UPGRADE_OSD.toBoolean() == true) {
+            backup(pepperEnv, 'osd')
+        }
     }
 
     if (flags.size() > 0) {
diff --git a/docker-mirror-images.groovy b/docker-mirror-images.groovy
new file mode 100644
index 0000000..91a65a6
--- /dev/null
+++ b/docker-mirror-images.groovy
@@ -0,0 +1,49 @@
+/**
+ *
+ * Mirror Docker images
+ *
+ * Expected parameters:
+ *   TARGET_REGISTRY_CREDENTIALS_ID            Credentials for target Docker Registry
+ *   TARGET_REGISTRY                           Target Docker Registry name
+ *   REGISTRY_URL                              Target Docker Registry URL
+ *   IMAGE_TAG                                 Tag to use when pushing images
+ *   IMAGE_LIST                                List of images to mirror
+ *
+ */
+import java.util.regex.Pattern;
+
+def common = new com.mirantis.mk.Common()
+
+@NonCPS
+def getImageName(String image) {
+    def regex = Pattern.compile('(?:.+/)?([^:]+)(?::.+)?')
+    def matcher = regex.matcher(image)
+    if(matcher.find()){
+        def imageName = matcher.group(1)
+        return imageName
+    }else{
+        throw new IllegalFormatException("Wrong format of image name.")
+    }
+}
+
+node("docker") {
+    try {
+        stage("Mirror Docker Images"){
+            def creds = common.getPasswordCredentials(TARGET_REGISTRY_CREDENTIALS_ID)
+            sh "docker login --username=${creds.username} --password=${creds.password.toString()} ${REGISTRY_URL}"
+            def images = IMAGE_LIST.tokenize('\n')
+            def imageName
+            for (image in images){
+                sh "echo ${image}"
+                imageName = getImageName(image)
+                sh "docker pull ${image}"
+                sh "docker tag ${image} ${TARGET_REGISTRY}/${imageName}:${IMAGE_TAG}"
+                sh "docker push ${TARGET_REGISTRY}/${imageName}:${IMAGE_TAG}"
+            }
+        }
+    } catch (Throwable e) {
+        // If there was an error or exception thrown, the build failed
+        currentBuild.result = "FAILURE"
+        throw e
+    }
+}
\ No newline at end of file
diff --git a/opencontrail-upgrade.groovy b/opencontrail-upgrade.groovy
index 805b856..83f17ee 100644
--- a/opencontrail-upgrade.groovy
+++ b/opencontrail-upgrade.groovy
@@ -39,6 +39,10 @@
 
     out = salt.runSaltCommand(pepperEnv, 'local', ['expression': target, 'type': 'compound'], command, null, args, null)
     salt.printSaltCommandResult(out)
+    // if Error occured - throw exception
+    if (out.toString().contains('E: ')) {
+        throw new Exception("Command execution failed")
+    }
     // wait until $check is in correct state
     if ( check == "nodetool status" ) {
         salt.commandStatus(pepperEnv, target, check, 'Status=Up')
@@ -81,8 +85,7 @@
             try {
                 salt.cmdRun(pepperEnv, 'I@opencontrail:control', "su root -c '/usr/local/bin/zookeeper-backup-runner.sh'")
             } catch (Exception er) {
-                common.errorMsg('Zookeeper failed to backup. Please fix it before continuing.')
-                return
+                throw new Exception('Zookeeper failed to backup. Please fix it before continuing.')
             }
 
             salt.enforceState(pepperEnv, 'I@cassandra:backup:server', 'cassandra.backup')
@@ -91,8 +94,7 @@
             try {
                 salt.cmdRun(pepperEnv, 'I@cassandra:backup:client', "su root -c '/usr/local/bin/cassandra-backup-runner-call.sh'")
             } catch (Exception er) {
-                common.errorMsg('Cassandra failed to backup. Please fix it before continuing.')
-                return
+                throw new Exception('Cassandra failed to backup. Please fix it before continuing.')
             }
 
             args = 'apt install contrail-database -y;'