You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by jo...@apache.org on 2014/12/30 01:48:22 UTC

ambari git commit: AMBARI-8909 - Alert Summary Counts Should Honor Maintenance States (jonathanhurley)

Repository: ambari
Updated Branches:
  refs/heads/trunk 9401a4937 -> dc8355c64


AMBARI-8909 - Alert Summary Counts Should Honor Maintenance States (jonathanhurley)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/dc8355c6
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/dc8355c6
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/dc8355c6

Branch: refs/heads/trunk
Commit: dc8355c64bd0469b1a836b87b70351f4d415701c
Parents: 9401a49
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Wed Dec 24 14:17:53 2014 -0500
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Mon Dec 29 19:48:15 2014 -0500

----------------------------------------------------------------------
 .../internal/AlertSummaryPropertyProvider.java  |  16 +--
 .../alerts/AlertAggregateListener.java          |   4 +-
 .../alerts/AlertMaintenanceModeListener.java    |  23 +++++
 .../server/orm/dao/AlertHostSummaryDTO.java     |   6 ++
 .../ambari/server/orm/dao/AlertSummaryDTO.java  |  29 ++++--
 .../apache/ambari/server/orm/dao/AlertsDAO.java |  81 ++++++++-------
 .../server/orm/entities/AlertCurrentEntity.java |   2 +-
 .../server/upgrade/UpgradeCatalog200.java       |   5 +
 .../main/resources/Ambari-DDL-MySQL-CREATE.sql  |   2 +-
 .../main/resources/Ambari-DDL-Oracle-CREATE.sql |   2 +-
 .../resources/Ambari-DDL-Postgres-CREATE.sql    |   2 +-
 .../Ambari-DDL-Postgres-EMBEDDED-CREATE.sql     |   2 +-
 .../resources/Ambari-DDL-SQLServer-CREATE.sql   |   2 +-
 .../ambari/server/orm/dao/AlertsDAOTest.java    | 100 ++++++++++++++-----
 14 files changed, 191 insertions(+), 85 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/dc8355c6/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertSummaryPropertyProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertSummaryPropertyProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertSummaryPropertyProvider.java
index d0cbf79..2e8cf83 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertSummaryPropertyProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertSummaryPropertyProvider.java
@@ -122,12 +122,12 @@ public class AlertSummaryPropertyProvider extends BaseProvider implements Proper
       case Cluster:
         long clusterId = cluster.getClusterId();
 
-        // only make the calculation of asked
+        // only make the calculation if asked
         if (BaseProvider.isPropertyRequested(ALERTS_SUMMARY, requestedIds)) {
           summary = s_dao.findCurrentCounts(cluster.getClusterId(), null, null);
         }
 
