Merge "Install openscap if enabled"
diff --git a/src/com/mirantis/mk/Debian.groovy b/src/com/mirantis/mk/Debian.groovy
index 4d7b1ee..d6c82db 100644
--- a/src/com/mirantis/mk/Debian.groovy
+++ b/src/com/mirantis/mk/Debian.groovy
@@ -251,3 +251,89 @@
         sh("export GNUPGHOME=${workspace}/.gnupg; dput -f \"ppa:${ppaRepo}\" *_source.changes")
     }
 }
+
+/**
+* Upgrade packages on given target.
+*
+* @param env    Salt Connection object or env  Salt command map
+* @param target Salt target to upgrade packages on.
+*/
+def osUpgrade(env, target){
+  def common = new com.mirantis.mk.Common()
+  def salt = new com.mirantis.mk.Salt()
+
+  common.infoMsg("Running upgrade on ${target}")
+
+  salt.runSaltProcessStep(env, target, 'pkg.refresh_db', [], null, true)
+  def cmd = 'export DEBIAN_FRONTEND=noninteractive; apt-get -y -q --allow-downgrades -o Dpkg::Options::=\"--force-confdef\" -o Dpkg::Options::=\"--force-confold\" upgrade;'
+  salt.runSaltProcessStep(env, target, 'cmd.run', [cmd])
+}
+
+/**
+* Running dist-upgrade on given target.
+*
+* @param env    Salt Connection object or env  Salt command map
+* @param target Salt target to upgrade packages on.
+*/
+def osDistUpgrade(env, target){
+  def salt = new com.mirantis.mk.Salt()
+  def common = new com.mirantis.mk.Common()
+
+  common.infoMsg("Running dist-upgrade on ${target}")
+  salt.runSaltProcessStep(env, target, 'pkg.refresh_db', [], null, true)
+  def cmd = 'export DEBIAN_FRONTEND=noninteractive; apt-get -y -q --allow-downgrades -o Dpkg::Options::=\"--force-confdef\" -o Dpkg::Options::=\"--force-confold\" dist-upgrade;'
+  salt.runSaltProcessStep(env, target, 'cmd.run', [cmd])
+}
+
+/**
+* Reboot specified target, and wait when minion is UP.
+*
+* @param env       Salt Connection object or env  Salt command map
+* @param target    Salt target to upgrade packages on.
+* @param timeout   Sleep timeout when doing retries.
+* @param attempts  Number of attemps to wait for.
+*/
+def osReboot(env, target, timeout=30, attempts=10){
+  def salt = new com.mirantis.mk.Salt()
+  def common = new com.mirantis.mk.Common()
+
+  salt.runSaltProcessStep(env, target, 'cmd.run', ["touch /tmp/rebooting"])
+  salt.runSaltProcessStep(env, target, 'system.reboot', [], null, true, 5)
+
+  common.retry(timeout, attempts){
+    if (salt.runSaltProcessStep(env, target, 'file.file_exists', ['/tmp/rebooting'], null, true, 5)['return'][0].values()[0].toBoolean()){
+      error("The system is still rebooting...")
+    }
+  }
+}
+
+/**
+* Upgrade OS on given node, wait when minion become reachable.
+*
+* @param env             Salt Connection object or env  Salt command map
+* @param target          Salt target to upgrade packages on.
+* @param mode            'upgrade' or 'dist-upgrade'
+* @param postponeReboot  Boolean flag to specify if reboot have to be postponed.
+* @param timeout   Sleep timeout when doing retries.
+* @param attempts  Number of attemps to wait for.
+*/
+def osUpgradeNode(env, target, mode, postponeReboot=false, timeout=30, attempts=10){
+    def common = new com.mirantis.mk.Common()
+    def salt = new com.mirantis.mk.Salt()
+
+    def rebootRequired = false
+    if (mode == 'dist-upgrade'){
+      osDistUpgrade(env, target)
+    } else if (mode == 'upgrade'){
+      osUpgrade(env, target)
+    }
+    rebootRequired = salt.runSaltProcessStep(env, target, 'file.file_exists', ['/var/run/reboot-required'], null, true, 5)['return'][0].values()[0].toBoolean()
+    if (rebootRequired) {
+      if (!postponeReboot){
+        common.infoMsg("Reboot is required after upgrade on ${target} Rebooting...")
+        osReboot(env, target, timeout, attempts)
+      } else {
+        common.infoMsg("Postponing reboot on node ${target}")
+      }
+    }
+}
diff --git a/src/com/mirantis/mk/Openstack.groovy b/src/com/mirantis/mk/Openstack.groovy
index f4a42ae..fa60053 100644
--- a/src/com/mirantis/mk/Openstack.groovy
+++ b/src/com/mirantis/mk/Openstack.groovy
@@ -454,6 +454,79 @@
 }
 
 /**
+ * Return intersection of globally installed services and those are
+ * defined on specific target according to theirs priorities.
+ *
+ * @param env     Salt Connection object or env
+ * @param target  The target node to get list of apps for.
+**/
+def getOpenStackUpgradeServices(env, target){
+    def salt = new com.mirantis.mk.Salt()
+    def common = new com.mirantis.mk.Common()
+
+    def global_apps = salt.getConfig(env, 'I@salt:master:enabled:true', 'orchestration.upgrade.applications')
+    def node_apps = salt.getPillar(env, target, '__reclass__:applications')['return'][0].values()[0]
+    def node_sorted_apps = []
+    if ( !global_apps['return'][0].values()[0].isEmpty() ) {
+        Map<String,Integer> _sorted_apps = [:]
+        for (k in global_apps['return'][0].values()[0].keySet()) {
+            if (k in node_apps) {
+              _sorted_apps[k] = global_apps['return'][0].values()[0][k].values()[0].toInteger()
+            }
+        }
+        node_sorted_apps = common.SortMapByValueAsc(_sorted_apps).keySet()
+        common.infoMsg("Applications are placed in following order:"+node_sorted_apps)
+    } else {
+        common.errorMsg("No applications found.")
+    }
+
+  return node_sorted_apps
+}
+
+
+/**
+ * Run specified upgrade phase for all services on given node.
+ *
+ * @param env     Salt Connection object or env
+ * @param target  The target node to run states on.
+ * @param phase   The phase name to run.
+**/
+def runOpenStackUpgradePhase(env, target, phase){
+    def salt = new com.mirantis.mk.Salt()
+    def common = new com.mirantis.mk.Common()
+
+    services = getOpenStackUpgradeServices(env, target)
+    def st
+
+    for (service in services){
+        st = "${service}.upgrade.${phase}".trim()
+        common.infoMsg("Running ${phase} for service ${st} on ${target}")
+        salt.enforceState(env, target, st)
+    }
+}
+
+
+/**
+ * Run OpenStack states on specified node.
+ *
+ * @param env     Salt Connection object or env
+ * @param target  The target node to run states on.
+**/
+def applyOpenstackAppsStates(env, target){
+    def salt = new com.mirantis.mk.Salt()
+    def common = new com.mirantis.mk.Common()
+
+    services = getOpenStackUpgradeServices(env, target)
+    def st
+
+    for (service in services){
+        st = "${service}".trim()
+        common.infoMsg("Running ${st} on ${target}")
+        salt.enforceState(env, target, st)
+    }
+}
+
+/**
  * Restores Galera database
  * @param env Salt Connection object or pepperEnv
  * @return output of salt commands