Merge "Removed test for existing publisher during aptly promote PROD-19620"
diff --git a/src/com/mirantis/mk/Aptly.groovy b/src/com/mirantis/mk/Aptly.groovy
index 4e22a67..94f085f 100644
--- a/src/com/mirantis/mk/Aptly.groovy
+++ b/src/com/mirantis/mk/Aptly.groovy
@@ -206,6 +206,32 @@
 }
 
 /**
+ * Returns list of the packages from specified Aptly repo  by REST API
+ *
+ * @param server            URI of the server insluding port and protocol
+ * @param repo              Local repo name
+ **/
+def listPackagesFromRepoByAPI(server, repo){
+    http = new com.mirantis.mk.Http()
+    def packageList = http.restGet(server, "/api/repos/${repo}/packages")
+    return packageList
+}
+
+/**
+ * Deletes packages from specified Aptly repo by REST API
+ *
+ * @param server            URI of the server insluding port and protocol
+ * @param repo              Local repo name
+ * @param packageRefs       Package list specified by packageRefs
+ **/
+def deletePackagesFromRepoByAPI(server, repo, packageRefs){
+    http = new com.mirantis.mk.Http()
+    def data  = [:]
+    data['PackageRefs'] = packageRefs
+    http.restDelete(server, "/api/repos/${repo}/packages", data)
+}
+
+/**
  * Returns list of the packages matched to pattern and
  * belonged to particular snapshot by REST API
  *
@@ -248,7 +274,7 @@
         data['PackageRefs'] = packageRefs
         http.restPost(server, '/api/snapshots', data)
     } else {
-        http.restPost(server + "/api/repos/${repo}/snapshots", data)
+        http.restPost(server, "/api/repos/${repo}/snapshots", data)
     }
 }
 
diff --git a/src/com/mirantis/mk/Debian.groovy b/src/com/mirantis/mk/Debian.groovy
index ff05ce3..7b778e8 100644
--- a/src/com/mirantis/mk/Debian.groovy
+++ b/src/com/mirantis/mk/Debian.groovy
@@ -38,6 +38,7 @@
             export DEBUG="${debug}" &&
             export LD_LIBRARY_PATH=\${LD_LIBRARY_PATH:+"\$LD_LIBRARY_PATH:"}/usr/lib/libeatmydata &&
             export LD_PRELOAD=\${LD_PRELOAD:+"\$LD_PRELOAD "}libeatmydata.so &&
+            export DEB_BUILD_OPTIONS=nocheck &&
             [[ -z "${extraRepoUrl}" && "${extraRepoUrl}" != "null" ]] || echo "${extraRepoUrl}" | tr ";" "\\\\n" >/etc/apt/sources.list.d/extra.list &&
             [[ -z "${extraRepoKeyUrl}" && "${extraRepoKeyUrl}" != "null" ]] || (
                 which curl || (apt-get update && apt-get install -y curl) &&
diff --git a/src/com/mirantis/mk/Http.groovy b/src/com/mirantis/mk/Http.groovy
index e14a523..987a998 100644
--- a/src/com/mirantis/mk/Http.groovy
+++ b/src/com/mirantis/mk/Http.groovy
@@ -220,3 +220,138 @@
     System.getProperties().remove("http.nonProxyHosts")
     System.getProperties().remove("https.nonProxyHosts")
 }
+
+/**
+ * Make HTTP request to the specified URL
+ *
+ * @param url       URL to do HTTP request to
+ * @param method    HTTP method to execute (`GET` by default)
+ * @param credsId   Jenkins credentials ID to use for authorization
+ * @param pushData  Data to send
+ * @param pushType  MIME-type of pushData
+ * @param params    Custom HTTP-headers
+ *
+ * @return          Array containing return code and text
+ *
+ * @exception       org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException
+ */
+def methodCall(String url, String method = 'GET', String credsId = '',
+         String pushData = '', String pushType = '', Map params = [:]) {
+
+    // Connection object
+    def httpReq = new URI(url).normalize().toURL().openConnection()
+    httpReq.setRequestMethod(method)
+
+    // Timeouts
+    httpReq.setConnectTimeout(10*1000) // milliseconds
+    httpReq.setReadTimeout(600*1000)   // milliseconds
+
+    // Add authentication data
+    if (credsId) {
+        String authHeader = ''
+        def cred = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
+            com.cloudbees.plugins.credentials.impl.BaseStandardCredentials.class,
+            jenkins.model.Jenkins.instance).findAll {it.id == credsId}[0]
+        if (cred.class == com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl.class) {
+            authHeader = 'Basic ' + "${cred.getUsername()}:${cred.getPassword()}".getBytes('UTF-8').encodeBase64().toString()
+        } else if (cred.class == org.jenkinsci.plugins.plaincredentials.impl.StringCredentialsImpl.class) {
+            authHeader = 'Bearer ' + cred.getSecret()
+            //params << ['X-JFrog-Art-Api': cred.getSecret()]
+        }
+        params << ['Authorization': authHeader]
+    }
+
+    // Add custom headers if any
+    for (param in params) {
+        httpReq.setRequestProperty(param.key, param.value.toString())
+    }
+
+    // Do request
+    try {
+        if (pushData) {
+            httpReq.setRequestProperty('Content-Type', pushType ?: 'application/x-www-form-urlencoded')
+            if (method == 'GET') { // override incorrect method if pushData is passed
+                httpReq.setRequestMethod('POST')
+            }
+            httpReq.setDoOutput(true)
+            httpReq.getOutputStream().write(pushData.getBytes('UTF-8'))
+        } else {
+            httpReq.connect()
+        }
+    } catch (org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException e) {
+        throw e // show sandbox errors
+    } catch (Exception e) {
+        echo "Cauhgt '${e.class.name}' error: ${e.getMessage()}"
+        return [ -1, e.getMessage() ]
+    }
+
+    // Handle return data
+    int respCode = httpReq.getResponseCode()
+    String respText = ''
+    if (respCode >= 400) {
+        respText = httpReq.getErrorStream().getText() ?: httpReq.getResponseMessage()
+    } else {
+        respText = httpReq.getInputStream().getText()
+    }
+
+    // Return result as a tuple of response code and text
+    return [respCode, respText]
+}
+
+/**
+ * Make HTTP GET request to the specified URL
+ *
+ * @param url       URL to do HTTP request to
+ * @param credsId   Jenkins credentials ID to use for authorization
+ * @param params    Custom HTTP-headers
+ *
+ * @return          Array containing return code and text
+ */
+def doGet(String url, String credsId = '', Map params = [:]) {
+    return methodCall(url, 'GET', credsId, null, null, params)
+}
+
+/**
+ * Make HTTP POST request to the specified URL
+ *
+ * @param url       URL to do HTTP request to
+ * @param credsId   Jenkins credentials ID to use for authorization
+ * @param pushData  Data to send
+ * @param pushType  MIME-type of pushData
+ * @param params    Custom HTTP-headers
+ *
+ * @return          Array containing return code and text
+ */
+def doPost(String url, String credsId = '',
+         String pushData = '', String pushType = '', Map params = [:]) {
+    return methodCall(url, 'POST', credsId, pushData, pushType, params)
+}
+
+/**
+ * Make HTTP PUT request to the specified URL
+ *
+ * @param url       URL to do HTTP request to
+ * @param credsId   Jenkins credentials ID to use for authorization
+ * @param pushData  Data to send
+ * @param pushType  MIME-type of pushData
+ * @param params    Custom HTTP-headers
+ *
+ * @return          Array containing return code and text
+ */
+def doPut(String url, String credsId = '',
+        String pushData = '', String pushType = '', Map params = [:]) {
+    return methodCall(url, 'PUT', credsId, pushData, pushType, params)
+}
+
+/**
+ * Make HTTP DELETE request to the specified URL
+ *
+ * @param url       URL to do HTTP request to
+ * @param credsId   Jenkins credentials ID to use for authorization
+ * @param params    Custom HTTP-headers
+ *
+ * @return          Array containing return code and text
+ */
+def doDelete(String url, String credsId = '', Map params = [:]) {
+    return methodCall(url, 'DELETE', credsId, null, null, params)
+}
diff --git a/src/com/mirantis/mk/Orchestrate.groovy b/src/com/mirantis/mk/Orchestrate.groovy
index 664871f..de55a42 100644
--- a/src/com/mirantis/mk/Orchestrate.groovy
+++ b/src/com/mirantis/mk/Orchestrate.groovy
@@ -16,6 +16,7 @@
 
 def installFoundationInfra(master, staticMgmtNet=false) {
     def salt = new com.mirantis.mk.Salt()
+    def common = new com.mirantis.mk.Common()
 
     // NOTE(vsaienko) Apply reclass first, it may update cluster model
     // apply linux and salt.master salt.minion states afterwards to make sure
@@ -29,7 +30,13 @@
     salt.enforceState(master, 'I@salt:master', ['salt.minion'], true, false, null, false, 60, 2)
     salt.enforceState(master, 'I@salt:master', ['salt.minion'])
     salt.fullRefresh(master, "*")
-
+    salt.enforceState(master, '*', ['linux.network.proxy'], true, false, null, false, 60, 2)
+    try {
+        salt.enforceState(master, '*', ['salt.minion.base'], true, false, null, false, 60, 2)
+        sleep(5)
+    } catch (Throwable e) {
+        common.warningMsg('Salt state salt.minion.base is not present in the Salt-formula yet.')
+    }
     salt.enforceState(master, '*', ['linux.system'])
     if (staticMgmtNet) {
         salt.runSaltProcessStep(master, '*', 'cmd.shell', ["salt-call state.sls linux.network; salt-call service.restart salt-minion"], null, true, 60)
@@ -43,9 +50,17 @@
 
 def installFoundationInfraOnTarget(master, target, staticMgmtNet=false) {
     def salt = new com.mirantis.mk.Salt()
+    def common = new com.mirantis.mk.Common()
 
     salt.enforceState(master, 'I@salt:master', ['reclass'], true, false, null, false, 120, 2)
     salt.fullRefresh(master, target)
+    salt.enforceState(master, target, ['linux.network.proxy'], true, false, null, false, 60, 2)
+    try {
+        salt.enforceState(master, target, ['salt.minion.base'], true, false, null, false, 60, 2)
+        sleep(5)
+    } catch (Throwable e) {
+        common.warningMsg('Salt state salt.minion.base is not present in the Salt-formula yet.')
+    }
     salt.enforceState(master, target, ['linux.system'])
     if (staticMgmtNet) {
         salt.runSaltProcessStep(master, target, 'cmd.shell', ["salt-call state.sls linux.network; salt-call service.restart salt-minion"], null, true, 60)
@@ -265,11 +280,6 @@
         }
     }
 
-    // Create neutron resources
-    if (salt.testTarget(master, 'I@neutron:client')) {
-        salt.enforceState(master, 'I@neutron:client', 'neutron.client')
-    }
-
     // Install heat service
     if (salt.testTarget(master, 'I@heat:server')) {
         // run on first node first
@@ -409,6 +419,20 @@
 
 def installOpenstackNetwork(master, physical = "false") {
     def salt = new com.mirantis.mk.Salt()
+    //run full neutron state on neutron.gateway - this will install
+    //neutron agents in addition to neutron server. Once neutron agents
+    //are up neutron resources can be created without hitting the situation when neutron resources are created
+    //prior to neutron agents which results in creating ports in non-usable state
+    if (salt.testTarget(master, 'I@neutron:gateway')) {
+            salt.enforceState(master, 'I@neutron:gateway', 'neutron')
+    }
+
+    // Create neutron resources - this step was moved here to ensure that
+    //neutron resources are created after neutron agens are up. In this case neutron ports will be in
+    //usable state. More information: https://bugs.launchpad.net/neutron/+bug/1399249
+    if (salt.testTarget(master, 'I@neutron:client')) {
+        salt.enforceState(master, 'I@neutron:client', 'neutron.client')
+    }
 
     salt.enforceHighstate(master, 'I@neutron:gateway')