-        // only make the calculation of asked
+        // only make the calculation if asked
         if (BaseProvider.isPropertyRequested(ALERTS_SUMMARY_HOSTS,
             requestedIds)) {
           hostSummary = s_dao.findCurrentHostCounts(clusterId);
@@ -146,12 +146,12 @@ public class AlertSummaryPropertyProvider extends BaseProvider implements Proper
 
     // all alerts in the cluster, in summary count form
     if (null != summary) {
-      Map<AlertState, Integer> map = new HashMap<AlertState, Integer>();
-      map.put(AlertState.OK, Integer.valueOf(summary.getOkCount()));
-      map.put(AlertState.WARNING, Integer.valueOf(summary.getWarningCount()));
-      map.put(AlertState.CRITICAL, Integer.valueOf(summary.getCriticalCount()));
-      map.put(AlertState.UNKNOWN, Integer.valueOf(summary.getUnknownCount()));
-
+      Map<String, Integer> map = new HashMap<String, Integer>();
+      map.put(AlertState.OK.name(), Integer.valueOf(summary.getOkCount()));
+      map.put(AlertState.WARNING.name(), Integer.valueOf(summary.getWarningCount()));
+      map.put(AlertState.CRITICAL.name(), Integer.valueOf(summary.getCriticalCount()));
+      map.put(AlertState.UNKNOWN.name(), Integer.valueOf(summary.getUnknownCount()));
+      map.put("MAINTENANCE", Integer.valueOf(summary.getMaintenanceCount()));
       setResourceProperty(resource, ALERTS_SUMMARY, map, requestedIds);
     }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/dc8355c6/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertAggregateListener.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertAggregateListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertAggregateListener.java
index 47fc4e3..02bbba9 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertAggregateListener.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertAggregateListener.java
@@ -83,7 +83,9 @@ public class AlertAggregateListener {
     AlertSummaryDTO summary = m_alertsDao.findAggregateCounts(
         event.getClusterId(), aggregateSource.getAlertName());
 
-    int okCount = summary.getOkCount();
+    // OK should be based off of true OKs and those in maintenance mode
+    int okCount = summary.getOkCount() + summary.getMaintenanceCount();
+
     int warningCount = summary.getWarningCount();
     int criticalCount = summary.getCriticalCount();
     int unknownCount = summary.getUnknownCount();

http://git-wip-us.apache.org/repos/asf/ambari/blob/dc8355c6/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertMaintenanceModeListener.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertMaintenanceModeListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertMaintenanceModeListener.java
index cbd99a5..c54baa2 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertMaintenanceModeListener.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertMaintenanceModeListener.java
@@ -22,6 +22,8 @@ import java.util.List;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.EagerSingleton;
 import org.apache.ambari.server.controller.MaintenanceStateHelper;
+import org.apache.ambari.server.controller.RootServiceResponseFactory.Components;
+import org.apache.ambari.server.controller.RootServiceResponseFactory.Services;
 import org.apache.ambari.server.events.MaintenanceModeEvent;
 import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 import org.apache.ambari.server.orm.dao.AlertsDAO;
@@ -108,6 +110,27 @@ public class AlertMaintenanceModeListener {
       String componentName = history.getComponentName();
 
       try {
+        // although AMBARI is a service, it's not really a service and would
+        // fail in this loop; so handle it specifically
+        if (Services.AMBARI.name().equals(serviceName)
+            && Components.AMBARI_AGENT.name().equals(componentName)) {
+
+          // if this alert is an AMBARI_AGENT alert, then the only maintenance
+          // state that affects it is a host maintenance state
+          if (null == event.getHost()) {
+            continue;
+          }
+
+          MaintenanceState maintenanceState = MaintenanceState.OFF;
+          if (event.getMaintenanceState() != MaintenanceState.OFF) {
+            maintenanceState = MaintenanceState.ON;
+          }
+
+          currentAlert.setMaintenanceState(maintenanceState);
+          m_alertsDao.merge(currentAlert);
+          continue;
+        }
+
         Cluster cluster = m_clusters.get().getClusterById(clusterId);
         if (null == cluster) {
           LOG.warn("Unable to find cluster with ID {}", clusterId);

http://git-wip-us.apache.org/repos/asf/ambari/blob/dc8355c6/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertHostSummaryDTO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertHostSummaryDTO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertHostSummaryDTO.java
index 94a8267..c73948d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertHostSummaryDTO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertHostSummaryDTO.java
@@ -17,6 +17,8 @@
  */
 package org.apache.ambari.server.orm.dao;
 
+import org.apache.ambari.server.state.AlertState;
+
 
 /**
  * The {@link AlertHostSummaryDTO} is used to return a summary of the alerts
@@ -25,6 +27,10 @@ package org.apache.ambari.server.orm.dao;
  * <p/>
  * The sum of all of the values of this DTO should equal the total number of
  * hosts.
+ * <p/>
+ * If a host or a host's components are in maintenance mode, then any alerts
+ * triggered will not be reported here. Instead, they will be counted as
+ * {@link AlertState#OK}.
  */
 public class AlertHostSummaryDTO {
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/dc8355c6/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertSummaryDTO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertSummaryDTO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertSummaryDTO.java
index 80fa4e8..f56875f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertSummaryDTO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertSummaryDTO.java
@@ -20,7 +20,8 @@ package org.apache.ambari.server.orm.dao;
 import org.apache.ambari.server.state.AlertState;
 
 /**
- * Used to return alert summary data out of the database.
+ * Used to return alert summary data out of the database. Alerts that are in
+ * maintenance mode will be reported as such instead of their actual values.
  */
 public class AlertSummaryDTO {
 
@@ -28,43 +29,53 @@ public class AlertSummaryDTO {
   private int warningCount;
   private int criticalCount;
   private int unknownCount;
-  
+  private int maintenanceCount;
+
   /**
    * Constructor, used by JPA.  JPA invokes this constructor, even if there
    * are no records in the resultset.  In that case, all arguments are {@code null}.
    */
-  public AlertSummaryDTO(Number ok, Number warning, Number critical, Number unknown) {
+  public AlertSummaryDTO(Number ok, Number warning, Number critical,
+      Number unknown, Number maintenance) {
     okCount = null == ok ? 0 : ok.intValue();
     warningCount = null == warning ? 0 : warning.intValue();
     criticalCount = null == critical ? 0 : critical.intValue();
     unknownCount = null == unknown ? 0 : unknown.intValue();
+    maintenanceCount = null == maintenance ? 0 : maintenance.intValue();
   }
-  
+
   /**
    * @return the count of {@link AlertState#OK} states
    */
   public int getOkCount() {
     return okCount;
   }
-  
+
   /**
    * @return the count of {@link AlertState#WARNING} states
    */
   public int getWarningCount() {
     return warningCount;
-  }  
-  
+  }
+
   /**
    * @return the count of {@link AlertState#CRITICAL} states
    */
   public int getCriticalCount() {
     return criticalCount;
   }
-  
+
   /**
    * @return the count of {@link AlertState#UNKNOWN} states
    */
   public int getUnknownCount() {
     return unknownCount;
-  }  
+  }
+
+  /**
+   * @return the count of alerts that are in the maintenance state.
+   */
+  public int getMaintenanceCount() {
+    return maintenanceCount;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/dc8355c6/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertsDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertsDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertsDAO.java
index 016dfe5..34216e7 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertsDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertsDAO.java
@@ -38,6 +38,7 @@ import org.apache.ambari.server.orm.entities.AlertCurrentEntity;
 import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
 import org.apache.ambari.server.orm.entities.AlertHistoryEntity_;
 import org.apache.ambari.server.state.AlertState;
+import org.apache.ambari.server.state.MaintenanceState;
 import org.apache.ambari.server.state.alert.Scope;
 import org.eclipse.persistence.config.HintValues;
 import org.eclipse.persistence.config.QueryHints;
@@ -55,6 +56,25 @@ import com.google.inject.persist.Transactional;
 @Singleton
 public class AlertsDAO {
   /**
+   * A template of JPQL for getting the number of hosts in various states.
+   */
+  private static final String HOST_COUNT_SQL_TEMPLATE = "SELECT MAX("
+      + "CASE "
+      + "  WHEN history.alertState = :criticalState AND alert.maintenanceState = :maintenanceStateOff THEN 3 "
+      + "  WHEN history.alertState = :warningState AND alert.maintenanceState = :maintenanceStateOff THEN 2 "
+      + "  WHEN history.alertState = :unknownState AND alert.maintenanceState = :maintenanceStateOff THEN 1 ELSE 0 END) "
+      + "FROM AlertCurrentEntity alert JOIN alert.alertHistory history "
+      + "WHERE history.clusterId = :clusterId AND history.hostName IS NOT NULL GROUP BY history.hostName";
+
+  private static final String ALERT_COUNT_SQL_TEMPLATE = "SELECT NEW %s("
+      + "SUM(CASE WHEN history.alertState = :okState AND alert.maintenanceState = :maintenanceStateOff THEN 1 ELSE 0 END), "
+      + "SUM(CASE WHEN history.alertState = :warningState AND alert.maintenanceState = :maintenanceStateOff THEN 1 ELSE 0 END), "
+      + "SUM(CASE WHEN history.alertState = :criticalState AND alert.maintenanceState = :maintenanceStateOff THEN 1 ELSE 0 END), "
+      + "SUM(CASE WHEN history.alertState = :unknownState AND alert.maintenanceState = :maintenanceStateOff THEN 1 ELSE 0 END), "
+      + "SUM(CASE WHEN alert.maintenanceState != :maintenanceStateOff THEN 1 ELSE 0 END)) "
+      + "FROM AlertCurrentEntity alert JOIN alert.alertHistory history WHERE history.clusterId = :clusterId";
+
+  /**
    * JPA entity manager
    */
   @Inject
@@ -300,13 +320,10 @@ public class AlertsDAO {
    */
   @RequiresSession
   public AlertSummaryDTO findCurrentCounts(long clusterId, String serviceName, String hostName) {
-    StringBuilder sb = new StringBuilder();
-    sb.append("SELECT NEW %s (");
-    sb.append("SUM(CASE WHEN history.alertState = %s.%s THEN 1 ELSE 0 END), ");
-    sb.append("SUM(CASE WHEN history.alertState = %s.%s THEN 1 ELSE 0 END), ");
-    sb.append("SUM(CASE WHEN history.alertState = %s.%s THEN 1 ELSE 0 END), ");
-    sb.append("SUM(CASE WHEN history.alertState = %s.%s THEN 1 ELSE 0 END)) ");
-    sb.append("FROM AlertCurrentEntity alert JOIN alert.alertHistory history WHERE history.clusterId = :clusterId");
+    String sql = String.format(ALERT_COUNT_SQL_TEMPLATE,
+        AlertSummaryDTO.class.getName());
+
+    StringBuilder sb = new StringBuilder(sql);
 
     if (null != serviceName) {
       sb.append(" AND history.serviceName = :serviceName");
@@ -316,17 +333,15 @@ public class AlertsDAO {
       sb.append(" AND history.hostName = :hostName");
     }
 
-    String str = String.format(sb.toString(),
-        AlertSummaryDTO.class.getName(),
-        AlertState.class.getName(), AlertState.OK.name(),
-        AlertState.class.getName(), AlertState.WARNING.name(),
-        AlertState.class.getName(), AlertState.CRITICAL.name(),
-        AlertState.class.getName(), AlertState.UNKNOWN.name());
-
     TypedQuery<AlertSummaryDTO> query = entityManagerProvider.get().createQuery(
-        str, AlertSummaryDTO.class);
+        sb.toString(), AlertSummaryDTO.class);
 
     query.setParameter("clusterId", Long.valueOf(clusterId));
+    query.setParameter("okState", AlertState.OK);
+    query.setParameter("warningState", AlertState.WARNING);
+    query.setParameter("criticalState", AlertState.CRITICAL);
+    query.setParameter("unknownState", AlertState.UNKNOWN);
+    query.setParameter("maintenanceStateOff", MaintenanceState.OFF);
 
     if (null != serviceName) {
       query.setParameter("serviceName", serviceName);
@@ -351,20 +366,16 @@ public class AlertsDAO {
    */
   @RequiresSession
   public AlertHostSummaryDTO findCurrentHostCounts(long clusterId) {
-    StringBuilder sb = new StringBuilder();
-    sb.append("SELECT MAX(CASE WHEN history.alertState = :criticalState THEN 3 WHEN history.alertState = :warningState THEN 2 WHEN history.alertState = :unknownState THEN 1 ELSE 0 END) ");
-    sb.append("FROM AlertCurrentEntity alert JOIN alert.alertHistory history ");
-    sb.append("WHERE history.clusterId = :clusterId AND history.hostName IS NOT NULL GROUP BY history.hostName");
-
     // use Number here since some databases like MySQL return Long and some
     // return Integer and we don't want a class cast exception
     TypedQuery<Number> query = entityManagerProvider.get().createQuery(
-        sb.toString(), Number.class);
+        HOST_COUNT_SQL_TEMPLATE, Number.class);
 
     query.setParameter("clusterId", Long.valueOf(clusterId));
     query.setParameter("criticalState", AlertState.CRITICAL);
     query.setParameter("warningState", AlertState.WARNING);
     query.setParameter("unknownState", AlertState.UNKNOWN);
+    query.setParameter("maintenanceStateOff", MaintenanceState.OFF);
 
     int okCount = 0;
     int warningCount = 0;
@@ -678,26 +689,21 @@ public class AlertsDAO {
    */
   @RequiresSession
   public AlertSummaryDTO findAggregateCounts(long clusterId, String alertName) {
-    StringBuilder sb = new StringBuilder();
-    sb.append("SELECT NEW %s (");
-    sb.append("SUM(CASE WHEN history.alertState = %s.%s THEN 1 ELSE 0 END), ");
-    sb.append("SUM(CASE WHEN history.alertState = %s.%s THEN 1 ELSE 0 END), ");
-    sb.append("SUM(CASE WHEN history.alertState = %s.%s THEN 1 ELSE 0 END), ");
-    sb.append("SUM(CASE WHEN history.alertState = %s.%s THEN 1 ELSE 0 END)) ");
-    sb.append("FROM AlertCurrentEntity alert JOIN alert.alertHistory history WHERE history.clusterId = :clusterId");
-    sb.append(" AND history.alertDefinition.definitionName = :definitionName");
-
-    String str = String.format(sb.toString(),
-        AlertSummaryDTO.class.getName(),
-        AlertState.class.getName(), AlertState.OK.name(),
-        AlertState.class.getName(), AlertState.WARNING.name(),
-        AlertState.class.getName(), AlertState.CRITICAL.name(),
-        AlertState.class.getName(), AlertState.UNKNOWN.name());
+    String sql = String.format(ALERT_COUNT_SQL_TEMPLATE,
+        AlertSummaryDTO.class.getName());
+
+    StringBuilder buffer = new StringBuilder(sql);
+    buffer.append(" AND history.alertDefinition.definitionName = :definitionName");
 
     TypedQuery<AlertSummaryDTO> query = entityManagerProvider.get().createQuery(
-        str, AlertSummaryDTO.class);
+        buffer.toString(), AlertSummaryDTO.class);
 
     query.setParameter("clusterId", Long.valueOf(clusterId));
+    query.setParameter("okState", AlertState.OK);
+    query.setParameter("warningState", AlertState.WARNING);
+    query.setParameter("criticalState", AlertState.CRITICAL);
+    query.setParameter("unknownState", AlertState.UNKNOWN);
+    query.setParameter("maintenanceStateOff", MaintenanceState.OFF);
     query.setParameter("definitionName", alertName);
 
     return daoUtils.selectSingle(query);
@@ -713,7 +719,6 @@ public class AlertsDAO {
    */
   @RequiresSession
   public AlertCurrentEntity findCurrentByNameNoHost(long clusterId, String alertName) {
-
     TypedQuery<AlertCurrentEntity> query = entityManagerProvider.get().createNamedQuery(
         "AlertCurrentEntity.findByNameAndNoHost", AlertCurrentEntity.class);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/dc8355c6/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertCurrentEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertCurrentEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertCurrentEntity.java
index 08c7fb3..51aa688 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertCurrentEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertCurrentEntity.java
@@ -70,7 +70,7 @@ public class AlertCurrentEntity {
 
   @Column(name = "maintenance_state", length = 255)
   @Enumerated(value = EnumType.STRING)
-  private MaintenanceState maintenanceState;
+  private MaintenanceState maintenanceState = MaintenanceState.OFF;
 
   @Column(name = "original_timestamp", nullable = false)
   private Long originalTimestamp;

http://git-wip-us.apache.org/repos/asf/ambari/blob/dc8355c6/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog200.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog200.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog200.java
index 06fe380..e18331f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog200.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog200.java
@@ -57,6 +57,7 @@ public class UpgradeCatalog200 extends AbstractUpgradeCatalog {
   private static final String ALERT_DEFINITION_TABLE = "alert_definition";
   private static final String ALERT_TARGET_TABLE = "alert_target";
   private static final String ALERT_TARGET_STATES_TABLE = "alert_target_states";
+  private static final String ALERT_CURRENT_TABLE = "alert_current";
 
   /**
    * {@inheritDoc}
@@ -149,6 +150,10 @@ public class UpgradeCatalog200 extends AbstractUpgradeCatalog {
     dbAccessor.addFKConstraint(ALERT_TARGET_STATES_TABLE,
         "fk_alert_target_states_target_id", "target_id", ALERT_TARGET_TABLE,
         "target_id", false);
+
+    // update alert current maintenance mode
+    dbAccessor.alterColumn(ALERT_CURRENT_TABLE, new DBColumnInfo(
+        "maintenance_state", String.class, 255, null, false));
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/dc8355c6/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
index d266b06..9047b15 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
@@ -632,7 +632,7 @@ CREATE TABLE alert_current (
   alert_id BIGINT NOT NULL,
   definition_id BIGINT NOT NULL,
   history_id BIGINT NOT NULL UNIQUE,
-  maintenance_state VARCHAR(255),
+  maintenance_state VARCHAR(255) NOT NULL,
   original_timestamp BIGINT NOT NULL,
   latest_timestamp BIGINT NOT NULL,
   latest_text TEXT,

http://git-wip-us.apache.org/repos/asf/ambari/blob/dc8355c6/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
index e98a165..4b915aa 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
@@ -622,7 +622,7 @@ CREATE TABLE alert_current (
   alert_id NUMBER(19) NOT NULL,
   definition_id NUMBER(19) NOT NULL,
   history_id NUMBER(19) NOT NULL UNIQUE,
-  maintenance_state VARCHAR2(255),
+  maintenance_state VARCHAR2(255) NOT NULL,
   original_timestamp NUMBER(19) NOT NULL,
   latest_timestamp NUMBER(19) NOT NULL,
   latest_text VARCHAR2(4000),

http://git-wip-us.apache.org/repos/asf/ambari/blob/dc8355c6/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
index 248d86c..0e7b9c6 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
@@ -619,7 +619,7 @@ CREATE TABLE alert_current (
   alert_id BIGINT NOT NULL,
   definition_id BIGINT NOT NULL,
   history_id BIGINT NOT NULL UNIQUE,
-  maintenance_state VARCHAR(255),
+  maintenance_state VARCHAR(255) NOT NULL,
   original_timestamp BIGINT NOT NULL,
   latest_timestamp BIGINT NOT NULL,
   latest_text TEXT,

http://git-wip-us.apache.org/repos/asf/ambari/blob/dc8355c6/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
index 57a960c..0159a11 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
@@ -692,7 +692,7 @@ CREATE TABLE ambari.alert_current (
   alert_id BIGINT NOT NULL,
   definition_id BIGINT NOT NULL,
   history_id BIGINT NOT NULL UNIQUE,
-  maintenance_state VARCHAR(255),
+  maintenance_state VARCHAR(255) NOT NULL,
   original_timestamp BIGINT NOT NULL,
   latest_timestamp BIGINT NOT NULL,
   latest_text TEXT,

http://git-wip-us.apache.org/repos/asf/ambari/blob/dc8355c6/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
index 3cf548d..50085f2 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
@@ -204,7 +204,7 @@ CREATE TABLE alert_current (
   alert_id BIGINT NOT NULL,
   definition_id BIGINT NOT NULL,
   history_id BIGINT NOT NULL UNIQUE,
-  maintenance_state VARCHAR(255),
+  maintenance_state VARCHAR(255) NOT NULL,
   original_timestamp BIGINT NOT NULL,
   latest_timestamp BIGINT NOT NULL,
   latest_text TEXT,

http://git-wip-us.apache.org/repos/asf/ambari/blob/dc8355c6/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertsDAOTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertsDAOTest.java b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertsDAOTest.java
index f831d14..789fa90 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertsDAOTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertsDAOTest.java
@@ -416,9 +416,16 @@ public class AlertsDAOTest {
     int warn = 0;
     int crit = 0;
     int unk = 0;
+    int maintenance = 0;
 
-    for (AlertCurrentEntity h : m_dao.findCurrentByCluster(m_cluster.getClusterId())) {
-      switch (h.getAlertHistory().getAlertState()) {
+    List<AlertCurrentEntity> currents = m_dao.findCurrentByCluster(m_cluster.getClusterId());
+    for (AlertCurrentEntity current : currents) {
+      if (current.getMaintenanceState() != MaintenanceState.OFF) {
+        maintenance++;
+        continue;
+      }
+
+      switch (current.getAlertHistory().getAlertState()) {
         case CRITICAL:
           crit++;
           break;
@@ -432,39 +439,58 @@ public class AlertsDAOTest {
           warn++;
           break;
       }
-
     }
 
     summary = m_dao.findCurrentCounts(m_cluster.getClusterId(), null, null);
+
     // !!! db-to-db compare
     assertEquals(ok, summary.getOkCount());
     assertEquals(warn, summary.getWarningCount());
     assertEquals(crit, summary.getCriticalCount());
-    assertEquals(unk, summary.getCriticalCount());
+    assertEquals(unk, summary.getUnknownCount());
+    assertEquals(maintenance, summary.getMaintenanceCount());
 
     // !!! expected
     assertEquals(2, summary.getOkCount());
     assertEquals(1, summary.getWarningCount());
     assertEquals(1, summary.getCriticalCount());
-    assertEquals(1, summary.getCriticalCount());
+    assertEquals(1, summary.getUnknownCount());
+    assertEquals(0, summary.getMaintenanceCount());
 
     summary = m_dao.findCurrentCounts(m_cluster.getClusterId(), "YARN", null);
     assertEquals(2, summary.getOkCount());
     assertEquals(1, summary.getWarningCount());
     assertEquals(1, summary.getCriticalCount());
-    assertEquals(1, summary.getCriticalCount());
+    assertEquals(1, summary.getUnknownCount());
 
     summary = m_dao.findCurrentCounts(m_cluster.getClusterId(), null, "h1");
     assertEquals(2, summary.getOkCount());
     assertEquals(1, summary.getWarningCount());
     assertEquals(1, summary.getCriticalCount());
-    assertEquals(1, summary.getCriticalCount());
+    assertEquals(1, summary.getUnknownCount());
+    assertEquals(0, summary.getMaintenanceCount());
 
     summary = m_dao.findCurrentCounts(m_cluster.getClusterId(), "foo", null);
     assertEquals(0, summary.getOkCount());
     assertEquals(0, summary.getWarningCount());
     assertEquals(0, summary.getCriticalCount());
-    assertEquals(0, summary.getCriticalCount());
+    assertEquals(0, summary.getUnknownCount());
+    assertEquals(0, summary.getMaintenanceCount());
+
+    // try out maintenance mode for all WARNINGs
+    for (AlertCurrentEntity current : currents) {
+      if (current.getAlertHistory().getAlertState() == AlertState.WARNING) {
+        current.setMaintenanceState(MaintenanceState.ON);
+        m_dao.merge(current);
+      }
+    }
+
+    summary = m_dao.findCurrentCounts(m_cluster.getClusterId(), null, null);
+    assertEquals(2, summary.getOkCount());
+    assertEquals(0, summary.getWarningCount());
+    assertEquals(1, summary.getCriticalCount());
+    assertEquals(1, summary.getUnknownCount());
+    assertEquals(1, summary.getMaintenanceCount());
   }
 
   /**
@@ -480,11 +506,11 @@ public class AlertsDAOTest {
     assertEquals(1, summary.getOkCount());
 
     // grab 1 and change it to warning
-    AlertHistoryEntity h1 = m_dao.findCurrentByCluster(m_cluster.getClusterId()).get(
+    AlertHistoryEntity history1 = m_dao.findCurrentByCluster(m_cluster.getClusterId()).get(
         1).getAlertHistory();
 
-    h1.setAlertState(AlertState.WARNING);
-    m_dao.merge(h1);
+    history1.setAlertState(AlertState.WARNING);
+    m_dao.merge(history1);
 
     // verify host changed to warning
     summary = m_dao.findCurrentHostCounts(m_cluster.getClusterId());
@@ -493,8 +519,8 @@ public class AlertsDAOTest {
     assertEquals(0, summary.getUnknownCount());
     assertEquals(0, summary.getOkCount());
 
-    h1.setAlertState(AlertState.CRITICAL);
-    m_dao.merge(h1);
+    history1.setAlertState(AlertState.CRITICAL);
+    m_dao.merge(history1);
 
     // verify host changed to critical
     summary = m_dao.findCurrentHostCounts(m_cluster.getClusterId());
@@ -504,11 +530,11 @@ public class AlertsDAOTest {
     assertEquals(0, summary.getOkCount());
 
     // grab another and change the host so that an OK shows up
-    AlertHistoryEntity h2 = m_dao.findCurrentByCluster(m_cluster.getClusterId()).get(
+    AlertHistoryEntity history2 = m_dao.findCurrentByCluster(m_cluster.getClusterId()).get(
         2).getAlertHistory();
 
-    h2.setHostName(h2.getHostName() + "-foo");
-    m_dao.merge(h2);
+    history2.setHostName(history2.getHostName() + "-foo");
+    m_dao.merge(history2);
 
     summary = m_dao.findCurrentHostCounts(m_cluster.getClusterId());
     assertEquals(0, summary.getWarningCount());
@@ -517,12 +543,12 @@ public class AlertsDAOTest {
     assertEquals(1, summary.getOkCount());
 
     // grab another and change that host name as well
-    AlertHistoryEntity h3 = m_dao.findCurrentByCluster(m_cluster.getClusterId()).get(
+    AlertHistoryEntity history3 = m_dao.findCurrentByCluster(m_cluster.getClusterId()).get(
         3).getAlertHistory();
 
     // change the name to simulate a 3rd host
-    h3.setHostName(h3.getHostName() + "-bar");
-    m_dao.merge(h3);
+    history3.setHostName(history3.getHostName() + "-bar");
+    m_dao.merge(history3);
 
     // verify 2 hosts report OK
     summary = m_dao.findCurrentHostCounts(m_cluster.getClusterId());
@@ -532,12 +558,12 @@ public class AlertsDAOTest {
     assertEquals(2, summary.getOkCount());
 
     // grab another and change that host name and the state to UNKNOWN
-    AlertHistoryEntity h4 = m_dao.findCurrentByCluster(m_cluster.getClusterId()).get(
+    AlertHistoryEntity history4 = m_dao.findCurrentByCluster(m_cluster.getClusterId()).get(
         4).getAlertHistory();
 
-    h4.setHostName(h4.getHostName() + "-baz");
-    h4.setAlertState(AlertState.UNKNOWN);
-    m_dao.merge(h3);
+    history4.setHostName(history4.getHostName() + "-baz");
+    history4.setAlertState(AlertState.UNKNOWN);
+    m_dao.merge(history3);
 
     // verify a new host shows up with UNKNOWN status hosts report OK
     summary = m_dao.findCurrentHostCounts(m_cluster.getClusterId());
@@ -545,6 +571,34 @@ public class AlertsDAOTest {
     assertEquals(1, summary.getCriticalCount());
     assertEquals(1, summary.getUnknownCount());
     assertEquals(2, summary.getOkCount());
+
+    // put 1 alert into maintenance mode
+    AlertCurrentEntity current4 = m_dao.findCurrentByCluster(
+        m_cluster.getClusterId()).get(4);
+
+    current4.setMaintenanceState(MaintenanceState.ON);
+    m_dao.merge(current4);
+
+    // verify that the UNKNOWN host has moved back to OK
+    summary = m_dao.findCurrentHostCounts(m_cluster.getClusterId());
+    assertEquals(0, summary.getWarningCount());
+    assertEquals(1, summary.getCriticalCount());
+    assertEquals(0, summary.getUnknownCount());
+    assertEquals(3, summary.getOkCount());
+
+    // put all alerts into maintenance mode
+    List<AlertCurrentEntity> currents = m_dao.findCurrentByCluster(m_cluster.getClusterId());
+    for (AlertCurrentEntity current : currents) {
+      current.setMaintenanceState(MaintenanceState.ON);
+      m_dao.merge(current);
+    }
+
+    // verify that all are OK
+    summary = m_dao.findCurrentHostCounts(m_cluster.getClusterId());
+    assertEquals(0, summary.getWarningCount());
+    assertEquals(0, summary.getCriticalCount());
+    assertEquals(0, summary.getUnknownCount());
+    assertEquals(4, summary.getOkCount());
   }
 
   @Test