Merge "Fix scheduling algorithm for KaaS jobs"
diff --git a/src/com/mirantis/mk/Gerrit.groovy b/src/com/mirantis/mk/Gerrit.groovy
index 4d04906..a48f554 100644
--- a/src/com/mirantis/mk/Gerrit.groovy
+++ b/src/com/mirantis/mk/Gerrit.groovy
@@ -188,7 +188,7 @@
     if(includeCurrentPatchset){
         curPatchset = "--current-patch-set"
     }
-    return common.parseJSON(ssh.agentSh(String.format("ssh -p %s %s@%s gerrit query ${curPatchset} --format=JSON change:%s", gerritPort, gerritName, gerritHost, gerritChangeNumber)))
+    return common.parseJSON(ssh.agentSh(String.format("ssh -p %s %s@%s gerrit query ${curPatchset} --commit-message --format=JSON change:%s", gerritPort, gerritName, gerritHost, gerritChangeNumber)))
 }
 
 /**
@@ -295,8 +295,7 @@
  */
 LinkedHashMap getDependentPatches(LinkedHashMap changeInfo) {
     def dependentPatches = [:]
-    def currentChange = getGerritChange(changeInfo.gerritName, changeInfo.gerritHost, changeInfo.gerritChangeNumber, changeInfo.credentialsId, true)
-    def dependentCommits = currentChange.commitMessage.tokenize('\n').findAll { it  ==~ /Depends-On: \b[^ ]+\b(\/)?/  }
+    def dependentCommits = changeInfo.gerritCommitMessage.tokenize('\n').findAll { it  ==~ /Depends-On: \b[^ ]+\b(\/)?/  }
     if (dependentCommits) {
         dependentCommits.each { commit ->
             def patchLink = commit.tokenize(' ')[1]
diff --git a/src/com/mirantis/mk/KaasUtils.groovy b/src/com/mirantis/mk/KaasUtils.groovy
index e78921c..5a67005 100644
--- a/src/com/mirantis/mk/KaasUtils.groovy
+++ b/src/com/mirantis/mk/KaasUtils.groovy
@@ -53,6 +53,7 @@
     def seedMacOs = env.SEED_MACOS ? env.SEED_MACOS.toBoolean() : false
     def deployChild = env.DEPLOY_CHILD_CLUSTER ? env.DEPLOY_CHILD_CLUSTER.toBoolean() : false
     def upgradeChild = env.UPGRADE_CHILD_CLUSTER ? env.UPGRADE_CHILD_CLUSTER.toBoolean() : false
+    def fullUpgradeChild = env.FULL_UPGRADE_CHILD_CLUSTER ? env.FULL_UPGRADE_CHILD_CLUSTER.toBoolean() : false
     def mosDeployChild = env.DEPLOY_MOS_CHILD_CLUSTER ? env.DEPLOY_MOS_CHILD_CLUSTER.toBoolean() : false
     def mosUpgradeChild = env.UPGRADE_MOS_CHILD_CLUSTER ? env.UPGRADE_MOS_CHILD_CLUSTER.toBoolean() : false
     def customChildRelease = env.KAAS_CHILD_CLUSTER_RELEASE_NAME ? env.KAAS_CHILD_CLUSTER_RELEASE_NAME : ''
@@ -64,6 +65,7 @@
     def upgradeMgmt = env.UPGRADE_MGMT_CLUSTER ? env.UPGRADE_MGMT_CLUSTER.toBoolean() : false
     def autoUpgradeMgmt = env.AUTO_UPGRADE_MCC ? env.AUTO_UPGRADE_MCC.toBoolean() : false
     def enableLMALogging = env.ENABLE_LMA_LOGGING ? env.ENABLE_LMA_LOGGING.toBoolean(): false
+    def deployOsOnMos = env.DEPLOY_OS_ON_MOS? env.DEPLOY_OS_ON_MOS.toBoolean() : false
     def runUie2e = env.RUN_UI_E2E ? env.RUN_UI_E2E.toBoolean() : false
     def runUie2eNew = env.RUN_UI_E2E_NEW ? env.RUN_UI_E2E_NEW.toBoolean() : false
     def runMgmtConformance = env.RUN_MGMT_CFM ? env.RUN_MGMT_CFM.toBoolean() : false
@@ -78,6 +80,8 @@
     def runMgmtDeleteMasterTest = env.RUN_MGMT_DELETE_MASTER_TEST ? env.RUN_MGMT_DELETE_MASTER_TEST.toBoolean() : false
     def runRgnlDeleteMasterTest = env.RUN_RGNL_DELETE_MASTER_TEST ? env.RUN_RGNL_DELETE_MASTER_TEST.toBoolean() : false
     def runChildDeleteMasterTest = env.RUN_CHILD_DELETE_MASTER_TEST ? env.RUN_CHILD_DELETE_MASTER_TEST.toBoolean() : false
+    def runGracefulRebootTest = env.RUN_GRACEFUL_REBOOT_TEST ? env.RUN_GRACEFUL_REBOOT_TEST.toBoolean() : false
+    def pauseForDebug = env.PAUSE_FOR_DEBUG ? env.PAUSE_FOR_DEBUG.toBoolean() : false
     // multiregion configuration from env variable: comma-separated string in form $mgmt_provider,$regional_provider
     def multiregionalMappings = env.MULTIREGION_SETUP ? multiregionWorkflowParser(env.MULTIREGION_SETUP) : [
         enabled: false,
@@ -108,6 +112,7 @@
     def childOsBootFromVolume = env.OPENSTACK_BOOT_FROM_VOLUME ? env.OPENSTACK_BOOT_FROM_VOLUME.toBoolean() : false
     def bootstrapV2Scenario = env.BOOTSTRAP_V2_ENABLED ? env.BOOTSTRAP_V2_ENABLED.toBoolean() : false
     def equinixMetalV2Metro = env.EQUINIX_MGMT_METRO ? env.EQUINIX_MGMT_METRO : ''
+    def enableFips = env.ENABLE_FIPS ? env.ENABLE_FIPS.toBoolean() : false
 
     def commitMsg = env.GERRIT_CHANGE_COMMIT_MESSAGE ? new String(env.GERRIT_CHANGE_COMMIT_MESSAGE.decodeBase64()) : ''
     if (commitMsg ==~ /(?s).*\[mgmt-proxy\].*/ || env.GERRIT_EVENT_COMMENT_TEXT ==~ /(?s).*mgmt-proxy.*/) {
@@ -124,6 +129,11 @@
         deployChild = true
         upgradeChild = true
     }
+    if (commitMsg ==~ /(?s).*\[child-upgrade-full\].*/ || env.GERRIT_EVENT_COMMENT_TEXT ==~ /(?s).*child-upgrade-full.*/) {
+        deployChild = true
+        upgradeChild = true
+        fullUpgradeChild = true
+    }
     def childDeployMatches = (commitMsg =~ /(\[child-deploy\s*(\w|\-)+?\])/)
     if (childDeployMatches.size() > 0) {
         // override child version when it set explicitly
@@ -178,6 +188,11 @@
     if (commitMsg ==~ /(?s).*\[lma-logging\].*/ || env.GERRIT_EVENT_COMMENT_TEXT ==~ /(?s).*lma-logging.*/) {
         enableLMALogging = true
     }
+    if (commitMsg ==~ /(?s).*\[deploy-os-on-mos\].*/ || env.GERRIT_EVENT_COMMENT_TEXT ==~ /(?s).*deploy-os-on-mos.*/) {
+        deployOsOnMos = true
+        mosDeployChild = true
+        openstackIMC = 'eu2'
+    }
     if (commitMsg ==~ /(?s).*\[ui-e2e\].*/ || env.GERRIT_EVENT_COMMENT_TEXT ==~ /(?s).*ui-e2e.*/) {
         runUie2e = true
     }
@@ -219,6 +234,12 @@
     if (commitMsg ==~ /(?s).*\[child-delete-master-test\].*/ || env.GERRIT_EVENT_COMMENT_TEXT ==~ /(?s).*child-delete-master-test.*/) {
         runChildDeleteMasterTest = true
     }
+    if (commitMsg ==~ /(?s).*\[graceful-reboot-test\].*/ || env.GERRIT_EVENT_COMMENT_TEXT ==~ /(?s).*graceful-reboot-test.*/) {
+        runGracefulRebootTest = true
+    }
+    if (commitMsg ==~ /(?s).*\[pause-for-debug\].*/ || env.GERRIT_EVENT_COMMENT_TEXT ==~ /(?s).*pause-for-debug.*/) {
+        pauseForDebug = true
+    }
     if (commitMsg ==~ /(?s).*\[child-offline\].*/ || env.GERRIT_EVENT_COMMENT_TEXT ==~ /(?s).*child-offline.*/) {
         proxyConfig['childOffline'] = true
         deployChild = true
@@ -376,6 +397,10 @@
         bootstrapV2Scenario = true
     }
 
+    if (commitMsg ==~ /(?s).*\[enable-fips\].*/ || env.GERRIT_EVENT_COMMENT_TEXT ==~ /(?s).*enable-fips\.*/) {
+        enableFips = true
+    }
+
     // parse equinixmetalv2-metro trigger
     def equinixMetalV2MetroMatcher = (commitMsg =~ /\[equinixmetalv2-metro(\s+.*)?\]/)
     if (equinixMetalV2OnDemandDemo && equinixMetalV2MetroMatcher.size() > 0) {
@@ -391,6 +416,7 @@
         Child cluster deployment scheduled: ${deployChild}
         Custom child cluster release: ${customChildRelease}
         Child cluster release upgrade scheduled: ${upgradeChild}
+        Full Child cluster release upgrade scheduled: ${fullUpgradeChild}
         MOS child deploy scheduled: ${mosDeployChild}
         MOS child upgrade scheduled: ${mosUpgradeChild}
         Child conformance testing scheduled: ${runChildConformance}
@@ -401,6 +427,7 @@
         Mgmt cluster release upgrade scheduled: ${upgradeMgmt}
         Mgmt cluster release auto upgrade scheduled: ${autoUpgradeMgmt}
         Mgmt LMA logging enabled: ${enableLMALogging}
+        Deploy Os on child with mos release ${deployOsOnMos}
         Mgmt conformance testing scheduled: ${runMgmtConformance}
         LMA testing scheduled: ${runLMATest}
         Mgmt user controller testing scheduled: ${runMgmtUserControllerTest}
@@ -409,6 +436,7 @@
         Maintenance test: ${runMaintenanceTest}
         Container Registry test: ${runContainerregistryTest}
         Child proxy test: ${runProxyChildTest}
+        Graceful reboot test: ${runGracefulRebootTest}
         Delete mgmt master node test: ${runMgmtDeleteMasterTest}
         Delete rgnl master node test: ${runRgnlDeleteMasterTest}
         Delete child master node test: ${runChildDeleteMasterTest}
@@ -430,6 +458,8 @@
         Service binaries fetching scheduled: ${fetchServiceBinaries}
         Current weight of the demo run: ${demoWeight} (Used to manage lockable resources)
         Bootstrap v2 scenario enabled: ${bootstrapV2Scenario}
+        FIPS enabled: ${enableFips}
+        Pause for debug enabled: ${pauseForDebug}
         Triggers: https://gerrit.mcp.mirantis.com/plugins/gitiles/kaas/core/+/refs/heads/master/hack/ci-gerrit-keywords.md""")
     return [
         osCloudLocation                      : openstackIMC,
@@ -439,6 +469,7 @@
         deployChildEnabled                   : deployChild,
         childDeployCustomRelease             : customChildRelease,
         upgradeChildEnabled                  : upgradeChild,
+        fullUpgradeChildEnabled              : fullUpgradeChild,
         mosDeployChildEnabled                : mosDeployChild,
         mosUpgradeChildEnabled               : mosUpgradeChild,
         runChildConformanceEnabled           : runChildConformance,
@@ -449,11 +480,14 @@
         upgradeMgmtEnabled                   : upgradeMgmt,
         autoUpgradeMgmtEnabled               : autoUpgradeMgmt,
         enableLMALoggingEnabled              : enableLMALogging,
+        deployOsOnMosEnabled                 : deployOsOnMos,
         runUie2eEnabled                      : runUie2e,
         runUie2eNewEnabled                   : runUie2eNew,
         runMgmtConformanceEnabled            : runMgmtConformance,
         runMaintenanceTestEnabled            : runMaintenanceTest,
         runContainerregistryTestEnabled      : runContainerregistryTest,
+        runGracefulRebootTestEnabled         : runGracefulRebootTest,
+        pauseForDebugEnabled                 : pauseForDebug,
         runMgmtDeleteMasterTestEnabled       : runMgmtDeleteMasterTest,
         runRgnlDeleteMasterTestEnabled       : runRgnlDeleteMasterTest,
         runChildDeleteMasterTestEnabled      : runChildDeleteMasterTest,
@@ -478,7 +512,8 @@
         multiregionalConfiguration           : multiregionalMappings,
         demoWeight                           : demoWeight,
         bootstrapV2Scenario                  : bootstrapV2Scenario,
-        equinixMetalV2Metro                  : equinixMetalV2Metro]
+        equinixMetalV2Metro                  : equinixMetalV2Metro,
+        enableFips                           : enableFips]
 }
 
 /**
@@ -750,10 +785,12 @@
         booleanParam(name: 'UPGRADE_MGMT_CLUSTER', value: triggers.upgradeMgmtEnabled),
         booleanParam(name: 'AUTO_UPGRADE_MCC', value: triggers.autoUpgradeMgmtEnabled),
         booleanParam(name: 'ENABLE_LMA_LOGGING', value: triggers.enableLMALoggingEnabled),
+        booleanParam(name: 'DEPLOY_OS_ON_MOS', value: triggers.deployOsOnMosEnabled),
         booleanParam(name: 'RUN_UI_E2E', value: triggers.runUie2eEnabled),
         booleanParam(name: 'RUN_MGMT_CFM', value: triggers.runMgmtConformanceEnabled),
         booleanParam(name: 'RUN_MAINTENANCE_TEST', value: triggers.runMaintenanceTestEnabled),
         booleanParam(name: 'RUN_CONTAINER_REGISTRY_TEST', value: triggers.runContainerregistryTestEnabled),
+        booleanParam(name: 'RUN_GRACEFUL_REBOOT_TEST', value: triggers.runGracefulRebootTestEnabled),
         booleanParam(name: 'RUN_MGMT_DELETE_MASTER_TEST', value: triggers.runMgmtDeleteMasterTestEnabled),
         booleanParam(name: 'RUN_RGNL_DELETE_MASTER_TEST', value: triggers.runRgnlDeleteMasterTestEnabled),
         booleanParam(name: 'RUN_CHILD_DELETE_MASTER_TEST', value: triggers.runChildDeleteMasterTestEnabled),
@@ -761,6 +798,7 @@
         booleanParam(name: 'RUN_MGMT_USER_CONTROLLER_TEST', value: triggers.runMgmtUserControllerTestEnabled),
         booleanParam(name: 'DEPLOY_CHILD_CLUSTER', value: triggers.deployChildEnabled),
         booleanParam(name: 'UPGRADE_CHILD_CLUSTER', value: triggers.upgradeChildEnabled),
+        booleanParam(name: 'FULL_UPGRADE_CHILD_CLUSTER', value: triggers.fullUpgradeChildEnabled),
         booleanParam(name: 'RUN_PROXY_CHILD_TEST', value: triggers.runProxyChildTestEnabled),
         booleanParam(name: 'ATTACH_BYO', value: triggers.attachBYOEnabled),
         booleanParam(name: 'UPGRADE_BYO', value: triggers.upgradeBYOEnabled),
@@ -774,6 +812,7 @@
         booleanParam(name: 'ALLOW_AZURE_ON_DEMAND', value: triggers.azureOnDemandDemoEnabled),
         booleanParam(name: 'AZURE_ON_AWS_DEMO', value: triggers.azureOnAwsDemoEnabled),
         booleanParam(name: 'VSPHERE_DEPLOY_UBUNTU', value: triggers.vsphereUbuntuEnabled),
+        booleanParam(name: 'PAUSE_FOR_DEBUG', value: triggers.pauseForDebugEnabled),
     ]
 
     // customize multiregional demo
@@ -1113,46 +1152,58 @@
 
 
 /**
-* getEquinixMetrosWithCapacity returns list of Equinix metros using specified
-* instance type (nodeType) and desired count of instances (nodeCount) in a metro.
+* getEquinixFacilityWithCapacity returns list of Equinix facilities using specified
+* instance type (nodeType), desired count of facilities (facilityCount) and
+* instances (nodeCount) in a facility using specified matal version.
 * Function downloads metal CLI from the
-* https://github.com/equinix/metal-cli/releases/download/v0.9.0/metal-linux-amd64
-* Empty list is returned in case of errors.
+* https://artifactory.mcp.mirantis.net:443/artifactory/binary-dev-kaas-local/core/bin/mirror/metal-${version}-linux
+* Empty list is returned in case of no facilities with specified capacity was found or any other errors.
+* Non-empty list is shuffled.
 *
-* @param:        nodeCount (int)      Desired count of instances
-* @param:        nodeType  (string)   Instance type
-* @return                  ([]string) List of selected metros
+* @param:        facilityCount  (int) Desired count of facilities
+* @param:        nodeCount      (int) Desired count of instances
+* @param:        nodeType    (string) Instance type
+* @param:        version     (string) Metal version to use
+* @return                  ([]string) List of selected facilities
 *
 **/
-def getEquinixMetrosWithCapacity(nodeCount = 50, nodeType = 'c3.small.x86', version = '0.9.0') {
+def getEquinixFacilityWithCapacity(facilityCount = 1, nodeCount = 50, nodeType = 'c3.small.x86', version = '0.9.0') {
     def common = new com.mirantis.mk.Common()
     def metalUrl = "https://artifactory.mcp.mirantis.net:443/artifactory/binary-dev-kaas-local/core/bin/mirror/metal-${version}-linux"
-    def metros = []
+    def metal = './metal --config metal.yaml'
+    def facility = []
     def out = ''
     def retries = 3 // number of retries
     def i = 0
     def delay = 60 // 1 minute sleep
-    def metal = './metal --config metal.yaml'
+    def excludeFacility = [] // list of facilities to exclude from selection
     try {
+        if (excludeFacility.size() > 0) {
+            common.infoMsg("Excluded facilities: ${excludeFacility}")
+        }
         sh "curl -o metal -# ${metalUrl} && chmod +x metal"
         withCredentials([string(credentialsId: env.KAAS_EQUINIX_API_TOKEN, variable: 'KAAS_EQUINIX_API_TOKEN')]) {
             sh 'echo "project-id: ${KAAS_EQUINIX_PROJECT_ID}\ntoken: ${KAAS_EQUINIX_API_TOKEN}" >metal.yaml'
         }
-        while (metros.size() == 0 && i < retries) {
-            common.infoMsg("Selecting available Equinix metro with free ${nodeCount} ${nodeType} hosts, try ${i+1}/${retries} ...")
+        while (facility.size() < facilityCount && i < retries) {
+            common.infoMsg("Selecting ${facilityCount} available Equinix facilities with free ${nodeCount} ${nodeType} hosts, try ${i+1}/${retries} ...")
             if (i > 0 ) { // skip sleep on first step
                 sleep(delay)
             }
-            out = sh(script: "${metal} capacity get -m -P ${nodeType}|awk '/${nodeType}/ {print \$2}'|paste -s -d,|xargs ${metal} capacity check -P ${nodeType} -q ${nodeCount} -m|grep true|awk '{print \$2}'|paste -s -d,", returnStdout: true).trim()
-            metros = out.tokenize(',')
-            if (metros.size() == 0) {
+            out = sh(script: "${metal} capacity get -f -P ${nodeType}|awk '/${nodeType}/ {print \$2}'|paste -s -d,|xargs ${metal} capacity check -P ${nodeType} -q ${nodeCount} -f|grep true|awk '{print \$2}'|paste -s -d,", returnStdout: true).trim()
+            facility = out.tokenize(',')
+            facility -= excludeFacility
+            if (facility.size() < facilityCount) {
+                nodeCount -= 10
+            // We need different metros for the [equinixmetalv2-child-diff-metro] case, facility[][0, 1] contains a metro name
+            } else if (facility.size() == 2 && facility[0][0, 1] == facility[1][0, 1]) {
                 nodeCount -= 10
             }
             i++
         }
-        if (metros.size() > 0) {
-            m = metros.size() > 1 ? "${metros[0]},${metros[1]}" : "${metros[0]}"
-            sh "${metal} capacity check -P ${nodeType} -m ${m} -q ${nodeCount}"
+        if (facility.size() > 0) {
+            f = facility.size() > 1 ? "${facility[0]},${facility[1]}" : "${facility[0]}"
+            sh "${metal} capacity check -P ${nodeType} -f ${f} -q ${nodeCount}"
         }
     } catch (Exception e) {
         common.errorMsg "Exception: '${e}'"
@@ -1160,12 +1211,13 @@
     } finally {
         sh 'rm metal.yaml'
     }
-    if (metros.size() > 0) {
-        common.infoMsg("Selected metros: ${metros}")
+    if (facility.size() > 0) {
+        Collections.shuffle(facility)
+        common.infoMsg("Selected facilities: ${facility}")
     } else {
-        common.warningMsg('No any metros have been selected !!! :(')
+        common.warningMsg('No any facilities have been selected !!! :(')
     }
-    return metros
+    return facility
 }