Merge "Add pipeline for job to test new Reclass version compatibility"
diff --git a/docker-mirror-images.groovy b/docker-mirror-images.groovy
index 92fea8e..4ccc74a 100644
--- a/docker-mirror-images.groovy
+++ b/docker-mirror-images.groovy
@@ -59,13 +59,17 @@
                     imageName = getImageName(sourceImage)
                     targetImageFull = "${targetRegistryPath}/${imageName}:${env.IMAGE_TAG}"
                     srcImage = docker.image(sourceImage)
-                    srcImage.pull()
+                    common.retry(3, 5) {
+                        srcImage.pull()
+                    }
                     // Use sh-docker call for tag, due magic code in plugin:
                     // https://github.com/jenkinsci/docker-workflow-plugin/blob/docker-workflow-1.17/src/main/resources/org/jenkinsci/plugins/docker/workflow/Docker.groovy#L168-L170
                     sh("docker tag ${srcImage.id} ${targetImageFull}")
                     common.infoMsg("Attempt to push docker image into remote registry: ${env.REGISTRY_URL}")
-                    docker.withRegistry(env.REGISTRY_URL, env.TARGET_REGISTRY_CREDENTIALS_ID) {
-                        sh("docker push ${targetImageFull}")
+                    common.retry(3, 5) {
+                        docker.withRegistry(env.REGISTRY_URL, env.TARGET_REGISTRY_CREDENTIALS_ID) {
+                            sh("docker push ${targetImageFull}")
+                        }
                     }
                     if (targetImageFull.contains(externalMarker)) {
                         external = true
@@ -97,7 +101,9 @@
                                 common.infoMsg("artifactoryProperties=> ${artifactoryProperties}")
                                 // Call pipeline-library routine to set properties
                                 def mcp_artifactory = new com.mirantis.mcp.MCPArtifactory()
-                                mcp_artifactory.setProperties(imgUrl - '/manifest.json', artifactoryProperties)
+                                common.retry(3, 5) {
+                                    mcp_artifactory.setProperties(imgUrl - '/manifest.json', artifactoryProperties)
+                                }
                             }
                         }
                     }
diff --git a/k8s-upgrade-pipeline.groovy b/k8s-upgrade-pipeline.groovy
index 1dfc13a..c8e2d06 100644
--- a/k8s-upgrade-pipeline.groovy
+++ b/k8s-upgrade-pipeline.groovy
@@ -90,6 +90,15 @@
     }
 }
 
+def updateAddons(pepperEnv, target) {
+    def salt = new com.mirantis.mk.Salt()
+
+    stage("Upgrading Addons at ${target}") {
+        salt.enforceState(pepperEnv, target, "kubernetes.master.addons")
+        salt.enforceState(pepperEnv, target, "kubernetes.master.setup")
+    }
+}
+
 def upgradeDocker(pepperEnv, target) {
     def salt = new com.mirantis.mk.Salt()
 
@@ -130,6 +139,7 @@
                                 upgradeDocker(pepperEnv, t)
                             }
                             performKubernetesControlUpdate(pepperEnv, t)
+                            updateAddons(pepperEnv, t)
                             uncordonNode(pepperEnv, t)
                         }
                     }
diff --git a/openstack-control-upgrade.groovy b/openstack-control-upgrade.groovy
index 6a6eea2..5febb3c 100644
--- a/openstack-control-upgrade.groovy
+++ b/openstack-control-upgrade.groovy
@@ -159,6 +159,7 @@
     for (target in upgradeTargets){
       common.stageWrapper(upgradeStageMap, "Pre upgrade", target, interactive) {
         openstack.runOpenStackUpgradePhase(env, target, 'pre')
+        openstack.runOpenStackUpgradePhase(env, target, 'verify')
       }
     }
 
