Merge "Improve exception report from execute_commands"
diff --git a/jobs/pipelines/swarm-bootstrap-salt-cluster-devops.groovy b/jobs/pipelines/swarm-bootstrap-salt-cluster-devops.groovy
index 570f47f..ad1a6b3 100644
--- a/jobs/pipelines/swarm-bootstrap-salt-cluster-devops.groovy
+++ b/jobs/pipelines/swarm-bootstrap-salt-cluster-devops.groovy
@@ -24,6 +24,8 @@
 
 @Library('tcp-qa')_
 
+import groovy.xml.XmlUtil
+
 common = new com.mirantis.mk.Common()
 shared = new com.mirantis.system_qa.SharedPipeline()
 
@@ -85,10 +87,11 @@
             """)
         }
 
-        try {
-            stage("Run the 'underlay' and 'salt-deployed' fixtures to bootstrap salt cluster") {
+        stage("Run the 'underlay' and 'salt-deployed' fixtures to bootstrap salt cluster") {
+            def xml_report_name = "deploy_salt.xml"
+            try {
                 // deploy_salt.xml
-                shared.run_cmd("""\
+                shared.run_sh("""\
                     export ENV_NAME=${ENV_NAME}
                     export LAB_CONFIG_NAME=${LAB_CONFIG_NAME}
                     export MANAGER=devops
@@ -97,23 +100,29 @@
                     export PYTHONIOENCODING=UTF-8
                     export REPOSITORY_SUITE=${MCP_VERSION}
                     export TEST_GROUP=test_bootstrap_salt
-                    py.test -vvv -s -p no:django -p no:ipdb --junit-xml=deploy_salt.xml -k \${TEST_GROUP}
+                    py.test -vvv -s -p no:django -p no:ipdb --junit-xml=${xml_report_name} -k \${TEST_GROUP}
                     sleep 60  # wait for jenkins to start and IO calm down
                 """)
-            }
 
-          } catch (e) {
-              common.printMsg("Saltstack cluster deploy is failed", "purple")
-              shared.download_logs("deploy_salt")
-              throw e
-          } finally {
-            // TODO(ddmitriev): analyze the "def currentResult = currentBuild.result ?: 'SUCCESS'"
-            // and report appropriate data to TestRail
-            // TODO(ddmitriev): add checks for salt cluster
-            if ("${env.SHUTDOWN_ENV_ON_TEARDOWN}" == "true") {
-                shared.run_cmd("""\
-                    dos.py destroy ${ENV_NAME}
-                """)
+            } catch (e) {
+                  common.printMsg("Saltstack cluster deploy is failed", "purple")
+                  if (fileExists(xml_report_name)) {
+                      shared.download_logs("deploy_salt")
+                      def String junit_report_xml = readFile(xml_report_name)
+                      def String junit_report_xml_pretty = new XmlUtil().serialize(junit_report_xml)
+                      throw new Exception(junit_report_xml_pretty)
+                  } else {
+                      throw e
+                  }
+            } finally {
+                // TODO(ddmitriev): analyze the "def currentResult = currentBuild.result ?: 'SUCCESS'"
+                // and report appropriate data to TestRail
+                // TODO(ddmitriev): add checks for salt cluster
+                if ("${env.SHUTDOWN_ENV_ON_TEARDOWN}" == "true") {
+                    shared.run_cmd("""\
+                        dos.py destroy ${ENV_NAME}
+                    """)
+                }
             }
         }
     }
diff --git a/tcp_tests/managers/execute_commands.py b/tcp_tests/managers/execute_commands.py
index 193153c..e9b7d12 100644
--- a/tcp_tests/managers/execute_commands.py
+++ b/tcp_tests/managers/execute_commands.py
@@ -132,8 +132,14 @@
 
                 if x == 1 and skip_fail is False:
                     # In the last retry iteration, raise an exception
-                    raise Exception("Step '{0}' failed"
-                                    .format(description))
+                    raise Exception("Step '{0}' failed:\n"
+                                    "=======================================\n"
+                                    "STDOUT: {1}\n"
+                                    "=======================================\n"
+                                    "STDERR: {2}\n"
+                                    .format(description,
+                                            result.stdout_str,
+                                            result.stderr_str))
 
     def command2(self, step, msg):
         # Required fields