diff --git a/test-openscap-pipeline.groovy b/test-openscap-pipeline.groovy
index 244126b..c57e67d 100644
--- a/test-openscap-pipeline.groovy
+++ b/test-openscap-pipeline.groovy
@@ -31,9 +31,12 @@
   * @param apiUrl               The base dashboard api url
   * @param cloudName            The cloud name (mostly, the given node's domain name)
   * @param nodeName             The node name
-  * @param results              The scanning results
+  * @param reportType           Type of the report to create/use, either 'openscap' or 'cve'
+  * @param reportId             Report Id to re-use, if empty report will be created
+  * @param results              The scanning results as a json file content (string)
+  * @return reportId            The Id of the report created if incoming reportId was empty, otherwise incoming reportId
   */
-def uploadResultToDashboard(apiUrl, cloudName, nodeName, results) {
+def uploadResultToDashboard(apiUrl, cloudName, nodeName, reportType, reportId, results) {
     def common = new com.mirantis.mk.Common()
     def http = new com.mirantis.mk.Http()
 
@@ -43,9 +46,13 @@
     def cloudId
     def nodeId
 
+    def worpApi = [:]
+    worpApi["url"] = apiUrl
+
     // Let's take a look, may be our minion is already presented on the dashboard
     // Get available environments
-    environments = common.parseJSON(http.sendHttpGetRequest("${apiUrl}/environment/"))
+    common.infoMsg("Making GET to ${worpApi.url}/environment/")
+    environments = http.restGet(worpApi, "/environment/")
     for (environment in environments) {
         if (environment['name'] == cloudName) {
             cloudId = environment['uuid']
@@ -55,22 +62,27 @@
     // Cloud wasn't presented, let's create it
     if (! cloudId ) {
         // Create cloud
-        resuestData['name'] = cloudName
-        cloudId = common.parseJSON(http.sendHttpPostRequest("${apiUrl}/environment/", requestData))['env']['uuid']
+        requestData = [:]
+        requestData['name'] = cloudName
+        common.infoMsg("Making POST to ${worpApi.url}/environment/ with ${requestData}")
+        cloudId = http.restPost(worpApi, "/environment/", requestData)['env']['uuid']
 
         // And the node
         // It was done here to reduce count of requests to the api.
         // Because if there was not cloud presented on the dashboard, then the node was not presented as well.
+        requestData = [:]
         requestData['nodes'] = [nodeName]
-        nodeId = common.parseJSON(http.sendHttpPutRequest("${apiUrl}/environment/${cloudId}/nodes/", requestData))['uuid']
+        common.infoMsg("Making PUT to ${worpApi.url}/environment/${cloudId}/nodes/ with ${requestData}")
+        nodeId = http.restCall(worpApi, "/environment/${cloudId}/nodes/", "PUT", requestData)['uuid']
     }
 
     if (! nodeId ) {
         // Get available nodes in our environment
-        nodes = common.parseJSON(http.sendHttpGetRequest("${apiUrl}/environment/${cloudId}/nodes/"))
+        common.infoMsg("Making GET to ${worpApi.url}/environment/${cloudId}/nodes/")
+        nodes = http.restGet(worpApi, "/environment/${cloudId}/nodes/")
         for (node in nodes) {
             if (node['name'] == nodeName) {
-                nodeId = node['id']
+                nodeId = node['uuid']
                 break
             }
         }
@@ -79,18 +91,29 @@
     // Node wasn't presented, let's create it
     if (! nodeId ) {
         // Create node
+        requestData = [:]
         requestData['nodes'] = [nodeName]
-        nodeId = common.parseJSON(http.sendHttpPutRequest("${apiUrl}/environment/${cloudId}/nodes/", requestData))['uuid']
+        common.infoMsg("Making PUT to ${worpApi.url}/environment/${cloudId}/nodes/ with ${requestData}")
+        nodeId = http.restCall(worpApi, "/environment/${cloudId}/nodes/", "PUT", requestData)['uuid']
     }
 
-    // Get report_id
-    requestData['env_uuid'] = cloudId
-    def reportId = common.parseJSON(http.sendHttpPostRequest("${apiUrl}/reports/openscap/", requestData))['report']['uuid']
+    // Create report if needed
+    if (! reportId ) {
+        requestData = [:]
+        requestData['env_uuid'] = cloudId
+        common.infoMsg("Making POST to ${worpApi.url}/reports/${reportType}/ with ${requestData}")
+        reportId = http.restPost(worpApi, "/reports/${reportType}/", requestData)['report']['uuid']
+    }
 
     // Upload results
-    requestData['results'] = results
+    // NOTE(pas-ha) results should already be a dict with 'results' key
+    requestData = common.parseJSON(results)
     requestData['node_name'] = nodeName
-    http.sendHttpPutRequest("${apiUrl}/reports/openscap/${reportId}/", requestData)
+    common.infoMsg("First result in results to PUT is ${requestData['results'][0]}")
+    // NOTE(pas-ha) not logging whole results to be sent, is too large and just spams the logs
+    common.infoMsg("Making PUT to ${worpApi.url}/reports/${reportType}/${reportId}/ with node name ${requestData['node_name']} and results")
+    http.restCall(worpApi, "/reports/${reportType}/${reportId}/", "PUT", requestData)
+    return reportId
 }
 
 
@@ -137,6 +160,7 @@
             deleteDir()
         }
 
+        def reportId
         for (minion in liveMinions) {
 
             // Iterate oscap evaluation over the benchmarks
@@ -179,7 +203,7 @@
                 if (UPLOAD_TO_DASHBOARD.toBoolean()) {
                     if (common.validInputParam('DASHBOARD_API_URL')) {
                         def cloudName = salt.getGrain(pepperEnv, minion, 'domain')['return'][0].values()[0].values()[0]
-                        uploadResultToDashboard(DASHBOARD_API_URL, cloudName, minion, salt.getFileContent(pepperEnv, minion, "${resultsDir}/results.json"))
+                        reportId = uploadResultToDashboard(DASHBOARD_API_URL, cloudName, minion, "openscap", reportId, salt.getFileContent(pepperEnv, minion, "${resultsDir}/results.json"))
                     } else {
                         throw new Exception('Uploading to the dashboard is enabled but the DASHBOARD_API_URL was not set')
                     }