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/10/06 23:03:23 UTC

[01/50] [abbrv] git commit: Merge branch 'trunk' into branch-alerts-dev

Repository: ambari
Updated Branches:
  refs/heads/trunk 0d953b468 -> 80bceaf3a


Merge branch 'trunk' into branch-alerts-dev


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

Branch: refs/heads/trunk
Commit: 6ba11a2a94d1646a08bf49215e6776870302325e
Parents: 7bb0194 3c13f40
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Mon Aug 25 08:31:55 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Mon Aug 25 08:31:55 2014 -0400

----------------------------------------------------------------------
 .../scripts/controllers/users/UsersShowCtrl.js  |  65 +++--
 .../ui/admin-web/app/scripts/services/User.js   |   3 +-
 .../resources/ui/admin-web/app/styles/main.css  |  12 +-
 .../admin-web/app/views/ambariViews/create.html |   6 +-
 .../admin-web/app/views/ambariViews/edit.html   |  95 ++++----
 .../admin-web/app/views/ambariViews/list.html   |  81 -------
 .../app/views/ambariViews/listTable.html        |   2 +-
 .../app/views/clusters/manageAccess.html        |  75 +++---
 .../ui/admin-web/app/views/groups/list.html     |  10 +-
 .../ui/admin-web/app/views/users/show.html      |   2 +-
 ambari-admin/src/main/resources/view.xml        |   1 +
 .../libraries/providers/hdfs_directory.py       |   2 +-
 .../api/services/ConfigurationService.java      |   2 +-
 .../server/api/util/StackExtensionHelper.java   |  69 ++++--
 .../server/configuration/Configuration.java     |   8 -
 .../server/controller/AmbariHandlerList.java    | 151 ++++++++++++
 .../ambari/server/controller/AmbariServer.java  |  13 +-
 .../server/controller/ControllerModule.java     |   2 +
 .../server/controller/FailsafeHandlerList.java  |  40 +++-
 .../internal/ClientConfigResourceProvider.java  |   2 +-
 .../internal/ConfigGroupResourceProvider.java   |  26 +-
 .../internal/ViewInstanceResourceProvider.java  |   6 +-
 .../ambari/server/orm/dao/PrincipalDAO.java     |  16 +-
 .../apache/ambari/server/orm/dao/RoleDAO.java   |  69 ------
 .../ambari/server/orm/dao/ServiceConfigDAO.java |   9 +-
 .../apache/ambari/server/orm/dao/UserDAO.java   |   8 -
 .../server/orm/entities/ConfigGroupEntity.java  |  11 +
 .../server/orm/entities/PrincipalEntity.java    |   5 +
 .../ambari/server/orm/entities/RoleEntity.java  |  70 ------
 .../ambari/server/orm/entities/UserEntity.java  |  11 -
 .../server/orm/entities/ViewInstanceEntity.java |  20 ++
 .../AmbariLdapAuthoritiesPopulator.java         | 134 +----------
 .../AmbariLocalUserDetailsService.java          |   8 +-
 .../server/security/authorization/User.java     |   9 -
 .../server/security/authorization/Users.java    | 147 +-----------
 .../internal/InternalAuthenticationToken.java   |  30 ++-
 .../server/state/cluster/ClusterImpl.java       |   8 +-
 .../server/state/configgroup/ConfigGroup.java   |   4 +
 .../state/configgroup/ConfigGroupImpl.java      |  21 ++
 .../server/upgrade/UpgradeCatalog170.java       |  56 +++--
 .../server/view/ViewInstanceHandlerList.java    |  43 ++++
 .../apache/ambari/server/view/ViewRegistry.java |  58 ++---
 .../main/resources/Ambari-DDL-MySQL-CREATE.sql  |  16 +-
 .../main/resources/Ambari-DDL-Oracle-CREATE.sql |  16 +-
 .../resources/Ambari-DDL-Postgres-CREATE.sql    |  18 +-
 .../Ambari-DDL-Postgres-EMBEDDED-CREATE.sql     |  20 +-
 .../src/main/resources/META-INF/persistence.xml |   1 -
 .../services/HBASE/package/scripts/params.py    |   1 +
 .../HDFS/package/scripts/hdfs_namenode.py       |   2 +-
 .../services/HDFS/package/scripts/params.py     |   1 +
 .../HIVE/package/scripts/hcat_service_check.py  |  27 ++-
 .../services/HIVE/package/scripts/params.py     |   1 +
 .../MAPREDUCE/configuration/core-site.xml       |  20 --
 .../MAPREDUCE/package/scripts/params.py         |   1 +
 .../services/OOZIE/package/scripts/params.py    |   1 +
 .../services/WEBHCAT/package/scripts/params.py  |   1 +
 .../services/HBASE/package/scripts/params.py    |   1 +
 .../HDFS/package/scripts/hdfs_namenode.py       |   2 +-
 .../services/HDFS/package/scripts/params.py     |   1 +
 .../HIVE/package/scripts/hcat_service_check.py  |  27 ++-
 .../HIVE/package/scripts/install_jars.py        |   2 +-
 .../services/HIVE/package/scripts/params.py     |   1 +
 .../services/OOZIE/package/scripts/params.py    |   1 +
 .../services/PIG/package/scripts/params.py      |   1 +
 .../services/WEBHCAT/package/scripts/params.py  |   1 +
 .../services/WEBHCAT/package/scripts/webhcat.py |   2 +-
 .../YARN/configuration-mapred/core-site.xml     |  20 --
 .../services/YARN/configuration/core-site.xml   |  20 --
 .../services/YARN/package/scripts/params.py     |   1 +
 .../services/FALCON/package/scripts/params.py   |   1 +
 .../services/YARN/package/scripts/params.py     |   1 +
 .../services/FALCON/package/scripts/params.py   |   1 +
 .../services/YARN/configuration/core-site.xml   |  20 --
 .../api/util/StackExtensionHelperTest.java      | 235 ++++++++-----------
 .../controller/AmbariHandlerListTest.java       | 107 +++++++++
 .../AmbariManagementControllerTest.java         |  11 -
 .../apache/ambari/server/orm/OrmTestHelper.java |  26 +-
 .../ambari/server/orm/dao/UserDAOTest.java      |  40 +---
 ...uthenticationProviderForDNWithSpaceTest.java |  38 ---
 .../AmbariLdapAuthenticationProviderTest.java   |  39 ---
 .../AmbariLdapDataPopulatorTest.java            |   2 -
 .../AmbariLocalUserDetailsServiceTest.java      |   7 -
 .../TestAmbariLdapAuthoritiesPopulator.java     | 212 +----------------
 .../security/authorization/TestUsers.java       |  87 -------
 .../server/upgrade/UpgradeCatalog170Test.java   |   8 +-
 .../ambari/server/upgrade/UpgradeTest.java      |   8 -
 .../ambari/server/view/ViewRegistryTest.java    |   8 +-
 .../1.3.2/HIVE/test_hive_service_check.py       |   3 +-
 .../python/stacks/1.3.2/configs/secured.json    |   3 +-
 .../2.0.6/HIVE/test_hive_service_check.py       |   3 +-
 .../python/stacks/2.0.6/configs/secured.json    |   5 +-
 .../test/python/stacks/2.1/configs/secured.json |   5 +-
 ambari-web/app/app.js                           |  31 +--
 ambari-web/app/config.js                        |   1 -
 .../controllers/global/cluster_controller.js    |   8 +-
 ambari-web/app/controllers/installer.js         |   7 -
 ambari-web/app/controllers/main.js              |   1 +
 .../app/controllers/main/admin/repositories.js  |   8 +-
 .../app/controllers/main/views_controller.js    |  80 ++++++-
 .../app/controllers/wizard/step5_controller.js  |  29 ++-
 .../app/controllers/wizard/step6_controller.js  |  35 +--
 ambari-web/app/mappers/stack_service_mapper.js  |   2 +
 ambari-web/app/mappers/users_mapper.js          |   2 +-
 ambari-web/app/messages.js                      |   2 -
 ambari-web/app/mixins.js                        |   1 +
 ambari-web/app/mixins/common/blueprint.js       |  70 ++++++
 ambari-web/app/router.js                        | 115 +++++----
 ambari-web/app/routes/add_service_routes.js     |   4 +-
 ambari-web/app/routes/installer.js              |   2 +-
 ambari-web/app/routes/main.js                   |  22 --
 ambari-web/app/routes/views.js                  |  53 +++++
 ambari-web/app/templates/application.hbs        |   6 +-
 ambari-web/app/utils/ajax/ajax.js               |   4 +-
 ambari-web/app/utils/blueprint.js               |   4 +
 ambari-web/app/views/main/admin/repositories.js |   4 +-
 ambari-web/app/views/main/menu.js               |   7 +-
 ambari-web/app/views/main/views_view.js         |   4 +-
 ambari-web/app/views/wizard/controls_view.js    |   1 +
 ambari-web/test/app_test.js                     |  14 +-
 .../test/controllers/wizard/step4_test.js       |   6 +-
 ambari-web/test/mappers/users_mapper_test.js    |   2 +-
 121 files changed, 1352 insertions(+), 1659 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/6ba11a2a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/6ba11a2a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/6ba11a2a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/6ba11a2a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/6ba11a2a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/6ba11a2a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/6ba11a2a/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/6ba11a2a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
----------------------------------------------------------------------


[25/50] [abbrv] git commit: AMBARI-7336 - Alerts: Create Default AlertGroup When Service Is Installed (jonathanhurley)

Posted by jo...@apache.org.
AMBARI-7336 - Alerts: Create Default AlertGroup When Service Is Installed (jonathanhurley)


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

Branch: refs/heads/trunk
Commit: b7ae2d74adcd07759b2308bc2a7b0f8115480a7e
Parents: 17b8e79
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Tue Sep 16 12:26:36 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Tue Sep 16 12:26:36 2014 -0400

----------------------------------------------------------------------
 .../server/controller/ControllerModule.java     |   2 +
 .../apache/ambari/server/events/AlertEvent.java |   2 +-
 .../ambari/server/events/AmbariEvent.java       |  75 ++++++++++
 .../ambari/server/events/ServiceEvent.java      |  75 ++++++++++
 .../server/events/ServiceInstalledEvent.java    |  52 +++++++
 .../events/listeners/AlertReceivedListener.java |   4 +-
 .../listeners/AlertServiceStateListener.java    | 147 +++++++++++++++++++
 .../listeners/AlertStateChangedListener.java    |   2 +
 .../events/publishers/AlertEventPublisher.java  |   8 +-
 .../events/publishers/AmbariEventPublisher.java |  66 +++++++++
 .../apache/ambari/server/state/ServiceImpl.java |  49 ++-----
 .../state/alerts/AlertEventPublisherTest.java   | 132 +++++++++++++++++
 12 files changed, 572 insertions(+), 42 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/b7ae2d74/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
index 8413762..349e465 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
@@ -52,6 +52,7 @@ import org.apache.ambari.server.controller.internal.MemberResourceProvider;
 import org.apache.ambari.server.controller.internal.ServiceResourceProvider;
 import org.apache.ambari.server.controller.spi.ResourceProvider;
 import org.apache.ambari.server.events.listeners.AlertReceivedListener;
+import org.apache.ambari.server.events.listeners.AlertServiceStateListener;
 import org.apache.ambari.server.events.listeners.AlertStateChangedListener;
 import org.apache.ambari.server.orm.DBAccessor;
 import org.apache.ambari.server.orm.DBAccessorImpl;
@@ -313,5 +314,6 @@ public class ControllerModule extends AbstractModule {
     // them as eager singletons to have them register with the eventbus
     bind(AlertReceivedListener.class).asEagerSingleton();
     bind(AlertStateChangedListener.class).asEagerSingleton();
+    bind(AlertServiceStateListener.class).asEagerSingleton();
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b7ae2d74/ambari-server/src/main/java/org/apache/ambari/server/events/AlertEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/AlertEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/AlertEvent.java
index a75477d..767cb6b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/AlertEvent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/AlertEvent.java
@@ -20,7 +20,7 @@ package org.apache.ambari.server.events;
 import org.apache.ambari.server.state.Alert;
 
 /**
- * The {@link AlertEvent} class the base for all events related to alerts.
+ * The {@link AlertEvent} class is the base for all events related to alerts.
  */
 public abstract class AlertEvent {
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b7ae2d74/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java
new file mode 100644
index 0000000..dda18c7
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java
@@ -0,0 +1,75 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.events;
+
+
+/**
+ * The {@link AmbariEvent} class is the base for all events in Ambari.
+ */
+public abstract class AmbariEvent {
+
+  /**
+   * The {@link AmbariEventType} defines the type of Ambari event.
+   */
+  public enum AmbariEventType {
+    /**
+     * A service was successfully installed.
+     */
+    SERVICE_INSTALL_SUCCESS;
+  }
+
+  /**
+   * The concrete event's type.
+   */
+  protected final AmbariEventType m_eventType;
+
+  /**
+   * The cluster ID.
+   */
+  protected final long m_clusterId;
+
+  /**
+   * Constructor.
+   *
+   * @param eventType
+   *          the type of event (not {@code null}).
+   * @param clusterId
+   */
+  public AmbariEvent(AmbariEventType eventType, long clusterId) {
+    m_eventType = eventType;
+    m_clusterId = clusterId;
+  }
+
+  /**
+   * Gets the cluster ID that the event belongs to.
+   *
+   * @return the ID of the cluster.
+   */
+  public long getClusterId() {
+    return m_clusterId;
+  }
+
+  /**
+   * Gets the type of {@link AmbariEvent}.
+   *
+   * @return the event type (never {@code null}).
+   */
+  public AmbariEventType getType() {
+    return m_eventType;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b7ae2d74/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceEvent.java
new file mode 100644
index 0000000..5e01431
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceEvent.java
@@ -0,0 +1,75 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.events;
+
+
+/**
+ * The {@link ServiceEvent} class is the base for all service events in Ambari.
+ */
+public abstract class ServiceEvent extends AmbariEvent {
+
+  /**
+   * The name of the service.
+   */
+  protected final String m_serviceName;
+
+  /**
+   * The name of the services' stack.
+   */
+  protected final String m_stackName;
+
+  /**
+   * The version of the services' stack.
+   */
+  protected final String m_stackVersion;
+
+  /**
+   * Constructor.
+   *
+   * @param eventType
+   * @param clusterId
+   */
+  public ServiceEvent(AmbariEventType eventType, long clusterId,
+      String stackName, String stackVersion, String serviceName) {
+    super(eventType, clusterId);
+    m_stackName = stackName;
+    m_stackVersion = stackVersion;
+    m_serviceName = serviceName;
+  }
+
+  /**
+   * @return the serviceName (never {@code null}).
+   */
+  public String getServiceName() {
+    return m_serviceName;
+  }
+
+  /**
+   * @return the stackName (never {@code null}).
+   */
+  public String getStackName() {
+    return m_stackName;
+  }
+
+  /**
+   * @return the stackVersion (never {@code null}).
+   */
+  public String getStackVersion() {
+    return m_stackVersion;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b7ae2d74/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceInstalledEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceInstalledEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceInstalledEvent.java
new file mode 100644
index 0000000..c2b6e7a
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceInstalledEvent.java
@@ -0,0 +1,52 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.events;
+
+/**
+ * The {@link ServiceInstalledEvent} class is fired when a service is
+ * successfully installed.
+ */
+public class ServiceInstalledEvent extends ServiceEvent {
+  /**
+   * Constructor.
+   *
+   * @param clusterId
+   * @param stackName
+   * @param stackVersion
+   * @param serviceName
+   */
+  public ServiceInstalledEvent(long clusterId, String stackName,
+      String stackVersion, String serviceName) {
+    super(AmbariEventType.SERVICE_INSTALL_SUCCESS, clusterId, stackName,
+        stackVersion, serviceName);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString() {
+    StringBuilder buffer = new StringBuilder("ServiceInstalledEvent{ ");
+    buffer.append("cluserId=").append(m_clusterId);
+    buffer.append(", stackName=").append(m_stackName);
+    buffer.append(", stackVersion=").append(m_stackVersion);
+    buffer.append(", serviceName=").append(m_serviceName);
+    buffer.append("}");
+    return buffer.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b7ae2d74/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java
index 1bdd7e2..519ceeb 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java
@@ -38,7 +38,7 @@ import com.google.inject.Singleton;
 
 /**
  * The {@link AlertReceivedListener} class handles {@link AlertReceivedEvent}
- * and updates the appropirate DAOs. It may also fire new
+ * and updates the appropriate DAOs. It may also fire new
  * {@link AlertStateChangeEvent} when an {@link AlertState} change is detected.
  */
 @Singleton
@@ -80,6 +80,8 @@ public class AlertReceivedListener {
   @Subscribe
   @AllowConcurrentEvents
   public void onAlertEvent(AlertReceivedEvent event) {
+    LOG.debug(event);
+
     long clusterId = event.getClusterId();
     Alert alert = event.getAlert();
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b7ae2d74/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertServiceStateListener.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertServiceStateListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertServiceStateListener.java
new file mode 100644
index 0000000..906d52d
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertServiceStateListener.java
@@ -0,0 +1,147 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.events.listeners;
+
+import java.text.MessageFormat;
+import java.util.Set;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.controller.AmbariServer;
+import org.apache.ambari.server.controller.ControllerModule;
+import org.apache.ambari.server.events.ServiceInstalledEvent;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
+import org.apache.ambari.server.orm.GuiceJpaInitializer;
+import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
+import org.apache.ambari.server.orm.dao.AlertDispatchDAO;
+import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
+import org.apache.ambari.server.orm.entities.AlertGroupEntity;
+import org.apache.ambari.server.state.alert.AlertDefinition;
+import org.apache.ambari.server.state.alert.AlertDefinitionFactory;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import com.google.common.eventbus.AllowConcurrentEvents;
+import com.google.common.eventbus.Subscribe;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+
+/**
+ * The {@link AlertServiceStateListener} class handles
+ * {@link ServiceInstalledEvent} and ensures that {@link AlertDefinitionEntity}
+ * and {@link AlertGroupEntity} instances are correctly populated.
+ */
+@Singleton
+public class AlertServiceStateListener {
+  /**
+   * Logger.
+   */
+  private static Log LOG = LogFactory.getLog(AlertServiceStateListener.class);
+
+  /**
+   * Services metainfo; injected lazily as a {@link Provider} since JPA is not
+   * fully initialized when this singleton is eagerly instantiated. See
+   * {@link AmbariServer#main(String[])} and the ordering of
+   * {@link ControllerModule} and {@link GuiceJpaInitializer}.
+   */
+  @Inject
+  private Provider<AmbariMetaInfo> m_metaInfoProvider;
+
+  /**
+   * Used when a service is installed to read alert definitions from the stack
+   * and coerce them into {@link AlertDefinitionEntity}.
+   */
+  @Inject
+  private AlertDefinitionFactory m_alertDefinitionFactory;
+
+  /**
+   * Used when a service is installed to insert a default
+   * {@link AlertGroupEntity} into the database.
+   */
+  @Inject
+  private AlertDispatchDAO m_alertDispatchDao;
+
+  /**
+   * Used when a service is installed to insert {@link AlertDefinitionEntity}
+   * into the database.
+   */
+  @Inject
+  private AlertDefinitionDAO m_definitionDao;
+
+  /**
+   * Constructor.
+   *
+   * @param publisher
+   */
+  @Inject
+  public AlertServiceStateListener(AmbariEventPublisher publisher) {
+    publisher.register(this);
+  }
+
+
+  /**
+   * Handles service installed events by populating the database with all known
+   * alert definitions for the newly installed service and creates the service's
+   * default alert group.
+   *
+   * @param event
+   *          the published event being handled (not {@code null}).
+   */
+  @Subscribe
+  @AllowConcurrentEvents
+  public void onAmbariEvent(ServiceInstalledEvent event) {
+    LOG.debug(event);
+
+    long clusterId = event.getClusterId();
+    String stackName = event.getStackName();
+    String stackVersion = event.getStackVersion();
+    String serviceName = event.getServiceName();
+
+    // populate alert definitions for the new service from the database, but
+    // don't worry about sending down commands to the agents; the host
+    // components are not yet bound to the hosts so we'd have no way of knowing
+    // which hosts are invalidated; do that in another impl
+    try {
+      Set<AlertDefinition> alertDefinitions = m_metaInfoProvider.get().getAlertDefinitions(
+          stackName, stackVersion, serviceName);
+
+      for (AlertDefinition definition : alertDefinitions) {
+        AlertDefinitionEntity entity = m_alertDefinitionFactory.coerce(
+            clusterId,
+            definition);
+
+        m_definitionDao.create(entity);
+      }
+    } catch (AmbariException ae) {
+      String message = MessageFormat.format(
+          "Unable to populate alert definitions from the database during installation of {0}",
+          serviceName);
+      LOG.error(message, ae);
+    }
+
+    // create the default alert group for the new service
+    AlertGroupEntity serviceAlertGroup = new AlertGroupEntity();
+    serviceAlertGroup.setClusterId(clusterId);
+    serviceAlertGroup.setDefault(true);
+    serviceAlertGroup.setGroupName(serviceName);
+    serviceAlertGroup.setServiceName(serviceName);
+
+    m_alertDispatchDao.create(serviceAlertGroup);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b7ae2d74/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertStateChangedListener.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertStateChangedListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertStateChangedListener.java
index a327110..ac22f88 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertStateChangedListener.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertStateChangedListener.java
@@ -72,6 +72,8 @@ public class AlertStateChangedListener {
   @Subscribe
   @AllowConcurrentEvents
   public void onAlertEvent(AlertStateChangeEvent event) {
+    LOG.debug(event);
+
     AlertHistoryEntity history = event.getNewHistoricalEntry();
     AlertDefinitionEntity definition = history.getAlertDefinition();
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b7ae2d74/ambari-server/src/main/java/org/apache/ambari/server/events/publishers/AlertEventPublisher.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/publishers/AlertEventPublisher.java b/ambari-server/src/main/java/org/apache/ambari/server/events/publishers/AlertEventPublisher.java
index e42e317..f1a0b3e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/publishers/AlertEventPublisher.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/publishers/AlertEventPublisher.java
@@ -42,13 +42,13 @@ public final class AlertEventPublisher {
   /**
    * A multi-threaded event bus that can handle dispatching {@link AlertEvent}s.
    */
-  private final EventBus s_eventBus;
+  private final EventBus m_eventBus;
 
   /**
    * Constructor.
    */
   public AlertEventPublisher() {
-    s_eventBus = new AsyncEventBus(Executors.newFixedThreadPool(2,
+    m_eventBus = new AsyncEventBus(Executors.newFixedThreadPool(2,
         new AlertEventBusThreadFactory()));
   }
 
@@ -59,7 +59,7 @@ public final class AlertEventPublisher {
    * @param event
    */
   public void publish(AlertEvent event) {
-    s_eventBus.post(event);
+    m_eventBus.post(event);
   }
 
   /**
@@ -70,7 +70,7 @@ public final class AlertEventPublisher {
    *          the listener to receive events.
    */
   public void register(Object object) {
-    s_eventBus.register(object);
+    m_eventBus.register(object);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/b7ae2d74/ambari-server/src/main/java/org/apache/ambari/server/events/publishers/AmbariEventPublisher.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/publishers/AmbariEventPublisher.java b/ambari-server/src/main/java/org/apache/ambari/server/events/publishers/AmbariEventPublisher.java
new file mode 100644
index 0000000..0236e03
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/publishers/AmbariEventPublisher.java
@@ -0,0 +1,66 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.events.publishers;
+
+import org.apache.ambari.server.events.AmbariEvent;
+
+import com.google.common.eventbus.EventBus;
+import com.google.common.eventbus.Subscribe;
+import com.google.inject.Singleton;
+
+/**
+ * The {@link AmbariEventPublisher} is used to publish instances of
+ * {@link AmbariEvent} to any {@link Subscribe} interested. It uses a
+ * single-threaded, serial {@link EventBus}.
+ */
+@Singleton
+public final class AmbariEventPublisher {
+
+  /**
+   * A single threaded event bus for processing Ambari events in serial.
+   */
+  private final EventBus m_eventBus;
+
+  /**
+   * Constructor.
+   */
+  public AmbariEventPublisher() {
+    m_eventBus = new EventBus("ambari-event-bus");
+  }
+
+  /**
+   * Publishes the specified event to all registered listeners that
+   * {@link Subscribe} to any of the {@link AmbariEvent} instances.
+   *
+   * @param event
+   */
+  public void publish(AmbariEvent event) {
+    m_eventBus.post(event);
+  }
+
+  /**
+   * Register a listener to receive events. The listener should use the
+   * {@link Subscribe} annotation.
+   *
+   * @param object
+   *          the listener to receive events.
+   */
+  public void register(Object object) {
+    m_eventBus.register(object);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b7ae2d74/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java
index b2b84fc..e6b5921 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java
@@ -20,7 +20,6 @@ package org.apache.ambari.server.state;
 
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Set;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
@@ -28,18 +27,16 @@ import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.ServiceComponentNotFoundException;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.controller.ServiceResponse;
-import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
+import org.apache.ambari.server.events.ServiceInstalledEvent;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 import org.apache.ambari.server.orm.dao.ClusterDAO;
 import org.apache.ambari.server.orm.dao.ClusterServiceDAO;
 import org.apache.ambari.server.orm.dao.ServiceDesiredStateDAO;
-import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
 import org.apache.ambari.server.orm.entities.ClusterEntity;
 import org.apache.ambari.server.orm.entities.ClusterServiceEntity;
 import org.apache.ambari.server.orm.entities.ClusterServiceEntityPK;
 import org.apache.ambari.server.orm.entities.ServiceComponentDesiredStateEntity;
 import org.apache.ambari.server.orm.entities.ServiceDesiredStateEntity;
-import org.apache.ambari.server.state.alert.AlertDefinition;
-import org.apache.ambari.server.state.alert.AlertDefinitionFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -80,18 +77,10 @@ public class ServiceImpl implements Service {
   private AmbariMetaInfo ambariMetaInfo;
 
   /**
-   * Used when a service is installed to insert {@link AlertDefinitionEntity}
-   * into the database.
+   * Used to publish events relating to service CRUD operations.
    */
   @Inject
-  private AlertDefinitionDAO alertDefinitionDAO;
-
-  /**
-   * Used when a service is installed to read alert definitions from the stack
-   * and coerce them into {@link AlertDefinitionEntity}.
-   */
-  @Inject
-  private AlertDefinitionFactory alertDefinitionFactory;
+  private AmbariEventPublisher eventPublisher;
 
   private void init() {
     // TODO load from DB during restart?
@@ -476,6 +465,15 @@ public class ServiceImpl implements Service {
           refresh();
           cluster.refresh();
           persisted = true;
+
+          // publish the service installed event
+          StackId stackId = cluster.getDesiredStackVersion();
+
+          ServiceInstalledEvent event = new ServiceInstalledEvent(
+              getClusterId(), stackId.getStackName(),
+              stackId.getStackVersion(), getName());
+
+          eventPublisher.publish(event);
         } else {
           saveIfPersisted();
         }
@@ -491,7 +489,6 @@ public class ServiceImpl implements Service {
   @Transactional
   protected void persistEntities() {
     long clusterId = cluster.getClusterId();
-    StackId stackId = cluster.getDesiredStackVersion();
 
     ClusterEntity clusterEntity = clusterDAO.findById(clusterId);
     serviceEntity.setClusterEntity(clusterEntity);
@@ -501,26 +498,6 @@ public class ServiceImpl implements Service {
     clusterDAO.merge(clusterEntity);
     clusterServiceDAO.merge(serviceEntity);
     serviceDesiredStateDAO.merge(serviceDesiredStateEntity);
-
-    // populate alert definitions for the new service from the database, but
-    // don't worry about sending down commands to the agents; the host
-    // components are not yet bound to the hosts so we'd have no way of knowing
-    // which hosts are invalidated; do that in another impl
-    try{
-      Set<AlertDefinition> alertDefinitions = ambariMetaInfo.getAlertDefinitions(
-          stackId.getStackName(), stackId.getStackVersion(), getName());
-
-      for (AlertDefinition definition : alertDefinitions) {
-        AlertDefinitionEntity entity = alertDefinitionFactory.coerce(clusterId,
-            definition);
-
-        alertDefinitionDAO.create(entity);
-      }
-    } catch( AmbariException ae ){
-      LOG.error(
-          "Unable to populate alert definitions from the database during installation of {}",
-          getName(), ae);
-    }
   }
 
   @Transactional

http://git-wip-us.apache.org/repos/asf/ambari/blob/b7ae2d74/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertEventPublisherTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertEventPublisherTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertEventPublisherTest.java
new file mode 100644
index 0000000..482b5ef
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertEventPublisherTest.java
@@ -0,0 +1,132 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state.alerts;
+
+import junit.framework.Assert;
+
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.events.AmbariEvent;
+import org.apache.ambari.server.events.listeners.AlertServiceStateListener;
+import org.apache.ambari.server.orm.GuiceJpaInitializer;
+import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
+import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
+import org.apache.ambari.server.orm.dao.AlertDispatchDAO;
+import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
+import org.apache.ambari.server.orm.entities.AlertGroupEntity;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.Service;
+import org.apache.ambari.server.state.ServiceFactory;
+import org.apache.ambari.server.state.StackId;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.persist.PersistService;
+
+/**
+ * Tests that {@link AmbariEvent} instances are fired correctly and that alert
+ * data is bootstrapped into the database.
+ */
+public class AlertEventPublisherTest {
+
+  private AlertDispatchDAO dispatchDao;
+  private AlertDefinitionDAO definitionDao;
+  private Clusters clusters;
+  private Cluster cluster;
+  private String clusterName;
+  private Injector injector;
+  private ServiceFactory serviceFactory;
+  private AmbariMetaInfo metaInfo;
+
+  /**
+   *
+   */
+  @Before
+  public void setup() throws Exception {
+    injector = Guice.createInjector(new InMemoryDefaultTestModule());
+    injector.getInstance(GuiceJpaInitializer.class);
+
+    // force singleton init via Guice so the listener registers with the bus
+    injector.getInstance(AlertServiceStateListener.class);
+
+    dispatchDao = injector.getInstance(AlertDispatchDAO.class);
+    definitionDao = injector.getInstance(AlertDefinitionDAO.class);
+    clusters = injector.getInstance(Clusters.class);
+    serviceFactory = injector.getInstance(ServiceFactory.class);
+
+    metaInfo = injector.getInstance(AmbariMetaInfo.class);
+    metaInfo.init();
+
+    clusterName = "foo";
+    clusters.addCluster(clusterName);
+    cluster = clusters.getCluster(clusterName);
+    cluster.setDesiredStackVersion(new StackId("HDP", "2.0.6"));
+    Assert.assertNotNull(cluster);
+  }
+
+  /**
+   * @throws Exception
+   */
+  @After
+  public void teardown() throws Exception {
+    injector.getInstance(PersistService.class).stop();
+    injector = null;
+  }
+
+  /**
+   * Tests that a default {@link AlertGroupEntity} is created when a service is
+   * installed.
+   *
+   * @throws Exception
+   */
+  @Test
+  public void testDefaultAlertGroupCreation() throws Exception {
+    Assert.assertEquals(0, dispatchDao.findAllGroups().size());
+    installHdfsService();
+    Assert.assertEquals(1, dispatchDao.findAllGroups().size());
+  }
+
+  /**
+   * Tests that all {@link AlertDefinitionEntity} instances are created for the
+   * installed service.
+   * 
+   * @throws Exception
+   */
+  @Test
+  public void testAlertDefinitionInsertion() throws Exception {
+    Assert.assertEquals(0, definitionDao.findAll().size());
+    installHdfsService();
+    Assert.assertEquals(4, definitionDao.findAll().size());
+  }
+
+  /**
+   * Calls {@link Service#persist()} to mock a service install.
+   */
+  private void installHdfsService() throws Exception {
+    String serviceName = "HDFS";
+    Service service = serviceFactory.createNew(cluster, serviceName);
+    cluster.addService(service);
+    service.persist();
+    service = cluster.getService(serviceName);
+
+    Assert.assertNotNull(service);
+  }
+}


[08/50] [abbrv] git commit: Merge branch 'trunk' into branch-alerts-dev

Posted by jo...@apache.org.
Merge branch 'trunk' into branch-alerts-dev


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

Branch: refs/heads/trunk
Commit: c13730a065646ba404c91f0f06819c71d669ebe7
Parents: 2f5c78e 866f5b2
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Mon Sep 1 07:39:49 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Mon Sep 1 07:39:49 2014 -0400

----------------------------------------------------------------------
 .../ambariViews/CreateViewInstanceCtrl.js       |   5 +-
 .../controllers/ambariViews/ViewsListCtrl.js    |   6 +-
 .../controllers/groups/GroupsCreateCtrl.js      |   1 +
 .../controllers/users/UsersCreateCtrl.js        |   1 +
 .../scripts/controllers/users/UsersShowCtrl.js  |  21 +-
 .../admin-web/app/scripts/services/uiAlert.js   |  21 +-
 .../app/views/ambariViews/listTable.html        |   3 +
 .../ui/admin-web/app/views/leftNavbar.html      |   2 +-
 ambari-client/groovy-client/pom.xml             |   4 +
 .../ambari/groovy/client/AmbariClient.groovy    | 506 +++++++++++++++++--
 .../client/InvalidBlueprintException.groovy     |  28 +
 .../InvalidHostGroupHostAssociation.groovy      |  39 ++
 .../resources/blueprints/hdp-multinode-default  | 182 +++++++
 .../resources/blueprints/hdp-singlenode-default | 133 +++++
 .../resources/blueprints/lambda-architecture    |   8 +-
 .../resources/blueprints/multi-node-hdfs-yarn   |   4 +-
 .../resources/blueprints/single-node-hdfs-yarn  |   2 +-
 .../groovy/client/AmbariBlueprintsTest.groovy   |  95 ++++
 .../ambari/groovy/client/AmbariHostsTest.groovy |  34 +-
 .../groovy/client/AmbariRecommendTest.groovy    | 150 ++++++
 .../groovy/client/AmbariServicesTest.groovy     |  63 +++
 .../ambari/groovy/client/TestResources.groovy   |   2 +
 .../src/test/resources/blueprint-config.json    |  61 +++
 .../test/resources/hdp-multinode-default.json   | 200 ++++++++
 .../test/resources/hdp-multinode-default2.json  | 164 ++++++
 .../resources/multi-node-hdfs-yarn-config.json  |  89 ++++
 .../test/resources/multi-node-hdfs-yarn.json    |  83 +++
 .../server/api/handlers/DeleteHandler.java      |   9 +-
 .../controller/AmbariActionExecutionHelper.java |   4 +-
 .../AmbariManagementControllerImpl.java         |  12 +-
 .../controller/MaintenanceStateHelper.java      |  49 +-
 .../internal/ComponentResourceProvider.java     |   2 -
 .../internal/ConfigGroupResourceProvider.java   |   2 +-
 .../internal/HostResourceProvider.java          |  12 +-
 .../internal/ServiceResourceProvider.java       |  12 +-
 .../controller/jmx/JMXPropertyProvider.java     |  81 ++-
 .../orm/dao/ConfigGroupHostMappingDAO.java      |   2 +
 .../apache/ambari/server/state/ConfigImpl.java  |  17 +-
 .../server/state/cluster/ClusterImpl.java       |  52 +-
 .../state/configgroup/ConfigGroupImpl.java      |  41 +-
 .../HIVE/package/scripts/hive_client.py         |   3 +-
 .../HIVE/package/scripts/hive_metastore.py      |   3 +-
 .../HIVE/package/scripts/hive_server.py         |   3 +-
 .../HIVE/package/scripts/mysql_server.py        |   4 +-
 .../services/HIVE/package/scripts/params.py     |  10 +
 .../resources/stacks/HDP/2.1/repos/repoinfo.xml |  14 +-
 .../server/api/handlers/DeleteHandlerTest.java  |  36 +-
 .../controller/MaintenanceStateHelperTest.java  |  34 +-
 .../controller/jmx/JMXPropertyProviderTest.java |  49 +-
 .../server/state/cluster/ClusterTest.java       | 122 ++++-
 .../ambari/server/state/host/HostTest.java      |   8 -
 .../HDP/0.1/services/MAPREDUCE/metainfo.xml     |   6 +
 .../ambari/shell/commands/BasicCommands.java    |  74 ---
 .../ambari/shell/commands/ClusterCommands.java  |   3 +-
 .../ambari/shell/commands/ServiceCommands.java  | 155 ++++++
 .../apache/ambari/shell/completion/Service.java |  31 ++
 .../configuration/ConverterConfiguration.java   |   6 +
 .../shell/converter/ServiceConverter.java       |  55 ++
 .../ambari/shell/flash/InstallProgress.java     |   2 +-
 .../shell/commands/ClusterCommandsTest.java     |   5 +-
 .../shell/commands/ServiceCommandsTest.java     |  70 +++
 ambari-web/app/assets/licenses/NOTICE.txt       |   4 +-
 ambari-web/app/config.js                        |   2 +-
 .../nameNode/step5_controller.js                |  26 +-
 .../nameNode/step9_controller.js                |   8 +-
 .../highAvailability/progress_controller.js     |  23 +
 .../resourceManager/step4_controller.js         |  11 +-
 .../security/security_progress_controller.js    |  45 +-
 ambari-web/app/controllers/main/host/details.js |  22 +-
 ambari-web/app/controllers/main/service.js      | 134 +++--
 .../controllers/main/service/info/configs.js    |  77 +--
 .../main/service/reassign/step4_controller.js   |  73 ++-
 .../app/controllers/wizard/step4_controller.js  |   4 +-
 .../app/controllers/wizard/step6_controller.js  |  22 +-
 .../app/controllers/wizard/step8_controller.js  |  69 +--
 ambari-web/app/messages.js                      |  16 +-
 ambari-web/app/mixins/common/serverValidator.js |  20 +-
 ambari-web/app/models/service_config.js         |   5 +
 ambari-web/app/models/service_config_version.js |  12 +-
 ambari-web/app/models/stack_service.js          |  10 +-
 ambari-web/app/styles/application.less          |  14 +-
 .../common/configs/compare_property.hbs         |   2 +-
 .../common/configs/config_history_flow.hbs      |  32 +-
 .../configs/config_recommendation_popup.hbs     |  28 +
 .../common/configs/overriddenProperty.hbs       |   2 +-
 .../common/configs/service_config_category.hbs  |   4 +-
 .../templates/main/dashboard/config_history.hbs |   8 +-
 .../main/dashboard/plus_button_filter.hbs       |   2 +-
 ambari-web/app/templates/main/menu_item.hbs     |   6 +-
 ambari-web/app/templates/wizard/step6.hbs       |  27 +-
 .../wizard/step6/step6_issues_popup.hbs         |  41 ++
 ambari-web/app/templates/wizard/step7.hbs       |   2 +-
 ambari-web/app/utils/ajax/ajax.js               |  67 ++-
 .../views/common/configs/config_history_flow.js | 134 +++--
 ambari-web/app/views/main/dashboard/widgets.js  |  12 +-
 ambari-web/app/views/main/menu.js               |   2 +-
 ambari-web/app/views/main/service.js            |   1 +
 ambari-web/app/views/main/views/details.js      |  28 +
 .../test/controllers/main/service_test.js       | 254 ++++++++++
 .../jquery.iframe-auto-height.plugin.1.9.5.js   | 224 ++++++++
 .../app/assets/data/resource/cluster_name.json  |  12 +
 .../assets/data/resource/components_hosts.json  |  16 +
 .../app/controllers/slider_apps_controller.js   |  50 ++
 .../ui/app/controllers/tooltip_controller.js    |  19 +
 .../src/main/resources/ui/app/helpers/ajax.js   |   2 +
 .../ui/app/mappers/slider_apps_mapper.js        |   3 +-
 .../main/resources/ui/app/models/slider_app.js  |   5 +
 .../src/main/resources/ui/app/routes/main.js    |  12 +
 .../resources/ui/app/styles/application.less    |  13 +
 .../resources/ui/app/templates/application.hbs  |   1 +
 .../ui/app/templates/common/app_tooltip.hbs     |  28 +
 .../ui/app/templates/slider_app/summary.hbs     |  50 +-
 .../resources/ui/app/templates/slider_apps.hbs  |   2 +-
 .../src/main/resources/ui/app/translations.js   |   8 +-
 .../ui/app/views/slider_app/summary_view.js     |  21 +-
 .../resources/ui/app/views/slider_apps_view.js  |  18 +-
 .../slider/src/main/resources/ui/config.js      |   2 +
 .../ui/vendor/scripts/common/bs-popover.min.js  |   1 +
 118 files changed, 3958 insertions(+), 673 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/c13730a0/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
----------------------------------------------------------------------
diff --cc ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
index b181399,06f46fe..0d4f6aa
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
@@@ -1687,18 -1646,29 +1680,29 @@@ public class ClusterImpl implements Clu
      serviceConfigVersionResponse.setClusterName(getClusterName());
      serviceConfigVersionResponse.setServiceName(serviceConfigEntity.getServiceName());
      serviceConfigVersionResponse.setVersion(serviceConfigEntity.getVersion());
 -    serviceConfigVersionResponse.setCreateTime(serviceConfigEntity.getCreateTimestamp());    
 +    serviceConfigVersionResponse.setCreateTime(serviceConfigEntity.getCreateTimestamp());
      serviceConfigVersionResponse.setUserName(serviceConfigEntity.getUser());
      serviceConfigVersionResponse.setNote(serviceConfigEntity.getNote());
-     if (clusterConfigGroups != null) {
-       ConfigGroup configGroup = clusterConfigGroups.get(serviceConfigEntity.getGroupId());
+ 
+     Long groupId = serviceConfigEntity.getGroupId();
+ 
+     if (groupId != null) {
+       serviceConfigVersionResponse.setGroupId(groupId);
+       ConfigGroup configGroup = null;
+       if (clusterConfigGroups != null) {
+         configGroup = clusterConfigGroups.get(groupId);
+       }
+ 
        if (configGroup != null) {
-         serviceConfigVersionResponse.setGroupId(configGroup.getId());
          serviceConfigVersionResponse.setGroupName(configGroup.getName());
+       } else {
+         serviceConfigVersionResponse.setGroupName("deleted");
        }
+     } else {
+       serviceConfigVersionResponse.setGroupId(-1L); // -1 if no group
+       serviceConfigVersionResponse.setGroupName("default");
      }
  
- 
      return serviceConfigVersionResponse;
    }
  


[29/50] [abbrv] git commit: AMBARI-7410. Alerts: add aggregate type and processing (ncole)

Posted by jo...@apache.org.
AMBARI-7410. Alerts: add aggregate type and processing (ncole)


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

Branch: refs/heads/trunk
Commit: 179290e0fc5370b9d46a18d5ba9d187d6c1112c8
Parents: ba325d0
Author: Nate Cole <nc...@hortonworks.com>
Authored: Fri Sep 19 10:55:54 2014 -0400
Committer: Nate Cole <nc...@hortonworks.com>
Committed: Fri Sep 19 10:56:10 2014 -0400

----------------------------------------------------------------------
 .../server/api/services/AmbariMetaInfo.java     |  22 ++-
 .../AlertDefinitionResourceProvider.java        |  11 +-
 .../listeners/AlertAggregateListener.java       | 144 +++++++++++++++
 .../events/listeners/AlertReceivedListener.java |  14 +-
 .../apache/ambari/server/orm/dao/AlertsDAO.java |  52 ++++++
 .../server/orm/entities/AlertCurrentEntity.java |   1 +
 .../orm/entities/AlertDefinitionEntity.java     |  14 +-
 .../state/alert/AlertDefinitionFactory.java     |   2 +-
 .../ambari/server/state/alert/MetricSource.java |  46 ++++-
 .../stacks/HDP/2.0.6/services/HBASE/alerts.json |   4 +-
 .../stacks/HDP/2.0.6/services/HDFS/alerts.json  |  30 +++-
 .../server/api/services/AmbariMetaInfoTest.java |   4 +-
 .../AlertDefinitionResourceProviderTest.java    |   4 +-
 .../AlertGroupResourceProviderTest.java         |   2 +-
 .../apache/ambari/server/orm/OrmTestHelper.java |   3 +-
 .../server/orm/dao/AlertDefinitionDAOTest.java  |   9 +-
 .../server/orm/dao/AlertDispatchDAOTest.java    |   3 +-
 .../ambari/server/orm/dao/AlertsDAOTest.java    |  83 ++++++++-
 .../state/cluster/AlertDataManagerTest.java     | 174 ++++++++++++++++++-
 .../stacks/HDP/2.0.5/services/HDFS/alerts.json  |  19 +-
 20 files changed, 592 insertions(+), 49 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/179290e0/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
index e3e5779..ec53afc 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
@@ -31,7 +31,6 @@ import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Scanner;
 import java.util.Set;
 import java.util.concurrent.ExecutorService;
@@ -48,6 +47,7 @@ import org.apache.ambari.server.api.util.StackExtensionHelper;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.customactions.ActionDefinition;
 import org.apache.ambari.server.customactions.ActionDefinitionManager;
+import org.apache.ambari.server.events.listeners.AlertAggregateListener;
 import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
 import org.apache.ambari.server.orm.dao.MetainfoDAO;
 import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
@@ -66,6 +66,7 @@ import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.StackInfo;
 import org.apache.ambari.server.state.alert.AlertDefinition;
 import org.apache.ambari.server.state.alert.AlertDefinitionFactory;
+import org.apache.ambari.server.state.alert.SourceType;
 import org.apache.ambari.server.state.stack.LatestRepoCallable;
 import org.apache.ambari.server.state.stack.MetricDefinition;
 import org.apache.ambari.server.state.stack.RepositoryXml;
@@ -1205,9 +1206,7 @@ public class AmbariMetaInfo {
     }
 
     // for every cluster
-    Set<Entry<String, Cluster>> clusterEntries = clusterMap.entrySet();
-    for (Entry<String, Cluster> clusterEntry : clusterEntries) {
-      Cluster cluster = clusterEntry.getValue();
+    for (Cluster cluster : clusterMap.values()) {
       long clusterId = cluster.getClusterId();
       StackId stackId = cluster.getDesiredStackVersion();
       StackInfo stackInfo = getStackInfo(stackId.getStackName(),
@@ -1246,7 +1245,7 @@ public class AmbariMetaInfo {
       List<AlertDefinitionEntity> persist = new ArrayList<AlertDefinitionEntity>();
       List<AlertDefinitionEntity> entities = alertDefinitionDao.findAll(clusterId);
 
-      // create a map of the enntities for fast extraction
+      // create a map of the entities for fast extraction
       Map<String, AlertDefinitionEntity> mappedEntities = new HashMap<String, AlertDefinitionEntity>(100);
       for (AlertDefinitionEntity entity : entities) {
         mappedEntities.put(entity.getDefinitionName(), entity);
@@ -1279,9 +1278,20 @@ public class AmbariMetaInfo {
           LOG.info("Merging Alert Definition {} into the database",
               entity.getDefinitionName());
         }
-
         alertDefinitionDao.createOrUpdate(entity);
       }
+      
+      // all definitions have been resolved.  pull and initialize the aggregates
+      for (AlertDefinitionEntity def : alertDefinitionDao.findAll(cluster.getClusterId())) {
+        if (def.getSourceType().equals(SourceType.AGGREGATE)) {
+          AlertDefinition realDef = alertDefinitionFactory.coerce(def);
+          
+          AlertAggregateListener listener = injector.getInstance(AlertAggregateListener.class);
+          
+          listener.addAggregateType(cluster.getClusterId(), realDef); 
+        }
+      }
+      
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/179290e0/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java
index c63f063..7cb9886 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java
@@ -310,7 +310,7 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
     String definitionName = (String) requestMap.get(ALERT_DEF_NAME);
     String serviceName = (String) requestMap.get(ALERT_DEF_SERVICE_NAME);
     String componentName = (String) requestMap.get(ALERT_DEF_COMPONENT_NAME);
-    String sourceType = (String) requestMap.get(ALERT_DEF_SOURCE_TYPE);
+    String type = (String) requestMap.get(ALERT_DEF_SOURCE_TYPE);
     String label = (String) requestMap.get(ALERT_DEF_LABEL);
     String desiredScope = (String) requestMap.get(ALERT_DEF_SCOPE);
 
@@ -330,6 +330,11 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
     if (null != desiredScope && desiredScope.length() > 0) {
       scope = Scope.valueOf(desiredScope);
     }
+    
+    SourceType sourceType = null;
+    if (null != type && type.length() > 0) {
+      sourceType = SourceType.valueOf(type);
+    }
 
     // if not specified when creating an alert definition, the scope is
     // assumed to be ANY
@@ -354,7 +359,7 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
       throw new IllegalArgumentException("Service name must be specified");
     }
 
-    if (bCreate && StringUtils.isEmpty(sourceType)) {
+    if (bCreate && null == sourceType) {
       throw new IllegalArgumentException(String.format(
           "Source type must be specified and one of %s",
           EnumSet.allOf(SourceType.class)));
@@ -439,7 +444,7 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
     }
 
     if (null != enabled) {
-      entity.setEnabled(enabled);
+      entity.setEnabled(enabled.booleanValue());
     }
 
     if (null != interval) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/179290e0/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertAggregateListener.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertAggregateListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertAggregateListener.java
new file mode 100644
index 0000000..8340c26
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertAggregateListener.java
@@ -0,0 +1,144 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.events.listeners;
+
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.ambari.server.events.AlertReceivedEvent;
+import org.apache.ambari.server.events.publishers.AlertEventPublisher;
+import org.apache.ambari.server.orm.dao.AlertSummaryDTO;
+import org.apache.ambari.server.orm.dao.AlertsDAO;
+import org.apache.ambari.server.state.Alert;
+import org.apache.ambari.server.state.AlertState;
+import org.apache.ambari.server.state.alert.AggregateSource;
+import org.apache.ambari.server.state.alert.AlertDefinition;
+import org.apache.ambari.server.state.alert.Reporting;
+import org.apache.ambari.server.state.alert.Reporting.ReportTemplate;
+
+import com.google.common.eventbus.Subscribe;
+import com.google.inject.Inject;
+
+/**
+ * Used to aggregate alerts. 
+ */
+public class AlertAggregateListener {
+
+  @Inject
+  private AlertsDAO m_alertsDao = null;
+
+  private AlertEventPublisher m_publisher = null;
+  private Map<Long, Map<String, AlertDefinition>> m_aggregateMap = 
+      new HashMap<Long, Map<String, AlertDefinition>>();
+  
+  @Inject
+  public AlertAggregateListener(AlertEventPublisher publisher) {
+    m_publisher = publisher;
+
+    publisher.register(this);
+  }
+  
+  /**
+   * Consume an alert that was received.
+   */
+  @Subscribe
+  public void onAlertEvent(AlertReceivedEvent event) {
+    AlertDefinition def = getAggregateDefinition(event.getClusterId(), event.getAlert().getName());
+    
+    if (null == def || null == m_alertsDao) {
+      return;
+    }
+    
+    AggregateSource as = (AggregateSource) def.getSource();
+    
+    AlertSummaryDTO summary = m_alertsDao.findAggregateCounts(
+        event.getClusterId(), as.getAlertName());
+    
+    Alert alert = new Alert(def.getName(), null, def.getServiceName(),
+        null, null, AlertState.UNKNOWN);
+    alert.setLabel(def.getLabel());
+    alert.setTimestamp(System.currentTimeMillis());
+    
+    if (0 == summary.getOkCount()) {
+      alert.setText("Cannot determine, there are no records");
+    } else if (summary.getUnknownCount() > 0) {
+      alert.setText("There are alerts with status UNKNOWN.");
+    } else {
+      Reporting reporting = as.getReporting();
+      
+      int numerator = summary.getCriticalCount() + summary.getWarningCount();
+      int denominator = summary.getOkCount();
+      double value = (double)(numerator) / denominator;
+      
+      if (value > reporting.getCritical().getValue().doubleValue()) {
+        alert.setState(AlertState.CRITICAL);
+        alert.setText(MessageFormat.format(reporting.getCritical().getText(),
+            Integer.valueOf(denominator), Integer.valueOf(numerator)));
+        
+      } else if (value > reporting.getWarning().getValue().doubleValue()) {
+        alert.setState(AlertState.WARNING);
+        alert.setText(MessageFormat.format(reporting.getWarning().getText(),
+            Integer.valueOf(denominator), Integer.valueOf(numerator)));
+        
+      } else {
+        alert.setState(AlertState.OK);
+        alert.setText(MessageFormat.format(reporting.getOk().getText(),
+            Integer.valueOf(denominator), Integer.valueOf(numerator)));
+      }
+      
+    }
+    
+    // make a new event and allow others to consume it
+    AlertReceivedEvent aggEvent = new AlertReceivedEvent(event.getClusterId(), alert);
+    
+    m_publisher.publish(aggEvent);
+  }
+  
+  private AlertDefinition getAggregateDefinition(long clusterId, String name) {
+    Long id = Long.valueOf(clusterId);
+    if (!m_aggregateMap.containsKey(id))
+      return null;
+    
+    if (!m_aggregateMap.get(id).containsKey(name))
+      return null;
+    
+    return m_aggregateMap.get(id).get(name);
+  }
+
+  /**
+   * @param source the aggregate source
+   */
+  public void addAggregateType(long clusterId, AlertDefinition definition) {
+    Long id = Long.valueOf(clusterId);
+    
+    if (!m_aggregateMap.containsKey(id)) {
+      m_aggregateMap.put(id, new HashMap<String, AlertDefinition>());
+    }
+    
+    Map<String, AlertDefinition> map = m_aggregateMap.get(id);
+    
+    AggregateSource as = (AggregateSource) definition.getSource();
+    
+    map.put(as.getAlertName(), definition);
+  }
+  
+  
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/179290e0/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java
index 0f1b49a..fb7a608 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java
@@ -85,9 +85,15 @@ public class AlertReceivedListener {
     long clusterId = event.getClusterId();
     Alert alert = event.getAlert();
 
-    AlertCurrentEntity current = m_alertsDao.findCurrentByHostAndName(clusterId,
-        alert.getHost(), alert.getName());
-
+    AlertCurrentEntity current = null;
+    
+    if (null == alert.getHost()) {
+      current = m_alertsDao.findCurrentByNameNoHost(clusterId, alert.getName());
+    } else {
+      current = m_alertsDao.findCurrentByHostAndName(clusterId, alert.getHost(),
+          alert.getName());
+    }
+    
     if (null == current) {
       AlertDefinitionEntity definition = m_definitionDao.findByName(clusterId,
           alert.getName());
@@ -122,7 +128,7 @@ public class AlertReceivedListener {
       current.setOriginalTimestamp(Long.valueOf(alert.getTimestamp()));
 
       m_alertsDao.merge(current);
-
+      
       // broadcast the alert changed event for other subscribers
       AlertStateChangeEvent alertChangedEvent = new AlertStateChangeEvent(
           event.getClusterId(), event.getAlert(), current.getAlertHistory(),

http://git-wip-us.apache.org/repos/asf/ambari/blob/179290e0/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 a274089..aba41a5 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
@@ -457,5 +457,57 @@ public class AlertsDAO {
   public void remove(AlertCurrentEntity alert) {
     entityManagerProvider.get().remove(merge(alert));
   }
+  
+  /**
+   * Finds the aggregate counts for an alert name, across all hosts. 
+   * @param clusterId the cluster id
+   * @param alertName the name of the alert to find the aggregate
+   * @return the summary data
+   */
+  @RequiresSession
+  public AlertSummaryDTO findAggregateCounts(long clusterId, String alertName) {
+    StringBuilder sb = new StringBuilder();
+    sb.append("SELECT NEW %s (");
+    sb.append("COUNT(history), ");
+    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.WARNING.name(),
+        AlertState.class.getName(), AlertState.CRITICAL.name(),
+        AlertState.class.getName(), AlertState.UNKNOWN.name());
+    
+    TypedQuery<AlertSummaryDTO> query = entityManagerProvider.get().createQuery(
+        str, AlertSummaryDTO.class);
+    
+    query.setParameter("clusterId", Long.valueOf(clusterId));
+    query.setParameter("definitionName", alertName);
+    
+    return daoUtils.selectSingle(query);    
+  }
+  
+  /**
+   * Locate the current alert for the provided service and alert name, but when
+   * host is not set ({@code IS NULL}).
+   * @param clusterId the cluster id
+   * @param serviceName the service name
+   * @param alertName the name of the alert
+   * @return the current record, or {@code null} if not found
+   */
+  @RequiresSession
+  public AlertCurrentEntity findCurrentByNameNoHost(long clusterId, String alertName) {
+    
+    TypedQuery<AlertCurrentEntity> query = entityManagerProvider.get().createNamedQuery(
+        "AlertCurrentEntity.findByNameAndNoHost", AlertCurrentEntity.class);
+
+    query.setParameter("clusterId", Long.valueOf(clusterId));
+    query.setParameter("definitionName", alertName);
+
+    return daoUtils.selectOne(query);
+  }
 
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/179290e0/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 c24ac17..5b54d57 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
@@ -51,6 +51,7 @@ import org.apache.ambari.server.state.MaintenanceState;
     @NamedQuery(name = "AlertCurrentEntity.findByService", query = "SELECT alert FROM AlertCurrentEntity alert JOIN alert.alertHistory history WHERE history.clusterId = :clusterId AND history.serviceName = :serviceName AND history.alertDefinition.scope IN :inlist"),
     @NamedQuery(name = "AlertCurrentEntity.findByHost", query = "SELECT alert FROM AlertCurrentEntity alert JOIN alert.alertHistory history WHERE history.clusterId = :clusterId AND history.hostName = :hostName AND history.alertDefinition.scope IN :inlist"),
     @NamedQuery(name = "AlertCurrentEntity.findByHostAndName", query = "SELECT alert FROM AlertCurrentEntity alert JOIN alert.alertHistory history WHERE history.clusterId = :clusterId AND history.alertDefinition.definitionName = :definitionName AND history.hostName = :hostName"),
+    @NamedQuery(name = "AlertCurrentEntity.findByNameAndNoHost", query = "SELECT alert FROM AlertCurrentEntity alert JOIN alert.alertHistory history WHERE history.clusterId = :clusterId AND history.alertDefinition.definitionName = :definitionName AND history.hostName IS NULL"),
     @NamedQuery(name = "AlertCurrentEntity.removeByHistoryId", query = "DELETE FROM AlertCurrentEntity alert WHERE alert.alertHistory.alertId = :historyId"),
     @NamedQuery(name = "AlertCurrentEntity.removeByDefinitionId", query = "DELETE FROM AlertCurrentEntity alert WHERE alert.alertDefinition.definitionId = :definitionId") })
 public class AlertCurrentEntity {

http://git-wip-us.apache.org/repos/asf/ambari/blob/179290e0/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertDefinitionEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertDefinitionEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertDefinitionEntity.java
index b4b8a44..8548fda 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertDefinitionEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertDefinitionEntity.java
@@ -43,6 +43,7 @@ import javax.persistence.TableGenerator;
 import javax.persistence.UniqueConstraint;
 
 import org.apache.ambari.server.state.alert.Scope;
+import org.apache.ambari.server.state.alert.SourceType;
 
 /**
  * The {@link AlertDefinitionEntity} class is used to model an alert that needs
@@ -106,7 +107,8 @@ public class AlertDefinitionEntity {
   private String serviceName;
 
   @Column(name = "source_type", nullable = false, length = 255)
-  private String sourceType;
+  @Enumerated(value = EnumType.STRING)
+  private SourceType sourceType;
 
   /**
    * Bi-directional many-to-many association to {@link AlertGroupEntity}
@@ -266,7 +268,7 @@ public class AlertDefinitionEntity {
    *         otherwise.
    */
   public boolean getEnabled() {
-    return enabled == 0 ? false : true;
+    return enabled == Integer.valueOf(0) ? false : true;
   }
 
   /**
@@ -277,7 +279,7 @@ public class AlertDefinitionEntity {
    *          otherwise.
    */
   public void setEnabled(boolean enabled) {
-    this.enabled = enabled ? 1 : 0;
+    this.enabled = enabled ? Integer.valueOf(1) : Integer.valueOf(0);
   }
 
   /**
@@ -344,16 +346,14 @@ public class AlertDefinitionEntity {
   /**
    * @return
    */
-  // !!! FIXME: Create enumeration for this
-  public String getSourceType() {
+  public SourceType getSourceType() {
     return sourceType;
   }
 
   /**
    * @param sourceType
    */
-  // !!! FIXME: Create enumeration for this
-  public void setSourceType(String sourceType) {
+  public void setSourceType(SourceType sourceType) {
     this.sourceType = sourceType;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/179290e0/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionFactory.java
index f16f4a6..f8e44bd 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionFactory.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionFactory.java
@@ -203,7 +203,7 @@ public class AlertDefinitionFactory {
     entity.setScope(scope);
 
     Source source = definition.getSource();
-    entity.setSourceType(source.getType().name());
+    entity.setSourceType(source.getType());
 
     try {
       String sourceJson = m_gson.toJson(source);

http://git-wip-us.apache.org/repos/asf/ambari/blob/179290e0/ambari-server/src/main/java/org/apache/ambari/server/state/alert/MetricSource.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/MetricSource.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/MetricSource.java
index 530c1bb..15351d9 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/MetricSource.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/MetricSource.java
@@ -17,6 +17,10 @@
  */
 package org.apache.ambari.server.state.alert;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
 import com.google.gson.annotations.SerializedName;
 
 /**
@@ -31,7 +35,7 @@ public class MetricSource extends Source {
   private String m_uri = null;
   
   @SerializedName("jmx")
-  private Object jmxInfo = null;
+  private JmxInfo jmxInfo = null;
 
   @SerializedName("ganglia")
   private String gangliaInfo = null;
@@ -39,7 +43,7 @@ public class MetricSource extends Source {
   /**
    * @return the jmx info, if this metric is jmx-based
    */
-  public Object getJmxInfo() {
+  public JmxInfo getJmxInfo() {
     return jmxInfo;
   }
 
@@ -116,4 +120,42 @@ public class MetricSource extends Source {
 
     return true;
   }
+  
+  /**
+   * Represents the {@code jmx} element in a Metric alert.
+   */
+  public static class JmxInfo {
+    @SerializedName("property_list")
+    private List<String> propertyList;
+    
+    private String value;
+    
+    public List<String> getPropertyList() {
+      return propertyList;
+    }
+    
+    public String getValue() {
+      return value;
+    }
+    
+    @Override
+    public boolean equals(Object object) {
+      if (!JmxInfo.class.isInstance(object)) {
+        return false;
+      }
+      
+      JmxInfo other = (JmxInfo)object;
+      
+      List<String> list1 = new ArrayList<String>(propertyList);
+      List<String> list2 = new ArrayList<String>(other.propertyList);
+      
+      if ((null == list1 && null != list2) || (null != list1 && null == list2)) {
+        return false;
+      }
+      
+      // !!! even if out of order, this is enough to fail
+      return list1.equals(list2);
+      
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/179290e0/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HBASE/alerts.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HBASE/alerts.json b/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HBASE/alerts.json
index 3958106..2e21aad 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HBASE/alerts.json
+++ b/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HBASE/alerts.json
@@ -5,7 +5,7 @@
       "name": "hbase_master_process",
       "label": "HBase Master Process",
       "interval": 1,
-      "scope": "any",
+      "scope": "ANY",
       "source": {
         "type": "PORT",
         "uri": "{{hbase-site/hbase.master.port}}",
@@ -21,4 +21,4 @@
       }
     }
   ]
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/179290e0/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HDFS/alerts.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HDFS/alerts.json b/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HDFS/alerts.json
index 00286b1..88503af 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HDFS/alerts.json
+++ b/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HDFS/alerts.json
@@ -1,11 +1,35 @@
 {
-  "service": [],
+  "service": [
+    {
+      "name": "percent_datanode",
+      "label": "Percent DataNodes live",
+      "interval": 1,
+      "scope": "SERVICE",
+      "source": {
+        "type": "AGGREGATE",
+        "alert_name": "datanode_process",
+        "reporting": {
+          "ok": {
+            "text": "OK: total: <{0}>, affected: <{1}>"
+          },
+          "warning": {
+            "text": "OK: total: <{0}>, affected: <{1}>",
+            "value": 0.1
+          },
+          "critical": {
+            "text": "CRITICAL: total: <{0}>, affected <{1}>",
+            "value": 0.3
+          }
+        }
+      }
+    }
+  ],
   "NAMENODE": [
     {
       "name": "namenode_process",
       "label": "NameNode Process",
       "interval": 1,
-      "scope": "any",
+      "scope": "ANY",
       "source": {
         "type": "PORT",
         "uri": "{{hdfs-site/dfs.namenode.http-address}}",
@@ -24,7 +48,7 @@
       "name": "check_cpu",
       "label": "NameNode host CPU utilization",
       "interval": 2,
-      "scope": "any",
+      "scope": "ANY",
       "source": {
         "type": "METRIC",
         "uri": "{{hdfs-site/dfs.namenode.http-address}}",

http://git-wip-us.apache.org/repos/asf/ambari/blob/179290e0/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
index 66c0b3d..23d0efa 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
@@ -1530,7 +1530,7 @@ public class AmbariMetaInfoTest {
     expect(cluster.getClusterId()).andReturn(Long.valueOf(1)).anyTimes();
     expect(cluster.getDesiredStackVersion()).andReturn(stackId).anyTimes();
     expect(cluster.getServices()).andReturn(clusterServiceMap).anyTimes();
-    expect(dao.findAll(EasyMock.anyInt())).andReturn(entities);
+    expect(dao.findAll(EasyMock.anyInt())).andReturn(entities).atLeastOnce();
     dao.createOrUpdate(EasyMock.anyObject(AlertDefinitionEntity.class));
     EasyMock.expectLastCall().times(4);
 
@@ -1549,7 +1549,7 @@ public class AmbariMetaInfoTest {
     expect(cluster.getClusterId()).andReturn(Long.valueOf(1)).anyTimes();
     expect(cluster.getDesiredStackVersion()).andReturn(stackId).anyTimes();
     expect(cluster.getServices()).andReturn(clusterServiceMap).anyTimes();
-    expect(dao.findAll(EasyMock.anyInt())).andReturn(entities);
+    expect(dao.findAll(EasyMock.anyInt())).andReturn(entities).atLeastOnce();
 
     EasyMock.replay(clusters, cluster, dao);
     metaInfo.reconcileAlertDefinitions(clusters);

http://git-wip-us.apache.org/repos/asf/ambari/blob/179290e0/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProviderTest.java
index 7ea2ffe..78655dd 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProviderTest.java
@@ -264,7 +264,7 @@ public class AlertDefinitionResourceProviderTest {
     Assert.assertEquals(Integer.valueOf(1), entity.getScheduleInterval());
     Assert.assertEquals(Scope.ANY, entity.getScope());
     Assert.assertEquals("HDFS", entity.getServiceName());
-    Assert.assertEquals("METRIC", entity.getSourceType());
+    Assert.assertEquals(SourceType.METRIC, entity.getSourceType());
     Assert.assertEquals("Mock Label (Create)", entity.getLabel());
 
     // verify Source
@@ -474,7 +474,7 @@ public class AlertDefinitionResourceProviderTest {
     entity.setHash(DEFINITION_UUID);
     entity.setScheduleInterval(Integer.valueOf(2));
     entity.setServiceName(null);
-    entity.setSourceType(SourceType.METRIC.name());
+    entity.setSourceType(SourceType.METRIC);
     entity.setSource(sourceJson);
     return Arrays.asList(entity);
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/179290e0/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java
index ddfc75a..d2ce6fb 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java
@@ -478,7 +478,7 @@ public class AlertGroupResourceProviderTest {
     entity.setHash(DEFINITION_UUID);
     entity.setScheduleInterval(Integer.valueOf(2));
     entity.setServiceName(null);
-    entity.setSourceType(SourceType.METRIC.name());
+    entity.setSourceType(SourceType.METRIC);
     entity.setSource(null);
 
     Set<AlertDefinitionEntity> definitions = new HashSet<AlertDefinitionEntity>();

http://git-wip-us.apache.org/repos/asf/ambari/blob/179290e0/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java b/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
index a9d126c..08cd7b8 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
@@ -61,6 +61,7 @@ import org.apache.ambari.server.orm.entities.StageEntity;
 import org.apache.ambari.server.orm.entities.UserEntity;
 import org.apache.ambari.server.state.HostState;
 import org.apache.ambari.server.state.alert.Scope;
+import org.apache.ambari.server.state.alert.SourceType;
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.util.Assert;
 
@@ -330,7 +331,7 @@ public class OrmTestHelper {
     definition.setScheduleInterval(60);
     definition.setScope(Scope.SERVICE);
     definition.setSource("Source " + System.currentTimeMillis());
-    definition.setSourceType("SCRIPT");
+    definition.setSourceType(SourceType.SCRIPT);
 
     alertDefinitionDAO.create(definition);
     return alertDefinitionDAO.findById(definition.getDefinitionId());

http://git-wip-us.apache.org/repos/asf/ambari/blob/179290e0/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
index cdca3dd..3e20cd6 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
@@ -45,6 +45,7 @@ import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.MaintenanceState;
 import org.apache.ambari.server.state.NotificationState;
 import org.apache.ambari.server.state.alert.Scope;
+import org.apache.ambari.server.state.alert.SourceType;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -97,7 +98,7 @@ public class AlertDefinitionDAOTest {
       definition.setScheduleInterval(60);
       definition.setScope(Scope.SERVICE);
       definition.setSource("Source " + i);
-      definition.setSourceType("SCRIPT");
+      definition.setSourceType(SourceType.SCRIPT);
       dao.create(definition);
     }
 
@@ -118,7 +119,7 @@ public class AlertDefinitionDAOTest {
       definition.setScheduleInterval(60);
       definition.setScope(Scope.SERVICE);
       definition.setSource("Source " + i);
-      definition.setSourceType("SCRIPT");
+      definition.setSourceType(SourceType.SCRIPT);
       dao.create(definition);
     }
 
@@ -133,7 +134,7 @@ public class AlertDefinitionDAOTest {
       definition.setScheduleInterval(60);
       definition.setScope(Scope.HOST);
       definition.setSource("Source " + i);
-      definition.setSourceType("SCRIPT");
+      definition.setSourceType(SourceType.SCRIPT);
       dao.create(definition);
     }
 
@@ -148,7 +149,7 @@ public class AlertDefinitionDAOTest {
       definition.setScheduleInterval(60);
       definition.setScope(Scope.HOST);
       definition.setSource("Source " + i);
-      definition.setSourceType("SCRIPT");
+      definition.setSourceType(SourceType.SCRIPT);
       dao.create(definition);
     }
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/179290e0/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDispatchDAOTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDispatchDAOTest.java b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDispatchDAOTest.java
index 2c3a876..7f4deda 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDispatchDAOTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDispatchDAOTest.java
@@ -41,6 +41,7 @@ import org.apache.ambari.server.orm.entities.AlertTargetEntity;
 import org.apache.ambari.server.state.AlertState;
 import org.apache.ambari.server.state.NotificationState;
 import org.apache.ambari.server.state.alert.Scope;
+import org.apache.ambari.server.state.alert.SourceType;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -431,7 +432,7 @@ public class AlertDispatchDAOTest {
       definition.setScheduleInterval(60);
       definition.setScope(Scope.SERVICE);
       definition.setSource("Source " + i);
-      definition.setSourceType("SCRIPT");
+      definition.setSourceType(SourceType.SCRIPT);
       definitionDao.create(definition);
     }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/179290e0/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 a397da4..9e638e8 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
@@ -40,6 +40,7 @@ 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.apache.ambari.server.state.alert.SourceType;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -84,7 +85,7 @@ public class AlertsDAOTest {
       definition.setScheduleInterval(Integer.valueOf(60));
       definition.setScope(Scope.SERVICE);
       definition.setSource("Source " + i);
-      definition.setSourceType("SCRIPT");
+      definition.setSourceType(SourceType.SCRIPT);
       definitionDao.create(definition);
     }
     
@@ -208,7 +209,7 @@ public class AlertsDAOTest {
     hostDef.setScheduleInterval(Integer.valueOf(60));
     hostDef.setScope(Scope.HOST);
     hostDef.setSource("HostService");
-    hostDef.setSourceType("SCRIPT");
+    hostDef.setSourceType(SourceType.SCRIPT);
     definitionDao.create(hostDef);
     
     // history for the definition
@@ -395,5 +396,83 @@ public class AlertsDAOTest {
     assertEquals(0, summary.getCriticalCount());
     assertEquals(0, summary.getCriticalCount());
     
+  }
+  
+  @Test
+  public void testFindAggregates() throws Exception {
+    // definition
+    AlertDefinitionEntity definition = new AlertDefinitionEntity();
+    definition.setDefinitionName("many_per_cluster");
+    definition.setServiceName("ServiceName");
+    definition.setComponentName(null);
+    definition.setClusterId(clusterId);
+    definition.setHash(UUID.randomUUID().toString());
+    definition.setScheduleInterval(Integer.valueOf(60));
+    definition.setScope(Scope.SERVICE);
+    definition.setSource("SourceScript");
+    definition.setSourceType(SourceType.SCRIPT);
+    definitionDao.create(definition);
+    
+    // history record #1 and current
+    AlertHistoryEntity history = new AlertHistoryEntity();
+    history.setAlertDefinition(definition);
+    history.setAlertInstance(null);
+    history.setAlertLabel("");
+    history.setAlertState(AlertState.OK);
+    history.setAlertText("");
+    history.setAlertTimestamp(Long.valueOf(1L));
+    history.setClusterId(clusterId);
+    history.setComponentName("");
+    history.setHostName("h1");
+    history.setServiceName("ServiceName");
+    
+    AlertCurrentEntity current = new AlertCurrentEntity();
+    current.setAlertHistory(history);
+    current.setLatestTimestamp(Long.valueOf(1L));
+    current.setOriginalTimestamp(Long.valueOf(1L));
+    dao.merge(current);
+    
+    // history record #2 and current
+    history = new AlertHistoryEntity();
+    history.setAlertDefinition(definition);
+    history.setAlertInstance(null);
+    history.setAlertLabel("");
+    history.setAlertState(AlertState.OK);
+    history.setAlertText("");
+    history.setAlertTimestamp(Long.valueOf(1L));
+    history.setClusterId(clusterId);
+    history.setComponentName("");
+    history.setHostName("h2");
+    history.setServiceName("ServiceName");
+    
+    current = new AlertCurrentEntity();
+    current.setAlertHistory(history);
+    current.setLatestTimestamp(Long.valueOf(1L));
+    current.setOriginalTimestamp(Long.valueOf(1L));
+    dao.merge(current);
+    
+    AlertSummaryDTO summary = dao.findAggregateCounts(clusterId.longValue(), "many_per_cluster");
+    assertEquals(2, summary.getOkCount());
+    assertEquals(0, summary.getWarningCount());
+    assertEquals(0, summary.getCriticalCount());
+    assertEquals(0, summary.getUnknownCount());
+    
+    AlertCurrentEntity c = dao.findCurrentByHostAndName(clusterId.longValue(),
+        "h2", "many_per_cluster");
+    AlertHistoryEntity h = c.getAlertHistory();
+    h.setAlertState(AlertState.CRITICAL);
+    dao.merge(h);
+    
+    summary = dao.findAggregateCounts(clusterId.longValue(), "many_per_cluster");
+    assertEquals(2, summary.getOkCount());
+    assertEquals(0, summary.getWarningCount());
+    assertEquals(1, summary.getCriticalCount());
+    assertEquals(0, summary.getUnknownCount());
+    
+    summary = dao.findAggregateCounts(clusterId.longValue(), "foo");
+    assertEquals(0, summary.getOkCount());
+    assertEquals(0, summary.getWarningCount());
+    assertEquals(0, summary.getCriticalCount());
+    assertEquals(0, summary.getUnknownCount());
   }  
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/179290e0/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java
index bbf7774..00ba942 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java
@@ -20,17 +20,22 @@ package org.apache.ambari.server.state.cluster;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
+import java.lang.reflect.Field;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.UUID;
+import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.ambari.server.events.AlertEvent;
 import org.apache.ambari.server.events.AlertReceivedEvent;
 import org.apache.ambari.server.events.AlertStateChangeEvent;
+import org.apache.ambari.server.events.listeners.AlertAggregateListener;
 import org.apache.ambari.server.events.listeners.AlertReceivedListener;
 import org.apache.ambari.server.events.listeners.AlertStateChangedListener;
+import org.apache.ambari.server.events.publishers.AlertEventPublisher;
 import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
 import org.apache.ambari.server.orm.OrmTestHelper;
@@ -45,15 +50,25 @@ import org.apache.ambari.server.orm.entities.AlertNoticeEntity;
 import org.apache.ambari.server.orm.entities.AlertTargetEntity;
 import org.apache.ambari.server.state.Alert;
 import org.apache.ambari.server.state.AlertState;
+import org.apache.ambari.server.state.alert.AggregateSource;
+import org.apache.ambari.server.state.alert.AlertDefinitionFactory;
+import org.apache.ambari.server.state.alert.Reporting;
+import org.apache.ambari.server.state.alert.Reporting.ReportTemplate;
 import org.apache.ambari.server.state.alert.Scope;
+import org.apache.ambari.server.state.alert.Source;
+import org.apache.ambari.server.state.alert.SourceType;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
+import com.google.common.eventbus.EventBus;
+import com.google.common.eventbus.Subscribe;
+import com.google.gson.Gson;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.persist.PersistService;
 
+
 /**
  * Tests the management of {@link AlertEvent}s in the system.
  */
@@ -94,7 +109,7 @@ public class AlertDataManagerTest {
       definition.setScheduleInterval(Integer.valueOf(60));
       definition.setScope(Scope.SERVICE);
       definition.setSource("Source " + i);
-      definition.setSourceType("SCRIPT");
+      definition.setSourceType(SourceType.SCRIPT);
       definitionDao.create(definition);
     }
   }
@@ -253,4 +268,161 @@ public class AlertDataManagerTest {
     notices = dispatchDao.findAllNotices();
     assertEquals(1, notices.size());
   }
+  
+  @Test
+  public void testAggregateAlerts() throws Exception {
+    // create definition
+    AlertDefinitionEntity definition = new AlertDefinitionEntity();
+    definition.setDefinitionName("to_aggregate");
+    definition.setLabel("My Label");
+    definition.setServiceName("SERVICE");
+    definition.setComponentName(null);
+    definition.setClusterId(clusterId);
+    definition.setHash(UUID.randomUUID().toString());
+    definition.setScheduleInterval(Integer.valueOf(60));
+    definition.setScope(Scope.HOST);
+    definition.setSource("Source");
+    definition.setSourceType(SourceType.SCRIPT);
+    definitionDao.create(definition);
+    
+    // create aggregate of definition
+    AlertDefinitionEntity aggDef = new AlertDefinitionEntity();
+    aggDef.setDefinitionName("aggregate_test");
+    aggDef.setServiceName("SERVICE");
+    aggDef.setComponentName(null);
+    aggDef.setClusterId(clusterId);
+    aggDef.setHash(UUID.randomUUID().toString());
+    aggDef.setScheduleInterval(Integer.valueOf(60));
+    aggDef.setScope(Scope.SERVICE);
+    
+    AggregateSource source = new AggregateSource();
+
+    source.setAlertName("to_aggregate");
+    // !!! type is protected
+    Field field = Source.class.getDeclaredField("type");
+    field.setAccessible(true);
+    field.set(source, SourceType.AGGREGATE);
+
+    Reporting reporting = new Reporting();
+    
+    ReportTemplate template = new ReportTemplate();
+    template.setText("You are good {1}/{0}");
+    reporting.setOk(template);
+
+    template = new ReportTemplate();
+    template.setText("Going bad {1}/{0}");
+    template.setValue(Double.valueOf(0.33d));
+    reporting.setWarning(template);
+    
+    template = new ReportTemplate();
+    template.setText("On fire! {1}/{0}");
+    template.setValue(Double.valueOf(0.66d));
+    reporting.setCritical(template);
+    
+    source.setReporting(reporting);
+
+    Gson gson = new Gson();
+    
+    aggDef.setSource(gson.toJson(source));
+    aggDef.setSourceType(SourceType.AGGREGATE);
+    definitionDao.create(aggDef);
+    
+    // add current and history across four hosts
+    for (int i = 0; i < 4; i++) {
+      AlertHistoryEntity history = new AlertHistoryEntity();
+      history.setAlertDefinition(definition);
+      history.setAlertInstance(null);
+      history.setAlertLabel(definition.getLabel());
+      history.setAlertState(AlertState.OK);
+      history.setAlertText("OK");
+      history.setAlertTimestamp(Long.valueOf(1));
+      history.setClusterId(clusterId);
+      history.setComponentName(definition.getComponentName());
+      history.setHostName("h" + (i+1));
+      history.setServiceName(definition.getServiceName());
+      dao.create(history);
+     
+      AlertCurrentEntity current = new AlertCurrentEntity();
+      current.setAlertHistory(history);
+      current.setLatestText(history.getAlertText());
+      current.setLatestTimestamp(Long.valueOf(1L));
+      current.setOriginalTimestamp(Long.valueOf(1L));
+      dao.merge(current);
+    }
+    
+    AlertEventPublisher publisher = injector.getInstance(AlertEventPublisher.class);
+
+    // !!! need a synchronous op for testing
+    field = AlertEventPublisher.class.getDeclaredField("m_eventBus");
+    field.setAccessible(true);
+    field.set(publisher, new EventBus());
+
+    final AtomicReference<Alert> ref = new AtomicReference<Alert>();    
+    publisher.register(new TestListener() {
+      @Subscribe
+      public void catchIt(AlertReceivedEvent event) {
+        ref.set(event.getAlert());
+      }
+    });
+    
+    AlertAggregateListener listener = injector.getInstance(AlertAggregateListener.class);
+    AlertDefinitionFactory factory = new AlertDefinitionFactory();
+    listener.addAggregateType(clusterId.longValue(), factory.coerce(aggDef));
+
+    // any alert and event will do that is for the definition since an aggregate
+    // checks them all regardless of state
+    Alert alert = new Alert(
+        definition.getDefinitionName(),
+        null,
+        definition.getServiceName(),
+        definition.getComponentName(),
+        "h1",
+        AlertState.OK);
+    AlertReceivedEvent event = new AlertReceivedEvent(clusterId.longValue(), alert);
+    
+    listener.onAlertEvent(event);
+    assertNotNull(ref.get());
+    assertEquals(AlertState.OK, ref.get().getState());
+    assertTrue(ref.get().getText().indexOf("0/4") > -1);
+    
+    // check if one is critical, still ok
+    AlertCurrentEntity current = dao.findCurrentByHostAndName(
+        clusterId.longValue(), "h1", definition.getDefinitionName());
+    current.getAlertHistory().setAlertState(AlertState.CRITICAL);
+    dao.merge(current.getAlertHistory());
+
+    listener.onAlertEvent(event);
+    assertEquals("aggregate_test", ref.get().getName());    
+    assertEquals(AlertState.OK, ref.get().getState());
+    assertTrue(ref.get().getText().indexOf("1/4") > -1);
+
+    // two are either warning or critical, warning
+    current = dao.findCurrentByHostAndName(
+        clusterId.longValue(), "h2", definition.getDefinitionName());
+    current.getAlertHistory().setAlertState(AlertState.WARNING);
+    dao.merge(current.getAlertHistory());
+    
+    listener.onAlertEvent(event);
+    assertEquals("aggregate_test", ref.get().getName());
+    assertEquals(AlertState.WARNING, ref.get().getState());
+    assertTrue(ref.get().getText().indexOf("2/4") > -1);
+
+    // three make it critical
+    current = dao.findCurrentByHostAndName(
+        clusterId.longValue(), "h3", definition.getDefinitionName());
+    current.getAlertHistory().setAlertState(AlertState.CRITICAL);
+    dao.merge(current.getAlertHistory());
+    
+    listener.onAlertEvent(event);
+    assertEquals("aggregate_test", ref.get().getName());    
+    assertEquals(AlertState.CRITICAL, ref.get().getState());
+    assertTrue(ref.get().getText().indexOf("3/4") > -1);
+  }
+  
+  /**
+   * Test interface collects aggregate alert invocations 
+   */
+  private static interface TestListener {
+    public void catchIt(AlertReceivedEvent event);
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/179290e0/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/alerts.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/alerts.json b/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/alerts.json
index f4a3001..0077bad 100644
--- a/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/alerts.json
+++ b/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/alerts.json
@@ -1,13 +1,18 @@
 {
-  "service": [],
+  "service": [
+  ],
   "NAMENODE": [
     {
       "name": "namenode_cpu",
       "label": "NameNode host CPU Utilization",
-      "scope": "host",
+      "scope": "ANY",
       "source": {
         "type": "METRIC",
-        "jmx": "java.lang:type=OperatingSystem/SystemCpuLoad",
+        "jmx": {
+          "property_list": [
+            "java.lang:type=OperatingSystem/SystemCpuLoad"
+          ]
+        },
         "host": "{{hdfs-site/dfs.namenode.secondary.http-address}}",
         "reporting": {
           "ok": {
@@ -28,7 +33,7 @@
       "name": "namenode_process",
       "label": "NameNode process",
       "interval": 1,
-      "scope": "any",
+      "scope": "ANY",
       "source": {
         "type": "PORT",
         "uri": "{{hdfs-site/dfs.namenode.http-address}}",
@@ -47,7 +52,7 @@
       "name": "hdfs_last_checkpoint",
       "label": "Last Checkpoint Time",
       "interval": 1,
-      "scope": "service",
+      "SCOPE": "service",
       "enabled": false,
       "source": {
         "type": "SCRIPT",
@@ -60,7 +65,7 @@
       "name": "secondary_namenode_process",
       "label": "Secondary NameNode process",
       "interval": 1,
-      "scope": "any",
+      "scope": "ANY",
       "source": {
         "type": "PORT",        
         "uri": "{{hdfs-site/dfs.namenode.secondary.http-address}}",
@@ -69,4 +74,4 @@
     }
   ],  
   "DATANODE": []
-}
\ No newline at end of file
+}


[41/50] [abbrv] git commit: AMBARI-7540 - Alerts: Stack Alerts Should Not Be Merged Into the DB (jonathanhurley)

Posted by jo...@apache.org.
AMBARI-7540 - Alerts: Stack Alerts Should Not Be Merged Into the DB (jonathanhurley)


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

Branch: refs/heads/trunk
Commit: a42b727260fde066429347f640c4cb1958f712e3
Parents: f923fd8
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Mon Sep 29 11:06:22 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Mon Sep 29 12:17:53 2014 -0400

----------------------------------------------------------------------
 .../ambari_agent/dummy_files/definitions.json   |  2 +-
 .../server/api/services/AmbariMetaInfo.java     | 17 ++++++--
 .../stacks/HDP/2.0.6/services/HDFS/alerts.json  |  6 +++
 .../server/api/services/AmbariMetaInfoTest.java | 42 ++++++++++++++++++++
 4 files changed, 62 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/a42b7272/ambari-agent/src/test/python/ambari_agent/dummy_files/definitions.json
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/dummy_files/definitions.json b/ambari-agent/src/test/python/ambari_agent/dummy_files/definitions.json
index 8e01833..6e80dea 100644
--- a/ambari-agent/src/test/python/ambari_agent/dummy_files/definitions.json
+++ b/ambari-agent/src/test/python/ambari_agent/dummy_files/definitions.json
@@ -15,7 +15,7 @@
         "component": "NAMENODE",
         "label": "NameNode process",
         "interval": 6,
-        "scope": "host",
+        "scope": "HOST",
         "uuid": "3f82ae27-fa6a-465b-b77d-67963ac55d2f",
         "enabled": true,
         "source": {

http://git-wip-us.apache.org/repos/asf/ambari/blob/a42b7272/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
index c15f73b..28dd397 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
@@ -197,6 +197,7 @@ public class AmbariMetaInfo {
 
     alertDefinitionFactory = injector.getInstance(AlertDefinitionFactory.class);
     alertDefinitionDao = injector.getInstance(AlertDefinitionDAO.class);
+    eventPublisher = injector.getInstance(AmbariEventPublisher.class);
   }
 
   /**
@@ -1275,12 +1276,20 @@ public class AmbariMetaInfo {
           continue;
         }
 
-        // if the definition exists in the stack and the database and they are
-        // not deeply equal, then merge the stack definition into the database
+        // definitions from the stack that are altered will not be overwritten;
+        // use the REST APIs to modify them instead
         AlertDefinition databaseDefinition = alertDefinitionFactory.coerce(entity);
         if (!stackDefinition.deeplyEquals(databaseDefinition)) {
-          entity = alertDefinitionFactory.merge(stackDefinition, entity);
-          persist.add(entity);
+          // this is the code that would normally merge the stack definition
+          // into the database; this is not the behavior we want today
+
+          // entity = alertDefinitionFactory.merge(stackDefinition, entity);
+          // persist.add(entity);
+
+          LOG.debug(
+              "The alert named {} has been modified from the stack definition and will not be merged",
+              stackDefinition.getName());
+
           continue;
         }
       }

http://git-wip-us.apache.org/repos/asf/ambari/blob/a42b7272/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HDFS/alerts.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HDFS/alerts.json b/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HDFS/alerts.json
index 620c89f..d81170a 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HDFS/alerts.json
+++ b/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HDFS/alerts.json
@@ -5,6 +5,7 @@
       "label": "Percent DataNodes Live",
       "interval": 1,
       "scope": "SERVICE",
+      "enabled": true,
       "source": {
         "type": "AGGREGATE",
         "alert_name": "datanode_process",
@@ -30,6 +31,7 @@
       "label": "NameNode Process",
       "interval": 1,
       "scope": "ANY",
+      "enabled": true,
       "source": {
         "type": "PORT",
         "uri": "{{hdfs-site/dfs.namenode.http-address}}",
@@ -49,6 +51,7 @@
       "label": "NameNode host CPU utilization",
       "interval": 2,
       "scope": "ANY",
+      "enabled": true,
       "source": {
         "type": "METRIC",
         "uri": "{{hdfs-site/dfs.namenode.http-address}}",
@@ -81,6 +84,7 @@
       "label": "Secondary NameNode Process",
       "interval": 1,
       "scope": "any",
+      "enabled": true,
       "source": {
         "type": "PORT",        
         "uri": "{{hdfs-site/dfs.namenode.secondary.http-address}}",
@@ -102,6 +106,7 @@
       "label": "JournalNode Process",
       "interval": 1,
       "scope": "host",
+      "enabled": true,
       "source": {
         "type": "PORT",        
         "uri": "{{hdfs-site/dfs.journalnode.http-address}}",
@@ -123,6 +128,7 @@
       "label": "DateNode Process",
       "interval": 1,
       "scope": "host",
+      "enabled": true,
       "source": {
         "type": "PORT",        
         "uri": "{{hdfs-site/dfs.datanode.http.address}}",

http://git-wip-us.apache.org/repos/asf/ambari/blob/a42b7272/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
index 4c59a36..613b950 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
@@ -47,7 +47,12 @@ import org.apache.ambari.server.api.util.StackExtensionHelper;
 import org.apache.ambari.server.metadata.ActionMetadata;
 import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
+import org.apache.ambari.server.orm.OrmTestHelper;
+import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
+import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
 import org.apache.ambari.server.state.AutoDeployInfo;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.ComponentInfo;
 import org.apache.ambari.server.state.CustomCommandDefinition;
 import org.apache.ambari.server.state.DependencyInfo;
@@ -56,6 +61,7 @@ import org.apache.ambari.server.state.PropertyInfo;
 import org.apache.ambari.server.state.RepositoryInfo;
 import org.apache.ambari.server.state.ServiceInfo;
 import org.apache.ambari.server.state.Stack;
+import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.StackInfo;
 import org.apache.ambari.server.state.alert.AlertDefinition;
 import org.apache.ambari.server.state.alert.PortSource;
@@ -1617,6 +1623,42 @@ public class AmbariMetaInfoTest {
     assertNotNull(reporting.getWarning().getValue());
   }
 
+  /**
+   * Tests merging stack-based with existing definitions works
+   *
+   * @throws Exception
+   */
+  @Test
+  public void testAlertDefinitionMerging() throws Exception {
+    injector.getInstance(OrmTestHelper.class).createCluster();
+    Clusters clusters = injector.getInstance(Clusters.class);
+    Cluster cluster = clusters.getClusterById(1);
+    cluster.setDesiredStackVersion(
+        new StackId(STACK_NAME_HDP, "2.0.6"));
+
+    cluster.addService("HDFS");
+
+    metaInfo.reconcileAlertDefinitions(clusters);
+
+    AlertDefinitionDAO dao = injector.getInstance(AlertDefinitionDAO.class);
+    List<AlertDefinitionEntity> definitions = dao.findAll();
+    assertEquals(4, definitions.size());
+
+    for (AlertDefinitionEntity definition : definitions) {
+      definition.setScheduleInterval(28);
+      dao.merge(definition);
+    }
+
+    metaInfo.reconcileAlertDefinitions(clusters);
+
+    definitions = dao.findAll();
+    assertEquals(4, definitions.size());
+
+    for (AlertDefinitionEntity definition : definitions) {
+      assertEquals(28, definition.getScheduleInterval().intValue());
+    }
+  }
+
   private AmbariMetaInfo setupTempAmbariMetaInfo(String buildDir)
       throws Exception {
     File stackRootTmp = new File(buildDir + "/ambari-metaInfo");


[28/50] [abbrv] git commit: AMBARI-7391 - Alerts: Scan Database For Pending AlertNoticeEntity (jonathanhurley)

Posted by jo...@apache.org.
AMBARI-7391 - Alerts: Scan Database For Pending AlertNoticeEntity (jonathanhurley)


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

Branch: refs/heads/trunk
Commit: ba325d0831e9816992849490766e511450ef7f3a
Parents: f1018b1
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Thu Sep 18 11:20:44 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Thu Sep 18 15:21:26 2014 -0400

----------------------------------------------------------------------
 ambari-server/pom.xml                           |  10 +
 .../ambari/server/controller/AmbariServer.java  |  12 +
 .../server/controller/ControllerModule.java     |  22 ++
 .../events/listeners/AlertReceivedListener.java |   7 +-
 .../listeners/AlertServiceStateListener.java    |  20 +-
 .../listeners/AlertStateChangedListener.java    |   4 +-
 .../events/publishers/AlertEventPublisher.java  |  14 +-
 .../server/notifications/DispatchCallback.java  |  50 ++++
 .../server/notifications/DispatchFactory.java   |  62 +++++
 .../server/notifications/DispatchRunnable.java  |  60 +++++
 .../server/notifications/Notification.java      |  57 +++++
 .../notifications/NotificationDispatcher.java   |  47 ++++
 .../dispatchers/EmailDispatcher.java            |  60 +++++
 .../server/orm/dao/AlertDefinitionDAO.java      |  15 +-
 .../ambari/server/orm/dao/AlertDispatchDAO.java |  69 +++++-
 .../server/orm/entities/AlertCurrentEntity.java |  38 +--
 .../server/orm/entities/AlertGroupEntity.java   |   3 +-
 .../server/orm/entities/AlertNoticeEntity.java  |   2 +
 .../ambari/server/state/alert/TargetType.java   |  15 +-
 .../server/state/cluster/ClusterImpl.java       |   7 +-
 .../services/AlertNoticeDispatchService.java    | 231 +++++++++++++++++++
 .../apache/ambari/server/orm/OrmTestHelper.java |  37 +++
 .../server/orm/dao/AlertDefinitionDAOTest.java  |  11 +-
 .../server/orm/dao/AlertDispatchDAOTest.java    |  40 +++-
 24 files changed, 847 insertions(+), 46 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/ba325d08/ambari-server/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-server/pom.xml b/ambari-server/pom.xml
index b07afbf..d83db61 100644
--- a/ambari-server/pom.xml
+++ b/ambari-server/pom.xml
@@ -1418,6 +1418,16 @@
       <artifactId>velocity</artifactId>
       <version>1.7</version>
     </dependency>
+    <dependency>
+      <groupId>com.sun.mail</groupId>
+      <artifactId>mailapi</artifactId>
+      <version>1.5.2</version>
+    </dependency>
+    <dependency>
+      <groupId>com.sun.mail</groupId>
+      <artifactId>smtp</artifactId>
+      <version>1.5.2</version>
+    </dependency>
   </dependencies>
   <!--<reporting> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId>
     <artifactId>findbugs-maven-plugin</artifactId> <version>2.5.2</version> </plugin>

http://git-wip-us.apache.org/repos/asf/ambari/blob/ba325d08/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
index 7354706..57b678a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
@@ -113,10 +113,12 @@ import org.springframework.web.context.WebApplicationContext;
 import org.springframework.web.context.support.GenericWebApplicationContext;
 import org.springframework.web.filter.DelegatingFilterProxy;
 
+import com.google.common.util.concurrent.ServiceManager;
 import com.google.gson.Gson;
 import com.google.inject.Guice;
 import com.google.inject.Inject;
 import com.google.inject.Injector;
+import com.google.inject.Scopes;
 import com.google.inject.Singleton;
 import com.google.inject.name.Named;
 import com.google.inject.persist.Transactional;
@@ -147,6 +149,13 @@ public class AmbariServer {
   @Inject
   @Named("dbInitNeeded")
   boolean dbInitNeeded;
+
+  /**
+   * Guava service manager singleton (bound with {@link Scopes#SINGLETON}).
+   */
+  @Inject
+  private ServiceManager serviceManager;
+
   /**
    * The singleton view registry.
    */
@@ -473,6 +482,9 @@ public class AmbariServer {
       executionScheduleManager.start();
       LOG.info("********* Started Scheduled Request Manager **********");
 
+      serviceManager.startAsync();
+      LOG.info("********* Started Services **********");
+
       server.join();
       LOG.info("Joined the Server");
     } catch (BadPaddingException bpe){

http://git-wip-us.apache.org/repos/asf/ambari/blob/ba325d08/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
index 349e465..cfab1f8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
@@ -33,9 +33,11 @@ import static org.eclipse.persistence.config.PersistenceUnitProperties.JDBC_USER
 import static org.eclipse.persistence.config.PersistenceUnitProperties.THROW_EXCEPTIONS;
 
 import java.security.SecureRandom;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Properties;
+import java.util.Set;
 
 import org.apache.ambari.server.actionmanager.ActionDBAccessor;
 import org.apache.ambari.server.actionmanager.ActionDBAccessorImpl;
@@ -88,6 +90,7 @@ import org.apache.ambari.server.state.host.HostImpl;
 import org.apache.ambari.server.state.scheduler.RequestExecution;
 import org.apache.ambari.server.state.scheduler.RequestExecutionFactory;
 import org.apache.ambari.server.state.scheduler.RequestExecutionImpl;
+import org.apache.ambari.server.state.services.AlertNoticeDispatchService;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostImpl;
 import org.apache.ambari.server.view.ViewInstanceHandlerList;
 import org.eclipse.jetty.server.SessionIdManager;
@@ -98,6 +101,7 @@ import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.security.crypto.password.StandardPasswordEncoder;
 import org.springframework.web.filter.DelegatingFilterProxy;
 
+import com.google.common.util.concurrent.ServiceManager;
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 import com.google.inject.AbstractModule;
@@ -226,6 +230,7 @@ public class ControllerModule extends AbstractModule {
 
     requestStaticInjection(ExecutionCommandWrapper.class);
 
+    bindServices();
     bindEagerSingletons();
   }
 
@@ -306,6 +311,23 @@ public class ControllerModule extends AbstractModule {
   }
 
   /**
+   * Bind all {@link com.google.common.util.concurrent.Service} singleton
+   * instances and then register them with a singleton {@link ServiceManager}.
+   */
+  private void bindServices() {
+    Set<com.google.common.util.concurrent.Service> services = new HashSet<com.google.common.util.concurrent.Service>();
+
+    AlertNoticeDispatchService alertNoticeDispatchService = new AlertNoticeDispatchService();
+
+    bind(AlertNoticeDispatchService.class).toInstance(
+        alertNoticeDispatchService);
+
+    services.add(alertNoticeDispatchService);
+    ServiceManager manager = new ServiceManager(services);
+    bind(ServiceManager.class).toInstance(manager);
+  }
+
+  /**
    * Initializes all eager singletons that should be instantiated as soon as
    * possible and not wait for injection.
    */

http://git-wip-us.apache.org/repos/asf/ambari/blob/ba325d08/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java
index 519ceeb..0f1b49a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java
@@ -113,6 +113,10 @@ public class AlertReceivedListener {
       AlertHistoryEntity history = createHistory(clusterId,
           current.getAlertHistory().getAlertDefinition(), alert);
 
+      // manually create the new history entity since we are merging into
+      // an existing current entity
+      m_alertsDao.create(history);
+
       current.setAlertHistory(history);
       current.setLatestTimestamp(Long.valueOf(alert.getTimestamp()));
       current.setOriginalTimestamp(Long.valueOf(alert.getTimestamp()));
@@ -121,7 +125,8 @@ public class AlertReceivedListener {
 
       // broadcast the alert changed event for other subscribers
       AlertStateChangeEvent alertChangedEvent = new AlertStateChangeEvent(
-          event.getClusterId(), event.getAlert(), history, oldState);
+          event.getClusterId(), event.getAlert(), current.getAlertHistory(),
+          oldState);
 
       m_alertEventPublisher.publish(alertChangedEvent);
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ba325d08/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertServiceStateListener.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertServiceStateListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertServiceStateListener.java
index 906d52d..f1ce617 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertServiceStateListener.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertServiceStateListener.java
@@ -113,6 +113,17 @@ public class AlertServiceStateListener {
     String stackVersion = event.getStackVersion();
     String serviceName = event.getServiceName();
 
+    // create the default alert group for the new service; this MUST be done
+    // before adding definitions so that they are properly added to the
+    // default group
+    AlertGroupEntity serviceAlertGroup = new AlertGroupEntity();
+    serviceAlertGroup.setClusterId(clusterId);
+    serviceAlertGroup.setDefault(true);
+    serviceAlertGroup.setGroupName(serviceName);
+    serviceAlertGroup.setServiceName(serviceName);
+
+    m_alertDispatchDao.create(serviceAlertGroup);
+
     // populate alert definitions for the new service from the database, but
     // don't worry about sending down commands to the agents; the host
     // components are not yet bound to the hosts so we'd have no way of knowing
@@ -134,14 +145,5 @@ public class AlertServiceStateListener {
           serviceName);
       LOG.error(message, ae);
     }
-
-    // create the default alert group for the new service
-    AlertGroupEntity serviceAlertGroup = new AlertGroupEntity();
-    serviceAlertGroup.setClusterId(clusterId);
-    serviceAlertGroup.setDefault(true);
-    serviceAlertGroup.setGroupName(serviceName);
-    serviceAlertGroup.setServiceName(serviceName);
-
-    m_alertDispatchDao.create(serviceAlertGroup);
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ba325d08/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertStateChangedListener.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertStateChangedListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertStateChangedListener.java
index ac22f88..b2f08d7 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertStateChangedListener.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertStateChangedListener.java
@@ -19,6 +19,7 @@ package org.apache.ambari.server.events.listeners;
 
 import java.util.List;
 import java.util.Set;
+import java.util.UUID;
 
 import org.apache.ambari.server.events.AlertStateChangeEvent;
 import org.apache.ambari.server.events.publishers.AlertEventPublisher;
@@ -89,11 +90,12 @@ public class AlertStateChangedListener {
 
       for (AlertTargetEntity target : targets) {
         AlertNoticeEntity notice = new AlertNoticeEntity();
+        notice.setUuid(UUID.randomUUID().toString());
         notice.setAlertTarget(target);
         notice.setAlertHistory(event.getNewHistoricalEntry());
         notice.setNotifyState(NotificationState.PENDING);
 
-        m_alertsDispatchDao.merge(notice);
+        m_alertsDispatchDao.create(notice);
       }
     }
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ba325d08/ambari-server/src/main/java/org/apache/ambari/server/events/publishers/AlertEventPublisher.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/publishers/AlertEventPublisher.java b/ambari-server/src/main/java/org/apache/ambari/server/events/publishers/AlertEventPublisher.java
index f1a0b3e..006837a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/publishers/AlertEventPublisher.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/publishers/AlertEventPublisher.java
@@ -17,8 +17,10 @@
  */
 package org.apache.ambari.server.events.publishers;
 
-import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.ambari.server.events.AlertEvent;
@@ -48,8 +50,14 @@ public final class AlertEventPublisher {
    * Constructor.
    */
   public AlertEventPublisher() {
-    m_eventBus = new AsyncEventBus(Executors.newFixedThreadPool(2,
-        new AlertEventBusThreadFactory()));
+    // create a fixed executor that is unbounded for now and will run rejected
+    // requests in the calling thread to prevent loss of alert handling
+    ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 2, 0L,
+        TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(),
+        new AlertEventBusThreadFactory(),
+        new ThreadPoolExecutor.CallerRunsPolicy());
+
+    m_eventBus = new AsyncEventBus(executor);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/ba325d08/ambari-server/src/main/java/org/apache/ambari/server/notifications/DispatchCallback.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/notifications/DispatchCallback.java b/ambari-server/src/main/java/org/apache/ambari/server/notifications/DispatchCallback.java
new file mode 100644
index 0000000..e4e944d
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/notifications/DispatchCallback.java
@@ -0,0 +1,50 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.notifications;
+
+import java.util.List;
+
+/**
+ * The {@link DispatchCallback} interface is used by an {@link NotificationDispatcher} to
+ * callback to an interested party when a {@link Notification} delivery is
+ * attempted.
+ * <p/>
+ * This class can be used to let the caller know the success or failure status
+ * of the outbound {@link Notification}.
+ */
+public interface DispatchCallback {
+
+  /**
+   * Invoked when a {@link Notification} was successfully dispatched.
+   *
+   * @param callbackIds
+   *          a list of unique IDs that the caller can use to identify the
+   *          {@link Notification} that was dispatched.
+   */
+  public void onSuccess(List<String> callbackIds);
+
+  /**
+   * Invoked when a {@link Notification} failed to be dispatched.
+   * 
+   * @param callbackIds
+   *          a list of unique IDs that the caller can use to identify the
+   *          {@link Notification} that was dispatched.
+   */
+  public void onFailure(List<String> callbackIds);
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/ba325d08/ambari-server/src/main/java/org/apache/ambari/server/notifications/DispatchFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/notifications/DispatchFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/notifications/DispatchFactory.java
new file mode 100644
index 0000000..3414035
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/notifications/DispatchFactory.java
@@ -0,0 +1,62 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.notifications;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.ambari.server.notifications.dispatchers.EmailDispatcher;
+
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.Singleton;
+
+/**
+ * The {@link DispatchFactory} is used to provide singleton instances of
+ * {@link NotificationDispatcher} based on a supplied type.
+ */
+@Singleton
+public final class DispatchFactory {
+
+  /**
+   * Mapping of dispatch type to dispatcher singleton.
+   */
+  private final Map<String, NotificationDispatcher> m_dispatchers = new HashMap<String, NotificationDispatcher>();
+
+  /**
+   * Constructor.
+   *
+   */
+  @Inject
+  public DispatchFactory(Injector injector) {
+    EmailDispatcher emailDispatcher = injector.getInstance(EmailDispatcher.class);
+
+    m_dispatchers.put(emailDispatcher.getType(), emailDispatcher);
+  }
+
+  /**
+   * Gets a dispatcher based on the type.
+   *
+   * @param type
+   *          the type (not {@code null}).
+   * @return a dispatcher instance, or {@code null} if none.
+   */
+  public NotificationDispatcher getDispatcher(String type) {
+    return m_dispatchers.get(type);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/ba325d08/ambari-server/src/main/java/org/apache/ambari/server/notifications/DispatchRunnable.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/notifications/DispatchRunnable.java b/ambari-server/src/main/java/org/apache/ambari/server/notifications/DispatchRunnable.java
new file mode 100644
index 0000000..dcc2103
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/notifications/DispatchRunnable.java
@@ -0,0 +1,60 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.notifications;
+
+import java.util.concurrent.Executor;
+
+/**
+ * The {@link DispatchRunnable} class is a simple {@link Runnable} that can be
+ * used to pass a {@link Notification} to an {@link NotificationDispatcher} via an
+ * {@link Executor}.
+ */
+public final class DispatchRunnable implements Runnable {
+
+  /**
+   * The dispatcher to dispatch to.
+   */
+  private final NotificationDispatcher m_dispatcher;
+
+  /**
+   * The notification to dispatch.
+   */
+  private final Notification m_notification;
+
+  /**
+   * Constructor.
+   * 
+   * @param dispatcher
+   *          the dispatcher to dispatch to (not {@code null}).
+   * @param notification
+   *          the notification to dispatch (not {@code null}).
+   */
+  public DispatchRunnable(NotificationDispatcher dispatcher, Notification notification) {
+    m_dispatcher = dispatcher;
+    m_notification = notification;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void run() {
+    m_dispatcher.dispatch(m_notification);
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/ba325d08/ambari-server/src/main/java/org/apache/ambari/server/notifications/Notification.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/notifications/Notification.java b/ambari-server/src/main/java/org/apache/ambari/server/notifications/Notification.java
new file mode 100644
index 0000000..08c5242
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/notifications/Notification.java
@@ -0,0 +1,57 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.notifications;
+
+import java.util.List;
+
+/**
+ * The {@link Notification} class is a generic way to relay content through an
+ * {@link NotificationDispatcher}.
+ */
+public class Notification {
+
+  /**
+   *
+   */
+  public String Subject;
+
+  /**
+   * The main content of the notification.
+   */
+  public String Body;
+
+  /**
+   * An optional callback implementation that the dispatcher can use to report
+   * success/failure on delivery.
+   */
+  public DispatchCallback Callback;
+
+  /**
+   * An option list of unique IDs that will identify the origins of this
+   * notification.
+   */
+  public List<String> CallbackIds;
+
+  /**
+   * Constructor.
+   *
+   */
+  public Notification() {
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/ba325d08/ambari-server/src/main/java/org/apache/ambari/server/notifications/NotificationDispatcher.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/notifications/NotificationDispatcher.java b/ambari-server/src/main/java/org/apache/ambari/server/notifications/NotificationDispatcher.java
new file mode 100644
index 0000000..10946be
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/notifications/NotificationDispatcher.java
@@ -0,0 +1,47 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.notifications;
+
+
+/**
+ * The {@link NotificationDispatcher} interface represents a mechanism for dispatching a
+ * {@link Notification}.
+ * <p/>
+ * Dispatchers should, in general, be singletons. They should also invoke the
+ * appropriate methods on {@link Notification#Callback} to indicate a success or
+ * failure during dispatch.
+ */
+public interface NotificationDispatcher {
+
+  /**
+   * Gets the type of dispatcher. The type of each different dispatcher should
+   * be unique.
+   *
+   * @return the dispatcher's type (never {@code null}).
+   */
+  public String getType();
+
+  /**
+   * Dispatches the specified notification.
+   *
+   * @param notification
+   *          the notificationt to dispatch (not {@code null}).
+   */
+  public void dispatch(Notification notification);
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/ba325d08/ambari-server/src/main/java/org/apache/ambari/server/notifications/dispatchers/EmailDispatcher.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/notifications/dispatchers/EmailDispatcher.java b/ambari-server/src/main/java/org/apache/ambari/server/notifications/dispatchers/EmailDispatcher.java
new file mode 100644
index 0000000..d0858d3
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/notifications/dispatchers/EmailDispatcher.java
@@ -0,0 +1,60 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.notifications.dispatchers;
+
+import org.apache.ambari.server.notifications.NotificationDispatcher;
+import org.apache.ambari.server.notifications.Notification;
+import org.apache.ambari.server.state.alert.TargetType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.Singleton;
+
+/**
+ * The {@link EmailDispatcher} class is used to dispatch {@link Notification}
+ * via JavaMail.
+ */
+@Singleton
+public class EmailDispatcher implements NotificationDispatcher {
+
+  /**
+   * Logger.
+   */
+  private static final Logger LOG = LoggerFactory.getLogger(EmailDispatcher.class);
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getType() {
+    return TargetType.EMAIL.name();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void dispatch(Notification notification) {
+    LOG.info("Sending email: {}", notification);
+
+    // callback to inform the interested parties about the successful dispatch
+    if (null != notification.Callback) {
+      notification.Callback.onSuccess(notification.CallbackIds);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/ba325d08/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java
index f410c39..570f268 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java
@@ -26,6 +26,7 @@ import javax.persistence.TypedQuery;
 
 import org.apache.ambari.server.controller.RootServiceResponseFactory;
 import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
+import org.apache.ambari.server.orm.entities.AlertGroupEntity;
 import org.apache.ambari.server.state.alert.Scope;
 
 import com.google.inject.Inject;
@@ -125,7 +126,7 @@ public class AlertDefinitionDAO {
 
   /**
    * Gets all of the alert definitions for the list of IDs given.
-   * 
+   *
    * @param definitionIds
    *          the IDs of the definitions to retrieve.
    * @return the definition or an empty list (never {@code null}).
@@ -246,7 +247,9 @@ public class AlertDefinitionDAO {
   }
 
   /**
-   * Persists a new alert definition.
+   * Persists a new alert definition, also creating the associated
+   * {@link AlertGroupEntity} relationship for the definition's service default
+   * group.
    *
    * @param alertDefinition
    *          the definition to persist (not {@code null}).
@@ -254,6 +257,13 @@ public class AlertDefinitionDAO {
   @Transactional
   public void create(AlertDefinitionEntity alertDefinition) {
     entityManagerProvider.get().persist(alertDefinition);
+
+    AlertGroupEntity group = dispatchDao.findDefaultServiceGroup(alertDefinition.getServiceName());
+
+    if (null != group) {
+      group.addAlertDefinition(alertDefinition);
+      dispatchDao.merge(group);
+    }
   }
 
   /**
@@ -305,7 +315,6 @@ public class AlertDefinitionDAO {
    */
   @Transactional
   public void remove(AlertDefinitionEntity alertDefinition) {
-    alertDefinition = merge(alertDefinition);
     dispatchDao.removeNoticeByDefinitionId(alertDefinition.getDefinitionId());
     alertsDao.removeByDefinitionId(alertDefinition.getDefinitionId());
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/ba325d08/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDispatchDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDispatchDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDispatchDAO.java
index 6d4d19b..2239c8f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDispatchDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDispatchDAO.java
@@ -26,6 +26,7 @@ import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
 import org.apache.ambari.server.orm.entities.AlertGroupEntity;
 import org.apache.ambari.server.orm.entities.AlertNoticeEntity;
 import org.apache.ambari.server.orm.entities.AlertTargetEntity;
+import org.apache.ambari.server.state.NotificationState;
 import org.apache.ambari.server.state.alert.AlertGroup;
 
 import com.google.inject.Inject;
@@ -101,6 +102,37 @@ public class AlertDispatchDAO {
   }
 
   /**
+   * Gets a notification with the specified UUID.
+   *
+   * @param uuid
+   *          the UUID of the notification to retrieve.
+   * @return the notification or {@code null} if none exists.
+   */
+  public AlertNoticeEntity findNoticeByUuid(String uuid) {
+    TypedQuery<AlertNoticeEntity> query = entityManagerProvider.get().createNamedQuery(
+        "AlertNoticeEntity.findByUuid", AlertNoticeEntity.class);
+
+    query.setParameter("uuid", uuid);
+
+    return daoUtils.selectOne(query);
+  }
+
+  /**
+   * Gets all {@link AlertNoticeEntity} instances that are
+   * {@link NotificationState#PENDING} and not yet dispatched.
+   *
+   * @return the notices that are waiting to be dispatched, or an empty list
+   *         (never {@code null}).
+   */
+  public List<AlertNoticeEntity> findPendingNotices() {
+    TypedQuery<AlertNoticeEntity> query = entityManagerProvider.get().createNamedQuery(
+        "AlertNoticeEntity.findByState", AlertNoticeEntity.class);
+
+    query.setParameter("notifyState", NotificationState.PENDING);
+    return daoUtils.selectList(query);
+  }
+
+  /**
    * Gets an alert group with the specified name across all clusters. Alert
    * group names are unique within a cluster.
    *
@@ -195,12 +227,13 @@ public class AlertDispatchDAO {
 
   /**
    * Gets all of the {@link AlertGroup} instances that include the specified
-   * alert definition.
+   * alert definition. Service default groups will also be returned.
    *
    * @param definitionEntity
    *          the definition that the group must include (not {@code null}).
    * @return all alert groups that have an association with the specified
-   *         definition or empty list if none exist (never {@code null}).
+   *         definition and the definition's service default group or empty list
+   *         if none exist (never {@code null}).
    */
   public List<AlertGroupEntity> findGroupsByDefinition(
       AlertDefinitionEntity definitionEntity) {
@@ -214,6 +247,23 @@ public class AlertDispatchDAO {
   }
 
   /**
+   * Gets the default group for the specified service.
+   *
+   * @param serviceName
+   *          the name of the service (not {@code null}).
+   * @return the default group, or {@code null} if the service name is not valid
+   *         for an installed service; otherwise {@code null} should not be
+   *         possible.
+   */
+  public AlertGroupEntity findDefaultServiceGroup(String serviceName) {
+    TypedQuery<AlertGroupEntity> query = entityManagerProvider.get().createNamedQuery(
+        "AlertGroupEntity.findServiceDefaultGroup", AlertGroupEntity.class);
+
+    query.setParameter("serviceName", serviceName);
+    return daoUtils.selectSingle(query);
+  }
+
+  /**
    * Gets all alert notifications stored in the database.
    *
    * @return all alert notifications or empty list if none exist (never
@@ -289,6 +339,21 @@ public class AlertDispatchDAO {
   }
 
   /**
+   * Removes all {@link AlertDefinitionEntity} that are associated with the
+   * specified cluster ID.
+   *
+   * @param clusterId
+   *          the cluster ID.
+   */
+  @Transactional
+  public void removeAllGroups(long clusterId) {
+    List<AlertGroupEntity> groups = findAllGroups(clusterId);
+    for (AlertGroupEntity group : groups) {
+      remove(group);
+    }
+  }
+
+  /**
    * Persists new alert targets.
    *
    * @param entities

http://git-wip-us.apache.org/repos/asf/ambari/blob/ba325d08/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 8db89f7..c24ac17 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
@@ -69,14 +69,15 @@ public class AlertCurrentEntity {
 
   @Column(name = "original_timestamp", nullable = false)
   private Long originalTimestamp;
-  
+
   @Column(name = "latest_text", length = 4000)
   private String latestText = null;
 
   /**
    * Unidirectional one-to-one association to {@link AlertHistoryEntity}
    */
-  @OneToOne(cascade = { CascadeType.PERSIST })
+  @OneToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE,
+      CascadeType.REFRESH })
   @JoinColumn(name = "history_id", unique = true, nullable = false)
   private AlertHistoryEntity alertHistory;
 
@@ -95,7 +96,7 @@ public class AlertCurrentEntity {
 
   /**
    * Gets the unique ID for this current alert.
-   * 
+   *
    * @return the ID (never {@code null}).
    */
   public Long getAlertId() {
@@ -104,7 +105,7 @@ public class AlertCurrentEntity {
 
   /**
    * Sets the unique ID for this current alert.
-   * 
+   *
    * @param alertId
    *          the ID (not {@code null}).
    */
@@ -115,7 +116,7 @@ public class AlertCurrentEntity {
   /**
    * Gets the time, in millis, that the last instance of this alert state was
    * received.
-   * 
+   *
    * @return the time of the most recently received alert data for this instance
    *         (never {@code null}).
    */
@@ -126,7 +127,7 @@ public class AlertCurrentEntity {
   /**
    * Sets the time, in millis, that the last instance of this alert state was
    * received.
-   * 
+   *
    * @param latestTimestamp
    *          the time of the most recently received alert data for this
    *          instance (never {@code null}).
@@ -137,7 +138,7 @@ public class AlertCurrentEntity {
 
   /**
    * Gets the current maintenance state for the alert.
-   * 
+   *
    * @return the current maintenance state (never {@code null}).
    */
   public MaintenanceState getMaintenanceState() {
@@ -146,7 +147,7 @@ public class AlertCurrentEntity {
 
   /**
    * Sets the current maintenance state for the alert.
-   * 
+   *
    * @param maintenanceState
    *          the state to set (not {@code null}).
    */
@@ -157,7 +158,7 @@ public class AlertCurrentEntity {
   /**
    * Gets the time, in milliseconds, when the alert was first received with the
    * current state.
-   * 
+   *
    * @return the time of the first instance of this alert.
    */
   public Long getOriginalTimestamp() {
@@ -167,14 +168,14 @@ public class AlertCurrentEntity {
   /**
    * Sets the time, in milliseconds, when the alert was first received with the
    * current state.
-   * 
+   *
    * @param originalTimestamp
    *          the time of the first instance of this alert (not {@code null}).
    */
   public void setOriginalTimestamp(Long originalTimestamp) {
     this.originalTimestamp = originalTimestamp;
   }
-  
+
   /**
    * Gets the latest text for this alert.  History will not get a new record on
    * update when the state is the same, but the text may be changed.  For example,
@@ -183,7 +184,7 @@ public class AlertCurrentEntity {
   public String getLatestText() {
     return latestText;
   }
-  
+
   /**
    * Sets the latest text.  {@link #getLatestText()}
    */
@@ -194,7 +195,7 @@ public class AlertCurrentEntity {
   /**
    * Gets the associated {@link AlertHistoryEntity} entry for this current alert
    * instance.
-   * 
+   *
    * @return the most recently received history entry (never {@code null}).
    */
   public AlertHistoryEntity getAlertHistory() {
@@ -204,7 +205,7 @@ public class AlertCurrentEntity {
   /**
    * Gets the associated {@link AlertHistoryEntity} entry for this current alert
    * instance.
-   * 
+   *
    * @param alertHistory
    *          the most recently received history entry (not {@code null}).
    */
@@ -218,16 +219,19 @@ public class AlertCurrentEntity {
    */
   @Override
   public boolean equals(Object object) {
-    if (this == object)
+    if (this == object) {
       return true;
+    }
 
-    if (object == null || getClass() != object.getClass())
+    if (object == null || getClass() != object.getClass()) {
       return false;
+    }
 
     AlertCurrentEntity that = (AlertCurrentEntity) object;
 
-    if (alertId != null ? !alertId.equals(that.alertId) : that.alertId != null)
+    if (alertId != null ? !alertId.equals(that.alertId) : that.alertId != null) {
       return false;
+    }
 
     return true;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ba325d08/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertGroupEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertGroupEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertGroupEntity.java
index e7fa9c6..1cc9bcc 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertGroupEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertGroupEntity.java
@@ -49,7 +49,8 @@ import javax.persistence.UniqueConstraint;
     @NamedQuery(name = "AlertGroupEntity.findAllInCluster", query = "SELECT alertGroup FROM AlertGroupEntity alertGroup WHERE alertGroup.clusterId = :clusterId"),
     @NamedQuery(name = "AlertGroupEntity.findByName", query = "SELECT alertGroup FROM AlertGroupEntity alertGroup WHERE alertGroup.groupName = :groupName"),
     @NamedQuery(name = "AlertGroupEntity.findByNameInCluster", query = "SELECT alertGroup FROM AlertGroupEntity alertGroup WHERE alertGroup.groupName = :groupName AND alertGroup.clusterId = :clusterId"),
-    @NamedQuery(name = "AlertGroupEntity.findByAssociatedDefinition", query = "SELECT alertGroup FROM AlertGroupEntity alertGroup WHERE :alertDefinition MEMBER OF alertGroup.alertDefinitions"), })
+    @NamedQuery(name = "AlertGroupEntity.findByAssociatedDefinition", query = "SELECT alertGroup FROM AlertGroupEntity alertGroup WHERE :alertDefinition MEMBER OF alertGroup.alertDefinitions"),
+    @NamedQuery(name = "AlertGroupEntity.findServiceDefaultGroup", query = "SELECT alertGroup FROM AlertGroupEntity alertGroup WHERE alertGroup.serviceName = :serviceName AND alertGroup.isDefault = 1") })
 public class AlertGroupEntity {
 
   @Id

http://git-wip-us.apache.org/repos/asf/ambari/blob/ba325d08/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertNoticeEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertNoticeEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertNoticeEntity.java
index c9470ce..d0d4c9a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertNoticeEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertNoticeEntity.java
@@ -46,6 +46,8 @@ import org.apache.ambari.server.state.NotificationState;
 @TableGenerator(name = "alert_notice_id_generator", table = "ambari_sequences", pkColumnName = "sequence_name", valueColumnName = "sequence_value", pkColumnValue = "alert_notice_id_seq", initialValue = 0, allocationSize = 1)
 @NamedQueries({
     @NamedQuery(name = "AlertNoticeEntity.findAll", query = "SELECT notice FROM AlertNoticeEntity notice"),
+    @NamedQuery(name = "AlertNoticeEntity.findByState", query = "SELECT notice FROM AlertNoticeEntity notice WHERE notice.notifyState = :notifyState"),
+    @NamedQuery(name = "AlertNoticeEntity.findByUuid", query = "SELECT notice FROM AlertNoticeEntity notice WHERE notice.uuid = :uuid"),
     @NamedQuery(name = "AlertNoticeEntity.removeByDefinitionId", query = "DELETE FROM AlertNoticeEntity notice WHERE notice.alertHistory.alertDefinition.definitionId = :definitionId") })
 public class AlertNoticeEntity {
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/ba325d08/ambari-server/src/main/java/org/apache/ambari/server/state/alert/TargetType.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/TargetType.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/TargetType.java
index e2564cc..9f3b5d8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/TargetType.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/TargetType.java
@@ -17,7 +17,6 @@
  */
 package org.apache.ambari.server.state.alert;
 
-import org.apache.ambari.server.orm.dao.AlertsDAO;
 
 /**
  * The {@link TargetType} enumeration is used to represent the built-in target
@@ -31,7 +30,17 @@ public enum TargetType {
   EMAIL,
 
   /**
-   * {@link AlertsDAO} will be distributed via SNMP.
+   * Alerts will be distributed via SNMP.
    */
-  SNMP;
+  SNMP,
+
+  /**
+   * Alerts will be distributed to Nagios.
+   */
+  NAGIOS,
+
+  /**
+   * Alerts will be distributed to a logger.
+   */
+  LOG;
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ba325d08/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
index d938771..ff973f6 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
@@ -37,6 +37,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
 import javax.persistence.RollbackException;
 
 import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.ConfigGroupNotFoundException;
 import org.apache.ambari.server.ObjectNotFoundException;
 import org.apache.ambari.server.ParentObjectNotFoundException;
 import org.apache.ambari.server.ServiceComponentHostNotFoundException;
@@ -50,6 +51,7 @@ import org.apache.ambari.server.orm.RequiresSession;
 import org.apache.ambari.server.orm.cache.ConfigGroupHostMapping;
 import org.apache.ambari.server.orm.cache.HostConfigMapping;
 import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
+import org.apache.ambari.server.orm.dao.AlertDispatchDAO;
 import org.apache.ambari.server.orm.dao.ClusterDAO;
 import org.apache.ambari.server.orm.dao.ClusterStateDAO;
 import org.apache.ambari.server.orm.dao.ConfigGroupHostMappingDAO;
@@ -106,7 +108,6 @@ import com.google.inject.Inject;
 import com.google.inject.Injector;
 import com.google.inject.assistedinject.Assisted;
 import com.google.inject.persist.Transactional;
-import org.apache.ambari.server.ConfigGroupNotFoundException;
 
 public class ClusterImpl implements Cluster {
 
@@ -191,6 +192,9 @@ public class ClusterImpl implements Cluster {
   @Inject
   private AlertDefinitionDAO alertDefinitionDAO;
 
+  @Inject
+  private AlertDispatchDAO alertDispatchDAO;
+
   private volatile boolean svcHostsLoaded = false;
 
   private volatile Multimap<String, String> serviceConfigTypes;
@@ -1363,6 +1367,7 @@ public class ClusterImpl implements Cluster {
   protected void removeEntities() throws AmbariException {
     long clusterId = getClusterId();
     alertDefinitionDAO.removeAll(clusterId);
+    alertDispatchDAO.removeAllGroups(clusterId);
     clusterDAO.removeByPK(clusterId);
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/ba325d08/ambari-server/src/main/java/org/apache/ambari/server/state/services/AlertNoticeDispatchService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/services/AlertNoticeDispatchService.java b/ambari-server/src/main/java/org/apache/ambari/server/state/services/AlertNoticeDispatchService.java
new file mode 100644
index 0000000..7025e14
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/services/AlertNoticeDispatchService.java
@@ -0,0 +1,231 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state.services;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.ambari.server.events.AlertEvent;
+import org.apache.ambari.server.notifications.DispatchFactory;
+import org.apache.ambari.server.notifications.DispatchRunnable;
+import org.apache.ambari.server.notifications.DispatchCallback;
+import org.apache.ambari.server.notifications.NotificationDispatcher;
+import org.apache.ambari.server.notifications.Notification;
+import org.apache.ambari.server.orm.dao.AlertDispatchDAO;
+import org.apache.ambari.server.orm.entities.AlertNoticeEntity;
+import org.apache.ambari.server.orm.entities.AlertTargetEntity;
+import org.apache.ambari.server.state.NotificationState;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.util.concurrent.AbstractScheduledService;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+/**
+ * The {@link AlertNoticeDispatchService} is used to scan the database for
+ * {@link AlertNoticeEntity} that are in the {@link NotificationState#PENDING}.
+ * It will then process them through the dispatch system.
+ */
+@Singleton
+public class AlertNoticeDispatchService extends AbstractScheduledService {
+
+  /**
+   * Logger.
+   */
+  private static final Logger LOG = LoggerFactory.getLogger(AlertNoticeDispatchService.class);
+
+  /**
+   * Dispatch DAO to query pending {@link AlertNoticeEntity} instances from.
+   */
+  @Inject
+  private AlertDispatchDAO m_dao;
+
+  /**
+   * The factory used to get an {@link NotificationDispatcher} instance to submit to the
+   * {@link #m_executor}.
+   */
+  @Inject
+  private DispatchFactory m_dispatchFactory;
+
+  /**
+   * The executor responsible for dispatching.
+   */
+  private final ThreadPoolExecutor m_executor;
+
+  /**
+   * Constructor.
+   */
+  public AlertNoticeDispatchService() {
+    m_executor = new ThreadPoolExecutor(0, 2, 5L,
+        TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>(),
+        new AlertDispatchThreadFactory(),
+        new ThreadPoolExecutor.CallerRunsPolicy());
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected void runOneIteration() throws Exception {
+    List<AlertNoticeEntity> pending = m_dao.findPendingNotices();
+    if (pending.size() == 0) {
+      return;
+    }
+
+    LOG.info("There are {} pending alert notices about to be dispatched..."
+        + pending.size());
+
+    // combine all histories by target
+    Map<AlertTargetEntity, List<AlertNoticeEntity>> aggregateMap = new HashMap<AlertTargetEntity, List<AlertNoticeEntity>>(
+        pending.size());
+
+    for (AlertNoticeEntity notice : pending) {
+      AlertTargetEntity target = notice.getAlertTarget();
+
+      List<AlertNoticeEntity> notices = aggregateMap.get(target);
+      if (null == notices) {
+        notices = new ArrayList<AlertNoticeEntity>();
+        aggregateMap.put(target, notices);
+      }
+
+      notices.add(notice);
+    }
+
+    Set<AlertTargetEntity> targets = aggregateMap.keySet();
+    for (AlertTargetEntity target : targets) {
+      List<AlertNoticeEntity> notices = aggregateMap.get(target);
+      if (null == notices || notices.size() == 0) {
+        continue;
+      }
+
+      Notification notification = new Notification();
+      notification.Subject = target.getTargetName();
+      notification.Body = target.getDescription();
+      notification.Callback = new AlertNoticeDispatchCallback();
+      notification.CallbackIds = new ArrayList<String>(notices.size());
+
+      for (AlertNoticeEntity notice : notices) {
+        notification.CallbackIds.add(notice.getUuid());
+      }
+
+      NotificationDispatcher dispatcher = m_dispatchFactory.getDispatcher(target.getNotificationType());
+      DispatchRunnable runnable = new DispatchRunnable(dispatcher, notification);
+
+      m_executor.execute(runnable);
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   * <p/>
+   * Returns a schedule that starts after 1 minute and runs every minute after
+   * {@link #runOneIteration()} completes.
+   */
+  @Override
+  protected Scheduler scheduler() {
+    return Scheduler.newFixedDelaySchedule(1, 1, TimeUnit.MINUTES);
+  }
+
+  /**
+   * A custom {@link ThreadFactory} for the threads that will handle dispatching
+   * {@link AlertNoticeEntity} instances. Threads created will have slightly
+   * reduced priority since {@link AlertEvent} instances are not critical to the
+   * system.
+   */
+  private static final class AlertDispatchThreadFactory implements
+      ThreadFactory {
+
+    private static final AtomicInteger s_threadIdPool = new AtomicInteger(1);
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Thread newThread(Runnable r) {
+      Thread thread = new Thread(r, "alert-dispatch-"
+          + s_threadIdPool.getAndIncrement());
+
+      thread.setDaemon(false);
+      thread.setPriority(Thread.NORM_PRIORITY - 1);
+
+      return thread;
+    }
+  }
+
+  /**
+   * The {@link AlertNoticeDispatchCallback} is used to receive a callback from
+   * the dispatch framework and then update the {@link AlertNoticeEntity}
+   * {@link NotificationState}.
+   */
+  private final class AlertNoticeDispatchCallback implements
+      DispatchCallback {
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onSuccess(List<String> callbackIds) {
+      for (String callbackId : callbackIds) {
+        updateAlertNotice(callbackId, NotificationState.DELIVERED);
+      }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onFailure(List<String> callbackIds) {
+      for (String callbackId : callbackIds) {
+        updateAlertNotice(callbackId, NotificationState.FAILED);
+      }
+    }
+
+    /**
+     * Updates the {@link AlertNoticeEntity} matching the given UUID with the
+     * specified state.
+     *
+     * @param uuid
+     * @param state
+     */
+    private void updateAlertNotice(String uuid, NotificationState state) {
+      try {
+        AlertNoticeEntity entity = m_dao.findNoticeByUuid(uuid);
+        if (null == entity) {
+          LOG.warn("Unable to find an alert notice with UUID {}", uuid);
+          return;
+        }
+
+        entity.setNotifyState(state);
+        m_dao.merge(entity);
+      } catch (Exception exception) {
+        LOG.error(
+            "Unable to update the alert notice with UUID {} to {}, notifications will continue to be sent",
+            uuid, state, exception);
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/ba325d08/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java b/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
index 526104f..a9d126c 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
@@ -18,6 +18,9 @@
 
 package org.apache.ambari.server.orm;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -353,4 +356,38 @@ public class OrmTestHelper {
     alertDispatchDAO.create(group);
     return alertDispatchDAO.findGroupById(group.getGroupId());
   }
+
+  /**
+   * Creates some default alert groups for various services used in the tests.
+   *
+   * @param clusterId
+   * @return
+   * @throws Exception
+   */
+  @Transactional
+  public List<AlertGroupEntity> createDefaultAlertGroups(long clusterId)
+      throws Exception {
+    AlertGroupEntity hdfsGroup = new AlertGroupEntity();
+    hdfsGroup.setDefault(true);
+    hdfsGroup.setClusterId(clusterId);
+    hdfsGroup.setGroupName("HDFS");
+    hdfsGroup.setServiceName("HDFS");
+
+    AlertGroupEntity oozieGroup = new AlertGroupEntity();
+    oozieGroup.setDefault(true);
+    oozieGroup.setClusterId(clusterId);
+    oozieGroup.setGroupName("OOZIE");
+    oozieGroup.setServiceName("OOZIE");
+
+    alertDispatchDAO.create(hdfsGroup);
+    alertDispatchDAO.create(oozieGroup);
+
+    List<AlertGroupEntity> defaultGroups = alertDispatchDAO.findAllGroups(clusterId);
+    assertEquals(2, defaultGroups.size());
+    assertNotNull(alertDispatchDAO.findDefaultServiceGroup("HDFS"));
+    assertNotNull(alertDispatchDAO.findDefaultServiceGroup("OOZIE"));
+
+    return defaultGroups;
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ba325d08/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
index f7deef5..cdca3dd 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
@@ -72,16 +72,19 @@ public class AlertDefinitionDAOTest {
    *
    */
   @Before
-  public void setup() {
+  public void setup() throws Exception {
     injector = Guice.createInjector(new InMemoryDefaultTestModule());
     injector.getInstance(GuiceJpaInitializer.class);
 
+    dispatchDao = injector.getInstance(AlertDispatchDAO.class);
     dao = injector.getInstance(AlertDefinitionDAO.class);
     alertsDao = injector.getInstance(AlertsDAO.class);
-    dispatchDao = injector.getInstance(AlertDispatchDAO.class);
     helper = injector.getInstance(OrmTestHelper.class);
     clusterId = helper.createCluster();
 
+    // create required default groups
+    helper.createDefaultAlertGroups(clusterId);
+
     // create 8 HDFS alerts
     int i = 0;
     for (; i < 8; i++) {
@@ -148,7 +151,6 @@ public class AlertDefinitionDAOTest {
       definition.setSourceType("SCRIPT");
       dao.create(definition);
     }
-
   }
 
   @After
@@ -287,7 +289,6 @@ public class AlertDefinitionDAOTest {
     history.setAlertState(AlertState.OK);
     history.setAlertText("Alert Text");
     history.setAlertTimestamp(calendar.getTimeInMillis());
-//    alertsDao.create(history);
 
     AlertCurrentEntity current = new AlertCurrentEntity();
     current.setAlertHistory(history);
@@ -359,5 +360,7 @@ public class AlertDefinitionDAOTest {
 
     assertNull(clusterDAO.findById(clusterId));
     assertNull(dao.findById(definition.getDefinitionId()));
+
+    assertEquals(0, dispatchDao.findAllGroups(clusterId).size());
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ba325d08/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDispatchDAOTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDispatchDAOTest.java b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDispatchDAOTest.java
index 1103961..2c3a876 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDispatchDAOTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDispatchDAOTest.java
@@ -35,7 +35,11 @@ import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
 import org.apache.ambari.server.orm.OrmTestHelper;
 import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
 import org.apache.ambari.server.orm.entities.AlertGroupEntity;
+import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
+import org.apache.ambari.server.orm.entities.AlertNoticeEntity;
 import org.apache.ambari.server.orm.entities.AlertTargetEntity;
+import org.apache.ambari.server.state.AlertState;
+import org.apache.ambari.server.state.NotificationState;
 import org.apache.ambari.server.state.alert.Scope;
 import org.junit.After;
 import org.junit.Before;
@@ -54,6 +58,7 @@ public class AlertDispatchDAOTest {
   Injector injector;
   AlertDispatchDAO dao;
   AlertDefinitionDAO definitionDao;
+  AlertsDAO alertsDao;
   OrmTestHelper helper;
 
   /**
@@ -64,6 +69,7 @@ public class AlertDispatchDAOTest {
     injector = Guice.createInjector(new InMemoryDefaultTestModule());
     injector.getInstance(GuiceJpaInitializer.class);
     dao = injector.getInstance(AlertDispatchDAO.class);
+    alertsDao = injector.getInstance(AlertsDAO.class);
     definitionDao = injector.getInstance(AlertDefinitionDAO.class);
     helper = injector.getInstance(OrmTestHelper.class);
 
@@ -352,7 +358,7 @@ public class AlertDispatchDAOTest {
 
   /**
    * Tests finding groups by a definition ID that they are associatd with.
-   * 
+   *
    * @throws Exception
    */
   @Test
@@ -380,6 +386,38 @@ public class AlertDispatchDAOTest {
   }
 
   /**
+   * @throws Exception
+   */
+  @Test
+  public void testFindNoticeByUuid() throws Exception {
+    List<AlertDefinitionEntity> definitions = createDefinitions();
+    AlertDefinitionEntity definition = definitions.get(0);
+
+    AlertHistoryEntity history = new AlertHistoryEntity();
+    history.setServiceName(definition.getServiceName());
+    history.setClusterId(clusterId);
+    history.setAlertDefinition(definition);
+    history.setAlertLabel("Label");
+    history.setAlertState(AlertState.OK);
+    history.setAlertText("Alert Text");
+    history.setAlertTimestamp(System.currentTimeMillis());
+    alertsDao.create(history);
+
+    AlertTargetEntity target = helper.createAlertTarget();
+
+    AlertNoticeEntity notice = new AlertNoticeEntity();
+    notice.setUuid(UUID.randomUUID().toString());
+    notice.setAlertTarget(target);
+    notice.setAlertHistory(history);
+    notice.setNotifyState(NotificationState.PENDING);
+    dao.create(notice);
+
+    AlertNoticeEntity actual = dao.findNoticeByUuid(notice.getUuid());
+    assertEquals(notice.getNotificationId(), actual.getNotificationId());
+    assertNull(dao.findNoticeByUuid("DEADBEEF"));
+  }
+
+  /**
    * @return
    */
   private List<AlertDefinitionEntity> createDefinitions() throws Exception {


[45/50] [abbrv] AMBARI-7642 - Alerts: Maintenance Mode Should Prevent Alert Notifications (jonathanhurley)

Posted by jo...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/3e54f956/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 0cc2ae7..a2023d8 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
@@ -24,14 +24,21 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
+import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Collections;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.TimeZone;
 import java.util.UUID;
 
+import junit.framework.Assert;
+
+import org.apache.ambari.server.events.listeners.AlertMaintenanceModeListener;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
 import org.apache.ambari.server.orm.OrmTestHelper;
@@ -39,13 +46,26 @@ import org.apache.ambari.server.orm.entities.AlertCurrentEntity;
 import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
 import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
 import org.apache.ambari.server.state.AlertState;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.Host;
+import org.apache.ambari.server.state.HostState;
 import org.apache.ambari.server.state.MaintenanceState;
+import org.apache.ambari.server.state.Service;
+import org.apache.ambari.server.state.ServiceComponent;
+import org.apache.ambari.server.state.ServiceComponentFactory;
+import org.apache.ambari.server.state.ServiceComponentHost;
+import org.apache.ambari.server.state.ServiceComponentHostFactory;
+import org.apache.ambari.server.state.ServiceFactory;
+import org.apache.ambari.server.state.StackId;
+import org.apache.ambari.server.state.State;
 import org.apache.ambari.server.state.alert.Scope;
 import org.apache.ambari.server.state.alert.SourceType;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
+import com.google.common.eventbus.EventBus;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.persist.PersistService;
@@ -55,25 +75,46 @@ import com.google.inject.persist.PersistService;
  */
 public class AlertsDAOTest {
 
-  static Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+  final static String HOSTNAME = "c6401.ambari.apache.org";
+  final static Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+
+  private Clusters m_clusters;
+  private Long m_clusterId;
+  private Injector m_injector;
+  private OrmTestHelper m_helper;
+  private AlertsDAO m_dao;
+  private AlertDefinitionDAO m_definitionDao;
 
-  private Long clusterId;
-  private Injector injector;
-  private OrmTestHelper helper;
-  private AlertsDAO dao;
-  private AlertDefinitionDAO definitionDao;
+  private ServiceFactory m_serviceFactory;
+  private ServiceComponentFactory m_componentFactory;
+  private ServiceComponentHostFactory m_schFactory;
+  private AmbariEventPublisher m_eventPublisher;
 
   /**
    *
    */
   @Before
   public void setup() throws Exception {
-    injector = Guice.createInjector(new InMemoryDefaultTestModule());
-    injector.getInstance(GuiceJpaInitializer.class);
-    helper = injector.getInstance(OrmTestHelper.class);
-    clusterId = helper.createCluster();
-    dao = injector.getInstance(AlertsDAO.class);
-    definitionDao = injector.getInstance(AlertDefinitionDAO.class);
+    m_injector = Guice.createInjector(new InMemoryDefaultTestModule());
+    m_injector.getInstance(GuiceJpaInitializer.class);
+    m_helper = m_injector.getInstance(OrmTestHelper.class);
+    m_clusterId = m_helper.createCluster();
+    m_dao = m_injector.getInstance(AlertsDAO.class);
+    m_definitionDao = m_injector.getInstance(AlertDefinitionDAO.class);
+    m_serviceFactory = m_injector.getInstance(ServiceFactory.class);
+    m_componentFactory = m_injector.getInstance(ServiceComponentFactory.class);
+    m_schFactory = m_injector.getInstance(ServiceComponentHostFactory.class);
+    m_eventPublisher = m_injector.getInstance(AmbariEventPublisher.class);
+    m_clusters = m_injector.getInstance(Clusters.class);
+
+    // register a listener
+    EventBus synchronizedBus = new EventBus();
+    synchronizedBus.register(m_injector.getInstance(AlertMaintenanceModeListener.class));
+
+    // !!! need a synchronous op for testing
+    Field field = AmbariEventPublisher.class.getDeclaredField("m_eventBus");
+    field.setAccessible(true);
+    field.set(m_eventPublisher, synchronizedBus);
 
     // create 5 definitions
     for (int i = 0; i < 5; i++) {
@@ -81,16 +122,16 @@ public class AlertsDAOTest {
       definition.setDefinitionName("Alert Definition " + i);
       definition.setServiceName("Service " + i);
       definition.setComponentName(null);
-      definition.setClusterId(clusterId);
+      definition.setClusterId(m_clusterId);
       definition.setHash(UUID.randomUUID().toString());
       definition.setScheduleInterval(Integer.valueOf(60));
       definition.setScope(Scope.SERVICE);
       definition.setSource("{\"type\" : \"SCRIPT\"}");
       definition.setSourceType(SourceType.SCRIPT);
-      definitionDao.create(definition);
+      m_definitionDao.create(definition);
     }
 
-    List<AlertDefinitionEntity> definitions = definitionDao.findAll();
+    List<AlertDefinitionEntity> definitions = m_definitionDao.findAll();
     assertNotNull(definitions);
     assertEquals(5, definitions.size());
 
@@ -102,7 +143,7 @@ public class AlertsDAOTest {
       for (int i = 0; i < 10; i++) {
         AlertHistoryEntity history = new AlertHistoryEntity();
         history.setServiceName(definition.getServiceName());
-        history.setClusterId(clusterId);
+        history.setClusterId(m_clusterId);
         history.setAlertDefinition(definition);
         history.setAlertLabel(definition.getDefinitionName() + " " + i);
         history.setAlertText(definition.getDefinitionName() + " " + i);
@@ -117,13 +158,13 @@ public class AlertsDAOTest {
         // increase the days for each
         calendar.add(Calendar.DATE, 1);
 
-        dao.create(history);
+        m_dao.create(history);
       }
     }
 
     // for each definition, create a current alert
     for (AlertDefinitionEntity definition : definitions) {
-      List<AlertHistoryEntity> alerts = dao.findAll();
+      List<AlertHistoryEntity> alerts = m_dao.findAll();
       AlertHistoryEntity history = null;
       for (AlertHistoryEntity alert : alerts) {
         if (definition.equals(alert.getAlertDefinition())) {
@@ -138,7 +179,7 @@ public class AlertsDAOTest {
       current.setLatestTimestamp(new Date().getTime());
       current.setOriginalTimestamp(new Date().getTime() - 10800000);
       current.setMaintenanceState(MaintenanceState.OFF);
-      dao.create(current);
+      m_dao.create(current);
     }
   }
 
@@ -147,8 +188,8 @@ public class AlertsDAOTest {
    */
   @After
   public void teardown() {
-    injector.getInstance(PersistService.class).stop();
-    injector = null;
+    m_injector.getInstance(PersistService.class).stop();
+    m_injector = null;
   }
 
 
@@ -157,7 +198,7 @@ public class AlertsDAOTest {
    */
   @Test
   public void testFindAll() {
-    List<AlertHistoryEntity> alerts = dao.findAll(clusterId);
+    List<AlertHistoryEntity> alerts = m_dao.findAll(m_clusterId);
     assertNotNull(alerts);
     assertEquals(50, alerts.size());
   }
@@ -167,7 +208,7 @@ public class AlertsDAOTest {
    */
   @Test
   public void testFindAllCurrent() {
-    List<AlertCurrentEntity> currentAlerts = dao.findCurrent();
+    List<AlertCurrentEntity> currentAlerts = m_dao.findCurrent();
     assertNotNull(currentAlerts);
     assertEquals(5, currentAlerts.size());
   }
@@ -177,19 +218,19 @@ public class AlertsDAOTest {
    */
   @Test
   public void testFindCurrentByService() {
-    List<AlertCurrentEntity> currentAlerts = dao.findCurrent();
+    List<AlertCurrentEntity> currentAlerts = m_dao.findCurrent();
     AlertCurrentEntity current = currentAlerts.get(0);
     AlertHistoryEntity history = current.getAlertHistory();
 
     assertNotNull(history);
 
-    currentAlerts = dao.findCurrentByService(clusterId,
+    currentAlerts = m_dao.findCurrentByService(m_clusterId,
         history.getServiceName());
 
     assertNotNull(currentAlerts);
     assertEquals(1, currentAlerts.size());
 
-    currentAlerts = dao.findCurrentByService(clusterId, "foo");
+    currentAlerts = m_dao.findCurrentByService(m_clusterId, "foo");
 
     assertNotNull(currentAlerts);
     assertEquals(0, currentAlerts.size());
@@ -205,18 +246,18 @@ public class AlertsDAOTest {
     hostDef.setDefinitionName("Host Alert Definition ");
     hostDef.setServiceName("HostService");
     hostDef.setComponentName(null);
-    hostDef.setClusterId(clusterId);
+    hostDef.setClusterId(m_clusterId);
     hostDef.setHash(UUID.randomUUID().toString());
     hostDef.setScheduleInterval(Integer.valueOf(60));
     hostDef.setScope(Scope.HOST);
     hostDef.setSource("{\"type\" : \"SCRIPT\"}");
     hostDef.setSourceType(SourceType.SCRIPT);
-    definitionDao.create(hostDef);
+    m_definitionDao.create(hostDef);
 
     // history for the definition
     AlertHistoryEntity history = new AlertHistoryEntity();
     history.setServiceName(hostDef.getServiceName());
-    history.setClusterId(clusterId);
+    history.setClusterId(m_clusterId);
     history.setAlertDefinition(hostDef);
     history.setAlertLabel(hostDef.getDefinitionName());
     history.setAlertText(hostDef.getDefinitionName());
@@ -229,14 +270,15 @@ public class AlertsDAOTest {
     current.setOriginalTimestamp(1L);
     current.setLatestTimestamp(2L);
     current.setAlertHistory(history);
-    dao.create(current);
+    m_dao.create(current);
 
-    List<AlertCurrentEntity> currentAlerts = dao.findCurrentByHost(clusterId, history.getHostName());
+    List<AlertCurrentEntity> currentAlerts = m_dao.findCurrentByHost(
+        m_clusterId, history.getHostName());
 
     assertNotNull(currentAlerts);
     assertEquals(1, currentAlerts.size());
 
-    currentAlerts = dao.findCurrentByHost(clusterId, "foo");
+    currentAlerts = m_dao.findCurrentByHost(m_clusterId, "foo");
 
     assertNotNull(currentAlerts);
     assertEquals(0, currentAlerts.size());
@@ -252,20 +294,21 @@ public class AlertsDAOTest {
     allStates.add(AlertState.WARNING);
     allStates.add(AlertState.CRITICAL);
 
-    List<AlertHistoryEntity> history = dao.findAll(clusterId, allStates);
+    List<AlertHistoryEntity> history = m_dao.findAll(m_clusterId, allStates);
     assertNotNull(history);
     assertEquals(50, history.size());
 
-    history = dao.findAll(clusterId, Collections.singletonList(AlertState.OK));
+    history = m_dao.findAll(m_clusterId,
+        Collections.singletonList(AlertState.OK));
     assertNotNull(history);
     assertEquals(40, history.size());
 
-    history = dao.findAll(clusterId,
+    history = m_dao.findAll(m_clusterId,
         Collections.singletonList(AlertState.CRITICAL));
     assertNotNull(history);
     assertEquals(10, history.size());
 
-    history = dao.findAll(clusterId,
+    history = m_dao.findAll(m_clusterId,
         Collections.singletonList(AlertState.WARNING));
     assertNotNull(history);
     assertEquals(0, history.size());
@@ -280,14 +323,14 @@ public class AlertsDAOTest {
     calendar.set(2014, Calendar.JANUARY, 1);
 
     // on or after 1/1/2014
-    List<AlertHistoryEntity> history = dao.findAll(clusterId,
+    List<AlertHistoryEntity> history = m_dao.findAll(m_clusterId,
         calendar.getTime(), null);
 
     assertNotNull(history);
     assertEquals(50, history.size());
 
     // on or before 1/1/2014
-    history = dao.findAll(clusterId, null, calendar.getTime());
+    history = m_dao.findAll(m_clusterId, null, calendar.getTime());
     assertNotNull(history);
     assertEquals(1, history.size());
 
@@ -298,27 +341,29 @@ public class AlertsDAOTest {
     calendar.set(2014, Calendar.JANUARY, 10);
     Date endDate = calendar.getTime();
 
-    history = dao.findAll(clusterId, startDate, endDate);
+    history = m_dao.findAll(m_clusterId, startDate, endDate);
     assertNotNull(history);
     assertEquals(6, history.size());
 
     // after 3/1
     calendar.set(2014, Calendar.MARCH, 5);
-    history = dao.findAll(clusterId, calendar.getTime(), null);
+    history = m_dao.findAll(m_clusterId, calendar.getTime(), null);
     assertNotNull(history);
     assertEquals(0, history.size());
 
-    history = dao.findAll(clusterId, endDate, startDate);
+    history = m_dao.findAll(m_clusterId, endDate, startDate);
     assertNotNull(history);
     assertEquals(0, history.size());
   }
 
   @Test
   public void testFindCurrentByHostAndName() throws Exception {
-    AlertCurrentEntity entity = dao.findCurrentByHostAndName(clusterId.longValue(), "h2", "Alert Definition 1");
+    AlertCurrentEntity entity = m_dao.findCurrentByHostAndName(
+        m_clusterId.longValue(), "h2", "Alert Definition 1");
     assertNull(entity);
 
-    entity = dao.findCurrentByHostAndName(clusterId.longValue(), "h1", "Alert Definition 1");
+    entity = m_dao.findCurrentByHostAndName(m_clusterId.longValue(), "h1",
+        "Alert Definition 1");
 
     assertNotNull(entity);
     assertNotNull(entity.getAlertHistory());
@@ -330,25 +375,29 @@ public class AlertsDAOTest {
    */
   @Test
   public void testFindCurrentSummary() throws Exception {
-    AlertSummaryDTO summary = dao.findCurrentCounts(clusterId.longValue(), null, null);
+    AlertSummaryDTO summary = m_dao.findCurrentCounts(m_clusterId.longValue(),
+        null, null);
     assertEquals(5, summary.getOkCount());
 
-    AlertHistoryEntity h1 = dao.findCurrentByCluster(clusterId.longValue()).get(2).getAlertHistory();
-    AlertHistoryEntity h2 = dao.findCurrentByCluster(clusterId.longValue()).get(3).getAlertHistory();
-    AlertHistoryEntity h3 = dao.findCurrentByCluster(clusterId.longValue()).get(4).getAlertHistory();
+    AlertHistoryEntity h1 = m_dao.findCurrentByCluster(m_clusterId.longValue()).get(
+        2).getAlertHistory();
+    AlertHistoryEntity h2 = m_dao.findCurrentByCluster(m_clusterId.longValue()).get(
+        3).getAlertHistory();
+    AlertHistoryEntity h3 = m_dao.findCurrentByCluster(m_clusterId.longValue()).get(
+        4).getAlertHistory();
     h1.setAlertState(AlertState.WARNING);
-    dao.merge(h1);
+    m_dao.merge(h1);
     h2.setAlertState(AlertState.CRITICAL);
-    dao.merge(h2);
+    m_dao.merge(h2);
     h3.setAlertState(AlertState.UNKNOWN);
-    dao.merge(h3);
+    m_dao.merge(h3);
 
     int ok = 0;
     int warn = 0;
     int crit = 0;
     int unk = 0;
 
-    for (AlertCurrentEntity h : dao.findCurrentByCluster(clusterId.longValue())) {
+    for (AlertCurrentEntity h : m_dao.findCurrentByCluster(m_clusterId.longValue())) {
       switch (h.getAlertHistory().getAlertState()) {
         case CRITICAL:
           crit++;
@@ -366,7 +415,7 @@ public class AlertsDAOTest {
 
     }
 
-    summary = dao.findCurrentCounts(clusterId.longValue(), null, null);
+    summary = m_dao.findCurrentCounts(m_clusterId.longValue(), null, null);
     // !!! db-to-db compare
     assertEquals(ok, summary.getOkCount());
     assertEquals(warn, summary.getWarningCount());
@@ -379,19 +428,20 @@ public class AlertsDAOTest {
     assertEquals(1, summary.getCriticalCount());
     assertEquals(1, summary.getCriticalCount());
 
-    summary = dao.findCurrentCounts(clusterId.longValue(), "Service 0", null);
+    summary = m_dao.findCurrentCounts(m_clusterId.longValue(), "Service 0",
+        null);
     assertEquals(1, summary.getOkCount());
     assertEquals(0, summary.getWarningCount());
     assertEquals(0, summary.getCriticalCount());
     assertEquals(0, summary.getCriticalCount());
 
-    summary = dao.findCurrentCounts(clusterId.longValue(), null, "h1");
+    summary = m_dao.findCurrentCounts(m_clusterId.longValue(), null, "h1");
     assertEquals(2, summary.getOkCount());
     assertEquals(1, summary.getWarningCount());
     assertEquals(1, summary.getCriticalCount());
     assertEquals(1, summary.getCriticalCount());
 
-    summary = dao.findCurrentCounts(clusterId.longValue(), "foo", null);
+    summary = m_dao.findCurrentCounts(m_clusterId.longValue(), "foo", null);
     assertEquals(0, summary.getOkCount());
     assertEquals(0, summary.getWarningCount());
     assertEquals(0, summary.getCriticalCount());
@@ -405,13 +455,13 @@ public class AlertsDAOTest {
     definition.setDefinitionName("many_per_cluster");
     definition.setServiceName("ServiceName");
     definition.setComponentName(null);
-    definition.setClusterId(clusterId);
+    definition.setClusterId(m_clusterId);
     definition.setHash(UUID.randomUUID().toString());
     definition.setScheduleInterval(Integer.valueOf(60));
     definition.setScope(Scope.SERVICE);
     definition.setSource("{\"type\" : \"SCRIPT\"}");
     definition.setSourceType(SourceType.SCRIPT);
-    definitionDao.create(definition);
+    m_definitionDao.create(definition);
 
     // history record #1 and current
     AlertHistoryEntity history = new AlertHistoryEntity();
@@ -421,7 +471,7 @@ public class AlertsDAOTest {
     history.setAlertState(AlertState.OK);
     history.setAlertText("");
     history.setAlertTimestamp(Long.valueOf(1L));
-    history.setClusterId(clusterId);
+    history.setClusterId(m_clusterId);
     history.setComponentName("");
     history.setHostName("h1");
     history.setServiceName("ServiceName");
@@ -430,7 +480,7 @@ public class AlertsDAOTest {
     current.setAlertHistory(history);
     current.setLatestTimestamp(Long.valueOf(1L));
     current.setOriginalTimestamp(Long.valueOf(1L));
-    dao.merge(current);
+    m_dao.merge(current);
 
     // history record #2 and current
     history = new AlertHistoryEntity();
@@ -440,7 +490,7 @@ public class AlertsDAOTest {
     history.setAlertState(AlertState.OK);
     history.setAlertText("");
     history.setAlertTimestamp(Long.valueOf(1L));
-    history.setClusterId(clusterId);
+    history.setClusterId(m_clusterId);
     history.setComponentName("");
     history.setHostName("h2");
     history.setServiceName("ServiceName");
@@ -449,27 +499,30 @@ public class AlertsDAOTest {
     current.setAlertHistory(history);
     current.setLatestTimestamp(Long.valueOf(1L));
     current.setOriginalTimestamp(Long.valueOf(1L));
-    dao.merge(current);
+    m_dao.merge(current);
 
-    AlertSummaryDTO summary = dao.findAggregateCounts(clusterId.longValue(), "many_per_cluster");
+    AlertSummaryDTO summary = m_dao.findAggregateCounts(
+        m_clusterId.longValue(), "many_per_cluster");
     assertEquals(2, summary.getOkCount());
     assertEquals(0, summary.getWarningCount());
     assertEquals(0, summary.getCriticalCount());
     assertEquals(0, summary.getUnknownCount());
 
-    AlertCurrentEntity c = dao.findCurrentByHostAndName(clusterId.longValue(),
+    AlertCurrentEntity c = m_dao.findCurrentByHostAndName(
+        m_clusterId.longValue(),
         "h2", "many_per_cluster");
     AlertHistoryEntity h = c.getAlertHistory();
     h.setAlertState(AlertState.CRITICAL);
-    dao.merge(h);
+    m_dao.merge(h);
 
-    summary = dao.findAggregateCounts(clusterId.longValue(), "many_per_cluster");
+    summary = m_dao.findAggregateCounts(m_clusterId.longValue(),
+        "many_per_cluster");
     assertEquals(2, summary.getOkCount());
     assertEquals(0, summary.getWarningCount());
     assertEquals(1, summary.getCriticalCount());
     assertEquals(0, summary.getUnknownCount());
 
-    summary = dao.findAggregateCounts(clusterId.longValue(), "foo");
+    summary = m_dao.findAggregateCounts(m_clusterId.longValue(), "foo");
     assertEquals(0, summary.getOkCount());
     assertEquals(0, summary.getWarningCount());
     assertEquals(0, summary.getCriticalCount());
@@ -484,7 +537,7 @@ public class AlertsDAOTest {
    */
   @Test
   public void testJPAInnerEntityStaleness() {
-    List<AlertCurrentEntity> currents = dao.findCurrent();
+    List<AlertCurrentEntity> currents = m_dao.findCurrent();
     AlertCurrentEntity current = currents.get(0);
     AlertHistoryEntity oldHistory = current.getAlertHistory();
 
@@ -506,14 +559,14 @@ public class AlertsDAOTest {
     newHistory.setHostName(oldHistory.getHostName());
     newHistory.setServiceName(oldHistory.getServiceName());
 
-    dao.create(newHistory);
+    m_dao.create(newHistory);
 
     assertTrue(newHistory.getAlertId().longValue() != oldHistory.getAlertId().longValue());
 
     current.setAlertHistory(newHistory);
-    dao.merge(current);
+    m_dao.merge(current);
 
-    AlertCurrentEntity newCurrent = dao.findCurrentByHostAndName(
+    AlertCurrentEntity newCurrent = m_dao.findCurrentByHostAndName(
         newHistory.getClusterId(),
         newHistory.getHostName(),
         newHistory.getAlertDefinition().getDefinitionName());
@@ -524,4 +577,267 @@ public class AlertsDAOTest {
     assertEquals(newHistory.getAlertState(),
         newCurrent.getAlertHistory().getAlertState());
   }
+
+  /**
+   * Tests that maintenance mode is set correctly on notices.
+   *
+   * @throws Exception
+   */
+  @Test
+  public void testMaintenanceMode() throws Exception {
+    Cluster cluster = initializeNewCluster();
+
+    List<AlertCurrentEntity> currents = m_dao.findCurrent();
+    for (AlertCurrentEntity current : currents) {
+      m_dao.remove(current);
+    }
+
+    // create some definitions
+    AlertDefinitionEntity namenode = new AlertDefinitionEntity();
+    namenode.setDefinitionName("NAMENODE");
+    namenode.setServiceName("HDFS");
+    namenode.setComponentName("NAMENODE");
+    namenode.setClusterId(cluster.getClusterId());
+    namenode.setHash(UUID.randomUUID().toString());
+    namenode.setScheduleInterval(Integer.valueOf(60));
+    namenode.setScope(Scope.ANY);
+    namenode.setSource("{\"type\" : \"SCRIPT\"}");
+    namenode.setSourceType(SourceType.SCRIPT);
+    m_definitionDao.create(namenode);
+
+    AlertDefinitionEntity datanode = new AlertDefinitionEntity();
+    datanode.setDefinitionName("DATANODE");
+    datanode.setServiceName("HDFS");
+    datanode.setComponentName("DATANODE");
+    datanode.setClusterId(cluster.getClusterId());
+    datanode.setHash(UUID.randomUUID().toString());
+    datanode.setScheduleInterval(Integer.valueOf(60));
+    datanode.setScope(Scope.HOST);
+    datanode.setSource("{\"type\" : \"SCRIPT\"}");
+    datanode.setSourceType(SourceType.SCRIPT);
+    m_definitionDao.create(datanode);
+
+    AlertDefinitionEntity aggregate = new AlertDefinitionEntity();
+    aggregate.setDefinitionName("DATANODE_UP");
+    aggregate.setServiceName("HDFS");
+    aggregate.setComponentName(null);
+    aggregate.setClusterId(cluster.getClusterId());
+    aggregate.setHash(UUID.randomUUID().toString());
+    aggregate.setScheduleInterval(Integer.valueOf(60));
+    aggregate.setScope(Scope.SERVICE);
+    aggregate.setSource("{\"type\" : \"SCRIPT\"}");
+    aggregate.setSourceType(SourceType.SCRIPT);
+    m_definitionDao.create(aggregate);
+
+    // create some history
+    AlertHistoryEntity nnHistory = new AlertHistoryEntity();
+    nnHistory.setAlertState(AlertState.OK);
+    nnHistory.setServiceName(namenode.getServiceName());
+    nnHistory.setComponentName(namenode.getComponentName());
+    nnHistory.setClusterId(cluster.getClusterId());
+    nnHistory.setAlertDefinition(namenode);
+    nnHistory.setAlertLabel(namenode.getDefinitionName());
+    nnHistory.setAlertText(namenode.getDefinitionName());
+    nnHistory.setAlertTimestamp(calendar.getTimeInMillis());
+    nnHistory.setHostName(HOSTNAME);
+    m_dao.create(nnHistory);
+
+    AlertCurrentEntity nnCurrent = new AlertCurrentEntity();
+    nnCurrent.setAlertHistory(nnHistory);
+    nnCurrent.setLatestText(nnHistory.getAlertText());
+    nnCurrent.setMaintenanceState(MaintenanceState.OFF);
+    nnCurrent.setOriginalTimestamp(System.currentTimeMillis());
+    nnCurrent.setLatestTimestamp(System.currentTimeMillis());
+    m_dao.create(nnCurrent);
+
+    AlertHistoryEntity dnHistory = new AlertHistoryEntity();
+    dnHistory.setAlertState(AlertState.WARNING);
+    dnHistory.setServiceName(datanode.getServiceName());
+    dnHistory.setComponentName(datanode.getComponentName());
+    dnHistory.setClusterId(cluster.getClusterId());
+    dnHistory.setAlertDefinition(datanode);
+    dnHistory.setAlertLabel(datanode.getDefinitionName());
+    dnHistory.setAlertText(datanode.getDefinitionName());
+    dnHistory.setAlertTimestamp(calendar.getTimeInMillis());
+    dnHistory.setHostName(HOSTNAME);
+    m_dao.create(dnHistory);
+
+    AlertCurrentEntity dnCurrent = new AlertCurrentEntity();
+    dnCurrent.setAlertHistory(dnHistory);
+    dnCurrent.setLatestText(dnHistory.getAlertText());
+    dnCurrent.setMaintenanceState(MaintenanceState.OFF);
+    dnCurrent.setOriginalTimestamp(System.currentTimeMillis());
+    dnCurrent.setLatestTimestamp(System.currentTimeMillis());
+    m_dao.create(dnCurrent);
+
+    AlertHistoryEntity aggregateHistory = new AlertHistoryEntity();
+    aggregateHistory.setAlertState(AlertState.CRITICAL);
+    aggregateHistory.setServiceName(aggregate.getServiceName());
+    aggregateHistory.setComponentName(aggregate.getComponentName());
+    aggregateHistory.setClusterId(cluster.getClusterId());
+    aggregateHistory.setAlertDefinition(aggregate);
+    aggregateHistory.setAlertLabel(aggregate.getDefinitionName());
+    aggregateHistory.setAlertText(aggregate.getDefinitionName());
+    aggregateHistory.setAlertTimestamp(calendar.getTimeInMillis());
+    m_dao.create(aggregateHistory);
+
+    AlertCurrentEntity aggregateCurrent = new AlertCurrentEntity();
+    aggregateCurrent.setAlertHistory(aggregateHistory);
+    aggregateCurrent.setLatestText(aggregateHistory.getAlertText());
+    aggregateCurrent.setMaintenanceState(MaintenanceState.OFF);
+    aggregateCurrent.setOriginalTimestamp(System.currentTimeMillis());
+    aggregateCurrent.setLatestTimestamp(System.currentTimeMillis());
+    m_dao.create(aggregateCurrent);
+
+    currents = m_dao.findCurrent();
+    assertEquals(3, currents.size());
+
+    for (AlertCurrentEntity current : currents) {
+      assertEquals(MaintenanceState.OFF, current.getMaintenanceState());
+    }
+
+    // turn on HDFS MM
+    Service hdfs = m_clusters.getClusterById(cluster.getClusterId()).getService(
+        "HDFS");
+
+    hdfs.setMaintenanceState(MaintenanceState.ON);
+
+    currents = m_dao.findCurrent();
+    assertEquals(3, currents.size());
+    for (AlertCurrentEntity current : currents) {
+      assertEquals(MaintenanceState.ON, current.getMaintenanceState());
+    }
+
+    // turn HDFS MM off
+    hdfs.setMaintenanceState(MaintenanceState.OFF);
+
+    currents = m_dao.findCurrent();
+    assertEquals(3, currents.size());
+    for (AlertCurrentEntity current : currents) {
+      assertEquals(MaintenanceState.OFF, current.getMaintenanceState());
+    }
+
+    // turn on host MM
+    Host host = m_clusters.getHost(HOSTNAME);
+    host.setMaintenanceState(cluster.getClusterId(), MaintenanceState.ON);
+
+    // only NAMENODE and DATANODE should be in MM; the aggregate should not
+    // since the host is in MM
+    currents = m_dao.findCurrent();
+    assertEquals(3, currents.size());
+    for (AlertCurrentEntity current : currents) {
+      if (current.getAlertHistory().getComponentName() != null) {
+        assertEquals(MaintenanceState.ON, current.getMaintenanceState());
+      } else {
+        assertEquals(MaintenanceState.OFF, current.getMaintenanceState());
+      }
+    }
+
+    // turn host MM off
+    host.setMaintenanceState(cluster.getClusterId(), MaintenanceState.OFF);
+
+    currents = m_dao.findCurrent();
+    assertEquals(3, currents.size());
+    for (AlertCurrentEntity current : currents) {
+      assertEquals(MaintenanceState.OFF, current.getMaintenanceState());
+    }
+
+    // turn a component MM on
+    ServiceComponentHost nnComponent = null;
+    List<ServiceComponentHost> schs = cluster.getServiceComponentHosts(HOSTNAME);
+    for (ServiceComponentHost sch : schs) {
+      if ("NAMENODE".equals(sch.getServiceComponentName())) {
+        sch.setMaintenanceState(MaintenanceState.ON);
+        nnComponent = sch;
+      }
+    }
+
+    assertNotNull(nnComponent);
+
+    currents = m_dao.findCurrent();
+    assertEquals(3, currents.size());
+    for (AlertCurrentEntity current : currents) {
+      if ("NAMENODE".equals(current.getAlertHistory().getComponentName())) {
+        assertEquals(MaintenanceState.ON, current.getMaintenanceState());
+      } else {
+        assertEquals(MaintenanceState.OFF, current.getMaintenanceState());
+      }
+    }
+
+  }
+
+  private Cluster initializeNewCluster() throws Exception {
+    String clusterName = "cluster-" + System.currentTimeMillis();
+    m_clusters.addCluster(clusterName);
+
+    Cluster cluster = m_clusters.getCluster(clusterName);
+    cluster.setDesiredStackVersion(new StackId("HDP", "2.0.6"));
+
+    addHost();
+    m_clusters.mapHostToCluster(HOSTNAME, cluster.getClusterName());
+
+    installHdfsService(cluster);
+    return cluster;
+  }
+
+  /**
+   * @throws Exception
+   */
+  private void addHost() throws Exception {
+    m_clusters.addHost(HOSTNAME);
+
+    Host host = m_clusters.getHost(HOSTNAME);
+    Map<String, String> hostAttributes = new HashMap<String, String>();
+    hostAttributes.put("os_family", "redhat");
+    hostAttributes.put("os_release_version", "6.4");
+    host.setHostAttributes(hostAttributes);
+    host.setState(HostState.HEALTHY);
+    host.persist();
+  }
+
+  /**
+   * Calls {@link Service#persist()} to mock a service install along with
+   * creating a single {@link Host} and {@link ServiceComponentHost}.
+   */
+  private void installHdfsService(Cluster cluster) throws Exception {
+    String serviceName = "HDFS";
+    Service service = m_serviceFactory.createNew(cluster, serviceName);
+    cluster.addService(service);
+    service.persist();
+    service = cluster.getService(serviceName);
+    Assert.assertNotNull(service);
+
+    ServiceComponent datanode = m_componentFactory.createNew(service,
+        "DATANODE");
+
+    service.addServiceComponent(datanode);
+    datanode.setDesiredState(State.INSTALLED);
+    datanode.persist();
+
+    ServiceComponentHost sch = m_schFactory.createNew(datanode, HOSTNAME);
+
+    datanode.addServiceComponentHost(sch);
+    sch.setDesiredState(State.INSTALLED);
+    sch.setState(State.INSTALLED);
+    sch.setDesiredStackVersion(new StackId("HDP-2.0.6"));
+    sch.setStackVersion(new StackId("HDP-2.0.6"));
+
+    sch.persist();
+
+    ServiceComponent namenode = m_componentFactory.createNew(service,
+        "NAMENODE");
+
+    service.addServiceComponent(namenode);
+    namenode.setDesiredState(State.INSTALLED);
+    namenode.persist();
+
+    sch = m_schFactory.createNew(namenode, HOSTNAME);
+    namenode.addServiceComponentHost(sch);
+    sch.setDesiredState(State.INSTALLED);
+    sch.setState(State.INSTALLED);
+    sch.setDesiredStackVersion(new StackId("HDP-2.0.6"));
+    sch.setStackVersion(new StackId("HDP-2.0.6"));
+
+    sch.persist();
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/3e54f956/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java
index 502c3b9..f2c4053 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java
@@ -50,6 +50,7 @@ import org.apache.ambari.server.orm.entities.AlertNoticeEntity;
 import org.apache.ambari.server.orm.entities.AlertTargetEntity;
 import org.apache.ambari.server.state.Alert;
 import org.apache.ambari.server.state.AlertState;
+import org.apache.ambari.server.state.MaintenanceState;
 import org.apache.ambari.server.state.alert.AggregateDefinitionMapping;
 import org.apache.ambari.server.state.alert.AggregateSource;
 import org.apache.ambari.server.state.alert.AlertDefinition;
@@ -250,6 +251,13 @@ public class AlertDataManagerTest {
     List<AlertHistoryEntity> histories = dao.findAll(clusterId);
     assertEquals(1, histories.size());
 
+    AlertCurrentEntity currentAlert = new AlertCurrentEntity();
+    currentAlert.setAlertHistory(histories.get(0));
+    currentAlert.setMaintenanceState(MaintenanceState.OFF);
+    currentAlert.setOriginalTimestamp(System.currentTimeMillis());
+    currentAlert.setLatestTimestamp(System.currentTimeMillis());
+    dao.create(currentAlert);
+
     AlertTargetEntity target = helper.createAlertTarget();
     Set<AlertTargetEntity> targets = new HashSet<AlertTargetEntity>();
     targets.add(target);
@@ -262,7 +270,7 @@ public class AlertDataManagerTest {
         AlertState.OK);
 
     AlertStateChangeEvent event = new AlertStateChangeEvent(clusterId, alert1,
-        histories.get(0), AlertState.CRITICAL);
+        currentAlert, AlertState.CRITICAL);
 
     AlertStateChangedListener listener = injector.getInstance(AlertStateChangedListener.class);
     listener.onAlertEvent(event);


[04/50] [abbrv] git commit: Merge branch 'trunk' into branch-alerts-dev

Posted by jo...@apache.org.
Merge branch 'trunk' into branch-alerts-dev

Conflicts:
	ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
	ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
	ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
	ambari-server/src/main/java/org/apache/ambari/server/utils/StageUtils.java
	ambari-server/src/test/java/org/apache/ambari/server/utils/TestStageUtils.java


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

Branch: refs/heads/trunk
Commit: ae8f1e77eafe32c2ad8bded7da24a2cef07b605f
Parents: 4a4644b a826334
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Wed Aug 27 10:04:14 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Wed Aug 27 10:04:14 2014 -0400

----------------------------------------------------------------------
 ambari-agent/conf/unix/install-helper.sh        |   7 -
 ambari-agent/pom.xml                            |  11 +-
 ambari-server/conf/unix/install-helper.sh       |   3 -
 .../server/actionmanager/ActionScheduler.java   |  33 ++
 .../ambari/server/actionmanager/Stage.java      |  32 +-
 .../server/actionmanager/StageFactory.java      |   4 +-
 .../ambari/server/agent/ExecutionCommand.java   |   2 +-
 .../resources/RequestResourceDefinition.java    |  12 +-
 .../ServiceConfigVersionResourceDefinition.java |  10 +-
 .../server/api/services/AmbariMetaInfo.java     |  18 +
 .../stackadvisor/StackAdvisorHelper.java        |  14 +-
 .../stackadvisor/StackAdvisorHelper.java.orig   | 116 ----
 .../stackadvisor/StackAdvisorResponse.java      |  73 +++
 ...GetComponentLayoutRecommnedationCommand.java |   5 +-
 .../GetComponentLayoutValidationCommand.java    |   5 +-
 .../GetConfigurationRecommnedationCommand.java  |  18 +-
 .../GetConfigurationValidationCommand.java      |   5 +-
 .../commands/StackAdvisorCommand.java           |  30 +-
 .../recommendations/RecommendationResponse.java |  38 +-
 .../validations/ValidationResponse.java         |  15 +-
 .../server/api/util/StackExtensionHelper.java   |   9 +
 .../controller/AmbariActionExecutionHelper.java |   9 +-
 .../AmbariCustomCommandExecutionHelper.java     |  34 +-
 .../AmbariManagementControllerImpl.java         | 184 ++++---
 .../server/controller/ClusterRequest.java       |  28 +-
 .../server/controller/ClusterResponse.java      |   9 +-
 .../server/controller/ConfigGroupRequest.java   |   9 +
 .../ambari/server/controller/HostRequest.java   |  11 +-
 .../controller/ServiceConfigVersionRequest.java |  23 +
 .../ServiceConfigVersionResponse.java           |  13 +-
 .../StackServiceComponentResponse.java          |  33 +-
 .../server/controller/StackServiceResponse.java |  16 +-
 .../internal/AbstractResourceProvider.java      |  92 ++--
 .../internal/BaseBlueprintProcessor.java        |  37 +-
 .../BlueprintConfigurationProcessor.java        |   5 +-
 .../internal/ClusterResourceProvider.java       | 126 +++--
 .../internal/ConfigGroupResourceProvider.java   |   4 +
 .../internal/HostResourceProvider.java          |  54 +-
 .../RecommendationResourceProvider.java         |   4 +-
 .../ServiceConfigVersionResourceProvider.java   |  12 +-
 .../StackServiceComponentResourceProvider.java  |  22 +-
 .../internal/StackServiceResourceProvider.java  |  22 +-
 .../internal/ValidationResourceProvider.java    |   4 +-
 .../internal/ViewInstanceResourceProvider.java  |   9 +-
 .../internal/ViewVersionResourceProvider.java   |   3 +
 .../ambari/server/orm/dao/ServiceConfigDAO.java |  41 +-
 .../server/orm/entities/AlertGroupEntity.java   |  74 ++-
 .../ambari/server/orm/entities/StageEntity.java |  28 +
 .../ambari/server/orm/entities/ViewEntity.java  |  39 +-
 .../ambari/server/stageplanner/RoleGraph.java   |   3 +-
 .../org/apache/ambari/server/state/Cluster.java |  15 +-
 .../ambari/server/state/ComponentInfo.java      |  14 +-
 .../ambari/server/state/ConfigHelper.java       |  15 +-
 .../apache/ambari/server/state/ServiceInfo.java |   9 +
 .../server/state/cluster/ClusterImpl.java       | 119 +++-
 .../server/upgrade/AbstractUpgradeCatalog.java  |   3 +-
 .../server/upgrade/UpgradeCatalog170.java       |  19 +-
 .../apache/ambari/server/utils/StageUtils.java  |  13 +-
 .../apache/ambari/server/view/ViewRegistry.java |  15 +
 .../server/view/configuration/ViewConfig.java   |  14 +
 .../main/resources/Ambari-DDL-MySQL-CREATE.sql  |   5 +-
 .../main/resources/Ambari-DDL-Oracle-CREATE.sql |   5 +-
 .../resources/Ambari-DDL-Postgres-CREATE.sql    |   5 +-
 .../Ambari-DDL-Postgres-EMBEDDED-CREATE.sql     |   5 +-
 .../main/resources/custom_actions/check_host.py |   7 +-
 .../src/main/resources/properties.json          |   7 +-
 .../src/main/resources/scripts/stack_advisor.py |   5 +-
 .../1.3.2/hooks/before-ANY/scripts/params.py    |   3 +-
 .../hooks/before-INSTALL/scripts/params.py      |   2 +-
 .../HDP/1.3.2/services/GANGLIA/metainfo.xml     |   3 +
 .../HDP/1.3.2/services/HBASE/metainfo.xml       |   4 +
 .../stacks/HDP/1.3.2/services/HDFS/metainfo.xml |   5 +
 .../stacks/HDP/1.3.2/services/HIVE/metainfo.xml |  11 +-
 .../services/HIVE/package/scripts/params.py     |   2 +-
 .../HDP/1.3.2/services/MAPREDUCE/metainfo.xml   |   5 +
 .../HDP/1.3.2/services/NAGIOS/metainfo.xml      |   2 +
 .../HDP/1.3.2/services/OOZIE/metainfo.xml       |   3 +
 .../stacks/HDP/1.3.2/services/PIG/metainfo.xml  |   2 +
 .../HDP/1.3.2/services/SQOOP/metainfo.xml       |   2 +
 .../HDP/1.3.2/services/WEBHCAT/metainfo.xml     |   4 +-
 .../HDP/1.3.2/services/ZOOKEEPER/metainfo.xml   |   3 +
 .../stacks/HDP/1.3.2/services/stack_advisor.py  | 519 ++++++++++++++++++
 .../stacks/HDP/1.3.3/services/stack_advisor.py  |  25 +
 .../stacks/HDP/1.3/services/stack_advisor.py    |  25 +
 .../2.0.6/hooks/before-ANY/scripts/params.py    |   3 +-
 .../hooks/before-INSTALL/scripts/params.py      |   2 +-
 .../HDP/2.0.6/services/FLUME/metainfo.xml       |   2 +
 .../HDP/2.0.6/services/GANGLIA/metainfo.xml     |   3 +
 .../HDP/2.0.6/services/HBASE/metainfo.xml       |   4 +
 .../stacks/HDP/2.0.6/services/HDFS/metainfo.xml |   7 +
 .../stacks/HDP/2.0.6/services/HIVE/metainfo.xml |  11 +-
 .../services/HIVE/package/scripts/params.py     |   2 +-
 .../HDP/2.0.6/services/NAGIOS/metainfo.xml      |   2 +
 .../HDP/2.0.6/services/OOZIE/metainfo.xml       |   3 +
 .../stacks/HDP/2.0.6/services/PIG/metainfo.xml  |   2 +
 .../HDP/2.0.6/services/SQOOP/metainfo.xml       |   2 +
 .../HDP/2.0.6/services/WEBHCAT/metainfo.xml     |   4 +-
 .../stacks/HDP/2.0.6/services/YARN/metainfo.xml |   7 +
 .../HDP/2.0.6/services/ZOOKEEPER/metainfo.xml   |   2 +
 .../FALCON/configuration/falcon-env.xml         |  63 +++
 .../2.1.GlusterFS/services/FALCON/metainfo.xml  |   2 +-
 .../services/FALCON/package/scripts/params.py   |  32 +-
 .../FALCON/package/scripts/status_params.py     |   2 +-
 .../GLUSTERFS/configuration/core-site.xml       |  26 -
 .../GLUSTERFS/configuration/hadoop-env.xml      | 207 +++++++
 .../services/GLUSTERFS/metainfo.xml             |   7 +-
 .../2.1.GlusterFS/services/OOZIE/metainfo.xml   |   2 +-
 .../services/STORM/configuration/storm-env.xml  |  39 ++
 .../2.1.GlusterFS/services/STORM/metainfo.xml   |   2 +-
 .../services/STORM/package/scripts/params.py    |  12 +-
 .../STORM/package/scripts/status_params.py      |   2 +-
 .../services/TEZ/configuration/tez-env.xml      |  29 +
 .../HDP/2.1.GlusterFS/services/TEZ/metainfo.xml |   2 +-
 .../services/TEZ/package/scripts/params.py      |   4 +-
 .../services/YARN/configuration/global.xml      |  64 ---
 .../services/YARN/configuration/yarn-env.xml    | 181 +++++++
 .../2.1.GlusterFS/services/YARN/metainfo.xml    |   3 +-
 .../services/YARN/package/scripts/params.py     |  41 +-
 .../YARN/package/scripts/status_params.py       |   8 +-
 .../stacks/HDP/2.1/services/FALCON/metainfo.xml |   3 +
 .../stacks/HDP/2.1/services/STORM/metainfo.xml  |   6 +
 .../stacks/HDP/2.1/services/TEZ/metainfo.xml    |   2 +
 .../stacks/HDP/2.1/services/YARN/metainfo.xml   |   2 +
 .../stacks/HDP/2.1/services/stack_advisor.py    |   7 -
 .../ExecutionCommandWrapperTest.java            |   2 +-
 .../actionmanager/TestActionDBAccessorImpl.java |  20 +-
 .../server/actionmanager/TestActionManager.java |  31 +-
 .../actionmanager/TestActionScheduler.java      |  33 +-
 .../ambari/server/actionmanager/TestStage.java  |   4 +-
 .../server/agent/TestHeartbeatHandler.java      |  15 +-
 .../server/agent/TestHeartbeatMonitor.java      |   4 +-
 .../server/api/services/AmbariMetaInfoTest.java |   9 +
 .../stackadvisor/StackAdvisorHelperTest.java    |  22 +-
 ...tConfigurationRecommnedationCommandTest.java | 103 ++++
 .../commands/StackAdvisorCommandTest.java       |  86 ++-
 .../api/util/StackExtensionHelperTest.java      |   2 +
 .../AmbariManagementControllerTest.java         | 164 +++---
 ...hYarnCapacitySchedulerReleaseConfigTest.java |   4 +-
 .../internal/ClusterResourceProviderTest.java   | 537 ++++++++++++++++++-
 .../internal/JMXHostProviderTest.java           |  10 +-
 .../RecommendationResourceProviderTest.java     |  31 ++
 .../ValidationResourceProviderTest.java         |  70 +++
 .../ViewInstanceResourceProviderTest.java       |  89 ++-
 .../server/stageplanner/TestStagePlanner.java   |   6 +-
 .../ambari/server/state/ConfigHelperTest.java   |   6 +-
 .../server/state/cluster/ClusterTest.java       |  66 ++-
 .../server/state/cluster/ClustersTest.java      |   3 +-
 .../svccomphost/ServiceComponentHostTest.java   |   3 +-
 .../server/upgrade/UpgradeCatalog170Test.java   |  41 +-
 .../server/upgrade/UpgradeCatalogTest.java      |   2 +-
 .../ambari/server/utils/TestStageUtils.java     |   6 +-
 .../view/configuration/ViewConfigTest.java      |   7 +
 ambari-server/src/test/python/TestCheckHost.py  |  29 +-
 .../stacks/1.3.2/HIVE/test_hive_metastore.py    |   4 +-
 .../stacks/1.3.2/HIVE/test_hive_server.py       |   4 +-
 .../1.3.2/hooks/before-ANY/test_before_any.py   |   6 +-
 .../hooks/before-INSTALL/test_before_install.py |   4 +-
 .../stacks/2.0.6/HIVE/test_hive_metastore.py    |   4 +-
 .../stacks/2.0.6/HIVE/test_hive_server.py       |   4 +-
 .../2.0.6/hooks/before-ANY/test_before_any.py   |   6 +-
 .../hooks/before-INSTALL/test_before_install.py |   4 +-
 .../stacks/2.1/HIVE/test_hive_metastore.py      |   4 +-
 .../HDP/2.0.6/services/NAGIOS/metainfo.xml      |   2 +
 .../HDP/2.0.6/services/WEBHCAT/metainfo.xml     |   1 +
 .../stacks/HDP/2.0.6/services/YARN/metainfo.xml |   4 +
 .../HDP/2.0.7/services/HBASE/metainfo.xml       |   4 +
 .../stacks/HDP/2.0.7/services/HDFS/metainfo.xml |   7 +
 .../stacks/HDP/2.0.7/services/HIVE/metainfo.xml |   5 +
 .../HDP/2.0.7/services/ZOOKEEPER/metainfo.xml   |   3 +
 .../HDP/2.0.8/services/SQOOP/metainfo.xml       |   1 +
 .../HDP/2.1.1/services/STORM/metainfo.xml       |   4 +
 .../org/apache/ambari/view/ViewDefinition.java  |   7 +
 .../data/configurations/service_version.json    |   7 +-
 .../data/configurations/service_versions.json   |  77 +--
 ambari-web/app/assets/test/tests.js             |   2 +
 ambari-web/app/config.js                        |   2 +-
 .../main/dashboard/config_history_controller.js |   4 +-
 .../controllers/main/service/info/configs.js    |   8 +-
 .../app/controllers/wizard/step3_controller.js  |   1 -
 ambari-web/app/data/HDP2/secure_properties.js   |   1 +
 ambari-web/app/data/HDP2/site_properties.js     | 178 +++---
 ambari-web/app/data/site_properties.js          | 160 +++---
 ambari-web/app/mappers.js                       |   1 +
 .../mappers/service_config_version_mapper.js    |   3 +-
 ambari-web/app/mappers/stack_service_mapper.js  |   2 +
 ambari-web/app/messages.js                      |   5 +-
 ambari-web/app/mixins.js                        |   1 -
 ambari-web/app/mixins/common/serverValidator.js |  19 +-
 ambari-web/app/mixins/models/service_mixin.js   |  30 --
 ambari-web/app/models/host_component.js         |  28 +-
 ambari-web/app/models/service.js                |   7 +-
 ambari-web/app/models/service_config_version.js |  12 +-
 ambari-web/app/models/stack_service.js          |  13 +-
 .../app/models/stack_service_component.js       |  10 +-
 ambari-web/app/styles/application.less          |  58 +-
 .../common/configs/config_history_flow.hbs      |  42 +-
 .../templates/main/dashboard/config_history.hbs |  11 +-
 ambari-web/app/utils/ajax/ajax.js               |   2 +-
 ambari-web/app/utils/config.js                  |   2 +-
 ambari-web/app/utils/helper.js                  |  15 +-
 .../views/common/configs/config_history_flow.js |  67 ++-
 .../common/configs/overriddenProperty_view.js   |   1 +
 .../app/views/common/configs/services_config.js |   3 +-
 .../views/main/dashboard/config_history_view.js |  12 +-
 ambari-web/test/app_test.js                     |  54 +-
 .../dashboard/config_history_controller_test.js |  25 +-
 ambari-web/test/models/host_component_test.js   | 212 +++++++-
 ambari-web/test/models/host_test.js             | 357 +++++++++++-
 ambari-web/test/models/service_test.js          |  59 +-
 ambari-web/test/models/stack_service_test.js    | 343 ++++++++++++
 ambari-web/test/service_components.js           |  61 +++
 ambari-web/test/utils/blueprint_test.js         |   1 -
 ambari-web/test/utils/date_test.js              |   4 +-
 .../common/configs/config_history_flow_test.js  |  26 +-
 .../src/main/resources/ui/app/styles/main.less  |   7 +-
 docs/pom.xml                                    |  18 +-
 216 files changed, 5151 insertions(+), 1390 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/ae8f1e77/ambari-agent/pom.xml
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae8f1e77/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
----------------------------------------------------------------------
diff --cc ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
index 0600f27,33c5af4..75ba178
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
@@@ -42,53 -42,23 +42,53 @@@ public class ExecutionCommand extends A
      super(AgentCommandType.EXECUTION_COMMAND);
    }
  
 +  @SerializedName("clusterName")
    private String clusterName;
 +
 +  @SerializedName("taskId")
    private long taskId;
 +
 +  @SerializedName("commandId")
    private String commandId;
 +
 +  @SerializedName("hostname")
    private String hostname;
 +
 +  @SerializedName("role")
    private String role;
 +
 +  @SerializedName("hostLevelParams")
    private Map<String, String> hostLevelParams = new HashMap<String, String>();
 +
 +  @SerializedName("roleParams")
    private Map<String, String> roleParams = null;
 +
 +  @SerializedName("roleCommand")
    private RoleCommand roleCommand;
 -  private Map<String, Set<String>> clusterHostInfo = 
 +
 +  @SerializedName("clusterHostInfo")
 +  private Map<String, Set<String>> clusterHostInfo =
        new HashMap<String, Set<String>>();
 +
 +  @SerializedName("configurations")
    private Map<String, Map<String, String>> configurations;
 +
    @SerializedName("configuration_attributes")
    private Map<String, Map<String, Map<String, String>>> configurationAttributes;
 +
 +  @SerializedName("configurationTags")
    private Map<String, Map<String, String>> configurationTags;
 +
 +  @SerializedName("forceRefreshConfigTags")
    private Set<String> forceRefreshConfigTags = new HashSet<String>();
 +
 +  @SerializedName("commandParams")
-   private Map<String, String> commandParams;
+   private Map<String, String> commandParams = new HashMap<String, String>();
 +
 +  @SerializedName("serviceName")
    private String serviceName;
 +
 +  @SerializedName("componentName")
    private String componentName;
  
    /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae8f1e77/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae8f1e77/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
----------------------------------------------------------------------
diff --cc ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
index 5d904ef,c3b6a86..b181399
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
@@@ -1370,10 -1338,9 +1370,10 @@@ public class ClusterImpl implements Clu
    }
  
    @Override
-   public ServiceConfigVersionResponse addDesiredConfig(String user, Config config, String serviceConfigVersionNote) {
+   public ServiceConfigVersionResponse addDesiredConfig(String user, Set<Config> configs, String serviceConfigVersionNote) {
 -    if (null == user)
 +    if (null == user) {
        throw new NullPointerException("User must be specified.");
 +    }
  
      clusterGlobalLock.readLock().lock();
      try {
@@@ -1525,10 -1505,9 +1538,10 @@@
    }
  
    @Override
-   public boolean setServiceConfigVersion(String serviceName, Long version, String user, String note) throws AmbariException {
+   public ServiceConfigVersionResponse setServiceConfigVersion(String serviceName, Long version, String user, String note) throws AmbariException {
 -    if (null == user)
 +    if (null == user) {
        throw new NullPointerException("User must be specified.");
 +    }
  
      clusterGlobalLock.writeLock().lock();
      try {
@@@ -1644,9 -1653,18 +1687,18 @@@
      serviceConfigVersionResponse.setClusterName(getClusterName());
      serviceConfigVersionResponse.setServiceName(serviceConfigEntity.getServiceName());
      serviceConfigVersionResponse.setVersion(serviceConfigEntity.getVersion());
 -    serviceConfigVersionResponse.setCreateTime(serviceConfigEntity.getCreateTimestamp());    
 +    serviceConfigVersionResponse.setCreateTime(serviceConfigEntity.getCreateTimestamp());
      serviceConfigVersionResponse.setUserName(serviceConfigEntity.getUser());
      serviceConfigVersionResponse.setNote(serviceConfigEntity.getNote());
+     if (clusterConfigGroups != null) {
+       ConfigGroup configGroup = clusterConfigGroups.get(serviceConfigEntity.getGroupId());
+       if (configGroup != null) {
+         serviceConfigVersionResponse.setGroupId(configGroup.getId());
+         serviceConfigVersionResponse.setGroupName(configGroup.getName());
+       }
+     }
+ 
+ 
      return serviceConfigVersionResponse;
    }
  

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae8f1e77/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
----------------------------------------------------------------------
diff --cc ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
index 0acd61b,0ac9da7..0884c50
--- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
@@@ -73,8 -73,6 +73,7 @@@ import org.apache.ambari.server.state.C
  import org.apache.ambari.server.state.Clusters;
  import org.apache.ambari.server.state.Config;
  import org.apache.ambari.server.state.ConfigHelper;
 +import org.apache.ambari.server.state.alert.Scope;
- import org.apache.ambari.server.view.configuration.InstanceConfig;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae8f1e77/ambari-server/src/main/java/org/apache/ambari/server/utils/StageUtils.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae8f1e77/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae8f1e77/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae8f1e77/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae8f1e77/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae8f1e77/ambari-server/src/main/resources/properties.json
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae8f1e77/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae8f1e77/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae8f1e77/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java
----------------------------------------------------------------------
diff --cc ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java
index d7c8c54,5d85b0d..79ae350
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java
@@@ -1045,9 -1042,9 +1046,9 @@@ public class ServiceComponentHostTest 
      config.setTag(tag);
      config.persist();
      cluster.addConfig(config);
-     cluster.addDesiredConfig("user", config);
+     cluster.addDesiredConfig("user", Collections.singleton(config));
    }
 -  
 +
    @Test
    public void testMaintenance() throws Exception {
      String stackVersion="HDP-2.0.6";

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae8f1e77/ambari-server/src/test/java/org/apache/ambari/server/utils/TestStageUtils.java
----------------------------------------------------------------------
diff --cc ambari-server/src/test/java/org/apache/ambari/server/utils/TestStageUtils.java
index d3f0e37,988c67b..8b134c4
--- a/ambari-server/src/test/java/org/apache/ambari/server/utils/TestStageUtils.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/utils/TestStageUtils.java
@@@ -152,8 -147,8 +152,8 @@@ public class TestStageUtils 
    @Ignore
    public void testJasonToExecutionCommand() throws JsonGenerationException,
        JsonMappingException, JAXBException, IOException {
-     Stage s = StageUtils.getATestStage(1, 2, "host1", "clusterHostInfo");
+     Stage s = StageUtils.getATestStage(1, 2, "host1", "clusterHostInfo", "hostParamsStage");
 -    ExecutionCommand cmd = s.getExecutionCommands("host1").get(0).getExecutionCommand();    
 +    ExecutionCommand cmd = s.getExecutionCommands("host1").get(0).getExecutionCommand();
      HashMap<String, Map<String,String>> configTags = new HashMap<String, Map<String,String>>();
      Map<String, String> globalTag = new HashMap<String, String>();
      globalTag.put("tag", "version1");


[05/50] [abbrv] git commit: AMBARI-7051 - Alerts: Expose Creation and Updating of Group Targets & Definitions (jonathanhurley)

Posted by jo...@apache.org.
AMBARI-7051 - Alerts: Expose Creation and Updating of Group Targets & Definitions (jonathanhurley)


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

Branch: refs/heads/trunk
Commit: 76fc94ec1ab6ee904e0efa254c19521a201c06d4
Parents: ae8f1e7
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Wed Aug 27 21:07:43 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Thu Aug 28 09:38:28 2014 -0400

----------------------------------------------------------------------
 .../python/ambari_agent/alerts/base_alert.py    |  45 ++-
 .../python/ambari_agent/alerts/port_alert.py    |  42 +--
 .../server/api/services/AlertGroupService.java  |  10 +
 .../controller/AlertDefinitionResponse.java     | 143 +++++++++
 .../internal/AlertGroupResourceProvider.java    | 144 ++++++++-
 .../server/orm/dao/AlertDefinitionDAO.java      |  16 +
 .../ambari/server/orm/dao/AlertDispatchDAO.java |  18 +-
 .../orm/entities/AlertDefinitionEntity.java     |  37 ++-
 .../server/orm/entities/AlertGroupEntity.java   |  56 +++-
 .../server/orm/entities/AlertTargetEntity.java  |   3 +-
 .../ambari/server/state/alert/AlertTarget.java  |  37 ++-
 .../AlertGroupResourceProviderTest.java         | 295 +++++++++++++++----
 .../AlertTargetResourceProviderTest.java        |   2 +-
 .../server/orm/dao/AlertDefinitionDAOTest.java  |  18 +-
 .../server/orm/dao/AlertDispatchDAOTest.java    |  53 ++--
 15 files changed, 773 insertions(+), 146 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/76fc94ec/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py b/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py
index 88c7f92..bf8ada6 100644
--- a/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py
+++ b/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py
@@ -34,7 +34,7 @@ class BaseAlert(object):
     self.alert_meta = alert_meta
     self.alert_source_meta = alert_source_meta
     self.cluster = ''
-    self.hostName = ''
+    self.host_name = ''
     self._lookup_keys = []
     
     
@@ -54,7 +54,7 @@ class BaseAlert(object):
   def set_cluster(self, cluster, host):
     ''' sets cluster information for the alert '''
     self.cluster = cluster
-    self.hostName = host
+    self.host_name = host
   
   def collect(self):
     ''' method used for collection.  defers to _collect() '''
@@ -123,4 +123,43 @@ class BaseAlert(object):
     res[0] = the result code
     res[1] = the list of arguments supplied to the reporting text for the result code
     '''  
-    raise NotImplementedError
\ No newline at end of file
+    raise NotImplementedError
+
+  '''
+  See RFC3986, Appendix B
+  Tested on the following cases:
+    "192.168.54.1"
+    "192.168.54.2:7661
+    "hdfs://192.168.54.3/foo/bar"
+    "ftp://192.168.54.4:7842/foo/bar"
+
+    Returns None if only a port is passsed in
+  '''
+  @staticmethod
+  def get_host_from_url(uri):
+    # RFC3986, Appendix B
+    parts = re.findall('^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?', uri)
+
+    # index of parts
+    # scheme    = 1
+    # authority = 3
+    # path      = 4
+    # query     = 6
+    # fragment  = 8
+
+    host_and_port = uri
+    if 0 == len(parts[0][1]):
+      host_and_port = parts[0][4]
+    elif 0 == len(parts[0][2]):
+      host_and_port = parts[0][1]
+    elif parts[0][2].startswith("//"):
+      host_and_port = parts[0][3]
+
+    if -1 == host_and_port.find(':'):
+      # if no : then it might only be a port; if it's a port, return this host
+      if host_and_port.isdigit():
+        return None
+
+      return host_and_port
+    else:
+      return host_and_port.split(':')[0]

http://git-wip-us.apache.org/repos/asf/ambari/blob/76fc94ec/ambari-agent/src/main/python/ambari_agent/alerts/port_alert.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/alerts/port_alert.py b/ambari-agent/src/main/python/ambari_agent/alerts/port_alert.py
index eaf744a..1d34410 100644
--- a/ambari-agent/src/main/python/ambari_agent/alerts/port_alert.py
+++ b/ambari-agent/src/main/python/ambari_agent/alerts/port_alert.py
@@ -39,9 +39,11 @@ class PortAlert(BaseAlert):
   def _collect(self):
     urivalue = self._lookup_property_value(self.uri)
 
-    host = get_host_from_url(self, urivalue)
     port = self.port
-    
+    host = BaseAlert.get_host_from_url(urivalue)
+    if host is None:
+      host = self.host_name
+
     try:
       port = int(get_port_from_url(urivalue))
     except:
@@ -67,39 +69,3 @@ class PortAlert(BaseAlert):
         except:
           pass
 
-'''
-See RFC3986, Appendix B
-Tested on the following cases:
-  "192.168.54.1"
-  "192.168.54.2:7661
-  "hdfs://192.168.54.3/foo/bar"
-  "ftp://192.168.54.4:7842/foo/bar"
-'''    
-def get_host_from_url(self, uri):
-  # RFC3986, Appendix B
-  parts = re.findall('^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?', uri)
-
-  # index of parts
-  # scheme    = 1
-  # authority = 3
-  # path      = 4
-  # query     = 6
-  # fragment  = 8
- 
-  host_and_port = uri
-  if 0 == len(parts[0][1]):
-    host_and_port = parts[0][4]
-  elif 0 == len(parts[0][2]):
-    host_and_port = parts[0][1]
-  elif parts[0][2].startswith("//"):
-    host_and_port = parts[0][3]
-
-  if -1 == host_and_port.find(':'):
-    # if no : then it might only be a port; if it's a port, return this host
-    if host_and_port.isdigit():
-      return self.hostName
-
-    return host_and_port
-  else:
-    return host_and_port.split(':')[0]
-

http://git-wip-us.apache.org/repos/asf/ambari/blob/76fc94ec/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertGroupService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertGroupService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertGroupService.java
index c2e5048..12cdb70 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertGroupService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertGroupService.java
@@ -23,6 +23,7 @@ import java.util.Map;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
@@ -80,6 +81,15 @@ public class AlertGroupService extends BaseService {
         createAlertGroupResource(m_clusterName, null));
   }
 
+  @PUT
+  @Produces("text/plain")
+  @Path("{groupId}")
+  public Response updateGroup(String body, @Context HttpHeaders headers,
+      @Context UriInfo ui, @PathParam("groupId") Long groupId) {
+    return handleRequest(headers, body, ui, Request.Type.PUT,
+        createAlertGroupResource(m_clusterName, groupId));
+  }
+
   @DELETE
   @Produces("text/plain")
   @Path("{groupId}")

http://git-wip-us.apache.org/repos/asf/ambari/blob/76fc94ec/ambari-server/src/main/java/org/apache/ambari/server/controller/AlertDefinitionResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AlertDefinitionResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AlertDefinitionResponse.java
new file mode 100644
index 0000000..26e2f24
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AlertDefinitionResponse.java
@@ -0,0 +1,143 @@
+/**
+® * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.controller;
+
+import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
+import org.codehaus.jackson.annotate.JsonProperty;
+
+
+/**
+ * The {@link AlertDefinitionResponse} encapsulates the definition information
+ * that should be serialized and returned in REST requests for alerts, groups,
+ * and targets.
+ */
+public class AlertDefinitionResponse {
+
+  private String serviceName = null;
+  private String componentName = null;
+  private String name = null;
+  private String label = null;
+  private Long definitionId;
+
+  /**
+   * @return the definitionId
+   */
+  @JsonProperty("id")
+  public Long getDefinitionId() {
+    return definitionId;
+  }
+
+  /**
+   * @param definitionId
+   *          the definitionId to set
+   */
+  public void setDefinitionId(Long definitionId) {
+    this.definitionId = definitionId;
+  }
+
+  /**
+   * @return the service name
+   */
+  @JsonProperty("service_name")
+  public String getServiceName() {
+    return serviceName;
+  }
+
+  /**
+   * @param name the service name
+   */
+  public void setServiceName(String name) {
+    serviceName = name;
+  }
+
+  /**
+   * @return the component name
+   */
+  @JsonProperty("component_name")
+  public String getComponentName() {
+    return componentName;
+  }
+
+  /**
+   *
+   * @param name the component name
+   */
+  public void setComponentName(String name) {
+    componentName = name;
+  }
+
+  /**
+   * @return the name
+   */
+  @JsonProperty("name")
+  public String getName() {
+    return name;
+  }
+
+  /**
+   * @param definitionName
+   *          the definition name.
+   */
+  public void setName(String definitionName) {
+    name = definitionName;
+  }
+
+  /**
+   * @return the label for the definition or {@code null} if none.
+   */
+  @JsonProperty("label")
+  public String getLabel() {
+    return label;
+  }
+
+  /**
+   * Sets the label for this definition.
+   *
+   * @param definitionLabel
+   */
+  public void setLabel(String definitionLabel) {
+    label = definitionLabel;
+  }
+
+  @Override
+  public String toString() {
+    return name;
+  }
+
+  /**
+   * Gets an {@link AlertDefinitionResponse} from the supplied entity.
+   *
+   * @param entity
+   *          the entity (not {@code null}).
+   * @return the response.
+   */
+  public static AlertDefinitionResponse coerce(AlertDefinitionEntity entity) {
+    if (null == entity) {
+      return null;
+    }
+
+    AlertDefinitionResponse response = new AlertDefinitionResponse();
+    response.setDefinitionId(entity.getDefinitionId());
+    response.setComponentName(entity.getComponentName());
+    response.setLabel(entity.getLabel());
+    response.setName(entity.getDefinitionName());
+    response.setServiceName(entity.getServiceName());
+
+    return response;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/76fc94ec/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProvider.java
index f14e76f..fc51ddd 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProvider.java
@@ -17,14 +17,17 @@
  */
 package org.apache.ambari.server.controller.internal;
 
+import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.AlertDefinitionResponse;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
 import org.apache.ambari.server.controller.spi.NoSuchResourceException;
@@ -36,11 +39,14 @@ import org.apache.ambari.server.controller.spi.Resource.Type;
 import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
 import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
 import org.apache.ambari.server.orm.dao.AlertDispatchDAO;
+import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
 import org.apache.ambari.server.orm.entities.AlertGroupEntity;
 import org.apache.ambari.server.orm.entities.AlertTargetEntity;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.alert.AlertGroup;
+import org.apache.ambari.server.state.alert.AlertTarget;
 import org.apache.commons.lang.StringUtils;
 
 import com.google.inject.Inject;
@@ -66,12 +72,16 @@ public class AlertGroupResourceProvider extends
       Arrays.asList(ALERT_GROUP_ID, ALERT_GROUP_CLUSTER_NAME));
 
   /**
-   * Group DAO
+   * Group/Target DAO
    */
-  @Inject
   private static AlertDispatchDAO s_dao;
 
   /**
+   * Definitions DAO
+   */
+  private static AlertDefinitionDAO s_definitionDao;
+
+  /**
    * Initializes the injectable members of this class with the specified
    * injector.
    *
@@ -81,6 +91,7 @@ public class AlertGroupResourceProvider extends
   @Inject
   public static void init(Injector injector) {
     s_dao = injector.getInstance(AlertDispatchDAO.class);
+    s_definitionDao = injector.getInstance(AlertDefinitionDAO.class);
   }
 
   /**
@@ -156,11 +167,21 @@ public class AlertGroupResourceProvider extends
   }
 
   @Override
-  public RequestStatus updateResources(Request request, Predicate predicate)
+  public RequestStatus updateResources(final Request request,
+      Predicate predicate)
       throws SystemException, UnsupportedPropertyException,
       NoSuchResourceException, NoSuchParentResourceException {
 
-    throw new UnsupportedOperationException();
+    modifyResources(new Command<Void>() {
+      @Override
+      public Void invoke() throws AmbariException {
+        updateAlertGroups(request.getProperties());
+        return null;
+      }
+    });
+
+    notifyUpdate(Resource.Type.AlertGroup, request, predicate);
+    return getRequestStatus(null);
   }
 
   @Override
@@ -207,6 +228,7 @@ public class AlertGroupResourceProvider extends
    * @param requestMaps
    * @throws AmbariException
    */
+  @SuppressWarnings("unchecked")
   private void createAlertGroups(Set<Map<String, Object>> requestMaps)
       throws AmbariException {
 
@@ -231,9 +253,27 @@ public class AlertGroupResourceProvider extends
           clusterName);
 
       entity.setClusterId(cluster.getClusterId());
-      entity.setDefault(false);
       entity.setGroupName(name);
 
+      // groups created through the provider are not default service groups
+      entity.setDefault(false);
+
+      // targets are not required on creation
+      if (requestMap.containsKey(ALERT_GROUP_TARGETS)) {
+        List<Long> targetIds = (List<Long>) requestMap.get(ALERT_GROUP_TARGETS);
+        Set<AlertTargetEntity> targets = new HashSet<AlertTargetEntity>();
+        targets.addAll(s_dao.findTargetsById(targetIds));
+        entity.setAlertTargets(targets);
+      }
+
+      // definitions are not required on creation
+      if (requestMap.containsKey(ALERT_GROUP_DEFINITIONS)) {
+        List<Long> definitionIds = (List<Long>) requestMap.get(ALERT_GROUP_DEFINITIONS);
+        Set<AlertDefinitionEntity> definitions = new HashSet<AlertDefinitionEntity>();
+        definitions.addAll(s_definitionDao.findByIds(definitionIds));
+        entity.setAlertDefinitions(definitions);
+      }
+
       entities.add(entity);
     }
 
@@ -241,6 +281,74 @@ public class AlertGroupResourceProvider extends
   }
 
   /**
+   * Updates existing {@link AlertGroupEntity}s with the specified properties.
+   *
+   * @param requestMaps
+   *          a set of property maps, one map for each entity.
+   * @throws AmbariException
+   *           if the entity could not be found.
+   */
+  @SuppressWarnings("unchecked")
+  private void updateAlertGroups(Set<Map<String, Object>> requestMaps)
+      throws AmbariException {
+
+    for (Map<String, Object> requestMap : requestMaps) {
+      String stringId = (String) requestMap.get(ALERT_GROUP_ID);
+
+      if( StringUtils.isEmpty(stringId)){
+        throw new IllegalArgumentException("The ID of the alert group is required when updating an existing group");
+      }
+
+      long id = Long.parseLong(stringId);
+      AlertGroupEntity entity = s_dao.findGroupById(id);
+
+      if( null == entity ){
+        String message = MessageFormat.format("The alert group with ID {0} could not be found", id);
+        throw new AmbariException(message);
+      }
+
+      String name = (String) requestMap.get(ALERT_GROUP_NAME);
+
+      // empty arrays are deserialized as HashSet while populated arrays
+      // are deserialized as ArrayList; use Collection for safety
+      Collection<Long> targetIds = (Collection<Long>) requestMap.get(ALERT_GROUP_TARGETS);
+      Collection<Long> definitionIds = (Collection<Long>) requestMap.get(ALERT_GROUP_DEFINITIONS);
+
+      if (!StringUtils.isBlank(name)) {
+        entity.setGroupName(name);
+      }
+
+      // if targets were supplied, replace existing
+      Set<AlertTargetEntity> targets = new HashSet<AlertTargetEntity>();
+      if (null != targetIds && targetIds.size() > 0) {
+        List<Long> ids = new ArrayList<Long>(targetIds.size());
+        ids.addAll(targetIds);
+        targets.addAll(s_dao.findTargetsById(ids));
+
+        entity.setAlertTargets(targets);
+      } else if (targetIds.size() == 0) {
+        // empty array supplied, clear out existing targets
+        entity.setAlertTargets(targets);
+      }
+
+      // if definitions were supplied, replace existing
+      Set<AlertDefinitionEntity> definitions = new HashSet<AlertDefinitionEntity>();
+      if (null != definitionIds && definitionIds.size() > 0) {
+        List<Long> ids = new ArrayList<Long>(definitionIds.size());
+        ids.addAll(definitionIds);
+        definitions.addAll(s_definitionDao.findByIds(ids));
+
+        entity.setAlertDefinitions(definitions);
+      } else if (definitionIds.size() == 0) {
+        // empty array supplied, clear out existing definitions
+        entity.setAlertDefinitions(definitions);
+      }
+
+      s_dao.merge(entity);
+    }
+  }
+
+  /**
    * Convert the given {@link AlertGroupEntity} to a {@link Resource}.
    *
    * @param isCollection
@@ -259,9 +367,31 @@ public class AlertGroupResourceProvider extends
     resource.setProperty(ALERT_GROUP_ID, entity.getGroupId());
     resource.setProperty(ALERT_GROUP_NAME, entity.getGroupName());
     resource.setProperty(ALERT_GROUP_CLUSTER_NAME, clusterName);
+    resource.setProperty(ALERT_GROUP_DEFAULT, entity.isDefault());
+
+    if( !isCollection ){
+      Set<AlertTargetEntity> targetEntities = entity.getAlertTargets();
+      Set<AlertDefinitionEntity> definitions = entity.getAlertDefinitions();
+
+      List<AlertTarget> targets = new ArrayList<AlertTarget>(
+          targetEntities.size());
 
-    setResourceProperty(resource, ALERT_GROUP_DEFAULT,
-        entity.isDefault(), requestedIds);
+      List<AlertDefinitionResponse> definitionList = new ArrayList<AlertDefinitionResponse>(
+          definitions.size());
+
+      for (AlertTargetEntity targetEntity : targetEntities) {
+        AlertTarget target = AlertTarget.coerce(targetEntity);
+        targets.add(target);
+      }
+
+      for (AlertDefinitionEntity definition : definitions) {
+        AlertDefinitionResponse response = AlertDefinitionResponse.coerce(definition);
+        definitionList.add(response);
+      }
+
+      resource.setProperty(ALERT_GROUP_DEFINITIONS, definitionList);
+      resource.setProperty(ALERT_GROUP_TARGETS, targets);
+    }
 
     return resource;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/76fc94ec/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java
index 4a8fe12..f410c39 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java
@@ -124,6 +124,22 @@ public class AlertDefinitionDAO {
   }
 
   /**
+   * Gets all of the alert definitions for the list of IDs given.
+   * 
+   * @param definitionIds
+   *          the IDs of the definitions to retrieve.
+   * @return the definition or an empty list (never {@code null}).
+   */
+  public List<AlertDefinitionEntity> findByIds(List<Long> definitionIds) {
+    TypedQuery<AlertDefinitionEntity> query = entityManagerProvider.get().createNamedQuery(
+        "AlertDefinitionEntity.findByIds", AlertDefinitionEntity.class);
+
+    query.setParameter("definitionIds", definitionIds);
+
+    return daoUtils.selectList(query);
+  }
+
+  /**
    * Gets all alert definitions for the given service in the specified cluster.
    *
    * @param clusterId

http://git-wip-us.apache.org/repos/asf/ambari/blob/76fc94ec/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDispatchDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDispatchDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDispatchDAO.java
index dfbe747..e08c948 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDispatchDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDispatchDAO.java
@@ -72,6 +72,22 @@ public class AlertDispatchDAO {
   }
 
   /**
+   * Gets all of the alert targets for the list of IDs given.
+   *
+   * @param targetIds
+   *          the IDs of the targets to retrieve.
+   * @return the targets or an empty list (never {@code null}).
+   */
+  public List<AlertTargetEntity> findTargetsById(List<Long> targetIds) {
+    TypedQuery<AlertTargetEntity> query = entityManagerProvider.get().createNamedQuery(
+        "AlertTargetEntity.findByIds", AlertTargetEntity.class);
+
+    query.setParameter("targetIds", targetIds);
+
+    return daoUtils.selectList(query);
+  }
+
+  /**
    * Gets a notification with the specified ID.
    *
    * @param noticeId
@@ -207,7 +223,7 @@ public class AlertDispatchDAO {
 
   /**
    * Persists a new alert group.
-   * 
+   *
    * @param alertGroup
    *          the group to persist (not {@code null}).
    */

http://git-wip-us.apache.org/repos/asf/ambari/blob/76fc94ec/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertDefinitionEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertDefinitionEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertDefinitionEntity.java
index 299467c..b4b8a44 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertDefinitionEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertDefinitionEntity.java
@@ -17,6 +17,7 @@
  */
 package org.apache.ambari.server.orm.entities;
 
+import java.util.HashSet;
 import java.util.Set;
 
 import javax.persistence.Basic;
@@ -58,7 +59,8 @@ import org.apache.ambari.server.state.alert.Scope;
     @NamedQuery(name = "AlertDefinitionEntity.findByName", query = "SELECT ad FROM AlertDefinitionEntity ad WHERE ad.definitionName = :definitionName AND ad.clusterId = :clusterId"),
     @NamedQuery(name = "AlertDefinitionEntity.findByService", query = "SELECT ad FROM AlertDefinitionEntity ad WHERE ad.serviceName = :serviceName AND ad.clusterId = :clusterId"),
     @NamedQuery(name = "AlertDefinitionEntity.findByServiceAndComponent", query = "SELECT ad FROM AlertDefinitionEntity ad WHERE ad.serviceName = :serviceName AND ad.componentName = :componentName AND ad.clusterId = :clusterId"),
-    @NamedQuery(name = "AlertDefinitionEntity.findByServiceMaster", query = "SELECT ad FROM AlertDefinitionEntity ad WHERE ad.serviceName IN :services AND ad.scope = :scope AND ad.clusterId = :clusterId") })
+    @NamedQuery(name = "AlertDefinitionEntity.findByServiceMaster", query = "SELECT ad FROM AlertDefinitionEntity ad WHERE ad.serviceName IN :services AND ad.scope = :scope AND ad.clusterId = :clusterId"),
+    @NamedQuery(name = "AlertDefinitionEntity.findByIds", query = "SELECT ad FROM AlertDefinitionEntity ad WHERE ad.definitionId IN :definitionIds") })
 public class AlertDefinitionEntity {
 
   @Id
@@ -394,6 +396,34 @@ public class AlertDefinitionEntity {
   }
 
   /**
+   * Adds the specified alert group to the groups that this definition is
+   * associated with. This is used to complement the JPA bidirectional
+   * association.
+   *
+   * @param alertGroup
+   */
+  protected void addAlertGroup(AlertGroupEntity alertGroup) {
+    if (null == alertGroups) {
+      alertGroups = new HashSet<AlertGroupEntity>();
+    }
+
+    alertGroups.add(alertGroup);
+  }
+
+  /**
+   * Removes the specified alert group to the groups that this definition is
+   * associated with. This is used to complement the JPA bidirectional
+   * association.
+   *
+   * @param alertGroup
+   */
+  protected void removeAlertGroup(AlertGroupEntity alertGroup) {
+    if (null != alertGroups) {
+      alertGroups.remove(alertGroup);
+    }
+  }
+
+  /**
    * Called before {@link EntityManager#remove(Object)} for this entity, removes
    * the non-owning relationship between definitions and groups.
    */
@@ -405,10 +435,7 @@ public class AlertDefinitionEntity {
     }
 
     for (AlertGroupEntity group : groups) {
-      Set<AlertDefinitionEntity> definitions = group.getAlertDefinitions();
-      if (null != definitions) {
-        definitions.remove(this);
-      }
+      group.removeAlertDefinition(this);
     }
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/76fc94ec/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertGroupEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertGroupEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertGroupEntity.java
index 1ca592c..f97a0eb 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertGroupEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertGroupEntity.java
@@ -177,7 +177,7 @@ public class AlertGroupEntity {
   /**
    * Set the service name. This is only applicable when {@link #isDefault()} is
    * {@code true}.
-   * 
+   *
    * @param serviceName
    *          the service that this is the default group for, or {@code null} if
    *          this is not a default group.
@@ -189,10 +189,14 @@ public class AlertGroupEntity {
   /**
    * Gets all of the alert definitions that are a part of this grouping.
    *
-   * @return the alert definitions or {@code null} if none.
+   * @return the alert definitions or an empty set if none (never {@code null).
    */
   public Set<AlertDefinitionEntity> getAlertDefinitions() {
-    return alertDefinitions;
+    if (null == alertDefinitions) {
+      alertDefinitions = new HashSet<AlertDefinitionEntity>();
+    }
+
+    return Collections.unmodifiableSet(alertDefinitions);
   }
 
   /**
@@ -202,14 +206,58 @@ public class AlertGroupEntity {
    *          the definitions, or {@code null} for none.
    */
   public void setAlertDefinitions(Set<AlertDefinitionEntity> alertDefinitions) {
+    if (null != this.alertDefinitions) {
+      for (AlertDefinitionEntity definition : this.alertDefinitions) {
+        definition.removeAlertGroup(this);
+      }
+    }
+
     this.alertDefinitions = alertDefinitions;
+
+    if (null != alertDefinitions) {
+      for (AlertDefinitionEntity definition : alertDefinitions) {
+        definition.addAlertGroup(this);
+      }
+    }
+  }
+
+  /**
+   * Adds the specified definition to the definitions that this group will
+   * dispatch to.
+   * 
+   * @param definition
+   *          the definition to add (not {@code null}).
+   */
+  public void addAlertDefinition(AlertDefinitionEntity definition) {
+    if (null == alertDefinitions) {
+      alertDefinitions = new HashSet<AlertDefinitionEntity>();
+    }
+
+    alertDefinitions.add(definition);
+    definition.addAlertGroup(this);
+  }
+
+  /**
+   * Removes the specified definition from the definitions that this group will
+   * dispatch to.
+   * 
+   * @param definition
+   *          the definition to remove (not {@code null}).
+   */
+  public void removeAlertDefinition(AlertDefinitionEntity definition) {
+    if (null != alertDefinitions) {
+      alertDefinitions.remove(definition);
+    }
+
+    definition.removeAlertGroup(this);
   }
 
   /**
    * Gets an immutable set of the targets that will receive notifications for
    * alert definitions in this group.
    *
-   * @return the targets, or {@code null} if there are none.
+   * @return the targets that will be dispatch to for alerts in this group, or
+   *         an empty set if there are none (never {@code null}).
    */
   public Set<AlertTargetEntity> getAlertTargets() {
     if( null == alertTargets ) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/76fc94ec/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertTargetEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertTargetEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertTargetEntity.java
index 89728e5..12c394d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertTargetEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertTargetEntity.java
@@ -46,7 +46,8 @@ import javax.persistence.TableGenerator;
 @TableGenerator(name = "alert_target_id_generator", table = "ambari_sequences", pkColumnName = "sequence_name", valueColumnName = "sequence_value", pkColumnValue = "alert_target_id_seq", initialValue = 0, allocationSize = 1)
 @NamedQueries({
     @NamedQuery(name = "AlertTargetEntity.findAll", query = "SELECT alertTarget FROM AlertTargetEntity alertTarget"),
-    @NamedQuery(name = "AlertTargetEntity.findByName", query = "SELECT alertTarget FROM AlertTargetEntity alertTarget WHERE alertTarget.targetName = :targetName"), })
+    @NamedQuery(name = "AlertTargetEntity.findByName", query = "SELECT alertTarget FROM AlertTargetEntity alertTarget WHERE alertTarget.targetName = :targetName"),
+    @NamedQuery(name = "AlertTargetEntity.findByIds", query = "SELECT alertTarget FROM AlertTargetEntity alertTarget WHERE alertTarget.targetId IN :targetIds") })
 public class AlertTargetEntity {
 
   @Id

http://git-wip-us.apache.org/repos/asf/ambari/blob/76fc94ec/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertTarget.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertTarget.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertTarget.java
index 21e83d9..f495787 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertTarget.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertTarget.java
@@ -17,24 +17,27 @@
  */
 package org.apache.ambari.server.state.alert;
 
-import java.util.List;
+import org.apache.ambari.server.orm.entities.AlertTargetEntity;
+import org.codehaus.jackson.annotate.JsonProperty;
+
 
 /**
  * The {@link AlertTarget} class represents a dispatch mechanism and audience
  * that will receive information about alerts int he system.
  */
 public class AlertTarget {
-  private String m_id;
+
+  private Long m_id;
   private String m_name;
   private String m_description;
   private String m_notificationType;
   private String m_properties;
-  private List<AlertGroup> m_groups;
 
   /**
    * @return the id
    */
-  public String getId() {
+  @JsonProperty("id")
+  public Long getId() {
     return m_id;
   }
 
@@ -42,13 +45,14 @@ public class AlertTarget {
    * @param id
    *          the id to set
    */
-  public void setId(String id) {
+  public void setId(Long id) {
     m_id = id;
   }
 
   /**
    * @return the name
    */
+  @JsonProperty("name")
   public String getName() {
     return m_name;
   }
@@ -64,6 +68,7 @@ public class AlertTarget {
   /**
    * @return the description
    */
+  @JsonProperty("description")
   public String getDescription() {
     return m_description;
   }
@@ -79,6 +84,7 @@ public class AlertTarget {
   /**
    * @return the notificationType
    */
+  @JsonProperty("notification_type")
   public String getNotificationType() {
     return m_notificationType;
   }
@@ -94,6 +100,7 @@ public class AlertTarget {
   /**
    * @return the properties
    */
+  @JsonProperty("properties")
   public String getProperties() {
     return m_properties;
   }
@@ -107,17 +114,17 @@ public class AlertTarget {
   }
 
   /**
-   * @return the groups
+   * @param entity
+   * @return
    */
-  public List<AlertGroup> getGroups() {
-    return m_groups;
-  }
+  public static AlertTarget coerce(AlertTargetEntity entity) {
+    AlertTarget target = new AlertTarget();
+    target.setId(entity.getTargetId());
+    target.setDescription(entity.getDescription());
+    target.setName(entity.getTargetName());
+    target.setNotificationType(entity.getNotificationType());
+    target.setProperties(entity.getProperties());
 
-  /**
-   * @param groups
-   *          the groups to set
-   */
-  public void setGroups(List<AlertGroup> groups) {
-    m_groups = groups;
+    return target;
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/76fc94ec/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java
index c9428b7..ddfc75a 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java
@@ -17,24 +17,30 @@
  */
 package org.apache.ambari.server.controller.internal;
 
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
 import static org.easymock.EasyMock.anyObject;
 import static org.easymock.EasyMock.capture;
 import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.createStrictMock;
 import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.expectLastCall;
 import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.resetToStrict;
 import static org.easymock.EasyMock.verify;
-import static org.junit.Assert.assertEquals;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.UUID;
 
+import org.apache.ambari.server.controller.AlertDefinitionResponse;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.spi.Predicate;
 import org.apache.ambari.server.controller.spi.Request;
@@ -43,13 +49,18 @@ import org.apache.ambari.server.controller.utilities.PredicateBuilder;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
 import org.apache.ambari.server.metadata.ActionMetadata;
 import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
+import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
 import org.apache.ambari.server.orm.dao.AlertDispatchDAO;
+import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
 import org.apache.ambari.server.orm.entities.AlertGroupEntity;
+import org.apache.ambari.server.orm.entities.AlertTargetEntity;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.alert.AlertTarget;
+import org.apache.ambari.server.state.alert.SourceType;
+import org.apache.ambari.server.state.alert.TargetType;
 import org.easymock.Capture;
 import org.easymock.EasyMock;
-import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -69,17 +80,42 @@ public class AlertGroupResourceProviderTest {
   private static final long ALERT_GROUP_CLUSTER_ID = 1L;
   private static final String ALERT_GROUP_CLUSTER_NAME = "c1";
 
+  private static final Long ALERT_TARGET_ID = Long.valueOf(28);
+  private static final String ALERT_TARGET_NAME = "The Administrators";
+  private static final String ALERT_TARGET_DESC = "Admins and Others";
+  private static final String ALERT_TARGET_TYPE = TargetType.EMAIL.name();
+
+  private static final Long ALERT_DEF_ID = Long.valueOf(10);
+  private static final String ALERT_DEF_NAME = "Mock Definition";
+  private static final String ALERT_DEF_LABEL = "Mock Label";
+
+  private static String DEFINITION_UUID = UUID.randomUUID().toString();
+
   private AlertDispatchDAO m_dao;
+  private AlertDefinitionDAO m_definitionDao;
   private Injector m_injector;
 
+  private AmbariManagementController m_amc;
+  private Clusters m_clusters;
+  private Cluster m_cluster;
+
   @Before
-  public void before() {
-    m_dao = createStrictMock(AlertDispatchDAO.class);
+  public void before() throws Exception {
+    m_dao = createMock(AlertDispatchDAO.class);
+    m_definitionDao = createMock(AlertDefinitionDAO.class);
+
+    m_amc = createMock(AmbariManagementController.class);
+    m_clusters = createMock(Clusters.class);
+    m_cluster = createMock(Cluster.class);
 
     m_injector = Guice.createInjector(Modules.override(
         new InMemoryDefaultTestModule()).with(new MockModule()));
 
     AlertGroupResourceProvider.init(m_injector);
+
+    expect(m_amc.getClusters()).andReturn(m_clusters).atLeastOnce();
+    expect(m_clusters.getCluster((String) anyObject())).andReturn(m_cluster).atLeastOnce();
+    expect(m_cluster.getClusterId()).andReturn(Long.valueOf(1)).anyTimes();
   }
 
   /**
@@ -108,44 +144,41 @@ public class AlertGroupResourceProviderTest {
         AlertGroupResourceProvider.ALERT_GROUP_CLUSTER_NAME,
         AlertGroupResourceProvider.ALERT_GROUP_DEFAULT);
 
-    AmbariManagementController amc = createMock(AmbariManagementController.class);
-    Clusters clusters = createMock(Clusters.class);
-    Cluster cluster = createMock(Cluster.class);
-    expect(amc.getClusters()).andReturn(clusters).atLeastOnce();
-    expect(clusters.getCluster((String) anyObject())).andReturn(cluster).atLeastOnce();
-    expect(cluster.getClusterId()).andReturn(Long.valueOf(1)).anyTimes();
-
     Predicate predicate = new PredicateBuilder().property(
         AlertGroupResourceProvider.ALERT_GROUP_CLUSTER_NAME).equals("c1").toPredicate();
 
     expect(m_dao.findAllGroups(ALERT_GROUP_CLUSTER_ID)).andReturn(
         getMockEntities());
 
-    replay(amc, clusters, cluster, m_dao);
+    replay(m_amc, m_clusters, m_cluster, m_dao);
 
-    AlertGroupResourceProvider provider = createProvider(amc);
+    AlertGroupResourceProvider provider = createProvider(m_amc);
     Set<Resource> results = provider.getResources(request, predicate);
 
     assertEquals(1, results.size());
 
     Resource r = results.iterator().next();
 
-    Assert.assertEquals(ALERT_GROUP_NAME,
+    assertEquals(ALERT_GROUP_NAME,
         r.getPropertyValue(AlertGroupResourceProvider.ALERT_GROUP_NAME));
 
-    Assert.assertEquals(ALERT_GROUP_ID,
+    assertEquals(ALERT_GROUP_ID,
         r.getPropertyValue(AlertGroupResourceProvider.ALERT_GROUP_ID));
 
-    Assert.assertEquals(ALERT_GROUP_CLUSTER_NAME,
+    assertEquals(ALERT_GROUP_CLUSTER_NAME,
         r.getPropertyValue(AlertGroupResourceProvider.ALERT_GROUP_CLUSTER_NAME));
 
-    verify(amc, clusters, cluster, m_dao);
+    // verify definitions do not come back in collections
+    assertNull(r.getPropertyValue(AlertGroupResourceProvider.ALERT_GROUP_DEFINITIONS));
+
+    verify(m_amc, m_clusters, m_cluster, m_dao);
   }
 
   /**
    * @throws Exception
    */
   @Test
+  @SuppressWarnings("unchecked")
   public void testGetSingleResource() throws Exception {
     Request request = PropertyHelper.getReadRequest(
         AlertGroupResourceProvider.ALERT_GROUP_ID,
@@ -173,15 +206,28 @@ public class AlertGroupResourceProviderTest {
 
     Resource r = results.iterator().next();
 
-    Assert.assertEquals(ALERT_GROUP_NAME,
+    assertEquals(ALERT_GROUP_NAME,
         r.getPropertyValue(AlertGroupResourceProvider.ALERT_GROUP_NAME));
 
-    Assert.assertEquals(ALERT_GROUP_ID,
+    assertEquals(ALERT_GROUP_ID,
         r.getPropertyValue(AlertGroupResourceProvider.ALERT_GROUP_ID));
 
-    Assert.assertEquals(ALERT_GROUP_CLUSTER_NAME,
+    assertEquals(ALERT_GROUP_CLUSTER_NAME,
         r.getPropertyValue(AlertGroupResourceProvider.ALERT_GROUP_CLUSTER_NAME));
 
+    // verify definitions and targets are returned on single instances
+    List<AlertDefinitionResponse> definitions = (List<AlertDefinitionResponse>) r.getPropertyValue(AlertGroupResourceProvider.ALERT_GROUP_DEFINITIONS);
+    List<AlertTarget> targets = (List<AlertTarget>) r.getPropertyValue(AlertGroupResourceProvider.ALERT_GROUP_TARGETS);
+
+    assertNotNull(definitions);
+    assertNotNull(targets);
+
+    assertEquals(1, definitions.size());
+    assertEquals(ALERT_DEF_NAME, definitions.get(0).getName());
+
+    assertEquals(1, targets.size());
+    assertEquals(ALERT_TARGET_NAME, targets.get(0).getName());
+
     verify(amc, m_dao);
   }
 
@@ -190,21 +236,40 @@ public class AlertGroupResourceProviderTest {
    */
   @Test
   public void testCreateResources() throws Exception {
-    AmbariManagementController amc = createMock(AmbariManagementController.class);
-    Clusters clusters = createMock(Clusters.class);
-    Cluster cluster = createMock(Cluster.class);
-    expect(amc.getClusters()).andReturn(clusters).atLeastOnce();
-    expect(clusters.getCluster((String) anyObject())).andReturn(cluster).atLeastOnce();
-    expect(cluster.getClusterId()).andReturn(Long.valueOf(1)).anyTimes();
-
     Capture<List<AlertGroupEntity>> listCapture = new Capture<List<AlertGroupEntity>>();
 
+    // the definition IDs to associate with the group
+    List<Long> definitionIds = new ArrayList<Long>();
+    definitionIds.add(ALERT_DEF_ID);
+
+    // the target IDs to associate with the group
+    List<Long> targetIds = new ArrayList<Long>();
+    targetIds.add(ALERT_TARGET_ID);
+
+    // definition entities to return from DAO
+    List<AlertDefinitionEntity> definitionEntities = new ArrayList<AlertDefinitionEntity>();
+    definitionEntities.addAll(getMockDefinitions());
+
+    // target entities to return from DAO
+    List<AlertTargetEntity> targetEntities = new ArrayList<AlertTargetEntity>();
+    targetEntities.addAll(getMockTargets());
+
+    // expect create group
     m_dao.createGroups(capture(listCapture));
-    expectLastCall();
+    expectLastCall().once();
 
-    replay(amc, clusters, cluster, m_dao);
+    // expect target entity lookup for association
+    expect(m_dao.findTargetsById(EasyMock.eq(targetIds))).andReturn(
+        targetEntities).times(1);
+
+    // expect definition entity lookup for association
+    expect(m_definitionDao.findByIds(definitionIds)).andReturn(
+        definitionEntities).times(1);
+
+    replay(m_amc, m_clusters, m_cluster, m_dao, m_definitionDao);
+
+    AlertGroupResourceProvider provider = createProvider(m_amc);
 
-    AlertGroupResourceProvider provider = createProvider(amc);
     Map<String, Object> requestProps = new HashMap<String, Object>();
     requestProps.put(AlertGroupResourceProvider.ALERT_GROUP_NAME,
         ALERT_GROUP_NAME);
@@ -212,25 +277,109 @@ public class AlertGroupResourceProviderTest {
     requestProps.put(AlertGroupResourceProvider.ALERT_GROUP_CLUSTER_NAME,
         ALERT_GROUP_CLUSTER_NAME);
 
+    requestProps.put(AlertGroupResourceProvider.ALERT_GROUP_DEFINITIONS,
+        definitionIds);
+
+    requestProps.put(AlertGroupResourceProvider.ALERT_GROUP_TARGETS, targetIds);
+
     Request request = PropertyHelper.getCreateRequest(Collections.singleton(requestProps), null);
     provider.createResources(request);
 
-    Assert.assertTrue(listCapture.hasCaptured());
+    assertTrue(listCapture.hasCaptured());
     AlertGroupEntity entity = listCapture.getValue().get(0);
-    Assert.assertNotNull(entity);
+    assertNotNull(entity);
 
-    Assert.assertEquals(ALERT_GROUP_NAME, entity.getGroupName());
-    Assert.assertEquals(ALERT_GROUP_CLUSTER_ID,
+    assertEquals(ALERT_GROUP_NAME, entity.getGroupName());
+    assertEquals(ALERT_GROUP_CLUSTER_ID,
         entity.getClusterId().longValue());
 
-    verify(amc, clusters, cluster, m_dao);
+    verify(m_amc, m_clusters, m_cluster, m_dao, m_definitionDao);
   }
 
   /**
    * @throws Exception
    */
   @Test
+  @SuppressWarnings("unchecked")
   public void testUpdateResources() throws Exception {
+    Capture<AlertGroupEntity> entityCapture = new Capture<AlertGroupEntity>();
+
+    // the definition IDs to associate with the group
+    List<Long> definitionIds = new ArrayList<Long>();
+    definitionIds.add(ALERT_DEF_ID);
+
+    // the target IDs to associate with the group
+    List<Long> targetIds = new ArrayList<Long>();
+    targetIds.add(ALERT_TARGET_ID);
+
+    // definition entities to return from DAO
+    List<AlertDefinitionEntity> definitionEntities = new ArrayList<AlertDefinitionEntity>();
+    definitionEntities.addAll(getMockDefinitions());
+
+    // target entities to return from DAO
+    List<AlertTargetEntity> targetEntities = new ArrayList<AlertTargetEntity>();
+    targetEntities.addAll(getMockTargets());
+
+    m_dao.createGroups(EasyMock.anyObject(List.class));
+    expectLastCall().times(1);
+
+    AlertGroupEntity group = new AlertGroupEntity();
+    expect(m_dao.findGroupById(ALERT_GROUP_ID)).andReturn(
+        group).times(1);
+
+    expect(m_dao.merge(capture(entityCapture))).andReturn(group).once();
+
+    // expect target entity lookup for association
+    expect(m_dao.findTargetsById(EasyMock.eq(targetIds))).andReturn(
+        targetEntities).once();
+
+    // expect definition entity lookup for association
+    expect(m_definitionDao.findByIds(definitionIds)).andReturn(
+        definitionEntities).once();
+
+    replay(m_amc, m_clusters, m_cluster, m_dao, m_definitionDao);
+
+    AlertGroupResourceProvider provider = createProvider(m_amc);
+    Map<String, Object> requestProps = new HashMap<String, Object>();
+    requestProps.put(AlertGroupResourceProvider.ALERT_GROUP_NAME,
+        ALERT_GROUP_NAME);
+
+    requestProps.put(AlertGroupResourceProvider.ALERT_GROUP_CLUSTER_NAME,
+        ALERT_GROUP_CLUSTER_NAME);
+
+    Request request = PropertyHelper.getCreateRequest(
+        Collections.singleton(requestProps), null);
+
+    provider.createResources(request);
+
+    // create new properties, and include the ID since we're not going through
+    // a service layer which would add it for us automatically
+    requestProps = new HashMap<String, Object>();
+    requestProps.put(AlertGroupResourceProvider.ALERT_GROUP_ID,
+        ALERT_GROUP_ID.toString());
+
+    String newName = ALERT_GROUP_NAME + " Foo";
+    requestProps.put(AlertGroupResourceProvider.ALERT_GROUP_NAME, newName);
+
+    requestProps.put(AlertGroupResourceProvider.ALERT_GROUP_DEFINITIONS,
+        definitionIds);
+
+    requestProps.put(AlertGroupResourceProvider.ALERT_GROUP_TARGETS, targetIds);
+
+    Predicate predicate = new PredicateBuilder().property(
+        AlertGroupResourceProvider.ALERT_GROUP_CLUSTER_NAME).equals(
+        ALERT_GROUP_CLUSTER_NAME).and().property(
+        AlertGroupResourceProvider.ALERT_GROUP_ID).equals(
+        ALERT_GROUP_ID.toString()).toPredicate();
+
+    request = PropertyHelper.getUpdateRequest(requestProps, null);
+    provider.updateResources(request, predicate);
+
+    assertTrue(entityCapture.hasCaptured());
+
+    AlertGroupEntity entity = entityCapture.getValue();
+    assertEquals(newName, entity.getGroupName());
+    verify(m_amc, m_clusters, m_cluster, m_dao, m_definitionDao);
   }
 
   /**
@@ -238,22 +387,15 @@ public class AlertGroupResourceProviderTest {
    */
   @Test
   public void testDeleteResources() throws Exception {
-    AmbariManagementController amc = createMock(AmbariManagementController.class);
-    Clusters clusters = createMock(Clusters.class);
-    Cluster cluster = createMock(Cluster.class);
-    expect(amc.getClusters()).andReturn(clusters).atLeastOnce();
-    expect(clusters.getCluster((String) anyObject())).andReturn(cluster).atLeastOnce();
-    expect(cluster.getClusterId()).andReturn(Long.valueOf(1)).anyTimes();
-
     Capture<AlertGroupEntity> entityCapture = new Capture<AlertGroupEntity>();
     Capture<List<AlertGroupEntity>> listCapture = new Capture<List<AlertGroupEntity>>();
 
     m_dao.createGroups(capture(listCapture));
     expectLastCall();
 
-    replay(amc, clusters, cluster, m_dao);
+    replay(m_amc, m_clusters, m_cluster, m_dao);
 
-    AlertGroupResourceProvider provider = createProvider(amc);
+    AlertGroupResourceProvider provider = createProvider(m_amc);
 
     Map<String, Object> requestProps = new HashMap<String, Object>();
     requestProps.put(AlertGroupResourceProvider.ALERT_GROUP_NAME,
@@ -265,9 +407,9 @@ public class AlertGroupResourceProviderTest {
     Request request = PropertyHelper.getCreateRequest(Collections.singleton(requestProps), null);
     provider.createResources(request);
 
-    Assert.assertTrue(listCapture.hasCaptured());
+    assertTrue(listCapture.hasCaptured());
     AlertGroupEntity entity = listCapture.getValue().get(0);
-    Assert.assertNotNull(entity);
+    assertNotNull(entity);
 
     Predicate predicate = new PredicateBuilder().property(
         AlertGroupResourceProvider.ALERT_GROUP_CLUSTER_NAME).equals(
@@ -287,9 +429,9 @@ public class AlertGroupResourceProviderTest {
     provider.deleteResources(predicate);
 
     AlertGroupEntity entity1 = entityCapture.getValue();
-    Assert.assertEquals(ALERT_GROUP_ID, entity1.getGroupId());
+    assertEquals(ALERT_GROUP_ID, entity1.getGroupId());
 
-    verify(amc, clusters, cluster, m_dao);
+    verify(m_amc, m_clusters, m_cluster, m_dao);
   }
 
   /**
@@ -298,6 +440,7 @@ public class AlertGroupResourceProviderTest {
    */
   private AlertGroupResourceProvider createProvider(
       AmbariManagementController amc) {
+
     return new AlertGroupResourceProvider(
         PropertyHelper.getPropertyIds(Resource.Type.AlertGroup),
         PropertyHelper.getKeyPropertyIds(Resource.Type.AlertGroup), amc);
@@ -312,10 +455,57 @@ public class AlertGroupResourceProviderTest {
     entity.setGroupName(ALERT_GROUP_NAME);
     entity.setClusterId(ALERT_GROUP_CLUSTER_ID);
     entity.setDefault(false);
+
+    entity.setAlertTargets(getMockTargets());
+    entity.setAlertDefinitions(getMockDefinitions());
     return Arrays.asList(entity);
   }
 
   /**
+   * Gets some mock {@link AlertDefinitionEntity} instances.
+   *
+   * @return
+   * @throws Exception
+   */
+  private Set<AlertDefinitionEntity> getMockDefinitions() throws Exception {
+    AlertDefinitionEntity entity = new AlertDefinitionEntity();
+    entity.setClusterId(Long.valueOf(1L));
+    entity.setComponentName(null);
+    entity.setDefinitionId(ALERT_DEF_ID);
+    entity.setDefinitionName(ALERT_DEF_NAME);
+    entity.setLabel(ALERT_DEF_LABEL);
+    entity.setEnabled(true);
+    entity.setHash(DEFINITION_UUID);
+    entity.setScheduleInterval(Integer.valueOf(2));
+    entity.setServiceName(null);
+    entity.setSourceType(SourceType.METRIC.name());
+    entity.setSource(null);
+
+    Set<AlertDefinitionEntity> definitions = new HashSet<AlertDefinitionEntity>();
+    definitions.add(entity);
+
+    return definitions;
+  }
+
+  /**
+   * Gets some mock {@link AlertTargetEntity} instances.
+   *
+   * @return
+   */
+  private Set<AlertTargetEntity> getMockTargets() throws Exception {
+    AlertTargetEntity entity = new AlertTargetEntity();
+    entity.setTargetId(ALERT_TARGET_ID);
+    entity.setDescription(ALERT_TARGET_DESC);
+    entity.setTargetName(ALERT_TARGET_NAME);
+    entity.setNotificationType(ALERT_TARGET_TYPE);
+
+    Set<AlertTargetEntity> targets = new HashSet<AlertTargetEntity>();
+    targets.add(entity);
+
+    return targets;
+  }
+
+  /**
   *
   */
   private class MockModule implements Module {
@@ -325,10 +515,9 @@ public class AlertGroupResourceProviderTest {
     @Override
     public void configure(Binder binder) {
       binder.bind(AlertDispatchDAO.class).toInstance(m_dao);
-      binder.bind(Clusters.class).toInstance(
-          EasyMock.createNiceMock(Clusters.class));
-      binder.bind(Cluster.class).toInstance(
-          EasyMock.createNiceMock(Cluster.class));
+      binder.bind(AlertDefinitionDAO.class).toInstance(m_definitionDao);
+      binder.bind(Clusters.class).toInstance(m_clusters);
+      binder.bind(Cluster.class).toInstance(m_cluster);
       binder.bind(ActionMetadata.class);
     }
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/76fc94ec/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProviderTest.java
index 982dd4b..6ca2035 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProviderTest.java
@@ -266,7 +266,7 @@ public class AlertTargetResourceProviderTest {
     entity.setTargetId(ALERT_TARGET_ID);
     entity.setDescription(ALERT_TARGET_DESC);
     entity.setTargetName(ALERT_TARGET_NAME);
-    entity.setNotificationType(TargetType.EMAIL.name());
+    entity.setNotificationType(ALERT_TARGET_TYPE);
     return Arrays.asList(entity);
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/76fc94ec/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
index a7ef513..a7cc066 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
@@ -22,6 +22,7 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 
+import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.List;
@@ -193,6 +194,21 @@ public class AlertDefinitionDAOTest {
   }
 
   /**
+  *
+  */
+  @Test
+  public void testFindByIds() {
+    List<AlertDefinitionEntity> definitions = dao.findAll();
+    List<Long> ids = new ArrayList<Long>();
+    ids.add(definitions.get(0).getDefinitionId());
+    ids.add(definitions.get(1).getDefinitionId());
+    ids.add(99999L);
+
+    definitions = dao.findByIds(ids);
+    assertEquals(2, definitions.size());
+  }
+
+  /**
    *
    */
   @Test
@@ -260,7 +276,7 @@ public class AlertDefinitionDAOTest {
     AlertDefinitionEntity definition = helper.createAlertDefinition(clusterId);
 
     AlertGroupEntity group = helper.createAlertGroup(clusterId, null);
-    group.getAlertDefinitions().add(definition);
+    group.addAlertDefinition(definition);
     dispatchDao.merge(group);
 
     AlertHistoryEntity history = new AlertHistoryEntity();

http://git-wip-us.apache.org/repos/asf/ambari/blob/76fc94ec/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDispatchDAOTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDispatchDAOTest.java b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDispatchDAOTest.java
index 894f2c2..8451c9b 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDispatchDAOTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDispatchDAOTest.java
@@ -23,6 +23,7 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
+import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -56,7 +57,7 @@ public class AlertDispatchDAOTest {
   OrmTestHelper helper;
 
   /**
-   * 
+   *
    */
   @Before
   public void setup() throws Exception {
@@ -92,7 +93,7 @@ public class AlertDispatchDAOTest {
   }
 
   /**
-   * 
+   *
    */
   @Test
   public void testFindAllTargets() throws Exception {
@@ -102,7 +103,24 @@ public class AlertDispatchDAOTest {
   }
 
   /**
-   * 
+   * @throws Exception
+   */
+  public void testFindTargetsByIds() throws Exception {
+    List<AlertTargetEntity> targets = dao.findAllTargets();
+    assertNotNull(targets);
+    assertEquals(5, targets.size());
+
+    List<Long> ids = new ArrayList<Long>();
+    ids.add(targets.get(0).getTargetId());
+    ids.add(targets.get(1).getTargetId());
+    ids.add(99999L);
+
+    targets = dao.findTargetsById(ids);
+    assertEquals(2, targets.size());
+  }
+
+  /**
+   *
    */
   @Test
   public void testFindTargetByName() throws Exception {
@@ -115,7 +133,7 @@ public class AlertDispatchDAOTest {
   }
 
   /**
-   * 
+   *
    */
   @Test
   public void testFindAllGroups() throws Exception {
@@ -125,7 +143,7 @@ public class AlertDispatchDAOTest {
   }
 
   /**
-   * 
+   *
    */
   @Test
   public void testFindGroupByName() throws Exception {
@@ -140,7 +158,7 @@ public class AlertDispatchDAOTest {
   }
 
   /**
-   * 
+   *
    */
   @Test
   public void testCreateGroup() throws Exception {
@@ -159,7 +177,7 @@ public class AlertDispatchDAOTest {
   }
 
   /**
-   * 
+   *
    */
   @Test
   public void testGroupDefinitions() throws Exception {
@@ -170,7 +188,10 @@ public class AlertDispatchDAOTest {
     group = dao.findGroupById(group.getGroupId());
     assertNotNull(group);
 
-    group.getAlertDefinitions().addAll(definitions);
+    for (AlertDefinitionEntity definition : definitions) {
+      group.addAlertDefinition(definition);
+    }
+
     dao.merge(group);
 
     group = dao.findGroupByName(group.getGroupName());
@@ -193,7 +214,7 @@ public class AlertDispatchDAOTest {
   }
 
   /**
-   * 
+   *
    */
   @Test
   public void testCreateTarget() throws Exception {
@@ -222,12 +243,12 @@ public class AlertDispatchDAOTest {
   }
 
   /**
-   * 
+   *
    */
   @Test
   public void testDeleteGroup() throws Exception {
-    int targetCount = dao.findAllTargets().size();    
-    
+    int targetCount = dao.findAllTargets().size();
+
     AlertGroupEntity group = helper.createAlertGroup(clusterId, null);
     AlertTargetEntity target = helper.createAlertTarget();
     assertEquals(targetCount + 1, dao.findAllTargets().size());
@@ -255,7 +276,7 @@ public class AlertDispatchDAOTest {
   }
 
   /**
-   * 
+   *
    */
   @Test
   public void testDeleteTarget() throws Exception {
@@ -270,7 +291,7 @@ public class AlertDispatchDAOTest {
   }
 
   /**
-   * 
+   *
    */
   @Test
   public void testDeleteAssociatedTarget() throws Exception {
@@ -298,7 +319,7 @@ public class AlertDispatchDAOTest {
   }
 
   /**
-   * 
+   *
    */
   @Test
   public void testUpdateGroup() throws Exception {
@@ -319,8 +340,6 @@ public class AlertDispatchDAOTest {
 
     assertEquals(groupName + "FOO", group.getGroupName());
     assertEquals(true, group.isDefault());
-    assertNotNull(group.getAlertDefinitions());
-    assertNotNull(group.getAlertTargets());
     assertEquals(0, group.getAlertDefinitions().size());
     assertEquals(0, group.getAlertTargets().size());
 


[14/50] [abbrv] git commit: Merge branch 'trunk' into branch-alerts-dev

Posted by jo...@apache.org.
Merge branch 'trunk' into branch-alerts-dev


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

Branch: refs/heads/trunk
Commit: e508fe5a331c2fb8a98c55ccddbcee42ec77f2b6
Parents: 91ae5f2 637d521
Author: Nate Cole <nc...@hortonworks.com>
Authored: Sun Sep 7 05:44:24 2014 -0400
Committer: Nate Cole <nc...@hortonworks.com>
Committed: Sun Sep 7 05:44:24 2014 -0400

----------------------------------------------------------------------
 .../app/scripts/controllers/NavbarCtrl.js       |  41 +++-
 .../admin-web/app/scripts/services/Cluster.js   |  14 +-
 .../resources/ui/admin-web/app/styles/main.css  |  18 ++
 .../ui/admin-web/app/views/leftNavbar.html      |  39 +++-
 ambari-agent/conf/unix/install-helper.sh        |   6 +
 ambari-agent/pom.xml                            |   2 +-
 .../src/main/package/rpm/posttrans_agent.sh     |   7 +
 .../resources/blueprints/hdp-multinode-default  |   5 +-
 .../resources/blueprints/hdp-singlenode-default |   2 +-
 .../resources/blueprints/lambda-architecture    |  12 +-
 .../resources/blueprints/multi-node-hdfs-yarn   |   6 +-
 .../resources/blueprints/single-node-hdfs-yarn  |   2 +-
 .../src/main/resources/blueprints/warmup        |   8 +-
 ambari-server/conf/unix/install-helper.sh       |   6 +
 ambari-server/pom.xml                           |  25 ++
 .../server/api/util/StackExtensionHelper.java   |   8 +-
 .../server/configuration/Configuration.java     |  36 +++
 .../AmbariManagementControllerImpl.java         |  24 +-
 .../ambari/server/controller/AmbariServer.java  |  10 +-
 .../internal/ClientConfigResourceProvider.java  |   5 +
 .../internal/ViewVersionResourceProvider.java   |  22 +-
 .../nagios/NagiosPropertyProvider.java          |   8 +-
 .../ambari/server/orm/entities/ViewEntity.java  |  55 ++++-
 .../AmbariLdapAuthoritiesPopulator.java         |  18 +-
 .../AmbariLocalUserDetailsService.java          |   4 +-
 .../apache/ambari/server/view/ViewRegistry.java | 200 ++++++++++------
 .../src/main/package/rpm/posttrans_server.sh    |   7 +
 .../HDP/1.3.2/configuration/cluster-env.xml     |   5 +
 .../1.3.2/hooks/after-INSTALL/scripts/params.py |   5 +-
 .../1.3.2/hooks/before-ANY/scripts/params.py    |   3 +-
 .../hooks/before-INSTALL/scripts/params.py      |  11 +-
 .../1.3.2/hooks/before-START/scripts/params.py  |  16 +-
 .../scripts/shared_initialization.py            | 121 +++++-----
 .../services/GANGLIA/package/scripts/params.py  |   2 +-
 .../services/HBASE/package/scripts/params.py    |  11 +-
 .../services/HDFS/configuration/hadoop-env.xml  |  32 +--
 .../services/HDFS/package/scripts/params.py     |   9 +-
 .../1.3.2/services/HIVE/package/scripts/hive.py |  31 ++-
 .../services/HIVE/package/scripts/params.py     |   9 +-
 .../MAPREDUCE/package/scripts/params.py         |   9 +-
 .../services/NAGIOS/package/scripts/params.py   |   5 +-
 .../services/OOZIE/package/scripts/params.py    |   9 +-
 .../services/PIG/package/scripts/params.py      |   9 +-
 .../services/SQOOP/package/scripts/params.py    |  11 +-
 .../services/WEBHCAT/package/scripts/params.py  |   9 +-
 .../ZOOKEEPER/package/scripts/params.py         |   9 +-
 .../HDP/2.0.6/configuration/cluster-env.xml     |   5 +
 .../2.0.6/hooks/after-INSTALL/scripts/params.py |   8 +-
 .../scripts/shared_initialization.py            |  48 ++--
 .../2.0.6/hooks/before-ANY/scripts/params.py    |   3 +-
 .../hooks/before-INSTALL/scripts/params.py      |  11 +-
 .../2.0.6/hooks/before-START/scripts/params.py  |  12 +-
 .../scripts/shared_initialization.py            | 124 +++++-----
 .../services/FLUME/package/scripts/params.py    |   2 +-
 .../services/GANGLIA/package/scripts/params.py  |   2 +-
 .../services/HBASE/package/scripts/params.py    |  10 +-
 .../services/HDFS/configuration/hadoop-env.xml  |  27 ---
 .../services/HDFS/package/scripts/params.py     |   9 +-
 .../2.0.6/services/HIVE/package/scripts/hive.py |  42 +++-
 .../services/HIVE/package/scripts/params.py     |   9 +-
 .../services/NAGIOS/package/scripts/params.py   |  62 ++---
 .../services/OOZIE/package/scripts/params.py    |   9 +-
 .../services/PIG/package/scripts/params.py      |   9 +-
 .../services/SQOOP/package/scripts/params.py    |  10 +-
 .../services/WEBHCAT/package/scripts/params.py  |   9 +-
 .../YARN/configuration-mapred/mapred-site.xml   |   2 +-
 .../scripts/application_timeline_server.py      |   4 +-
 .../YARN/package/scripts/historyserver.py       |   4 +-
 .../services/YARN/package/scripts/params.py     |  18 +-
 .../services/YARN/package/scripts/service.py    |  30 ++-
 .../YARN/package/scripts/status_params.py       |   2 +-
 .../HDP/2.0.6/services/ZOOKEEPER/metainfo.xml   |   1 +
 .../ZOOKEEPER/package/scripts/params.py         |   9 +-
 .../stacks/HDP/2.0.6/services/stack_advisor.py  |  19 +-
 .../blueprints/multinode-default.json           |   7 +-
 .../blueprints/singlenode-default.json          |   4 +-
 .../services/FALCON/package/scripts/params.py   |   9 +-
 .../services/STORM/package/scripts/params.py    |   7 +-
 .../services/TEZ/package/scripts/params.py      |   2 +-
 .../services/YARN/package/scripts/params.py     |   9 +-
 .../HDP/2.1/blueprints/multinode-default.json   |   7 +-
 .../HDP/2.1/blueprints/singlenode-default.json  |   4 +-
 .../services/FALCON/package/scripts/params.py   |   9 +-
 .../services/STORM/package/scripts/params.py    |   7 +-
 .../2.1/services/TEZ/configuration/tez-site.xml |   2 +-
 .../2.1/services/TEZ/package/scripts/params.py  |   2 +-
 .../stacks/HDP/2.2.1/services/YARN/metainfo.xml |   8 +
 .../api/util/StackExtensionHelperTest.java      |  27 +++
 .../server/configuration/ConfigurationTest.java |  19 +-
 .../AmbariManagementControllerImplTest.java     |  86 +++++++
 .../AmbariPrivilegeResourceProviderTest.java    |   6 +-
 .../ClientConfigResourceProviderTest.java       | 175 +++++++++++++-
 .../ViewPrivilegeResourceProviderTest.java      |   6 +-
 .../nagios/NagiosPropertyProviderTest.java      |   2 +
 .../server/orm/entities/ViewEntityTest.java     |  30 ++-
 ...ariAuthorizationProviderDisableUserTest.java |  97 ++++++++
 .../TestAmbariLdapAuthoritiesPopulator.java     |   2 +
 .../ambari/server/view/ViewRegistryTest.java    |  52 ++++-
 .../stacks/1.3.2/HIVE/test_hive_client.py       |  36 +++
 .../stacks/1.3.2/HIVE/test_hive_metastore.py    |  36 +++
 .../stacks/1.3.2/HIVE/test_hive_server.py       |  36 +++
 .../1.3.2/configs/default.hbasedecom.json       |  24 +-
 .../python/stacks/1.3.2/configs/default.json    |  25 +-
 .../1.3.2/configs/default.non_gmetad_host.json  |  22 +-
 .../stacks/1.3.2/configs/default_client.json    |  24 +-
 .../python/stacks/1.3.2/configs/secured.json    |  24 +-
 .../stacks/1.3.2/configs/secured_client.json    |  25 +-
 .../hooks/before-START/test_before_start.py     |   3 +-
 .../stacks/2.0.6/HIVE/test_hive_client.py       |  52 +++++
 .../stacks/2.0.6/HIVE/test_hive_metastore.py    |  52 +++++
 .../stacks/2.0.6/HIVE/test_hive_server.py       |  52 +++++
 .../stacks/2.0.6/YARN/test_historyserver.py     | 104 ++++-----
 .../stacks/2.0.6/YARN/test_nodemanager.py       | 103 ++++----
 .../stacks/2.0.6/YARN/test_resourcemanager.py   | 102 ++++----
 .../stacks/2.0.6/common/test_stack_advisor.py   |  54 ++++-
 .../2.0.6/configs/default.hbasedecom.json       |  24 +-
 .../python/stacks/2.0.6/configs/default.json    |  23 +-
 .../2.0.6/configs/default.non_gmetad_host.json  |  24 +-
 .../stacks/2.0.6/configs/default_client.json    |  24 +-
 .../python/stacks/2.0.6/configs/ha_default.json |  24 +-
 .../python/stacks/2.0.6/configs/ha_secured.json |  35 +--
 .../2.0.6/configs/rebalancehdfs_default.json    |  24 +-
 .../python/stacks/2.0.6/configs/secured.json    |  29 ++-
 .../stacks/2.0.6/configs/secured_client.json    |  25 +-
 .../stacks/2.1/HIVE/test_hive_metastore.py      |  52 +++++
 .../stacks/2.1/YARN/test_apptimelineserver.py   |  54 +++--
 .../test/python/stacks/2.1/configs/default.json |  22 +-
 .../test/python/stacks/2.1/configs/secured.json |  25 +-
 .../HDP/2.0.5/services/ZOOKEEPER/metainfo.xml   |  12 +
 .../HDP/2.0.7/services/ZOOKEEPER/metainfo.xml   |  12 +
 .../org/apache/ambari/view/ViewDefinition.java  |  27 +++
 ambari-web/app/app.js                           |  13 ++
 ambari-web/app/controllers/login_controller.js  |  10 +-
 .../app/controllers/main/admin/security.js      |  43 ++--
 .../security/add/addSecurity_controller.js      |   7 +-
 .../main/admin/security/add/step1.js            |  11 +-
 .../main/admin/security/add/step2.js            |   1 +
 .../main/admin/security/add/step3.js            |  35 ++-
 .../main/admin/security/add/step4.js            |   9 +-
 .../controllers/main/admin/security/disable.js  |   4 +-
 .../security/security_progress_controller.js    |  20 +-
 ambari-web/app/controllers/main/host/details.js |  18 +-
 .../controllers/main/service/add_controller.js  |  23 +-
 .../controllers/main/service/info/configs.js    |   5 +-
 .../service/manage_config_groups_controller.js  |   5 +-
 .../main/service/reassign_controller.js         |   6 +-
 ambari-web/app/controllers/wizard.js            |  66 +++---
 .../app/controllers/wizard/step3_controller.js  |   3 +-
 .../app/controllers/wizard/step5_controller.js  |   8 +-
 .../app/controllers/wizard/step6_controller.js  |  55 ++++-
 .../app/controllers/wizard/step8_controller.js  |  16 +-
 ambari-web/app/data/HDP2/secure_configs.js      |  32 ++-
 ambari-web/app/data/HDP2/secure_mapping.js      |  45 ++++
 ambari-web/app/data/HDP2/secure_properties.js   |  91 ++++++--
 ambari-web/app/data/HDP2/site_properties.js     |  41 ++--
 ambari-web/app/data/secure_configs.js           |  10 +-
 ambari-web/app/data/secure_properties.js        |  23 +-
 ambari-web/app/data/service_configs.js          |   1 +
 ambari-web/app/data/site_properties.js          |  43 ++--
 ambari-web/app/messages.js                      |  11 +-
 ambari-web/app/mixins/common/blueprint.js       |   6 +-
 ambari-web/app/router.js                        |  25 +-
 ambari-web/app/routes/add_security.js           |   6 +-
 ambari-web/app/routes/main.js                   |   5 +-
 ambari-web/app/styles/application.less          |  71 +++---
 .../common/configs/config_history_flow.hbs      |  22 +-
 .../templates/main/admin/security/add/step1.hbs |   2 +-
 ambari-web/app/utils/ajax/ajax.js               |   4 +
 ambari-web/app/utils/blueprint.js               |   8 +-
 ambari-web/app/utils/config.js                  |  83 +++++--
 .../app/views/common/configs/services_config.js |   3 +-
 .../app/views/common/quick_view_link_view.js    | 234 +++++++++++--------
 .../app/views/main/admin/security/add/step1.js  |   6 +-
 ambari-web/app/views/wizard/controls_view.js    |   4 +
 .../main/admin/security/add/step1_test.js       |  10 +-
 .../main/admin/security/disable_test.js         |   6 +-
 .../controllers/main/admin/security_test.js     |  18 +-
 .../test/controllers/wizard/step6_test.js       |  96 ++++++++
 ambari-web/test/models/dataset_job_test.js      |   2 +-
 ambari-web/test/utils/blueprint_test.js         |   2 +-
 .../test/views/common/quick_link_view_test.js   |  56 +++++
 .../slider-core/0.41.0/slider-core-0.41.0.jar   | Bin 0 -> 1125710 bytes
 .../slider-core/0.41.0/slider-core-0.41.0.pom   |  25 ++
 .../slider/slider-core/maven-metadata-local.xml |  28 +++
 .../slider/slider/0.30.0/slider-0.30.0.jar      | Bin 1125710 -> 0 bytes
 .../slider/slider/0.30.0/slider-0.30.0.pom      |  25 --
 .../slider/slider/maven-metadata-local.xml      |  28 ---
 contrib/views/slider/pom.xml                    |   5 +-
 188 files changed, 3187 insertions(+), 1443 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/e508fe5a/ambari-agent/pom.xml
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/e508fe5a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
----------------------------------------------------------------------


[16/50] [abbrv] git commit: Merge branch 'trunk' into branch-alerts-dev

Posted by jo...@apache.org.
Merge branch 'trunk' into branch-alerts-dev


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

Branch: refs/heads/trunk
Commit: 0b406cbefdbfc8f53b25d203319c964fcf3f93c7
Parents: 84c16c5 42a07f9
Author: Nate Cole <nc...@hortonworks.com>
Authored: Sun Sep 7 16:53:49 2014 -0400
Committer: Nate Cole <nc...@hortonworks.com>
Committed: Sun Sep 7 16:53:49 2014 -0400

----------------------------------------------------------------------
 .../java/org/apache/ambari/server/orm/entities/ViewEntity.java | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
----------------------------------------------------------------------



[39/50] [abbrv] git commit: AMBARI-7534 - Alerts: Disabling an Alert Should Propagate to Agent (jonathanhurley)

Posted by jo...@apache.org.
AMBARI-7534 - Alerts: Disabling an Alert Should Propagate to Agent (jonathanhurley)


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

Branch: refs/heads/trunk
Commit: 10f1f73b810e2c84d5818314ff9d1743c644a3bf
Parents: 7324374
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Sat Sep 27 09:33:43 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Sat Sep 27 09:33:43 2014 -0400

----------------------------------------------------------------------
 .../ambari_agent/AlertSchedulerHandler.py       | 27 ++++++--
 .../python/ambari_agent/alerts/base_alert.py    | 12 +++-
 .../src/test/python/ambari_agent/TestAlerts.py  | 68 +++++++++++++++++++-
 .../ambari_agent/dummy_files/definitions.json   |  1 +
 4 files changed, 101 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/10f1f73b/ambari-agent/src/main/python/ambari_agent/AlertSchedulerHandler.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/AlertSchedulerHandler.py b/ambari-agent/src/main/python/ambari_agent/AlertSchedulerHandler.py
index 8dcce50..c645cba 100644
--- a/ambari-agent/src/main/python/ambari_agent/AlertSchedulerHandler.py
+++ b/ambari-agent/src/main/python/ambari_agent/AlertSchedulerHandler.py
@@ -125,7 +125,7 @@ class AlertSchedulerHandler():
       uuid_valid = False
       
       for definition in definitions:
-        definition_uuid = definition.definition_uuid()
+        definition_uuid = definition.get_uuid()
         if scheduled_job.name == definition_uuid:
           uuid_valid = True
           break
@@ -141,7 +141,7 @@ class AlertSchedulerHandler():
     for definition in definitions:
       definition_scheduled = False
       for scheduled_job in scheduled_jobs:
-        definition_uuid = definition.definition_uuid()
+        definition_uuid = definition.get_uuid()
         if definition_uuid == scheduled_job.name:
           definition_scheduled = True
           break
@@ -264,7 +264,16 @@ class AlertSchedulerHandler():
     '''
     Schedule a definition (callable). Scheduled jobs are given the UUID
     as their name so that they can be identified later on.
+    <p/>
+    This function can be called with a definition that is disabled; it will
+    simply NOOP.
     '''
+    # NOOP if the definition is disabled; don't schedule it
+    if definition.is_enabled() == False:
+      logger.info("The alert {0} with UUID {1} is disabled and will not be scheduled".format(
+          definition.get_name(),definition.get_uuid()))
+      return
+    
     job = None
 
     if self.__in_minutes:
@@ -277,10 +286,20 @@ class AlertSchedulerHandler():
     # although the documentation states that Job(kwargs) takes a name 
     # key/value pair, it does not actually set the name; do it manually
     if job is not None:
-      job.name = definition.definition_uuid()
+      job.name = definition.get_uuid()
       
     logger.info("Scheduling {0} with UUID {1}".format(
-      definition.definition_name(), definition.definition_uuid()))
+      definition.get_name(), definition.get_uuid()))
+  
+  def get_job_count(self):
+    '''
+    Gets the number of jobs currently scheduled. This is mainly used for
+    test verification of scheduling
+    '''
+    if self.__scheduler is None:
+      return 0
+    
+    return len(self.__scheduler.get_jobs())   
 
 def main():
   args = list(sys.argv)

http://git-wip-us.apache.org/repos/asf/ambari/blob/10f1f73b/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py b/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py
index 10dcff8..a3eb404 100644
--- a/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py
+++ b/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py
@@ -48,14 +48,21 @@ class BaseAlert(object):
       return 1 if interval < 1 else interval
 
 
-  def definition_name(self):
+  def is_enabled(self):
+    '''
+    gets whether the definition is enabled
+    '''
+    return self.alert_meta['enabled']
+  
+
+  def get_name(self):
     '''
     gets the unique name of the alert definition
     '''
     return self.alert_meta['name']
 
 
-  def definition_uuid(self):
+  def get_uuid(self):
     '''
     gets the unique has of the alert definition
     '''
@@ -101,6 +108,7 @@ class BaseAlert(object):
     data['component'] = self._find_value('componentName')
     data['timestamp'] = long(time.time() * 1000)
     data['uuid'] = self._find_value('uuid')
+    data['enabled'] = self._find_value('enabled')
 
     if logger.isEnabledFor(logging.DEBUG):
       logger.debug("debug alert text: {0}".format(data['text']))

http://git-wip-us.apache.org/repos/asf/ambari/blob/10f1f73b/ambari-agent/src/test/python/ambari_agent/TestAlerts.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/TestAlerts.py b/ambari-agent/src/test/python/ambari_agent/TestAlerts.py
index 662d8ee..f9c2ab4 100644
--- a/ambari-agent/src/test/python/ambari_agent/TestAlerts.py
+++ b/ambari-agent/src/test/python/ambari_agent/TestAlerts.py
@@ -34,9 +34,11 @@ class TestAlerts(TestCase):
   def setUp(self):
     pass
 
+
   def tearDown(self):
     sys.stdout == sys.__stdout__
 
+
   @patch.object(Scheduler, "add_interval_job")
   @patch.object(Scheduler, "start")
   def test_start(self, aps_add_interval_job_mock, aps_start_mock):
@@ -49,6 +51,7 @@ class TestAlerts(TestCase):
     self.assertTrue(aps_add_interval_job_mock.called)
     self.assertTrue(aps_start_mock.called)
 
+
   def test_port_alert(self):
     json = { "name": "namenode_process",
       "service": "HDFS",
@@ -56,6 +59,7 @@ class TestAlerts(TestCase):
       "label": "NameNode process",
       "interval": 6,
       "scope": "host",
+      "enabled": True,
       "uuid": "c1f73191-4481-4435-8dae-fd380e4c0be1",
       "source": {
         "type": "PORT",
@@ -80,6 +84,7 @@ class TestAlerts(TestCase):
 
     res = pa.collect()
 
+
   def test_port_alert_no_sub(self):
     json = { "name": "namenode_process",
       "service": "HDFS",
@@ -87,6 +92,7 @@ class TestAlerts(TestCase):
       "label": "NameNode process",
       "interval": 6,
       "scope": "host",
+      "enabled": True,
       "uuid": "c1f73191-4481-4435-8dae-fd380e4c0be1",
       "source": {
         "type": "PORT",
@@ -109,6 +115,7 @@ class TestAlerts(TestCase):
 
     res = pa.collect()
 
+
   def test_script_alert(self):
     json = {
       "name": "namenode_process",
@@ -117,6 +124,7 @@ class TestAlerts(TestCase):
       "label": "NameNode process",
       "interval": 6,
       "scope": "host",
+      "enabled": True,
       "uuid": "c1f73191-4481-4435-8dae-fd380e4c0be1",
       "source": {
         "type": "SCRIPT",
@@ -145,7 +153,8 @@ class TestAlerts(TestCase):
 
     self.assertEquals('WARNING', collector.alerts()[0]['state'])
     self.assertEquals('all is not well', collector.alerts()[0]['text'])
-   
+
+
   @patch.object(MetricAlert, "_load_jmx")
   def test_metric_alert(self, ma_load_jmx_mock):
     json = {
@@ -155,6 +164,7 @@ class TestAlerts(TestCase):
       "label": "NameNode process",
       "interval": 6,
       "scope": "host",
+      "enabled": True,
       "uuid": "c1f73191-4481-4435-8dae-fd380e4c0be1",
       "source": {
         "type": "METRIC",
@@ -201,13 +211,17 @@ class TestAlerts(TestCase):
     self.assertEquals('OK', collector.alerts()[0]['state'])
     self.assertEquals('ok_arr: 1 3 None', collector.alerts()[0]['text'])
     
+
   def test_reschedule(self):
     test_file_path = os.path.join('ambari_agent', 'dummy_files')
     test_stack_path = os.path.join('ambari_agent', 'dummy_files')
 
     ash = AlertSchedulerHandler(test_file_path, test_stack_path)
     ash.start()
+    
+    self.assertEquals(1, ash.get_job_count())
     ash.reschedule()
+    self.assertEquals(1, ash.get_job_count())
         
   
   def test_alert_collector_purge(self):
@@ -217,6 +231,7 @@ class TestAlerts(TestCase):
       "label": "NameNode process",
       "interval": 6,
       "scope": "host",
+      "enabled": True,
       "uuid": "c1f73191-4481-4435-8dae-fd380e4c0be1",
       "source": {
         "type": "PORT",
@@ -247,3 +262,54 @@ class TestAlerts(TestCase):
     collector.remove_by_uuid('c1f73191-4481-4435-8dae-fd380e4c0be1')
     self.assertEquals(0,len(collector.alerts()))
     
+
+  def test_disabled_definitions(self):
+    test_file_path = os.path.join('ambari_agent', 'dummy_files')
+    test_stack_path = os.path.join('ambari_agent', 'dummy_files')
+
+    ash = AlertSchedulerHandler(test_file_path, test_stack_path)
+    ash.start()
+
+    self.assertEquals(1, ash.get_job_count())
+
+    json = { "name": "namenode_process",
+      "service": "HDFS",
+      "component": "NAMENODE",
+      "label": "NameNode process",
+      "interval": 6,
+      "scope": "host",
+      "enabled": True,
+      "uuid": "c1f73191-4481-4435-8dae-fd380e4c0be1",
+      "source": {
+        "type": "PORT",
+        "uri": "{{hdfs-site/my-key}}",
+        "default_port": 50070,
+        "reporting": {
+          "ok": {
+            "text": "TCP OK - {0:.4f} response time on port {1}"
+          },
+          "critical": {
+            "text": "Could not load process info: {0}"
+          }
+        }
+      }
+    }
+
+    pa = PortAlert(json, json['source'])
+    ash.schedule_definition(pa)
+    
+    self.assertEquals(2, ash.get_job_count())
+    
+    json['enabled'] = False
+    pa = PortAlert(json, json['source'])
+    ash.schedule_definition(pa)
+    
+    # verify disabled alert not scheduled
+    self.assertEquals(2, ash.get_job_count())
+    
+    json['enabled'] = True
+    pa = PortAlert(json, json['source'])
+    ash.schedule_definition(pa)
+    
+    # verify enabled alert was scheduled
+    self.assertEquals(3, ash.get_job_count())    
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/10f1f73b/ambari-agent/src/test/python/ambari_agent/dummy_files/definitions.json
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/dummy_files/definitions.json b/ambari-agent/src/test/python/ambari_agent/dummy_files/definitions.json
index 30973c2..8e01833 100644
--- a/ambari-agent/src/test/python/ambari_agent/dummy_files/definitions.json
+++ b/ambari-agent/src/test/python/ambari_agent/dummy_files/definitions.json
@@ -17,6 +17,7 @@
         "interval": 6,
         "scope": "host",
         "uuid": "3f82ae27-fa6a-465b-b77d-67963ac55d2f",
+        "enabled": true,
         "source": {
           "type": "PORT",
           "uri": "{{hdfs-site/dfs.namenode.http-address}}",


[43/50] [abbrv] git commit: AMBARI-7568 - Alerts: An Alert Definition On Demand Execution (jonathanhurley)

Posted by jo...@apache.org.
AMBARI-7568 - Alerts: An Alert Definition On Demand Execution (jonathanhurley)


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

Branch: refs/heads/trunk
Commit: 054745d06472ef74430f47f09e1c8881f9f9780a
Parents: b9cca71
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Tue Sep 30 17:08:55 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Tue Sep 30 23:12:48 2014 -0400

----------------------------------------------------------------------
 .../ambari_agent/AlertSchedulerHandler.py       | 62 +++++++++++---
 .../src/main/python/ambari_agent/Controller.py  |  4 +
 .../python/ambari_agent/alerts/collector.py     | 12 ++-
 .../src/test/python/ambari_agent/TestAlerts.py  | 44 +++++++++-
 .../ambari/server/agent/AgentCommand.java       | 12 ++-
 .../server/agent/AlertExecutionCommand.java     | 74 +++++++++++++++++
 .../ambari/server/agent/HeartBeatHandler.java   |  4 +
 .../ambari/server/agent/HeartBeatResponse.java  | 17 ++++
 .../AlertDefinitionResourceProvider.java        | 87 ++++++++++++++++++--
 .../server/state/alert/AlertDefinitionHash.java | 63 ++++++++++----
 .../src/main/resources/properties.json          |  3 +-
 .../state/alerts/AlertDefinitionHashTest.java   | 47 ++++++++++-
 .../svccomphost/ServiceComponentHostTest.java   |  2 +-
 13 files changed, 389 insertions(+), 42 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/054745d0/ambari-agent/src/main/python/ambari_agent/AlertSchedulerHandler.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/AlertSchedulerHandler.py b/ambari-agent/src/main/python/ambari_agent/AlertSchedulerHandler.py
index c645cba..5863b23 100644
--- a/ambari-agent/src/main/python/ambari_agent/AlertSchedulerHandler.py
+++ b/ambari-agent/src/main/python/ambari_agent/AlertSchedulerHandler.py
@@ -33,9 +33,9 @@ from alerts.metric_alert import MetricAlert
 from alerts.port_alert import PortAlert
 from alerts.script_alert import ScriptAlert
 
-
 logger = logging.getLogger()
 
+
 class AlertSchedulerHandler():
   make_cachedir = True
 
@@ -50,6 +50,7 @@ class AlertSchedulerHandler():
     'standalone': False
   }
 
+
   def __init__(self, cachedir, stacks_dir, in_minutes=True):
     self.cachedir = cachedir
     self.stacks_dir = stacks_dir
@@ -66,7 +67,7 @@ class AlertSchedulerHandler():
     self.__in_minutes = in_minutes
     self.__config_maps = {}
 
-          
+
   def update_definitions(self, alert_commands, reschedule_jobs=False):
     ''' updates the persisted definitions and restarts the scheduler '''
     
@@ -76,11 +77,11 @@ class AlertSchedulerHandler():
     if reschedule_jobs:
       self.reschedule()
 
-      
+
   def __make_function(self, alert_def):
     return lambda: alert_def.collect()
 
-    
+
   def start(self):
     ''' loads definitions from file and starts the scheduler '''
 
@@ -102,7 +103,7 @@ class AlertSchedulerHandler():
 
     self.__scheduler.start()
 
-    
+
   def stop(self):
     if not self.__scheduler is None:
       self.__scheduler.shutdown(wait=False)
@@ -159,7 +160,7 @@ class AlertSchedulerHandler():
     ''' gets the collector for reporting to the server '''
     return self._collector
   
-      
+
   def __load_definitions(self):
     ''' loads all alert commands from the file.  all clusters are stored in one file '''
     definitions = []
@@ -184,13 +185,11 @@ class AlertSchedulerHandler():
         configmap = command_json['configurations']
 
       for definition in command_json['alertDefinitions']:
-        obj = self.__json_to_callable(definition)
+        obj = self.__json_to_callable(clusterName, hostName, definition)
         
         if obj is None:
           continue
           
-        obj.set_cluster(clusterName, hostName)
-
         # get the config values for the alerts 'lookup keys',
         # eg: hdfs-site/dfs.namenode.http-address : host_and_port        
         vals = self.__find_config_values(configmap, obj.get_lookup_keys())
@@ -202,7 +201,8 @@ class AlertSchedulerHandler():
       
     return definitions
 
-  def __json_to_callable(self, json_definition):
+
+  def __json_to_callable(self, clusterName, hostName, json_definition):
     '''
     converts the json that represents all aspects of a definition
     and makes an object that extends BaseAlert that is used for individual
@@ -223,8 +223,12 @@ class AlertSchedulerHandler():
       source['stacks_dir'] = self.stacks_dir
       alert = ScriptAlert(json_definition, source)
 
+    if alert is not None:
+      alert.set_cluster(clusterName, hostName)
+
     return alert
-    
+
+
   def __find_config_values(self, configmap, obj_keylist):
     ''' finds templated values in the configuration map provided  by the server '''
     if configmap is None:
@@ -242,7 +246,8 @@ class AlertSchedulerHandler():
         pass
         
     return result
-    
+
+ 
   def update_configurations(self, commands):
     '''
     when an execution command comes in, update any necessary values.
@@ -291,6 +296,7 @@ class AlertSchedulerHandler():
     logger.info("Scheduling {0} with UUID {1}".format(
       definition.get_name(), definition.get_uuid()))
   
+
   def get_job_count(self):
     '''
     Gets the number of jobs currently scheduled. This is mainly used for
@@ -299,7 +305,37 @@ class AlertSchedulerHandler():
     if self.__scheduler is None:
       return 0
     
-    return len(self.__scheduler.get_jobs())   
+    return len(self.__scheduler.get_jobs())
+
+  
+  def execute_alert(self, execution_commands):
+    '''
+    Executes an alert immediately, ignoring any scheduled jobs. The existing
+    jobs remain untouched. The result of this is stored in the alert
+    collector for tranmission during the next heartbeat
+    '''
+    if self.__scheduler is None or execution_commands is None:
+      return
+
+    for execution_command in execution_commands:
+      try:
+        alert_definition = execution_command['alertDefinition']
+        
+        clusterName = '' if not 'clusterName' in execution_command else execution_command['clusterName']
+        hostName = '' if not 'hostName' in execution_command else execution_command['hostName']      
+        
+        alert = self.__json_to_callable(clusterName, hostName, alert_definition)
+  
+        if alert is None:
+          continue
+  
+        logger.info("Executing on-demand alert {0} ({1})".format(alert.get_name(), 
+            alert.get_uuid()))
+        
+        alert.set_helpers(self._collector, self.__config_maps[clusterName])
+        alert.collect()
+      except:
+        logger.exception("Unable to execute the alert outside of the job scheduler")
 
 def main():
   args = list(sys.argv)

http://git-wip-us.apache.org/repos/asf/ambari/blob/054745d0/ambari-agent/src/main/python/ambari_agent/Controller.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/Controller.py b/ambari-agent/src/main/python/ambari_agent/Controller.py
index 18df06e..1f9471d 100644
--- a/ambari-agent/src/main/python/ambari_agent/Controller.py
+++ b/ambari-agent/src/main/python/ambari_agent/Controller.py
@@ -262,6 +262,10 @@ class Controller(threading.Thread):
         if 'alertDefinitionCommands' in response.keys():
           self.alert_scheduler_handler.update_definitions(response['alertDefinitionCommands'], True)
           pass
+        
+        if 'alertExecutionCommands' in response.keys():
+          self.alert_scheduler_handler.execute_alert(response['alertExecutionCommands'])
+          pass        
 
         if "true" == response['restartAgent']:
           logger.error("Received the restartAgent command")

http://git-wip-us.apache.org/repos/asf/ambari/blob/054745d0/ambari-agent/src/main/python/ambari_agent/alerts/collector.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/alerts/collector.py b/ambari-agent/src/main/python/ambari_agent/alerts/collector.py
index 9943211..f2c4f72 100644
--- a/ambari-agent/src/main/python/ambari_agent/alerts/collector.py
+++ b/ambari-agent/src/main/python/ambari_agent/alerts/collector.py
@@ -28,13 +28,15 @@ class AlertCollector():
   '''  
   def __init__(self):
     self.__buckets = {}
-    
+
+
   def put(self, cluster, alert):
     if not cluster in self.__buckets:
       self.__buckets[cluster] = {}
       
     self.__buckets[cluster][alert['name']] = alert
-    
+
+
   def remove(self, cluster, alert_name):
     '''
     Removes the alert with the specified name if it exists in the dictionary
@@ -43,7 +45,8 @@ class AlertCollector():
       return
     
     del self.__buckets[cluster][alert_name]
-    
+
+
   def remove_by_uuid(self, alert_uuid):
     '''
     Removes the alert with the specified uuid if it exists in the dictionary
@@ -53,7 +56,8 @@ class AlertCollector():
         alert = alert_map[alert_name]
         if alert['uuid'] == alert_uuid:
           self.remove(cluster, alert_name)
-        
+
+
   def alerts(self):
     alerts = []
     for clustermap in self.__buckets.values()[:]:

http://git-wip-us.apache.org/repos/asf/ambari/blob/054745d0/ambari-agent/src/test/python/ambari_agent/TestAlerts.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/TestAlerts.py b/ambari-agent/src/test/python/ambari_agent/TestAlerts.py
index f9c2ab4..1bacf24 100644
--- a/ambari-agent/src/test/python/ambari_agent/TestAlerts.py
+++ b/ambari-agent/src/test/python/ambari_agent/TestAlerts.py
@@ -312,4 +312,46 @@ class TestAlerts(TestCase):
     ash.schedule_definition(pa)
     
     # verify enabled alert was scheduled
-    self.assertEquals(3, ash.get_job_count())    
\ No newline at end of file
+    self.assertEquals(3, ash.get_job_count())
+    
+  def test_immediate_alert(self):
+    test_file_path = os.path.join('ambari_agent', 'dummy_files')
+    test_stack_path = os.path.join('ambari_agent', 'dummy_files')
+
+    ash = AlertSchedulerHandler(test_file_path, test_stack_path)
+    ash.start()
+
+    self.assertEquals(1, ash.get_job_count())
+    self.assertEquals(0, len(ash._collector.alerts()))
+
+    execution_commands = [ { 
+        "clusterName": "c1",
+        "hostName": "c6401.ambari.apache.org",    
+        "alertDefinition": {         
+          "name": "namenode_process",
+          "service": "HDFS",
+          "component": "NAMENODE",
+          "label": "NameNode process",
+          "interval": 6,
+          "scope": "host",
+          "enabled": True,
+          "uuid": "c1f73191-4481-4435-8dae-fd380e4c0be1",
+          "source": {
+            "type": "PORT",
+            "uri": "{{hdfs-site/my-key}}",
+            "default_port": 50070,
+            "reporting": {
+              "ok": {
+                "text": "TCP OK - {0:.4f} response time on port {1}"
+              },
+              "critical": {
+                "text": "Could not load process info: {0}"
+              }
+            }
+          }
+        }
+      } ]
+    
+    # execute the alert immediately and verify that the collector has the result
+    ash.execute_alert(execution_commands)
+    self.assertEquals(1, len(ash._collector.alerts()))
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/054745d0/ambari-server/src/main/java/org/apache/ambari/server/agent/AgentCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/AgentCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/AgentCommand.java
index 6e8aab1..e2f013d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/AgentCommand.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/AgentCommand.java
@@ -53,7 +53,17 @@ public abstract class AgentCommand {
     STATUS_COMMAND,
     CANCEL_COMMAND,
     REGISTRATION_COMMAND,
-    ALERT_DEFINITION_COMMAND
+
+    /**
+     * Sends alert definitions to an agent which will refresh all alerts running
+     * on that host.
+     */
+    ALERT_DEFINITION_COMMAND,
+
+    /**
+     * A single alert that should be run immediately.
+     */
+    ALERT_EXECUTION_COMMAND
   }
 
   public AgentCommandType getCommandType() {

http://git-wip-us.apache.org/repos/asf/ambari/blob/054745d0/ambari-server/src/main/java/org/apache/ambari/server/agent/AlertExecutionCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/AlertExecutionCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/AlertExecutionCommand.java
new file mode 100644
index 0000000..b0781da
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/AlertExecutionCommand.java
@@ -0,0 +1,74 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.agent;
+
+import org.apache.ambari.server.state.alert.AlertDefinition;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * The {@link AlertExecutionCommand} is used to instruct an agent to run an
+ * alert immediately and return the result in the next heartbeat. This does not
+ * affect any existing jobs and does cause the job for the executed alert to
+ * reset its interval.
+ */
+public class AlertExecutionCommand extends AgentCommand {
+
+  /**
+   * The name of the cluster.
+   */
+  @SerializedName("clusterName")
+  private final String m_clusterName;
+
+  /**
+   * The agent hostname.
+   */
+  @SerializedName("hostName")
+  private final String m_hostName;
+
+  /**
+   * The definition to run.
+   */
+  @SerializedName("alertDefinition")
+  private final AlertDefinition m_definition;
+
+  /**
+   * Constructor.
+   *
+   * @param clusterName
+   *          the name of the cluster (not {@code null}).
+   * @param hostName
+   *          the name of the host (not {@code null}).
+   * @param definition
+   *          the definition to run (not {@code null}).
+   */
+  public AlertExecutionCommand(String clusterName, String hostName, AlertDefinition definition) {
+    super(AgentCommandType.ALERT_EXECUTION_COMMAND);
+    m_clusterName = clusterName;
+    m_hostName = hostName;
+    m_definition = definition;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public AgentCommandType getCommandType() {
+    return AgentCommandType.ALERT_EXECUTION_COMMAND;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/054745d0/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
index c826153..f735fc5 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
@@ -621,6 +621,10 @@ public class HeartBeatHandler {
             response.addAlertDefinitionCommand((AlertDefinitionCommand) ac);
             break;
           }
+          case ALERT_EXECUTION_COMMAND: {
+            response.addAlertExecutionCommand((AlertExecutionCommand) ac);
+            break;
+          }
           default:
             LOG.error("There is no action for agent command ="
                 + ac.getCommandType().name());

http://git-wip-us.apache.org/repos/asf/ambari/blob/054745d0/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatResponse.java
index 1e9dc12..56b4f18 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatResponse.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatResponse.java
@@ -50,6 +50,13 @@ public class HeartBeatResponse {
   @SerializedName("alertDefinitionCommands")
   private List<AlertDefinitionCommand> alertDefinitionCommands = null;
 
+  /**
+   * {@link AlertExecutionCommand}s are used to execute an alert job
+   * immediately.
+   */
+  @SerializedName("alertExecutionCommands")
+  private List<AlertExecutionCommand> alertExecutionCommands = null;
+
   @SerializedName("registrationCommand")
   private RegistrationCommand registrationCommand;
 
@@ -159,6 +166,16 @@ public class HeartBeatResponse {
     alertDefinitionCommands.add(command);
   }
 
+  public void addAlertExecutionCommand(AlertExecutionCommand command) {
+    // commands are added here when they are taken off the queue; there should
+    // be no thread contention and thus no worry about locks for the null check
+    if (null == alertExecutionCommands) {
+      alertExecutionCommands = new ArrayList<AlertExecutionCommand>();
+    }
+
+    alertExecutionCommands.add(command);
+  }
+
   @Override
   public String toString() {
     StringBuilder buffer = new StringBuilder("HeartBeatResponse{");

http://git-wip-us.apache.org/repos/asf/ambari/blob/054745d0/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java
index e2d2837..e4aa222 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java
@@ -28,6 +28,8 @@ import java.util.Set;
 import java.util.UUID;
 
 import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.agent.ActionQueue;
+import org.apache.ambari.server.agent.AlertExecutionCommand;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
 import org.apache.ambari.server.controller.spi.NoSuchResourceException;
@@ -43,6 +45,8 @@ import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
 import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.alert.AlertDefinition;
+import org.apache.ambari.server.state.alert.AlertDefinitionFactory;
 import org.apache.ambari.server.state.alert.AlertDefinitionHash;
 import org.apache.ambari.server.state.alert.Scope;
 import org.apache.ambari.server.state.alert.SourceType;
@@ -77,6 +81,7 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
   protected static final String ALERT_DEF_SOURCE_REPORTING_WARNING = "AlertDefinition/source/reporting/warning";
   protected static final String ALERT_DEF_SOURCE_REPORTING_CRITICAL = "AlertDefinition/source/reporting/critical";
 
+  protected static final String ALERT_DEF_ACTION_RUN_NOW = "AlertDefinition/run_now";
 
   private static Set<String> pkPropertyIds = new HashSet<String>(
       Arrays.asList(ALERT_DEF_ID, ALERT_DEF_NAME));
@@ -88,12 +93,26 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
   private static AlertDefinitionHash alertDefinitionHash;
 
   /**
+   * Used for coercing an {@link AlertDefinitionEntity} to an
+   * {@link AlertDefinition}.
+   */
+  private static AlertDefinitionFactory definitionFactory;
+
+  /**
+   * Used to enqueue commands to send to the agents when running an alert
+   * on-demand.
+   */
+  private static ActionQueue actionQueue;
+
+  /**
    * @param instance
    */
   @Inject
   public static void init(Injector injector) {
     alertDefinitionDAO = injector.getInstance(AlertDefinitionDAO.class);
     alertDefinitionHash = injector.getInstance(AlertDefinitionHash.class);
+    definitionFactory = injector.getInstance(AlertDefinitionFactory.class);
+    actionQueue = injector.getInstance(ActionQueue.class);
   }
 
   AlertDefinitionResourceProvider(Set<String> propertyIds,
@@ -199,9 +218,24 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
       NoSuchResourceException, NoSuchParentResourceException {
 
     String clusterName = null;
-    Set<String> invalidatedHosts = new HashSet<String>();
     Clusters clusters = getManagementController().getClusters();
 
+    // check the predicate to see if there is a reques to run
+    // the alert definition immediately
+    if( null != predicate ){
+      Set<Map<String,Object>> predicateMaps = getPropertyMaps(predicate);
+      for (Map<String, Object> propertyMap : predicateMaps) {
+        String runNow = (String) propertyMap.get(ALERT_DEF_ACTION_RUN_NOW);
+        if (null != runNow) {
+          if (Boolean.valueOf(runNow) == Boolean.TRUE) {
+            scheduleImmediateAlert(propertyMap);
+          }
+        }
+      }
+    }
+
+    // if an AlertDefinition property body was specified, perform the update\
+    Set<String> invalidatedHosts = new HashSet<String>();
     for (Map<String, Object> requestPropMap : request.getProperties()) {
       for (Map<String, Object> propertyMap : getPropertyMaps(requestPropMap, predicate)) {
         String stringId = (String) propertyMap.get(ALERT_DEF_ID);
@@ -234,10 +268,13 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
       }
     }
 
-    // build alert definition commands for all agent hosts affected
-    alertDefinitionHash.enqueueAgentCommands(clusterName, invalidatedHosts);
-
-    notifyUpdate(Resource.Type.AlertDefinition, request, predicate);
+    // build alert definition commands for all agent hosts affected; only
+    // update agents and broadcast update event if there are actual invalidated
+    // hosts
+    if (invalidatedHosts.size() > 0) {
+      alertDefinitionHash.enqueueAgentCommands(clusterName, invalidatedHosts);
+      notifyUpdate(Resource.Type.AlertDefinition, request, predicate);
+    }
 
     return getRequestStatus(null);
   }
@@ -501,4 +538,44 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
 
     return resource;
   }
+
+  /**
+   * Extracts an {@link AlertDefinitionEntity} from the property map and
+   * enqueues an {@link AlertExecutionCommand} for every host that should re-run
+   * the specified definition.
+   *
+   * @param propertyMap
+   */
+  private void scheduleImmediateAlert(Map<String, Object> propertyMap) {
+    Clusters clusters = getManagementController().getClusters();
+    String stringId = (String) propertyMap.get(ALERT_DEF_ID);
+    long id = Long.parseLong(stringId);
+
+    AlertDefinitionEntity entity = alertDefinitionDAO.findById(id);
+    if (null == entity) {
+      LOG.error("Unable to lookup alert definition with ID {}", id);
+      return;
+    }
+
+    Cluster cluster = null;
+    try {
+      cluster = clusters.getClusterById(entity.getClusterId());
+    } catch (AmbariException ambariException) {
+      LOG.error("Unable to lookup cluster with ID {}", entity.getClusterId(),
+          ambariException);
+      return;
+    }
+
+    Set<String> hostNames = alertDefinitionHash.getAssociatedHosts(cluster,
+        entity.getDefinitionName(), entity.getServiceName(),
+        entity.getComponentName());
+
+    for (String hostName : hostNames) {
+      AlertDefinition definition = definitionFactory.coerce(entity);
+      AlertExecutionCommand command = new AlertExecutionCommand(
+          cluster.getClusterName(), hostName, definition);
+
+      actionQueue.enqueue(hostName, command);
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/054745d0/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java
index 35d7742..10cd54a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java
@@ -309,16 +309,13 @@ public class AlertDefinitionHash {
    */
   public Set<String> invalidateHosts(long clusterId, String definitionName,
       String definitionServiceName, String definitionComponentName) {
-    Set<String> invalidatedHosts = new HashSet<String>();
 
     Cluster cluster = null;
-    Map<String, Host> hosts = null;
     String clusterName = null;
     try {
       cluster = m_clusters.getClusterById(clusterId);
       if (null != cluster) {
         clusterName = cluster.getClusterName();
-        hosts = m_clusters.getHostsForCluster(clusterName);
       }
 
       if (null == cluster) {
@@ -329,16 +326,55 @@ public class AlertDefinitionHash {
     }
 
     if (null == cluster) {
-      return invalidatedHosts;
+      return Collections.emptySet();
+    }
+
+    // determine which hosts in the cluster would be affected by a change
+    // to the specified definition
+    Set<String> affectedHosts = getAssociatedHosts(cluster, definitionName,
+        definitionServiceName, definitionComponentName);
+
+    // invalidate all returned hosts
+    for (String hostName : affectedHosts) {
+      invalidate(clusterName, hostName);
+    }
+
+    return affectedHosts;
+  }
+
+  /**
+   * Gets the hosts that are associated with the specified definition. Each host
+   * returned is expected to be capable of running the alert. A change to the
+   * definition would entail contacting each returned host and invalidating
+   * their current alert definitions.
+   *
+   * @param cluster
+   * @param definitionName
+   * @param definitionServiceName
+   * @param definitionComponentName
+   * @return a set of all associated hosts or an empty set, never {@code null}.
+   */
+  public Set<String> getAssociatedHosts(Cluster cluster, String definitionName,
+      String definitionServiceName, String definitionComponentName) {
+
+    Map<String, Host> hosts = null;
+    String clusterName = cluster.getClusterName();
+    Set<String> affectedHosts = new HashSet<String>();
+
+    try {
+      hosts = m_clusters.getHostsForCluster(clusterName);
+    } catch (AmbariException ambariException) {
+      LOG.error("Unable to lookup hosts for cluster named {}", clusterName,
+          ambariException);
+
+      return affectedHosts;
     }
 
     // intercept host agent alerts; they affect all hosts
     if (Services.AMBARI.equals(definitionServiceName)
         && Components.AMBARI_AGENT.equals(definitionComponentName)) {
-
-      invalidateAll();
-      invalidatedHosts.addAll(hosts.keySet());
-      return invalidatedHosts;
+      affectedHosts.addAll(hosts.keySet());
+      return affectedHosts;
     }
 
     // find all hosts that have the matching service and component
@@ -354,8 +390,7 @@ public class AlertDefinitionHash {
         String componentName = component.getServiceComponentName();
         if (serviceName.equals(definitionServiceName)
             && componentName.equals(definitionComponentName)) {
-          invalidate(clusterName, hostName);
-          invalidatedHosts.add(hostName);
+          affectedHosts.add(hostName);
         }
       }
     }
@@ -367,7 +402,7 @@ public class AlertDefinitionHash {
       LOG.warn("The alert definition {} has an unknown service of {}",
           definitionName, definitionServiceName);
 
-      return invalidatedHosts;
+      return affectedHosts;
     }
 
     // get all master components of the definition's service; any hosts that
@@ -379,15 +414,14 @@ public class AlertDefinitionHash {
           Map<String, ServiceComponentHost> componentHosts = component.getValue().getServiceComponentHosts();
           if (null != componentHosts) {
             for (String componentHost : componentHosts.keySet()) {
-              invalidate(clusterName, componentHost);
-              invalidatedHosts.add(componentHost);
+              affectedHosts.add(componentHost);
             }
           }
         }
       }
     }
 
-    return invalidatedHosts;
+    return affectedHosts;
   }
 
   /**
@@ -462,6 +496,7 @@ public class AlertDefinitionHash {
       // before the next heartbeat, there would be several commands that would
       // force the agents to reschedule their alerts more than once
       m_actionQueue.dequeue(hostName, AgentCommandType.ALERT_DEFINITION_COMMAND);
+      m_actionQueue.dequeue(hostName, AgentCommandType.ALERT_EXECUTION_COMMAND);
       m_actionQueue.enqueue(hostName, command);
     }
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/054745d0/ambari-server/src/main/resources/properties.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/properties.json b/ambari-server/src/main/resources/properties.json
index 3893f39..96f44c4 100644
--- a/ambari-server/src/main/resources/properties.json
+++ b/ambari-server/src/main/resources/properties.json
@@ -447,7 +447,8 @@
       "AlertDefinition/interval",
       "AlertDefinition/enabled",
       "AlertDefinition/scope",
-      "AlertDefinition/source"
+      "AlertDefinition/source",
+      "AlertDefinition/run_now"
     ],
     "AlertGroup": [
       "AlertGroup/id",

http://git-wip-us.apache.org/repos/asf/ambari/blob/054745d0/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertDefinitionHashTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertDefinitionHashTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertDefinitionHashTest.java
index 1cb6eac..412b4d3 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertDefinitionHashTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertDefinitionHashTest.java
@@ -25,6 +25,7 @@ import java.security.MessageDigest;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -32,11 +33,16 @@ import java.util.UUID;
 
 import junit.framework.TestCase;
 
+import org.apache.ambari.server.agent.ActionQueue;
+import org.apache.ambari.server.agent.AlertDefinitionCommand;
+import org.apache.ambari.server.agent.AlertExecutionCommand;
 import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
 import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
 import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.Config;
+import org.apache.ambari.server.state.ConfigHelper;
 import org.apache.ambari.server.state.Host;
 import org.apache.ambari.server.state.Service;
 import org.apache.ambari.server.state.ServiceComponent;
@@ -344,6 +350,35 @@ public class AlertDefinitionHashTest extends TestCase {
     assertEquals(expected, m_hash.getHash(CLUSTERNAME, HOSTNAME));
   }
 
+  @Test
+  public void testActionQueueInvalidation() throws Exception{
+    ActionQueue actionQueue = m_injector.getInstance(ActionQueue.class);
+
+    AlertDefinitionCommand definitionCommand1 = new AlertDefinitionCommand(
+        CLUSTERNAME, HOSTNAME, "12345", null);
+
+    AlertDefinitionCommand definitionCommand2 = new AlertDefinitionCommand(
+        CLUSTERNAME, "anotherHost", "67890", null);
+
+    AlertExecutionCommand executionCommand = new AlertExecutionCommand(
+        CLUSTERNAME, HOSTNAME, null);
+
+    actionQueue.enqueue(HOSTNAME, definitionCommand1);
+    actionQueue.enqueue(HOSTNAME, executionCommand);
+    actionQueue.enqueue("anotherHost", definitionCommand2);
+
+    assertEquals(2, actionQueue.size(HOSTNAME));
+    assertEquals(1, actionQueue.size("anotherHost"));
+
+    Set<String> hosts = new HashSet<String>();
+    hosts.add(HOSTNAME);
+
+    // should invalidate both alert commands, and add a new definition command
+    m_hash.enqueueAgentCommands(CLUSTERNAME, hosts);
+    assertEquals(1, actionQueue.size(HOSTNAME));
+    assertEquals(1, actionQueue.size("anotherHost"));
+  }
+
   /**
    *
    */
@@ -353,12 +388,20 @@ public class AlertDefinitionHashTest extends TestCase {
      */
     @Override
     public void configure(Binder binder) {
+      Cluster cluster = EasyMock.createNiceMock(Cluster.class);
+      EasyMock.expect(cluster.getAllConfigs()).andReturn(
+          new ArrayList<Config>()).anyTimes();
+
       binder.bind(Clusters.class).toInstance(
           EasyMock.createNiceMock(Clusters.class));
-      binder.bind(Cluster.class).toInstance(
-          EasyMock.createNiceMock(Cluster.class));
+
+      binder.bind(Cluster.class).toInstance(cluster);
+
       binder.bind(AlertDefinitionDAO.class).toInstance(
           EasyMock.createNiceMock(AlertDefinitionDAO.class));
+
+      binder.bind(ConfigHelper.class).toInstance(
+          EasyMock.createNiceMock(ConfigHelper.class));
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/054745d0/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java
index 79ae350..5410ee3 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java
@@ -125,7 +125,7 @@ public class ServiceComponentHostTest {
       String svcComponent,
       String hostName, boolean isClient) throws AmbariException{
     Cluster c = clusters.getCluster("C1");
-
+    Assert.assertNotNull(c.getConfigGroups());
     return createNewServiceComponentHost(c, svc, svcComponent, hostName);
   }
 


[12/50] [abbrv] git commit: AMBARI-7118. Alerts: populate incoming alert data to history and current (ncole)

Posted by jo...@apache.org.
AMBARI-7118. Alerts: populate incoming alert data to history and current (ncole)


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

Branch: refs/heads/trunk
Commit: 0de98b0207b48007f39610f8dc8c0d13de6e7d92
Parents: 03a5be1
Author: Nate Cole <nc...@hortonworks.com>
Authored: Tue Sep 2 16:24:51 2014 -0400
Committer: Nate Cole <nc...@hortonworks.com>
Committed: Wed Sep 3 07:59:40 2014 -0400

----------------------------------------------------------------------
 .../ambari_agent/AlertSchedulerHandler.py       |   2 -
 .../python/ambari_agent/alerts/base_alert.py    |   2 +
 .../ambari/server/agent/HeartBeatHandler.java   |  13 ++
 .../apache/ambari/server/orm/dao/AlertsDAO.java |  14 ++
 .../server/orm/entities/AlertCurrentEntity.java |   4 +-
 .../org/apache/ambari/server/state/Alert.java   |  21 ++-
 .../server/state/cluster/AlertDataManager.java  | 110 +++++++++++
 .../server/orm/dao/AlertDefinitionDAOTest.java  |   2 +-
 .../ambari/server/orm/dao/AlertsDAOTest.java    |  14 ++
 .../state/cluster/AlertDataManagerTest.java     | 181 +++++++++++++++++++
 10 files changed, 358 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/0de98b02/ambari-agent/src/main/python/ambari_agent/AlertSchedulerHandler.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/AlertSchedulerHandler.py b/ambari-agent/src/main/python/ambari_agent/AlertSchedulerHandler.py
index cc5be92..e987dae 100644
--- a/ambari-agent/src/main/python/ambari_agent/AlertSchedulerHandler.py
+++ b/ambari-agent/src/main/python/ambari_agent/AlertSchedulerHandler.py
@@ -57,8 +57,6 @@ class AlertSchedulerHandler():
       except:
         logger.critical("Could not create the cache directory {0}".format(cachedir))
         pass
-    
-
 
     self.__scheduler = Scheduler(AlertSchedulerHandler.APS_CONFIG)
     self.__in_minutes = in_minutes

http://git-wip-us.apache.org/repos/asf/ambari/blob/0de98b02/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py b/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py
index bf8ada6..adb872a 100644
--- a/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py
+++ b/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py
@@ -20,6 +20,7 @@ limitations under the License.
 
 import logging
 import re
+import time
 import traceback
 
 logger = logging.getLogger()
@@ -78,6 +79,7 @@ class BaseAlert(object):
     data['cluster'] = self.cluster
     data['service'] = self._find_value('serviceName')
     data['component'] = self._find_value('componentName')
+    data['timestamp'] = long(time.time() * 1000)
     
     self.collector.put(self.cluster, data)
   

http://git-wip-us.apache.org/repos/asf/ambari/blob/0de98b02/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
index d0d5a13..492d832 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
@@ -60,6 +60,7 @@ import org.apache.ambari.server.state.StackInfo;
 import org.apache.ambari.server.state.State;
 import org.apache.ambari.server.state.alert.AlertDefinition;
 import org.apache.ambari.server.state.alert.AlertDefinitionHash;
+import org.apache.ambari.server.state.cluster.AlertDataManager;
 import org.apache.ambari.server.state.fsm.InvalidStateTransitionException;
 import org.apache.ambari.server.state.host.HostHealthyHeartbeatEvent;
 import org.apache.ambari.server.state.host.HostRegistrationRequestEvent;
@@ -114,6 +115,9 @@ public class HeartBeatHandler {
 
   @Inject
   private AlertDefinitionHash alertDefinitionHash;
+  
+  @Inject
+  private AlertDataManager alertManager;
 
   private Map<String, Long> hostResponseIds = new ConcurrentHashMap<String, Long>();
 
@@ -232,6 +236,15 @@ public class HeartBeatHandler {
     if (null == hostname || null == heartbeat) {
       return;
     }
+    
+    if (null != heartbeat.getAlerts()) {
+      for (Alert alert : heartbeat.getAlerts()) {
+        if (null == alert.getHost())
+          alert.setHost(hostname);
+        Cluster cluster = clusterFsm.getCluster(alert.getCluster());
+        alertManager.add(cluster.getClusterId(), alert);
+      }
+    }
 
     for (Cluster cluster : clusterFsm.getClustersForHost(hostname)) {
       cluster.addAlerts(heartbeat.getNodeStatus().getAlerts());

http://git-wip-us.apache.org/repos/asf/ambari/blob/0de98b02/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 f2a5886..b43b5b1 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
@@ -239,6 +239,20 @@ public class AlertsDAO {
 
     return daoUtils.selectList(query);
   }
+  
+  @RequiresSession
+  public AlertCurrentEntity findCurrentByHostAndName(long clusterId, String hostName,
+      String alertName) {
+    
+    TypedQuery<AlertCurrentEntity> query = entityManagerProvider.get().createNamedQuery(
+        "AlertCurrentEntity.findByHostAndName", AlertCurrentEntity.class);
+
+    query.setParameter("clusterId", Long.valueOf(clusterId));
+    query.setParameter("hostName", hostName);
+    query.setParameter("definitionName", alertName);
+
+    return daoUtils.selectOne(query);
+  }
 
   /**
    * Removes alert history and current alerts for the specified alert defintiion

http://git-wip-us.apache.org/repos/asf/ambari/blob/0de98b02/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 cde61f2..31b1673 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
@@ -17,6 +17,7 @@
  */
 package org.apache.ambari.server.orm.entities;
 
+import javax.persistence.CascadeType;
 import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.EnumType;
@@ -48,6 +49,7 @@ import org.apache.ambari.server.state.MaintenanceState;
     @NamedQuery(name = "AlertCurrentEntity.findAll", query = "SELECT alert FROM AlertCurrentEntity alert"),
     @NamedQuery(name = "AlertCurrentEntity.findByService", query = "SELECT alert FROM AlertCurrentEntity alert JOIN alert.alertHistory history WHERE history.clusterId = :clusterId AND history.serviceName = :serviceName"),
     @NamedQuery(name = "AlertCurrentEntity.findByHost", query = "SELECT alert FROM AlertCurrentEntity alert JOIN alert.alertHistory history WHERE history.clusterId = :clusterId AND history.hostName = :hostName"),
+    @NamedQuery(name = "AlertCurrentEntity.findByHostAndName", query = "SELECT alert FROM AlertCurrentEntity alert JOIN alert.alertHistory history WHERE history.clusterId = :clusterId AND history.alertDefinition.definitionName = :definitionName AND history.hostName = :hostName"),
     @NamedQuery(name = "AlertCurrentEntity.removeByHistoryId", query = "DELETE FROM AlertCurrentEntity alert WHERE alert.alertHistory.alertId = :historyId"),
     @NamedQuery(name = "AlertCurrentEntity.removeByDefinitionId", query = "DELETE FROM AlertCurrentEntity alert WHERE alert.alertDefinition.definitionId = :definitionId") })
 public class AlertCurrentEntity {
@@ -70,7 +72,7 @@ public class AlertCurrentEntity {
   /**
    * Unidirectional one-to-one association to {@link AlertHistoryEntity}
    */
-  @OneToOne
+  @OneToOne(cascade = { CascadeType.PERSIST })
   @JoinColumn(name = "history_id", unique = true, nullable = false)
   private AlertHistoryEntity alertHistory;
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/0de98b02/ambari-server/src/main/java/org/apache/ambari/server/state/Alert.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/Alert.java b/ambari-server/src/main/java/org/apache/ambari/server/state/Alert.java
index e39b900..7b8aabd 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/Alert.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/Alert.java
@@ -22,6 +22,7 @@ import org.codehaus.jackson.annotate.JsonProperty;
  * An alert represents a problem or notice for a cluster.
  */
 public class Alert {
+  private String cluster = null;
   private String name = null;
   private String instance = null;
   private String service = null;
@@ -30,6 +31,7 @@ public class Alert {
   private AlertState state = AlertState.UNKNOWN;
   private String label = null;
   private String text = null;
+  private long timestamp = 0L;
   
  
   /**
@@ -162,7 +164,23 @@ public class Alert {
   public void setState(AlertState state) {
     this.state = state;
   }
-
+  
+  @JsonProperty("timestamp")
+  public void setTimestamp(long ts) {
+    timestamp = ts;
+  }
+  
+  @JsonProperty("timestamp")
+  public long getTimestamp() {
+    return timestamp;
+  }
+  
+  /**
+   * @return
+   */
+  public String getCluster() {
+    return cluster;
+  }
   
   @Override
   public int hashCode() {
@@ -224,6 +242,7 @@ public class Alert {
     sb.append('}');
     return sb.toString();
   }
+
   
 
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/0de98b02/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/AlertDataManager.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/AlertDataManager.java b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/AlertDataManager.java
new file mode 100644
index 0000000..4670d3b
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/AlertDataManager.java
@@ -0,0 +1,110 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state.cluster;
+
+import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
+import org.apache.ambari.server.orm.dao.AlertsDAO;
+import org.apache.ambari.server.orm.entities.AlertCurrentEntity;
+import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
+import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
+import org.apache.ambari.server.state.Alert;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+/**
+ * The AlertManager is reponsible for tracking all alerts generated for a cluster. 
+ */
+@Singleton
+public class AlertDataManager {
+
+  @Inject
+  private AlertsDAO m_alertsDao;
+  @Inject
+  private AlertDefinitionDAO m_definitionDao;
+
+  
+  AlertDataManager() {
+  }
+  
+  /**
+   * Adds an alert.  Checks for a new state before creating a new history record.
+   * 
+   * @param clusterId the id for the cluster
+   * @param alert the alert to add
+   */
+  public void add(long clusterId, Alert alert) {
+    
+    AlertCurrentEntity current = m_alertsDao.findCurrentByHostAndName(clusterId,
+        alert.getHost(), alert.getName());
+    
+    if (null == current) {
+      AlertDefinitionEntity definition = m_definitionDao.findByName(clusterId,
+          alert.getName());
+      
+      AlertHistoryEntity history = createHistory(clusterId, definition, alert);
+      
+      current = new AlertCurrentEntity();
+      current.setAlertHistory(history);
+      current.setLatestTimestamp(Long.valueOf(alert.getTimestamp()));
+      current.setOriginalTimestamp(Long.valueOf(alert.getTimestamp()));
+      
+      m_alertsDao.create(current);
+      
+    } else if (alert.getState() == current.getAlertHistory().getAlertState()) {
+      current.setLatestTimestamp(Long.valueOf(alert.getTimestamp()));
+      
+      m_alertsDao.merge(current);
+    } else {
+      // insert history, update current
+      AlertHistoryEntity history = createHistory(clusterId,
+          current.getAlertHistory().getAlertDefinition(), alert);
+      
+      current.setAlertHistory(history);
+      current.setLatestTimestamp(Long.valueOf(alert.getTimestamp()));
+      current.setOriginalTimestamp(Long.valueOf(alert.getTimestamp()));
+      
+      m_alertsDao.merge(current);
+    }
+    
+  }
+  /**
+   * Convenience to create a new alert.
+   * @param clusterId the cluster id
+   * @param definition the definition
+   * @param alert the alert data
+   * @return the new history record
+   */
+  private AlertHistoryEntity createHistory(long clusterId, AlertDefinitionEntity definition, Alert alert) {
+    AlertHistoryEntity history = new AlertHistoryEntity();
+    history.setAlertDefinition(definition);
+    history.setAlertInstance(alert.getInstance());
+    history.setAlertLabel(alert.getLabel());
+    history.setAlertState(alert.getState());
+    history.setAlertText(alert.getText());
+    history.setAlertTimestamp(Long.valueOf(alert.getTimestamp()));
+    history.setClusterId(Long.valueOf(clusterId));
+    history.setComponentName(alert.getComponent());
+    history.setHostName(alert.getHost());
+    history.setServiceName(alert.getService());
+    
+    return history;
+  }
+  
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/0de98b02/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
index a7cc066..b8af7c1 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
@@ -287,7 +287,7 @@ public class AlertDefinitionDAOTest {
     history.setAlertState(AlertState.OK);
     history.setAlertText("Alert Text");
     history.setAlertTimestamp(calendar.getTimeInMillis());
-    alertsDao.create(history);
+//    alertsDao.create(history);
 
     AlertCurrentEntity current = new AlertCurrentEntity();
     current.setAlertHistory(history);

http://git-wip-us.apache.org/repos/asf/ambari/blob/0de98b02/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 caeada1..4500c1c 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
@@ -21,6 +21,7 @@ package org.apache.ambari.server.orm.dao;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 
 import java.util.ArrayList;
 import java.util.Calendar;
@@ -104,6 +105,7 @@ public class AlertsDAOTest {
         history.setAlertLabel(definition.getDefinitionName() + " " + i);
         history.setAlertText(definition.getDefinitionName() + " " + i);
         history.setAlertTimestamp(calendar.getTimeInMillis());
+        history.setHostName("h1");
 
         history.setAlertState(AlertState.OK);
         if (i == 0 || i == 5) {
@@ -261,4 +263,16 @@ public class AlertsDAOTest {
     assertNotNull(history);
     assertEquals(0, history.size());
   }
+  
+  @Test
+  public void testFindCurrentByHostAndName() throws Exception {
+    AlertCurrentEntity entity = dao.findCurrentByHostAndName(clusterId.longValue(), "h2", "Alert Definition 1");
+    assertNull(entity);
+    
+    entity = dao.findCurrentByHostAndName(clusterId.longValue(), "h1", "Alert Definition 1");
+    
+    assertNotNull(entity);
+    assertNotNull(entity.getAlertHistory());
+    assertNotNull(entity.getAlertHistory().getAlertDefinition());
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/0de98b02/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java
new file mode 100644
index 0000000..eae1de6
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java
@@ -0,0 +1,181 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state.cluster;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.apache.ambari.server.orm.GuiceJpaInitializer;
+import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
+import org.apache.ambari.server.orm.OrmTestHelper;
+import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
+import org.apache.ambari.server.orm.dao.AlertsDAO;
+import org.apache.ambari.server.orm.entities.AlertCurrentEntity;
+import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
+import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
+import org.apache.ambari.server.state.Alert;
+import org.apache.ambari.server.state.AlertState;
+import org.apache.ambari.server.state.alert.Scope;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.persist.PersistService;
+
+/**
+ * Tests the alert manager.
+ */
+public class AlertDataManagerTest {
+  
+  private static final String ALERT_DEFINITION = "Alert Definition 1";
+  private static final String SERVICE = "service1";
+  private static final String COMPONENT = "component1";
+  private static final String HOST1 = "h1";
+  private static final String HOST2 = "h2";
+  private static final String ALERT_LABEL = "My Label";
+  
+  private Long clusterId;
+  private Injector injector;
+  private OrmTestHelper helper;
+  private AlertsDAO dao;
+  
+  @Before
+  public void setup() throws Exception {
+    injector = Guice.createInjector(new InMemoryDefaultTestModule());
+    injector.getInstance(GuiceJpaInitializer.class);
+    helper = injector.getInstance(OrmTestHelper.class);
+    clusterId = helper.createCluster();
+    dao = injector.getInstance(AlertsDAO.class);
+    AlertDefinitionDAO definitionDao = injector.getInstance(AlertDefinitionDAO.class);
+
+    // create 5 definitions
+    for (int i = 0; i < 5; i++) {
+      AlertDefinitionEntity definition = new AlertDefinitionEntity();
+      definition.setDefinitionName("Alert Definition " + i);
+      definition.setServiceName("Service " + i);
+      definition.setComponentName(null);
+      definition.setClusterId(clusterId);
+      definition.setHash(UUID.randomUUID().toString());
+      definition.setScheduleInterval(Integer.valueOf(60));
+      definition.setScope(Scope.SERVICE);
+      definition.setSource("Source " + i);
+      definition.setSourceType("SCRIPT");
+      definitionDao.create(definition);
+    }
+  
+  }
+  
+  @After
+  public void teardown() {
+    injector.getInstance(PersistService.class).stop();
+    injector = null;
+  }
+  
+  @Test
+  public void testAlertRecords() {
+    
+    Alert alert1 = new Alert(ALERT_DEFINITION, null, SERVICE, COMPONENT, HOST1, AlertState.OK);
+    alert1.setLabel(ALERT_LABEL);
+    alert1.setText("Component component1 is OK");
+    alert1.setTimestamp(1L);
+
+    Alert alert2 = new Alert(ALERT_DEFINITION, null, SERVICE, COMPONENT, HOST2, AlertState.CRITICAL);
+    alert2.setLabel(ALERT_LABEL);
+    alert2.setText("Component component2 is not OK");
+    
+    AlertDataManager am = injector.getInstance(AlertDataManager.class);
+    
+    am.add(clusterId.longValue(), alert1);
+    am.add(clusterId.longValue(), alert2);
+    
+    List<AlertCurrentEntity> allCurrent = dao.findCurrentByService(clusterId.longValue(), SERVICE);
+    assertEquals(2, allCurrent.size());
+    
+    List<AlertHistoryEntity> allHistory = dao.findAll(clusterId.longValue());
+    assertEquals(2, allHistory.size());
+    
+    AlertCurrentEntity current = dao.findCurrentByHostAndName(clusterId.longValue(), HOST1, ALERT_DEFINITION);
+    assertNotNull(current);
+    assertEquals(HOST1, current.getAlertHistory().getHostName());
+    assertEquals(ALERT_DEFINITION, current.getAlertHistory().getAlertDefinition().getDefinitionName());
+    assertEquals(ALERT_LABEL, current.getAlertHistory().getAlertLabel());
+    assertEquals("Component component1 is OK", current.getAlertHistory().getAlertText());
+    assertEquals(current.getAlertHistory().getAlertState(), AlertState.OK);
+    assertEquals(1L, current.getOriginalTimestamp().longValue());
+    assertEquals(1L, current.getLatestTimestamp().longValue());
+    
+    Long currentId = current.getAlertId();
+    Long historyId = current.getAlertHistory().getAlertId();
+    
+    // no new history since the state is the same
+    Alert alert3 = new Alert(ALERT_DEFINITION, null, SERVICE, COMPONENT, HOST1, AlertState.OK);
+    alert3.setLabel(ALERT_LABEL);
+    alert3.setText("Component component1 is OK");
+    alert3.setTimestamp(2L);
+    am.add(clusterId.longValue(), alert3);
+    
+    current = dao.findCurrentByHostAndName(clusterId.longValue(), HOST1, ALERT_DEFINITION);
+    assertNotNull(current);
+    assertEquals(currentId, current.getAlertId());
+    assertEquals(historyId, current.getAlertHistory().getAlertId());
+    assertEquals(HOST1, current.getAlertHistory().getHostName());
+    assertEquals(ALERT_DEFINITION, current.getAlertHistory().getAlertDefinition().getDefinitionName());
+    assertEquals(ALERT_LABEL, current.getAlertHistory().getAlertLabel());
+    assertEquals("Component component1 is OK", current.getAlertHistory().getAlertText());
+    assertEquals(current.getAlertHistory().getAlertState(), AlertState.OK);
+    assertEquals(1L, current.getOriginalTimestamp().longValue());
+    assertEquals(2L, current.getLatestTimestamp().longValue());
+   
+    allCurrent = dao.findCurrentByService(clusterId.longValue(), SERVICE);
+    assertEquals(2, allCurrent.size());
+    
+    allHistory = dao.findAll(clusterId.longValue());
+    assertEquals(2, allHistory.size());
+    
+    // change to warning
+    Alert alert4 = new Alert(ALERT_DEFINITION, null, SERVICE, COMPONENT, HOST1, AlertState.WARNING);
+    alert4.setLabel(ALERT_LABEL);
+    alert4.setText("Component component1 is about to go down");
+    alert4.setTimestamp(3L);
+    am.add(clusterId.longValue(), alert4);
+
+    current = dao.findCurrentByHostAndName(clusterId.longValue(), HOST1, ALERT_DEFINITION);
+    assertNotNull(current);
+    assertEquals(current.getAlertId(), currentId);
+    assertFalse(historyId.equals(current.getAlertHistory().getAlertId()));    
+    assertEquals(HOST1, current.getAlertHistory().getHostName());
+    assertEquals(ALERT_DEFINITION, current.getAlertHistory().getAlertDefinition().getDefinitionName());
+    assertEquals(ALERT_LABEL, current.getAlertHistory().getAlertLabel());
+    assertEquals("Component component1 is about to go down", current.getAlertHistory().getAlertText());
+    assertEquals(current.getAlertHistory().getAlertState(), AlertState.WARNING);
+    assertEquals(3L, current.getOriginalTimestamp().longValue());
+    assertEquals(3L, current.getLatestTimestamp().longValue());
+
+    allCurrent = dao.findCurrentByService(clusterId.longValue(), SERVICE);
+    assertEquals(2, allCurrent.size());
+    
+    allHistory = dao.findAll(clusterId.longValue());
+    assertEquals(3, allHistory.size());
+  }
+}


[30/50] [abbrv] git commit: Merge branch 'trunk' into branch-alerts-dev

Posted by jo...@apache.org.
Merge branch 'trunk' into branch-alerts-dev


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

Branch: refs/heads/trunk
Commit: e2e79668ed94266487fe9d1d2ccba2003922e883
Parents: 179290e d7ed431
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Fri Sep 19 13:18:45 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Fri Sep 19 13:18:45 2014 -0400

----------------------------------------------------------------------
 .../clusters/ClustersManageAccessCtrl.js        |    2 +-
 .../app/scripts/directives/editableList.js      |   18 +-
 .../resources/ui/admin-web/app/styles/main.css  |   14 +-
 .../app/views/directives/editableList.html      |    2 +-
 .../ui/admin-web/app/views/groups/list.html     |    2 +-
 .../ui/admin-web/app/views/leftNavbar.html      |    9 +-
 .../resources/ui/admin-web/app/views/main.html  |    3 +-
 .../ui/admin-web/app/views/users/list.html      |    2 +-
 .../test/python/ambari_agent/TestController.py  |    4 +-
 .../TestCustomServiceOrchestrator.py            |    3 +-
 .../resource_management/TestCopyFromLocal.py    |    8 +-
 .../TestExecuteHadoopResource.py                |   12 +-
 .../resource_management/TestExecuteResource.py  |    3 +-
 .../core/providers/system.py                    |   12 +-
 .../python/resource_management/core/shell.py    |   24 +-
 .../libraries/providers/copy_from_local.py      |    4 +
 .../libraries/providers/execute_hadoop.py       |    6 +-
 .../libraries/providers/hdfs_directory.py       |    6 +-
 .../libraries/resources/copy_from_local.py      |    1 +
 ambari-server/pom.xml                           |    8 +
 .../server/api/util/StackExtensionHelper.java   |  122 +-
 .../controller/MaintenanceStateHelper.java      |    2 +-
 .../server/upgrade/UpgradeCatalog170.java       |   43 +-
 .../src/main/resources/properties.json          |    1 +
 .../1.3.2/hooks/before-START/scripts/params.py  |    2 +-
 .../services/HIVE/configuration/hcat-env.xml    |   57 +
 .../stacks/HDP/1.3.2/services/HIVE/metainfo.xml |   19 +-
 .../1.3.2/services/HIVE/package/scripts/hcat.py |   13 +-
 .../services/HIVE/package/scripts/params.py     |    2 +
 .../HIVE/package/templates/hcat-env.sh.j2       |   44 -
 .../configuration/capacity-scheduler.xml        |    2 +-
 .../2.0.6/hooks/after-INSTALL/scripts/params.py |   11 +-
 .../scripts/shared_initialization.py            |    4 +
 .../2.0.6/hooks/before-START/scripts/params.py  |   13 +-
 .../services/FLUME/package/scripts/flume.py     |    2 +-
 .../services/FLUME/package/scripts/params.py    |    6 +-
 .../GANGLIA/configuration/ganglia-env.xml       |    2 +-
 .../services/GANGLIA/package/scripts/params.py  |    8 +-
 .../services/HBASE/package/scripts/params.py    |   16 +-
 .../services/HDFS/package/scripts/params.py     |   18 +-
 .../HDFS/package/scripts/service_check.py       |    2 +-
 .../services/HIVE/configuration/hcat-env.xml    |   57 +
 .../stacks/HDP/2.0.6/services/HIVE/metainfo.xml |   19 +-
 .../2.0.6/services/HIVE/package/scripts/hcat.py |   15 +-
 .../HIVE/package/scripts/hcat_service_check.py  |   10 +-
 .../HIVE/package/scripts/install_jars.py        |    2 +
 .../services/HIVE/package/scripts/params.py     |   71 +-
 .../services/HIVE/package/scripts/webhcat.py    |    4 +
 .../HIVE/package/templates/hcat-env.sh.j2       |   43 -
 .../services/PIG/package/scripts/params.py      |   12 +-
 .../2.0.6/services/PIG/package/scripts/pig.py   |    1 +
 .../services/SQOOP/package/scripts/params.py    |   11 +-
 .../YARN/configuration/capacity-scheduler.xml   |    2 +-
 .../package/scripts/mapred_service_check.py     |    4 +
 .../services/YARN/package/scripts/params.py     |   24 +-
 .../YARN/package/scripts/service_check.py       |    2 +-
 .../ZOOKEEPER/package/scripts/params.py         |    7 +-
 .../services/FALCON/package/scripts/params.py   |   12 +-
 .../services/STORM/package/scripts/params.py    |   11 +-
 .../stacks/HDP/2.2/services/FALCON/metainfo.xml |    2 +-
 .../stacks/HDP/2.2/services/FLUME/metainfo.xml  |    2 +-
 .../stacks/HDP/2.2/services/HBASE/metainfo.xml  |    2 +-
 .../services/HDFS/configuration/hadoop-env.xml  |    2 +-
 .../services/HDFS/configuration/hdfs-site.xml   |   34 -
 .../stacks/HDP/2.2/services/HDFS/metainfo.xml   |    4 +-
 .../HIVE/configuration/webhcat-site.xml         |   14 +-
 .../stacks/HDP/2.2/services/HIVE/metainfo.xml   |    6 +-
 .../services/OOZIE/configuration/oozie-site.xml |   13 -
 .../stacks/HDP/2.2/services/OOZIE/metainfo.xml  |    6 +-
 .../stacks/HDP/2.2/services/PIG/metainfo.xml    |    2 +-
 .../services/SLIDER/package/scripts/params.py   |    4 +-
 .../stacks/HDP/2.2/services/SQOOP/metainfo.xml  |    2 +-
 .../services/STORM/configuration/storm-env.xml  |   29 -
 .../services/STORM/configuration/storm-site.xml |    6 +-
 .../stacks/HDP/2.2/services/STORM/metainfo.xml  |    2 +-
 .../stacks/HDP/2.2/services/TEZ/metainfo.xml    |    2 +-
 .../HDP/2.2/services/WEBHCAT/metainfo.xml       |   43 -
 .../YARN/configuration-mapred/mapred-site.xml   |   11 +-
 .../services/YARN/configuration/yarn-site.xml   |   11 +-
 .../stacks/HDP/2.2/services/YARN/metainfo.xml   |    6 +-
 .../HDP/2.2/services/ZOOKEEPER/metainfo.xml     |    2 +-
 .../api/util/StackExtensionHelperTest.java      |   40 +-
 .../stacks/1.3.2/HDFS/test_service_check.py     |    2 +-
 .../stacks/1.3.2/HIVE/test_hcat_client.py       |   20 +-
 .../python/stacks/1.3.2/configs/default.json    |    5 +-
 .../python/stacks/1.3.2/configs/secured.json    |    5 +-
 .../python/stacks/2.0.6/FLUME/test_flume.py     |    4 +-
 .../stacks/2.0.6/HDFS/test_service_check.py     |    2 +-
 .../stacks/2.0.6/HIVE/test_hcat_client.py       |   22 +-
 .../stacks/2.0.6/HIVE/test_hive_metastore.py    |    9 +-
 .../stacks/2.0.6/HIVE/test_hive_server.py       |   12 +-
 .../2.0.6/HIVE/test_hive_service_check.py       |   17 +-
 .../stacks/2.0.6/HIVE/test_webhcat_server.py    |    8 +
 .../python/stacks/2.0.6/PIG/test_pig_client.py  |    2 +
 .../2.0.6/YARN/test_mapreduce2_service_check.py |    8 +
 .../2.0.6/YARN/test_yarn_service_check.py       |    4 +-
 .../python/stacks/2.0.6/configs/default.json    |    5 +-
 .../python/stacks/2.0.6/configs/secured.json    |    5 +-
 .../stacks/2.1/HIVE/test_hive_metastore.py      |    8 +-
 .../services/YARN/configuration/yarn-site.xml   |    2 +-
 ambari-web/app/data/HDP2/site_properties.js     |   24 +
 ambari-web/app/data/site_properties.js          |   24 +
 ambari-web/app/messages.js                      |    1 +
 ambari-web/app/mixins/common/serverValidator.js |   11 +-
 ambari-web/app/models/service_config_version.js |    7 +-
 ambari-web/app/styles/application.less          |   51 +-
 .../common/configs/config_history_flow.hbs      |   20 +-
 .../common/configs/service_version_box.hbs      |   17 +-
 .../templates/main/dashboard/config_history.hbs |    6 +-
 ambari-web/app/utils/config.js                  |    2 +-
 .../views/common/configs/config_history_flow.js |   19 +-
 ambari-web/app/views/common/filter_view.js      |    8 +-
 .../views/main/dashboard/config_history_view.js |    4 +-
 contrib/views/slider/pom.xml                    |    9 +-
 .../ambari/view/slider/GangliaMetric.java       |  257 +++
 .../ambari/view/slider/MetricsHolder.java       |   44 +
 .../apache/ambari/view/slider/SliderApp.java    |   16 +-
 .../ambari/view/slider/SliderAppType.java       |   32 +-
 .../slider/SliderAppsViewControllerImpl.java    |   87 +-
 .../apache/ambari/view/slider/TemporalInfo.java |   48 +
 .../rest/client/SliderAppGangliaHelper.java     |  196 +++
 .../rest/client/SliderAppMasterClient.java      |  127 +-
 .../app/assets/data/resource/cluster_name.json  |   12 -
 .../assets/data/resource/components_hosts.json  |   16 -
 .../ui/app/assets/data/resource/empty_json.json |    1 +
 .../assets/data/resource/service_configs.json   |   38 -
 .../assets/data/resource/service_status.json    |   95 --
 .../assets/data/resource/slider-properties.json |    7 +-
 .../ui-bg_flat_0_aaaaaa_40x100.png              |  Bin 0 -> 180 bytes
 .../ui-bg_glass_55_fbf9ee_1x400.png             |  Bin 0 -> 120 bytes
 .../ui-bg_glass_65_ffffff_1x400.png             |  Bin 0 -> 105 bytes
 .../ui-bg_glass_75_dadada_1x400.png             |  Bin 0 -> 111 bytes
 .../ui-bg_glass_75_e6e6e6_1x400.png             |  Bin 0 -> 110 bytes
 .../ui-bg_glass_75_ffffff_1x400.png             |  Bin 0 -> 107 bytes
 .../ui-bg_highlight-soft_75_cccccc_1x100.png    |  Bin 0 -> 101 bytes
 .../ui-bg_inset-soft_95_fef1ec_1x100.png        |  Bin 0 -> 123 bytes
 .../ui-icons_222222_256x240.png                 |  Bin 0 -> 4369 bytes
 .../ui-icons_2e83ff_256x240.png                 |  Bin 0 -> 4369 bytes
 .../ui-icons_454545_256x240.png                 |  Bin 0 -> 4369 bytes
 .../ui-icons_888888_256x240.png                 |  Bin 0 -> 4369 bytes
 .../ui-icons_cd0a0a_256x240.png                 |  Bin 0 -> 4369 bytes
 .../ui-icons_f6cf3b_256x240.png                 |  Bin 0 -> 8884 bytes
 .../createAppWizard/step1_controller.js         |   90 +-
 .../createAppWizard/step4_controller.js         |   10 +-
 .../ui/app/controllers/slider_app_controller.js |   35 +-
 .../ui/app/controllers/slider_controller.js     |  305 +---
 .../src/main/resources/ui/app/helpers/ajax.js   |  133 +-
 .../src/main/resources/ui/app/initialize.js     |   11 +-
 .../ui/app/mappers/application_type.js          |    2 +-
 .../ui/app/mappers/slider_apps_mapper.js        |   41 +-
 .../ui/app/mixins/ajax_error_handler.js         |   84 +
 .../main/resources/ui/app/models/slider_app.js  |    5 +
 .../resources/ui/app/models/slider_config.js    |   51 +
 .../src/main/resources/ui/app/routes/main.js    |   16 +
 .../resources/ui/app/styles/application.less    |   80 +-
 .../resources/ui/app/templates/application.hbs  |   17 +-
 .../ui/app/templates/common/ajax_error.hbs      |   24 +
 .../resources/ui/app/templates/slider_app.hbs   |   26 +-
 .../ui/app/templates/slider_app/configs.hbs     |    2 +-
 .../resources/ui/app/templates/slider_apps.hbs  |   10 +-
 .../ui/app/templates/slider_title_tooltip.hbs   |    6 +-
 .../src/main/resources/ui/app/translations.js   |   22 +-
 .../resources/ui/app/views/application_view.js  |   18 +-
 .../views/slider_app/metrics/app_metric_view.js |   71 +
 .../ui/app/views/slider_app/summary_view.js     |   71 +-
 .../slider/src/main/resources/ui/config.js      |    1 +
 .../resources/ui/vendor/scripts/common/tv4.js   | 1605 ++++++++++++++++++
 .../views/slider/src/main/resources/view.xml    |   21 +-
 168 files changed, 3721 insertions(+), 1439 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/e2e79668/ambari-agent/src/test/python/ambari_agent/TestController.py
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/e2e79668/ambari-server/pom.xml
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/e2e79668/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/e2e79668/ambari-server/src/main/resources/properties.json
----------------------------------------------------------------------


[13/50] [abbrv] git commit: Merge branch 'trunk' into branch-alerts-dev

Posted by jo...@apache.org.
Merge branch 'trunk' into branch-alerts-dev


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

Branch: refs/heads/trunk
Commit: 91ae5f27e98ec4d81c7299480b8adb3619e31c5b
Parents: 0de98b0 ad983de
Author: Nate Cole <nc...@hortonworks.com>
Authored: Thu Sep 4 18:35:01 2014 -0400
Committer: Nate Cole <nc...@hortonworks.com>
Committed: Thu Sep 4 18:35:01 2014 -0400

----------------------------------------------------------------------
 .../src/main/resources/ui/admin-web/gulpfile.js |   51 -
 .../main/resources/ui/admin-web/package.json    |    9 -
 ambari-agent/pom.xml                            |   12 +-
 .../src/main/python/ambari_agent/HostInfo.py    |    2 +-
 .../test/python/ambari_agent/TestHardware.py    |    4 +-
 .../resource_management/TestContentSources.py   |    2 +-
 .../resource_management/TestPackageResource.py  |    8 +-
 .../TestRepositoryResource.py                   |   16 +-
 .../src/main/python/ambari_commons/os_check.py  |    8 +-
 .../src/main/python/ambari_jinja2/AUTHORS       |   31 +
 .../src/main/python/ambari_jinja2/CHANGES       |  235 +++
 .../src/main/python/ambari_jinja2/LICENSE       |   31 +
 .../src/main/python/ambari_jinja2/MANIFEST.in   |   12 +
 .../src/main/python/ambari_jinja2/Makefile      |    4 +
 .../ambari_jinja2/ambari_jinja2/__init__.py     |   73 +
 .../ambari_jinja2/ambari_jinja2/_debugsupport.c |   78 +
 .../ambari_jinja2/_markupsafe/__init__.py       |  225 +++
 .../ambari_jinja2/_markupsafe/_bundle.py        |   49 +
 .../ambari_jinja2/_markupsafe/_constants.py     |  267 +++
 .../ambari_jinja2/_markupsafe/_native.py        |   45 +
 .../ambari_jinja2/_markupsafe/tests.py          |   80 +
 .../ambari_jinja2/ambari_jinja2/_stringdefs.py  |  130 ++
 .../ambari_jinja2/ambari_jinja2/bccache.py      |  280 +++
 .../ambari_jinja2/ambari_jinja2/compiler.py     | 1640 ++++++++++++++++++
 .../ambari_jinja2/ambari_jinja2/constants.py    |   32 +
 .../python/ambari_jinja2/ambari_jinja2/debug.py |  308 ++++
 .../ambari_jinja2/ambari_jinja2/defaults.py     |   40 +
 .../ambari_jinja2/ambari_jinja2/environment.py  | 1118 ++++++++++++
 .../ambari_jinja2/ambari_jinja2/exceptions.py   |  143 ++
 .../python/ambari_jinja2/ambari_jinja2/ext.py   |  610 +++++++
 .../ambari_jinja2/ambari_jinja2/filters.py      |  719 ++++++++
 .../python/ambari_jinja2/ambari_jinja2/lexer.py |  681 ++++++++
 .../ambari_jinja2/ambari_jinja2/loaders.py      |  449 +++++
 .../python/ambari_jinja2/ambari_jinja2/meta.py  |  102 ++
 .../python/ambari_jinja2/ambari_jinja2/nodes.py |  901 ++++++++++
 .../ambari_jinja2/ambari_jinja2/optimizer.py    |   68 +
 .../ambari_jinja2/ambari_jinja2/parser.py       |  896 ++++++++++
 .../ambari_jinja2/ambari_jinja2/runtime.py      |  544 ++++++
 .../ambari_jinja2/ambari_jinja2/sandbox.py      |  271 +++
 .../python/ambari_jinja2/ambari_jinja2/tests.py |  146 ++
 .../ambari_jinja2/testsuite/__init__.py         |   95 +
 .../ambari_jinja2/testsuite/api.py              |  240 +++
 .../ambari_jinja2/testsuite/core_tags.py        |  286 +++
 .../ambari_jinja2/testsuite/debug.py            |   60 +
 .../ambari_jinja2/testsuite/doctests.py         |   29 +
 .../ambari_jinja2/testsuite/ext.py              |  455 +++++
 .../ambari_jinja2/testsuite/filters.py          |  291 ++++
 .../ambari_jinja2/testsuite/imports.py          |  144 ++
 .../ambari_jinja2/testsuite/inheritance.py      |  208 +++
 .../ambari_jinja2/testsuite/lexnparse.py        |  390 +++++
 .../ambari_jinja2/testsuite/loader.py           |  191 ++
 .../ambari_jinja2/testsuite/regression.py       |  258 +++
 .../testsuite/res/templates/broken.html         |    3 +
 .../testsuite/res/templates/foo/test.html       |    1 +
 .../testsuite/res/templates/syntaxerror.html    |    4 +
 .../testsuite/res/templates/test.html           |    1 +
 .../ambari_jinja2/testsuite/security.py         |  134 ++
 .../ambari_jinja2/testsuite/tests.py            |   87 +
 .../ambari_jinja2/testsuite/utils.py            |   85 +
 .../python/ambari_jinja2/ambari_jinja2/utils.py |  601 +++++++
 .../ambari_jinja2/ambari_jinja2/visitor.py      |   87 +
 .../python/ambari_jinja2/artwork/jinjalogo.svg  |  132 ++
 .../custom_fixers/fix_alt_unicode.py            |   13 +
 .../custom_fixers/fix_broken_reraising.py       |   21 +
 .../ambari_jinja2/custom_fixers/fix_xrange2.py  |   11 +
 .../src/main/python/ambari_jinja2/docs/Makefile |   75 +
 .../python/ambari_jinja2/docs/_static/jinja.js  |   26 +
 .../python/ambari_jinja2/docs/_static/print.css |    5 +
 .../python/ambari_jinja2/docs/_static/style.css |  390 +++++
 .../ambari_jinja2/docs/_templates/genindex.html |   36 +
 .../ambari_jinja2/docs/_templates/layout.html   |   77 +
 .../docs/_templates/opensearch.xml              |    9 +
 .../ambari_jinja2/docs/_templates/page.html     |    4 +
 .../ambari_jinja2/docs/_templates/search.html   |   35 +
 .../src/main/python/ambari_jinja2/docs/api.rst  |  787 +++++++++
 .../ambari_jinja2/docs/cache_extension.py       |   56 +
 .../python/ambari_jinja2/docs/changelog.rst     |    3 +
 .../src/main/python/ambari_jinja2/docs/conf.py  |  141 ++
 .../python/ambari_jinja2/docs/extensions.rst    |  347 ++++
 .../src/main/python/ambari_jinja2/docs/faq.rst  |  191 ++
 .../main/python/ambari_jinja2/docs/index.rst    |   27 +
 .../python/ambari_jinja2/docs/integration.rst   |   88 +
 .../main/python/ambari_jinja2/docs/intro.rst    |  168 ++
 .../main/python/ambari_jinja2/docs/jinjaext.py  |  192 ++
 .../main/python/ambari_jinja2/docs/sandbox.rst  |   46 +
 .../python/ambari_jinja2/docs/switching.rst     |  242 +++
 .../python/ambari_jinja2/docs/templates.rst     | 1365 +++++++++++++++
 .../main/python/ambari_jinja2/docs/tricks.rst   |  100 ++
 .../ambari_jinja2/examples/basic/cycle.py       |   13 +
 .../ambari_jinja2/examples/basic/debugger.py    |    7 +
 .../ambari_jinja2/examples/basic/inheritance.py |   12 +
 .../examples/basic/templates/broken.html        |    6 +
 .../examples/basic/templates/subbroken.html     |    3 +
 .../python/ambari_jinja2/examples/basic/test.py |   27 +
 .../basic/test_filter_and_linestatements.py     |   25 +
 .../examples/basic/test_loop_filter.py          |   12 +
 .../ambari_jinja2/examples/basic/translate.py   |    6 +
 .../main/python/ambari_jinja2/examples/bench.py |  433 +++++
 .../python/ambari_jinja2/examples/profile.py    |   52 +
 .../examples/rwbench/django/_form.html          |    1 +
 .../examples/rwbench/django/_input_field.html   |    1 +
 .../examples/rwbench/django/_textarea.html      |    1 +
 .../examples/rwbench/django/index.html          |   29 +
 .../examples/rwbench/django/layout.html         |   29 +
 .../ambari_jinja2/examples/rwbench/djangoext.py |  135 ++
 .../examples/rwbench/genshi/helpers.html        |   12 +
 .../examples/rwbench/genshi/index.html          |   41 +
 .../examples/rwbench/genshi/layout.html         |   30 +
 .../examples/rwbench/jinja/helpers.html         |   12 +
 .../examples/rwbench/jinja/index.html           |   29 +
 .../examples/rwbench/jinja/layout.html          |   29 +
 .../examples/rwbench/mako/helpers.html          |   11 +
 .../examples/rwbench/mako/index.html            |   31 +
 .../examples/rwbench/mako/layout.html           |   30 +
 .../ambari_jinja2/examples/rwbench/rwbench.py   |  112 ++
 .../python/ambari_jinja2/ext/Vim/htmljinja.vim  |   27 +
 .../main/python/ambari_jinja2/ext/Vim/jinja.vim |  113 ++
 .../ext/django2jinja/django2jinja.py            |  768 ++++++++
 .../ambari_jinja2/ext/django2jinja/example.py   |    7 +
 .../ext/django2jinja/templates/index.html       |   58 +
 .../ext/django2jinja/templates/layout.html      |    4 +
 .../ext/django2jinja/templates/subtemplate.html |    1 +
 .../python/ambari_jinja2/ext/djangojinja2.py    |   86 +
 .../python/ambari_jinja2/ext/inlinegettext.py   |   78 +
 .../src/main/python/ambari_jinja2/ext/jinja.el  |  213 +++
 .../main/python/ambari_jinja2/jinja2-debug.py   |   40 +
 .../main/python/ambari_jinja2/scripts/pylintrc  |  301 ++++
 .../src/main/python/ambari_jinja2/setup.cfg     |    6 +
 .../src/main/python/ambari_jinja2/setup.py      |  110 ++
 ambari-common/src/main/python/jinja2/AUTHORS    |   31 -
 ambari-common/src/main/python/jinja2/CHANGES    |  235 ---
 ambari-common/src/main/python/jinja2/LICENSE    |   31 -
 .../src/main/python/jinja2/MANIFEST.in          |   12 -
 ambari-common/src/main/python/jinja2/Makefile   |    4 -
 .../main/python/jinja2/artwork/jinjalogo.svg    |  132 --
 .../python/jinja2/custom_fixers/__init__.py     |    0
 .../jinja2/custom_fixers/fix_alt_unicode.py     |   13 -
 .../custom_fixers/fix_broken_reraising.py       |   21 -
 .../python/jinja2/custom_fixers/fix_xrange2.py  |   11 -
 .../src/main/python/jinja2/docs/Makefile        |   75 -
 .../src/main/python/jinja2/docs/_build/.ignore  |    0
 .../src/main/python/jinja2/docs/_static/.ignore |    0
 .../main/python/jinja2/docs/_static/jinja.js    |   26 -
 .../main/python/jinja2/docs/_static/print.css   |    5 -
 .../main/python/jinja2/docs/_static/style.css   |  390 -----
 .../main/python/jinja2/docs/_templates/.ignore  |    0
 .../python/jinja2/docs/_templates/genindex.html |   36 -
 .../python/jinja2/docs/_templates/layout.html   |   77 -
 .../jinja2/docs/_templates/opensearch.xml       |    9 -
 .../python/jinja2/docs/_templates/page.html     |    4 -
 .../python/jinja2/docs/_templates/search.html   |   35 -
 .../src/main/python/jinja2/docs/api.rst         |  787 ---------
 .../main/python/jinja2/docs/cache_extension.py  |   56 -
 .../src/main/python/jinja2/docs/changelog.rst   |    3 -
 .../src/main/python/jinja2/docs/conf.py         |  141 --
 .../src/main/python/jinja2/docs/extensions.rst  |  347 ----
 .../src/main/python/jinja2/docs/faq.rst         |  191 --
 .../src/main/python/jinja2/docs/index.rst       |   27 -
 .../src/main/python/jinja2/docs/integration.rst |   88 -
 .../src/main/python/jinja2/docs/intro.rst       |  168 --
 .../src/main/python/jinja2/docs/jinjaext.py     |  192 --
 .../src/main/python/jinja2/docs/sandbox.rst     |   46 -
 .../src/main/python/jinja2/docs/switching.rst   |  242 ---
 .../src/main/python/jinja2/docs/templates.rst   | 1365 ---------------
 .../src/main/python/jinja2/docs/tricks.rst      |  100 --
 .../main/python/jinja2/examples/basic/cycle.py  |   13 -
 .../python/jinja2/examples/basic/debugger.py    |    7 -
 .../python/jinja2/examples/basic/inheritance.py |   12 -
 .../jinja2/examples/basic/templates/broken.html |    6 -
 .../examples/basic/templates/subbroken.html     |    3 -
 .../main/python/jinja2/examples/basic/test.py   |   27 -
 .../basic/test_filter_and_linestatements.py     |   25 -
 .../jinja2/examples/basic/test_loop_filter.py   |   12 -
 .../python/jinja2/examples/basic/translate.py   |    6 -
 .../src/main/python/jinja2/examples/bench.py    |  433 -----
 .../src/main/python/jinja2/examples/profile.py  |   52 -
 .../jinja2/examples/rwbench/django/_form.html   |    1 -
 .../examples/rwbench/django/_input_field.html   |    1 -
 .../examples/rwbench/django/_textarea.html      |    1 -
 .../jinja2/examples/rwbench/django/index.html   |   29 -
 .../jinja2/examples/rwbench/django/layout.html  |   29 -
 .../python/jinja2/examples/rwbench/djangoext.py |  135 --
 .../jinja2/examples/rwbench/genshi/helpers.html |   12 -
 .../jinja2/examples/rwbench/genshi/index.html   |   41 -
 .../jinja2/examples/rwbench/genshi/layout.html  |   30 -
 .../jinja2/examples/rwbench/jinja/helpers.html  |   12 -
 .../jinja2/examples/rwbench/jinja/index.html    |   29 -
 .../jinja2/examples/rwbench/jinja/layout.html   |   29 -
 .../jinja2/examples/rwbench/mako/helpers.html   |   11 -
 .../jinja2/examples/rwbench/mako/index.html     |   31 -
 .../jinja2/examples/rwbench/mako/layout.html    |   30 -
 .../python/jinja2/examples/rwbench/rwbench.py   |  112 --
 .../main/python/jinja2/ext/Vim/htmljinja.vim    |   27 -
 .../src/main/python/jinja2/ext/Vim/jinja.vim    |  113 --
 .../jinja2/ext/django2jinja/django2jinja.py     |  768 --------
 .../python/jinja2/ext/django2jinja/example.py   |    7 -
 .../ext/django2jinja/templates/index.html       |   58 -
 .../ext/django2jinja/templates/layout.html      |    4 -
 .../ext/django2jinja/templates/subtemplate.html |    1 -
 .../src/main/python/jinja2/ext/djangojinja2.py  |   86 -
 .../src/main/python/jinja2/ext/inlinegettext.py |   78 -
 .../src/main/python/jinja2/ext/jinja.el         |  213 ---
 .../src/main/python/jinja2/jinja2-debug.py      |   40 -
 .../src/main/python/jinja2/jinja2/__init__.py   |   73 -
 .../main/python/jinja2/jinja2/_debugsupport.c   |   78 -
 .../jinja2/jinja2/_markupsafe/__init__.py       |  225 ---
 .../python/jinja2/jinja2/_markupsafe/_bundle.py |   49 -
 .../jinja2/jinja2/_markupsafe/_constants.py     |  267 ---
 .../python/jinja2/jinja2/_markupsafe/_native.py |   45 -
 .../python/jinja2/jinja2/_markupsafe/tests.py   |   80 -
 .../main/python/jinja2/jinja2/_stringdefs.py    |  130 --
 .../src/main/python/jinja2/jinja2/bccache.py    |  280 ---
 .../src/main/python/jinja2/jinja2/compiler.py   | 1640 ------------------
 .../src/main/python/jinja2/jinja2/constants.py  |   32 -
 .../src/main/python/jinja2/jinja2/debug.py      |  308 ----
 .../src/main/python/jinja2/jinja2/defaults.py   |   40 -
 .../main/python/jinja2/jinja2/environment.py    | 1118 ------------
 .../src/main/python/jinja2/jinja2/exceptions.py |  143 --
 .../src/main/python/jinja2/jinja2/ext.py        |  610 -------
 .../src/main/python/jinja2/jinja2/filters.py    |  719 --------
 .../src/main/python/jinja2/jinja2/lexer.py      |  681 --------
 .../src/main/python/jinja2/jinja2/loaders.py    |  449 -----
 .../src/main/python/jinja2/jinja2/meta.py       |  102 --
 .../src/main/python/jinja2/jinja2/nodes.py      |  901 ----------
 .../src/main/python/jinja2/jinja2/optimizer.py  |   68 -
 .../src/main/python/jinja2/jinja2/parser.py     |  896 ----------
 .../src/main/python/jinja2/jinja2/runtime.py    |  544 ------
 .../src/main/python/jinja2/jinja2/sandbox.py    |  271 ---
 .../src/main/python/jinja2/jinja2/tests.py      |  146 --
 .../python/jinja2/jinja2/testsuite/__init__.py  |   95 -
 .../main/python/jinja2/jinja2/testsuite/api.py  |  240 ---
 .../python/jinja2/jinja2/testsuite/core_tags.py |  286 ---
 .../python/jinja2/jinja2/testsuite/debug.py     |   60 -
 .../python/jinja2/jinja2/testsuite/doctests.py  |   29 -
 .../main/python/jinja2/jinja2/testsuite/ext.py  |  455 -----
 .../python/jinja2/jinja2/testsuite/filters.py   |  291 ----
 .../python/jinja2/jinja2/testsuite/imports.py   |  144 --
 .../jinja2/jinja2/testsuite/inheritance.py      |  208 ---
 .../python/jinja2/jinja2/testsuite/lexnparse.py |  390 -----
 .../python/jinja2/jinja2/testsuite/loader.py    |  191 --
 .../jinja2/jinja2/testsuite/regression.py       |  258 ---
 .../jinja2/jinja2/testsuite/res/__init__.py     |    0
 .../jinja2/testsuite/res/templates/broken.html  |    3 -
 .../testsuite/res/templates/foo/test.html       |    1 -
 .../testsuite/res/templates/syntaxerror.html    |    4 -
 .../jinja2/testsuite/res/templates/test.html    |    1 -
 .../python/jinja2/jinja2/testsuite/security.py  |  134 --
 .../python/jinja2/jinja2/testsuite/tests.py     |   87 -
 .../python/jinja2/jinja2/testsuite/utils.py     |   85 -
 .../src/main/python/jinja2/jinja2/utils.py      |  601 -------
 .../src/main/python/jinja2/jinja2/visitor.py    |   87 -
 .../src/main/python/jinja2/scripts/pylintrc     |  301 ----
 ambari-common/src/main/python/jinja2/setup.cfg  |    6 -
 ambari-common/src/main/python/jinja2/setup.py   |  110 --
 .../core/providers/__init__.py                  |    2 +-
 .../python/resource_management/core/source.py   |    2 +-
 .../python/resource_management/core/system.py   |    4 +-
 .../libraries/providers/__init__.py             |    4 +-
 .../libraries/providers/monitor_webserver.py    |    2 +-
 .../libraries/providers/repository.py           |    2 +-
 ambari-server/pom.xml                           |    4 +-
 .../server/api/services/AmbariMetaInfo.java     |    2 +-
 .../server/configuration/Configuration.java     |    8 +-
 .../apache/ambari/server/orm/dao/GroupDAO.java  |    1 +
 .../apache/ambari/server/orm/dao/UserDAO.java   |    1 +
 .../authorization/AmbariLdapDataPopulator.java  |    5 +-
 .../org/apache/ambari/server/state/Host.java    |    2 +-
 .../server/state/stack/LatestRepoCallable.java  |    2 +-
 .../ambari/server/state/stack/OsFamily.java     |    6 +-
 .../server/upgrade/UpgradeCatalog161.java       |   22 +
 ambari-server/src/main/python/ambari-server.py  |    2 +
 .../src/main/python/ambari_server/utils.py      |   12 +-
 ambari-server/src/main/python/bootstrap.py      |   14 +-
 ambari-server/src/main/python/setupAgent.py     |    8 +-
 ambari-server/src/main/resources/os_family.json |    2 +-
 .../main/resources/scripts/kerberos-setup.sh    |    4 +-
 .../src/main/resources/scripts/stack_advisor.py |   19 +-
 .../scripts/repo_initialization.py              |    2 +-
 .../before-INSTALL/templates/repo_debian.j2     |    1 -
 .../before-INSTALL/templates/repo_ubuntu.j2     |    1 +
 .../HBASE/package/scripts/hbase_decommission.py |   62 +-
 .../services/HBASE/package/scripts/params.py    |    1 +
 .../stacks/HDP/1.3.2/services/stack_advisor.py  |  377 +---
 .../stacks/HDP/1.3.3/services/stack_advisor.py  |    4 -
 .../stacks/HDP/1.3/services/stack_advisor.py    |    4 -
 .../scripts/repo_initialization.py              |    2 +-
 .../before-INSTALL/templates/repo_debian.j2     |    1 -
 .../before-INSTALL/templates/repo_ubuntu.j2     |    1 +
 .../HDP/2.0.6/services/GANGLIA/metainfo.xml     |    2 +-
 .../GANGLIA/package/scripts/functions.py        |    4 +-
 .../GANGLIA/package/scripts/ganglia_server.py   |    2 +-
 .../services/GANGLIA/package/scripts/params.py  |    4 +-
 .../HBASE/package/scripts/hbase_decommission.py |   62 +-
 .../services/HBASE/package/scripts/params.py    |    1 +
 .../stacks/HDP/2.0.6/services/HDFS/metainfo.xml |    2 +-
 .../stacks/HDP/2.0.6/services/HIVE/metainfo.xml |    2 +-
 .../services/HIVE/package/scripts/params.py     |    2 +-
 .../HIVE/package/scripts/status_params.py       |    2 +-
 .../HDP/2.0.6/services/NAGIOS/metainfo.xml      |    2 +-
 .../services/NAGIOS/package/scripts/nagios.py   |    8 +-
 .../services/NAGIOS/package/scripts/params.py   |   10 +-
 .../NAGIOS/package/templates/nagios.conf.j2     |    2 +-
 .../HDP/2.0.6/services/OOZIE/metainfo.xml       |    2 +-
 .../services/OOZIE/package/files/oozieSmoke2.sh |    2 +-
 .../stacks/HDP/2.0.6/services/stack_advisor.py  |  316 +---
 .../2.1.GlusterFS/services/FLUME/metainfo.xml   |   31 +
 .../2.1.GlusterFS/services/HBASE/metainfo.xml   |    5 +
 .../2.1.GlusterFS/services/OOZIE/metainfo.xml   |    4 +-
 .../2.1.GlusterFS/services/SQOOP/metainfo.xml   |    3 +
 .../2.1.GlusterFS/services/YARN/metainfo.xml    |   10 +-
 .../resources/stacks/HDP/2.1/repos/repoinfo.xml |    2 +-
 .../stacks/HDP/2.1/services/OOZIE/metainfo.xml  |    2 +-
 .../stacks/HDP/2.1/services/SQOOP/metainfo.xml  |    4 -
 .../stacks/HDP/2.1/services/stack_advisor.py    |   64 +-
 .../resources/stacks/HDP/2.2.1/metainfo.xml     |   23 +
 .../stacks/HDP/2.2.1/repos/repoinfo.xml         |   67 +
 .../stacks/HDP/2.2.1/role_command_order.json    |   85 +
 .../HDP/2.2.1/services/FALCON/metainfo.xml      |   26 +
 .../HDP/2.2.1/services/FLUME/metainfo.xml       |   26 +
 .../HDP/2.2.1/services/HBASE/metainfo.xml       |   26 +
 .../stacks/HDP/2.2.1/services/HDFS/metainfo.xml |   27 +
 .../stacks/HDP/2.2.1/services/HIVE/metainfo.xml |   31 +
 .../HDP/2.2.1/services/OOZIE/metainfo.xml       |   26 +
 .../stacks/HDP/2.2.1/services/PIG/metainfo.xml  |   26 +
 .../HDP/2.2.1/services/SQOOP/metainfo.xml       |   26 +
 .../HDP/2.2.1/services/STORM/metainfo.xml       |   27 +
 .../stacks/HDP/2.2.1/services/TEZ/metainfo.xml  |   26 +
 .../HDP/2.2.1/services/WEBHCAT/metainfo.xml     |   26 +
 .../stacks/HDP/2.2.1/services/YARN/metainfo.xml |   31 +
 .../HDP/2.2.1/services/ZOOKEEPER/metainfo.xml   |   26 +
 .../src/main/resources/stacks/stack_advisor.py  |  271 +++
 .../server/api/services/AmbariMetaInfoTest.java |    1 -
 .../AmbariManagementControllerTest.java         |    4 +-
 .../AmbariLdapDataPopulatorTest.java            |   22 +-
 .../server/upgrade/UpgradeCatalog161Test.java   |   24 +
 .../src/test/python/TestAmbariServer.py         |   11 +-
 ambari-server/src/test/python/TestBootstrap.py  |    6 +-
 ambari-server/src/test/python/TestOSCheck.py    |   12 +-
 ambari-server/src/test/python/TestSetupAgent.py |   64 +-
 .../src/test/python/TestStackAdvisor.py         |  323 +++-
 ambari-server/src/test/python/TestUtils.py      |    6 +-
 .../stacks/1.3.2/HBASE/test_hbase_master.py     |    6 +-
 .../python/stacks/1.3.2/configs/default.json    |    4 +-
 .../hooks/before-INSTALL/test_before_install.py |   83 +-
 .../stacks/2.0.6/HBASE/test_hbase_master.py     |    6 +-
 .../stacks/2.0.6/common/test_stack_advisor.py   |    6 +-
 .../python/stacks/2.0.6/configs/default.json    |    5 +-
 .../hooks/before-INSTALL/test_before_install.py |   98 +-
 ambari-server/src/test/python/unitTests.py      |    2 +-
 .../HDP/2.0.1/services/GANGLIA/metainfo.xml     |    2 +-
 .../stacks/HDP/2.0.1/services/HDFS/metainfo.xml |    2 +-
 .../stacks/HDP/2.0.1/services/HIVE/metainfo.xml |    2 +-
 .../HDP/2.0.1/services/OOZIE/metainfo.xml       |    2 +-
 .../HDP/2.0.5/services/GANGLIA/metainfo.xml     |    2 +-
 .../stacks/HDP/2.0.5/services/HDFS/metainfo.xml |    2 +-
 .../stacks/HDP/2.0.5/services/HIVE/metainfo.xml |    2 +-
 .../HDP/2.0.5/services/OOZIE/metainfo.xml       |    2 +-
 .../stacks/HDP/2.0.7/services/HIVE/metainfo.xml |    2 +-
 .../assets/data/wizard/stack/HDP_versions.json  |   10 +-
 ambari-web/app/assets/test/tests.js             |    1 +
 ambari-web/app/controllers/application.js       |    4 +
 .../controllers/global/cluster_controller.js    |    6 +-
 ambari-web/app/controllers/installer.js         |    2 +-
 .../app/controllers/main/admin/repositories.js  |    2 +-
 .../main/admin/security/add/step4.js            |    3 +
 .../security/security_progress_controller.js    |    6 +-
 ambari-web/app/controllers/main/host/details.js |   11 +-
 .../controllers/main/service/info/configs.js    |   56 +-
 .../app/controllers/wizard/step3_controller.js  |    2 +-
 .../app/controllers/wizard/step7_controller.js  |    8 +
 .../app/controllers/wizard/step8_controller.js  |    2 +-
 .../mappers/service_config_version_mapper.js    |    1 +
 ambari-web/app/messages.js                      |    1 +
 ambari-web/app/models/service_config.js         |    8 +-
 ambari-web/app/models/service_config_version.js |    9 +-
 ambari-web/app/router.js                        |    2 +-
 ambari-web/app/routes/main.js                   |   19 +-
 ambari-web/app/styles/application.less          |   40 +-
 ambari-web/app/templates/application.hbs        |   22 +-
 .../common/configs/config_history_flow.hbs      |   16 +-
 .../templates/main/dashboard/config_history.hbs |    4 +-
 ambari-web/app/utils/blueprint.js               |    6 +-
 .../views/common/configs/config_history_flow.js |   42 +-
 .../app/views/common/configs/services_config.js |    2 +-
 .../app/views/common/filter_combo_cleanable.js  |    1 +
 ambari-web/app/views/main/menu.js               |   37 +-
 ambari-web/app/views/main/service/menu.js       |    2 +-
 .../views/common/filter_combo_cleanable_test.js |   42 +
 ambari-web/vendor/scripts/jquery.timeago.js     |    6 +-
 .../jobs/src/main/resources/ui/Gruntfile.js     |   13 -
 .../jobs/src/main/resources/ui/package.json     |    1 -
 pom.xml                                         |    2 +
 392 files changed, 23368 insertions(+), 22538 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/91ae5f27/ambari-agent/pom.xml
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/91ae5f27/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/91ae5f27/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/91ae5f27/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
----------------------------------------------------------------------


[42/50] [abbrv] git commit: Merge branch 'trunk' into branch-alerts-dev

Posted by jo...@apache.org.
Merge branch 'trunk' into branch-alerts-dev


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

Branch: refs/heads/trunk
Commit: b9cca7137540a6233a016ccf8ff3eba4c119b2b6
Parents: a42b727 753fe29
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Tue Sep 30 16:47:50 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Tue Sep 30 16:47:50 2014 -0400

----------------------------------------------------------------------
 .../controllers/ambariViews/ViewsListCtrl.js    |  36 ++++++
 .../ui/admin-web/app/scripts/services/View.js   |  18 +++
 .../resources/ui/admin-web/app/styles/main.css  |  18 ++-
 .../ui/admin-web/app/views/leftNavbar.html      |   6 +-
 .../src/main/python/ambari_agent/ActionQueue.py |   4 +-
 .../src/main/python/ambari_agent/Controller.py  |   6 +-
 ambari-server/conf/unix/ambari.properties       |   2 +-
 .../AmbariCustomCommandExecutionHelper.java     |  12 ++
 .../security/ldap/AmbariLdapDataPopulator.java  | 109 ++++++++++++-----
 ambari-server/src/main/python/ambari-server.py  |   2 +-
 .../1.3.2/hooks/after-INSTALL/scripts/hook.py   |   1 -
 .../1.3.2/hooks/after-INSTALL/scripts/params.py |   5 +-
 .../scripts/shared_initialization.py            |  37 ++----
 .../hooks/before-ANY/files/changeToSecureUid.sh |  50 ++++++++
 .../HDP/1.3.2/hooks/before-ANY/scripts/hook.py  |   3 +
 .../1.3.2/hooks/before-ANY/scripts/params.py    | 102 ++++++++++++++++
 .../before-ANY/scripts/shared_initialization.py |  58 +++++++++
 .../before-INSTALL/files/changeToSecureUid.sh   |  50 --------
 .../1.3.2/hooks/before-INSTALL/scripts/hook.py  |   1 -
 .../scripts/shared_initialization.py            |  35 ------
 .../1.3.2/hooks/before-START/scripts/hook.py    |   1 -
 .../2.0.6/hooks/after-INSTALL/scripts/hook.py   |   2 +-
 .../2.0.6/hooks/after-INSTALL/scripts/params.py |   5 +-
 .../scripts/shared_initialization.py            |  28 +----
 .../hooks/before-ANY/files/changeToSecureUid.sh |  50 ++++++++
 .../HDP/2.0.6/hooks/before-ANY/scripts/hook.py  |   2 +
 .../2.0.6/hooks/before-ANY/scripts/params.py    | 108 ++++++++++++++++-
 .../before-ANY/scripts/shared_initialization.py |  56 +++++++++
 .../before-INSTALL/files/changeToSecureUid.sh   |  50 --------
 .../2.0.6/hooks/before-INSTALL/scripts/hook.py  |   1 -
 .../scripts/shared_initialization.py            |  35 ------
 .../2.0.6/hooks/before-START/scripts/hook.py    |   1 -
 .../2.0.6/hooks/before-START/scripts/params.py  |   4 +-
 .../services/FLUME/package/scripts/params.py    |   4 +-
 .../services/HBASE/package/scripts/params.py    |   9 +-
 .../services/HDFS/package/scripts/params.py     |   4 +-
 .../services/HIVE/package/scripts/params.py     |   6 +-
 .../services/HIVE/package/scripts/webhcat.py    |  32 +++--
 .../services/OOZIE/package/scripts/params.py    |   4 +-
 .../services/PIG/package/scripts/params.py      |   4 +-
 .../services/SQOOP/package/scripts/params.py    |   4 +-
 .../services/YARN/package/scripts/params.py     |   4 +-
 .../ZOOKEEPER/package/scripts/params.py         |   4 +-
 .../services/FALCON/package/scripts/params.py   |   4 +-
 .../services/STORM/package/scripts/params.py    |   4 +-
 .../HDP/2.2/configuration/cluster-env.xml       |  29 +++++
 .../services/HDFS/configuration/hadoop-env.xml  |  29 -----
 .../HIVE/configuration/webhcat-site.xml         |  11 ++
 .../services/SLIDER/package/scripts/params.py   |   4 +-
 .../ldap/AmbariLdapDataPopulatorTest.java       |  32 +++++
 .../1.3.2/configs/default.hbasedecom.json       |   2 +-
 .../python/stacks/1.3.2/configs/default.json    |   2 +-
 .../1.3.2/configs/default.non_gmetad_host.json  |   2 +-
 .../stacks/1.3.2/configs/default_client.json    |   2 +-
 .../python/stacks/1.3.2/configs/secured.json    |   2 +-
 .../stacks/1.3.2/configs/secured_client.json    |   2 +-
 .../1.3.2/configs/secured_no_jce_name.json      |   2 +-
 .../hooks/after-INSTALL/test_after_install.py   |  13 --
 .../1.3.2/hooks/before-ANY/test_before_any.py   | 119 +++++++++++++++++++
 .../hooks/before-INSTALL/test_before_install.py | 110 +----------------
 .../stacks/2.0.6/HIVE/test_webhcat_server.py    |  20 ++++
 .../2.0.6/configs/default.hbasedecom.json       |   2 +-
 .../python/stacks/2.0.6/configs/default.json    |   2 +-
 .../2.0.6/configs/default.non_gmetad_host.json  |   2 +-
 .../stacks/2.0.6/configs/default_client.json    |   2 +-
 .../stacks/2.0.6/configs/flume_target.json      |   2 +-
 .../python/stacks/2.0.6/configs/ha_default.json |   2 +-
 .../python/stacks/2.0.6/configs/ha_secured.json |   2 +-
 .../python/stacks/2.0.6/configs/secured.json    |   2 +-
 .../stacks/2.0.6/configs/secured_client.json    |   2 +-
 .../2.0.6/configs/secured_no_jce_name.json      |   2 +-
 .../hooks/after-INSTALL/test_after_install.py   |  13 --
 .../2.0.6/hooks/before-ANY/test_before_any.py   | 119 +++++++++++++++++++
 .../hooks/before-INSTALL/test_before_install.py | 110 +----------------
 .../test/python/stacks/2.1/configs/default.json |   2 +-
 .../test/python/stacks/2.1/configs/secured.json |   2 +-
 .../test/python/stacks/2.2/configs/default.json |   2 +-
 .../test/python/stacks/2.2/configs/secured.json |   2 +-
 ambari-web/app/app.js                           |   2 +
 .../data/requests/host_check/jdk_name.json      |   2 +-
 ambari-web/app/controllers/application.js       |   4 +-
 .../controllers/global/cluster_controller.js    |  22 ++++
 ambari-web/app/controllers/main.js              |   4 +-
 ambari-web/app/controllers/main/host.js         |  24 ----
 .../app/controllers/main/host/add_controller.js |   1 +
 ambari-web/app/controllers/main/host/details.js |   6 +-
 .../controllers/main/service/info/configs.js    |  10 +-
 .../app/controllers/main/views_controller.js    |   4 -
 .../app/controllers/wizard/step3_controller.js  |   8 +-
 .../app/controllers/wizard/step7_controller.js  |   4 +-
 .../app/controllers/wizard/step8_controller.js  |   2 +-
 ambari-web/app/data/HDP2/site_properties.js     |  14 ++-
 .../mappers/service_config_version_mapper.js    |   1 +
 ambari-web/app/mappers/stack_service_mapper.js  |   7 +-
 ambari-web/app/messages.js                      |   2 +-
 ambari-web/app/mixins/common/serverValidator.js |  61 ++--------
 ambari-web/app/models/repository.js             |   2 +-
 ambari-web/app/models/service_config_version.js |  23 +++-
 ambari-web/app/routes/installer.js              |   3 +-
 ambari-web/app/routes/main.js                   |   3 +-
 .../templates/main/host/component_filter.hbs    |   6 +-
 ambari-web/app/utils/ajax/ajax.js               |   4 +-
 ambari-web/app/utils/components.js              |  33 ++++-
 ambari-web/app/utils/helper.js                  |  15 +++
 .../views/common/configs/config_history_flow.js |  19 ++-
 ambari-web/app/views/main/host.js               |  36 +++++-
 ambari-web/app/views/main/views/details.js      |  54 +++++++++
 ambari-web/test/utils/date_test.js              |   7 +-
 .../main/dashboard/config_history_view_test.js  |  24 ++--
 .../slider-core/0.51.0/slider-core-0.51.0.jar   | Bin 1146908 -> 1155217 bytes
 .../slider/SliderAppsViewControllerImpl.java    |  98 +++++++++------
 .../createAppWizard/step3_controller.js         |  20 ++--
 .../createAppWizard/step4_controller.js         |  59 +++++++--
 .../src/main/resources/ui/app/helpers/ajax.js   |   2 +-
 .../ui/app/mappers/slider_apps_mapper.js        |   1 +
 .../ui/app/mixins/ajax_error_handler.js         |   2 +-
 .../main/resources/ui/app/styles/common.less    |   3 +
 .../main/resources/ui/app/styles/wizard.less    |  44 +++----
 .../resources/ui/app/templates/application.hbs  |   2 +-
 .../ui/app/templates/createAppWizard/step1.hbs  |  10 +-
 .../ui/app/templates/createAppWizard/step2.hbs  |   8 +-
 .../src/main/resources/ui/app/translations.js   |  11 +-
 .../resources/ui/app/views/application_view.js  |  11 +-
 .../ui/app/views/common/config_set_view.js      |   7 +-
 .../ui/app/views/create_app_wizard_view.js      |   6 +-
 dev-support/test-patch.sh                       |  62 ----------
 pom.xml                                         |   2 +-
 127 files changed, 1477 insertions(+), 910 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/b9cca713/ambari-agent/src/main/python/ambari_agent/Controller.py
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/b9cca713/ambari-web/app/controllers/main/host.js
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/b9cca713/ambari-web/app/utils/ajax/ajax.js
----------------------------------------------------------------------


[37/50] [abbrv] git commit: AMBARI-7508 - Alerts: Reschedule Individual Alerts on Agents (jonathanhurley)

Posted by jo...@apache.org.
AMBARI-7508 - Alerts: Reschedule Individual Alerts on Agents (jonathanhurley)


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

Branch: refs/heads/trunk
Commit: 7db82c923c2903a2e2fab3d302fb9337423da08b
Parents: 2448352
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Thu Sep 25 22:19:49 2014 -0700
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Fri Sep 26 09:38:10 2014 -0700

----------------------------------------------------------------------
 .../ambari_agent/AlertSchedulerHandler.py       |  98 ++++++-
 .../python/ambari_agent/alerts/base_alert.py    |  37 ++-
 .../python/ambari_agent/alerts/collector.py     |  21 +-
 .../src/test/python/ambari_agent/TestAlerts.py  |  50 ++++
 .../ambari_agent/dummy_files/definitions.json   |   1 +
 ambari-project/pom.xml                          |   7 +-
 ambari-server/pom.xml                           |  12 +-
 .../internal/AlertGroupResourceProvider.java    |  33 ++-
 .../events/AlertDefinitionDeleteEvent.java      |  55 ++++
 .../ambari/server/events/AmbariEvent.java       |   7 +-
 .../listeners/AlertLifecycleListener.java       |  54 +++-
 .../events/listeners/AlertReceivedListener.java |   8 +
 .../server/orm/dao/AlertDefinitionDAO.java      |  13 +
 .../apache/ambari/server/orm/dao/AlertsDAO.java |   1 +
 .../orm/entities/AlertDefinitionEntity.java     |  15 +-
 .../server/orm/entities/AlertGroupEntity.java   |   5 +-
 .../state/alert/AggregateDefinitionMapping.java |  31 +-
 .../server/state/alert/AlertDefinition.java     |  19 ++
 .../state/alert/AlertDefinitionFactory.java     |   1 +
 .../server/state/alert/AlertDefinitionHash.java | 293 +++++++++++--------
 .../AlertGroupResourceProviderTest.java         |  87 ++++++
 .../server/orm/dao/AlertDefinitionDAOTest.java  |   6 +-
 .../alerts/AlertDefinitionEqualityTest.java     |   1 +
 .../state/alerts/AlertEventPublisherTest.java   |  68 ++++-
 .../alerts/AlertStateChangedEventTest.java      |  12 +-
 .../state/cluster/AlertDataManagerTest.java     |   2 +-
 26 files changed, 755 insertions(+), 182 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/7db82c92/ambari-agent/src/main/python/ambari_agent/AlertSchedulerHandler.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/AlertSchedulerHandler.py b/ambari-agent/src/main/python/ambari_agent/AlertSchedulerHandler.py
index 7cce533..8dcce50 100644
--- a/ambari-agent/src/main/python/ambari_agent/AlertSchedulerHandler.py
+++ b/ambari-agent/src/main/python/ambari_agent/AlertSchedulerHandler.py
@@ -61,22 +61,25 @@ class AlertSchedulerHandler():
         logger.critical("Could not create the cache directory {0}".format(cachedir))
         pass
 
+    self._collector = AlertCollector()
     self.__scheduler = Scheduler(AlertSchedulerHandler.APS_CONFIG)
     self.__in_minutes = in_minutes
-    self.__collector = AlertCollector()
     self.__config_maps = {}
+
           
-  def update_definitions(self, alert_commands, refresh_jobs=False):
+  def update_definitions(self, alert_commands, reschedule_jobs=False):
     ''' updates the persisted definitions and restarts the scheduler '''
     
     with open(os.path.join(self.cachedir, self.FILENAME), 'w') as f:
       json.dump(alert_commands, f, indent=2)
     
-    if refresh_jobs:
-      self.start()
+    if reschedule_jobs:
+      self.reschedule()
+
       
   def __make_function(self, alert_def):
     return lambda: alert_def.collect()
+
     
   def start(self):
     ''' loads definitions from file and starts the scheduler '''
@@ -90,26 +93,72 @@ class AlertSchedulerHandler():
 
     alert_callables = self.__load_definitions()
       
+    # schedule each definition
     for _callable in alert_callables:
-      if self.__in_minutes:
-        self.__scheduler.add_interval_job(self.__make_function(_callable),
-          minutes=_callable.interval())
-      else:
-        self.__scheduler.add_interval_job(self.__make_function(_callable),
-          seconds=_callable.interval())
+      self.schedule_definition(_callable)
       
     logger.debug("Starting scheduler {0}; currently running: {1}".format(
       str(self.__scheduler), str(self.__scheduler.running)))
+
     self.__scheduler.start()
+
     
   def stop(self):
     if not self.__scheduler is None:
       self.__scheduler.shutdown(wait=False)
       self.__scheduler = Scheduler(AlertSchedulerHandler.APS_CONFIG)
+
+
+  def reschedule(self):
+    '''
+    Removes jobs that are scheduled where their UUID no longer is valid. 
+    Schedules jobs where the definition UUID is not currently scheduled.
+    '''
+    jobs_scheduled = 0
+    jobs_removed = 0
+    
+    definitions = self.__load_definitions()
+    scheduled_jobs = self.__scheduler.get_jobs()
+    
+    # for every scheduled job, see if its UUID is still valid
+    for scheduled_job in scheduled_jobs:
+      uuid_valid = False
+      
+      for definition in definitions:
+        definition_uuid = definition.definition_uuid()
+        if scheduled_job.name == definition_uuid:
+          uuid_valid = True
+          break
+      
+      # jobs without valid UUIDs should be unscheduled
+      if uuid_valid == False:
+        jobs_removed += 1
+        logger.info("Unscheduling {0}".format(scheduled_job.name))
+        self._collector.remove_by_uuid(scheduled_job.name)
+        self.__scheduler.unschedule_job(scheduled_job)
       
+    # for every definition, determine if there is a scheduled job
+    for definition in definitions:
+      definition_scheduled = False
+      for scheduled_job in scheduled_jobs:
+        definition_uuid = definition.definition_uuid()
+        if definition_uuid == scheduled_job.name:
+          definition_scheduled = True
+          break
+      
+      # if no jobs are found with the definitions UUID, schedule it
+      if definition_scheduled == False:
+        jobs_scheduled += 1
+        self.schedule_definition(definition)
+  
+    logger.info("Alert Reschedule Summary: {0} rescheduled, {1} unscheduled".format(
+        str(jobs_scheduled), str(jobs_removed)))
+
+
   def collector(self):
     ''' gets the collector for reporting to the server '''
-    return self.__collector
+    return self._collector
+  
       
   def __load_definitions(self):
     ''' loads all alert commands from the file.  all clusters are stored in one file '''
@@ -147,7 +196,7 @@ class AlertSchedulerHandler():
         vals = self.__find_config_values(configmap, obj.get_lookup_keys())
         self.__config_maps[clusterName].update(vals)
 
-        obj.set_helpers(self.__collector, self.__config_maps[clusterName])
+        obj.set_helpers(self._collector, self.__config_maps[clusterName])
 
         definitions.append(obj)
       
@@ -208,7 +257,30 @@ class AlertSchedulerHandler():
         configmap = command['configurations']
         keylist = self.__config_maps[clusterName].keys()
         vals = self.__find_config_values(configmap, keylist)
-        self.__config_maps[clusterName].update(vals)  
+        self.__config_maps[clusterName].update(vals)
+        
+
+  def schedule_definition(self,definition):
+    '''
+    Schedule a definition (callable). Scheduled jobs are given the UUID
+    as their name so that they can be identified later on.
+    '''
+    job = None
+
+    if self.__in_minutes:
+      job = self.__scheduler.add_interval_job(self.__make_function(definition),
+        minutes=definition.interval())
+    else:
+      job = self.__scheduler.add_interval_job(self.__make_function(definition),
+        seconds=definition.interval())
+    
+    # although the documentation states that Job(kwargs) takes a name 
+    # key/value pair, it does not actually set the name; do it manually
+    if job is not None:
+      job.name = definition.definition_uuid()
+      
+    logger.info("Scheduling {0} with UUID {1}".format(
+      definition.definition_name(), definition.definition_uuid()))
 
 def main():
   args = list(sys.argv)

http://git-wip-us.apache.org/repos/asf/ambari/blob/7db82c92/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py b/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py
index b22938d..10dcff8 100644
--- a/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py
+++ b/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py
@@ -46,17 +46,34 @@ class BaseAlert(object):
     else:
       interval = self.alert_meta['interval']
       return 1 if interval < 1 else interval
-      
+
+
+  def definition_name(self):
+    '''
+    gets the unique name of the alert definition
+    '''
+    return self.alert_meta['name']
+
+
+  def definition_uuid(self):
+    '''
+    gets the unique has of the alert definition
+    '''
+    return self.alert_meta['uuid']
+
+
   def set_helpers(self, collector, value_dict):
     ''' sets helper objects for alerts without having to use them in a constructor '''
     self.collector = collector
     self.config_value_dict = value_dict
-      
+
+
   def set_cluster(self, cluster, host):
     ''' sets cluster information for the alert '''
     self.cluster = cluster
     self.host_name = host
-  
+
+
   def collect(self):
     ''' method used for collection.  defers to _collect() '''
     
@@ -83,12 +100,14 @@ class BaseAlert(object):
     data['service'] = self._find_value('serviceName')
     data['component'] = self._find_value('componentName')
     data['timestamp'] = long(time.time() * 1000)
+    data['uuid'] = self._find_value('uuid')
 
     if logger.isEnabledFor(logging.DEBUG):
       logger.debug("debug alert text: {0}".format(data['text']))
     
     self.collector.put(self.cluster, data)
-  
+
+
   def _find_value(self, meta_key):
     ''' safe way to get a value when outputting result json.  will not throw an exception '''
     if self.alert_meta.has_key(meta_key):
@@ -96,10 +115,12 @@ class BaseAlert(object):
     else:
       return None
 
+
   def get_lookup_keys(self):
     ''' returns a list of lookup keys found for this alert '''
     return self._lookup_keys
-      
+
+
   def _find_lookup_property(self, key):
     '''
     check if the supplied key is parameterized
@@ -112,7 +133,8 @@ class BaseAlert(object):
       return keys[0]
       
     return key
-    
+
+
   def _lookup_property_value(self, key):
     '''
     in the case of specifying a configuration path, lookup that path's value
@@ -124,7 +146,8 @@ class BaseAlert(object):
       return self.config_value_dict[key]
     else:
       return None
-  
+
+
   def _collect(self):
     '''
     Low level function to collect alert data.  The result is a tuple as:

http://git-wip-us.apache.org/repos/asf/ambari/blob/7db82c92/ambari-agent/src/main/python/ambari_agent/alerts/collector.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/alerts/collector.py b/ambari-agent/src/main/python/ambari_agent/alerts/collector.py
index 7249449..9943211 100644
--- a/ambari-agent/src/main/python/ambari_agent/alerts/collector.py
+++ b/ambari-agent/src/main/python/ambari_agent/alerts/collector.py
@@ -33,8 +33,27 @@ class AlertCollector():
     if not cluster in self.__buckets:
       self.__buckets[cluster] = {}
       
-    self.__buckets[cluster][alert['name']] = alert 
+    self.__buckets[cluster][alert['name']] = alert
     
+  def remove(self, cluster, alert_name):
+    '''
+    Removes the alert with the specified name if it exists in the dictionary
+    '''
+    if not cluster in self.__buckets:
+      return
+    
+    del self.__buckets[cluster][alert_name]
+    
+  def remove_by_uuid(self, alert_uuid):
+    '''
+    Removes the alert with the specified uuid if it exists in the dictionary
+    '''
+    for cluster,alert_map in self.__buckets.iteritems():
+      for alert_name in alert_map.keys():
+        alert = alert_map[alert_name]
+        if alert['uuid'] == alert_uuid:
+          self.remove(cluster, alert_name)
+        
   def alerts(self):
     alerts = []
     for clustermap in self.__buckets.values()[:]:

http://git-wip-us.apache.org/repos/asf/ambari/blob/7db82c92/ambari-agent/src/test/python/ambari_agent/TestAlerts.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/TestAlerts.py b/ambari-agent/src/test/python/ambari_agent/TestAlerts.py
index 5dc45b5..662d8ee 100644
--- a/ambari-agent/src/test/python/ambari_agent/TestAlerts.py
+++ b/ambari-agent/src/test/python/ambari_agent/TestAlerts.py
@@ -56,6 +56,7 @@ class TestAlerts(TestCase):
       "label": "NameNode process",
       "interval": 6,
       "scope": "host",
+      "uuid": "c1f73191-4481-4435-8dae-fd380e4c0be1",
       "source": {
         "type": "PORT",
         "uri": "{{hdfs-site/my-key}}",
@@ -86,6 +87,7 @@ class TestAlerts(TestCase):
       "label": "NameNode process",
       "interval": 6,
       "scope": "host",
+      "uuid": "c1f73191-4481-4435-8dae-fd380e4c0be1",
       "source": {
         "type": "PORT",
         "uri": "http://c6401.ambari.apache.org",
@@ -115,6 +117,7 @@ class TestAlerts(TestCase):
       "label": "NameNode process",
       "interval": 6,
       "scope": "host",
+      "uuid": "c1f73191-4481-4435-8dae-fd380e4c0be1",
       "source": {
         "type": "SCRIPT",
         "path": "test_script.py",
@@ -152,6 +155,7 @@ class TestAlerts(TestCase):
       "label": "NameNode process",
       "interval": 6,
       "scope": "host",
+      "uuid": "c1f73191-4481-4435-8dae-fd380e4c0be1",
       "source": {
         "type": "METRIC",
         "uri": "http://myurl:8633",
@@ -197,3 +201,49 @@ class TestAlerts(TestCase):
     self.assertEquals('OK', collector.alerts()[0]['state'])
     self.assertEquals('ok_arr: 1 3 None', collector.alerts()[0]['text'])
     
+  def test_reschedule(self):
+    test_file_path = os.path.join('ambari_agent', 'dummy_files')
+    test_stack_path = os.path.join('ambari_agent', 'dummy_files')
+
+    ash = AlertSchedulerHandler(test_file_path, test_stack_path)
+    ash.start()
+    ash.reschedule()
+        
+  
+  def test_alert_collector_purge(self):
+    json = { "name": "namenode_process",
+      "service": "HDFS",
+      "component": "NAMENODE",
+      "label": "NameNode process",
+      "interval": 6,
+      "scope": "host",
+      "uuid": "c1f73191-4481-4435-8dae-fd380e4c0be1",
+      "source": {
+        "type": "PORT",
+        "uri": "{{hdfs-site/my-key}}",
+        "default_port": 50070,
+        "reporting": {
+          "ok": {
+            "text": "TCP OK - {0:.4f} response time on port {1}"
+          },
+          "critical": {
+            "text": "Could not load process info: {0}"
+          }
+        }
+      }
+    }
+
+    collector = AlertCollector()
+
+    pa = PortAlert(json, json['source'])
+    pa.set_helpers(collector, {'hdfs-site/my-key': 'value1'})
+    self.assertEquals(6, pa.interval())
+
+    res = pa.collect()
+    
+    self.assertIsNotNone(collector.alerts()[0])
+    self.assertEquals('CRITICAL', collector.alerts()[0]['state'])
+    
+    collector.remove_by_uuid('c1f73191-4481-4435-8dae-fd380e4c0be1')
+    self.assertEquals(0,len(collector.alerts()))
+    

http://git-wip-us.apache.org/repos/asf/ambari/blob/7db82c92/ambari-agent/src/test/python/ambari_agent/dummy_files/definitions.json
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/dummy_files/definitions.json b/ambari-agent/src/test/python/ambari_agent/dummy_files/definitions.json
index ad52abc..30973c2 100644
--- a/ambari-agent/src/test/python/ambari_agent/dummy_files/definitions.json
+++ b/ambari-agent/src/test/python/ambari_agent/dummy_files/definitions.json
@@ -16,6 +16,7 @@
         "label": "NameNode process",
         "interval": 6,
         "scope": "host",
+        "uuid": "3f82ae27-fa6a-465b-b77d-67963ac55d2f",
         "source": {
           "type": "PORT",
           "uri": "{{hdfs-site/dfs.namenode.http-address}}",

http://git-wip-us.apache.org/repos/asf/ambari/blob/7db82c92/ambari-project/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-project/pom.xml b/ambari-project/pom.xml
index 58e2e8f..edba1dc 100644
--- a/ambari-project/pom.xml
+++ b/ambari-project/pom.xml
@@ -55,8 +55,9 @@
   </pluginRepositories>
   <repositories>
     <repository>
-      <id>EclipseLink</id>
-      <url>http://download.eclipse.org/rt/eclipselink/maven.repo</url>
+      <id>oss.sonatype.org</id>
+      <name>OSS Sonatype Staging</name>
+      <url>https://oss.sonatype.org/content/groups/staging</url>
     </repository>
     <repository>
       <id>spring-milestones</id>
@@ -211,7 +212,7 @@
       <dependency>
         <groupId>org.eclipse.persistence</groupId>
         <artifactId>eclipselink</artifactId>
-        <version>2.4.0</version>
+        <version>2.4.2</version>
       </dependency>
       <dependency>
         <groupId>org.postgresql</groupId>

http://git-wip-us.apache.org/repos/asf/ambari/blob/7db82c92/ambari-server/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-server/pom.xml b/ambari-server/pom.xml
index 5ac76f9..f37a177 100644
--- a/ambari-server/pom.xml
+++ b/ambari-server/pom.xml
@@ -191,7 +191,7 @@
           <dependency>
             <groupId>org.eclipse.persistence</groupId>
             <artifactId>eclipselink</artifactId>
-            <version>2.4.0</version>
+            <version>2.4.2</version>
           </dependency>
         </dependencies>
       </plugin>
@@ -1451,14 +1451,12 @@
       <version>1.5.2</version>
     </dependency>
   </dependencies>
-  <!--<reporting> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId>
-    <artifactId>findbugs-maven-plugin</artifactId> <version>2.5.2</version> </plugin>
-    </plugins> </reporting> -->
-
+  
   <pluginRepositories>
     <pluginRepository>
-      <id>EclipseLink</id>
-      <url>http://download.eclipse.org/rt/eclipselink/maven.repo</url>
+      <id>oss.sonatype.org</id>
+      <name>OSS Sonatype Staging</name>
+      <url>https://oss.sonatype.org/content/groups/staging</url>
     </pluginRepository>
   </pluginRepositories>
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/7db82c92/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProvider.java
index fc51ddd..8c55aa7 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProvider.java
@@ -314,10 +314,6 @@ public class AlertGroupResourceProvider extends
       Collection<Long> targetIds = (Collection<Long>) requestMap.get(ALERT_GROUP_TARGETS);
       Collection<Long> definitionIds = (Collection<Long>) requestMap.get(ALERT_GROUP_DEFINITIONS);
 
-      if (!StringUtils.isBlank(name)) {
-        entity.setGroupName(name);
-      }
-
       // if targets were supplied, replace existing
       Set<AlertTargetEntity> targets = new HashSet<AlertTargetEntity>();
       if (null != targetIds && targetIds.size() > 0) {
@@ -331,17 +327,26 @@ public class AlertGroupResourceProvider extends
         entity.setAlertTargets(targets);
       }
 
-      // if definitions were supplied, replace existing
-      Set<AlertDefinitionEntity> definitions = new HashSet<AlertDefinitionEntity>();
-      if (null != definitionIds && definitionIds.size() > 0) {
-        List<Long> ids = new ArrayList<Long>(definitionIds.size());
-        ids.addAll(definitionIds);
-        definitions.addAll(s_definitionDao.findByIds(ids));
+      // only the targets should be updatable on default groups; everything
+      // else is valid only on regular groups
+      if (!entity.isDefault()) {
+        // set the name if supplied
+        if (!StringUtils.isBlank(name)) {
+          entity.setGroupName(name);
+        }
 
-        entity.setAlertDefinitions(definitions);
-      } else if (definitionIds.size() == 0) {
-        // empty array supplied, clear out existing definitions
-        entity.setAlertDefinitions(definitions);
+        // if definitions were supplied, replace existing
+        Set<AlertDefinitionEntity> definitions = new HashSet<AlertDefinitionEntity>();
+        if (null != definitionIds && definitionIds.size() > 0) {
+          List<Long> ids = new ArrayList<Long>(definitionIds.size());
+          ids.addAll(definitionIds);
+          definitions.addAll(s_definitionDao.findByIds(ids));
+
+          entity.setAlertDefinitions(definitions);
+        } else {
+          // empty array supplied, clear out existing definitions
+          entity.setAlertDefinitions(definitions);
+        }
       }
 
       s_dao.merge(entity);

http://git-wip-us.apache.org/repos/asf/ambari/blob/7db82c92/ambari-server/src/main/java/org/apache/ambari/server/events/AlertDefinitionDeleteEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/AlertDefinitionDeleteEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/AlertDefinitionDeleteEvent.java
new file mode 100644
index 0000000..c8fd36b
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/AlertDefinitionDeleteEvent.java
@@ -0,0 +1,55 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.events;
+
+import org.apache.ambari.server.state.alert.AlertDefinition;
+
+/**
+ * The {@link AlertDefinitionDeleteEvent} is used to represent that an
+ * {@link AlertDefinition} has been removed from the system.
+ */
+public class AlertDefinitionDeleteEvent extends ClusterEvent {
+
+  /**
+   * The removed alert defintiion
+   */
+  private final AlertDefinition m_definition;
+
+  /**
+   * Constructor.
+   *
+   * @param clusterId
+   *          the ID of the cluster that the definition is in.
+   * @param definition
+   *          the alert definition being registered.
+   */
+  public AlertDefinitionDeleteEvent(
+      long clusterId, AlertDefinition definition) {
+    super(AmbariEventType.ALERT_DEFINITION_REMOVAL, clusterId);
+    m_definition = definition;
+  }
+
+  /**
+   * Get the registered alert definition.
+   *
+   * @return the alert definition (not {@code null}).
+   */
+  public AlertDefinition getDefinition() {
+    return m_definition;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/7db82c92/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java
index 6cf752e..3dae676 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java
@@ -35,7 +35,12 @@ public abstract class AmbariEvent {
     /**
      * An alert definition is registered with the system.
      */
-    ALERT_DEFINITION_REGISTRATION;
+    ALERT_DEFINITION_REGISTRATION,
+
+    /**
+     * An alert definition is removed from the system.
+     */
+    ALERT_DEFINITION_REMOVAL;
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/7db82c92/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertLifecycleListener.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertLifecycleListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertLifecycleListener.java
index 43d4b35..9d2f4c6 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertLifecycleListener.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertLifecycleListener.java
@@ -17,15 +17,22 @@
  */
 package org.apache.ambari.server.events.listeners;
 
+import java.util.Set;
+
+import org.apache.ambari.server.events.AlertDefinitionDeleteEvent;
 import org.apache.ambari.server.events.AlertDefinitionRegistrationEvent;
 import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 import org.apache.ambari.server.state.alert.AggregateDefinitionMapping;
 import org.apache.ambari.server.state.alert.AlertDefinition;
+import org.apache.ambari.server.state.alert.AlertDefinitionHash;
 import org.apache.ambari.server.state.alert.SourceType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.eventbus.AllowConcurrentEvents;
 import com.google.common.eventbus.Subscribe;
 import com.google.inject.Inject;
+import com.google.inject.Provider;
 import com.google.inject.Singleton;
 
 /**
@@ -34,6 +41,10 @@ import com.google.inject.Singleton;
  */
 @Singleton
 public class AlertLifecycleListener {
+  /**
+   * Logger.
+   */
+  private static Logger LOG = LoggerFactory.getLogger(AlertLifecycleListener.class);
 
   /**
    * Used for quick lookups of aggregate alerts.
@@ -42,6 +53,13 @@ public class AlertLifecycleListener {
   private AggregateDefinitionMapping m_aggregateMapping;
 
   /**
+   * Invalidates hosts so that they can receive updated alert definition
+   * commands.
+   */
+  @Inject
+  private Provider<AlertDefinitionHash> m_alertDefinitionHash;
+
+  /**
    * Constructor.
    *
    * @param publisher
@@ -66,8 +84,42 @@ public class AlertLifecycleListener {
   public void onAmbariEvent(AlertDefinitionRegistrationEvent event) {
     AlertDefinition definition = event.getDefinition();
 
+    LOG.debug("Registering alert definition {}", definition);
+
     if (definition.getSource().getType() == SourceType.AGGREGATE) {
-      m_aggregateMapping.addAggregateType(event.getClusterId(), definition);
+      m_aggregateMapping.registerAggregate(event.getClusterId(), definition);
+    }
+  }
+
+  /**
+   * Handles {@link AlertDefinitionDeleteEvent} by performing the following
+   * tasks:
+   * <ul>
+   * <li>Removal from with {@link AggregateDefinitionMapping}</li>
+   * <li>{@link AlertDefinitionHash} invalidation</li>
+   * </ul>
+   *
+   * @param event
+   *          the event being handled.
+   */
+  @Subscribe
+  @AllowConcurrentEvents
+  public void onAmbariEvent(AlertDefinitionDeleteEvent event) {
+    AlertDefinition definition = event.getDefinition();
+
+    LOG.debug("Removing alert definition {}", definition);
+
+    if (null == definition) {
+      return;
     }
+
+    m_aggregateMapping.removeAssociatedAggregate(event.getClusterId(),
+        definition.getName());
+
+    AlertDefinitionHash hashHelper = m_alertDefinitionHash.get();
+    Set<String> invalidatedHosts = hashHelper.invalidateHosts(definition);
+
+    hashHelper.enqueueAgentCommands(definition.getClusterId(),
+        invalidatedHosts);
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/7db82c92/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java
index e87ba7d..78d8e66 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java
@@ -101,6 +101,14 @@ public class AlertReceivedListener {
       AlertDefinitionEntity definition = m_definitionDao.findByName(clusterId,
           alert.getName());
 
+      if (null == definition) {
+        LOG.warn(
+            "Received an alert for {} which is a definition that does not exist anymore",
+            alert.getName());
+
+        return;
+      }
+
       AlertHistoryEntity history = createHistory(clusterId, definition, alert);
 
       current = new AlertCurrentEntity();

http://git-wip-us.apache.org/repos/asf/ambari/blob/7db82c92/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java
index 075ee04..8e8c808 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java
@@ -25,6 +25,7 @@ import javax.persistence.EntityManager;
 import javax.persistence.TypedQuery;
 
 import org.apache.ambari.server.controller.RootServiceResponseFactory;
+import org.apache.ambari.server.events.AlertDefinitionDeleteEvent;
 import org.apache.ambari.server.events.AlertDefinitionRegistrationEvent;
 import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
@@ -364,6 +365,18 @@ public class AlertDefinitionDAO {
     if (null != alertDefinition) {
       entityManager.remove(alertDefinition);
     }
+
+    // publish the alert definition removal
+    AlertDefinition coerced = alertDefinitionFactory.coerce(alertDefinition);
+    if (null != coerced) {
+      AlertDefinitionDeleteEvent event = new AlertDefinitionDeleteEvent(
+          alertDefinition.getClusterId(), coerced);
+
+      eventPublisher.publish(event);
+    } else {
+      LOG.warn("Unable to broadcast alert removal event for {}",
+          alertDefinition.getDefinitionName());
+    }
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/7db82c92/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 a28b448..f2161f3 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
@@ -515,6 +515,7 @@ public class AlertsDAO {
     query.setParameter("clusterId", Long.valueOf(clusterId));
     query.setParameter("definitionName", alertName);
 
+    query = setQueryRefreshHint(query);
     return daoUtils.selectOne(query);
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/7db82c92/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertDefinitionEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertDefinitionEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertDefinitionEntity.java
index 8548fda..4ab2c80 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertDefinitionEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertDefinitionEntity.java
@@ -17,7 +17,9 @@
  */
 package org.apache.ambari.server.orm.entities;
 
+import java.util.Collections;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.Set;
 
 import javax.persistence.Basic;
@@ -363,7 +365,7 @@ public class AlertDefinitionEntity {
    * @return the groups, or {@code null} if none.
    */
   public Set<AlertGroupEntity> getAlertGroups() {
-    return alertGroups;
+    return Collections.unmodifiableSet(alertGroups);
   }
 
   /**
@@ -418,7 +420,7 @@ public class AlertDefinitionEntity {
    * @param alertGroup
    */
   protected void removeAlertGroup(AlertGroupEntity alertGroup) {
-    if (null != alertGroups) {
+    if (null != alertGroups && alertGroups.contains(alertGroup)) {
       alertGroups.remove(alertGroup);
     }
   }
@@ -429,12 +431,15 @@ public class AlertDefinitionEntity {
    */
   @PreRemove
   public void preRemove() {
-    Set<AlertGroupEntity> groups = getAlertGroups();
-    if (null == groups || groups.size() == 0) {
+    if (null == alertGroups || alertGroups.size() == 0) {
       return;
     }
 
-    for (AlertGroupEntity group : groups) {
+    Iterator<AlertGroupEntity> iterator = alertGroups.iterator();
+    while (iterator.hasNext()) {
+      AlertGroupEntity group = iterator.next();
+      iterator.remove();
+
       group.removeAlertDefinition(this);
     }
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/7db82c92/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertGroupEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertGroupEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertGroupEntity.java
index 1cc9bcc..ac3586d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertGroupEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertGroupEntity.java
@@ -21,6 +21,7 @@ import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
 
+import javax.persistence.CascadeType;
 import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.GeneratedValue;
@@ -73,14 +74,14 @@ public class AlertGroupEntity {
   /**
    * Bi-directional many-to-many association to {@link AlertDefinitionEntity}
    */
-  @ManyToMany
+  @ManyToMany(cascade = CascadeType.MERGE)
   @JoinTable(name = "alert_grouping", joinColumns = { @JoinColumn(name = "group_id", nullable = false) }, inverseJoinColumns = { @JoinColumn(name = "definition_id", nullable = false) })
   private Set<AlertDefinitionEntity> alertDefinitions;
 
   /**
    * Unidirectional many-to-many association to {@link AlertTargetEntity}
    */
-  @ManyToMany
+  @ManyToMany(cascade = CascadeType.MERGE)
   @JoinTable(name = "alert_group_target", joinColumns = { @JoinColumn(name = "group_id", nullable = false) }, inverseJoinColumns = { @JoinColumn(name = "target_id", nullable = false) })
   private Set<AlertTargetEntity> alertTargets;
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/7db82c92/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AggregateDefinitionMapping.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AggregateDefinitionMapping.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AggregateDefinitionMapping.java
index 04f20f9..c63c0d4 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AggregateDefinitionMapping.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AggregateDefinitionMapping.java
@@ -19,6 +19,7 @@ package org.apache.ambari.server.state.alert;
 
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 import com.google.inject.Singleton;
 
@@ -33,7 +34,8 @@ public final class AggregateDefinitionMapping {
    * In-memory mapping of cluster ID to definition name / aggregate definition.
    * This is used for fast lookups when receiving events.
    */
-  private Map<Long, Map<String, AlertDefinition>> m_aggregateMap = new HashMap<Long, Map<String, AlertDefinition>>();
+  private Map<Long, Map<String, AlertDefinition>> m_aggregateMap =
+      new ConcurrentHashMap<Long, Map<String, AlertDefinition>>();
 
   /**
    * Constructor.
@@ -69,10 +71,10 @@ public final class AggregateDefinitionMapping {
    *
    * @param clusterId
    *          the ID of the cluster that the definition is bound to.
-   * @param name
-   *          the unique name of the definition.
+   * @param definition
+   *          the aggregate definition to register (not {@code null}).
    */
-  public void addAggregateType(long clusterId, AlertDefinition definition) {
+  public void registerAggregate(long clusterId, AlertDefinition definition) {
     Long id = Long.valueOf(clusterId);
 
     if (!m_aggregateMap.containsKey(id)) {
@@ -85,4 +87,25 @@ public final class AggregateDefinitionMapping {
 
     map.put(as.getAlertName(), definition);
   }
+
+  /**
+   * Removes the associated aggregate for the specified aggregated definition.
+   *
+   * @param clusterId
+   *          the ID of the cluster that the definition is bound to.
+   * @param name
+   *          the unique name of the definition for which aggregates should be
+   *          unassociated (not {@code null}).
+   */
+  public void removeAssociatedAggregate(long clusterId,
+      String aggregatedDefinitonName) {
+    Long id = Long.valueOf(clusterId);
+
+    if (!m_aggregateMap.containsKey(id)) {
+      return;
+    }
+
+    Map<String, AlertDefinition> map = m_aggregateMap.get(id);
+    map.remove(aggregatedDefinitonName);
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/7db82c92/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinition.java
index 5058e91..961fb66 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinition.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinition.java
@@ -34,6 +34,7 @@ import java.util.HashSet;
  */
 public class AlertDefinition {
 
+  private long clusterId;
   private String serviceName = null;
   private String componentName = null;
 
@@ -46,6 +47,24 @@ public class AlertDefinition {
   private String uuid = null;
 
   /**
+   * Gets the cluster ID for this definition.
+   *
+   * @return
+   */
+  public long getClusterId() {
+    return clusterId;
+  }
+
+  /**
+   * Sets the cluster ID for this definition.
+   *
+   * @param clusterId
+   */
+  public void setClusterId(long clusterId) {
+    this.clusterId = clusterId;
+  }
+
+  /**
    * @return the service name
    */
   public String getServiceName() {

http://git-wip-us.apache.org/repos/asf/ambari/blob/7db82c92/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionFactory.java
index 4f6a9a3..9c72b6a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionFactory.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionFactory.java
@@ -125,6 +125,7 @@ public class AlertDefinitionFactory {
     }
 
     AlertDefinition definition = new AlertDefinition();
+    definition.setClusterId(entity.getClusterId());
     definition.setComponentName(entity.getComponentName());
     definition.setEnabled(entity.getEnabled());
     definition.setInterval(entity.getScheduleInterval());

http://git-wip-us.apache.org/repos/asf/ambari/blob/7db82c92/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java
index 9ea039c..35d7742 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java
@@ -262,85 +262,19 @@ public class AlertDefinitionHash {
 
 
   /**
-   * Gets the alert definition entities for the specified host. This will include the
-   * following types of alert definitions:
-   * <ul>
-   * <li>Service/Component alerts</li>
-   * <li>Service alerts where the host is a MASTER</li>
-   * <li>Host alerts that are not bound to a service</li>
-   * </ul>
+   * Invalidate the hashes of any host that would be affected by the specified
+   * definition.
    *
-   * @param clusterName
-   *          the cluster name (not {@code null}).
-   * @param hostName
-   *          the host name (not {@code null}).
-   * @return the alert definitions for the host, or an empty set (never
+   * @param definition
+   *          the definition to use to find the hosts to invlidate (not
+   *          {@code null}).
+   * @return the hosts that were invalidated, or an empty set (never
    *         {@code null}).
    */
-  private Set<AlertDefinitionEntity> getAlertDefinitionEntities(
-      String clusterName,
-      String hostName) {
-    Set<AlertDefinitionEntity> definitions = new HashSet<AlertDefinitionEntity>();
-
-    try {
-      Cluster cluster = m_clusters.getCluster(clusterName);
-      if (null == cluster) {
-        LOG.warn("Unable to get alert definitions for the missing cluster {}",
-            clusterName);
-
-        return Collections.emptySet();
-      }
-
-      long clusterId = cluster.getClusterId();
-      List<ServiceComponentHost> serviceComponents = cluster.getServiceComponentHosts(hostName);
-      if (null == serviceComponents || serviceComponents.size() == 0) {
-        LOG.warn(
-            "Unable to get alert definitions for {} since there are no service components defined",
-            hostName);
-
-        return Collections.emptySet();
-      }
-
-      for (ServiceComponentHost serviceComponent : serviceComponents) {
-        String serviceName = serviceComponent.getServiceName();
-        String componentName = serviceComponent.getServiceComponentName();
-
-        // add all alerts for this service/component pair
-        definitions.addAll(m_definitionDao.findByServiceComponent(
-            clusterId, serviceName, componentName));
-      }
-
-      // for every service, get the master components and see if the host
-      // is a master
-      Set<String> services = new HashSet<String>();
-      for (Entry<String, Service> entry : cluster.getServices().entrySet()) {
-        Service service = entry.getValue();
-        Map<String, ServiceComponent> components = service.getServiceComponents();
-        for (Entry<String, ServiceComponent> component : components.entrySet()) {
-          if (component.getValue().isMasterComponent()) {
-            Map<String, ServiceComponentHost> hosts = component.getValue().getServiceComponentHosts();
-
-            if( hosts.containsKey( hostName ) ){
-              services.add(service.getName());
-            }
-          }
-        }
-      }
-
-      // add all service scoped alerts
-      if( services.size() > 0 ){
-        definitions.addAll(m_definitionDao.findByServiceMaster(clusterId,
-            services));
-      }
-
-      // add any alerts not bound to a service (host level alerts)
-      definitions.addAll(m_definitionDao.findAgentScoped(clusterId));
-    } catch (AmbariException ambariException) {
-      LOG.error("Unable to get alert definitions", ambariException);
-      return Collections.emptySet();
-    }
-
-    return definitions;
+  public Set<String> invalidateHosts(AlertDefinitionEntity definition) {
+    return invalidateHosts(definition.getClusterId(),
+        definition.getDefinitionName(), definition.getServiceName(),
+        definition.getComponentName());
   }
 
   /**
@@ -353,8 +287,28 @@ public class AlertDefinitionHash {
    * @return the hosts that were invalidated, or an empty set (never
    *         {@code null}).
    */
-  public Set<String> invalidateHosts(AlertDefinitionEntity definition) {
-    long clusterId = definition.getClusterId();
+  public Set<String> invalidateHosts(AlertDefinition definition) {
+    return invalidateHosts(definition.getClusterId(), definition.getName(),
+        definition.getServiceName(), definition.getComponentName());
+  }
+
+  /**
+   * Invalidate the hashes of any host that would be affected by the specified
+   * definition.
+   *
+   * @param clusterId
+   *          the cluster ID
+   * @param definitionName
+   *          the definition unique name.
+   * @param definitionServiceName
+   *          the definition's service name.
+   * @param definitionComponentName
+   *          the definition's component name.
+   * @return the hosts that were invalidated, or an empty set (never
+   *         {@code null}).
+   */
+  public Set<String> invalidateHosts(long clusterId, String definitionName,
+      String definitionServiceName, String definitionComponentName) {
     Set<String> invalidatedHosts = new HashSet<String>();
 
     Cluster cluster = null;
@@ -379,8 +333,6 @@ public class AlertDefinitionHash {
     }
 
     // intercept host agent alerts; they affect all hosts
-    String definitionServiceName = definition.getServiceName();
-    String definitionComponentName = definition.getComponentName();
     if (Services.AMBARI.equals(definitionServiceName)
         && Components.AMBARI_AGENT.equals(definitionComponentName)) {
 
@@ -413,7 +365,7 @@ public class AlertDefinitionHash {
     Service service = services.get(definitionServiceName);
     if (null == service) {
       LOG.warn("The alert definition {} has an unknown service of {}",
-          definition.getDefinitionName(), definitionServiceName);
+          definitionName, definitionServiceName);
 
       return invalidatedHosts;
     }
@@ -439,6 +391,82 @@ public class AlertDefinitionHash {
   }
 
   /**
+   * Enqueue {@link AlertDefinitionCommand}s for every host specified so that
+   * they will receive a payload of alert definitions that they should be
+   * running.
+   * <p/>
+   * This method is typically called after
+   * {@link #invalidateHosts(AlertDefinitionEntity)} has caused a cache
+   * invalidation of the alert definition hash.
+   *
+   * @param clusterName
+   *          the name of the cluster (not {@code null}).
+   * @param hosts
+   *          the hosts to push {@link AlertDefinitionCommand}s for.
+   */
+  public void enqueueAgentCommands(long clusterId, Set<String> hosts) {
+    String clusterName = null;
+
+    try {
+      Cluster cluster = m_clusters.getClusterById(clusterId);
+      clusterName = cluster.getClusterName();
+    } catch (AmbariException ae) {
+      LOG.error("Unable to lookup cluster for alert definition commands", ae);
+    }
+
+    enqueueAgentCommands(clusterName, hosts);
+  }
+
+  /**
+   * Enqueue {@link AlertDefinitionCommand}s for every host specified so that
+   * they will receive a payload of alert definitions that they should be
+   * running.
+   * <p/>
+   * This method is typically called after
+   * {@link #invalidateHosts(AlertDefinitionEntity)} has caused a cache
+   * invalidation of the alert definition hash.
+   *
+   * @param clusterName
+   *          the name of the cluster (not {@code null}).
+   * @param hosts
+   *          the hosts to push {@link AlertDefinitionCommand}s for.
+   */
+  public void enqueueAgentCommands(String clusterName, Set<String> hosts) {
+    if (null == clusterName) {
+      LOG.warn("Unable to create alert definition agent commands because of a null cluster name");
+      return;
+    }
+
+    if (null == hosts || hosts.size() == 0) {
+      return;
+    }
+
+    for (String hostName : hosts) {
+      List<AlertDefinition> definitions = getAlertDefinitions(clusterName,
+          hostName);
+
+      String hash = getHash(clusterName, hostName);
+
+      AlertDefinitionCommand command = new AlertDefinitionCommand(clusterName,
+          hostName, hash, definitions);
+
+      try {
+        Cluster cluster = m_clusters.getCluster(clusterName);
+        command.addConfigs(m_configHelper.get(), cluster);
+      } catch (AmbariException ae) {
+        LOG.warn("Unable to add configurations to alert definition command", ae);
+      }
+
+      // unlike other commands, the alert definitions commands are really
+      // designed to be 1:1 per change; if multiple invalidations happened
+      // before the next heartbeat, there would be several commands that would
+      // force the agents to reschedule their alerts more than once
+      m_actionQueue.dequeue(hostName, AgentCommandType.ALERT_DEFINITION_COMMAND);
+      m_actionQueue.enqueue(hostName, command);
+    }
+  }
+
+  /**
    * Calculates a unique hash value representing all of the alert definitions
    * that should be scheduled to run on a given host. Alerts of type
    * {@link SourceType#AGGREGATE} are not included in the hash since they are
@@ -492,51 +520,84 @@ public class AlertDefinitionHash {
   }
 
   /**
-   * Enqueue {@link AlertDefinitionCommand}s for every host specified so that
-   * they will receive a payload of alert definitions that they should be
-   * running.
-   * <p/>
-   * This method is typically called after
-   * {@link #invalidateHosts(AlertDefinitionEntity)} has caused a cache
-   * invalidation of the alert definition hash.
+   * Gets the alert definition entities for the specified host. This will include the
+   * following types of alert definitions:
+   * <ul>
+   * <li>Service/Component alerts</li>
+   * <li>Service alerts where the host is a MASTER</li>
+   * <li>Host alerts that are not bound to a service</li>
+   * </ul>
    *
    * @param clusterName
-   *          the name of the cluster (not {@code null}).
-   * @param hosts
-   *          the hosts to push {@link AlertDefinitionCommand}s for.
+   *          the cluster name (not {@code null}).
+   * @param hostName
+   *          the host name (not {@code null}).
+   * @return the alert definitions for the host, or an empty set (never
+   *         {@code null}).
    */
-  public void enqueueAgentCommands(String clusterName, Set<String> hosts) {
-    if (null == clusterName) {
-      LOG.warn("Unable to create alert definition agent commands because of a null cluster name");
-      return;
-    }
+  private Set<AlertDefinitionEntity> getAlertDefinitionEntities(
+      String clusterName,
+      String hostName) {
+    Set<AlertDefinitionEntity> definitions = new HashSet<AlertDefinitionEntity>();
 
-    if (null == hosts || hosts.size() == 0) {
-      return;
-    }
+    try {
+      Cluster cluster = m_clusters.getCluster(clusterName);
+      if (null == cluster) {
+        LOG.warn("Unable to get alert definitions for the missing cluster {}",
+            clusterName);
 
-    for (String hostName : hosts) {
-      List<AlertDefinition> definitions = getAlertDefinitions(clusterName,
-          hostName);
+        return Collections.emptySet();
+      }
 
-      String hash = getHash(clusterName, hostName);
+      long clusterId = cluster.getClusterId();
+      List<ServiceComponentHost> serviceComponents = cluster.getServiceComponentHosts(hostName);
+      if (null == serviceComponents || serviceComponents.size() == 0) {
+        LOG.warn(
+            "Unable to get alert definitions for {} since there are no service components defined",
+            hostName);
 
-      AlertDefinitionCommand command = new AlertDefinitionCommand(clusterName,
-          hostName, hash, definitions);
+        return Collections.emptySet();
+      }
 
-      try {
-        Cluster cluster = m_clusters.getCluster(clusterName);
-        command.addConfigs(m_configHelper.get(), cluster);
-      } catch (AmbariException ae) {
-        LOG.warn("Unable to add configurations to alert definition command", ae);
+      for (ServiceComponentHost serviceComponent : serviceComponents) {
+        String serviceName = serviceComponent.getServiceName();
+        String componentName = serviceComponent.getServiceComponentName();
+
+        // add all alerts for this service/component pair
+        definitions.addAll(m_definitionDao.findByServiceComponent(
+            clusterId, serviceName, componentName));
       }
 
-      // unlike other commands, the alert definitions commands are really
-      // designed to be 1:1 per change; if multiple invalidations happened
-      // before the next heartbeat, there would be several commands that would
-      // force the agents to reschedule their alerts more than once
-      m_actionQueue.dequeue(hostName, AgentCommandType.ALERT_DEFINITION_COMMAND);
-      m_actionQueue.enqueue(hostName, command);
+      // for every service, get the master components and see if the host
+      // is a master
+      Set<String> services = new HashSet<String>();
+      for (Entry<String, Service> entry : cluster.getServices().entrySet()) {
+        Service service = entry.getValue();
+        Map<String, ServiceComponent> components = service.getServiceComponents();
+        for (Entry<String, ServiceComponent> component : components.entrySet()) {
+          if (component.getValue().isMasterComponent()) {
+            Map<String, ServiceComponentHost> hosts = component.getValue().getServiceComponentHosts();
+
+            if( hosts.containsKey( hostName ) ){
+              services.add(service.getName());
+            }
+          }
+        }
+      }
+
+      // add all service scoped alerts
+      if( services.size() > 0 ){
+        definitions.addAll(m_definitionDao.findByServiceMaster(clusterId,
+            services));
+      }
+
+      // add any alerts not bound to a service (host level alerts)
+      definitions.addAll(m_definitionDao.findAgentScoped(clusterId));
+    } catch (AmbariException ambariException) {
+      LOG.error("Unable to get alert definitions", ambariException);
+      return Collections.emptySet();
     }
+
+    return definitions;
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/7db82c92/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java
index 5583617..771bf8a 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java
@@ -383,6 +383,93 @@ public class AlertGroupResourceProviderTest {
   }
 
   /**
+   * Tests that updating a default group doesn't change read-only properties
+   *
+   * @throws Exception
+   */
+  @Test
+  @SuppressWarnings("unchecked")
+  public void testUpdateDefaultGroup() throws Exception {
+    Capture<AlertGroupEntity> entityCapture = new Capture<AlertGroupEntity>();
+
+    // the definition IDs to associate with the group
+    List<Long> definitionIds = new ArrayList<Long>();
+    definitionIds.add(ALERT_DEF_ID);
+
+    // the target IDs to associate with the group
+    List<Long> targetIds = new ArrayList<Long>();
+    targetIds.add(ALERT_TARGET_ID);
+
+    // definition entities to return from DAO
+    List<AlertDefinitionEntity> definitionEntities = new ArrayList<AlertDefinitionEntity>();
+    definitionEntities.addAll(getMockDefinitions());
+
+    // target entities to return from DAO
+    List<AlertTargetEntity> newTargetEntities = new ArrayList<AlertTargetEntity>();
+    newTargetEntities.addAll(getMockTargets());
+
+    Set<AlertTargetEntity> mockTargets2 = getMockTargets();
+    AlertTargetEntity target2 = mockTargets2.iterator().next();
+    target2.setTargetId(29L);
+
+    newTargetEntities.add(target2);
+
+    AlertGroupEntity group = new AlertGroupEntity();
+    group.setDefault(true);
+    group.setGroupName(ALERT_GROUP_NAME);
+    group.setAlertDefinitions(getMockDefinitions());
+    group.setAlertTargets(getMockTargets());
+
+    expect(m_dao.findGroupById(ALERT_GROUP_ID)).andReturn(group).times(1);
+    expect(m_dao.merge(capture(entityCapture))).andReturn(group).once();
+
+    // expect target entity lookup for association
+    List<Long> newTargets = Arrays.asList(28L, 29L);
+    expect(m_dao.findTargetsById(EasyMock.eq(newTargets))).andReturn(
+        newTargetEntities).once();
+
+    replay(m_dao, m_definitionDao);
+
+    AlertGroupResourceProvider provider = createProvider(m_amc);
+
+    // create new properties, and include the ID since we're not going through
+    // a service layer which would add it for us automatically
+    Map<String, Object> requestProps = new HashMap<String, Object>();
+    requestProps.put(AlertGroupResourceProvider.ALERT_GROUP_ID,
+        ALERT_GROUP_ID.toString());
+
+    // try to change the name (it should not work)
+    String newName = ALERT_GROUP_NAME + " Foo";
+    requestProps.put(AlertGroupResourceProvider.ALERT_GROUP_NAME, newName);
+
+    // try to change the definitions (it should not work)
+    requestProps.put(AlertGroupResourceProvider.ALERT_GROUP_DEFINITIONS,
+        new ArrayList<Long>());
+
+    // try to change the targets (it should work)
+    requestProps.put(AlertGroupResourceProvider.ALERT_GROUP_TARGETS,
+        newTargets);
+
+    Predicate predicate = new PredicateBuilder().property(
+        AlertGroupResourceProvider.ALERT_GROUP_CLUSTER_NAME).equals(
+        ALERT_GROUP_CLUSTER_NAME).and().property(
+        AlertGroupResourceProvider.ALERT_GROUP_ID).equals(
+        ALERT_GROUP_ID.toString()).toPredicate();
+
+    Request request = PropertyHelper.getUpdateRequest(requestProps, null);
+    provider.updateResources(request, predicate);
+
+    assertTrue(entityCapture.hasCaptured());
+
+    AlertGroupEntity entity = entityCapture.getValue();
+    assertEquals(ALERT_GROUP_NAME, entity.getGroupName());
+    assertEquals(2, entity.getAlertTargets().size());
+    assertEquals(1, entity.getAlertDefinitions().size());
+
+    verify(m_dao, m_definitionDao);
+  }
+
+  /**
    * @throws Exception
    */
   @Test

http://git-wip-us.apache.org/repos/asf/ambari/blob/7db82c92/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
index 4d182cc..a1cd063 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
@@ -118,7 +118,7 @@ public class AlertDefinitionDAOTest {
       definition.setHash(UUID.randomUUID().toString());
       definition.setScheduleInterval(60);
       definition.setScope(Scope.SERVICE);
-      definition.setSource("Source " + i);
+      definition.setSource("{\"type\" : \"SCRIPT\"}");
       definition.setSourceType(SourceType.SCRIPT);
       dao.create(definition);
     }
@@ -133,7 +133,7 @@ public class AlertDefinitionDAOTest {
       definition.setHash(UUID.randomUUID().toString());
       definition.setScheduleInterval(60);
       definition.setScope(Scope.HOST);
-      definition.setSource("Source " + i);
+      definition.setSource("{\"type\" : \"SCRIPT\"}");
       definition.setSourceType(SourceType.SCRIPT);
       dao.create(definition);
     }
@@ -148,7 +148,7 @@ public class AlertDefinitionDAOTest {
       definition.setHash(UUID.randomUUID().toString());
       definition.setScheduleInterval(60);
       definition.setScope(Scope.HOST);
-      definition.setSource("Source " + i);
+      definition.setSource("{\"type\" : \"SCRIPT\"}");
       definition.setSourceType(SourceType.SCRIPT);
       dao.create(definition);
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/7db82c92/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertDefinitionEqualityTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertDefinitionEqualityTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertDefinitionEqualityTest.java
index fd18134..1ee1224 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertDefinitionEqualityTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertDefinitionEqualityTest.java
@@ -72,6 +72,7 @@ public class AlertDefinitionEqualityTest extends TestCase {
    */
   private AlertDefinition getAlertDefinition(SourceType sourceType) {
     AlertDefinition definition = new AlertDefinition();
+    definition.setClusterId(1);
     definition.setComponentName("component");
     definition.setEnabled(true);
     definition.setInterval(1);

http://git-wip-us.apache.org/repos/asf/ambari/blob/7db82c92/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertEventPublisherTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertEventPublisherTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertEventPublisherTest.java
index 482b5ef..7309851 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertEventPublisherTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertEventPublisherTest.java
@@ -17,13 +17,20 @@
  */
 package org.apache.ambari.server.state.alerts;
 
+import java.lang.reflect.Field;
+
 import junit.framework.Assert;
 
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.events.AlertDefinitionDeleteEvent;
 import org.apache.ambari.server.events.AmbariEvent;
+import org.apache.ambari.server.events.listeners.AlertLifecycleListener;
 import org.apache.ambari.server.events.listeners.AlertServiceStateListener;
+import org.apache.ambari.server.events.listeners.AlertStateChangedListener;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
+import org.apache.ambari.server.orm.OrmTestHelper;
 import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
 import org.apache.ambari.server.orm.dao.AlertDispatchDAO;
 import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
@@ -33,10 +40,15 @@ import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.Service;
 import org.apache.ambari.server.state.ServiceFactory;
 import org.apache.ambari.server.state.StackId;
+import org.apache.ambari.server.state.alert.AggregateDefinitionMapping;
+import org.apache.ambari.server.state.alert.AggregateSource;
+import org.apache.ambari.server.state.alert.AlertDefinition;
+import org.apache.ambari.server.state.alert.Scope;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
+import com.google.common.eventbus.EventBus;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.persist.PersistService;
@@ -55,6 +67,9 @@ public class AlertEventPublisherTest {
   private Injector injector;
   private ServiceFactory serviceFactory;
   private AmbariMetaInfo metaInfo;
+  private OrmTestHelper ormHelper;
+  private AggregateDefinitionMapping aggregateMapping;
+  private AmbariEventPublisher eventPublisher;
 
   /**
    *
@@ -64,13 +79,25 @@ public class AlertEventPublisherTest {
     injector = Guice.createInjector(new InMemoryDefaultTestModule());
     injector.getInstance(GuiceJpaInitializer.class);
 
+    eventPublisher = injector.getInstance(AmbariEventPublisher.class);
+    EventBus synchronizedBus = new EventBus();
+
     // force singleton init via Guice so the listener registers with the bus
-    injector.getInstance(AlertServiceStateListener.class);
+    synchronizedBus.register(injector.getInstance(AlertLifecycleListener.class));
+    synchronizedBus.register(injector.getInstance(AlertStateChangedListener.class));
+    synchronizedBus.register(injector.getInstance(AlertServiceStateListener.class));
+
+    // !!! need a synchronous op for testing
+    Field field = AmbariEventPublisher.class.getDeclaredField("m_eventBus");
+    field.setAccessible(true);
+    field.set(eventPublisher, synchronizedBus);
 
     dispatchDao = injector.getInstance(AlertDispatchDAO.class);
     definitionDao = injector.getInstance(AlertDefinitionDAO.class);
     clusters = injector.getInstance(Clusters.class);
     serviceFactory = injector.getInstance(ServiceFactory.class);
+    ormHelper = injector.getInstance(OrmTestHelper.class);
+    aggregateMapping = injector.getInstance(AggregateDefinitionMapping.class);
 
     metaInfo = injector.getInstance(AmbariMetaInfo.class);
     metaInfo.init();
@@ -107,7 +134,7 @@ public class AlertEventPublisherTest {
   /**
    * Tests that all {@link AlertDefinitionEntity} instances are created for the
    * installed service.
-   * 
+   *
    * @throws Exception
    */
   @Test
@@ -118,6 +145,43 @@ public class AlertEventPublisherTest {
   }
 
   /**
+   * Tests that {@link AlertDefinitionDeleteEvent} instances are fired when a
+   * definition is removed.
+   *
+   * @throws Exception
+   */
+  @Test
+  public void testAlertDefinitionRemoval() throws Exception {
+    Assert.assertEquals(0, definitionDao.findAll().size());
+    AlertDefinitionEntity definition = ormHelper.createAlertDefinition(1L);
+    Assert.assertEquals(1, definitionDao.findAll().size());
+
+    AggregateSource source = new AggregateSource();
+    source.setAlertName(definition.getDefinitionName());
+
+    AlertDefinition aggregate = new AlertDefinition();
+    aggregate.setClusterId(1L);
+    aggregate.setComponentName("DATANODE");
+    aggregate.setEnabled(true);
+    aggregate.setInterval(1);
+    aggregate.setLabel("DataNode Aggregate");
+    aggregate.setName("datanode_aggregate");
+    aggregate.setScope(Scope.ANY);
+    aggregate.setServiceName("HDFS");
+    aggregate.setSource(source);
+    aggregate.setUuid("uuid");
+
+    aggregateMapping.registerAggregate(1L, aggregate);
+    Assert.assertNotNull(aggregateMapping.getAggregateDefinition(1L,
+        source.getAlertName()));
+
+    definitionDao.remove(definition);
+
+    Assert.assertNull(aggregateMapping.getAggregateDefinition(1L,
+        source.getAlertName()));
+  }
+
+  /**
    * Calls {@link Service#persist()} to mock a service install.
    */
   private void installHdfsService() throws Exception {

http://git-wip-us.apache.org/repos/asf/ambari/blob/7db82c92/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertStateChangedEventTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertStateChangedEventTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertStateChangedEventTest.java
index 312f297..18b4123 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertStateChangedEventTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertStateChangedEventTest.java
@@ -17,6 +17,7 @@
  */
 package org.apache.ambari.server.state.alerts;
 
+import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
@@ -39,6 +40,7 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
+import com.google.common.eventbus.EventBus;
 import com.google.inject.Binder;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
@@ -72,6 +74,14 @@ public class AlertStateChangedEventTest {
 
     dispatchDao = injector.getInstance(AlertDispatchDAO.class);
     eventPublisher = injector.getInstance(AlertEventPublisher.class);
+
+    EventBus synchronizedBus = new EventBus();
+    synchronizedBus.register(injector.getInstance(AlertStateChangedListener.class));
+
+    // !!! need a synchronous op for testing
+    Field field = AlertEventPublisher.class.getDeclaredField("m_eventBus");
+    field.setAccessible(true);
+    field.set(eventPublisher, synchronizedBus);
   }
 
   /**
@@ -99,8 +109,6 @@ public class AlertStateChangedEventTest {
 
     // async publishing
     eventPublisher.publish(event);
-    Thread.sleep(2000);
-
     EasyMock.verify(dispatchDao, history, event);
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/7db82c92/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java
index 85a6e9b..502c3b9 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java
@@ -373,7 +373,7 @@ public class AlertDataManagerTest {
     AggregateDefinitionMapping aggregateMapping = injector.getInstance(AggregateDefinitionMapping.class);
 
     AlertDefinition aggregateDefinition = factory.coerce(aggDef);
-    aggregateMapping.addAggregateType(clusterId.longValue(),
+    aggregateMapping.registerAggregate(clusterId.longValue(),
         aggregateDefinition );
 
     AggregateSource as = (AggregateSource) aggregateDefinition.getSource();


[32/50] [abbrv] git commit: Merge branch 'trunk' into branch-alerts-dev

Posted by jo...@apache.org.
Merge branch 'trunk' into branch-alerts-dev


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

Branch: refs/heads/trunk
Commit: e6cc05872462d53f9b420837f129921d0e2e0b24
Parents: 7f86e75 802df76
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Mon Sep 22 10:47:55 2014 -0700
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Mon Sep 22 10:47:55 2014 -0700

----------------------------------------------------------------------
 ambari-server/pom.xml                           |  22 ++++
 .../internal/ClientConfigResourceProvider.java  |  33 ++++-
 .../internal/ConfigGroupResourceProvider.java   |  15 ++-
 .../server/upgrade/UpgradeCatalog170.java       |  68 +++++-----
 .../main/resources/slider_resources/README.txt  |  17 +++
 .../services/GANGLIA/package/scripts/params.py  |   5 +-
 .../services/GANGLIA/package/scripts/params.py  |   6 +-
 .../services/OOZIE/package/scripts/oozie.py     |  10 +-
 .../services/OOZIE/package/scripts/params.py    |  13 +-
 .../services/SQOOP/package/scripts/params.py    |   2 +
 .../SQOOP/package/scripts/service_check.py      |   1 +
 .../services/FALCON/package/scripts/falcon.py   |   4 +
 .../services/STORM/configuration/storm-site.xml |   6 +-
 .../services/SLIDER/package/scripts/slider.py   |   3 +-
 .../services/STORM/configuration/storm-site.xml |   6 +-
 .../ClientConfigResourceProviderTest.java       |   9 +-
 .../ConfigGroupResourceProviderTest.java        |  37 +++++-
 .../server/upgrade/UpgradeCatalog170Test.java   | 125 ++++++++++++-------
 .../stacks/2.0.6/OOZIE/test_oozie_client.py     |  18 +--
 .../stacks/2.0.6/OOZIE/test_oozie_server.py     |  18 +--
 .../stacks/2.0.6/SQOOP/test_service_check.py    |   2 +
 .../stacks/2.1/FALCON/test_falcon_client.py     |   4 +
 .../stacks/2.1/FALCON/test_falcon_server.py     |   4 +
 .../stacks/2.2/SLIDER/test_slider_client.py     |   4 +-
 .../main/dashboard/config_history_controller.js |   1 +
 ambari-web/app/controllers/main/service/item.js |  28 ++++-
 ambari-web/app/templates/main/host/details.hbs  |   2 +-
 ambari-web/app/templates/main/service/item.hbs  |  13 +-
 ambari-web/app/views/common/filter_view.js      |  74 ++++++++++-
 .../views/main/dashboard/config_history_view.js |  10 +-
 ambari-web/app/views/main/service/item.js       |   6 +-
 contrib/views/slider/docs/index.md              |  63 ++++++++++
 .../view/slider/SliderAppsViewController.java   |   8 ++
 .../slider/SliderAppsViewControllerImpl.java    |  69 +++++-----
 .../assets/data/resource/slider-properties.json |   7 +-
 .../ui/app/controllers/slider_controller.js     |  20 ++-
 .../src/main/resources/ui/app/helpers/ajax.js   |   7 +-
 .../resources/ui/app/models/slider_config.js    |   8 +-
 .../src/main/resources/ui/app/routes/main.js    |   7 +-
 .../src/main/resources/ui/app/translations.js   |   1 +
 .../views/slider/src/main/resources/view.xml    |  25 ++++
 41 files changed, 596 insertions(+), 185 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/e6cc0587/ambari-server/pom.xml
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/e6cc0587/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
----------------------------------------------------------------------


[36/50] [abbrv] git commit: Merge branch 'trunk' into branch-alerts-dev

Posted by jo...@apache.org.
Merge branch 'trunk' into branch-alerts-dev


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

Branch: refs/heads/trunk
Commit: 24483521f96f395b61b786e12c444901c90073c7
Parents: ae9bf4c 7d6731b
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Wed Sep 24 13:50:41 2014 -0700
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Wed Sep 24 13:50:41 2014 -0700

----------------------------------------------------------------------
 .../TestExecuteHadoopResource.py                |   14 +-
 .../libraries/resources/execute_hadoop.py       |    2 +-
 .../server/configuration/Configuration.java     |   14 +-
 .../BlueprintConfigurationProcessor.java        |   28 +-
 .../ambari/server/orm/dao/PermissionDAO.java    |   25 +-
 .../server/security/authorization/Users.java    |   24 +-
 .../server/upgrade/UpgradeCatalog170.java       |   33 +
 ambari-server/src/main/python/ambari-server.py  |   14 +-
 .../services/HBASE/package/scripts/params.py    |    3 +-
 .../HBASE/package/scripts/service_check.py      |    4 +-
 .../stacks/HDP/1.3.2/services/HIVE/metainfo.xml |    2 +-
 .../OOZIE/configuration/oozie-log4j.xml         |    2 +-
 .../stacks/HDP/2.0.6.GlusterFS/metainfo.xml     |    6 +-
 .../HDP/2.0.6.GlusterFS/repos/repoinfo.xml      |   39 +
 .../HDP/2.0.6.GlusterFS/role_command_order.json |   30 +-
 .../GLUSTERFS/configuration/core-site.xml       |  272 +-
 .../services/GLUSTERFS/configuration/global.xml |   35 -
 .../GLUSTERFS/configuration/hadoop-env.xml      |  209 +
 .../services/GLUSTERFS/metainfo.xml             |   36 +-
 .../services/HBASE/configuration/hbase-site.xml |  370 +
 .../2.0.6.GlusterFS/services/HBASE/metainfo.xml |   34 +
 .../2.0.6.GlusterFS/services/HDFS/metainfo.xml  |   46 +-
 .../2.0.6.GlusterFS/services/HDFS/metrics.json  | 7840 ------------------
 .../services/HIVE/configuration/hive-site.xml   |  502 ++
 .../HIVE/etc/hive-schema-0.13.0.mysql.sql       |  889 ++
 .../HIVE/etc/hive-schema-0.13.0.oracle.sql      |  835 ++
 .../HIVE/etc/hive-schema-0.13.0.postgres.sql    | 1538 ++++
 .../etc/upgrade-0.12.0-to-0.13.0.oracle.sql     |  165 +
 .../services/HIVE/etc/upgrade-0.13.0.oracle.sql |   38 +
 .../2.0.6.GlusterFS/services/HIVE/metainfo.xml  |  100 +
 .../services/OOZIE/configuration/oozie-site.xml |  313 +
 .../2.0.6.GlusterFS/services/OOZIE/metainfo.xml |   78 +
 .../PIG/configuration/pig-properties.xml        |   91 +
 .../2.0.6.GlusterFS/services/PIG/metainfo.xml   |   27 +
 .../2.0.6.GlusterFS/services/SQOOP/metainfo.xml |   32 +
 .../YARN/configuration-mapred/core-site.xml.2   |   20 +
 .../YARN/configuration-mapred/mapred-site.xml   |   88 +
 .../YARN/configuration-mapred/mapred-site.xml.2 |   68 +
 .../YARN/configuration/capacity-scheduler.xml   |  124 +
 .../YARN/configuration/mapred-site.xml.2        |   68 +
 .../services/YARN/configuration/yarn-env.xml    |  181 +
 .../services/YARN/configuration/yarn-site.xml   |  413 +
 .../2.0.6.GlusterFS/services/YARN/metainfo.xml  |  143 +
 .../2.0.6.GlusterFS/services/YARN/metrics.json  | 2534 ++++++
 .../files/validateYarnComponentStatus.py        |  170 +
 .../services/YARN/package/scripts/__init__.py   |   20 +
 .../scripts/application_timeline_server.py      |   55 +
 .../YARN/package/scripts/historyserver.py       |   53 +
 .../package/scripts/mapred_service_check.py     |   73 +
 .../YARN/package/scripts/mapreduce2_client.py   |   42 +
 .../YARN/package/scripts/nodemanager.py         |   59 +
 .../services/YARN/package/scripts/params.py     |  143 +
 .../YARN/package/scripts/resourcemanager.py     |   90 +
 .../services/YARN/package/scripts/service.py    |   62 +
 .../YARN/package/scripts/service_check.py       |   67 +
 .../YARN/package/scripts/status_params.py       |   35 +
 .../services/YARN/package/scripts/yarn.py       |  163 +
 .../YARN/package/scripts/yarn_client.py         |   42 +
 .../package/templates/container-executor.cfg.j2 |   22 +
 .../YARN/package/templates/mapreduce.conf.j2    |   17 +
 .../YARN/package/templates/yarn-env.sh.j2       |  128 +
 .../YARN/package/templates/yarn.conf.j2         |   17 +
 .../services/ZOOKEEPER/metainfo.xml             |   28 +
 .../services/HBASE/package/scripts/params.py    |    3 +-
 .../stacks/HDP/2.0.6/services/HIVE/metainfo.xml |    2 +-
 .../NAGIOS/package/files/nagios_alerts.php      |    2 +-
 .../OOZIE/configuration/oozie-log4j.xml         |    2 +-
 .../package/templates/oozie-log4j.properties.j2 |    2 +-
 .../scripts/application_timeline_server.py      |    2 +-
 .../services/STORM/package/scripts/params.py    |    5 +-
 .../services/STORM/package/scripts/service.py   |   10 +-
 .../STORM/package/scripts/service_check.py      |    6 +-
 .../services/STORM/configuration/storm-site.xml |   12 +-
 .../src/main/resources/stacks/stack_advisor.py  |  270 +-
 .../BlueprintConfigurationProcessorTest.java    |   54 +-
 .../security/authorization/TestUsers.java       |  112 +-
 .../server/upgrade/UpgradeCatalog170Test.java   |    2 +
 .../src/test/python/TestAmbariServer.py         |    3 +-
 ambari-server/src/test/python/ldap-password.dat |    1 +
 .../python/stacks/1.3.2/HDFS/test_namenode.py   |   37 +
 .../stacks/1.3.2/HDFS/test_service_check.py     |   75 +-
 .../python/stacks/1.3.2/configs/secured.json    |    5 +-
 .../python/stacks/2.0.6/HDFS/test_namenode.py   |   25 +-
 .../stacks/2.0.6/YARN/test_resourcemanager.py   |   36 +
 .../python/stacks/2.0.6/configs/default.json    |    1 +
 .../python/stacks/2.0.6/configs/secured.json    |    6 +-
 .../stacks/2.1/STORM/test_service_check.py      |    5 +-
 .../stacks/2.1/STORM/test_storm_drpc_server.py  |    8 +-
 .../stacks/2.1/STORM/test_storm_nimbus.py       |    8 +-
 .../2.1/STORM/test_storm_rest_api_service.py    |    8 +-
 .../stacks/2.1/STORM/test_storm_supervisor.py   |   16 +-
 .../2.1/STORM/test_storm_supervisor_prod.py     |    8 +-
 .../stacks/2.1/STORM/test_storm_ui_server.py    |    8 +-
 .../stacks/2.1/YARN/test_apptimelineserver.py   |   14 +
 ambari-web/app/controllers/installer.js         |   20 +-
 .../security/security_progress_controller.js    |   27 -
 .../main/mirroring/jobs_controller.js           |    2 +-
 .../controllers/main/service/info/configs.js    |   21 +-
 .../app/controllers/wizard/step7_controller.js  |    8 +-
 .../app/controllers/wizard/step8_controller.js  |   24 +-
 ambari-web/app/data/HDP2/secure_properties.js   |    1 +
 ambari-web/app/data/secure_properties.js        |    1 +
 ambari-web/app/mappers/users_mapper.js          |   12 +
 ambari-web/app/models/user.js                   |    1 +
 ambari-web/app/router.js                        |   14 +-
 ambari-web/app/utils/config.js                  |  107 +-
 ambari-web/app/utils/helper.js                  |    2 +-
 ambari-web/app/views/wizard/controls_view.js    |   21 +-
 .../security_progress_controller_test.js        |   71 -
 .../main/service/info/config_test.js            |    9 +-
 .../test/controllers/wizard/step8_test.js       |   34 +-
 ambari-web/test/utils/config_test.js            |   38 +-
 .../slider-agent/0.51.0/slider-agent-0.51.0.pom |   25 +
 .../0.51.0/slider-agent-0.51.0.tar.gz           |  Bin 0 -> 472393 bytes
 .../slider-agent/maven-metadata-local.xml       |   28 +
 .../slider-core/0.51.0/slider-core-0.51.0.jar   |  Bin 1144236 -> 1146908 bytes
 .../slider/slider-core/maven-metadata-local.xml |    2 +-
 contrib/views/slider/lib/slider-agent.tar.gz    |  Bin 480985 -> 0 bytes
 contrib/views/slider/pom.xml                    |   29 +-
 .../slider/SliderAppsViewControllerImpl.java    |   27 +-
 .../resources/ui/app/assets/data/apps/apps.json |  475 ++
 .../createAppWizard/step1_controller.js         |   37 +-
 .../createAppWizard/step3_controller.js         |    1 +
 .../ui/app/controllers/slider_controller.js     |   36 +
 .../main/resources/ui/app/models/slider_app.js  |   11 +-
 .../resources/ui/app/styles/application.less    |   37 +-
 .../ui/app/templates/common/app_tooltip.hbs     |   12 +-
 .../ui/app/templates/createAppWizard/step1.hbs  |   41 +-
 .../ui/app/templates/slider_app/summary.hbs     |   95 +-
 .../ui/app/templates/slider_title_tooltip.hbs   |    3 -
 .../src/main/resources/ui/app/translations.js   |    8 +-
 .../resources/ui/app/views/application_view.js  |   11 +-
 .../resources/ui/app/views/common/chart_view.js |    6 +-
 .../views/slider_app/metrics/app_metric_view.js |    2 +-
 .../ui/app/views/slider_app/summary_view.js     |   68 +-
 .../resources/ui/app/views/slider_apps_view.js  |    1 +
 ...test-patch-find-new-patch-available-jiras.sh |  126 +
 dev-support/test-patch.sh                       | 1077 +++
 138 files changed, 13120 insertions(+), 8814 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/24483521/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
----------------------------------------------------------------------


[03/50] [abbrv] git commit: AMBARI-7021 - Alerts: Create Group and Target REST Endpoints (jonathanhurley)

Posted by jo...@apache.org.
AMBARI-7021 - Alerts: Create Group and Target REST Endpoints (jonathanhurley)


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

Branch: refs/heads/trunk
Commit: 4a4644b882c9a0d39b249db5a106f7075cb0c93d
Parents: 6ba11a2
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Tue Aug 26 14:21:31 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Wed Aug 27 08:51:49 2014 -0400

----------------------------------------------------------------------
 .../python/ambari_agent/alerts/base_alert.py    |   4 +-
 .../python/ambari_agent/alerts/port_alert.py    |  11 +-
 .../ambari/server/agent/HeartBeatHandler.java   |  16 +-
 .../resources/AlertGroupResourceDefinition.java |  50 +++
 .../AlertTargetResourceDefinition.java          |  50 +++
 .../resources/ResourceInstanceFactoryImpl.java  |   8 +
 .../server/api/services/AlertGroupService.java  | 111 ++++++
 .../server/api/services/AlertTargetService.java |  96 ++++++
 .../server/api/services/ClusterService.java     |  66 +++-
 .../ambari/server/controller/AmbariServer.java  |   4 +
 .../AbstractControllerResourceProvider.java     |  10 +-
 .../internal/AlertGroupResourceProvider.java    | 268 +++++++++++++++
 .../internal/AlertTargetResourceProvider.java   | 258 ++++++++++++++
 .../ambari/server/controller/spi/Resource.java  |  13 +-
 .../ambari/server/orm/dao/AlertDispatchDAO.java |  78 +++--
 .../ambari/server/state/alert/AlertGroup.java   | 124 +++++++
 .../ambari/server/state/alert/AlertTarget.java  | 123 +++++++
 .../ambari/server/state/alert/TargetType.java   |  37 ++
 .../svccomphost/ServiceComponentHostImpl.java   |   2 +
 .../src/main/resources/key_properties.json      |   7 +
 .../src/main/resources/properties.json          |  18 +-
 .../AlertGroupResourceProviderTest.java         | 335 +++++++++++++++++++
 .../AlertTargetResourceProviderTest.java        | 290 ++++++++++++++++
 .../svccomphost/ServiceComponentHostTest.java   | 242 +++++++-------
 24 files changed, 2045 insertions(+), 176 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py b/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py
index 07987d9..88c7f92 100644
--- a/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py
+++ b/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py
@@ -34,7 +34,7 @@ class BaseAlert(object):
     self.alert_meta = alert_meta
     self.alert_source_meta = alert_source_meta
     self.cluster = ''
-    self.hostname = ''
+    self.hostName = ''
     self._lookup_keys = []
     
     
@@ -54,7 +54,7 @@ class BaseAlert(object):
   def set_cluster(self, cluster, host):
     ''' sets cluster information for the alert '''
     self.cluster = cluster
-    self.hostname = host
+    self.hostName = host
   
   def collect(self):
     ''' method used for collection.  defers to _collect() '''

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-agent/src/main/python/ambari_agent/alerts/port_alert.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/alerts/port_alert.py b/ambari-agent/src/main/python/ambari_agent/alerts/port_alert.py
index d06d1f4..eaf744a 100644
--- a/ambari-agent/src/main/python/ambari_agent/alerts/port_alert.py
+++ b/ambari-agent/src/main/python/ambari_agent/alerts/port_alert.py
@@ -22,7 +22,6 @@ import logging
 import re
 import socket
 import time
-import traceback
 from alerts.base_alert import BaseAlert
 from resource_management.libraries.functions.get_port_from_url import get_port_from_url
 
@@ -40,7 +39,7 @@ class PortAlert(BaseAlert):
   def _collect(self):
     urivalue = self._lookup_property_value(self.uri)
 
-    host = get_host_from_url(urivalue)
+    host = get_host_from_url(self, urivalue)
     port = self.port
     
     try:
@@ -76,9 +75,9 @@ Tested on the following cases:
   "hdfs://192.168.54.3/foo/bar"
   "ftp://192.168.54.4:7842/foo/bar"
 '''    
-def get_host_from_url(uri):
+def get_host_from_url(self, uri):
   # RFC3986, Appendix B
-  parts = re.findall('^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?' , uri)
+  parts = re.findall('^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?', uri)
 
   # index of parts
   # scheme    = 1
@@ -96,6 +95,10 @@ def get_host_from_url(uri):
     host_and_port = parts[0][3]
 
   if -1 == host_and_port.find(':'):
+    # if no : then it might only be a port; if it's a port, return this host
+    if host_and_port.isdigit():
+      return self.hostName
+
     return host_and_port
   else:
     return host_and_port.split(':')[0]

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
index dca3bd9..d0d5a13 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
@@ -229,11 +229,13 @@ public class HeartBeatHandler {
 
   protected void calculateHostAlerts(HeartBeat heartbeat, String hostname)
           throws AmbariException {
-      if (heartbeat != null && hostname != null) {
-        for (Cluster cluster : clusterFsm.getClustersForHost(hostname)) {
-          cluster.addAlerts(heartbeat.getNodeStatus().getAlerts());
-        }
-      }
+    if (null == hostname || null == heartbeat) {
+      return;
+    }
+
+    for (Cluster cluster : clusterFsm.getClustersForHost(hostname)) {
+      cluster.addAlerts(heartbeat.getNodeStatus().getAlerts());
+    }
   }
 
   protected void processHostStatus(HeartBeat heartbeat, String hostname) throws AmbariException {
@@ -710,7 +712,7 @@ public class HeartBeatHandler {
     response.setResponseStatus(RegistrationStatus.OK);
 
     // force the registering agent host to receive its list of alert definitions
-    List<AlertDefinitionCommand> alertDefinitionCommands = getAlertDefinitionCommands(hostname);
+    List<AlertDefinitionCommand> alertDefinitionCommands = getRegistrationAlertDefinitionCommands(hostname);
     response.setAlertDefinitionCommands(alertDefinitionCommands);
 
     Long requestId = 0L;
@@ -787,7 +789,7 @@ public class HeartBeatHandler {
    * @return
    * @throws AmbariException
    */
-  private List<AlertDefinitionCommand> getAlertDefinitionCommands(
+  private List<AlertDefinitionCommand> getRegistrationAlertDefinitionCommands(
       String hostname) throws AmbariException {
 
     Set<Cluster> hostClusters = clusterFsm.getClustersForHost(hostname);

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertGroupResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertGroupResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertGroupResourceDefinition.java
new file mode 100644
index 0000000..67e5d60
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertGroupResourceDefinition.java
@@ -0,0 +1,50 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.api.resources;
+
+import org.apache.ambari.server.controller.spi.Resource;
+
+/**
+ * The {@link AlertGroupResourceDefinition} class is used to register alert
+ * groups to be returned via the REST API.
+ */
+public class AlertGroupResourceDefinition extends BaseResourceDefinition {
+
+  /**
+   * Constructor.
+   */
+  public AlertGroupResourceDefinition() {
+    super(Resource.Type.AlertGroup);
+  }
+
+  /**
+   *
+   */
+  @Override
+  public String getPluralName() {
+    return "alert_groups";
+  }
+
+  /**
+   *
+   */
+  @Override
+  public String getSingularName() {
+    return "alert_group";
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertTargetResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertTargetResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertTargetResourceDefinition.java
new file mode 100644
index 0000000..bc0d81d
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertTargetResourceDefinition.java
@@ -0,0 +1,50 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.api.resources;
+
+import org.apache.ambari.server.controller.spi.Resource;
+
+/**
+ * The {@link AlertTargetResourceDefinition} class is used to register alert
+ * targets to be returned via the REST API.
+ */
+public class AlertTargetResourceDefinition extends BaseResourceDefinition {
+
+  /**
+   * Constructor.
+   */
+  public AlertTargetResourceDefinition() {
+    super(Resource.Type.AlertTarget);
+  }
+
+  /**
+   *
+   */
+  @Override
+  public String getPluralName() {
+    return "alert_targets";
+  }
+
+  /**
+   *
+   */
+  @Override
+  public String getSingularName() {
+    return "alert_target";
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
index 13fff1d..7faf365 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
@@ -251,6 +251,14 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
         resourceDefinition = new AlertDefResourceDefinition();
         break;
 
+      case AlertGroup:
+        resourceDefinition = new AlertGroupResourceDefinition();
+        break;
+
+      case AlertTarget:
+        resourceDefinition = new AlertTargetResourceDefinition();
+        break;
+
       case AmbariPrivilege:
         resourceDefinition = new PrivilegeResourceDefinition(Resource.Type.AmbariPrivilege);
         break;

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertGroupService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertGroupService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertGroupService.java
new file mode 100644
index 0000000..c2e5048
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertGroupService.java
@@ -0,0 +1,111 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.api.services;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.state.alert.AlertGroup;
+
+/**
+ * The {@link AlertGroupService} handles CRUD operations for a cluster's alert
+ * groups.
+ */
+public class AlertGroupService extends BaseService {
+
+  /**
+   * Cluster name for cluster-based requests
+   */
+  private String m_clusterName = null;
+
+  /**
+   * Constructor.
+   *
+   * @param clusterName
+   */
+  AlertGroupService(String clusterName) {
+    m_clusterName = clusterName;
+  }
+
+  @GET
+  @Produces("text/plain")
+  public Response getGroups(String body, @Context HttpHeaders headers,
+      @Context UriInfo ui) {
+    return handleRequest(headers, body, ui, Request.Type.GET,
+        createAlertGroupResource(m_clusterName, null));
+  }
+
+  @GET
+  @Produces("text/plain")
+  @Path("{groupId}")
+  public Response getGroup(String body, @Context HttpHeaders headers,
+      @Context UriInfo ui, @PathParam("groupId") Long groupId) {
+    return handleRequest(headers, body, ui, Request.Type.GET,
+        createAlertGroupResource(m_clusterName, groupId));
+  }
+
+  @POST
+  @Produces("text/plain")
+  public Response createGroup(String body, @Context HttpHeaders headers,
+      @Context UriInfo ui) {
+    return handleRequest(headers, body, ui, Request.Type.POST,
+        createAlertGroupResource(m_clusterName, null));
+  }
+
+  @DELETE
+  @Produces("text/plain")
+  @Path("{groupId}")
+  public Response deleteGroup(String body, @Context HttpHeaders headers,
+      @Context UriInfo ui, @PathParam("groupId") Long groupId) {
+    return handleRequest(headers, body, ui, Request.Type.DELETE,
+        createAlertGroupResource(m_clusterName, groupId));
+  }
+
+  /**
+   * Create a request capturing the group ID and resource type for an
+   * {@link AlertGroup}.
+   *
+   * @param groupId
+   *          the unique ID of the group to create the query for (not
+   *          {@code null}).
+   * @return the instance of the query.
+   */
+  private ResourceInstance createAlertGroupResource(String clusterName,
+      Long groupId) {
+
+    Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.Cluster, m_clusterName);
+    mapIds.put(Resource.Type.AlertGroup,
+        null == groupId ? null : groupId.toString());
+
+    return createResource(Resource.Type.AlertGroup, mapIds);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertTargetService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertTargetService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertTargetService.java
new file mode 100644
index 0000000..86281b3
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertTargetService.java
@@ -0,0 +1,96 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.api.services;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.state.alert.AlertTarget;
+
+/**
+ * The {@link AlertTargetService} handles CRUD operation requests for alert
+ * targets.
+ */
+@Path("/alert_targets/")
+public class AlertTargetService extends BaseService {
+
+  @GET
+  @Produces("text/plain")
+  public Response getTargets(String body, @Context HttpHeaders headers,
+      @Context UriInfo ui) {
+    return handleRequest(headers, body, ui, Request.Type.GET,
+        createAlertTargetResource(null));
+  }
+
+  @GET
+  @Produces("text/plain")
+  @Path("{targetId}")
+  public Response getTargets(String body, @Context HttpHeaders headers,
+      @Context UriInfo ui, @PathParam("targetId") Long targetId) {
+    return handleRequest(headers, body, ui, Request.Type.GET,
+        createAlertTargetResource(targetId));
+  }
+
+  @POST
+  @Produces("text/plain")
+  public Response createTarget(String body, @Context HttpHeaders headers,
+      @Context UriInfo ui) {
+    return handleRequest(headers, body, ui, Request.Type.POST,
+        createAlertTargetResource(null));
+  }
+
+  @DELETE
+  @Produces("text/plain")
+  @Path("{targetId}")
+  public Response deleteTarget(String body, @Context HttpHeaders headers,
+      @Context UriInfo ui, @PathParam("targetId") Long targetId) {
+    return handleRequest(headers, body, ui, Request.Type.DELETE,
+        createAlertTargetResource(targetId));
+  }
+
+  /**
+   * Create a request capturing the target ID and resource type for an
+   * {@link AlertTarget}.
+   *
+   * @param targetId
+   *          the unique ID of the target to create the query for (not
+   *          {@code null}).
+   * @return the instance of the query.
+   */
+  private ResourceInstance createAlertTargetResource(Long targetId) {
+    Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+
+    mapIds.put(Resource.Type.AlertTarget,
+        null == targetId ? null : targetId.toString());
+
+    return createResource(Resource.Type.AlertTarget, mapIds);
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
index 8043b3f..3f1ce36 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
@@ -18,15 +18,26 @@
 
 package org.apache.ambari.server.api.services;
 
+import java.util.Collections;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.controller.AmbariServer;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.state.Clusters;
 
-import javax.ws.rs.*;
-import javax.ws.rs.core.*;
-import java.util.Collections;
-
 
 /**
  * Service responsible for cluster resource requests.
@@ -46,7 +57,7 @@ public class ClusterService extends BaseService {
    * Construct a ClusterService.
    */
   public ClusterService() {
-    this.clusters = AmbariServer.getController().getClusters();
+    clusters = AmbariServer.getController().getClusters();
   }
 
   /**
@@ -187,7 +198,7 @@ public class ClusterService extends BaseService {
     hasPermission(Request.Type.valueOf(request.getMethod()), clusterName);
     return new ServiceService(clusterName);
   }
-  
+
   /**
    * Gets the configurations sub-resource.
    *
@@ -295,7 +306,7 @@ public class ClusterService extends BaseService {
     hasPermission(Request.Type.valueOf(request.getMethod()), clusterName);
     return new RequestScheduleService(clusterName);
   }
-  
+
   /**
    * Gets the alert definition service
    *
@@ -313,12 +324,32 @@ public class ClusterService extends BaseService {
   }
 
   /**
+   * Gets the alert group service.
+   *
+   * @param request
+   *          the request.
+   * @param clusterName
+   *          the cluster name.
+   * @return the alert group service.
+   */
+  @Path("{clusterName}/alert_groups")
+  public AlertGroupService getAlertGroups(
+      @Context javax.ws.rs.core.Request request,
+      @PathParam("clusterName") String clusterName) {
+
+    hasPermission(Request.Type.valueOf(request.getMethod()), clusterName);
+    return new AlertGroupService(clusterName);
+  }
+
+  /**
    * Gets the privilege service
    *
-   * @param request      the request
-   * @param clusterName  the cluster name
+   * @param request
+   *          the request
+   * @param clusterName
+   *          the cluster name
    *
-   * @return  the privileges service
+   * @return the privileges service
    */
   @Path("{clusterName}/privileges")
   public PrivilegeService getPrivilegeService(@Context javax.ws.rs.core.Request request, @PathParam ("clusterName") String clusterName) {
@@ -343,14 +374,17 @@ public class ClusterService extends BaseService {
   }
 
   /**
-   * Determine whether or not the access specified by the given request type
-   * is permitted for the current user on the cluster resource identified by
-   * the given cluster name.
+   * Determine whether or not the access specified by the given request type is
+   * permitted for the current user on the cluster resource identified by the
+   * given cluster name.
    *
-   * @param requestType  the request method type
-   * @param clusterName  the name of the cluster resource
+   * @param requestType
+   *          the request method type
+   * @param clusterName
+   *          the name of the cluster resource
    *
-   * @throws WebApplicationException if access is forbidden
+   * @throws WebApplicationException
+   *           if access is forbidden
    */
   private void hasPermission(Request.Type requestType, String clusterName) throws WebApplicationException {
     if (!clusters.checkPermission(clusterName, requestType == Request.Type.GET)) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
index 21c9d80..c75a7bb 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
@@ -46,6 +46,8 @@ import org.apache.ambari.server.configuration.ComponentSSLConfiguration;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.internal.AbstractControllerResourceProvider;
 import org.apache.ambari.server.controller.internal.AlertDefinitionResourceProvider;
+import org.apache.ambari.server.controller.internal.AlertGroupResourceProvider;
+import org.apache.ambari.server.controller.internal.AlertTargetResourceProvider;
 import org.apache.ambari.server.controller.internal.AmbariPrivilegeResourceProvider;
 import org.apache.ambari.server.controller.internal.BlueprintResourceProvider;
 import org.apache.ambari.server.controller.internal.ClusterPrivilegeResourceProvider;
@@ -538,6 +540,8 @@ public class AmbariServer {
     StackDependencyResourceProvider.init(ambariMetaInfo);
     ClusterResourceProvider.init(injector.getInstance(BlueprintDAO.class), ambariMetaInfo, injector.getInstance(ConfigHelper.class));
     AlertDefinitionResourceProvider.init(injector);
+    AlertGroupResourceProvider.init(injector);
+    AlertTargetResourceProvider.init(injector);
     PermissionResourceProvider.init(injector.getInstance(PermissionDAO.class));
     ViewPermissionResourceProvider.init(injector.getInstance(PermissionDAO.class));
     PrivilegeResourceProvider.init(injector.getInstance(PrivilegeDAO.class), injector.getInstance(UserDAO.class),

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
index 71ddc8d..c10d300 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
@@ -18,15 +18,15 @@
 
 package org.apache.ambari.server.controller.internal;
 
+import java.util.Map;
+import java.util.Set;
+
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.ResourceProviderFactory;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.controller.spi.ResourceProvider;
 import org.apache.ambari.server.controller.utilities.ClusterControllerHelper;
 
-import java.util.Map;
-import java.util.Set;
-
 /**
  * Abstract resource provider implementation that maps to an Ambari management controller.
  */
@@ -149,6 +149,10 @@ public abstract class AbstractControllerResourceProvider extends AbstractResourc
         return new ValidationResourceProvider(propertyIds, keyPropertyIds, managementController);
       case AlertDefinition:
         return new AlertDefinitionResourceProvider(propertyIds, keyPropertyIds, managementController);
+      case AlertGroup:
+        return new AlertGroupResourceProvider(propertyIds, keyPropertyIds, managementController);
+      case AlertTarget:
+        return new AlertTargetResourceProvider(propertyIds, keyPropertyIds, managementController);
       case Controller:
         return new ControllerResourceProvider(propertyIds, keyPropertyIds, managementController);
       case ClientConfig:

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProvider.java
new file mode 100644
index 0000000..f14e76f
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProvider.java
@@ -0,0 +1,268 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.controller.internal;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
+import org.apache.ambari.server.controller.spi.NoSuchResourceException;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.RequestStatus;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.Resource.Type;
+import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.orm.dao.AlertDispatchDAO;
+import org.apache.ambari.server.orm.entities.AlertGroupEntity;
+import org.apache.ambari.server.orm.entities.AlertTargetEntity;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.alert.AlertGroup;
+import org.apache.commons.lang.StringUtils;
+
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+
+/**
+ * The {@link AlertGroupResourceProvider} class deals with managing the CRUD
+ * operations for {@link AlertGroup}, including property coercion to and from
+ * {@link AlertGroupEntity}.
+ */
+public class AlertGroupResourceProvider extends
+    AbstractControllerResourceProvider {
+
+  protected static final String ALERT_GROUP = "AlertGroup";
+  protected static final String ALERT_GROUP_ID = "AlertGroup/id";
+  protected static final String ALERT_GROUP_CLUSTER_NAME = "AlertGroup/cluster_name";
+  protected static final String ALERT_GROUP_NAME = "AlertGroup/name";
+  protected static final String ALERT_GROUP_DEFAULT = "AlertGroup/default";
+  protected static final String ALERT_GROUP_DEFINITIONS = "AlertGroup/definitions";
+  protected static final String ALERT_GROUP_TARGETS = "AlertGroup/targets";
+
+  private static final Set<String> PK_PROPERTY_IDS = new HashSet<String>(
+      Arrays.asList(ALERT_GROUP_ID, ALERT_GROUP_CLUSTER_NAME));
+
+  /**
+   * Group DAO
+   */
+  @Inject
+  private static AlertDispatchDAO s_dao;
+
+  /**
+   * Initializes the injectable members of this class with the specified
+   * injector.
+   *
+   * @param injector
+   *          the injector (not {@code null}).
+   */
+  @Inject
+  public static void init(Injector injector) {
+    s_dao = injector.getInstance(AlertDispatchDAO.class);
+  }
+
+  /**
+   * Constructor.
+   *
+   * @param propertyIds
+   * @param keyPropertyIds
+   * @param managementController
+   */
+  AlertGroupResourceProvider(Set<String> propertyIds,
+      Map<Type, String> keyPropertyIds,
+      AmbariManagementController managementController) {
+    super(propertyIds, keyPropertyIds, managementController);
+  }
+
+  @Override
+  public RequestStatus createResources(final Request request)
+      throws SystemException,
+      UnsupportedPropertyException, ResourceAlreadyExistsException,
+      NoSuchParentResourceException {
+
+    createResources(new Command<Void>() {
+      @Override
+      public Void invoke() throws AmbariException {
+        createAlertGroups(request.getProperties());
+        return null;
+      }
+    });
+
+    notifyCreate(Resource.Type.AlertGroup, request);
+    return getRequestStatus(null);
+  }
+
+  @Override
+  public Set<Resource> getResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException,
+      NoSuchResourceException, NoSuchParentResourceException {
+
+    Set<Resource> results = new HashSet<Resource>();
+    Set<String> requestPropertyIds = getRequestPropertyIds(request, predicate);
+
+    for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
+      String clusterName = (String) propertyMap.get(ALERT_GROUP_CLUSTER_NAME);
+
+      if (null == clusterName || clusterName.isEmpty()) {
+        throw new IllegalArgumentException("The cluster name is required when retrieving alert groups");
+      }
+
+      String id = (String) propertyMap.get(ALERT_GROUP_ID);
+      if (null != id) {
+        AlertGroupEntity entity = s_dao.findGroupById(Long.parseLong(id));
+        if (null != entity) {
+          results.add(toResource(false, clusterName, entity, requestPropertyIds));
+        }
+      } else {
+        Cluster cluster = null;
+
+        try {
+          cluster = getManagementController().getClusters().getCluster(clusterName);
+        } catch (AmbariException ae) {
+          throw new NoSuchResourceException("Parent Cluster resource doesn't exist", ae);
+        }
+
+        List<AlertGroupEntity> entities = s_dao.findAllGroups(cluster.getClusterId());
+
+        for (AlertGroupEntity entity : entities) {
+          results.add(toResource(true, clusterName, entity, requestPropertyIds));
+        }
+      }
+    }
+
+    return results;
+  }
+
+  @Override
+  public RequestStatus updateResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException,
+      NoSuchResourceException, NoSuchParentResourceException {
+
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public RequestStatus deleteResources(Predicate predicate)
+      throws SystemException, UnsupportedPropertyException,
+      NoSuchResourceException, NoSuchParentResourceException {
+
+    Set<Resource> resources = getResources(new RequestImpl(null, null, null,
+        null), predicate);
+
+    Set<Long> groupIds = new HashSet<Long>();
+
+    for (final Resource resource : resources) {
+      Long id = (Long) resource.getPropertyValue(ALERT_GROUP_ID);
+      groupIds.add(id);
+    }
+
+    for (Long groupId : groupIds) {
+      LOG.info("Deleting alert target {}", groupId);
+
+      final AlertGroupEntity entity = s_dao.findGroupById(groupId.longValue());
+
+      modifyResources(new Command<Void>() {
+        @Override
+        public Void invoke() throws AmbariException {
+          s_dao.remove(entity);
+          return null;
+        }
+      });
+    }
+
+    notifyDelete(Resource.Type.AlertGroup, predicate);
+    return getRequestStatus(null);
+  }
+
+  @Override
+  protected Set<String> getPKPropertyIds() {
+    return PK_PROPERTY_IDS;
+  }
+
+  /**
+   * Create and persist {@link AlertTargetEntity} from the map of properties.
+   *
+   * @param requestMaps
+   * @throws AmbariException
+   */
+  private void createAlertGroups(Set<Map<String, Object>> requestMaps)
+      throws AmbariException {
+
+    List<AlertGroupEntity> entities = new ArrayList<AlertGroupEntity>();
+    for (Map<String, Object> requestMap : requestMaps) {
+      AlertGroupEntity entity = new AlertGroupEntity();
+
+      String name = (String) requestMap.get(ALERT_GROUP_NAME);
+      String clusterName = (String) requestMap.get(ALERT_GROUP_CLUSTER_NAME);
+
+      if (StringUtils.isEmpty(name)) {
+        throw new IllegalArgumentException(
+            "The name of the alert group is required.");
+      }
+
+      if (StringUtils.isEmpty(clusterName)) {
+        throw new IllegalArgumentException(
+            "The name of the cluster is required when creating an alert group.");
+      }
+
+      Cluster cluster = getManagementController().getClusters().getCluster(
+          clusterName);
+
+      entity.setClusterId(cluster.getClusterId());
+      entity.setDefault(false);
+      entity.setGroupName(name);
+
+      entities.add(entity);
+    }
+
+    s_dao.createGroups(entities);
+  }
+
+  /**
+   * Convert the given {@link AlertGroupEntity} to a {@link Resource}.
+   *
+   * @param isCollection
+   *          {@code true} if the resource is part of a collection.
+   * @param entity
+   *          the entity to convert.
+   * @param requestedIds
+   *          the properties that were requested or {@code null} for all.
+   * @return the resource representation of the entity (never {@code null}).
+   */
+  private Resource toResource(boolean isCollection, String clusterName,
+      AlertGroupEntity entity,
+      Set<String> requestedIds) {
+
+    Resource resource = new ResourceImpl(Resource.Type.AlertGroup);
+    resource.setProperty(ALERT_GROUP_ID, entity.getGroupId());
+    resource.setProperty(ALERT_GROUP_NAME, entity.getGroupName());
+    resource.setProperty(ALERT_GROUP_CLUSTER_NAME, clusterName);
+
+    setResourceProperty(resource, ALERT_GROUP_DEFAULT,
+        entity.isDefault(), requestedIds);
+
+    return resource;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProvider.java
new file mode 100644
index 0000000..e00f60f
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProvider.java
@@ -0,0 +1,258 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.controller.internal;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
+import org.apache.ambari.server.controller.spi.NoSuchResourceException;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.RequestStatus;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.Resource.Type;
+import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.orm.dao.AlertDispatchDAO;
+import org.apache.ambari.server.orm.entities.AlertTargetEntity;
+import org.apache.ambari.server.state.alert.AlertTarget;
+import org.apache.commons.lang.StringUtils;
+
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+
+/**
+ * The {@link AlertTargetResourceProvider} class deals with managing the CRUD
+ * operations for {@link AlertTarget}, including property coercion to and from
+ * {@link AlertTargetEntity}.
+ */
+public class AlertTargetResourceProvider extends
+    AbstractControllerResourceProvider {
+
+  protected static final String ALERT_TARGET = "AlertTarget";
+  protected static final String ALERT_TARGET_ID = "AlertTarget/id";
+  protected static final String ALERT_TARGET_NAME = "AlertTarget/name";
+  protected static final String ALERT_TARGET_DESCRIPTION = "AlertTarget/description";
+  protected static final String ALERT_TARGET_NOTIFICATION_TYPE = "AlertTarget/notification_type";
+  protected static final String ALERT_TARGET_PROPERTIES = "AlertTarget/properties";
+  protected static final String ALERT_TARGET_GROUPS = "AlertTarget/groups";
+
+  private static final Set<String> PK_PROPERTY_IDS = new HashSet<String>(
+      Arrays.asList(ALERT_TARGET_ID, ALERT_TARGET_NAME));
+
+  /**
+   * Target DAO
+   */
+  @Inject
+  private static AlertDispatchDAO s_dao;
+
+  /**
+   * Initializes the injectable members of this class with the specified
+   * injector.
+   *
+   * @param injector
+   *          the injector (not {@code null}).
+   */
+  @Inject
+  public static void init(Injector injector) {
+    s_dao = injector.getInstance(AlertDispatchDAO.class);
+  }
+
+  /**
+   * Constructor.
+   *
+   * @param propertyIds
+   * @param keyPropertyIds
+   * @param managementController
+   */
+  AlertTargetResourceProvider(Set<String> propertyIds,
+      Map<Type, String> keyPropertyIds,
+      AmbariManagementController managementController) {
+    super(propertyIds, keyPropertyIds, managementController);
+  }
+
+  @Override
+  public RequestStatus createResources(final Request request)
+      throws SystemException,
+      UnsupportedPropertyException, ResourceAlreadyExistsException,
+      NoSuchParentResourceException {
+
+    createResources(new Command<Void>() {
+      @Override
+      public Void invoke() throws AmbariException {
+        createAlertTargets(request.getProperties());
+        return null;
+      }
+    });
+
+    notifyCreate(Resource.Type.AlertTarget, request);
+    return getRequestStatus(null);
+  }
+
+  @Override
+  public Set<Resource> getResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException,
+      NoSuchResourceException, NoSuchParentResourceException {
+
+    Set<Resource> results = new HashSet<Resource>();
+    Set<String> requestPropertyIds = getRequestPropertyIds(request, predicate);
+
+    if( null == predicate ){
+      List<AlertTargetEntity> entities = s_dao.findAllTargets();
+      for (AlertTargetEntity entity : entities) {
+        results.add(toResource(true, entity, requestPropertyIds));
+      }
+    } else {
+      for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
+        String id = (String) propertyMap.get(ALERT_TARGET_ID);
+        if (null == id) {
+          continue;
+        }
+
+        AlertTargetEntity entity = s_dao.findTargetById(Long.parseLong(id));
+        if (null != entity) {
+          results.add(toResource(false, entity, requestPropertyIds));
+        }
+      }
+    }
+
+    return results;
+  }
+
+  @Override
+  public RequestStatus updateResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException,
+      NoSuchResourceException, NoSuchParentResourceException {
+
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public RequestStatus deleteResources(Predicate predicate)
+      throws SystemException, UnsupportedPropertyException,
+      NoSuchResourceException, NoSuchParentResourceException {
+
+    Set<Resource> resources = getResources(new RequestImpl(null, null, null,
+        null), predicate);
+
+    Set<Long> targetIds = new HashSet<Long>();
+
+    for (final Resource resource : resources) {
+      Long id = (Long) resource.getPropertyValue(ALERT_TARGET_ID);
+      targetIds.add(id);
+    }
+
+    for (Long targetId : targetIds) {
+      LOG.info("Deleting alert target {}", targetId);
+
+      final AlertTargetEntity entity = s_dao.findTargetById(targetId.longValue());
+
+      modifyResources(new Command<Void>() {
+        @Override
+        public Void invoke() throws AmbariException {
+          s_dao.remove(entity);
+          return null;
+        }
+      });
+    }
+
+    notifyDelete(Resource.Type.AlertTarget, predicate);
+    return getRequestStatus(null);
+  }
+
+  @Override
+  protected Set<String> getPKPropertyIds() {
+    return PK_PROPERTY_IDS;
+  }
+
+  /**
+   * Create and persist {@link AlertTargetEntity} from the map of properties.
+   *
+   * @param requestMaps
+   * @throws AmbariException
+   */
+  private void createAlertTargets(Set<Map<String, Object>> requestMaps)
+      throws AmbariException {
+    List<AlertTargetEntity> entities = new ArrayList<AlertTargetEntity>();
+    for (Map<String, Object> requestMap : requestMaps) {
+      AlertTargetEntity entity = new AlertTargetEntity();
+
+      String name = (String) requestMap.get(ALERT_TARGET_NAME);
+      String description = (String) requestMap.get(ALERT_TARGET_DESCRIPTION);
+      String notificationType = (String) requestMap.get(ALERT_TARGET_NOTIFICATION_TYPE);
+      String properties = (String) requestMap.get(ALERT_TARGET_PROPERTIES);
+
+      if (StringUtils.isEmpty(name)) {
+        throw new IllegalArgumentException(
+            "The name of the alert target is required.");
+      }
+
+      if (StringUtils.isEmpty(notificationType)) {
+        throw new IllegalArgumentException(
+            "The type of the alert target is required.");
+      }
+
+      entity.setDescription(description);
+      entity.setNotificationType(notificationType);
+      entity.setProperties(properties);
+      entity.setTargetName(name);
+
+      entities.add(entity);
+    }
+
+    s_dao.createTargets(entities);
+  }
+
+  /**
+   * Convert the given {@link AlertTargetEntity} to a {@link Resource}.
+   *
+   * @param isCollection
+   *          {@code true} if the resource is part of a collection.
+   * @param entity
+   *          the entity to convert.
+   * @param requestedIds
+   *          the properties that were requested or {@code null} for all.
+   * @return the resource representation of the entity (never {@code null}).
+   */
+  private Resource toResource(boolean isCollection, AlertTargetEntity entity,
+      Set<String> requestedIds) {
+
+    Resource resource = new ResourceImpl(Resource.Type.AlertTarget);
+    resource.setProperty(ALERT_TARGET_ID, entity.getTargetId());
+    resource.setProperty(ALERT_TARGET_NAME, entity.getTargetName());
+
+    setResourceProperty(resource, ALERT_TARGET_DESCRIPTION,
+        entity.getDescription(), requestedIds);
+
+    setResourceProperty(resource, ALERT_TARGET_NOTIFICATION_TYPE,
+        entity.getNotificationType(), requestedIds);
+
+    setResourceProperty(resource, ALERT_TARGET_PROPERTIES,
+        entity.getProperties(), requestedIds);
+
+    return resource;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
index b10b4bc..3114809 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
@@ -115,6 +115,8 @@ public interface Resource {
     HostComponentProcess,
     Permission,
     AlertDefinition,
+    AlertGroup,
+    AlertTarget,
     AmbariPrivilege,
     ClusterPrivilege,
     ViewPrivilege,
@@ -196,6 +198,8 @@ public interface Resource {
     public static final Type HostComponentProcess = InternalType.HostComponentProcess.getType();
     public static final Type Permission = InternalType.Permission.getType();
     public static final Type AlertDefinition = InternalType.AlertDefinition.getType();
+    public static final Type AlertGroup = InternalType.AlertGroup.getType();
+    public static final Type AlertTarget = InternalType.AlertTarget.getType();
     public static final Type AmbariPrivilege = InternalType.AmbariPrivilege.getType();
     public static final Type ClusterPrivilege = InternalType.ClusterPrivilege.getType();
     public static final Type ViewPrivilege = InternalType.ViewPrivilege.getType();
@@ -315,8 +319,13 @@ public interface Resource {
 
     @Override
     public boolean equals(Object o) {
-      if (this == o) return true;
-      if (o == null || getClass() != o.getClass()) return false;
+      if (this == o) {
+        return true;
+      }
+
+      if (o == null || getClass() != o.getClass()) {
+        return false;
+      }
 
       Type type = (Type) o;
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDispatchDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDispatchDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDispatchDAO.java
index 2871e62..dfbe747 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDispatchDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDispatchDAO.java
@@ -51,7 +51,7 @@ public class AlertDispatchDAO {
 
   /**
    * Gets an alert group with the specified ID.
-   * 
+   *
    * @param groupId
    *          the ID of the group to retrieve.
    * @return the group or {@code null} if none exists.
@@ -62,7 +62,7 @@ public class AlertDispatchDAO {
 
   /**
    * Gets an alert target with the specified ID.
-   * 
+   *
    * @param targetId
    *          the ID of the target to retrieve.
    * @return the target or {@code null} if none exists.
@@ -73,7 +73,7 @@ public class AlertDispatchDAO {
 
   /**
    * Gets a notification with the specified ID.
-   * 
+   *
    * @param noticeId
    *          the ID of the notification to retrieve.
    * @return the notification or {@code null} if none exists.
@@ -85,7 +85,7 @@ public class AlertDispatchDAO {
   /**
    * Gets an alert group with the specified name across all clusters. Alert
    * group names are unique within a cluster.
-   * 
+   *
    * @param groupName
    *          the name of the group (not {@code null}).
    * @return the alert group or {@code null} if none exists.
@@ -102,7 +102,7 @@ public class AlertDispatchDAO {
   /**
    * Gets an alert group with the specified name for the given cluster. Alert
    * group names are unique within a cluster.
-   * 
+   *
    * @param clusterId
    *          the ID of the cluster.
    * @param groupName
@@ -122,7 +122,7 @@ public class AlertDispatchDAO {
   /**
    * Gets an alert target with the specified name. Alert target names are unique
    * across all clusters.
-   * 
+   *
    * @param targetName
    *          the name of the target (not {@code null}).
    * @return the alert target or {@code null} if none exists.
@@ -138,7 +138,7 @@ public class AlertDispatchDAO {
 
   /**
    * Gets all alert groups stored in the database across all clusters.
-   * 
+   *
    * @return all alert groups or empty list if none exist (never {@code null}).
    */
   public List<AlertGroupEntity> findAllGroups() {
@@ -150,7 +150,7 @@ public class AlertDispatchDAO {
 
   /**
    * Gets all alert groups stored in the database for the specified cluster.
-   * 
+   *
    * @return all alert groups in the specified cluster or empty list if none
    *         exist (never {@code null}).
    */
@@ -165,7 +165,7 @@ public class AlertDispatchDAO {
 
   /**
    * Gets all alert targets stored in the database.
-   * 
+   *
    * @return all alert targets or empty list if none exist (never {@code null}).
    */
   public List<AlertTargetEntity> findAllTargets() {
@@ -177,7 +177,7 @@ public class AlertDispatchDAO {
 
   /**
    * Gets all alert notifications stored in the database.
-   * 
+   *
    * @return all alert notifications or empty list if none exist (never
    *         {@code null}).
    */
@@ -189,6 +189,23 @@ public class AlertDispatchDAO {
   }
 
   /**
+   * Persists new alert groups.
+   *
+   * @param entities
+   *          the groups to persist (not {@code null}).
+   */
+  @Transactional
+  public void createGroups(List<AlertGroupEntity> entities) {
+    if (null == entities) {
+      return;
+    }
+
+    for (AlertGroupEntity entity : entities) {
+      create(entity);
+    }
+  }
+
+  /**
    * Persists a new alert group.
    * 
    * @param alertGroup
@@ -201,7 +218,7 @@ public class AlertDispatchDAO {
 
   /**
    * Refresh the state of the alert group from the database.
-   * 
+   *
    * @param alertGroup
    *          the group to refresh (not {@code null}).
    */
@@ -212,7 +229,7 @@ public class AlertDispatchDAO {
 
   /**
    * Merge the speicified alert group with the existing group in the database.
-   * 
+   *
    * @param alertGroup
    *          the group to merge (not {@code null}).
    * @return the updated group with merged content (never {@code null}).
@@ -224,7 +241,7 @@ public class AlertDispatchDAO {
 
   /**
    * Removes the specified alert group from the database.
-   * 
+   *
    * @param alertGroup
    *          the group to remove.
    */
@@ -234,8 +251,25 @@ public class AlertDispatchDAO {
   }
 
   /**
+   * Persists new alert targets.
+   *
+   * @param entities
+   *          the targets to persist (not {@code null}).
+   */
+  @Transactional
+  public void createTargets(List<AlertTargetEntity> entities) {
+    if (null == entities) {
+      return;
+    }
+
+    for (AlertTargetEntity entity : entities) {
+      create(entity);
+    }
+  }
+
+  /**
    * Persists a new alert target.
-   * 
+   *
    * @param alertTarget
    *          the target to persist (not {@code null}).
    */
@@ -246,7 +280,7 @@ public class AlertDispatchDAO {
 
   /**
    * Refresh the state of the alert target from the database.
-   * 
+   *
    * @param alertTarget
    *          the target to refresh (not {@code null}).
    */
@@ -257,7 +291,7 @@ public class AlertDispatchDAO {
 
   /**
    * Merge the speicified alert target with the existing target in the database.
-   * 
+   *
    * @param alertTarget
    *          the target to merge (not {@code null}).
    * @return the updated target with merged content (never {@code null}).
@@ -269,7 +303,7 @@ public class AlertDispatchDAO {
 
   /**
    * Removes the specified alert target from the database.
-   * 
+   *
    * @param alertTarget
    *          the target to remove.
    */
@@ -280,7 +314,7 @@ public class AlertDispatchDAO {
 
   /**
    * Persists a new notification.
-   * 
+   *
    * @param alertNotice
    *          the notification to persist (not {@code null}).
    */
@@ -291,7 +325,7 @@ public class AlertDispatchDAO {
 
   /**
    * Refresh the state of the notification from the database.
-   * 
+   *
    * @param alertNotice
    *          the notification to refresh (not {@code null}).
    */
@@ -302,7 +336,7 @@ public class AlertDispatchDAO {
 
   /**
    * Merge the specified notification with the existing target in the database.
-   * 
+   *
    * @param alertNotice
    *          the notification to merge (not {@code null}).
    * @return the updated notification with merged content (never {@code null}).
@@ -314,7 +348,7 @@ public class AlertDispatchDAO {
 
   /**
    * Removes the specified notification from the database.
-   * 
+   *
    * @param alertNotice
    *          the notification to remove.
    */
@@ -327,7 +361,7 @@ public class AlertDispatchDAO {
    * Removes notifications for the specified alert definition ID. This will
    * invoke {@link EntityManager#clear()} when completed since the JPQL
    * statement will remove entries without going through the EM.
-   * 
+   *
    * @param definitionId
    *          the ID of the definition to remove.
    */

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertGroup.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertGroup.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertGroup.java
new file mode 100644
index 0000000..659efa9
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertGroup.java
@@ -0,0 +1,124 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state.alert;
+
+import java.util.List;
+
+/**
+ * The {@link AlertGroup} class represents a grouping of {@link AlertDefinition}
+ * instances as well as the targets that will be invoked when an alert is
+ * triggered.
+ */
+public class AlertGroup {
+  private String m_id;
+  private String m_name;
+  private String m_clusterName;
+  private boolean m_isDefault;
+  private List<AlertDefinition> m_definitions;
+  private List<AlertTarget> m_targets;
+
+  /**
+   * @return the id
+   */
+  public String getId() {
+    return m_id;
+  }
+
+  /**
+   * @param id
+   *          the id to set
+   */
+  public void setId(String id) {
+    m_id = id;
+  }
+
+  /**
+   * @return the name
+   */
+  public String getName() {
+    return m_name;
+  }
+
+  /**
+   * @param name
+   *          the name to set
+   */
+  public void setName(String name) {
+    m_name = name;
+  }
+
+  /**
+   * @return the clusterName
+   */
+  public String getClusterName() {
+    return m_clusterName;
+  }
+
+  /**
+   * @param clusterName
+   *          the clusterName to set
+   */
+  public void setClusterName(String clusterName) {
+    m_clusterName = clusterName;
+  }
+
+  /**
+   * @return the isDefault
+   */
+  public boolean isDefault() {
+    return m_isDefault;
+  }
+
+  /**
+   * @param isDefault
+   *          the isDefault to set
+   */
+  public void setDefault(boolean isDefault) {
+    m_isDefault = isDefault;
+  }
+
+  /**
+   * @return the definitions
+   */
+  public List<AlertDefinition> getDefinitions() {
+    return m_definitions;
+  }
+
+  /**
+   * @param definitions
+   *          the definitions to set
+   */
+  public void setDefinitions(List<AlertDefinition> definitions) {
+    m_definitions = definitions;
+  }
+
+  /**
+   * @return the targets
+   */
+  public List<AlertTarget> getTargets() {
+    return m_targets;
+  }
+
+  /**
+   * @param targets
+   *          the targets to set
+   */
+  public void setTargets(List<AlertTarget> targets) {
+    m_targets = targets;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertTarget.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertTarget.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertTarget.java
new file mode 100644
index 0000000..21e83d9
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertTarget.java
@@ -0,0 +1,123 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state.alert;
+
+import java.util.List;
+
+/**
+ * The {@link AlertTarget} class represents a dispatch mechanism and audience
+ * that will receive information about alerts int he system.
+ */
+public class AlertTarget {
+  private String m_id;
+  private String m_name;
+  private String m_description;
+  private String m_notificationType;
+  private String m_properties;
+  private List<AlertGroup> m_groups;
+
+  /**
+   * @return the id
+   */
+  public String getId() {
+    return m_id;
+  }
+
+  /**
+   * @param id
+   *          the id to set
+   */
+  public void setId(String id) {
+    m_id = id;
+  }
+
+  /**
+   * @return the name
+   */
+  public String getName() {
+    return m_name;
+  }
+
+  /**
+   * @param name
+   *          the name to set
+   */
+  public void setName(String name) {
+    m_name = name;
+  }
+
+  /**
+   * @return the description
+   */
+  public String getDescription() {
+    return m_description;
+  }
+
+  /**
+   * @param description
+   *          the description to set
+   */
+  public void setDescription(String description) {
+    m_description = description;
+  }
+
+  /**
+   * @return the notificationType
+   */
+  public String getNotificationType() {
+    return m_notificationType;
+  }
+
+  /**
+   * @param notificationType
+   *          the notificationType to set
+   */
+  public void setNotificationType(String notificationType) {
+    m_notificationType = notificationType;
+  }
+
+  /**
+   * @return the properties
+   */
+  public String getProperties() {
+    return m_properties;
+  }
+
+  /**
+   * @param properties
+   *          the properties to set
+   */
+  public void setProperties(String properties) {
+    m_properties = properties;
+  }
+
+  /**
+   * @return the groups
+   */
+  public List<AlertGroup> getGroups() {
+    return m_groups;
+  }
+
+  /**
+   * @param groups
+   *          the groups to set
+   */
+  public void setGroups(List<AlertGroup> groups) {
+    m_groups = groups;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/state/alert/TargetType.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/TargetType.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/TargetType.java
new file mode 100644
index 0000000..e2564cc
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/TargetType.java
@@ -0,0 +1,37 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state.alert;
+
+import org.apache.ambari.server.orm.dao.AlertsDAO;
+
+/**
+ * The {@link TargetType} enumeration is used to represent the built-in target
+ * dispatch mechanisms that are supported internally. {@link AlertTarget}
+ * instances may have other custom target types that are not listed here.
+ */
+public enum TargetType {
+  /**
+   * Alerts will be distributed via email.
+   */
+  EMAIL,
+
+  /**
+   * {@link AlertsDAO} will be distributed via SNMP.
+   */
+  SNMP;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
index cc5bb5b..75265b7 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
@@ -555,6 +555,8 @@ public class ServiceComponentHostImpl implements ServiceComponentHost {
       impl.alertDefinitionHash.invalidate(impl.getClusterName(), hostName);
       impl.alertDefinitionHash.enqueueAgentCommands(impl.getClusterName(),
           Collections.singleton(hostName));
+
+      impl.updateLastOpInfo(event.getType(), event.getOpTimestamp());
     }
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/resources/key_properties.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/key_properties.json b/ambari-server/src/main/resources/key_properties.json
index 06ebb61..3007fee 100644
--- a/ambari-server/src/main/resources/key_properties.json
+++ b/ambari-server/src/main/resources/key_properties.json
@@ -149,6 +149,13 @@
     "Cluster": "AlertDefinition/cluster_name",
     "AlertDefinition": "AlertDefinition/id"
   },
+  "AlertTarget": {
+    "AlertTarget": "AlertTarget/id"
+  },
+  "AlertGroup": {
+    "Cluster": "AlertGroup/cluster_name",
+    "AlertGroup": "AlertGroup/id"
+  },  
   "Controller": {
     "Controller": "Controllers/name"
   },

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/main/resources/properties.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/properties.json b/ambari-server/src/main/resources/properties.json
index bc2ad22..9574aa9 100644
--- a/ambari-server/src/main/resources/properties.json
+++ b/ambari-server/src/main/resources/properties.json
@@ -425,7 +425,23 @@
       "AlertDefinition/enabled",
       "AlertDefinition/scope",
       "AlertDefinition/source"
-    ],      
+    ],
+    "AlertGroup": [
+      "AlertGroup/id",
+      "AlertGroup/name",
+      "AlertGroup/cluster_name",
+      "AlertGroup/default",
+      "AlertGroup/definitions",
+      "AlertGroup/targets"
+    ],
+    "AlertTarget": [
+      "AlertTarget/id",
+      "AlertTarget/name",
+      "AlertTarget/description",      
+      "AlertTarget/notification_type",
+      "AlertTarget/properties",
+      "AlertTarget/groups"
+    ],
     "Controller":[
         "Controllers/name",
         "LDAP/configured",

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java
new file mode 100644
index 0000000..c9428b7
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java
@@ -0,0 +1,335 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.controller.internal;
+
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.createStrictMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.resetToStrict;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.utilities.PredicateBuilder;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.metadata.ActionMetadata;
+import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
+import org.apache.ambari.server.orm.dao.AlertDispatchDAO;
+import org.apache.ambari.server.orm.entities.AlertGroupEntity;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.easymock.Capture;
+import org.easymock.EasyMock;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.inject.Binder;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Module;
+import com.google.inject.util.Modules;
+
+/**
+ * {@link AlertGroupResourceProvider} tests.
+ */
+public class AlertGroupResourceProviderTest {
+
+  private static final Long ALERT_GROUP_ID = Long.valueOf(28);
+  private static final String ALERT_GROUP_NAME = "Important Alerts";
+  private static final long ALERT_GROUP_CLUSTER_ID = 1L;
+  private static final String ALERT_GROUP_CLUSTER_NAME = "c1";
+
+  private AlertDispatchDAO m_dao;
+  private Injector m_injector;
+
+  @Before
+  public void before() {
+    m_dao = createStrictMock(AlertDispatchDAO.class);
+
+    m_injector = Guice.createInjector(Modules.override(
+        new InMemoryDefaultTestModule()).with(new MockModule()));
+
+    AlertGroupResourceProvider.init(m_injector);
+  }
+
+  /**
+   * @throws Exception
+   */
+  @Test
+  public void testGetResourcesNoPredicate() throws Exception {
+    AlertGroupResourceProvider provider = createProvider(null);
+
+    Request request = PropertyHelper.getReadRequest("AlertGroup/cluster_name",
+        "AlertGroup/id");
+
+    Set<Resource> results = provider.getResources(request, null);
+
+    assertEquals(0, results.size());
+  }
+
+  /**
+   * @throws Exception
+   */
+  @Test
+  public void testGetResourcesClusterPredicate() throws Exception {
+    Request request = PropertyHelper.getReadRequest(
+        AlertGroupResourceProvider.ALERT_GROUP_ID,
+        AlertGroupResourceProvider.ALERT_GROUP_NAME,
+        AlertGroupResourceProvider.ALERT_GROUP_CLUSTER_NAME,
+        AlertGroupResourceProvider.ALERT_GROUP_DEFAULT);
+
+    AmbariManagementController amc = createMock(AmbariManagementController.class);
+    Clusters clusters = createMock(Clusters.class);
+    Cluster cluster = createMock(Cluster.class);
+    expect(amc.getClusters()).andReturn(clusters).atLeastOnce();
+    expect(clusters.getCluster((String) anyObject())).andReturn(cluster).atLeastOnce();
+    expect(cluster.getClusterId()).andReturn(Long.valueOf(1)).anyTimes();
+
+    Predicate predicate = new PredicateBuilder().property(
+        AlertGroupResourceProvider.ALERT_GROUP_CLUSTER_NAME).equals("c1").toPredicate();
+
+    expect(m_dao.findAllGroups(ALERT_GROUP_CLUSTER_ID)).andReturn(
+        getMockEntities());
+
+    replay(amc, clusters, cluster, m_dao);
+
+    AlertGroupResourceProvider provider = createProvider(amc);
+    Set<Resource> results = provider.getResources(request, predicate);
+
+    assertEquals(1, results.size());
+
+    Resource r = results.iterator().next();
+
+    Assert.assertEquals(ALERT_GROUP_NAME,
+        r.getPropertyValue(AlertGroupResourceProvider.ALERT_GROUP_NAME));
+
+    Assert.assertEquals(ALERT_GROUP_ID,
+        r.getPropertyValue(AlertGroupResourceProvider.ALERT_GROUP_ID));
+
+    Assert.assertEquals(ALERT_GROUP_CLUSTER_NAME,
+        r.getPropertyValue(AlertGroupResourceProvider.ALERT_GROUP_CLUSTER_NAME));
+
+    verify(amc, clusters, cluster, m_dao);
+  }
+
+  /**
+   * @throws Exception
+   */
+  @Test
+  public void testGetSingleResource() throws Exception {
+    Request request = PropertyHelper.getReadRequest(
+        AlertGroupResourceProvider.ALERT_GROUP_ID,
+        AlertGroupResourceProvider.ALERT_GROUP_NAME,
+        AlertGroupResourceProvider.ALERT_GROUP_CLUSTER_NAME,
+        AlertGroupResourceProvider.ALERT_GROUP_DEFAULT);
+
+    AmbariManagementController amc = createMock(AmbariManagementController.class);
+
+    Predicate predicate = new PredicateBuilder().property(
+        AlertGroupResourceProvider.ALERT_GROUP_CLUSTER_NAME).equals(
+        ALERT_GROUP_CLUSTER_NAME).and().property(
+        AlertGroupResourceProvider.ALERT_GROUP_ID).equals(
+        ALERT_GROUP_ID.toString()).toPredicate();
+
+    expect(m_dao.findGroupById(ALERT_GROUP_ID.longValue())).andReturn(
+        getMockEntities().get(0));
+
+    replay(amc, m_dao);
+
+    AlertGroupResourceProvider provider = createProvider(amc);
+    Set<Resource> results = provider.getResources(request, predicate);
+
+    assertEquals(1, results.size());
+
+    Resource r = results.iterator().next();
+
+    Assert.assertEquals(ALERT_GROUP_NAME,
+        r.getPropertyValue(AlertGroupResourceProvider.ALERT_GROUP_NAME));
+
+    Assert.assertEquals(ALERT_GROUP_ID,
+        r.getPropertyValue(AlertGroupResourceProvider.ALERT_GROUP_ID));
+
+    Assert.assertEquals(ALERT_GROUP_CLUSTER_NAME,
+        r.getPropertyValue(AlertGroupResourceProvider.ALERT_GROUP_CLUSTER_NAME));
+
+    verify(amc, m_dao);
+  }
+
+  /**
+   * @throws Exception
+   */
+  @Test
+  public void testCreateResources() throws Exception {
+    AmbariManagementController amc = createMock(AmbariManagementController.class);
+    Clusters clusters = createMock(Clusters.class);
+    Cluster cluster = createMock(Cluster.class);
+    expect(amc.getClusters()).andReturn(clusters).atLeastOnce();
+    expect(clusters.getCluster((String) anyObject())).andReturn(cluster).atLeastOnce();
+    expect(cluster.getClusterId()).andReturn(Long.valueOf(1)).anyTimes();
+
+    Capture<List<AlertGroupEntity>> listCapture = new Capture<List<AlertGroupEntity>>();
+
+    m_dao.createGroups(capture(listCapture));
+    expectLastCall();
+
+    replay(amc, clusters, cluster, m_dao);
+
+    AlertGroupResourceProvider provider = createProvider(amc);
+    Map<String, Object> requestProps = new HashMap<String, Object>();
+    requestProps.put(AlertGroupResourceProvider.ALERT_GROUP_NAME,
+        ALERT_GROUP_NAME);
+
+    requestProps.put(AlertGroupResourceProvider.ALERT_GROUP_CLUSTER_NAME,
+        ALERT_GROUP_CLUSTER_NAME);
+
+    Request request = PropertyHelper.getCreateRequest(Collections.singleton(requestProps), null);
+    provider.createResources(request);
+
+    Assert.assertTrue(listCapture.hasCaptured());
+    AlertGroupEntity entity = listCapture.getValue().get(0);
+    Assert.assertNotNull(entity);
+
+    Assert.assertEquals(ALERT_GROUP_NAME, entity.getGroupName());
+    Assert.assertEquals(ALERT_GROUP_CLUSTER_ID,
+        entity.getClusterId().longValue());
+
+    verify(amc, clusters, cluster, m_dao);
+  }
+
+  /**
+   * @throws Exception
+   */
+  @Test
+  public void testUpdateResources() throws Exception {
+  }
+
+  /**
+   * @throws Exception
+   */
+  @Test
+  public void testDeleteResources() throws Exception {
+    AmbariManagementController amc = createMock(AmbariManagementController.class);
+    Clusters clusters = createMock(Clusters.class);
+    Cluster cluster = createMock(Cluster.class);
+    expect(amc.getClusters()).andReturn(clusters).atLeastOnce();
+    expect(clusters.getCluster((String) anyObject())).andReturn(cluster).atLeastOnce();
+    expect(cluster.getClusterId()).andReturn(Long.valueOf(1)).anyTimes();
+
+    Capture<AlertGroupEntity> entityCapture = new Capture<AlertGroupEntity>();
+    Capture<List<AlertGroupEntity>> listCapture = new Capture<List<AlertGroupEntity>>();
+
+    m_dao.createGroups(capture(listCapture));
+    expectLastCall();
+
+    replay(amc, clusters, cluster, m_dao);
+
+    AlertGroupResourceProvider provider = createProvider(amc);
+
+    Map<String, Object> requestProps = new HashMap<String, Object>();
+    requestProps.put(AlertGroupResourceProvider.ALERT_GROUP_NAME,
+        ALERT_GROUP_NAME);
+
+    requestProps.put(AlertGroupResourceProvider.ALERT_GROUP_CLUSTER_NAME,
+        ALERT_GROUP_CLUSTER_NAME);
+
+    Request request = PropertyHelper.getCreateRequest(Collections.singleton(requestProps), null);
+    provider.createResources(request);
+
+    Assert.assertTrue(listCapture.hasCaptured());
+    AlertGroupEntity entity = listCapture.getValue().get(0);
+    Assert.assertNotNull(entity);
+
+    Predicate predicate = new PredicateBuilder().property(
+        AlertGroupResourceProvider.ALERT_GROUP_CLUSTER_NAME).equals(
+        ALERT_GROUP_CLUSTER_NAME).and().property(
+        AlertGroupResourceProvider.ALERT_GROUP_ID).equals(
+        ALERT_GROUP_ID.toString()).toPredicate();
+
+    // everything is mocked, there is no DB
+    entity.setGroupId(ALERT_GROUP_ID);
+
+    resetToStrict(m_dao);
+    expect(m_dao.findGroupById(ALERT_GROUP_ID.longValue())).andReturn(entity).anyTimes();
+    m_dao.remove(capture(entityCapture));
+    expectLastCall();
+    replay(m_dao);
+
+    provider.deleteResources(predicate);
+
+    AlertGroupEntity entity1 = entityCapture.getValue();
+    Assert.assertEquals(ALERT_GROUP_ID, entity1.getGroupId());
+
+    verify(amc, clusters, cluster, m_dao);
+  }
+
+  /**
+   * @param amc
+   * @return
+   */
+  private AlertGroupResourceProvider createProvider(
+      AmbariManagementController amc) {
+    return new AlertGroupResourceProvider(
+        PropertyHelper.getPropertyIds(Resource.Type.AlertGroup),
+        PropertyHelper.getKeyPropertyIds(Resource.Type.AlertGroup), amc);
+  }
+
+  /**
+   * @return
+   */
+  private List<AlertGroupEntity> getMockEntities() throws Exception {
+    AlertGroupEntity entity = new AlertGroupEntity();
+    entity.setGroupId(ALERT_GROUP_ID);
+    entity.setGroupName(ALERT_GROUP_NAME);
+    entity.setClusterId(ALERT_GROUP_CLUSTER_ID);
+    entity.setDefault(false);
+    return Arrays.asList(entity);
+  }
+
+  /**
+  *
+  */
+  private class MockModule implements Module {
+    /**
+    *
+    */
+    @Override
+    public void configure(Binder binder) {
+      binder.bind(AlertDispatchDAO.class).toInstance(m_dao);
+      binder.bind(Clusters.class).toInstance(
+          EasyMock.createNiceMock(Clusters.class));
+      binder.bind(Cluster.class).toInstance(
+          EasyMock.createNiceMock(Cluster.class));
+      binder.bind(ActionMetadata.class);
+    }
+  }
+}


[40/50] [abbrv] git commit: Merge branch 'trunk' into branch-alerts-dev

Posted by jo...@apache.org.
Merge branch 'trunk' into branch-alerts-dev


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

Branch: refs/heads/trunk
Commit: f923fd880b49548bc1cc289e89c18039fc3552b0
Parents: 10f1f73 f1557e8
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Mon Sep 29 08:13:51 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Mon Sep 29 08:13:51 2014 -0400

----------------------------------------------------------------------
 .../admin-web/app/scripts/services/Cluster.js   |   2 +-
 .../resources/ui/admin-web/app/styles/main.css  |  15 ++
 .../admin-web/app/views/ambariViews/create.html |   2 +-
 .../admin-web/app/views/ambariViews/edit.html   |   2 +-
 .../ui/admin-web/app/views/leftNavbar.html      |   3 +-
 .../resources/ui/admin-web/app/views/main.html  |   4 +-
 ambari-agent/pom.xml                            |   3 +-
 ambari-server/pom.xml                           |   8 +-
 ambari-server/src/main/assemblies/server.xml    |   3 +-
 .../ambari/server/controller/AmbariServer.java  |   2 +-
 .../server/orm/entities/ViewInstanceEntity.java |  34 +--
 .../AmbariAuthorizationFilter.java              |  91 ++++++-
 .../server/security/authorization/Users.java    |   3 +-
 .../server/upgrade/UpgradeCatalog170.java       | 139 ++++++----
 .../apache/ambari/server/view/ViewRegistry.java |  26 +-
 .../GANGLIA/configuration/ganglia-env.xml       |   2 +-
 .../services/GANGLIA/package/scripts/params.py  |   7 +-
 .../services/OOZIE/configuration/oozie-env.xml  |   2 +-
 .../services/OOZIE/package/files/oozieSmoke2.sh |  27 +-
 .../services/OOZIE/package/scripts/oozie.py     |   8 +-
 .../OOZIE/package/scripts/oozie_service.py      |  17 +-
 .../services/OOZIE/package/scripts/params.py    |  30 ++-
 .../OOZIE/package/scripts/service_check.py      |   5 +-
 .../stacks/HDP/2.2/services/SLIDER/metainfo.xml |   5 +-
 .../services/SLIDER/package/scripts/params.py   |   6 +-
 .../orm/entities/ViewInstanceEntityTest.java    |  19 +-
 .../AmbariAuthorizationFilterTest.java          | 266 ++++++++++++++++++-
 .../security/authorization/TestUsers.java       |   1 +
 .../server/upgrade/UpgradeCatalog170Test.java   |  63 ++++-
 .../ambari/server/upgrade/UpgradeTest.java      |  11 +-
 .../stacks/2.0.6/OOZIE/test_oozie_server.py     |  12 +
 .../stacks/2.0.6/OOZIE/test_service_check.py    |   3 +-
 .../service/manage_config_groups_controller.js  |  57 +++-
 ambari-web/app/controllers/wizard.js            |   1 +
 .../app/controllers/wizard/step7_controller.js  |  14 +-
 ambari-web/app/models/config_group.js           |   5 +
 .../manage_configuration_groups_popup.hbs       |   2 +-
 contrib/views/jobs/src/main/resources/view.xml  |   4 +-
 .../slider/SliderAppsViewControllerImpl.java    |   4 +-
 .../app/controllers/slider_apps_controller.js   |   3 +-
 .../ui/app/controllers/slider_controller.js     |  11 +-
 .../ui/app/mappers/slider_apps_mapper.js        |   7 +-
 .../ui/app/templates/unavailable_apps.hbs       |   3 +
 .../src/main/resources/ui/app/translations.js   |   2 +-
 .../views/slider/src/main/resources/view.xml    |   2 +-
 docs/pom.xml                                    |  16 +-
 pom.xml                                         |   1 +
 47 files changed, 741 insertions(+), 212 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/f923fd88/ambari-agent/pom.xml
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/f923fd88/ambari-server/pom.xml
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/f923fd88/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/f923fd88/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
----------------------------------------------------------------------
diff --cc ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
index 338fede,d86bf35..f8f6f5b
--- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
@@@ -69,8 -70,8 +70,9 @@@ import org.apache.ambari.server.state.C
  import org.apache.ambari.server.state.Clusters;
  import org.apache.ambari.server.state.Config;
  import org.apache.ambari.server.state.ConfigHelper;
 +import org.apache.ambari.server.state.alert.Scope;
  import org.apache.ambari.server.utils.StageUtils;
+ import org.apache.ambari.server.view.ViewRegistry;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  


[27/50] [abbrv] git commit: Merge branch 'trunk' into branch-alerts-dev

Posted by jo...@apache.org.
Merge branch 'trunk' into branch-alerts-dev

Conflicts:
	ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java


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

Branch: refs/heads/trunk
Commit: f1018b176a64451c2d62fcd3e2f5238e4587ab02
Parents: a4e97aa 5fc5828
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Thu Sep 18 10:43:23 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Thu Sep 18 10:43:23 2014 -0400

----------------------------------------------------------------------
 .../ui/admin-web/app/scripts/services/View.js   |  19 +--
 .../resources/ui/admin-web/app/styles/main.css  |  87 ++++++++++
 .../app/views/ambariViews/listTable.html        |  19 ++-
 ambari-admin/src/main/resources/view.xml        |   1 +
 .../resource_management/TestCopyFromLocal.py    |   8 +-
 .../ambari/groovy/client/AmbariClient.groovy    |   7 +-
 .../libraries/providers/copy_from_local.py      |  12 +-
 .../libraries/resources/copy_from_local.py      |   3 +-
 .../server/api/util/StackExtensionHelper.java   |   9 +-
 .../internal/ClientConfigResourceProvider.java  |  35 +++-
 .../server/orm/entities/AlertNoticeEntity.java  |  51 ++++--
 .../ambari/server/state/ConfigHelper.java       |  21 ++-
 .../server/state/cluster/ClusterImpl.java       |   3 +-
 .../server/upgrade/UpgradeCatalog161.java       |   1 -
 .../server/upgrade/UpgradeCatalog170.java       |  28 +++-
 .../main/resources/Ambari-DDL-MySQL-CREATE.sql  |   7 +-
 .../main/resources/Ambari-DDL-Oracle-CREATE.sql |   7 +-
 .../resources/Ambari-DDL-Postgres-CREATE.sql    |   7 +-
 .../Ambari-DDL-Postgres-EMBEDDED-CREATE.sql     |   7 +-
 .../services/HDFS/configuration/hadoop-env.xml  |   2 +-
 .../GANGLIA/configuration/ganglia-env.xml       |   5 +
 .../GANGLIA/package/scripts/ganglia_monitor.py  |   4 +-
 .../services/GANGLIA/package/scripts/params.py  |  24 +--
 .../HIVE/package/scripts/install_jars.py        |  28 ++--
 .../services/HIVE/package/scripts/params.py     |  11 +-
 .../services/NAGIOS/package/files/sys_logger.py |  30 ++--
 .../stacks/HDP/2.2.1/role_command_order.json    |   2 +-
 .../services/TEZ/configuration/tez-site.xml     |  29 ++++
 .../stacks/HDP/2.2/role_command_order.json      |   3 +-
 .../SLIDER/configuration/slider-client.xml      |  56 +++++++
 .../SLIDER/configuration/slider-log4j.xml       |  89 ++++++++++
 .../stacks/HDP/2.2/services/SLIDER/metainfo.xml |  72 ++++++++
 .../SLIDER/package/files/hbaseSmokeVerify.sh    |  34 ++++
 .../services/SLIDER/package/scripts/__init__.py |  19 +++
 .../services/SLIDER/package/scripts/params.py   |  45 +++++
 .../SLIDER/package/scripts/service_check.py     |  45 +++++
 .../services/SLIDER/package/scripts/slider.py   |  68 ++++++++
 .../SLIDER/package/scripts/slider_client.py     |  43 +++++
 .../SLIDER/package/templates/slider-wrapper.j2  |  42 +++++
 .../2.2/services/TEZ/configuration/tez-site.xml |  29 ++++
 .../ClientConfigResourceProviderTest.java       |  24 ++-
 .../server/orm/dao/AlertDefinitionDAOTest.java  |   1 +
 .../server/upgrade/UpgradeCatalog161Test.java   |   4 -
 .../server/upgrade/UpgradeCatalog170Test.java   | 114 ++++++++++---
 .../stacks/2.0.6/HIVE/test_hive_server.py       |   3 +-
 .../stacks/2.2/SLIDER/test_slider_client.py     | 109 +++++++++++++
 .../test/python/stacks/2.2/configs/default.json | 115 +++++++++++++
 .../test/python/stacks/2.2/configs/secured.json |  79 +++++++++
 ambari-shell/ambari-groovy-shell/pom.xml        |  11 ++
 .../ambari/shell/commands/ConfigCommands.java   | 163 +++++++++++++++++++
 .../shell/completion/AbstractCompletion.java    |  34 ++++
 .../ambari/shell/completion/Blueprint.java      |   9 +-
 .../ambari/shell/completion/ConfigType.java     |  29 ++++
 .../apache/ambari/shell/completion/Host.java    |   9 +-
 .../apache/ambari/shell/completion/Service.java |  12 +-
 .../configuration/ConverterConfiguration.java   |   6 +
 .../shell/converter/AbstractConverter.java      |  63 +++++++
 .../shell/converter/BlueprintConverter.java     |  21 +--
 .../shell/converter/ConfigTypeConverter.java    |  45 +++++
 .../ambari/shell/converter/HostConverter.java   |  21 +--
 .../shell/converter/ServiceConverter.java       |  24 +--
 .../shell/commands/ConfigCommandsTest.java      |  98 +++++++++++
 .../src/test/resources/core-site.xml            |  13 ++
 ambari-web/app/controllers/application.js       |   8 +-
 ambari-web/app/controllers/main.js              |   1 -
 .../resourceManager/wizard_controller.js        |   1 -
 ambari-web/app/controllers/main/host/details.js |   9 +-
 .../controllers/main/service/info/configs.js    |  42 +++--
 .../main/service/reassign/step2_controller.js   |   1 +
 .../app/controllers/main/views_controller.js    |   6 +-
 .../app/controllers/wizard/step5_controller.js  |  10 +-
 .../app/controllers/wizard/step7_controller.js  |   5 +
 ambari-web/app/messages.js                      |   3 +-
 ambari-web/app/mixins/common/serverValidator.js |   1 +
 ambari-web/app/models/service_config_version.js |   2 +-
 ambari-web/app/routes/installer.js              |   1 +
 ambari-web/app/routes/main.js                   |   1 -
 ambari-web/app/routes/reassign_master_routes.js | 124 +++++++-------
 .../app/routes/rm_high_availability_routes.js   |  12 +-
 ambari-web/app/styles/application.less          |  22 ++-
 ambari-web/app/templates/application.hbs        |  27 ++-
 .../common/configs/config_history_flow.hbs      |  36 +---
 .../configs/config_recommendation_popup.hbs     |  40 ++++-
 .../common/configs/service_version_box.hbs      |  53 ++++++
 .../app/templates/common/custom_date_popup.hbs  |  39 +++++
 ambari-web/app/templates/main/host/summary.hbs  |   8 +
 .../wizard/step6/step6_issues_popup.hbs         |  44 ++---
 ambari-web/app/utils/ajax/ajax.js               |   2 +-
 ambari-web/app/utils/config.js                  |   2 +-
 ambari-web/app/views.js                         |   1 +
 .../views/common/configs/config_history_flow.js |  22 +++
 .../app/views/common/select_custom_date_view.js |  36 ++++
 ambari-web/app/views/main/host/summary.js       |  11 ++
 .../test/nagios/plugins/test_sys_logger.py      |  77 ++++++++-
 .../apache/ambari/view/slider/AlertField.java   |  62 +++++++
 .../apache/ambari/view/slider/AlertState.java   |  40 +++++
 .../apache/ambari/view/slider/SliderApp.java    |   9 +
 .../ambari/view/slider/SliderAppsAlerts.java    | 126 ++++++++++++++
 .../slider/SliderAppsViewControllerImpl.java    |  24 ++-
 .../rest/client/SliderAppMasterClient.java      |  38 +++--
 .../assets/data/resource/service_configs.json   |   2 +-
 .../createAppWizard/step1_controller.js         |   2 +-
 .../resources/ui/app/models/slider_app_alert.js |  43 ++---
 .../ui/app/templates/slider_app/summary.hbs     |   2 +-
 .../ui/app/views/slider_app/summary_view.js     |   2 +-
 105 files changed, 2565 insertions(+), 451 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/f1018b17/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/f1018b17/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/f1018b17/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/f1018b17/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/f1018b17/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/f1018b17/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/f1018b17/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/f1018b17/ambari-web/app/utils/ajax/ajax.js
----------------------------------------------------------------------


[50/50] [abbrv] git commit: Merge branch 'branch-alerts-dev' into trunk

Posted by jo...@apache.org.
Merge branch 'branch-alerts-dev' into trunk


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

Branch: refs/heads/trunk
Commit: 80bceaf3abc8028e7d6b9f9d3a7738132ece6b8a
Parents: 0d953b4 cc2d934
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Mon Oct 6 17:02:54 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Mon Oct 6 17:02:54 2014 -0400

----------------------------------------------------------------------
 ambari-agent/pom.xml                            |   1 +
 .../ambari_agent/AlertSchedulerHandler.py       | 371 ++++++++++
 .../src/main/python/ambari_agent/Controller.py  |  35 +-
 .../src/main/python/ambari_agent/Heartbeat.py   |   8 +-
 .../main/python/ambari_agent/alerts/__init__.py |  18 +
 .../python/ambari_agent/alerts/base_alert.py    | 204 ++++++
 .../python/ambari_agent/alerts/collector.py     |  70 ++
 .../python/ambari_agent/alerts/metric_alert.py  | 174 +++++
 .../python/ambari_agent/alerts/port_alert.py    |  71 ++
 .../python/ambari_agent/alerts/script_alert.py  |  70 ++
 .../python/ambari_agent/apscheduler/__init__.py |   3 +
 .../python/ambari_agent/apscheduler/events.py   |  64 ++
 .../main/python/ambari_agent/apscheduler/job.py | 137 ++++
 .../apscheduler/jobstores/__init__.py           |   0
 .../ambari_agent/apscheduler/jobstores/base.py  |  25 +
 .../apscheduler/jobstores/mongodb_store.py      |  84 +++
 .../apscheduler/jobstores/ram_store.py          |  25 +
 .../apscheduler/jobstores/redis_store.py        |  91 +++
 .../apscheduler/jobstores/shelve_store.py       |  74 ++
 .../apscheduler/jobstores/sqlalchemy_store.py   |  91 +++
 .../ambari_agent/apscheduler/scheduler.py       | 607 +++++++++++++++++
 .../ambari_agent/apscheduler/threadpool.py      | 133 ++++
 .../apscheduler/triggers/__init__.py            |   3 +
 .../apscheduler/triggers/cron/__init__.py       | 144 ++++
 .../apscheduler/triggers/cron/expressions.py    | 194 ++++++
 .../apscheduler/triggers/cron/fields.py         | 100 +++
 .../apscheduler/triggers/interval.py            |  39 ++
 .../ambari_agent/apscheduler/triggers/simple.py |  17 +
 .../python/ambari_agent/apscheduler/util.py     | 230 +++++++
 .../src/test/python/ambari_agent/TestAlerts.py  | 357 ++++++++++
 .../test/python/ambari_agent/TestController.py  |   1 +
 .../ambari_agent/dummy_files/definitions.json   |  37 +
 .../ambari_agent/dummy_files/test_script.py     |   3 +
 ambari-project/pom.xml                          |   7 +-
 ambari-server/pom.xml                           |  22 +-
 .../apache/ambari/server/EagerSingleton.java    |  43 ++
 .../apache/ambari/server/agent/ActionQueue.java |  51 +-
 .../ambari/server/agent/AgentCommand.java       |  37 +-
 .../server/agent/AlertDefinitionCommand.java    | 168 +++++
 .../server/agent/AlertExecutionCommand.java     |  74 ++
 .../ambari/server/agent/CancelCommand.java      |   5 +-
 .../ambari/server/agent/ExecutionCommand.java   | 109 +--
 .../apache/ambari/server/agent/HeartBeat.java   |   6 +
 .../ambari/server/agent/HeartBeatHandler.java   | 174 +++--
 .../ambari/server/agent/HeartBeatResponse.java  | 119 +++-
 .../ambari/server/agent/HeartbeatMonitor.java   |  40 +-
 .../ambari/server/agent/NagiosAlertCommand.java |  11 +-
 .../server/agent/RegistrationResponse.java      |  50 +-
 .../ambari/server/agent/StatusCommand.java      |  43 +-
 .../resources/AlertDefResourceDefinition.java   |   3 -
 .../resources/AlertGroupResourceDefinition.java |  50 ++
 .../api/resources/AlertResourceDefinition.java  |  41 ++
 .../AlertTargetResourceDefinition.java          |  50 ++
 .../resources/ClusterResourceDefinition.java    |   1 +
 .../api/resources/HostResourceDefinition.java   |   7 +-
 .../resources/ResourceInstanceFactoryImpl.java  |  12 +
 .../resources/ServiceResourceDefinition.java    |   5 +-
 .../server/api/services/AlertGroupService.java  | 121 ++++
 .../server/api/services/AlertService.java       |  93 +++
 .../server/api/services/AlertTargetService.java | 106 +++
 .../server/api/services/AmbariMetaInfo.java     | 368 +++++++---
 .../server/api/services/ClusterService.java     |  82 ++-
 .../ambari/server/api/services/HostService.java |  11 +
 .../server/api/services/ServiceService.java     |   9 +
 .../services/parsers/JsonRequestBodyParser.java |  14 +-
 .../controller/AlertDefinitionResponse.java     | 143 ++++
 .../ambari/server/controller/AmbariServer.java  |  26 +-
 .../server/controller/ControllerModule.java     |  71 +-
 .../AbstractControllerResourceProvider.java     |  12 +-
 .../internal/AbstractProviderModule.java        |  41 +-
 .../AlertDefinitionResourceProvider.java        | 465 +++++++++----
 .../internal/AlertGroupResourceProvider.java    | 403 +++++++++++
 .../internal/AlertResourceProvider.java         | 191 ++++++
 .../internal/AlertSummaryPropertyProvider.java  | 138 ++++
 .../internal/AlertTargetResourceProvider.java   | 369 ++++++++++
 .../nagios/NagiosPropertyProvider.java          |  27 +-
 .../ambari/server/controller/spi/Resource.java  |  15 +-
 .../events/AlertDefinitionDeleteEvent.java      |  55 ++
 .../AlertDefinitionRegistrationEvent.java       |  57 ++
 .../apache/ambari/server/events/AlertEvent.java |  58 ++
 .../server/events/AlertReceivedEvent.java       |  50 ++
 .../server/events/AlertStateChangeEvent.java    | 101 +++
 .../ambari/server/events/AmbariEvent.java       |  75 ++
 .../ambari/server/events/ClusterEvent.java      |  50 ++
 .../server/events/MaintenanceModeEvent.java     | 175 +++++
 .../ambari/server/events/ServiceEvent.java      |  75 ++
 .../server/events/ServiceInstalledEvent.java    |  52 ++
 .../listeners/AlertAggregateListener.java       | 126 ++++
 .../listeners/AlertLifecycleListener.java       | 127 ++++
 .../listeners/AlertMaintenanceModeListener.java | 199 ++++++
 .../events/listeners/AlertReceivedListener.java | 191 ++++++
 .../listeners/AlertServiceStateListener.java    | 150 ++++
 .../listeners/AlertStateChangedListener.java    | 113 +++
 .../events/publishers/AlertEventPublisher.java  | 108 +++
 .../events/publishers/AmbariEventPublisher.java |  66 ++
 .../server/notifications/DispatchCallback.java  |  50 ++
 .../notifications/DispatchCredentials.java      |  44 ++
 .../server/notifications/DispatchFactory.java   |  78 +++
 .../server/notifications/DispatchRunnable.java  |  60 ++
 .../server/notifications/Notification.java      |  75 ++
 .../notifications/NotificationDispatcher.java   |  47 ++
 .../ambari/server/notifications/Recipient.java  |  45 ++
 .../dispatchers/EmailDispatcher.java            | 179 +++++
 .../server/orm/dao/AlertDefinitionDAO.java      | 242 ++++++-
 .../ambari/server/orm/dao/AlertDispatchDAO.java | 183 ++++-
 .../ambari/server/orm/dao/AlertSummaryDTO.java  |  70 ++
 .../apache/ambari/server/orm/dao/AlertsDAO.java | 206 +++++-
 .../server/orm/entities/AlertCurrentEntity.java |  45 +-
 .../orm/entities/AlertDefinitionEntity.java     |  91 ++-
 .../server/orm/entities/AlertGroupEntity.java   |  65 +-
 .../server/orm/entities/AlertHistoryEntity.java |  55 +-
 .../server/orm/entities/AlertNoticeEntity.java  |   2 +
 .../server/orm/entities/AlertTargetEntity.java  |   3 +-
 .../server/orm/entities/ClusterEntity.java      |  75 +-
 .../org/apache/ambari/server/state/Alert.java   |  66 +-
 .../ambari/server/state/ConfigFactory.java      |   2 -
 .../apache/ambari/server/state/ServiceImpl.java |  61 +-
 .../state/alert/AggregateDefinitionMapping.java | 111 +++
 .../server/state/alert/AggregateSource.java     |  92 +++
 .../server/state/alert/AlertDefinition.java     | 221 +++++-
 .../state/alert/AlertDefinitionFactory.java     | 285 ++++++++
 .../server/state/alert/AlertDefinitionHash.java | 638 +++++++++++++++++
 .../ambari/server/state/alert/AlertGroup.java   | 124 ++++
 .../ambari/server/state/alert/AlertTarget.java  | 130 ++++
 .../ambari/server/state/alert/MetricSource.java | 128 +++-
 .../server/state/alert/PercentSource.java       | 191 ++++++
 .../ambari/server/state/alert/PortSource.java   | 113 +++
 .../ambari/server/state/alert/Reporting.java    | 247 +++++++
 .../apache/ambari/server/state/alert/Scope.java |  18 +-
 .../ambari/server/state/alert/ScriptSource.java |  81 +++
 .../ambari/server/state/alert/Source.java       |  71 +-
 .../ambari/server/state/alert/SourceType.java   |   9 +-
 .../ambari/server/state/alert/TargetType.java   |  46 ++
 .../server/state/cluster/ClusterImpl.java       | 109 ++-
 .../ambari/server/state/host/HostImpl.java      | 133 ++--
 .../services/AlertNoticeDispatchService.java    | 398 +++++++++++
 .../svccomphost/ServiceComponentHostImpl.java   | 109 ++-
 .../server/upgrade/UpgradeCatalog170.java       |   3 +-
 .../apache/ambari/server/utils/StageUtils.java  |  10 -
 .../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 +-
 .../src/main/resources/key_properties.json      |  13 +
 .../src/main/resources/properties.json          |  37 +-
 .../stacks/HDP/2.0.6/services/HBASE/alerts.json |  24 +
 .../stacks/HDP/2.0.6/services/HDFS/alerts.json  | 147 ++++
 .../ambari/server/agent/TestActionQueue.java    |  88 ++-
 .../api/query/render/DefaultRendererTest.java   |   3 +-
 .../api/query/render/MinimalRendererTest.java   |   3 +-
 .../ClusterResourceDefinitionTest.java          |   3 +-
 .../server/api/services/AmbariMetaInfoTest.java | 104 ++-
 .../AmbariManagementControllerTest.java         | 132 +++-
 .../AlertDefinitionResourceProviderTest.java    | 221 +++++-
 .../AlertGroupResourceProviderTest.java         | 611 +++++++++++++++++
 .../internal/AlertResourceProviderTest.java     | 241 +++++++
 .../AlertTargetResourceProviderTest.java        | 408 +++++++++++
 .../nagios/NagiosPropertyProviderTest.java      |  80 +--
 .../apache/ambari/server/events/EventsTest.java | 188 +++++
 .../ambari/server/events/MockEventListener.java |  99 +++
 .../notifications/EmailDispatcherTest.java      | 117 ++++
 .../server/notifications/MockDispatcher.java    |  46 ++
 .../apache/ambari/server/orm/OrmTestHelper.java |  42 +-
 .../server/orm/dao/AlertDefinitionDAOTest.java  | 165 ++++-
 .../server/orm/dao/AlertDispatchDAOTest.java    | 125 +++-
 .../ambari/server/orm/dao/AlertsDAOTest.java    | 681 +++++++++++++++++--
 .../alerts/AlertDefinitionEqualityTest.java     | 158 +++++
 .../state/alerts/AlertDefinitionHashTest.java   | 407 +++++++++++
 .../state/alerts/AlertEventPublisherTest.java   | 196 ++++++
 .../alerts/AlertStateChangedEventTest.java      | 147 ++++
 .../state/cluster/AlertDataManagerTest.java     | 449 ++++++++++++
 .../svccomphost/ServiceComponentHostTest.java   | 242 +++----
 .../ambari/server/utils/TestStageUtils.java     | 120 ++--
 .../stacks/HDP/2.0.5/services/HDFS/alerts.json  |  77 +++
 .../app/controllers/global/update_controller.js |   4 +-
 .../app/controllers/main/alerts_controller.js   |   4 +-
 ambari-web/app/controllers/main/host.js         |   4 +-
 ambari-web/app/mappers/hosts_mapper.js          |   2 +-
 ambari-web/app/mappers/service_mapper.js        |   8 +-
 ambari-web/app/utils/ajax/ajax.js               |   6 +-
 .../controllers/main/alerts_controller_test.js  |  28 +-
 181 files changed, 18299 insertions(+), 1292 deletions(-)
----------------------------------------------------------------------



[46/50] [abbrv] git commit: AMBARI-7642 - Alerts: Maintenance Mode Should Prevent Alert Notifications (jonathanhurley)

Posted by jo...@apache.org.
AMBARI-7642 - Alerts: Maintenance Mode Should Prevent Alert Notifications (jonathanhurley)


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

Branch: refs/heads/trunk
Commit: 3e54f95689d7854fc17a31a2734aea080efd7d71
Parents: 6f9398f
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Fri Oct 3 16:23:31 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Fri Oct 3 23:13:44 2014 -0400

----------------------------------------------------------------------
 .../apache/ambari/server/EagerSingleton.java    |  43 ++
 .../server/controller/ControllerModule.java     |  56 ++-
 .../server/events/AlertStateChangeEvent.java    |  26 +-
 .../ambari/server/events/AmbariEvent.java       |   7 +-
 .../server/events/MaintenanceModeEvent.java     | 175 +++++++
 .../listeners/AlertAggregateListener.java       |   2 +
 .../listeners/AlertLifecycleListener.java       |   2 +
 .../listeners/AlertMaintenanceModeListener.java | 199 ++++++++
 .../events/listeners/AlertReceivedListener.java |   6 +-
 .../listeners/AlertServiceStateListener.java    |   2 +
 .../listeners/AlertStateChangedListener.java    |  11 +
 .../apache/ambari/server/state/ServiceImpl.java |   5 +
 .../ambari/server/state/host/HostImpl.java      | 133 +++---
 .../svccomphost/ServiceComponentHostImpl.java   |  13 +
 .../apache/ambari/server/events/EventsTest.java | 188 ++++++++
 .../ambari/server/events/MockEventListener.java |  99 ++++
 .../ambari/server/orm/dao/AlertsDAOTest.java    | 456 ++++++++++++++++---
 .../state/cluster/AlertDataManagerTest.java     |  10 +-
 18 files changed, 1280 insertions(+), 153 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/3e54f956/ambari-server/src/main/java/org/apache/ambari/server/EagerSingleton.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/EagerSingleton.java b/ambari-server/src/main/java/org/apache/ambari/server/EagerSingleton.java
new file mode 100644
index 0000000..dde4143
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/EagerSingleton.java
@@ -0,0 +1,43 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import com.google.inject.Module;
+import com.google.inject.ScopeAnnotation;
+import com.google.inject.Singleton;
+import com.google.inject.binder.AnnotatedBindingBuilder;
+
+/**
+ * The {@link EagerSingleton} annotation is used to mark a {@link Singleton}
+ * class as being needed to be eagerly registered by a {@link Module}.
+ * <p/>
+ * Classes marked with this annotation should also be {@link Singleton}. They
+ * will be discovered on the classpath and then
+ * {@link AnnotatedBindingBuilder#asEagerSingleton()} will be invoked on them.
+ */
+@Target({ ElementType.TYPE })
+@Retention(RUNTIME)
+@ScopeAnnotation
+public @interface EagerSingleton {
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/3e54f956/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
index da78639..535a75e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
@@ -39,6 +39,7 @@ import java.util.Map.Entry;
 import java.util.Properties;
 import java.util.Set;
 
+import org.apache.ambari.server.EagerSingleton;
 import org.apache.ambari.server.actionmanager.ActionDBAccessor;
 import org.apache.ambari.server.actionmanager.ActionDBAccessorImpl;
 import org.apache.ambari.server.actionmanager.ExecutionCommandWrapper;
@@ -53,11 +54,6 @@ import org.apache.ambari.server.controller.internal.HostResourceProvider;
 import org.apache.ambari.server.controller.internal.MemberResourceProvider;
 import org.apache.ambari.server.controller.internal.ServiceResourceProvider;
 import org.apache.ambari.server.controller.spi.ResourceProvider;
-import org.apache.ambari.server.events.listeners.AlertAggregateListener;
-import org.apache.ambari.server.events.listeners.AlertLifecycleListener;
-import org.apache.ambari.server.events.listeners.AlertReceivedListener;
-import org.apache.ambari.server.events.listeners.AlertServiceStateListener;
-import org.apache.ambari.server.events.listeners.AlertStateChangedListener;
 import org.apache.ambari.server.orm.DBAccessor;
 import org.apache.ambari.server.orm.DBAccessorImpl;
 import org.apache.ambari.server.orm.PersistenceType;
@@ -99,8 +95,14 @@ import org.eclipse.jetty.server.SessionIdManager;
 import org.eclipse.jetty.server.SessionManager;
 import org.eclipse.jetty.server.session.HashSessionIdManager;
 import org.eclipse.jetty.server.session.HashSessionManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
+import org.springframework.core.type.filter.AnnotationTypeFilter;
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.security.crypto.password.StandardPasswordEncoder;
+import org.springframework.util.ClassUtils;
 import org.springframework.web.filter.DelegatingFilterProxy;
 
 import com.google.common.util.concurrent.ServiceManager;
@@ -117,6 +119,7 @@ import com.google.inject.persist.jpa.AmbariJpaPersistModule;
  * Used for injection purposes.
  */
 public class ControllerModule extends AbstractModule {
+  private static Logger LOG = LoggerFactory.getLogger(ControllerModule.class);
 
   private final Configuration configuration;
   private final HostsMap hostsMap;
@@ -317,9 +320,11 @@ public class ControllerModule extends AbstractModule {
    * instances and then register them with a singleton {@link ServiceManager}.
    */
   private void bindServices() {
-    Set<com.google.common.util.concurrent.Service> services = new HashSet<com.google.common.util.concurrent.Service>();
+    Set<com.google.common.util.concurrent.Service> services =
+        new HashSet<com.google.common.util.concurrent.Service>();
 
-    AlertNoticeDispatchService alertNoticeDispatchService = new AlertNoticeDispatchService();
+    AlertNoticeDispatchService alertNoticeDispatchService =
+        new AlertNoticeDispatchService();
 
     bind(AlertNoticeDispatchService.class).toInstance(
         alertNoticeDispatchService);
@@ -332,14 +337,35 @@ public class ControllerModule extends AbstractModule {
   /**
    * Initializes all eager singletons that should be instantiated as soon as
    * possible and not wait for injection.
+   * <p/>
+   * An example of where this is needed is with a singleton that is headless; in
+   * other words, it doesn't have any injections but still needs to be part of
+   * the Guice framework.
+   * <p/>
+   * This currently scans {@code org.apache.ambari.server} for any
+   * {@link EagerSingleton} instances.
    */
   private void bindEagerSingletons() {
-    // alert subscribers are "headless" and have no guice references; created
-    // them as eager singletons to have them register with the eventbus
-    bind(AlertReceivedListener.class).asEagerSingleton();
-    bind(AlertStateChangedListener.class).asEagerSingleton();
-    bind(AlertServiceStateListener.class).asEagerSingleton();
-    bind(AlertLifecycleListener.class).asEagerSingleton();
-    bind(AlertAggregateListener.class).asEagerSingleton();
+    ClassPathScanningCandidateComponentProvider scanner =
+        new ClassPathScanningCandidateComponentProvider(false);
+
+    // match only singletons that are eager listeners
+    scanner.addIncludeFilter(new AnnotationTypeFilter(EagerSingleton.class));
+
+    Set<BeanDefinition> beanDefinitions = scanner.findCandidateComponents("org.apache.ambari.server");
+
+    if (null == beanDefinitions || beanDefinitions.size() == 0) {
+      LOG.warn("No instances of {} found to register", EagerSingleton.class);
+      return;
+    }
+
+    for (BeanDefinition beanDefinition : beanDefinitions) {
+      String className = beanDefinition.getBeanClassName();
+      Class<?> clazz = ClassUtils.resolveClassName(className,
+          ClassUtils.getDefaultClassLoader());
+
+      bind(clazz).asEagerSingleton();
+      LOG.debug("Binding singleton {} eagerly", clazz);
+    }
   }
-}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/3e54f956/ambari-server/src/main/java/org/apache/ambari/server/events/AlertStateChangeEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/AlertStateChangeEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/AlertStateChangeEvent.java
index efb7119..e637709 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/AlertStateChangeEvent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/AlertStateChangeEvent.java
@@ -17,6 +17,7 @@
  */
 package org.apache.ambari.server.events;
 
+import org.apache.ambari.server.orm.entities.AlertCurrentEntity;
 import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
 import org.apache.ambari.server.state.Alert;
 import org.apache.ambari.server.state.AlertState;
@@ -33,9 +34,14 @@ public class AlertStateChangeEvent extends AlertEvent {
   private final AlertState m_fromState;
 
   /**
-   * The newly created historical entry.
+   * The current alert, including state and history.
    */
-  private final AlertHistoryEntity m_newEntity;
+  private final AlertCurrentEntity m_currentAlert;
+
+  /**
+   * The historical record for this alert state change event.
+   */
+  private final AlertHistoryEntity m_history;
 
   /**
    * Constructor.
@@ -44,20 +50,30 @@ public class AlertStateChangeEvent extends AlertEvent {
    * @param alert
    */
   public AlertStateChangeEvent(long clusterId, Alert alert,
-      AlertHistoryEntity newEntity, AlertState fromState) {
+      AlertCurrentEntity currentAlert, AlertState fromState) {
     super(clusterId, alert);
 
-    m_newEntity = newEntity;
+    m_currentAlert = currentAlert;
+    m_history = currentAlert.getAlertHistory();
     m_fromState = fromState;
   }
 
   /**
+   * Gets the current alert.
+   *
+   * @return the current alert.
+   */
+  public AlertCurrentEntity getCurrentAlert() {
+    return m_currentAlert;
+  }
+
+  /**
    * Gets the newly created item in alert history.
    *
    * @return the newly created historical item.
    */
   public AlertHistoryEntity getNewHistoricalEntry() {
-    return m_newEntity;
+    return m_history;
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/3e54f956/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java
index 3dae676..5f2517e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java
@@ -40,7 +40,12 @@ public abstract class AmbariEvent {
     /**
      * An alert definition is removed from the system.
      */
-    ALERT_DEFINITION_REMOVAL;
+    ALERT_DEFINITION_REMOVAL,
+
+    /**
+     * A host/service/component has had a maintenance mode change.
+     */
+    MAINTENANCE_MODE;
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/3e54f956/ambari-server/src/main/java/org/apache/ambari/server/events/MaintenanceModeEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/MaintenanceModeEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/MaintenanceModeEvent.java
new file mode 100644
index 0000000..810cab4
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/MaintenanceModeEvent.java
@@ -0,0 +1,175 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.events;
+
+import org.apache.ambari.server.state.Host;
+import org.apache.ambari.server.state.MaintenanceState;
+import org.apache.ambari.server.state.Service;
+import org.apache.ambari.server.state.ServiceComponentHost;
+
+/**
+ * The {@link MaintenanceModeEvent} is used to capture a host/service/component
+ * maintenance mode change and broadcast it to the system.
+ * <p/>
+ * Although there are several different states aside from on & off in
+ * {@link MaintenanceState}, this event should handle explicit on or off state
+ * changes. This event should not be used for implied state changes, such as
+ * when a component goes into implied maintenance mode as a result of its host's
+ * maintenance mode being explicitely invoked.
+ */
+public class MaintenanceModeEvent extends AmbariEvent {
+
+  /**
+   * The new maintenance state.
+   */
+  private final MaintenanceState m_state;
+
+  /**
+   * The service whose maintenance state changed, or {@code null}.
+   */
+  private final Service m_service;
+
+  /**
+   * The host whose maintenance state changed, or {@code null}.
+   */
+  private final Host m_host;
+
+  /**
+   * The component whose maintenace state changed, or {@code null}.
+   */
+  private final ServiceComponentHost m_serviceComponentHost;
+
+  /**
+   * Constructor.
+   *
+   * @param state
+   *          the new state (not {@code null}).
+   * @param service
+   *          the service that changed maintenance state (not {@code null})).
+   */
+  public MaintenanceModeEvent(MaintenanceState state, Service service) {
+    this(state, service, null, null);
+  }
+
+  /**
+   * Constructor.
+   *
+   * @param state
+   *          the new state (not {@code null}).
+   * @param host
+   *          the host that changed maintenance state (not {@code null})).
+   */
+  public MaintenanceModeEvent(MaintenanceState state, Host host) {
+    this(state, null, host, null);
+  }
+
+  /**
+   * Constructor.
+   *
+   * @param state
+   *          the new state (not {@code null}).
+   * @param serviceComponentHost
+   *          the component that changed maintenance state (not {@code null})).
+   */
+  public MaintenanceModeEvent(MaintenanceState state,
+      ServiceComponentHost serviceComponentHost) {
+    this(state, null, null, serviceComponentHost);
+  }
+
+  /**
+   * Constructor.
+   *
+   * @param state
+   *          the new state (not {@code null}).
+   * @param service
+   *          the service that changed maintenance state, or {@code null}.
+   * @param host
+   *          the host that changed maintenance state, or {@code null}.
+   * @param serviceComponentHost
+   *          the component that changed maintenance state, or {@code null}.
+   */
+  private MaintenanceModeEvent(MaintenanceState state, Service service,
+      Host host, ServiceComponentHost serviceComponentHost) {
+    super(AmbariEventType.MAINTENANCE_MODE);
+    m_state = state;
+    m_service = service;
+    m_host = host;
+    m_serviceComponentHost = serviceComponentHost;
+  }
+
+  /**
+   * Gets the service that had the direct maintenance mode event, or
+   * {@code null} if the event was not directly on a service.
+   *
+   * @return the service or {@code null}
+   */
+  public Service getService() {
+    return m_service;
+  }
+
+  /**
+   * Gets the host that had the direct maintenance mode event, or {@code null}
+   * if the event was not directly on a host.
+   *
+   * @return the host or {@code null}
+   */
+  public Host getHost() {
+    return m_host;
+  }
+
+  /**
+   * Gets the component that had the direct maintenance mode event, or
+   * {@code null} if the event was not directly on a component.
+   *
+   * @return the component or {@code null}
+   */
+  public ServiceComponentHost getServiceComponentHost() {
+    return m_serviceComponentHost;
+  }
+
+  /**
+   * Gets the new maintenance state for the service/host/component.
+   *
+   * @return the new maintenance state (never {@code null}).
+   */
+  public MaintenanceState getMaintenanceState() {
+    return m_state;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString() {
+    Object object = null;
+    if (null != m_service) {
+      object = m_service;
+    } else if (null != m_host) {
+      object = m_host;
+    } else {
+      object = m_serviceComponentHost;
+    }
+
+    StringBuilder buffer = new StringBuilder("MaintenanceModeEvent{ ");
+    buffer.append("state=").append(m_state);
+    buffer.append(", object=").append(object);
+    buffer.append(" }");
+
+    return buffer.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/3e54f956/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertAggregateListener.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertAggregateListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertAggregateListener.java
index a0c8e46..5e9dea2 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertAggregateListener.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertAggregateListener.java
@@ -19,6 +19,7 @@ package org.apache.ambari.server.events.listeners;
 
 import java.text.MessageFormat;
 
+import org.apache.ambari.server.EagerSingleton;
 import org.apache.ambari.server.events.AlertReceivedEvent;
 import org.apache.ambari.server.events.publishers.AlertEventPublisher;
 import org.apache.ambari.server.orm.dao.AlertSummaryDTO;
@@ -41,6 +42,7 @@ import com.google.inject.Singleton;
  * {@link SourceType#AGGREGATE} alert that needs to run.
  */
 @Singleton
+@EagerSingleton
 public class AlertAggregateListener {
 
   @Inject

http://git-wip-us.apache.org/repos/asf/ambari/blob/3e54f956/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertLifecycleListener.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertLifecycleListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertLifecycleListener.java
index 9d2f4c6..22932ee 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertLifecycleListener.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertLifecycleListener.java
@@ -19,6 +19,7 @@ package org.apache.ambari.server.events.listeners;
 
 import java.util.Set;
 
+import org.apache.ambari.server.EagerSingleton;
 import org.apache.ambari.server.events.AlertDefinitionDeleteEvent;
 import org.apache.ambari.server.events.AlertDefinitionRegistrationEvent;
 import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
@@ -40,6 +41,7 @@ import com.google.inject.Singleton;
  * infrastructure lifecycle such as definition registration events.
  */
 @Singleton
+@EagerSingleton
 public class AlertLifecycleListener {
   /**
    * Logger.

http://git-wip-us.apache.org/repos/asf/ambari/blob/3e54f956/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertMaintenanceModeListener.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertMaintenanceModeListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertMaintenanceModeListener.java
new file mode 100644
index 0000000..af008be
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertMaintenanceModeListener.java
@@ -0,0 +1,199 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.events.listeners;
+
+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.events.MaintenanceModeEvent;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
+import org.apache.ambari.server.orm.dao.AlertsDAO;
+import org.apache.ambari.server.orm.entities.AlertCurrentEntity;
+import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
+import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
+import org.apache.ambari.server.orm.entities.AlertNoticeEntity;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.MaintenanceState;
+import org.apache.ambari.server.state.Service;
+import org.apache.ambari.server.state.ServiceComponentHost;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.eventbus.AllowConcurrentEvents;
+import com.google.common.eventbus.Subscribe;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+
+/**
+ * The {@link AlertMaintenanceModeListener} handles events that relate to
+ * Maintenance Mode changes.
+ */
+@Singleton
+@EagerSingleton
+public class AlertMaintenanceModeListener {
+  /**
+   * Logger.
+   */
+  private static Logger LOG = LoggerFactory.getLogger(AlertMaintenanceModeListener.class);
+
+  /**
+   * Used for updating the MM of current alerts.
+   */
+  @Inject
+  private AlertsDAO m_alertsDao = null;
+
+  /**
+   * Used to assist in determining implied maintenance state.
+   */
+  @Inject
+  private Provider<MaintenanceStateHelper> m_maintenanceHelper;
+
+  /**
+   * Used to lookup MM states.
+   */
+  @Inject
+  private Provider<Clusters> m_clusters;
+
+  /**
+   * Constructor.
+   *
+   * @param publisher
+   */
+  @Inject
+  public AlertMaintenanceModeListener(AmbariEventPublisher publisher) {
+    publisher.register(this);
+  }
+
+  /**
+   * Handles {@link MaintenanceModeEvent} by performing the following tasks:
+   * <ul>
+   * <li>Iterates through all {@link AlertNoticeEntity}, updating the MM state</li>
+   * </ul>
+   *
+   * @param event
+   *          the event being handled.
+   */
+  @Subscribe
+  @AllowConcurrentEvents
+  public void onEvent(MaintenanceModeEvent event) {
+    List<AlertCurrentEntity> currentAlerts = m_alertsDao.findCurrent();
+
+    for( AlertCurrentEntity currentAlert : currentAlerts ){
+      MaintenanceState currentState = currentAlert.getMaintenanceState();
+      AlertHistoryEntity history = currentAlert.getAlertHistory();
+      AlertDefinitionEntity definition = history.getAlertDefinition();
+
+      long clusterId = history.getClusterId();
+      String hostName = history.getHostName();
+      String serviceName = history.getServiceName();
+      String componentName = history.getComponentName();
+
+      try {
+        Cluster cluster = m_clusters.get().getClusterById(clusterId);
+        if (null == cluster) {
+          LOG.warn("Unable to find cluster with ID {}", clusterId);
+          continue;
+        }
+
+        Service service = cluster.getService(serviceName);
+        if (null == service) {
+          LOG.warn("Unable to find service named {} in cluster {}",
+              serviceName, cluster.getClusterName());
+
+          continue;
+        }
+
+        // if this is a service-level alert, then check explicitely against the
+        // service for the MM state
+        if (null == componentName) {
+          MaintenanceState serviceState = service.getMaintenanceState();
+          if (currentState != serviceState) {
+            currentAlert.setMaintenanceState(serviceState);
+            m_alertsDao.merge(currentAlert);
+          }
+        }
+        // the presence of a component name means that it's a component alert
+        // which require a host
+        else {
+          if (hostName == null) {
+            LOG.warn("The alert {} for component {} must have a host",
+                definition.getDefinitionName(), componentName);
+
+            continue;
+          }
+
+          List<ServiceComponentHost> serviceComponentHosts = cluster.getServiceComponentHosts(hostName);
+          if (null == serviceComponentHosts) {
+            LOG.warn(
+                "Unable to find service components on host {} for {} in cluster {}",
+                hostName, serviceName, cluster.getClusterName());
+
+            continue;
+          }
+
+          ServiceComponentHost serviceComponentHost = null;
+          for (ServiceComponentHost sch : serviceComponentHosts) {
+            if (componentName.equals(sch.getServiceComponentName())) {
+              serviceComponentHost = sch;
+              break;
+            }
+          }
+
+          if (null == serviceComponentHost) {
+            LOG.warn("Unable to find component {} of {} on host {}",
+                componentName, serviceName, hostName);
+
+            continue;
+          }
+
+          MaintenanceState effectiveState = m_maintenanceHelper.get().getEffectiveState(
+              serviceComponentHost);
+
+          switch (effectiveState) {
+            case OFF:
+              if (currentState != MaintenanceState.OFF) {
+                currentAlert.setMaintenanceState(MaintenanceState.OFF);
+                m_alertsDao.merge(currentAlert);
+              }
+
+              break;
+            case ON:
+            case IMPLIED_FROM_HOST:
+            case IMPLIED_FROM_SERVICE:
+            case IMPLIED_FROM_SERVICE_AND_HOST:
+              if (currentState == MaintenanceState.OFF) {
+                currentAlert.setMaintenanceState(MaintenanceState.ON);
+                m_alertsDao.merge(currentAlert);
+              }
+
+              break;
+            default:
+              break;
+          }
+        }
+      } catch (AmbariException ambariException) {
+        LOG.error("Unable to put alert '{}' for host {} into maintenance mode",
+            definition.getDefinitionName(), hostName, ambariException);
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/3e54f956/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java
index 78d8e66..45d0734 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java
@@ -17,6 +17,7 @@
  */
 package org.apache.ambari.server.events.listeners;
 
+import org.apache.ambari.server.EagerSingleton;
 import org.apache.ambari.server.events.AlertEvent;
 import org.apache.ambari.server.events.AlertReceivedEvent;
 import org.apache.ambari.server.events.AlertStateChangeEvent;
@@ -28,6 +29,7 @@ import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
 import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
 import org.apache.ambari.server.state.Alert;
 import org.apache.ambari.server.state.AlertState;
+import org.apache.ambari.server.state.MaintenanceState;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -42,6 +44,7 @@ import com.google.inject.Singleton;
  * {@link AlertStateChangeEvent} when an {@link AlertState} change is detected.
  */
 @Singleton
+@EagerSingleton
 public class AlertReceivedListener {
   /**
    * Logger.
@@ -112,6 +115,7 @@ public class AlertReceivedListener {
       AlertHistoryEntity history = createHistory(clusterId, definition, alert);
 
       current = new AlertCurrentEntity();
+      current.setMaintenanceState(MaintenanceState.OFF);
       current.setAlertHistory(history);
       current.setLatestTimestamp(Long.valueOf(alert.getTimestamp()));
       current.setOriginalTimestamp(Long.valueOf(alert.getTimestamp()));
@@ -155,7 +159,7 @@ public class AlertReceivedListener {
 
       // broadcast the alert changed event for other subscribers
       AlertStateChangeEvent alertChangedEvent = new AlertStateChangeEvent(
-          event.getClusterId(), event.getAlert(), current.getAlertHistory(),
+          event.getClusterId(), event.getAlert(), current,
           oldState);
 
       m_alertEventPublisher.publish(alertChangedEvent);

http://git-wip-us.apache.org/repos/asf/ambari/blob/3e54f956/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertServiceStateListener.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertServiceStateListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertServiceStateListener.java
index 6215cc1..9a1a68b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertServiceStateListener.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertServiceStateListener.java
@@ -21,6 +21,7 @@ import java.text.MessageFormat;
 import java.util.Set;
 
 import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.EagerSingleton;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.controller.AmbariServer;
 import org.apache.ambari.server.controller.ControllerModule;
@@ -48,6 +49,7 @@ import com.google.inject.Singleton;
  * and {@link AlertGroupEntity} instances are correctly populated.
  */
 @Singleton
+@EagerSingleton
 public class AlertServiceStateListener {
   /**
    * Logger.

http://git-wip-us.apache.org/repos/asf/ambari/blob/3e54f956/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertStateChangedListener.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertStateChangedListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertStateChangedListener.java
index b2f08d7..c42851b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertStateChangedListener.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertStateChangedListener.java
@@ -21,14 +21,17 @@ import java.util.List;
 import java.util.Set;
 import java.util.UUID;
 
+import org.apache.ambari.server.EagerSingleton;
 import org.apache.ambari.server.events.AlertStateChangeEvent;
 import org.apache.ambari.server.events.publishers.AlertEventPublisher;
 import org.apache.ambari.server.orm.dao.AlertDispatchDAO;
+import org.apache.ambari.server.orm.entities.AlertCurrentEntity;
 import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
 import org.apache.ambari.server.orm.entities.AlertGroupEntity;
 import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
 import org.apache.ambari.server.orm.entities.AlertNoticeEntity;
 import org.apache.ambari.server.orm.entities.AlertTargetEntity;
+import org.apache.ambari.server.state.MaintenanceState;
 import org.apache.ambari.server.state.NotificationState;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -44,6 +47,7 @@ import com.google.inject.Singleton;
  * in the database.
  */
 @Singleton
+@EagerSingleton
 public class AlertStateChangedListener {
 
   /**
@@ -75,6 +79,13 @@ public class AlertStateChangedListener {
   public void onAlertEvent(AlertStateChangeEvent event) {
     LOG.debug(event);
 
+    // don't create any outbound alert notices if in MM
+    AlertCurrentEntity currentAlert = event.getCurrentAlert();
+    if (null != currentAlert
+        && currentAlert.getMaintenanceState() != MaintenanceState.OFF) {
+      return;
+    }
+
     AlertHistoryEntity history = event.getNewHistoricalEntry();
     AlertDefinitionEntity definition = history.getAlertDefinition();
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/3e54f956/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java
index e6b5921..d7880c4 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java
@@ -27,6 +27,7 @@ import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.ServiceComponentNotFoundException;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.controller.ServiceResponse;
+import org.apache.ambari.server.events.MaintenanceModeEvent;
 import org.apache.ambari.server.events.ServiceInstalledEvent;
 import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 import org.apache.ambari.server.orm.dao.ClusterDAO;
@@ -675,6 +676,10 @@ public class ServiceImpl implements Service {
         readWriteLock.writeLock().lock();
         serviceDesiredStateEntity.setMaintenanceState(state);
         saveIfPersisted();
+
+        // broadcast the maintenance mode change
+        MaintenanceModeEvent event = new MaintenanceModeEvent(state, this);
+        eventPublisher.publish(event);
       } finally {
         readWriteLock.writeLock().unlock();
       }

http://git-wip-us.apache.org/repos/asf/ambari/blob/3e54f956/ambari-server/src/main/java/org/apache/ambari/server/state/host/HostImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/host/HostImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/host/HostImpl.java
index 619859c..53f5f40 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/host/HostImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/host/HostImpl.java
@@ -31,6 +31,8 @@ import org.apache.ambari.server.agent.AgentEnv;
 import org.apache.ambari.server.agent.DiskInfo;
 import org.apache.ambari.server.agent.HostInfo;
 import org.apache.ambari.server.controller.HostResponse;
+import org.apache.ambari.server.events.MaintenanceModeEvent;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 import org.apache.ambari.server.orm.cache.HostConfigMapping;
 import org.apache.ambari.server.orm.cache.HostConfigMappingImpl;
 import org.apache.ambari.server.orm.dao.ClusterDAO;
@@ -89,7 +91,7 @@ public class HostImpl implements Host {
   private static final String TIMEZONE = "timezone";
   private static final String OS_RELEASE_VERSION = "os_release_version";
 
-  
+
   private final Gson gson;
 
   private static final Type hostAttributesType =
@@ -114,18 +116,22 @@ public class HostImpl implements Host {
   private List<DiskInfo> disksInfo = new ArrayList<DiskInfo>();
   private boolean persisted = false;
   private Integer currentPingPort = null;
-  
+
   private final StateMachine<HostState, HostEventType, HostEvent> stateMachine;
   private Map<Long, MaintenanceState> maintMap = null;
 
-  
-  
   // In-memory status, based on host components states
   private String status;
 
   // In-memory prefix of log file paths that is retrieved when the agent registers with the server
   private String prefix;
 
+  /**
+   * Used to publish events relating to host CRUD operations.
+   */
+  @Inject
+  private AmbariEventPublisher eventPublisher;
+
   private static final StateMachineFactory
     <HostImpl, HostState, HostEventType, HostEvent>
       stateMachineFactory
@@ -214,19 +220,19 @@ public class HostImpl implements Host {
   @Inject
   public HostImpl(@Assisted HostEntity hostEntity,
       @Assisted boolean persisted, Injector injector) {
-    this.stateMachine = stateMachineFactory.make(this);
+    stateMachine = stateMachineFactory.make(this);
     rwLock = new ReentrantReadWriteLock();
-    this.readLock = rwLock.readLock();
-    this.writeLock = rwLock.writeLock();
+    readLock = rwLock.readLock();
+    writeLock = rwLock.writeLock();
 
     this.hostEntity = hostEntity;
     this.persisted = persisted;
-    this.hostDAO = injector.getInstance(HostDAO.class);
-    this.hostStateDAO = injector.getInstance(HostStateDAO.class);
-    this.gson = injector.getInstance(Gson.class);
-    this.clusterDAO = injector.getInstance(ClusterDAO.class);
-    this.clusters = injector.getInstance(Clusters.class);
-    this.hostConfigMappingDAO = injector.getInstance(HostConfigMappingDAO.class);
+    hostDAO = injector.getInstance(HostDAO.class);
+    hostStateDAO = injector.getInstance(HostStateDAO.class);
+    gson = injector.getInstance(Gson.class);
+    clusterDAO = injector.getInstance(ClusterDAO.class);
+    clusters = injector.getInstance(Clusters.class);
+    hostConfigMappingDAO = injector.getInstance(HostConfigMappingDAO.class);
 
     hostStateEntity = hostEntity.getHostStateEntity();
     if (hostStateEntity == null) {
@@ -238,7 +244,7 @@ public class HostImpl implements Host {
         persist();
       }
     } else {
-      this.stateMachine.setCurrentState(hostStateEntity.getCurrentState());
+      stateMachine.setCurrentState(hostStateEntity.getCurrentState());
     }
 
   }
@@ -405,7 +411,7 @@ public class HostImpl implements Host {
       }
 
       // FIXME add all other information into host attributes
-      this.setAgentVersion(new AgentVersion(
+      setAgentVersion(new AgentVersion(
           hostInfo.getAgentUserId()));
 
       Map<String, String> attrs = new HashMap<String, String>();
@@ -462,7 +468,7 @@ public class HostImpl implements Host {
       if (hostInfo.getOSRelease() != null) {
         attrs.put(OS_RELEASE_VERSION, hostInfo.getOSRelease());
       }
-      
+
       setHostAttributes(attrs);
 
       saveIfPersisted();
@@ -482,7 +488,7 @@ public class HostImpl implements Host {
     }
 
   }
-  
+
   @Override
   public AgentEnv getLastAgentEnv() {
     readLock.lock();
@@ -533,7 +539,7 @@ public class HostImpl implements Host {
         stateMachine.doTransition(event.getType(), event);
       } catch (InvalidStateTransitionException e) {
         LOG.error("Can't handle Host event at current state"
-            + ", host=" + this.getHostName()
+            + ", host=" + getHostName()
             + ", currentState=" + oldState
             + ", eventType=" + event.getType()
             + ", event=" + event);
@@ -546,7 +552,7 @@ public class HostImpl implements Host {
     if (oldState != getState()) {
       if (LOG.isDebugEnabled()) {
         LOG.debug("Host transitioned to a new state"
-            + ", host=" + this.getHostName()
+            + ", host=" + getHostName()
             + ", oldState=" + oldState
             + ", currentState=" + getState()
             + ", eventType=" + event.getType().name()
@@ -574,7 +580,7 @@ public class HostImpl implements Host {
       writeLock.unlock();
     }
   }
-  
+
   @Override
   public Integer getCurrentPingPort() {
     try {
@@ -608,7 +614,7 @@ public class HostImpl implements Host {
       writeLock.unlock();
     }
   }
-  
+
   @Override
   public String getPublicHostName() {
     try {
@@ -703,8 +709,8 @@ public class HostImpl implements Host {
       writeLock.unlock();
     }
   }
-  
-  
+
+
   @Override
   public long getTotalMemBytes() {
     try {
@@ -811,18 +817,18 @@ public class HostImpl implements Host {
       writeLock.unlock();
     }
   }
-  
+
   @Override
   public String getOsFamily() {
-	  String majorVersion = this.getHostAttributes().get(OS_RELEASE_VERSION).split("\\.")[0];
-	  return this.getHostAttributes().get(OSFAMILY) + majorVersion;
+	  String majorVersion = getHostAttributes().get(OS_RELEASE_VERSION).split("\\.")[0];
+	  return getHostAttributes().get(OSFAMILY) + majorVersion;
   }
 
   @Override
   public List<DiskInfo> getDisksInfo() {
     try {
       readLock.lock();
-      return this.disksInfo;
+      return disksInfo;
     } finally {
       readLock.unlock();
     }
@@ -854,10 +860,11 @@ public class HostImpl implements Host {
     try {
       writeLock.lock();
       hostStateEntity.setHealthStatus(gson.toJson(healthStatus));
-      
-      if (healthStatus.getHealthStatus().equals(HealthStatus.UNKNOWN))
+
+      if (healthStatus.getHealthStatus().equals(HealthStatus.UNKNOWN)) {
         setStatus(HealthStatus.UNKNOWN.name());
-      
+      }
+
       saveIfPersisted();
     } finally {
       writeLock.unlock();
@@ -943,7 +950,7 @@ public class HostImpl implements Host {
   public void setLastRegistrationTime(long lastRegistrationTime) {
     try {
       writeLock.lock();
-      this.hostEntity.setLastRegistrationTime(lastRegistrationTime);
+      hostEntity.setLastRegistrationTime(lastRegistrationTime);
       saveIfPersisted();
     } finally {
       writeLock.unlock();
@@ -1012,8 +1019,8 @@ public class HostImpl implements Host {
       writeLock.unlock();
     }
   }
-  
-  
+
+
   @Override
   public String getStatus() {
     return status;
@@ -1142,13 +1149,14 @@ public class HostImpl implements Host {
       hostStateDAO.merge(hostStateEntity);
     }
   }
-  
+
   @Override
   @Transactional
   public boolean addDesiredConfig(long clusterId, boolean selected, String user, Config config) {
-    if (null == user)
+    if (null == user) {
       throw new NullPointerException("User must be specified.");
-    
+    }
+
     HostConfigMapping exist = getDesiredConfigEntity(clusterId, config.getType());
     if (null != exist && exist.getVersion().equals(config.getTag())) {
       if (!selected) {
@@ -1157,9 +1165,9 @@ public class HostImpl implements Host {
       }
       return false;
     }
-    
+
     writeLock.lock();
-    
+
     try {
       // set all old mappings for this type to empty
       for (HostConfigMapping e : hostConfigMappingDAO.findByType(clusterId,
@@ -1167,7 +1175,7 @@ public class HostImpl implements Host {
         e.setSelected(0);
         hostConfigMappingDAO.merge(e);
       }
-      
+
       HostConfigMapping hostConfigMapping = new HostConfigMappingImpl();
       hostConfigMapping.setClusterId(Long.valueOf(clusterId));
       hostConfigMapping.setCreateTimestamp(Long.valueOf(System.currentTimeMillis()));
@@ -1176,31 +1184,31 @@ public class HostImpl implements Host {
       hostConfigMapping.setUser(user);
       hostConfigMapping.setType(config.getType());
       hostConfigMapping.setVersion(config.getTag());
-      
+
       hostConfigMappingDAO.create(hostConfigMapping);
     }
     finally {
       writeLock.unlock();
     }
-    
+
     hostDAO.merge(hostEntity);
-    
+
     return true;
   }
-  
+
   @Override
   public Map<String, DesiredConfig> getDesiredConfigs(long clusterId) {
     Map<String, DesiredConfig> map = new HashMap<String, DesiredConfig>();
 
     for (HostConfigMapping e : hostConfigMappingDAO.findSelected(
         clusterId, hostEntity.getHostName())) {
-      
+
       DesiredConfig dc = new DesiredConfig();
       dc.setTag(e.getVersion());
       dc.setServiceName(e.getServiceName());
       dc.setUser(e.getUser());
       map.put(e.getType(), dc);
-      
+
     }
     return map;
   }
@@ -1221,7 +1229,7 @@ public class HostImpl implements Host {
       hostConfigMap.put(desiredConfigEntry.getKey(), hostConfig);
     }
 
-    Map<Long, ConfigGroup> configGroups = cluster.getConfigGroupsByHostname(this.getHostName());
+    Map<Long, ConfigGroup> configGroups = cluster.getConfigGroupsByHostname(getHostName());
 
     if (configGroups != null && !configGroups.isEmpty()) {
       for (ConfigGroup configGroup : configGroups.values()) {
@@ -1249,11 +1257,11 @@ public class HostImpl implements Host {
   private HostConfigMapping getDesiredConfigEntity(long clusterId, String type) {
     HostConfigMapping findSelectedByType = hostConfigMappingDAO.findSelectedByType(clusterId,
         hostEntity.getHostName(), type);
-    
-    
+
+
     return findSelectedByType;
   }
-  
+
   private void ensureMaintMap() {
     if (null == maintMap) {
       String entity = hostStateEntity.getMaintenanceState();
@@ -1268,42 +1276,47 @@ public class HostImpl implements Host {
       }
     }
   }
-  
+
   @Override
   public void setMaintenanceState(long clusterId, MaintenanceState state) {
     try {
       writeLock.lock();
-      
+
       ensureMaintMap();
-      
+
       maintMap.put(Long.valueOf(clusterId), state);
       String json = gson.toJson(maintMap, maintMapType);
-      
+
       hostStateEntity.setMaintenanceState(json);
       saveIfPersisted();
+
+      // broadcast the maintenance mode change
+      MaintenanceModeEvent event = new MaintenanceModeEvent(state, this);
+      eventPublisher.publish(event);
     } finally {
       writeLock.unlock();
     }
   }
-  
+
   @Override
   public MaintenanceState getMaintenanceState(long clusterId) {
     try {
       readLock.lock();
 
       ensureMaintMap();
-      
+
       Long id = Long.valueOf(clusterId);
-      
-      if (!maintMap.containsKey(id))
+
+      if (!maintMap.containsKey(id)) {
         maintMap.put(id, MaintenanceState.OFF);
-        
+      }
+
       return maintMap.get(id);
     } finally {
       readLock.unlock();
     }
   }
-  
+
 }
 
-  
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/3e54f956/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
index 75265b7..bc97936 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
@@ -31,6 +31,8 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.agent.AlertDefinitionCommand;
 import org.apache.ambari.server.controller.ServiceComponentHostResponse;
+import org.apache.ambari.server.events.MaintenanceModeEvent;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 import org.apache.ambari.server.orm.dao.HostComponentDesiredStateDAO;
 import org.apache.ambari.server.orm.dao.HostComponentStateDAO;
 import org.apache.ambari.server.orm.dao.HostDAO;
@@ -110,6 +112,12 @@ public class ServiceComponentHostImpl implements ServiceComponentHost {
   @Inject
   private AlertDefinitionHash alertDefinitionHash;
 
+  /**
+   * Used to publish events relating to service CRUD operations.
+   */
+  @Inject
+  private AmbariEventPublisher eventPublisher;
+
   private HostComponentStateEntity stateEntity;
   private HostComponentDesiredStateEntity desiredStateEntity;
 
@@ -1431,6 +1439,11 @@ public class ServiceComponentHostImpl implements ServiceComponentHost {
       try {
         desiredStateEntity.setMaintenanceState(state);
         saveIfPersisted();
+
+        // broadcast the maintenance mode change
+        MaintenanceModeEvent event = new MaintenanceModeEvent(state, this);
+        eventPublisher.publish(event);
+
       } finally {
         writeLock.unlock();
       }

http://git-wip-us.apache.org/repos/asf/ambari/blob/3e54f956/ambari-server/src/test/java/org/apache/ambari/server/events/EventsTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/events/EventsTest.java b/ambari-server/src/test/java/org/apache/ambari/server/events/EventsTest.java
new file mode 100644
index 0000000..ec85cbd
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/events/EventsTest.java
@@ -0,0 +1,188 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.events;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.Assert;
+
+import org.apache.ambari.server.events.MaintenanceModeEvent;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
+import org.apache.ambari.server.orm.GuiceJpaInitializer;
+import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.Host;
+import org.apache.ambari.server.state.HostState;
+import org.apache.ambari.server.state.MaintenanceState;
+import org.apache.ambari.server.state.Service;
+import org.apache.ambari.server.state.ServiceComponent;
+import org.apache.ambari.server.state.ServiceComponentFactory;
+import org.apache.ambari.server.state.ServiceComponentHost;
+import org.apache.ambari.server.state.ServiceComponentHostFactory;
+import org.apache.ambari.server.state.ServiceFactory;
+import org.apache.ambari.server.state.StackId;
+import org.apache.ambari.server.state.State;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.eventbus.EventBus;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.persist.PersistService;
+
+/**
+ * Tests that {@link EventsTest} instances are fired correctly and
+ * that alert data is bootstrapped into the database.
+ */
+public class EventsTest {
+
+  private static final String HOSTNAME = "c6401.ambari.apache.org";
+
+  private Clusters m_clusters;
+  private Cluster m_cluster;
+  private String m_clusterName;
+  private Injector m_injector;
+  private ServiceFactory m_serviceFactory;
+  private ServiceComponentFactory m_componentFactory;
+  private ServiceComponentHostFactory m_schFactory;
+  private AmbariEventPublisher m_eventPublisher;
+  private MockEventListener m_listener;
+
+  /**
+   *
+   */
+  @Before
+  public void setup() throws Exception {
+    m_injector = Guice.createInjector(new InMemoryDefaultTestModule());
+    m_injector.getInstance(GuiceJpaInitializer.class);
+
+    m_eventPublisher = m_injector.getInstance(AmbariEventPublisher.class);
+    EventBus synchronizedBus = new EventBus();
+
+    // register mock listener
+    m_listener = m_injector.getInstance(MockEventListener.class);
+    synchronizedBus.register(m_listener);
+
+    // !!! need a synchronous op for testing
+    Field field = AmbariEventPublisher.class.getDeclaredField("m_eventBus");
+    field.setAccessible(true);
+    field.set(m_eventPublisher, synchronizedBus);
+
+    m_clusters = m_injector.getInstance(Clusters.class);
+    m_serviceFactory = m_injector.getInstance(ServiceFactory.class);
+    m_componentFactory = m_injector.getInstance(ServiceComponentFactory.class);
+    m_schFactory = m_injector.getInstance(ServiceComponentHostFactory.class);
+
+    m_clusterName = "foo";
+    m_clusters.addCluster(m_clusterName);
+    m_clusters.addHost(HOSTNAME);
+
+    Host host = m_clusters.getHost(HOSTNAME);
+    Map<String, String> hostAttributes = new HashMap<String, String>();
+    hostAttributes.put("os_family", "redhat");
+    hostAttributes.put("os_release_version", "6.4");
+    host.setHostAttributes(hostAttributes);
+    host.setState(HostState.HEALTHY);
+    host.persist();
+
+    m_cluster = m_clusters.getCluster(m_clusterName);
+    m_cluster.setDesiredStackVersion(new StackId("HDP", "2.0.6"));
+    Assert.assertNotNull(m_cluster);
+
+    m_clusters.mapHostToCluster(HOSTNAME, m_clusterName);
+  }
+
+  /**
+   * @throws Exception
+   */
+  @After
+  public void teardown() throws Exception {
+    m_injector.getInstance(PersistService.class).stop();
+    m_injector = null;
+  }
+
+  /**
+   * Tests that {@link MaintenanceModeEvent}s are fired correctly.
+   *
+   * @throws Exception
+   */
+  @Test
+  public void testMaintenanceModeEvents() throws Exception {
+    installHdfsService();
+    Service service = m_cluster.getService("HDFS");
+    Class<?> eventClass = MaintenanceModeEvent.class;
+
+    Assert.assertFalse(m_listener.isEventReceived(eventClass));
+    service.setMaintenanceState(MaintenanceState.ON);
+    Assert.assertTrue(m_listener.isEventReceived(eventClass));
+    Assert.assertEquals(1, m_listener.getEventReceivedCount(eventClass));
+
+    m_listener.reset();
+    Assert.assertFalse(m_listener.isEventReceived(eventClass));
+
+    List<ServiceComponentHost> componentHosts = m_cluster.getServiceComponentHosts(HOSTNAME);
+    ServiceComponentHost componentHost = componentHosts.get(0);
+    componentHost.setMaintenanceState(MaintenanceState.OFF);
+
+    Assert.assertTrue(m_listener.isEventReceived(eventClass));
+    Assert.assertEquals(1, m_listener.getEventReceivedCount(eventClass));
+
+    m_listener.reset();
+    Assert.assertFalse(m_listener.isEventReceived(eventClass));
+
+    Host host = m_clusters.getHost(HOSTNAME);
+    host.setMaintenanceState(m_cluster.getClusterId(), MaintenanceState.ON);
+    host.setMaintenanceState(m_cluster.getClusterId(), MaintenanceState.OFF);
+
+    Assert.assertTrue(m_listener.isEventReceived(eventClass));
+    Assert.assertEquals(2, m_listener.getEventReceivedCount(eventClass));
+  }
+
+  /**
+   * Calls {@link Service#persist()} to mock a service install along with
+   * creating a single {@link Host} and {@link ServiceComponentHost}.
+   */
+  private void installHdfsService() throws Exception {
+    String serviceName = "HDFS";
+    Service service = m_serviceFactory.createNew(m_cluster, serviceName);
+    m_cluster.addService(service);
+    service.persist();
+    service = m_cluster.getService(serviceName);
+    Assert.assertNotNull(service);
+
+    ServiceComponent component = m_componentFactory.createNew(service, "DATANODE");
+    service.addServiceComponent(component);
+    component.setDesiredState(State.INSTALLED);
+    component.persist();
+
+    ServiceComponentHost sch = m_schFactory.createNew(component, HOSTNAME);
+
+    component.addServiceComponentHost(sch);
+    sch.setDesiredState(State.INSTALLED);
+    sch.setState(State.INSTALLED);
+    sch.setDesiredStackVersion(new StackId("HDP-2.0.6"));
+    sch.setStackVersion(new StackId("HDP-2.0.6"));
+
+    sch.persist();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/3e54f956/ambari-server/src/test/java/org/apache/ambari/server/events/MockEventListener.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/events/MockEventListener.java b/ambari-server/src/test/java/org/apache/ambari/server/events/MockEventListener.java
new file mode 100644
index 0000000..bf0d535
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/events/MockEventListener.java
@@ -0,0 +1,99 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.events;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.google.common.eventbus.EventBus;
+import com.google.common.eventbus.Subscribe;
+import com.google.inject.Singleton;
+
+/**
+ * The {@link MockEventListener} is used to provide a way to capture events
+ * being fired via an {@link EventBus}.
+ */
+@Singleton
+public class MockEventListener {
+
+  /**
+   * When an event is received, its class is captured and the event object is
+   * added to the list.
+   */
+  private final Map<Class<?>, List<Object>> m_receivedEvents = new HashMap<Class<?>, List<Object>>();
+
+  /**
+   * Resets the captured events.
+   */
+  public void reset() {
+    m_receivedEvents.clear();
+  }
+
+  /**
+   * Gets whether an event of the specified class was received.
+   *
+   * @param clazz
+   * @return
+   */
+  public boolean isEventReceived(Class<?> clazz) {
+    if (!m_receivedEvents.containsKey(clazz)) {
+      return false;
+    }
+
+    return m_receivedEvents.get(clazz).size() > 0;
+  }
+
+  /**
+   * Gets the total number of events received for the specified class.
+   *
+   * @param clazz
+   * @return
+   */
+  public int getEventReceivedCount(Class<?> clazz){
+    if (!m_receivedEvents.containsKey(clazz)) {
+      return 0;
+    }
+
+    return m_receivedEvents.get(clazz).size();
+  }
+
+  /**
+   * @param event
+   */
+  @Subscribe
+  public void onEvent(MaintenanceModeEvent event) {
+    handleEvent(event);
+  }
+
+  /**
+   * Inserts the event into the map of class to event invocations.
+   *
+   * @param event
+   */
+  private void handleEvent(Object event) {
+    List<Object> events = m_receivedEvents.get(event.getClass());
+    if (null == events) {
+      events = new ArrayList<Object>();
+      m_receivedEvents.put(event.getClass(), events);
+    }
+
+    events.add(event);
+  }
+}


[17/50] [abbrv] git commit: AMBARI-7191. Alerts: rename old alerts endpoint for new alerts and provide summary info (ncole)

Posted by jo...@apache.org.
AMBARI-7191. Alerts: rename old alerts endpoint for new alerts and provide summary info (ncole)


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

Branch: refs/heads/trunk
Commit: 1f1059cff1ac749e5bdc8fd98febccb7ca346652
Parents: 0b406cb
Author: Nate Cole <nc...@hortonworks.com>
Authored: Sun Sep 7 16:42:35 2014 -0400
Committer: Nate Cole <nc...@hortonworks.com>
Committed: Mon Sep 8 10:04:00 2014 -0400

----------------------------------------------------------------------
 .../api/resources/AlertResourceDefinition.java  |   4 +-
 .../server/api/services/AlertService.java       |   4 +-
 .../server/api/services/ClusterService.java     |   2 +-
 .../ambari/server/api/services/HostService.java |   2 +-
 .../server/api/services/ServiceService.java     |   2 +-
 .../ambari/server/controller/AmbariServer.java  |   2 +
 .../internal/AbstractProviderModule.java        |  41 ++++--
 .../internal/AlertSummaryPropertyProvider.java  | 134 +++++++++++++++++++
 .../nagios/NagiosPropertyProvider.java          |  27 ++--
 .../ambari/server/orm/dao/AlertSummaryDTO.java  |  70 ++++++++++
 .../apache/ambari/server/orm/dao/AlertsDAO.java |  50 +++++++
 .../nagios/NagiosPropertyProviderTest.java      |  80 +++++------
 .../ambari/server/orm/dao/AlertsDAOTest.java    |  75 ++++++++++-
 .../app/controllers/global/update_controller.js |   4 +-
 .../app/controllers/main/alerts_controller.js   |   4 +-
 ambari-web/app/controllers/main/host.js         |   4 +-
 ambari-web/app/mappers/hosts_mapper.js          |   2 +-
 ambari-web/app/mappers/service_mapper.js        |   8 +-
 ambari-web/app/utils/ajax/ajax.js               |   6 +-
 .../controllers/main/alerts_controller_test.js  |  28 ++--
 20 files changed, 450 insertions(+), 99 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/1f1059cf/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertResourceDefinition.java
index afdbcfc..d7aca22 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertResourceDefinition.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertResourceDefinition.java
@@ -30,12 +30,12 @@ public class AlertResourceDefinition extends BaseResourceDefinition {
   
   @Override
   public String getPluralName() {
-    return "alerts_data";
+    return "alerts";
   }
   
   @Override
   public String getSingularName() {
-    return "alert_data";
+    return "alert";
   }
   
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/1f1059cf/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertService.java
index 8e163c2..a916c4c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertService.java
@@ -52,7 +52,7 @@ public class AlertService extends BaseService {
    */
   @GET
   @Produces("text/plain")
-  public Response getDefinitions(String body,
+  public Response getAlerts(String body,
       @Context HttpHeaders headers,
       @Context UriInfo ui) {
     return handleRequest(headers, body, ui, Request.Type.GET,
@@ -66,7 +66,7 @@ public class AlertService extends BaseService {
   @GET
   @Path("{alertId}")
   @Produces("text/plain")
-  public Response getDefinition(String body,
+  public Response getAlert(String body,
       @Context HttpHeaders headers,
       @Context UriInfo ui,
       @PathParam("alertId") Long id) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/1f1059cf/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
index c76acf7..a56bcbf 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
@@ -366,7 +366,7 @@ public class ClusterService extends BaseService {
    *
    * @return  the alert definition service
    */
-  @Path("{clusterName}/alerts_data")
+  @Path("{clusterName}/alerts")
   public AlertService getAlertService(
       @Context javax.ws.rs.core.Request request, @PathParam("clusterName") String clusterName) {
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/1f1059cf/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostService.java
index 8cec7e1..7962ee3 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostService.java
@@ -212,7 +212,7 @@ public class HostService extends BaseService {
    * @param hostName host id
    * @return the alerts service
    */
-  @Path("{hostName}/alerts_data")
+  @Path("{hostName}/alerts")
   public AlertService getAlertHandler(@PathParam("hostName") String hostName) {
     return new AlertService(m_clusterName, null, hostName);
   }  

http://git-wip-us.apache.org/repos/asf/ambari/blob/1f1059cf/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceService.java
index 30f4f2f..7371fad 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceService.java
@@ -187,7 +187,7 @@ public class ServiceService extends BaseService {
   /**
    * Gets the alerts sub-resource.
    */
-  @Path("{serviceName}/alerts_data")
+  @Path("{serviceName}/alerts")
   public AlertService getAlertHandler(
       @PathParam("serviceName") String serviceName) {
     return new AlertService(m_clusterName, serviceName, null);

http://git-wip-us.apache.org/repos/asf/ambari/blob/1f1059cf/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
index 73e4013..4cae67e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
@@ -48,6 +48,7 @@ import org.apache.ambari.server.controller.internal.AbstractControllerResourcePr
 import org.apache.ambari.server.controller.internal.AlertDefinitionResourceProvider;
 import org.apache.ambari.server.controller.internal.AlertGroupResourceProvider;
 import org.apache.ambari.server.controller.internal.AlertResourceProvider;
+import org.apache.ambari.server.controller.internal.AlertSummaryPropertyProvider;
 import org.apache.ambari.server.controller.internal.AlertTargetResourceProvider;
 import org.apache.ambari.server.controller.internal.AmbariPrivilegeResourceProvider;
 import org.apache.ambari.server.controller.internal.BlueprintResourceProvider;
@@ -535,6 +536,7 @@ public class AmbariServer {
     AlertResourceProvider.init(injector);
     AlertDefinitionResourceProvider.init(injector);
     AlertGroupResourceProvider.init(injector);
+    AlertSummaryPropertyProvider.init(injector);
     AlertTargetResourceProvider.init(injector);
     PermissionResourceProvider.init(injector.getInstance(PermissionDAO.class));
     ViewPermissionResourceProvider.init(injector.getInstance(PermissionDAO.class));

http://git-wip-us.apache.org/repos/asf/ambari/blob/1f1059cf/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java
index fc60210..f50955c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java
@@ -18,9 +18,21 @@
 
 package org.apache.ambari.server.controller.internal;
 
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.Role;
 import org.apache.ambari.server.configuration.ComponentSSLConfiguration;
+import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.AmbariServer;
 import org.apache.ambari.server.controller.HostRequest;
 import org.apache.ambari.server.controller.HostResponse;
@@ -29,30 +41,33 @@ import org.apache.ambari.server.controller.ServiceComponentHostResponse;
 import org.apache.ambari.server.controller.ganglia.GangliaComponentPropertyProvider;
 import org.apache.ambari.server.controller.ganglia.GangliaHostComponentPropertyProvider;
 import org.apache.ambari.server.controller.ganglia.GangliaHostPropertyProvider;
-import org.apache.ambari.server.controller.ganglia.GangliaReportPropertyProvider;
 import org.apache.ambari.server.controller.ganglia.GangliaHostProvider;
+import org.apache.ambari.server.controller.ganglia.GangliaReportPropertyProvider;
 import org.apache.ambari.server.controller.jmx.JMXHostProvider;
 import org.apache.ambari.server.controller.jmx.JMXPropertyProvider;
 import org.apache.ambari.server.controller.nagios.NagiosPropertyProvider;
-import org.apache.ambari.server.controller.spi.*;
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
+import org.apache.ambari.server.controller.spi.NoSuchResourceException;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.PropertyProvider;
+import org.apache.ambari.server.controller.spi.ProviderModule;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.ResourceProvider;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
 import org.apache.ambari.server.controller.utilities.PredicateBuilder;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
-import org.apache.ambari.server.controller.AmbariManagementController;
-
-import com.google.inject.Inject;
-
 import org.apache.ambari.server.controller.utilities.StreamProvider;
+import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.DesiredConfig;
 import org.apache.ambari.server.state.HostState;
 import org.apache.ambari.server.state.Service;
 import org.apache.ambari.server.state.State;
-import org.apache.ambari.server.state.Cluster;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.*;
-import java.util.Map.Entry;
-import java.util.concurrent.ConcurrentHashMap;
+import com.google.inject.Inject;
 
 /**
  * An abstract provider module implementation.
@@ -422,6 +437,8 @@ public abstract class AbstractProviderModule implements ProviderModule, Resource
                 configuration),
               "Clusters/cluster_name",
               "Clusters/version"));
+          providers.add(new AlertSummaryPropertyProvider(type,
+              "Clusters/cluster_name", null));
           break;
         case Service:
           providers.add(new NagiosPropertyProvider(type,
@@ -430,6 +447,8 @@ public abstract class AbstractProviderModule implements ProviderModule, Resource
                 configuration),
               "ServiceInfo/cluster_name",
               "ServiceInfo/service_name"));
+          providers.add(new AlertSummaryPropertyProvider(type,
+              "ServiceInfo/cluster_name", "ServiceInfo/service_name"));
           break;
         case Host:
           providers.add(createGangliaHostPropertyProvider(
@@ -446,6 +465,8 @@ public abstract class AbstractProviderModule implements ProviderModule, Resource
                 configuration),
               "Hosts/cluster_name",
               "Hosts/host_name"));
+          providers.add(new AlertSummaryPropertyProvider(type,
+              "Hosts/cluster_name", "Hosts/host_name"));
           break;
         case Component: {
           // TODO as we fill out stack metric definitions, these can be phased out

http://git-wip-us.apache.org/repos/asf/ambari/blob/1f1059cf/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
new file mode 100644
index 0000000..438d471
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertSummaryPropertyProvider.java
@@ -0,0 +1,134 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.controller.internal;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.PropertyProvider;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.orm.dao.AlertSummaryDTO;
+import org.apache.ambari.server.orm.dao.AlertsDAO;
+import org.apache.ambari.server.state.AlertState;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.Injector;
+
+/**
+ * Property provider that adds alert summary information to endpoints.
+ */
+public class AlertSummaryPropertyProvider extends BaseProvider implements PropertyProvider {
+
+  private final static Logger LOG = LoggerFactory.getLogger(AlertSummaryPropertyProvider.class);
+  
+  private static Clusters s_clusters = null;
+  private static AlertsDAO s_dao = null;
+  
+  private Resource.Type m_resourceType = null;
+  private String m_clusterPropertyId = null;
+  private String m_typeIdPropertyId = null;
+  
+  AlertSummaryPropertyProvider(Resource.Type type,
+      String clusterPropertyId, String typeIdPropertyId) {
+    super(Collections.singleton("alerts_summary"));
+    m_resourceType = type;
+    m_clusterPropertyId = clusterPropertyId;
+    m_typeIdPropertyId = typeIdPropertyId;
+  }
+  
+  public static void init(Injector injector) {
+    s_clusters = injector.getInstance(Clusters.class);
+    s_dao = injector.getInstance(AlertsDAO.class);
+  }
+
+  @Override
+  public Set<Resource> populateResources(Set<Resource> resources,
+      Request request, Predicate predicate) throws SystemException {
+
+    Set<String> propertyIds = getRequestPropertyIds(request, predicate);
+
+    try {
+      for (Resource res : resources) {
+        populateResource(res, propertyIds);
+      }
+    } catch (AmbariException e) {
+      LOG.error("Could not load built-in alerts - Executor exception ({})",
+          e.getMessage());
+    }
+    
+    return resources;
+  }
+  
+  private void populateResource(Resource resource, Set<String> requestedIds) throws AmbariException {
+
+    AlertSummaryDTO summary = null;
+
+    String clusterName = (String) resource.getPropertyValue(m_clusterPropertyId);
+    String typeId = null == m_typeIdPropertyId ? null : (String) resource.getPropertyValue(m_typeIdPropertyId);
+    Cluster cluster = s_clusters.getCluster(clusterName);
+    
+    switch (m_resourceType.getInternalType()) {
+      case Cluster:
+        summary = s_dao.findCurrentCounts(cluster.getClusterId(), null, null);
+        break;
+      case Service:
+        summary = s_dao.findCurrentCounts(cluster.getClusterId(), typeId, null);
+        break;
+      case Host:
+        summary = s_dao.findCurrentCounts(cluster.getClusterId(), null, typeId);
+        break;
+      default:
+        break;
+    }
+    
+    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()));
+      
+      setResourceProperty(resource, "alerts_summary", map, requestedIds);
+    }
+      
+  }
+
+  @Override
+  public Set<String> checkPropertyIds(Set<String> propertyIds) {
+    Set<String> rejects = new HashSet<String>();
+    
+    for (String id : propertyIds) {
+      if (!id.startsWith("alerts_summary"))
+        rejects.add(id);
+    }
+    
+    return rejects;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/1f1059cf/ambari-server/src/main/java/org/apache/ambari/server/controller/nagios/NagiosPropertyProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/nagios/NagiosPropertyProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/nagios/NagiosPropertyProvider.java
index d2e425f..5b93db8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/nagios/NagiosPropertyProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/nagios/NagiosPropertyProvider.java
@@ -17,14 +17,10 @@
  */
 package org.apache.ambari.server.controller.nagios;
 
-import com.google.gson.Gson;
-import com.google.inject.Inject;
-import com.google.inject.Injector;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashSet;
@@ -42,8 +38,8 @@ import java.util.concurrent.Future;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
-import java.util.logging.Level;
 import java.util.regex.Pattern;
+
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.configuration.ComponentSSLConfiguration;
 import org.apache.ambari.server.configuration.Configuration;
@@ -54,7 +50,6 @@ import org.apache.ambari.server.controller.spi.Request;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.controller.utilities.StreamProvider;
-import org.apache.ambari.server.state.Alert;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.Service;
@@ -63,20 +58,26 @@ import org.apache.commons.io.IOUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.gson.Gson;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+
 /**
  * Used to populate resources that have Nagios alertable properties.
  */
+@Deprecated
 public class NagiosPropertyProvider extends BaseProvider implements PropertyProvider {
   
   private static final Logger LOG = LoggerFactory.getLogger(NagiosPropertyProvider.class);
   private static final Set<String> NAGIOS_PROPERTY_IDS = new HashSet<String>();
   private static final String NAGIOS_TEMPLATE = "http://%s/ambarinagios/nagios/nagios_alerts.php?q1=alerts&alert_type=all";
   
-  private static final String ALERT_DETAIL_PROPERTY_ID = "alerts/detail";
-  private static final String ALERT_SUMMARY_OK_PROPERTY_ID = "alerts/summary/OK";
-  private static final String ALERT_SUMMARY_WARNING_PROPERTY_ID = "alerts/summary/WARNING";
-  private static final String ALERT_SUMMARY_CRITICAL_PROPERTY_ID = "alerts/summary/CRITICAL";
-  private static final String ALERT_SUMMARY_PASSIVE_PROPERTY_ID = "alerts/summary/PASSIVE";
+  private static final String ALERT_DETAIL_PROPERTY_ID = "legacy_alerts/detail";
+  private static final String ALERT_SUMMARY_PROPERTY_ID = "legacy_alerts/summary";
+  private static final String ALERT_SUMMARY_OK_PROPERTY_ID = "legacy_alerts/summary/OK";
+  private static final String ALERT_SUMMARY_WARNING_PROPERTY_ID = "legacy_alerts/summary/WARNING";
+  private static final String ALERT_SUMMARY_CRITICAL_PROPERTY_ID = "legacy_alerts/summary/CRITICAL";
+  private static final String ALERT_SUMMARY_PASSIVE_PROPERTY_ID = "legacy_alerts/summary/PASSIVE";
   private static final String PASSIVE_TOKEN = "AMBARIPASSIVE=";
   
   private static final List<String> DEFAULT_IGNORABLE_FOR_SERVICES = Collections.unmodifiableList(new ArrayList<String>(
@@ -99,8 +100,8 @@ public class NagiosPropertyProvider extends BaseProvider implements PropertyProv
   private static final Set<String> CLUSTER_NAMES = new CopyOnWriteArraySet<String>();
   
   static {
-    NAGIOS_PROPERTY_IDS.add("alerts/summary");
-    NAGIOS_PROPERTY_IDS.add("alerts/detail");
+    NAGIOS_PROPERTY_IDS.add(ALERT_SUMMARY_PROPERTY_ID);
+    NAGIOS_PROPERTY_IDS.add(ALERT_DETAIL_PROPERTY_ID);
     IGNORABLE_FOR_SERVICES = new ArrayList<String>(DEFAULT_IGNORABLE_FOR_SERVICES);
 
     scheduler = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {

http://git-wip-us.apache.org/repos/asf/ambari/blob/1f1059cf/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
new file mode 100644
index 0000000..80fa4e8
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertSummaryDTO.java
@@ -0,0 +1,70 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.orm.dao;
+
+import org.apache.ambari.server.state.AlertState;
+
+/**
+ * Used to return alert summary data out of the database.
+ */
+public class AlertSummaryDTO {
+
+  private int okCount;
+  private int warningCount;
+  private int criticalCount;
+  private int unknownCount;
+  
+  /**
+   * 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) {
+    okCount = null == ok ? 0 : ok.intValue();
+    warningCount = null == warning ? 0 : warning.intValue();
+    criticalCount = null == critical ? 0 : critical.intValue();
+    unknownCount = null == unknown ? 0 : unknown.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;
+  }  
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/1f1059cf/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 5fcc1ec..a274089 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
@@ -222,6 +222,55 @@ public class AlertsDAO {
     return daoUtils.selectList(query);
   }
   
+  /**
+   * Retrieves the summary information for a particular scope.  The result is a DTO
+   * since the columns are aggregated and don't fit to an entity.
+   * 
+   * @param clusterId the cluster id
+   * @param serviceName the service name. Use {@code null} to not filter on service.
+   * @param hostName the host name.  Use {@code null} to not filter on host.
+   * @return the summary DTO
+   */
+  @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");
+    
+    if (null != serviceName) {
+      sb.append(" AND history.serviceName = :serviceName");
+    }
+    
+    if (null != hostName) {
+      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);
+    
+    query.setParameter("clusterId", Long.valueOf(clusterId));
+    
+    if (null != serviceName) {
+      query.setParameter("serviceName", serviceName);
+    }
+    
+    if (null != hostName) {
+      query.setParameter("hostName", hostName);
+    }
+    
+    return daoUtils.selectSingle(query);
+  }
   
   /**
    * Gets the current alerts for a given service.
@@ -408,4 +457,5 @@ public class AlertsDAO {
   public void remove(AlertCurrentEntity alert) {
     entityManagerProvider.get().remove(merge(alert));
   }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/1f1059cf/ambari-server/src/test/java/org/apache/ambari/server/controller/nagios/NagiosPropertyProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/nagios/NagiosPropertyProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/nagios/NagiosPropertyProviderTest.java
index 4316dc9..8037451 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/nagios/NagiosPropertyProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/nagios/NagiosPropertyProviderTest.java
@@ -124,7 +124,7 @@ public class NagiosPropertyProviderTest {
     
     Map<String, Map<String, Object>> values = res.getPropertiesMap();
     
-    Assert.assertFalse("Expected no alerts", values.containsKey("alerts"));
+    Assert.assertFalse("Expected no alerts", values.containsKey("legacy_alerts"));
   }
 
 
@@ -176,9 +176,9 @@ public class NagiosPropertyProviderTest {
 
     Map<String, Map<String, Object>> values = res.getPropertiesMap();
 
-    Assert.assertTrue(values.containsKey("alerts/summary"));
+    Assert.assertTrue(values.containsKey("legacy_alerts/summary"));
 
-    Map<String, Object> summary = values.get("alerts/summary");
+    Map<String, Object> summary = values.get("legacy_alerts/summary");
     Assert.assertEquals(4L, summary.size());
     Assert.assertTrue(summary.containsKey("OK"));
     Assert.assertTrue(summary.containsKey("WARNING"));
@@ -230,7 +230,7 @@ public class NagiosPropertyProviderTest {
     
     Map<String, Map<String, Object>> values = res.getPropertiesMap();
     
-    Assert.assertFalse("Expected no alerts", values.containsKey("alerts"));
+    Assert.assertFalse("Expected no alerts", values.containsKey("legacy_alerts"));
   }
   
   @Test
@@ -260,12 +260,12 @@ public class NagiosPropertyProviderTest {
     
     Map<String, Map<String, Object>> values = res.getPropertiesMap();
     
-    Assert.assertTrue(values.containsKey("alerts"));
-    Assert.assertTrue(values.containsKey("alerts/summary"));
-    Assert.assertTrue(values.get("alerts").containsKey("detail"));
-    Assert.assertTrue(List.class.isInstance(values.get("alerts").get("detail")));
+    Assert.assertTrue(values.containsKey("legacy_alerts"));
+    Assert.assertTrue(values.containsKey("legacy_alerts/summary"));
+    Assert.assertTrue(values.get("legacy_alerts").containsKey("detail"));
+    Assert.assertTrue(List.class.isInstance(values.get("legacy_alerts").get("detail")));
     
-    List<?> list = (List<?>) values.get("alerts").get("detail");
+    List<?> list = (List<?>) values.get("legacy_alerts").get("detail");
     Assert.assertEquals(Integer.valueOf(3), Integer.valueOf(list.size()));
     for (Object o : list) {
       Assert.assertTrue(Map.class.isInstance(o));
@@ -275,7 +275,7 @@ public class NagiosPropertyProviderTest {
       Assert.assertTrue("expected HBASE", serviceName.equals("HBASE"));
     }
     
-    Map<String, Object> summary = values.get("alerts/summary");
+    Map<String, Object> summary = values.get("legacy_alerts/summary");
     Assert.assertTrue(summary.containsKey("OK"));
     Assert.assertTrue(summary.containsKey("WARNING"));
     Assert.assertTrue(summary.containsKey("CRITICAL"));
@@ -311,12 +311,12 @@ public class NagiosPropertyProviderTest {
     
     Map<String, Map<String, Object>> values = res.getPropertiesMap();
     
-    Assert.assertTrue(values.containsKey("alerts"));
-    Assert.assertTrue(values.containsKey("alerts/summary"));
-    Assert.assertTrue(values.get("alerts").containsKey("detail"));
-    Assert.assertTrue(List.class.isInstance(values.get("alerts").get("detail")));
+    Assert.assertTrue(values.containsKey("legacy_alerts"));
+    Assert.assertTrue(values.containsKey("legacy_alerts/summary"));
+    Assert.assertTrue(values.get("legacy_alerts").containsKey("detail"));
+    Assert.assertTrue(List.class.isInstance(values.get("legacy_alerts").get("detail")));
     
-    List<?> list = (List<?>) values.get("alerts").get("detail");
+    List<?> list = (List<?>) values.get("legacy_alerts").get("detail");
     Assert.assertTrue(7 == list.size());
     for (Object o : list) {
       Assert.assertTrue(Map.class.isInstance(o));
@@ -326,7 +326,7 @@ public class NagiosPropertyProviderTest {
       Assert.assertTrue("expected c6403.ambari.apache.org", host.equals("c6403.ambari.apache.org"));
     }
     
-    Map<String, Object> summary = values.get("alerts/summary");
+    Map<String, Object> summary = values.get("legacy_alerts/summary");
     Assert.assertTrue(summary.containsKey("OK"));
     Assert.assertTrue(summary.containsKey("WARNING"));
     Assert.assertTrue(summary.containsKey("CRITICAL"));
@@ -362,12 +362,12 @@ public class NagiosPropertyProviderTest {
     
     Map<String, Map<String, Object>> values = res.getPropertiesMap();
     
-    Assert.assertTrue(values.containsKey("alerts"));
-    Assert.assertTrue(values.containsKey("alerts/summary"));
-    Assert.assertTrue(values.get("alerts").containsKey("detail"));
-    Assert.assertTrue(List.class.isInstance(values.get("alerts").get("detail")));
+    Assert.assertTrue(values.containsKey("legacy_alerts"));
+    Assert.assertTrue(values.containsKey("legacy_alerts/summary"));
+    Assert.assertTrue(values.get("legacy_alerts").containsKey("detail"));
+    Assert.assertTrue(List.class.isInstance(values.get("legacy_alerts").get("detail")));
     
-    List<?> list = (List<?>) values.get("alerts").get("detail");
+    List<?> list = (List<?>) values.get("legacy_alerts").get("detail");
     Assert.assertEquals(Integer.valueOf(16), Integer.valueOf(list.size()));
     for (Object o : list) {
       Assert.assertTrue(Map.class.isInstance(o));
@@ -377,7 +377,7 @@ public class NagiosPropertyProviderTest {
       Assert.assertEquals("c6401.ambari.apache.org", host);
     }
     
-    Map<String, Object> summary = values.get("alerts/summary");
+    Map<String, Object> summary = values.get("legacy_alerts/summary");
     Assert.assertTrue(summary.containsKey("OK"));
     Assert.assertTrue(summary.containsKey("WARNING"));
     Assert.assertTrue(summary.containsKey("CRITICAL"));
@@ -417,12 +417,12 @@ public class NagiosPropertyProviderTest {
     
     Map<String, Map<String, Object>> values = res.getPropertiesMap();
     
-    Assert.assertTrue(values.containsKey("alerts"));
-    Assert.assertTrue(values.containsKey("alerts/summary"));
-    Assert.assertTrue(values.get("alerts").containsKey("detail"));
-    Assert.assertTrue(List.class.isInstance(values.get("alerts").get("detail")));
+    Assert.assertTrue(values.containsKey("legacy_alerts"));
+    Assert.assertTrue(values.containsKey("legacy_alerts/summary"));
+    Assert.assertTrue(values.get("legacy_alerts").containsKey("detail"));
+    Assert.assertTrue(List.class.isInstance(values.get("legacy_alerts").get("detail")));
     
-    List<?> list = (List<?>) values.get("alerts").get("detail");
+    List<?> list = (List<?>) values.get("legacy_alerts").get("detail");
     // removed an additional one
     Assert.assertEquals(Integer.valueOf(2), Integer.valueOf(list.size()));
     for (Object o : list) {
@@ -433,7 +433,7 @@ public class NagiosPropertyProviderTest {
       Assert.assertTrue("expected HBASE", serviceName.equals("HBASE"));
     }
     
-    Map<String, Object> summary = values.get("alerts/summary");
+    Map<String, Object> summary = values.get("legacy_alerts/summary");
     Assert.assertTrue(summary.containsKey("OK"));
     Assert.assertTrue(summary.containsKey("WARNING"));
     Assert.assertTrue(summary.containsKey("CRITICAL"));
@@ -490,12 +490,12 @@ public class NagiosPropertyProviderTest {
     
     Map<String, Map<String, Object>> values = res.getPropertiesMap();
     
-    Assert.assertTrue(values.containsKey("alerts"));
-    Assert.assertTrue(values.containsKey("alerts/summary"));
-    Assert.assertTrue(values.get("alerts").containsKey("detail"));
-    Assert.assertTrue(List.class.isInstance(values.get("alerts").get("detail")));
+    Assert.assertTrue(values.containsKey("legacy_alerts"));
+    Assert.assertTrue(values.containsKey("legacy_alerts/summary"));
+    Assert.assertTrue(values.get("legacy_alerts").containsKey("detail"));
+    Assert.assertTrue(List.class.isInstance(values.get("legacy_alerts").get("detail")));
     
-    List<?> list = (List<?>) values.get("alerts").get("detail");
+    List<?> list = (List<?>) values.get("legacy_alerts").get("detail");
     // removed an additional one
     Assert.assertEquals(Integer.valueOf(4), Integer.valueOf(list.size()));
     for (Object o : list) {
@@ -506,7 +506,7 @@ public class NagiosPropertyProviderTest {
       Assert.assertEquals(serviceName, "GANGLIA");
     }
     
-    Map<String, Object> summary = values.get("alerts/summary");
+    Map<String, Object> summary = values.get("legacy_alerts/summary");
     Assert.assertTrue(summary.containsKey("OK"));
     Assert.assertTrue(summary.containsKey("WARNING"));
     Assert.assertTrue(summary.containsKey("CRITICAL"));
@@ -543,12 +543,12 @@ public class NagiosPropertyProviderTest {
     
     Map<String, Map<String, Object>> values = res.getPropertiesMap();
     
-    Assert.assertTrue(values.containsKey("alerts"));
-    Assert.assertTrue(values.containsKey("alerts/summary"));
-    Assert.assertTrue(values.get("alerts").containsKey("detail"));
-    Assert.assertTrue(List.class.isInstance(values.get("alerts").get("detail")));
+    Assert.assertTrue(values.containsKey("legacy_alerts"));
+    Assert.assertTrue(values.containsKey("legacy_alerts/summary"));
+    Assert.assertTrue(values.get("legacy_alerts").containsKey("detail"));
+    Assert.assertTrue(List.class.isInstance(values.get("legacy_alerts").get("detail")));
     
-    List<?> list = (List<?>) values.get("alerts").get("detail");
+    List<?> list = (List<?>) values.get("legacy_alerts").get("detail");
     Assert.assertEquals(Integer.valueOf(1), Integer.valueOf(list.size()));
     for (Object o : list) {
       Assert.assertTrue(Map.class.isInstance(o));
@@ -558,7 +558,7 @@ public class NagiosPropertyProviderTest {
       Assert.assertEquals("c6404.ambari.apache.org", host);
     }
     
-    Map<String, Object> summary = values.get("alerts/summary");
+    Map<String, Object> summary = values.get("legacy_alerts/summary");
     Assert.assertTrue(summary.containsKey("OK"));
     Assert.assertTrue(summary.containsKey("WARNING"));
     Assert.assertTrue(summary.containsKey("CRITICAL"));

http://git-wip-us.apache.org/repos/asf/ambari/blob/1f1059cf/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 7c206a2..a397da4 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
@@ -229,7 +229,6 @@ public class AlertsDAOTest {
     current.setAlertHistory(history);
     dao.create(current);
     
-    
     List<AlertCurrentEntity> currentAlerts = dao.findCurrentByHost(clusterId, history.getHostName());
 
     assertNotNull(currentAlerts);
@@ -323,4 +322,78 @@ public class AlertsDAOTest {
     assertNotNull(entity.getAlertHistory());
     assertNotNull(entity.getAlertHistory().getAlertDefinition());
   }
+  
+  /**
+   * 
+   */
+  @Test
+  public void testFindCurrentSummary() throws Exception {
+    AlertSummaryDTO summary = dao.findCurrentCounts(clusterId.longValue(), null, null);
+    assertEquals(5, summary.getOkCount());
+
+    AlertHistoryEntity h1 = dao.findCurrentByCluster(clusterId.longValue()).get(2).getAlertHistory();
+    AlertHistoryEntity h2 = dao.findCurrentByCluster(clusterId.longValue()).get(3).getAlertHistory();
+    AlertHistoryEntity h3 = dao.findCurrentByCluster(clusterId.longValue()).get(4).getAlertHistory();
+    h1.setAlertState(AlertState.WARNING);
+    dao.merge(h1);
+    h2.setAlertState(AlertState.CRITICAL);
+    dao.merge(h2);
+    h3.setAlertState(AlertState.UNKNOWN);
+    dao.merge(h3);
+    
+    int ok = 0;
+    int warn = 0;
+    int crit = 0;
+    int unk = 0;
+    
+    for (AlertCurrentEntity h : dao.findCurrentByCluster(clusterId.longValue())) {
+      switch (h.getAlertHistory().getAlertState()) {
+        case CRITICAL:
+          crit++;
+          break;
+        case OK:
+          ok++;
+          break;
+        case UNKNOWN:
+          unk++;
+          break;
+        default:
+          warn++;
+          break;
+      }
+        
+    }
+      
+    summary = dao.findCurrentCounts(clusterId.longValue(), null, null);
+    // !!! db-to-db compare
+    assertEquals(ok, summary.getOkCount());
+    assertEquals(warn, summary.getWarningCount());
+    assertEquals(crit, summary.getCriticalCount());
+    assertEquals(unk, summary.getCriticalCount());
+    
+    // !!! expected
+    assertEquals(2, summary.getOkCount());
+    assertEquals(1, summary.getWarningCount());
+    assertEquals(1, summary.getCriticalCount());
+    assertEquals(1, summary.getCriticalCount());
+    
+    summary = dao.findCurrentCounts(clusterId.longValue(), "Service 0", null);
+    assertEquals(1, summary.getOkCount());
+    assertEquals(0, summary.getWarningCount());
+    assertEquals(0, summary.getCriticalCount());
+    assertEquals(0, summary.getCriticalCount());
+
+    summary = dao.findCurrentCounts(clusterId.longValue(), null, "h1");
+    assertEquals(2, summary.getOkCount());
+    assertEquals(1, summary.getWarningCount());
+    assertEquals(1, summary.getCriticalCount());
+    assertEquals(1, summary.getCriticalCount());
+    
+    summary = dao.findCurrentCounts(clusterId.longValue(), "foo", null);
+    assertEquals(0, summary.getOkCount());
+    assertEquals(0, summary.getWarningCount());
+    assertEquals(0, summary.getCriticalCount());
+    assertEquals(0, summary.getCriticalCount());
+    
+  }  
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/1f1059cf/ambari-web/app/controllers/global/update_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/global/update_controller.js b/ambari-web/app/controllers/global/update_controller.js
index a71f689..35b9e13 100644
--- a/ambari-web/app/controllers/global/update_controller.js
+++ b/ambari-web/app/controllers/global/update_controller.js
@@ -154,7 +154,7 @@ App.UpdateController = Em.Controller.extend({
     var realUrl = '/hosts?<parameters>fields=Hosts/host_name,Hosts/maintenance_state,Hosts/public_host_name,Hosts/cpu_count,Hosts/ph_cpu_count,' +
       'Hosts/host_status,Hosts/last_heartbeat_time,Hosts/ip,host_components/HostRoles/state,host_components/HostRoles/maintenance_state,' +
       'host_components/HostRoles/stale_configs,host_components/HostRoles/service_name,metrics/disk,metrics/load/load_one,Hosts/total_mem,' +
-      'alerts/summary<hostAuxiliaryInfo>&minimal_response=true';
+      'legacy_alerts/summary<hostAuxiliaryInfo>&minimal_response=true';
     var hostAuxiliaryInfo = ',Hosts/os_arch,Hosts/os_type,metrics/cpu/cpu_system,metrics/cpu/cpu_user,metrics/memory/mem_total,metrics/memory/mem_free';
 
     if (App.router.get('currentState.name') == 'index' && App.router.get('currentState.parentState.name') == 'hosts') {
@@ -423,7 +423,7 @@ App.UpdateController = Em.Controller.extend({
   },
   updateServices: function (callback) {
     var testUrl = '/data/services/HDP2/services.json';
-    var componentConfigUrl = this.getUrl(testUrl, '/services?fields=alerts/summary,ServiceInfo/state,ServiceInfo/maintenance_state&minimal_response=true');
+    var componentConfigUrl = this.getUrl(testUrl, '/services?fields=legacy_alerts/summary,ServiceInfo/state,ServiceInfo/maintenance_state&minimal_response=true');
     App.HttpClient.get(componentConfigUrl, App.serviceMapper, {
       complete: callback
     });

http://git-wip-us.apache.org/repos/asf/ambari/blob/1f1059cf/ambari-web/app/controllers/main/alerts_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/alerts_controller.js b/ambari-web/app/controllers/main/alerts_controller.js
index 0ea7212..2504ca1 100644
--- a/ambari-web/app/controllers/main/alerts_controller.js
+++ b/ambari-web/app/controllers/main/alerts_controller.js
@@ -139,8 +139,8 @@ App.MainAlertsController = Em.Controller.extend({
    */
   getAlertsSuccessCallback: function (json) {
     var alerts = [];
-    if (json && json.alerts && json.alerts.detail) {
-      json.alerts.detail.forEach(function (_alert) {
+    if (json && json.legacy_alerts && json.legacy_alerts.detail) {
+      json.legacy_alerts.detail.forEach(function (_alert) {
         alerts.pushObject(App.Alert.create({
           title: _alert.description,
           serviceType: _alert.service_name,

http://git-wip-us.apache.org/repos/asf/ambari/blob/1f1059cf/ambari-web/app/controllers/main/host.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/host.js b/ambari-web/app/controllers/main/host.js
index 227a091..ae36158 100644
--- a/ambari-web/app/controllers/main/host.js
+++ b/ambari-web/app/controllers/main/host.js
@@ -122,7 +122,7 @@ App.MainHostController = Em.ArrayController.extend({
     },
     {
       key: 'criticalAlertsCount',
-      alias: 'alerts/summary/CRITICAL{0}|alerts/summary/WARNING{1}',
+      alias: 'legacy_alerts/summary/CRITICAL{0}|legacy_alerts/summary/WARNING{1}',
       type: 'CUSTOM'
     },
     {
@@ -368,7 +368,7 @@ App.MainHostController = Em.ArrayController.extend({
       'UNHEALTHY': data.Clusters.health_report['Host/host_status/UNHEALTHY'],
       'ALERT': data.Clusters.health_report['Host/host_status/ALERT'],
       'UNKNOWN': data.Clusters.health_report['Host/host_status/UNKNOWN'],
-      'health-status-WITH-ALERTS': (data.alerts) ? data.alerts.summary.CRITICAL + data.alerts.summary.WARNING : 0,
+      'health-status-WITH-ALERTS': (data.legacy_alerts) ? data.legacy_alerts.summary.CRITICAL + data.legacy_alerts.summary.WARNING : 0,
       'health-status-RESTART': data.Clusters.health_report['Host/stale_config'],
       'health-status-PASSIVE_STATE': data.Clusters.health_report['Host/maintenance_state'],
       'TOTAL': data.Clusters.total_hosts

http://git-wip-us.apache.org/repos/asf/ambari/blob/1f1059cf/ambari-web/app/mappers/hosts_mapper.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers/hosts_mapper.js b/ambari-web/app/mappers/hosts_mapper.js
index 05037f2..241ea88 100644
--- a/ambari-web/app/mappers/hosts_mapper.js
+++ b/ambari-web/app/mappers/hosts_mapper.js
@@ -92,7 +92,7 @@ App.hostsMapper = App.QuickDataMapper.create({
           }
           serviceToHostComponentIdMap[serviceName].push(component.id);
         }, this);
-        item.critical_alerts_count = (item.alerts) ? item.alerts.summary.CRITICAL + item.alerts.summary.WARNING : 0;
+        item.critical_alerts_count = (item.legacy_alerts) ? item.legacy_alerts.summary.CRITICAL + item.legacy_alerts.summary.WARNING : 0;
         item.cluster_id = App.get('clusterName');
         item.index = index;
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/1f1059cf/ambari-web/app/mappers/service_mapper.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers/service_mapper.js b/ambari-web/app/mappers/service_mapper.js
index 00680a3..12f65f3 100644
--- a/ambari-web/app/mappers/service_mapper.js
+++ b/ambari-web/app/mappers/service_mapper.js
@@ -30,8 +30,8 @@ App.serviceMapper = App.QuickDataMapper.create({
         cachedService.ServiceInfo.passive_state = service.ServiceInfo.maintenance_state;
 
         //check whether Nagios installed and started
-        if (service.alerts) {
-          cachedService.ServiceInfo.critical_alerts_count = service.alerts.summary.CRITICAL + service.alerts.summary.WARNING;
+        if (service.legacy_alerts) {
+          cachedService.ServiceInfo.critical_alerts_count = service.legacy_alerts.summary.CRITICAL + service.legacy_alerts.summary.WARNING;
         }
       } else {
         var serviceData = {
@@ -45,8 +45,8 @@ App.serviceMapper = App.QuickDataMapper.create({
         };
 
         //check whether Nagios installed and started
-        if (service.alerts) {
-          serviceData.ServiceInfo.critical_alerts_count = service.alerts.summary.CRITICAL + service.alerts.summary.WARNING;
+        if (service.legacy_alerts) {
+          serviceData.ServiceInfo.critical_alerts_count = service.legacy_alerts.summary.CRITICAL + service.legacy_alerts.summary.WARNING;
         }
         App.cache['services'].push(serviceData);
       }

http://git-wip-us.apache.org/repos/asf/ambari/blob/1f1059cf/ambari-web/app/utils/ajax/ajax.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/ajax/ajax.js b/ambari-web/app/utils/ajax/ajax.js
index 3d1fda9..b787a2e 100644
--- a/ambari-web/app/utils/ajax/ajax.js
+++ b/ambari-web/app/utils/ajax/ajax.js
@@ -291,11 +291,11 @@ var urls = {
   },
 
   'alerts.get_by_service': {
-    'real': '/clusters/{clusterName}/services/{serviceName}?fields=alerts',
+    'real': '/clusters/{clusterName}/services/{serviceName}?fields=legacy_alerts',
     'mock': '/data/alerts/HDP2/service_alerts.json'
   },
   'alerts.get_by_host': {
-    'real': '/clusters/{clusterName}/hosts/{hostName}?fields=alerts',
+    'real': '/clusters/{clusterName}/hosts/{hostName}?fields=legacy_alerts',
     'mock': '/data/alerts/HDP2/host_alerts.json'
   },
   'background_operations.get_most_recent': {
@@ -1747,7 +1747,7 @@ var urls = {
     }
   },
   'host.status.counters': {
-    'real': '/clusters/{clusterName}?fields=alerts,Clusters/health_report,Clusters/total_hosts&minimal_response=true',
+    'real': '/clusters/{clusterName}?fields=legacy_alerts,Clusters/health_report,Clusters/total_hosts&minimal_response=true',
     'mock': '/data/hosts/HDP2/host_status_counters.json'
   },
   'components.filter_by_status': {

http://git-wip-us.apache.org/repos/asf/ambari/blob/1f1059cf/ambari-web/test/controllers/main/alerts_controller_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/alerts_controller_test.js b/ambari-web/test/controllers/main/alerts_controller_test.js
index 3a3dc7f..aee782a 100644
--- a/ambari-web/test/controllers/main/alerts_controller_test.js
+++ b/ambari-web/test/controllers/main/alerts_controller_test.js
@@ -171,18 +171,18 @@ describe('MainAlertsController', function () {
         result: []
       },
       {
-        title: 'data.alerts is null',
-        data: {alerts: null},
+        title: 'data.legacy_alerts is null',
+        data: {legacy_alerts: null},
         result: []
       },
       {
-        title: 'data.alerts.detail is null',
-        data: {alerts: {detail: null}},
+        title: 'data.legacy_alerts.detail is null',
+        data: {legacy_alerts: {detail: null}},
         result: []
       },
       {
-        title: 'data.alerts.detail is empty',
-        data: {alerts: {detail: []}},
+        title: 'data.legacy_alerts.detail is empty',
+        data: {legacy_alerts: {detail: []}},
         result: []
       }
     ];
@@ -195,7 +195,7 @@ describe('MainAlertsController', function () {
       });
     });
 
-    var data = {alerts: {detail: [
+    var data = {legacy_alerts: {detail: [
       {
         description: 't1',
         service_name: "s1",
@@ -208,27 +208,27 @@ describe('MainAlertsController', function () {
     ]}};
     var testCasesOfStatus = [
       {
-        title: 'data.alerts.detail is correct, OK status',
+        title: 'data.legacy_alerts.detail is correct, OK status',
         status: 'OK',
         result: '0'
       },
       {
-        title: 'data.alerts.detail is correct, WARNING status',
+        title: 'data.legacy_alerts.detail is correct, WARNING status',
         status: 'WARNING',
         result: '1'
       },
       {
-        title: 'data.alerts.detail is correct, CRITICAL status',
+        title: 'data.legacy_alerts.detail is correct, CRITICAL status',
         status: 'CRITICAL',
         result: '2'
       },
       {
-        title: 'data.alerts.detail is correct, PASSIVE status',
+        title: 'data.legacy_alerts.detail is correct, PASSIVE status',
         status: 'PASSIVE',
         result: '3'
       },
       {
-        title: 'data.alerts.detail is correct, unknown status',
+        title: 'data.legacy_alerts.detail is correct, unknown status',
         status: '',
         result: '4'
       }
@@ -236,7 +236,7 @@ describe('MainAlertsController', function () {
     testCasesOfStatus.forEach(function (test) {
       it(test.title, function () {
         controller.set('isLoaded', false);
-        data.alerts.detail[0].status = test.status;
+        data.legacy_alerts.detail[0].status = test.status;
         controller.getAlertsSuccessCallback(data);
         expect(controller.get('alerts.length')).to.equal(1);
         expect(controller.get('alerts').objectAt(0).get('status')).to.equal(test.result);
@@ -257,4 +257,4 @@ describe('MainAlertsController', function () {
       expect(controller.get('isLoaded')).to.be.true;
     });
   });
-});
\ No newline at end of file
+});


[09/50] [abbrv] git commit: Merge branch 'trunk' into branch-alerts-dev

Posted by jo...@apache.org.
Merge branch 'trunk' into branch-alerts-dev


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

Branch: refs/heads/trunk
Commit: 7a0f5091784d80b3ea3da535534850f8b6be5201
Parents: c13730a b6abb3d
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Tue Sep 2 08:12:12 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Tue Sep 2 08:12:12 2014 -0400

----------------------------------------------------------------------
 ambari-agent/conf/unix/install-helper.sh        |   6 -
 ambari-server/conf/unix/install-helper.sh       |   6 -
 .../apache/ambari/server/state/ConfigImpl.java  |   2 +-
 .../state/configgroup/ConfigGroupImpl.java      |   3 +-
 .../services/HIVE/configuration/hive-env.xml    |   2 +-
 .../1.3.2/services/HIVE/package/scripts/hive.py |   8 +-
 .../services/HIVE/package/scripts/params.py     |   4 +
 .../services/HIVE/configuration/hive-env.xml    |   2 +-
 .../2.0.6/services/HIVE/package/scripts/hive.py |  10 +-
 .../services/HIVE/package/scripts/params.py     |   4 +
 .../stacks/HDP/2.0.6/services/YARN/metainfo.xml |   1 -
 .../stacks/HDP/2.1/services/FALCON/metainfo.xml |   4 +
 .../server/state/cluster/ClusterTest.java       |  22 +
 .../stacks/1.3.2/HIVE/test_hive_client.py       |   8 +-
 .../stacks/1.3.2/HIVE/test_hive_metastore.py    |   4 +-
 .../stacks/1.3.2/HIVE/test_hive_server.py       |   4 +-
 .../python/stacks/1.3.2/configs/default.json    |   4 +-
 .../stacks/1.3.2/configs/default_client.json    | 600 ++++++++++++++
 .../python/stacks/1.3.2/configs/secured.json    |   2 +-
 .../stacks/1.3.2/configs/secured_client.json    | 786 ++++++++++++++++++
 .../stacks/2.0.6/HIVE/test_hive_client.py       |   8 +-
 .../stacks/2.0.6/HIVE/test_hive_metastore.py    |   4 +-
 .../stacks/2.0.6/HIVE/test_hive_server.py       |   4 +-
 .../python/stacks/2.0.6/configs/default.json    |   4 +-
 .../stacks/2.0.6/configs/default_client.json    | 797 ++++++++++++++++++
 .../python/stacks/2.0.6/configs/secured.json    |   4 +-
 .../stacks/2.0.6/configs/secured_client.json    | 818 +++++++++++++++++++
 .../stacks/2.1/HIVE/test_hive_metastore.py      |   4 +-
 .../test/python/stacks/2.1/configs/default.json |   4 +-
 .../test/python/stacks/2.1/configs/secured.json |   4 +-
 .../resourceManager/wizard_controller.js        |  12 +
 .../controllers/main/service/info/configs.js    |  53 +-
 ambari-web/app/messages.js                      |   1 +
 ambari-web/app/models/service_config.js         |   6 +-
 .../app/routes/rm_high_availability_routes.js   |  20 +-
 .../common/configs/config_history_flow.hbs      |   8 +-
 .../common/configs/save_configuration.hbs       |   6 +-
 .../views/common/configs/config_history_flow.js |  32 +-
 .../main/dashboard/widgets/pie_chart_widget.js  |   7 +-
 .../resources/ui/app/assets/data/apps/apps.json | 675 ++++++++++++---
 .../ui/app/controllers/slider_app_controller.js |   4 +-
 .../main/resources/ui/app/models/slider_app.js  |  51 +-
 .../ui/app/templates/slider_app/configs.hbs     |  84 +-
 43 files changed, 3788 insertions(+), 304 deletions(-)
----------------------------------------------------------------------



[22/50] [abbrv] git commit: Merge branch 'trunk' into branch-alerts-dev

Posted by jo...@apache.org.
Merge branch 'trunk' into branch-alerts-dev

Conflicts:
	ambari-server/conf/unix/ambari.properties
	ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java


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

Branch: refs/heads/trunk
Commit: aaf051357de9493217fd5b2e05daa06c55a13132
Parents: 853497f 3355733
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Fri Sep 12 19:52:41 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Fri Sep 12 19:52:41 2014 -0400

----------------------------------------------------------------------
 .../main/resources/ui/admin-web/app/index.html  |   7 +-
 .../resources/ui/admin-web/app/scripts/app.js   |   3 +-
 .../controllers/ambariViews/ViewsEditCtrl.js    |   7 +-
 .../controllers/groups/GroupsEditCtrl.js        |   8 +-
 .../app/scripts/controllers/mainCtrl.js         |   2 +-
 .../scripts/controllers/users/UsersShowCtrl.js  |  18 +-
 .../ui/admin-web/app/scripts/i18n.config.js     |  29 ++
 .../resources/ui/admin-web/app/styles/main.css  |   9 +
 .../admin-web/app/views/ambariViews/edit.html   |  10 +-
 .../app/views/clusters/manageAccess.html        |   2 +-
 .../ui/admin-web/app/views/groups/edit.html     |   4 +-
 .../ui/admin-web/app/views/leftNavbar.html      |  15 +-
 .../ui/admin-web/app/views/users/show.html      |   8 +-
 .../src/main/resources/ui/admin-web/bower.json  |   4 +-
 .../libraries/providers/execute_hadoop.py       |   9 +-
 .../libraries/providers/hdfs_directory.py       |  16 +-
 .../libraries/resources/execute_hadoop.py       |   1 +
 .../libraries/resources/hdfs_directory.py       |   1 +
 ambari-server/conf/unix/ambari.properties       |   2 +-
 ambari-server/docs/api/v1/clusters-cluster.md   | 284 +++++++-----
 .../server/configuration/Configuration.java     |   5 +-
 .../internal/BaseBlueprintProcessor.java        |  13 +-
 .../ServiceConfigVersionResourceProvider.java   |   2 +-
 .../internal/StackAdvisorResourceProvider.java  |   6 +-
 .../server/upgrade/UpgradeCatalog170.java       |   2 +
 .../ambari/server/view/ViewArchiveUtility.java  | 120 ++++++
 .../ambari/server/view/ViewExtractor.java       | 223 ++++++++++
 .../apache/ambari/server/view/ViewRegistry.java | 429 ++++++-------------
 ambari-server/src/main/python/ambari-server.py  | 100 ++++-
 .../src/main/resources/ganglia_properties.json  |  40 ++
 .../2.0.6/hooks/after-INSTALL/scripts/params.py |  20 +-
 .../hooks/before-INSTALL/scripts/params.py      |   3 +-
 .../hooks/before-START/files/checkForFormat.sh  |   3 +
 .../2.0.6/hooks/before-START/scripts/params.py  |  25 +-
 .../services/FLUME/package/scripts/flume.py     |   2 +-
 .../FLUME/package/scripts/flume_check.py        |   2 +-
 .../services/FLUME/package/scripts/params.py    |  14 +-
 .../HBASE/package/files/hbaseSmokeVerify.sh     |   3 +-
 .../services/HBASE/package/scripts/params.py    |  37 +-
 .../HBASE/package/scripts/service_check.py      |   6 +-
 .../HDFS/package/files/checkForFormat.sh        |   4 +-
 .../HDFS/package/scripts/hdfs_namenode.py       |  15 +-
 .../services/HDFS/package/scripts/namenode.py   |   2 +-
 .../services/HDFS/package/scripts/params.py     |  34 +-
 .../HDFS/package/scripts/service_check.py       |  27 +-
 .../2.0.6/services/HIVE/package/scripts/hcat.py |   6 +
 .../HIVE/package/scripts/hcat_service_check.py  |   8 +-
 .../2.0.6/services/HIVE/package/scripts/hive.py |   2 +
 .../HIVE/package/scripts/hive_service.py        |   9 +-
 .../HIVE/package/scripts/install_jars.py        |   6 +-
 .../services/HIVE/package/scripts/params.py     |  73 ++--
 .../package/templates/startHiveserver2.sh.j2    |   2 +-
 .../services/OOZIE/configuration/oozie-env.xml  |   2 +-
 .../services/OOZIE/package/files/oozieSmoke2.sh |   8 +-
 .../OOZIE/package/scripts/oozie_service.py      |   4 +-
 .../services/OOZIE/package/scripts/params.py    |  24 +-
 .../services/PIG/package/scripts/params.py      |  20 +-
 .../PIG/package/scripts/service_check.py        |  10 +-
 .../services/SQOOP/package/scripts/params.py    |  10 +-
 .../WEBHCAT/configuration/webhcat-env.xml       |   2 +-
 .../services/WEBHCAT/package/scripts/params.py  |  41 +-
 .../services/WEBHCAT/package/scripts/webhcat.py |  11 +-
 .../services/YARN/package/scripts/params.py     |  45 +-
 .../YARN/package/scripts/resourcemanager.py     |   5 +-
 .../services/YARN/package/scripts/service.py    |   2 +-
 .../YARN/package/scripts/service_check.py       |   3 +-
 .../2.0.6/services/YARN/package/scripts/yarn.py |  14 +-
 .../ZOOKEEPER/package/scripts/params.py         |  17 +-
 .../services/FALCON/package/scripts/params.py   |  15 +-
 .../services/STORM/package/scripts/params.py    |   5 +-
 .../main/resources/stacks/HDP/2.2/metainfo.xml  |  23 +
 .../resources/stacks/HDP/2.2/repos/repoinfo.xml |  82 ++++
 .../stacks/HDP/2.2/role_command_order.json      |  88 ++++
 .../stacks/HDP/2.2/services/FALCON/metainfo.xml |  28 ++
 .../stacks/HDP/2.2/services/FLUME/metainfo.xml  |  40 ++
 .../stacks/HDP/2.2/services/HBASE/metainfo.xml  |  42 ++
 .../services/HDFS/configuration/hadoop-env.xml  |  29 ++
 .../services/HDFS/configuration/hdfs-site.xml   |  34 ++
 .../stacks/HDP/2.2/services/HDFS/metainfo.xml   |  68 +++
 .../stacks/HDP/2.2/services/HIVE/metainfo.xml   |  44 ++
 .../services/OOZIE/configuration/oozie-site.xml |  45 ++
 .../stacks/HDP/2.2/services/OOZIE/metainfo.xml  |  28 ++
 .../stacks/HDP/2.2/services/PIG/metainfo.xml    |  41 ++
 .../stacks/HDP/2.2/services/SQOOP/metainfo.xml  |  29 ++
 .../services/STORM/configuration/storm-env.xml  |  29 ++
 .../services/STORM/configuration/storm-site.xml |  54 +++
 .../stacks/HDP/2.2/services/STORM/metainfo.xml  |  29 ++
 .../stacks/HDP/2.2/services/TEZ/metainfo.xml    |  40 ++
 .../WEBHCAT/configuration/webhcat-site.xml      |  59 +++
 .../HDP/2.2/services/WEBHCAT/metainfo.xml       |  44 ++
 .../YARN/configuration-mapred/mapred-site.xml   |  36 ++
 .../services/YARN/configuration/yarn-site.xml   |  35 ++
 .../stacks/HDP/2.2/services/YARN/metainfo.xml   |  71 +++
 .../HDP/2.2/services/ZOOKEEPER/metainfo.xml     |  40 ++
 .../AmbariPrivilegeResourceProviderTest.java    |   2 +-
 .../internal/BaseBlueprintProcessorTest.java    | 413 ++++++++++++++++++
 .../StackAdvisorResourceProviderTest.java       |  76 ++++
 .../ViewPrivilegeResourceProviderTest.java      |   2 +-
 ...mbariLdapAuthenticationProviderBaseTest.java |  50 +++
 ...uthenticationProviderForDNWithSpaceTest.java |   4 +-
 .../AmbariLdapAuthenticationProviderTest.java   |   4 +-
 .../ambari/server/view/ViewExtractorTest.java   | 262 +++++++++++
 .../ambari/server/view/ViewRegistryTest.java    | 105 +++--
 .../src/test/python/TestAmbariServer.py         |  60 ++-
 .../stacks/1.3.2/HDFS/test_service_check.py     |  18 +-
 .../stacks/2.0.6/HBASE/test_hbase_master.py     |   6 +
 .../2.0.6/HBASE/test_hbase_regionserver.py      |   6 +
 .../2.0.6/HBASE/test_hbase_service_check.py     |  10 +-
 .../python/stacks/2.0.6/HDFS/test_namenode.py   |  36 +-
 .../stacks/2.0.6/HDFS/test_service_check.py     |  18 +-
 .../stacks/2.0.6/HIVE/test_hcat_client.py       |  10 +-
 .../stacks/2.0.6/HIVE/test_hive_metastore.py    |   8 +
 .../stacks/2.0.6/HIVE/test_hive_server.py       |  18 +
 .../2.0.6/HIVE/test_hive_service_check.py       |   7 +
 .../stacks/2.0.6/OOZIE/test_oozie_server.py     |  10 +-
 .../stacks/2.0.6/PIG/test_pig_service_check.py  |  12 +-
 .../stacks/2.0.6/WEBHCAT/test_webhcat_server.py |  12 +
 .../stacks/2.0.6/YARN/test_historyserver.py     |  12 +
 .../stacks/2.0.6/YARN/test_nodemanager.py       |  12 +
 .../2.0.6/YARN/test_yarn_service_check.py       |   9 +-
 .../stacks/2.1/FALCON/test_falcon_server.py     |   2 +
 .../stacks/2.1/HIVE/test_hive_metastore.py      |   7 +
 ambari-web/app/assets/test/tests.js             |   1 +
 .../highAvailability/progress_controller.js     |  15 +-
 .../main/dashboard/config_history_controller.js |   2 +-
 .../app/controllers/wizard/step7_controller.js  |   8 +-
 ambari-web/app/data/HDP2/secure_properties.js   |   6 +-
 ambari-web/app/data/secure_properties.js        |  15 +
 ambari-web/app/models/service_config_version.js |   5 +-
 ambari-web/app/styles/application.less          |  20 +-
 .../common/configs/config_history_flow.hbs      |   8 +-
 .../templates/main/dashboard/config_history.hbs |  14 +-
 ambari-web/app/utils/config.js                  |  14 +-
 .../views/main/dashboard/config_history_view.js |   8 +-
 .../progress_controller_test.js                 | 144 +++++++
 .../assets/data/resource/slider-properties.json |  64 +++
 .../ui/app/components/configSection.js          |   2 +-
 .../createAppWizard/step1_controller.js         |  26 +-
 .../createAppWizard/step3_controller.js         |   8 +-
 .../app/controllers/slider_apps_controller.js   | 187 --------
 .../ui/app/controllers/slider_controller.js     | 294 +++++++++++++
 .../src/main/resources/ui/app/helpers/ajax.js   |  44 +-
 .../src/main/resources/ui/app/initialize.js     |  16 +-
 .../ui/app/mappers/application_status.js        |  52 ++-
 .../main/resources/ui/app/models/slider_app.js  |   7 +-
 .../resources/ui/app/styles/application.less    |  49 ++-
 .../app/templates/components/configSection.hbs  |   3 +-
 .../ui/app/templates/createAppWizard/step3.hbs  |   2 +-
 .../ui/app/templates/slider_app/summary.hbs     | 200 ++++-----
 .../ui/app/views/createAppWizard/step3_view.js  |   3 +-
 .../ui/app/views/slider_app/summary_view.js     |   4 +-
 151 files changed, 4293 insertions(+), 1097 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/aaf05135/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
----------------------------------------------------------------------


[21/50] [abbrv] git commit: AMBARI-7282. Add metric- and script-based alert types (ncole)

Posted by jo...@apache.org.
AMBARI-7282. Add metric- and script-based alert types (ncole)


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

Branch: refs/heads/trunk
Commit: 853497f8eda3fa39c2611391c9e2bce32856119e
Parents: 2262400
Author: Nate Cole <nc...@hortonworks.com>
Authored: Fri Sep 12 10:37:52 2014 -0400
Committer: Nate Cole <nc...@hortonworks.com>
Committed: Fri Sep 12 10:37:52 2014 -0400

----------------------------------------------------------------------
 .../ambari_agent/AlertSchedulerHandler.py       |  21 ++-
 .../src/main/python/ambari_agent/Controller.py  |  10 +-
 .../python/ambari_agent/alerts/base_alert.py    |   6 +
 .../python/ambari_agent/alerts/metric_alert.py  | 174 +++++++++++++++++++
 .../python/ambari_agent/alerts/script_alert.py  |  70 ++++++++
 .../src/test/python/ambari_agent/TestAlerts.py  | 102 ++++++++++-
 .../ambari_agent/dummy_files/definitions.json   |  21 ---
 .../ambari_agent/dummy_files/test_script.py     |   3 +
 .../internal/AlertResourceProvider.java         |   2 +-
 .../internal/AlertSummaryPropertyProvider.java  |   4 +
 .../ambari/server/state/alert/MetricSource.java |  23 +--
 .../server/state/cluster/AlertDataManager.java  |   1 +
 .../stacks/HDP/2.0.6/services/HDFS/alerts.json  |  32 +++-
 13 files changed, 419 insertions(+), 50 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/853497f8/ambari-agent/src/main/python/ambari_agent/AlertSchedulerHandler.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/AlertSchedulerHandler.py b/ambari-agent/src/main/python/ambari_agent/AlertSchedulerHandler.py
index e987dae..7cce533 100644
--- a/ambari-agent/src/main/python/ambari_agent/AlertSchedulerHandler.py
+++ b/ambari-agent/src/main/python/ambari_agent/AlertSchedulerHandler.py
@@ -29,7 +29,9 @@ import time
 import traceback
 from apscheduler.scheduler import Scheduler
 from alerts.collector import AlertCollector
+from alerts.metric_alert import MetricAlert
 from alerts.port_alert import PortAlert
+from alerts.script_alert import ScriptAlert
 
 
 logger = logging.getLogger()
@@ -48,8 +50,9 @@ class AlertSchedulerHandler():
     'standalone': False
   }
 
-  def __init__(self, cachedir, in_minutes=True):
+  def __init__(self, cachedir, stacks_dir, in_minutes=True):
     self.cachedir = cachedir
+    self.stacks_dir = stacks_dir
     
     if not os.path.exists(cachedir) and AlertSchedulerHandler.make_cachedir:
       try:
@@ -133,6 +136,7 @@ class AlertSchedulerHandler():
 
       for definition in command_json['alertDefinitions']:
         obj = self.__json_to_callable(definition)
+        
         if obj is None:
           continue
           
@@ -163,11 +167,12 @@ class AlertSchedulerHandler():
     alert = None
 
     if source_type == AlertSchedulerHandler.TYPE_METRIC:
-      pass
+      alert = MetricAlert(json_definition, source)
     elif source_type == AlertSchedulerHandler.TYPE_PORT:
       alert = PortAlert(json_definition, source)
-    elif type == AlertSchedulerHandler.TYPE_SCRIPT:
-      pass
+    elif source_type == AlertSchedulerHandler.TYPE_SCRIPT:
+      source['stacks_dir'] = self.stacks_dir
+      alert = ScriptAlert(json_definition, source)
 
     return alert
     
@@ -210,11 +215,15 @@ def main():
   del args[0]
 
   try:
-    logger.setLevel(logger.debug)
+    logger.setLevel(logging.DEBUG)
   except TypeError:
     logger.setLevel(12)
     
-  ash = AlertSchedulerHandler(args[0], False)
+  ch = logging.StreamHandler()
+  ch.setLevel(logger.level)
+  logger.addHandler(ch)
+    
+  ash = AlertSchedulerHandler(args[0], args[1], False)
   ash.start()
   
   i = 0

http://git-wip-us.apache.org/repos/asf/ambari/blob/853497f8/ambari-agent/src/main/python/ambari_agent/Controller.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/Controller.py b/ambari-agent/src/main/python/ambari_agent/Controller.py
index 0ceeeff..70b4500 100644
--- a/ambari-agent/src/main/python/ambari_agent/Controller.py
+++ b/ambari-agent/src/main/python/ambari_agent/Controller.py
@@ -31,13 +31,14 @@ import pprint
 from random import randint
 
 import hostname
+import security
+import ssl
 import AmbariConfig
 from Heartbeat import Heartbeat
 from Register import Register
 from ActionQueue import ActionQueue
-import security
+from FileCache import FileCache
 from NetUtil import NetUtil
-import ssl
 from LiveStatus import LiveStatus
 from AlertSchedulerHandler import AlertSchedulerHandler
 
@@ -78,9 +79,10 @@ class Controller(threading.Thread):
     cache_dir = config.get('agent', 'cache_dir')
     if cache_dir is None:
       cache_dir = '/var/lib/ambari-agent/cache'
-      
+
+    stacks_cache_dir = os.path.join(cache_dir, FileCache.STACKS_CACHE_DIRECTORY)
     alerts_cache_dir = os.path.join(cache_dir, 'alerts')
-    self.alert_scheduler_handler = AlertSchedulerHandler(alerts_cache_dir)
+    self.alert_scheduler_handler = AlertSchedulerHandler(alerts_cache_dir, stacks_cache_dir)
 
 
   def __del__(self):

http://git-wip-us.apache.org/repos/asf/ambari/blob/853497f8/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py b/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py
index adb872a..b22938d 100644
--- a/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py
+++ b/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py
@@ -70,6 +70,9 @@ class BaseAlert(object):
       traceback.print_exc()
       res = (BaseAlert.RESULT_UNKNOWN, [str(e)])
       res_base_text = "Unknown {0}"
+    
+    if logger.isEnabledFor(logging.DEBUG):
+      logger.debug("debug alert result: {0}".format(str(res)))
       
     data = {}
     data['name'] = self._find_value('name')
@@ -80,6 +83,9 @@ class BaseAlert(object):
     data['service'] = self._find_value('serviceName')
     data['component'] = self._find_value('componentName')
     data['timestamp'] = long(time.time() * 1000)
+
+    if logger.isEnabledFor(logging.DEBUG):
+      logger.debug("debug alert text: {0}".format(data['text']))
     
     self.collector.put(self.cluster, data)
   

http://git-wip-us.apache.org/repos/asf/ambari/blob/853497f8/ambari-agent/src/main/python/ambari_agent/alerts/metric_alert.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/alerts/metric_alert.py b/ambari-agent/src/main/python/ambari_agent/alerts/metric_alert.py
new file mode 100644
index 0000000..5e4ea9e
--- /dev/null
+++ b/ambari-agent/src/main/python/ambari_agent/alerts/metric_alert.py
@@ -0,0 +1,174 @@
+#!/usr/bin/env python
+
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+'''
+
+import imp
+import json
+import logging
+import re
+import urllib2
+import uuid
+from alerts.base_alert import BaseAlert
+from resource_management.libraries.functions.get_port_from_url import get_port_from_url
+
+logger = logging.getLogger()
+
+class MetricAlert(BaseAlert):
+  
+  def __init__(self, alert_meta, alert_source_meta):
+    super(MetricAlert, self).__init__(alert_meta, alert_source_meta)
+
+    self.uri = self._find_lookup_property(alert_source_meta['uri'])
+    self.metric_info = None
+    
+    if 'jmx' in alert_source_meta:
+      self.metric_info = JmxMetric(alert_source_meta['jmx'])
+      
+  def _collect(self):
+    if self.metric_info is None:
+      raise Exception("Could not determine result.  Specific metric collector is not defined.")
+
+    uri = self._lookup_property_value(self.uri)
+    
+    host = BaseAlert.get_host_from_url(uri)
+    if host is None:
+      host = self.host_name
+
+    port = 80 # probably not very realistic
+    try:      
+      port = int(get_port_from_url(uri))
+    except:
+      pass
+
+    collect_result = None
+    check_value = None
+    value_list = []
+
+    if isinstance(self.metric_info, JmxMetric):
+      value_list.extend(self._load_jmx(False, host, port, self.metric_info))
+      check_value = self.metric_info.calculate(value_list)
+      value_list.append(check_value)
+      
+      collect_result = self.__get_result(value_list[0] if check_value is None else check_value)
+
+    logger.debug("Resolved value list is: {0}".format(str(value_list)))
+    
+    return ((collect_result, value_list))
+  
+  def __get_result(self, value):
+    ok_value = self.__find_threshold('ok')
+    warn_value = self.__find_threshold('warning')
+    crit_value = self.__find_threshold('critical')
+    
+    # critical values are higher
+    crit_direction_up = crit_value > warn_value
+    
+    if crit_direction_up: 
+      # critcal values are higher
+      if value > crit_value:
+        return self.RESULT_CRITICAL
+      elif value > warn_value:
+        return self.RESULT_WARNING
+      else:
+        if ok_value is not None:
+          if value > ok_value and value <= warn_value:
+            return self.RESULT_OK
+          else:
+            return self.RESULT_UNKNOWN
+        else:
+          return self.RESULT_OK
+    else:
+      # critical values are lower
+      if value < crit_value:
+        return self.RESULT_CRITICAL
+      elif value < warn_value:
+        return self.RESULT_WARNING
+      else:
+        if ok_value is not None:
+          if value < ok_value and value >= warn_value:
+            return self.RESULT_OK
+          else:
+            return self.RESULT_UNKNOWN
+        else:
+          return self.RESULT_OK
+
+    return None
+    
+  def __find_threshold(self, reporting_type):
+    ''' find the defined thresholds for alert values '''
+    
+    if not 'reporting' in self.alert_source_meta:
+      return None
+      
+    if not reporting_type in self.alert_source_meta['reporting']:
+      return None
+      
+    if not 'value' in self.alert_source_meta['reporting'][reporting_type]:
+      return None
+      
+    return self.alert_source_meta['reporting'][reporting_type]['value']
+    
+  def _load_jmx(self, ssl, host, port, jmx_metric):
+    ''' creates a JmxMetric object that holds info about jmx-based metrics '''
+    
+    logger.debug(str(jmx_metric.property_map))
+    
+    value_list = []
+
+    for k, v in jmx_metric.property_map.iteritems():
+      url = "{0}://{1}:{2}/jmx?qry={3}".format(
+        "https" if ssl else "http", host, str(port), k)
+        
+      response = urllib2.urlopen(url)
+      json_response = json.loads(response.read())
+      json_data = json_response['beans'][0]
+      
+      for attr in v:
+        value_list.append(json_data[attr])
+        
+    return value_list
+    
+class JmxMetric:
+  def __init__(self, jmx_info):
+    self.custom_module = None
+    self.property_list = jmx_info['property_list']
+    self.property_map = {}
+    
+    if 'value' in jmx_info:
+      realcode = re.sub('(\{(\d+)\})', 'args[\g<2>]', jmx_info['value'])
+      
+      self.custom_module =  imp.new_module(str(uuid.uuid4()))
+      code = 'def f(args):\n  return ' + realcode
+      exec code in self.custom_module.__dict__
+    
+    for p in self.property_list:
+      parts = p.split('/')
+      if not parts[0] in self.property_map:
+        self.property_map[parts[0]] = []
+      self.property_map[parts[0]].append(parts[1])
+      
+  def calculate(self, args):
+    if self.custom_module is not None:
+      return self.custom_module.f(args)
+    return None
+    
+      
+    
+  
+    

http://git-wip-us.apache.org/repos/asf/ambari/blob/853497f8/ambari-agent/src/main/python/ambari_agent/alerts/script_alert.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/alerts/script_alert.py b/ambari-agent/src/main/python/ambari_agent/alerts/script_alert.py
new file mode 100644
index 0000000..93af917
--- /dev/null
+++ b/ambari-agent/src/main/python/ambari_agent/alerts/script_alert.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+'''
+
+import imp
+import logging
+import os
+from alerts.base_alert import BaseAlert
+
+logger = logging.getLogger()
+
+class ScriptAlert(BaseAlert):
+  def __init__(self, alert_meta, alert_source_meta):
+    ''' ScriptAlert reporting structure is output from the script itself '''
+    
+    alert_source_meta['reporting'] = {
+      'ok': { 'text': '{0}' },
+      'warning': { 'text': '{0}' },
+      'critical': { 'text': '{0}' },
+      'unknown': { 'text': '{0}' }
+    }
+    
+    super(ScriptAlert, self).__init__(alert_meta, alert_source_meta)
+    
+    self.path = None
+    if 'path' in alert_source_meta:
+      self.path = alert_source_meta['path']
+      
+    if 'stacks_dir' in alert_source_meta:
+      self.stacks_dir = alert_source_meta['stacks_dir']
+    
+  def _collect(self):
+    if self.path is None and self.stack_path is None:
+      raise Exception("The attribute 'path' must be specified")
+
+    path_to_script = self.path
+    if not os.path.exists(self.path) and self.stacks_dir is not None:
+      paths = self.path.split('/')
+      path_to_script = os.path.join(self.stacks_dir, *paths)
+      
+    if not os.path.exists(path_to_script) or not os.path.isfile(path_to_script):
+      raise Exception(
+        "Resolved script '{0}' does not appear to be a script".format(
+          path_to_script))
+
+    if logger.isEnabledFor(logging.DEBUG):
+      logger.debug("Executing script check {0}".format(path_to_script))
+
+          
+    if (path_to_script.endswith('.py')):
+      cmd_module = imp.load_source(self._find_value('name'), path_to_script)
+      return cmd_module.execute()
+    else:
+      return ((self.RESULT_UNKNOWN, ["could not execute script {0}".format(path_to_script)]))

http://git-wip-us.apache.org/repos/asf/ambari/blob/853497f8/ambari-agent/src/test/python/ambari_agent/TestAlerts.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/TestAlerts.py b/ambari-agent/src/test/python/ambari_agent/TestAlerts.py
index 6674fdf..5dc45b5 100644
--- a/ambari-agent/src/test/python/ambari_agent/TestAlerts.py
+++ b/ambari-agent/src/test/python/ambari_agent/TestAlerts.py
@@ -21,9 +21,11 @@ limitations under the License.
 import os
 import sys
 from ambari_agent.AlertSchedulerHandler import AlertSchedulerHandler
-from ambari_agent.apscheduler.scheduler import Scheduler
-from ambari_agent.alerts.port_alert import PortAlert
 from ambari_agent.alerts.collector import AlertCollector
+from ambari_agent.alerts.metric_alert import MetricAlert
+from ambari_agent.alerts.port_alert import PortAlert
+from ambari_agent.alerts.script_alert import ScriptAlert
+from ambari_agent.apscheduler.scheduler import Scheduler
 from mock.mock import patch
 from unittest import TestCase
 
@@ -39,8 +41,9 @@ class TestAlerts(TestCase):
   @patch.object(Scheduler, "start")
   def test_start(self, aps_add_interval_job_mock, aps_start_mock):
     test_file_path = os.path.join('ambari_agent', 'dummy_files')
+    test_stack_path = os.path.join('ambari_agent', 'dummy_files')
 
-    ash = AlertSchedulerHandler(test_file_path)
+    ash = AlertSchedulerHandler(test_file_path, test_stack_path)
     ash.start()
 
     self.assertTrue(aps_add_interval_job_mock.called)
@@ -75,8 +78,6 @@ class TestAlerts(TestCase):
     self.assertEquals(6, pa.interval())
 
     res = pa.collect()
-    
-    pass
 
   def test_port_alert_no_sub(self):
     json = { "name": "namenode_process",
@@ -105,5 +106,94 @@ class TestAlerts(TestCase):
     self.assertEquals('http://c6401.ambari.apache.org', pa.uri)
 
     res = pa.collect()
+
+  def test_script_alert(self):
+    json = {
+      "name": "namenode_process",
+      "service": "HDFS",
+      "component": "NAMENODE",
+      "label": "NameNode process",
+      "interval": 6,
+      "scope": "host",
+      "source": {
+        "type": "SCRIPT",
+        "path": "test_script.py",
+        "reporting": {
+          "ok": {
+            "text": "TCP OK - {0:.4f} response time on port {1}"
+          },
+          "critical": {
+            "text": "Could not load process info: {0}"
+          }
+        }
+      }
+    }
+
+    # normally set by AlertSchedulerHandler
+    json['source']['stacks_dir'] = os.path.join('ambari_agent', 'dummy_files')
+
+    collector = AlertCollector()
+    sa = ScriptAlert(json, json['source'])
+    sa.set_helpers(collector, '')
+    self.assertEquals(json['source']['path'], sa.path)
+    self.assertEquals(json['source']['stacks_dir'], sa.stacks_dir)
+
+    sa.collect()
+
+    self.assertEquals('WARNING', collector.alerts()[0]['state'])
+    self.assertEquals('all is not well', collector.alerts()[0]['text'])
+   
+  @patch.object(MetricAlert, "_load_jmx")
+  def test_metric_alert(self, ma_load_jmx_mock):
+    json = {
+      "name": "cpu_check",
+      "service": "HDFS",
+      "component": "NAMENODE",
+      "label": "NameNode process",
+      "interval": 6,
+      "scope": "host",
+      "source": {
+        "type": "METRIC",
+        "uri": "http://myurl:8633",
+        "jmx": {
+          "property_list": [
+            "someJmxObject/value",
+            "someOtherJmxObject/value"
+          ],
+          "value": "{0} * 100 + 123"
+        },
+        "reporting": {
+          "ok": {
+            "text": "ok_arr: {0} {1} {2}",
+          },
+          "warning": {
+            "text": "",
+            "value": 13
+          },
+          "critical": {
+            "text": "crit_arr: {0} {1} {2}",
+            "value": 72
+          }
+        }
+      }
+    }
+
+    ma_load_jmx_mock.return_value = [1, 3]
+
+    collector = AlertCollector()
+    ma = MetricAlert(json, json['source'])
+    ma.set_helpers(collector, '')
+    ma.collect()
+
+    self.assertEquals('CRITICAL', collector.alerts()[0]['state'])
+    self.assertEquals('crit_arr: 1 3 223', collector.alerts()[0]['text'])
+
+    del json['source']['jmx']['value']
+    collector = AlertCollector()
+    ma = MetricAlert(json, json['source'])
+    ma.set_helpers(collector, '')
+    ma.collect()
+
+    self.assertEquals('OK', collector.alerts()[0]['state'])
+    self.assertEquals('ok_arr: 1 3 None', collector.alerts()[0]['text'])
     
-    pass

http://git-wip-us.apache.org/repos/asf/ambari/blob/853497f8/ambari-agent/src/test/python/ambari_agent/dummy_files/definitions.json
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/dummy_files/definitions.json b/ambari-agent/src/test/python/ambari_agent/dummy_files/definitions.json
index 4894b62..ad52abc 100644
--- a/ambari-agent/src/test/python/ambari_agent/dummy_files/definitions.json
+++ b/ambari-agent/src/test/python/ambari_agent/dummy_files/definitions.json
@@ -10,16 +10,6 @@
     },
     "alertDefinitions": [
       {
-        "name": "namenode_cpu",
-        "label": "NameNode host CPU Utilization",
-        "scope": "host",
-        "source": {
-          "type": "METRIC",
-          "jmx": "java.lang:type=OperatingSystem/SystemCpuLoad",
-          "host": "{{hdfs-site/dfs.namenode.secondary.http-address}}"
-        }
-      },
-      {
         "name": "namenode_process",
         "service": "HDFS",
         "component": "NAMENODE",
@@ -39,17 +29,6 @@
             }
           }
         }
-      },
-      {
-        "name": "hdfs_last_checkpoint",
-        "label": "Last Checkpoint Time",
-        "interval": 1,
-        "scope": "service",
-        "enabled": false,
-        "source": {
-          "type": "SCRIPT",
-          "path": "scripts/alerts/last_checkpoint.py"
-        }
       }
     ]
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/853497f8/ambari-agent/src/test/python/ambari_agent/dummy_files/test_script.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/dummy_files/test_script.py b/ambari-agent/src/test/python/ambari_agent/dummy_files/test_script.py
new file mode 100644
index 0000000..211087c
--- /dev/null
+++ b/ambari-agent/src/test/python/ambari_agent/dummy_files/test_script.py
@@ -0,0 +1,3 @@
+
+def execute(params=None):
+  return (('WARNING', ['all is not well', str(params)]))

http://git-wip-us.apache.org/repos/asf/ambari/blob/853497f8/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertResourceProvider.java
index 639a02f..715d017 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertResourceProvider.java
@@ -167,12 +167,12 @@ public class AlertResourceProvider extends ReadOnlyResourceProvider {
     setResourceProperty(resource, ALERT_LATEST_TIMESTAMP, entity.getLatestTimestamp(), requestedIds);
     setResourceProperty(resource, ALERT_MAINTENANCE_STATE, entity.getMaintenanceState(), requestedIds);
     setResourceProperty(resource, ALERT_ORIGINAL_TIMESTAMP, entity.getOriginalTimestamp(), requestedIds);
+    setResourceProperty(resource, ALERT_TEXT, entity.getLatestText(), requestedIds);
     
     AlertHistoryEntity history = entity.getAlertHistory();
     setResourceProperty(resource, ALERT_INSTANCE, history.getAlertInstance(), requestedIds);
     setResourceProperty(resource, ALERT_LABEL, history.getAlertLabel(), requestedIds);
     setResourceProperty(resource, ALERT_STATE, history.getAlertState(), requestedIds);
-    setResourceProperty(resource, ALERT_TEXT, history.getAlertText(), requestedIds);
     setResourceProperty(resource, ALERT_COMPONENT, history.getComponentName(), requestedIds);
     setResourceProperty(resource, ALERT_HOST, history.getHostName(), requestedIds);
     setResourceProperty(resource, ALERT_SERVICE, history.getServiceName(), requestedIds);

http://git-wip-us.apache.org/repos/asf/ambari/blob/853497f8/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 438d471..d952ae7 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
@@ -90,6 +90,10 @@ public class AlertSummaryPropertyProvider extends BaseProvider implements Proper
     AlertSummaryDTO summary = null;
 
     String clusterName = (String) resource.getPropertyValue(m_clusterPropertyId);
+    
+    if (null == clusterName)
+      return;
+    
     String typeId = null == m_typeIdPropertyId ? null : (String) resource.getPropertyValue(m_typeIdPropertyId);
     Cluster cluster = s_clusters.getCluster(clusterName);
     

http://git-wip-us.apache.org/repos/asf/ambari/blob/853497f8/ambari-server/src/main/java/org/apache/ambari/server/state/alert/MetricSource.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/MetricSource.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/MetricSource.java
index 8bdd2ba..530c1bb 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/MetricSource.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/MetricSource.java
@@ -27,10 +27,11 @@ import com.google.gson.annotations.SerializedName;
  */
 public class MetricSource extends Source {
 
-  private String host = null;
-
+  @SerializedName("uri")
+  private String m_uri = null;
+  
   @SerializedName("jmx")
-  private String jmxInfo = null;
+  private Object jmxInfo = null;
 
   @SerializedName("ganglia")
   private String gangliaInfo = null;
@@ -38,7 +39,7 @@ public class MetricSource extends Source {
   /**
    * @return the jmx info, if this metric is jmx-based
    */
-  public String getJmxInfo() {
+  public Object getJmxInfo() {
     return jmxInfo;
   }
 
@@ -50,10 +51,10 @@ public class MetricSource extends Source {
   }
 
   /**
-   * @return the host info, which may include port information
+   * @return the uri info, which may include port information
    */
-  public String getHost() {
-    return host;
+  public String getUri() {
+    return m_uri;
   }
 
   /**
@@ -65,7 +66,7 @@ public class MetricSource extends Source {
     int result = super.hashCode();
     result = prime * result
         + ((gangliaInfo == null) ? 0 : gangliaInfo.hashCode());
-    result = prime * result + ((host == null) ? 0 : host.hashCode());
+    result = prime * result + ((m_uri == null) ? 0 : m_uri.hashCode());
     result = prime * result + ((jmxInfo == null) ? 0 : jmxInfo.hashCode());
 
     return result;
@@ -97,11 +98,11 @@ public class MetricSource extends Source {
       return false;
     }
 
-    if (host == null) {
-      if (other.host != null) {
+    if (m_uri == null) {
+      if (other.m_uri != null) {
         return false;
       }
-    } else if (!host.equals(other.host)) {
+    } else if (!m_uri.equals(other.m_uri)) {
       return false;
     }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/853497f8/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/AlertDataManager.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/AlertDataManager.java b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/AlertDataManager.java
index 4670d3b..4a65d5a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/AlertDataManager.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/AlertDataManager.java
@@ -68,6 +68,7 @@ public class AlertDataManager {
       
     } else if (alert.getState() == current.getAlertHistory().getAlertState()) {
       current.setLatestTimestamp(Long.valueOf(alert.getTimestamp()));
+      current.setLatestText(alert.getText());
       
       m_alertsDao.merge(current);
     } else {

http://git-wip-us.apache.org/repos/asf/ambari/blob/853497f8/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HDFS/alerts.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HDFS/alerts.json b/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HDFS/alerts.json
index 7f863a7..00286b1 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HDFS/alerts.json
+++ b/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HDFS/alerts.json
@@ -19,6 +19,36 @@
           }
         }        
       }
+    },
+    {
+      "name": "check_cpu",
+      "label": "NameNode host CPU utilization",
+      "interval": 2,
+      "scope": "any",
+      "source": {
+        "type": "METRIC",
+        "uri": "{{hdfs-site/dfs.namenode.http-address}}",
+        "reporting": {
+          "ok": {
+            "text": "{1} CPU, load {0:.1%}"
+          },
+          "warning": {
+            "text": "{1} CPU, load {0:.1%}",
+            "value": 200
+          },
+          "critical": {
+            "text": "{1} CPU, load {0:.1%}",
+            "value": 250
+          }
+        },
+        "jmx": {
+          "property_list": [
+            "java.lang:type=OperatingSystem/SystemCpuLoad",
+            "java.lang:type=OperatingSystem/AvailableProcessors"
+          ],
+          "value": "{0} * 100"
+        }
+      }
     }
   ],
   "SECONDARY_NAMENODE": [
@@ -84,4 +114,4 @@
       }
     }    
   ]
-}
\ No newline at end of file
+}


[44/50] [abbrv] git commit: Merge branch 'trunk' into branch-alerts-dev

Posted by jo...@apache.org.
Merge branch 'trunk' into branch-alerts-dev


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

Branch: refs/heads/trunk
Commit: 6f9398f0ff45da86c001eb86322695a3d76b7232
Parents: 054745d bd851c1
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Wed Oct 1 11:26:26 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Wed Oct 1 11:26:26 2014 -0400

----------------------------------------------------------------------
 .../resources/ui/admin-web/app/styles/main.css  |     2 +-
 .../src/main/python/ambari_agent/ActionQueue.py |     5 +-
 .../python/ambari_agent/ActualConfigHandler.py  |     5 +-
 .../test/python/ambari_agent/TestActionQueue.py |    55 +
 .../ambari_agent/TestActualConfigHandler.py     |    25 +-
 ambari-server/pom.xml                           |     2 +
 ambari-server/sbin/ambari-server                |     2 +-
 .../ambari/server/agent/ExecutionCommand.java   |     1 +
 .../server/api/util/StackExtensionHelper.java   |     6 +
 .../AmbariManagementControllerImpl.java         |    28 +
 .../ambari/server/state/ComponentInfo.java      |    21 +-
 .../server/upgrade/UpgradeCatalog170.java       |     2 +
 ambari-server/src/main/python/ambari-server.py  |   162 +-
 .../0.8/blueprints/multinode-default.json       |   182 +
 .../0.8/blueprints/singlenode-default.json      |   136 +
 .../BIGTOP/0.8/configuration/cluster-env.xml    |    56 +
 .../0.8/hooks/after-INSTALL/scripts/hook.py     |    35 +
 .../0.8/hooks/after-INSTALL/scripts/params.py   |    68 +
 .../scripts/shared_initialization.py            |    52 +
 .../BIGTOP/0.8/hooks/before-ANY/scripts/hook.py |    33 +
 .../0.8/hooks/before-ANY/scripts/params.py      |    33 +
 .../before-ANY/scripts/shared_initialization.py |    58 +
 .../before-INSTALL/files/changeToSecureUid.sh   |    50 +
 .../0.8/hooks/before-INSTALL/scripts/hook.py    |    39 +
 .../0.8/hooks/before-INSTALL/scripts/params.py  |   118 +
 .../scripts/repo_initialization.py              |    57 +
 .../scripts/shared_initialization.py            |    94 +
 .../before-INSTALL/templates/repo_suse_rhel.j2  |     7 +
 .../before-INSTALL/templates/repo_ubuntu.j2     |     1 +
 .../0.8/hooks/before-RESTART/scripts/hook.py    |    29 +
 .../hooks/before-START/files/checkForFormat.sh  |    62 +
 .../before-START/files/task-log4j.properties    |   134 +
 .../0.8/hooks/before-START/scripts/hook.py      |    38 +
 .../0.8/hooks/before-START/scripts/params.py    |   146 +
 .../scripts/shared_initialization.py            |   175 +
 .../templates/commons-logging.properties.j2     |    43 +
 .../templates/exclude_hosts_list.j2             |    21 +
 .../templates/hadoop-metrics2.properties.j2     |    65 +
 .../before-START/templates/health_check-v2.j2   |    81 +
 .../before-START/templates/health_check.j2      |   109 +
 .../templates/include_hosts_list.j2             |    21 +
 .../resources/stacks/BIGTOP/0.8/metainfo.xml    |    22 +
 .../stacks/BIGTOP/0.8/repos/repoinfo.xml        |    35 +
 .../stacks/BIGTOP/0.8/role_command_order.json   |    74 +
 .../services/FLUME/configuration/flume-conf.xml |    31 +
 .../services/FLUME/configuration/flume-env.xml  |    40 +
 .../FLUME/configuration/flume-log4j.xml         |    31 +
 .../BIGTOP/0.8/services/FLUME/metainfo.xml      |    69 +
 .../BIGTOP/0.8/services/FLUME/metrics.json      |   716 +
 .../0.8/services/FLUME/package/scripts/flume.py |   250 +
 .../FLUME/package/scripts/flume_check.py        |    40 +
 .../FLUME/package/scripts/flume_handler.py      |   121 +
 .../services/FLUME/package/scripts/params.py    |    60 +
 .../FLUME/package/templates/flume.conf.j2       |    24 +
 .../FLUME/package/templates/log4j.properties.j2 |    67 +
 .../GANGLIA/configuration/ganglia-env.xml       |    72 +
 .../BIGTOP/0.8/services/GANGLIA/metainfo.xml    |   127 +
 .../GANGLIA/package/files/checkGmetad.sh        |    37 +
 .../GANGLIA/package/files/checkGmond.sh         |    62 +
 .../GANGLIA/package/files/checkRrdcached.sh     |    34 +
 .../services/GANGLIA/package/files/gmetad.init  |    73 +
 .../services/GANGLIA/package/files/gmetadLib.sh |   204 +
 .../services/GANGLIA/package/files/gmond.init   |    73 +
 .../services/GANGLIA/package/files/gmondLib.sh  |   539 +
 .../GANGLIA/package/files/rrdcachedLib.sh       |    47 +
 .../GANGLIA/package/files/setupGanglia.sh       |   141 +
 .../GANGLIA/package/files/startGmetad.sh        |    68 +
 .../GANGLIA/package/files/startGmond.sh         |    85 +
 .../GANGLIA/package/files/startRrdcached.sh     |    79 +
 .../GANGLIA/package/files/stopGmetad.sh         |    43 +
 .../services/GANGLIA/package/files/stopGmond.sh |    54 +
 .../GANGLIA/package/files/stopRrdcached.sh      |    41 +
 .../GANGLIA/package/files/teardownGanglia.sh    |    28 +
 .../GANGLIA/package/scripts/functions.py        |    31 +
 .../services/GANGLIA/package/scripts/ganglia.py |    97 +
 .../GANGLIA/package/scripts/ganglia_monitor.py  |   236 +
 .../package/scripts/ganglia_monitor_service.py  |    27 +
 .../GANGLIA/package/scripts/ganglia_server.py   |   119 +
 .../package/scripts/ganglia_server_service.py   |    27 +
 .../services/GANGLIA/package/scripts/params.py  |   155 +
 .../GANGLIA/package/scripts/status_params.py    |    25 +
 .../GANGLIA/package/templates/ganglia.conf.j2   |    34 +
 .../package/templates/gangliaClusters.conf.j2   |    43 +
 .../GANGLIA/package/templates/gangliaEnv.sh.j2  |    46 +
 .../GANGLIA/package/templates/gangliaLib.sh.j2  |    85 +
 .../GANGLIA/package/templates/rrd.py.j2         |   361 +
 .../services/HBASE/configuration/hbase-env.xml  |   133 +
 .../HBASE/configuration/hbase-log4j.xml         |   143 +
 .../HBASE/configuration/hbase-policy.xml        |    53 +
 .../services/HBASE/configuration/hbase-site.xml |   370 +
 .../BIGTOP/0.8/services/HBASE/metainfo.xml      |   139 +
 .../BIGTOP/0.8/services/HBASE/metrics.json      | 13635 +++++++++++++++++
 .../HBASE/package/files/draining_servers.rb     |   164 +
 .../HBASE/package/files/hbaseSmokeVerify.sh     |    33 +
 .../services/HBASE/package/scripts/__init__.py  |    19 +
 .../services/HBASE/package/scripts/functions.py |    40 +
 .../0.8/services/HBASE/package/scripts/hbase.py |   144 +
 .../HBASE/package/scripts/hbase_client.py       |    43 +
 .../HBASE/package/scripts/hbase_decommission.py |    74 +
 .../HBASE/package/scripts/hbase_master.py       |    70 +
 .../HBASE/package/scripts/hbase_regionserver.py |    66 +
 .../HBASE/package/scripts/hbase_service.py      |    51 +
 .../services/HBASE/package/scripts/params.py    |   123 +
 .../HBASE/package/scripts/service_check.py      |    79 +
 .../HBASE/package/scripts/status_params.py      |    26 +
 ...-metrics2-hbase.properties-GANGLIA-MASTER.j2 |    81 +
 ...doop-metrics2-hbase.properties-GANGLIA-RS.j2 |    80 +
 .../HBASE/package/templates/hbase-smoke.sh.j2   |    44 +
 .../package/templates/hbase_client_jaas.conf.j2 |    23 +
 .../templates/hbase_grant_permissions.j2        |    39 +
 .../package/templates/hbase_master_jaas.conf.j2 |    26 +
 .../templates/hbase_regionserver_jaas.conf.j2   |    26 +
 .../HBASE/package/templates/regionservers.j2    |    20 +
 .../services/HDFS/configuration/core-site.xml   |   180 +
 .../services/HDFS/configuration/hadoop-env.xml  |   198 +
 .../HDFS/configuration/hadoop-policy.xml        |   134 +
 .../services/HDFS/configuration/hdfs-log4j.xml  |   201 +
 .../services/HDFS/configuration/hdfs-site.xml   |   496 +
 .../BIGTOP/0.8/services/HDFS/metainfo.xml       |   225 +
 .../BIGTOP/0.8/services/HDFS/metrics.json       |  7840 ++++++++++
 .../HDFS/package/files/checkForFormat.sh        |    68 +
 .../services/HDFS/package/files/checkWebUI.py   |    53 +
 .../scripts/balancer-emulator/balancer-err.log  |  1032 ++
 .../scripts/balancer-emulator/balancer.log      |    29 +
 .../scripts/balancer-emulator/hdfs-command.py   |    45 +
 .../services/HDFS/package/scripts/datanode.py   |    59 +
 .../0.8/services/HDFS/package/scripts/hdfs.py   |    64 +
 .../HDFS/package/scripts/hdfs_client.py         |    53 +
 .../HDFS/package/scripts/hdfs_datanode.py       |    47 +
 .../HDFS/package/scripts/hdfs_namenode.py       |   157 +
 .../HDFS/package/scripts/hdfs_rebalance.py      |   130 +
 .../HDFS/package/scripts/hdfs_snamenode.py      |    45 +
 .../HDFS/package/scripts/journalnode.py         |    73 +
 .../services/HDFS/package/scripts/namenode.py   |   134 +
 .../0.8/services/HDFS/package/scripts/params.py |   213 +
 .../HDFS/package/scripts/service_check.py       |   111 +
 .../services/HDFS/package/scripts/snamenode.py  |    65 +
 .../HDFS/package/scripts/status_params.py       |    31 +
 .../0.8/services/HDFS/package/scripts/utils.py  |    66 +
 .../services/HDFS/package/scripts/zkfc_slave.py |    64 +
 .../package/templates/exclude_hosts_list.j2     |    21 +
 .../HDFS/package/templates/hdfs.conf.j2         |    35 +
 .../services/HDFS/package/templates/slaves.j2   |    21 +
 .../services/HIVE/configuration/hive-env.xml    |   134 +
 .../HIVE/configuration/hive-exec-log4j.xml      |   111 +
 .../services/HIVE/configuration/hive-log4j.xml  |   120 +
 .../services/HIVE/configuration/hive-site.xml   |   314 +
 .../HIVE/etc/hive-schema-0.12.0.mysql.sql       |   777 +
 .../HIVE/etc/hive-schema-0.12.0.oracle.sql      |   718 +
 .../HIVE/etc/hive-schema-0.12.0.postgres.sql    |  1406 ++
 .../BIGTOP/0.8/services/HIVE/metainfo.xml       |   271 +
 .../services/HIVE/package/files/addMysqlUser.sh |    41 +
 .../HIVE/package/files/addPostgreSQLUser.sh     |    44 +
 .../services/HIVE/package/files/hcatSmoke.sh    |    36 +
 .../services/HIVE/package/files/hiveSmoke.sh    |    24 +
 .../services/HIVE/package/files/hiveserver2.sql |    23 +
 .../HIVE/package/files/hiveserver2Smoke.sh      |    32 +
 .../0.8/services/HIVE/package/files/pigSmoke.sh |    18 +
 .../HIVE/package/files/startMetastore.sh        |    23 +
 .../services/HIVE/package/scripts/__init__.py   |    19 +
 .../0.8/services/HIVE/package/scripts/hcat.py   |    55 +
 .../HIVE/package/scripts/hcat_client.py         |    43 +
 .../HIVE/package/scripts/hcat_service_check.py  |    78 +
 .../0.8/services/HIVE/package/scripts/hive.py   |   213 +
 .../HIVE/package/scripts/hive_client.py         |    42 +
 .../HIVE/package/scripts/hive_metastore.py      |    64 +
 .../HIVE/package/scripts/hive_server.py         |    66 +
 .../HIVE/package/scripts/hive_service.py        |   110 +
 .../HIVE/package/scripts/install_jars.py        |    99 +
 .../HIVE/package/scripts/mysql_server.py        |    70 +
 .../HIVE/package/scripts/mysql_service.py       |    46 +
 .../0.8/services/HIVE/package/scripts/params.py |   215 +
 .../HIVE/package/scripts/postgresql_server.py   |   109 +
 .../HIVE/package/scripts/postgresql_service.py  |    39 +
 .../HIVE/package/scripts/service_check.py       |    47 +
 .../HIVE/package/scripts/status_params.py       |    37 +
 .../HIVE/package/templates/hcat-env.sh.j2       |    43 +
 .../package/templates/startHiveserver2.sh.j2    |    29 +
 .../NAGIOS/configuration/nagios-env.xml         |    53 +
 .../BIGTOP/0.8/services/NAGIOS/metainfo.xml     |   160 +
 .../NAGIOS/package/files/check_aggregate.php    |   248 +
 .../NAGIOS/package/files/check_ambari_alerts.py |    80 +
 .../package/files/check_checkpoint_time.py      |   112 +
 .../services/NAGIOS/package/files/check_cpu.php |   109 +
 .../services/NAGIOS/package/files/check_cpu.pl  |   114 +
 .../NAGIOS/package/files/check_cpu_ha.php       |   116 +
 .../package/files/check_datanode_storage.php    |   100 +
 .../NAGIOS/package/files/check_hdfs_blocks.php  |   102 +
 .../package/files/check_hdfs_capacity.php       |   109 +
 .../files/check_hive_metastore_status.sh        |    45 +
 .../NAGIOS/package/files/check_hue_status.sh    |    31 +
 .../files/check_mapred_local_dir_used.sh        |    34 +
 .../package/files/check_name_dir_status.php     |    93 +
 .../NAGIOS/package/files/check_namenodes_ha.sh  |    83 +
 .../package/files/check_nodemanager_health.sh   |    45 +
 .../NAGIOS/package/files/check_oozie_status.sh  |    45 +
 .../NAGIOS/package/files/check_rpcq_latency.php |   104 +
 .../package/files/check_rpcq_latency_ha.php     |   115 +
 .../package/files/check_templeton_status.sh     |    46 +
 .../NAGIOS/package/files/check_webui.sh         |   103 +
 .../NAGIOS/package/files/check_webui_ha.sh      |    64 +
 .../NAGIOS/package/files/check_wrapper.sh       |    94 +
 .../package/files/hdp_mon_nagios_addons.conf    |    24 +
 .../NAGIOS/package/files/hdp_nagios_init.php    |    81 +
 .../NAGIOS/package/files/nagios_alerts.php      |   513 +
 .../services/NAGIOS/package/files/sys_logger.py |   186 +
 .../NAGIOS/package/scripts/functions.py         |    47 +
 .../services/NAGIOS/package/scripts/nagios.py   |   112 +
 .../NAGIOS/package/scripts/nagios_server.py     |   111 +
 .../package/scripts/nagios_server_config.py     |    98 +
 .../NAGIOS/package/scripts/nagios_service.py    |   103 +
 .../services/NAGIOS/package/scripts/params.py   |   287 +
 .../NAGIOS/package/scripts/status_params.py     |    29 +
 .../NAGIOS/package/templates/contacts.cfg.j2    |   109 +
 .../package/templates/hadoop-commands.cfg.j2    |   166 +
 .../package/templates/hadoop-hostgroups.cfg.j2  |    33 +
 .../package/templates/hadoop-hosts.cfg.j2       |    53 +
 .../templates/hadoop-servicegroups.cfg.j2       |   119 +
 .../package/templates/hadoop-services.cfg.j2    |   804 +
 .../NAGIOS/package/templates/nagios.cfg.j2      |  1365 ++
 .../NAGIOS/package/templates/nagios.conf.j2     |    84 +
 .../services/NAGIOS/package/templates/nagios.j2 |   164 +
 .../NAGIOS/package/templates/resource.cfg.j2    |    51 +
 .../services/OOZIE/configuration/oozie-env.xml  |   129 +
 .../OOZIE/configuration/oozie-log4j.xml         |    97 +
 .../services/OOZIE/configuration/oozie-site.xml |   312 +
 .../BIGTOP/0.8/services/OOZIE/metainfo.xml      |   165 +
 .../services/OOZIE/package/files/oozieSmoke2.sh |   107 +
 .../OOZIE/package/files/wrap_ooziedb.sh         |    31 +
 .../0.8/services/OOZIE/package/scripts/oozie.py |   152 +
 .../OOZIE/package/scripts/oozie_client.py       |    43 +
 .../OOZIE/package/scripts/oozie_server.py       |    56 +
 .../OOZIE/package/scripts/oozie_service.py      |    75 +
 .../services/OOZIE/package/scripts/params.py    |   121 +
 .../OOZIE/package/scripts/service_check.py      |    59 +
 .../OOZIE/package/scripts/status_params.py      |    26 +
 .../package/templates/oozie-log4j.properties.j2 |    92 +
 .../0.8/services/PIG/configuration/pig-env.xml  |    38 +
 .../services/PIG/configuration/pig-log4j.xml    |    62 +
 .../PIG/configuration/pig-properties.xml        |    92 +
 .../stacks/BIGTOP/0.8/services/PIG/metainfo.xml |    85 +
 .../0.8/services/PIG/package/files/pigSmoke.sh  |    18 +
 .../0.8/services/PIG/package/scripts/params.py  |    45 +
 .../0.8/services/PIG/package/scripts/pig.py     |    58 +
 .../services/PIG/package/scripts/pig_client.py  |    41 +
 .../PIG/package/scripts/service_check.py        |    67 +
 .../services/SQOOP/configuration/sqoop-env.xml  |    54 +
 .../BIGTOP/0.8/services/SQOOP/metainfo.xml      |    92 +
 .../services/SQOOP/package/scripts/__init__.py  |    19 +
 .../services/SQOOP/package/scripts/params.py    |    37 +
 .../SQOOP/package/scripts/service_check.py      |    37 +
 .../0.8/services/SQOOP/package/scripts/sqoop.py |    57 +
 .../SQOOP/package/scripts/sqoop_client.py       |    41 +
 .../WEBHCAT/configuration/webhcat-env.xml       |    54 +
 .../WEBHCAT/configuration/webhcat-site.xml      |   138 +
 .../BIGTOP/0.8/services/WEBHCAT/metainfo.xml    |   107 +
 .../WEBHCAT/package/files/templetonSmoke.sh     |    96 +
 .../WEBHCAT/package/scripts/__init__.py         |    20 +
 .../services/WEBHCAT/package/scripts/params.py  |    83 +
 .../WEBHCAT/package/scripts/service_check.py    |    45 +
 .../WEBHCAT/package/scripts/status_params.py    |    26 +
 .../services/WEBHCAT/package/scripts/webhcat.py |    93 +
 .../WEBHCAT/package/scripts/webhcat_server.py   |    53 +
 .../WEBHCAT/package/scripts/webhcat_service.py  |    40 +
 .../YARN/configuration-mapred/mapred-env.xml    |    65 +
 .../YARN/configuration-mapred/mapred-site.xml   |   366 +
 .../YARN/configuration/capacity-scheduler.xml   |   124 +
 .../services/YARN/configuration/yarn-env.xml    |   184 +
 .../services/YARN/configuration/yarn-log4j.xml  |    71 +
 .../services/YARN/configuration/yarn-site.xml   |   413 +
 .../BIGTOP/0.8/services/YARN/metainfo.xml       |   250 +
 .../BIGTOP/0.8/services/YARN/metrics.json       |  5360 +++++++
 .../files/validateYarnComponentStatus.py        |   170 +
 .../services/YARN/package/scripts/__init__.py   |    20 +
 .../scripts/application_timeline_server.py      |    55 +
 .../YARN/package/scripts/historyserver.py       |    53 +
 .../package/scripts/mapred_service_check.py     |    76 +
 .../YARN/package/scripts/mapreduce2_client.py   |    42 +
 .../YARN/package/scripts/nodemanager.py         |    59 +
 .../0.8/services/YARN/package/scripts/params.py |   157 +
 .../YARN/package/scripts/resourcemanager.py     |   100 +
 .../services/YARN/package/scripts/service.py    |    75 +
 .../YARN/package/scripts/service_check.py       |    67 +
 .../YARN/package/scripts/status_params.py       |    35 +
 .../0.8/services/YARN/package/scripts/yarn.py   |   231 +
 .../YARN/package/scripts/yarn_client.py         |    42 +
 .../package/templates/container-executor.cfg.j2 |    40 +
 .../package/templates/exclude_hosts_list.j2     |    21 +
 .../YARN/package/templates/mapreduce.conf.j2    |    35 +
 .../package/templates/taskcontroller.cfg.j2     |    38 +
 .../YARN/package/templates/yarn.conf.j2         |    35 +
 .../ZOOKEEPER/configuration/zookeeper-env.xml   |    84 +
 .../ZOOKEEPER/configuration/zookeeper-log4j.xml |   101 +
 .../BIGTOP/0.8/services/ZOOKEEPER/metainfo.xml  |    89 +
 .../services/ZOOKEEPER/package/files/zkEnv.sh   |    96 +
 .../ZOOKEEPER/package/files/zkServer.sh         |   120 +
 .../ZOOKEEPER/package/files/zkService.sh        |    26 +
 .../services/ZOOKEEPER/package/files/zkSmoke.sh |    78 +
 .../ZOOKEEPER/package/scripts/__init__.py       |    20 +
 .../ZOOKEEPER/package/scripts/params.py         |    76 +
 .../ZOOKEEPER/package/scripts/service_check.py  |    46 +
 .../ZOOKEEPER/package/scripts/status_params.py  |    26 +
 .../ZOOKEEPER/package/scripts/zookeeper.py      |   110 +
 .../package/scripts/zookeeper_client.py         |    42 +
 .../package/scripts/zookeeper_server.py         |    54 +
 .../package/scripts/zookeeper_service.py        |    42 +
 .../package/templates/configuration.xsl.j2      |    42 +
 .../ZOOKEEPER/package/templates/zoo.cfg.j2      |    69 +
 .../templates/zookeeper_client_jaas.conf.j2     |    24 +
 .../package/templates/zookeeper_jaas.conf.j2    |    26 +
 .../stacks/BIGTOP/0.8/services/stack_advisor.py |   439 +
 .../stacks/HDP/1.3.2.GlusterFS/metainfo.xml     |    23 -
 .../HDP/1.3.2.GlusterFS/repos/repoinfo.xml      |    40 -
 .../GLUSTERFS/configuration/core-site.xml       |   277 -
 .../GLUSTERFS/configuration/hadoop-policy.xml   |   134 -
 .../GLUSTERFS/configuration/hdfs-site.xml       |   408 -
 .../services/GLUSTERFS/metainfo.xml             |    58 -
 .../GLUSTERFS/package/scripts/glusterfs.py      |    29 -
 .../package/scripts/glusterfs_client.py         |    34 -
 .../GLUSTERFS/package/scripts/params.py         |    29 -
 .../GLUSTERFS/package/scripts/service_check.py  |    37 -
 .../package/templates/glusterfs-env.sh.j2       |    18 -
 .../package/templates/glusterfs.properties.j2   |    36 -
 .../services/HDFS/configuration/core-site.xml   |   253 -
 .../services/HDFS/configuration/global.xml      |   187 -
 .../HDFS/configuration/hadoop-policy.xml        |   134 -
 .../services/HDFS/configuration/hdfs-site.xml   |   439 -
 .../1.3.2.GlusterFS/services/HDFS/metainfo.xml  |    27 -
 .../stacks/HDP/1.3.2/services/HIVE/metainfo.xml |     6 +
 .../1.3.2/services/HIVE/package/scripts/hive.py |    36 +-
 .../package/templates/hadoop-services.cfg.j2    |     2 +
 .../services/HBASE/package/scripts/params.py    |     2 +-
 .../stacks/HDP/2.0.6/services/HIVE/metainfo.xml |     6 +
 .../2.0.6/services/HIVE/package/scripts/hive.py |    31 +-
 .../services/YARN/package/scripts/params.py     |    12 +-
 .../services/STORM/package/scripts/params.py    |    17 +-
 .../2.1/services/STORM/package/scripts/storm.py |    19 +-
 .../STORM/package/scripts/supervisor.py         |     1 -
 .../STORM/package/scripts/yaml_config.py        |    72 -
 .../STORM/package/scripts/yaml_utils.py         |    49 +
 .../STORM/package/templates/storm.yaml.j2       |    60 +
 .../STORM/package/templates/storm_jaas.conf.j2  |    22 +-
 .../stacks/HDP/2.2/services/SLIDER/metainfo.xml |     2 +-
 .../services/SLIDER/package/scripts/params.py   |     9 +-
 .../services/STORM/configuration/storm-site.xml |    38 +-
 .../src/main/resources/stacks/stack_advisor.py  |    17 +-
 .../AmbariManagementControllerTest.java         |     1 +
 .../src/test/python/TestAmbariServer.py         |    54 +
 .../src/test/python/TestStackAdvisor.py         |     9 +-
 .../stacks/1.3.2/HIVE/test_hive_client.py       |    58 +-
 .../stacks/1.3.2/HIVE/test_hive_metastore.py    |    46 +-
 .../stacks/1.3.2/HIVE/test_hive_server.py       |    50 +-
 .../stacks/2.0.6/HIVE/test_hive_client.py       |    78 +-
 .../stacks/2.0.6/HIVE/test_hive_metastore.py    |    80 +-
 .../stacks/2.0.6/HIVE/test_hive_server.py       |    80 +-
 .../stacks/2.1/HIVE/test_hive_metastore.py      |    80 +-
 .../python/stacks/2.1/STORM/test_storm_base.py  |   119 +
 .../stacks/2.1/STORM/test_storm_drpc_server.py  |    90 +-
 .../2.1/STORM/test_storm_jaas_configuration.py  |    77 +
 .../stacks/2.1/STORM/test_storm_nimbus.py       |   105 +-
 .../stacks/2.1/STORM/test_storm_nimbus_prod.py  |    89 +-
 .../2.1/STORM/test_storm_rest_api_service.py    |    87 +-
 .../stacks/2.1/STORM/test_storm_supervisor.py   |    42 +-
 .../2.1/STORM/test_storm_supervisor_prod.py     |    86 +-
 .../stacks/2.1/STORM/test_storm_ui_server.py    |    93 +-
 .../test/python/stacks/2.1/common/hosts.json    |   554 +
 .../test/python/stacks/2.1/common/services.json |  1036 ++
 .../stacks/2.1/common/test_stack_advisor.py     |    41 +-
 .../stacks/2.1/configs/default-storm-start.json |   356 +
 .../stacks/2.1/configs/secured-storm-start.json |   373 +
 .../stacks/2.2/SLIDER/test_slider_client.py     |     8 +-
 .../stacks/HDP/2.0.5/services/HIVE/metainfo.xml |     5 +
 .../stacks/HDP/2.0.7/services/HIVE/metainfo.xml |     3 +
 ambari-web/app/app.js                           |     7 +-
 ambari-web/app/assets/test/test.html            |     1 +
 ambari-web/app/assets/test/tests.js             |     2 -
 ambari-web/app/controllers/application.js       |     4 +
 .../app/controllers/main/admin/repositories.js  |     8 +-
 .../main/admin/security/add/step2.js            |    37 +-
 .../main/admin/security/add/step3.js            |   156 +-
 .../controllers/main/service/info/configs.js    |     8 +-
 .../app/controllers/main/views_controller.js    |     2 +-
 ambari-web/app/data/HDP2.2/site_properties.js   |    29 +
 ambari-web/app/data/HDP2/secure_configs.js      |    16 +-
 ambari-web/app/data/HDP2/secure_properties.js   |   207 +-
 ambari-web/app/data/HDP2/site_properties.js     |    41 +-
 ambari-web/app/messages.js                      |     1 +
 .../app/mixins/wizard/addSecurityConfigs.js     |    35 +-
 ambari-web/app/models/stack_service.js          |    24 +-
 ambari-web/app/router.js                        |    13 +
 ambari-web/app/routes/main.js                   |     3 +-
 ambari-web/app/templates/application.hbs        |     2 +-
 ambari-web/app/utils/config.js                  |    34 +-
 ambari-web/app/utils/string_utils.js            |     4 +-
 ambari-web/app/views/main/menu.js               |    12 +-
 .../main/admin/security/add/step2_test.js       |     4 +-
 .../main/admin/security/add/step3_test.js       |    66 +-
 .../main/admin/security/add/step4_test.js       |    15 +-
 .../test/controllers/main/host/details_test.js  |    25 +-
 .../test/controllers/wizard/step3_test.js       |     4 +-
 .../test/controllers/wizard/step7_test.js       |     3 +
 ambari-web/test/utils/ajax/ajax_test.js         |    11 +-
 ambari-web/test/utils/string_utils_test.js      |     2 +-
 .../widgets/uptime_text_widget_test.js          |    12 +-
 contrib/views/pom.xml                           |     2 +-
 contrib/views/slider/docs/index.md              |     2 +-
 .../view/slider/SliderAppsViewController.java   |    12 +-
 .../assets/data/resource/slider-properties.json |    12 +-
 .../ui/app/assets/javascripts/ember-qunit.js    |   266 +
 .../ui/app/assets/javascripts/qunit.js          |  2495 +++
 .../ui/app/assets/javascripts/tests.js          |    29 +
 .../ui/app/assets/stylesheets/qunit.css         |   237 +
 .../src/main/resources/ui/app/assets/tests.html |    43 +
 .../src/main/resources/ui/app/config/app.js     |     3 +-
 .../ui/app/controllers/slider_app_controller.js |     2 +-
 .../ui/app/controllers/slider_controller.js     |     2 +-
 .../src/main/resources/ui/app/helpers/ajax.js   |     8 +-
 .../src/main/resources/ui/app/helpers/helper.js |    17 +-
 .../src/main/resources/ui/app/initialize.js     |    10 +-
 .../ui/app/mappers/slider_apps_mapper.js        |     2 +-
 .../main/resources/ui/app/models/slider_app.js  |     3 -
 .../src/main/resources/ui/app/routes/main.js    |    17 +-
 .../src/main/resources/ui/app/styles/app.less   |     4 +-
 .../ui/app/templates/slider_app/configs.hbs     |    32 +-
 .../ui/app/templates/slider_app/flex_popup.hbs  |    25 +-
 .../src/main/resources/ui/app/translations.js   |     4 +-
 .../resources/ui/app/views/common/chart_view.js |     6 +-
 .../ui/app/views/slider_app/configs_view.js     |     7 +-
 .../views/slider_app/metrics/app_metric_view.js |     6 +-
 .../slider/src/main/resources/ui/config.js      |     3 +-
 .../ui/test/demo/demo_integration_test.js       |    24 -
 .../resources/ui/test/demo/demo_unit_test.js    |    21 -
 .../src/main/resources/ui/test/helpers.js       |    34 -
 .../ui/test/integration/pages/index_test.js     |    61 +
 .../createAppWizard/step1_controller_test.js    |    39 +
 .../unit/models/slider_app_component_test.js    |    51 +
 .../ui/test/unit/models/slider_app_test.js      |    93 +
 .../views/slider/src/main/resources/view.xml    |    33 +-
 pom.xml                                         |     8 +-
 439 files changed, 66680 insertions(+), 3668 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/6f9398f0/ambari-server/pom.xml
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/6f9398f0/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/6f9398f0/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/6f9398f0/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
----------------------------------------------------------------------


[31/50] [abbrv] git commit: Merge branch 'trunk' into branch-alerts-dev

Posted by jo...@apache.org.
Merge branch 'trunk' into branch-alerts-dev

Conflicts:
	ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java


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

Branch: refs/heads/trunk
Commit: 7f86e75c0c1e4868973340197b7cab112a319cb1
Parents: e2e7966 327accb
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Sat Sep 20 10:54:04 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Sat Sep 20 10:54:04 2014 -0400

----------------------------------------------------------------------
 .../main/resources/ui/admin-web/app/index.html  |    1 -
 .../app/scripts/controllers/NavbarCtrl.js       |   22 +-
 .../ui/admin-web/app/scripts/services/ldap.js   |   60 -
 .../resources/ui/admin-web/app/styles/main.css  |   10 +-
 .../ui/admin-web/app/views/leftNavbar.html      |    9 -
 ambari-server/sbin/ambari-server                |    4 +
 .../LdapSyncEventResourceDefinition.java        |   57 +
 .../resources/ResourceInstanceFactoryImpl.java  |    4 +
 .../api/services/LdapSyncEventService.java      |  144 ++
 .../controller/AmbariManagementController.java  |   10 +-
 .../AmbariManagementControllerImpl.java         |   31 +-
 .../internal/ControllerResourceProvider.java    |   53 +-
 .../internal/DefaultProviderModule.java         |    2 +
 .../internal/LdapSyncEventResourceProvider.java |  438 ++++++
 .../controller/internal/URLStreamProvider.java  |    4 +
 .../ambari/server/controller/spi/Resource.java  |    4 +-
 .../orm/entities/LdapSyncEventEntity.java       |  284 ++++
 .../server/orm/entities/LdapSyncSpecEntity.java |  143 ++
 .../ambari/server/proxy/ProxyService.java       |   17 +-
 .../server/security/authorization/Users.java    |   17 +-
 .../security/ldap/AmbariLdapDataPopulator.java  |  268 +++-
 .../ambari/server/state/ConfigHelper.java       |   39 +
 .../server/state/stack/LatestRepoCallable.java  |   59 +-
 .../server/upgrade/AbstractUpgradeCatalog.java  |  215 ++-
 .../server/upgrade/UpgradeCatalog161.java       |    2 +-
 .../server/upgrade/UpgradeCatalog170.java       |   27 +-
 .../server/view/HttpImpersonatorImpl.java       |  167 +++
 .../server/view/ImpersonatorSettingImpl.java    |   63 +
 .../ambari/server/view/ViewContextImpl.java     |   18 +-
 .../ambari/server/view/ViewProviderModule.java  |   26 +-
 .../apache/ambari/server/view/ViewRegistry.java |   22 +-
 ambari-server/src/main/python/ambari-server.py  |   74 +
 .../scripts/application_timeline_server.py      |    2 +
 .../YARN/package/scripts/status_params.py       |    1 +
 .../services/SLIDER/package/scripts/params.py   |    4 +-
 .../services/SLIDER/package/scripts/slider.py   |   22 +-
 .../SLIDER/package/templates/slider-env.sh.j2   |   38 +
 .../SLIDER/package/templates/slider-wrapper.j2  |   42 -
 .../LdapSyncEventResourceDefinitionTest.java    |   49 +
 .../server/api/services/AmbariMetaInfoTest.java |  205 ++-
 .../api/services/LdapSyncEventServiceTest.java  |   97 ++
 .../LdapSyncEventResourceProviderTest.java      |  114 ++
 .../orm/entities/LdapSyncEventEntityTest.java   |  166 +++
 .../orm/entities/LdapSyncSpecEntityTest.java    |   95 ++
 .../ambari/server/proxy/ProxyServiceTest.java   |   14 +
 .../ldap/AmbariLdapDataPopulatorTest.java       | 1329 +++++++++++++++++-
 .../security/ldap/LdapPerformanceTest.java      |   10 +-
 .../server/upgrade/UpgradeCatalog161Test.java   |    2 +-
 .../server/upgrade/UpgradeCatalog170Test.java   |   35 +-
 .../server/view/HttpImpersonatorImplTest.java   |  128 ++
 .../ambari/server/view/ViewRegistryTest.java    |   20 +
 .../stacks/2.2/SLIDER/test_slider_client.py     |   29 +-
 .../apache/ambari/view/HttpImpersonator.java    |   53 +
 .../apache/ambari/view/ImpersonatorSetting.java |   46 +
 .../org/apache/ambari/view/ViewContext.java     |   15 +
 ambari-web/app/utils/ajax/ajax.js               |   22 -
 contrib/views/jobs/pom.xml                      |   15 +
 .../apache/ambari/view/jobs/ProxyServlet.java   |   68 +
 .../jobs/src/main/resources/WEB-INF/web.xml     |   37 +
 .../app/scripts/controllers/jobs_controller.js  |   10 +-
 .../resources/ui/app/scripts/helpers/ajax.js    |   25 +-
 .../resources/ui/app/scripts/helpers/jobs.js    |   15 +-
 .../ui/app/scripts/routes/application_route.js  |    8 +
 .../ui/app/controllers/slider_app_controller.js |    2 +-
 .../ui/app/mappers/slider_apps_mapper.js        |    9 +
 .../main/resources/ui/app/models/slider_app.js  |    5 +
 .../resources/ui/app/styles/application.less    |    6 +-
 .../ui/app/templates/slider_app/summary.hbs     |    2 +-
 .../resources/ui/app/templates/slider_apps.hbs  |    2 +-
 69 files changed, 4458 insertions(+), 578 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/7f86e75c/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/7f86e75c/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/7f86e75c/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/7f86e75c/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
----------------------------------------------------------------------
diff --cc ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
index 23d0efa,b08ccc0..4c59a36
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
@@@ -30,11 -27,8 +27,9 @@@ import static org.junit.Assert.fail
  
  import java.io.File;
  import java.lang.reflect.Method;
- import java.util.ArrayList;
  import java.util.Collection;
- import java.util.HashMap;
  import java.util.HashSet;
 +import java.util.Iterator;
  import java.util.LinkedList;
  import java.util.List;
  import java.util.ListIterator;
@@@ -61,20 -53,14 +54,16 @@@ import org.apache.ambari.server.state.D
  import org.apache.ambari.server.state.OperatingSystemInfo;
  import org.apache.ambari.server.state.PropertyInfo;
  import org.apache.ambari.server.state.RepositoryInfo;
- import org.apache.ambari.server.state.Service;
  import org.apache.ambari.server.state.ServiceInfo;
  import org.apache.ambari.server.state.Stack;
- import org.apache.ambari.server.state.StackId;
  import org.apache.ambari.server.state.StackInfo;
  import org.apache.ambari.server.state.alert.AlertDefinition;
- import org.apache.ambari.server.state.alert.AlertDefinitionFactory;
 +import org.apache.ambari.server.state.alert.PortSource;
 +import org.apache.ambari.server.state.alert.Reporting;
 +import org.apache.ambari.server.state.alert.Source;
  import org.apache.ambari.server.state.stack.MetricDefinition;
  import org.apache.commons.io.FileUtils;
- import org.easymock.EasyMock;
  import org.junit.Before;
 -import org.junit.Ignore;
  import org.junit.Rule;
  import org.junit.Test;
  import org.junit.rules.TemporaryFolder;
@@@ -124,9 -109,9 +113,12 @@@ public class AmbariMetaInfoTest 
  
    @Before
    public void before() throws Exception {
 -    injector = Guice.createInjector(new InMemoryDefaultTestModule());
 +    injector = Guice.createInjector(Modules.override(
 +        new InMemoryDefaultTestModule()).with(new MockModule()));
 +
+     injector.getInstance(GuiceJpaInitializer.class);
+     injector.getInstance(EntityManager.class);
++
      File stackRoot = new File("src/test/resources/stacks");
      LOG.info("Stacks file " + stackRoot.getAbsolutePath());
      metaInfo = new AmbariMetaInfo(stackRoot, new File("target/version"));
@@@ -1450,109 -1559,17 +1566,66 @@@
      Assert.assertNotNull(set);
      Assert.assertTrue(set.size() > 0);
  
 +    // find two different definitions and test each one
 +    AlertDefinition nameNodeProcess = null;
 +    AlertDefinition nameNodeCpu = null;
 +
 +    Iterator<AlertDefinition> iterator = set.iterator();
 +    while (iterator.hasNext()) {
 +      AlertDefinition definition = iterator.next();
 +      if (definition.getName().equals("namenode_process")) {
 +        nameNodeProcess = definition;
 +      }
 +
 +      if (definition.getName().equals("namenode_cpu")) {
 +        nameNodeCpu = definition;
 +      }
 +    }
 +
 +    assertNotNull(nameNodeProcess);
 +    assertNotNull(nameNodeCpu);
 +
 +    assertEquals("NameNode host CPU Utilization", nameNodeCpu.getLabel());
 +
 +    // test namenode_process
 +    Source source = nameNodeProcess.getSource();
 +    assertNotNull(source);
 +    assertNotNull(((PortSource) source).getPort());
 +    Reporting reporting = source.getReporting();
 +    assertNotNull(reporting);
 +    assertNotNull(reporting.getOk());
 +    assertNotNull(reporting.getOk().getText());
 +    assertNull(reporting.getOk().getValue());
 +    assertNotNull(reporting.getCritical());
 +    assertNotNull(reporting.getCritical().getText());
 +    assertNull(reporting.getCritical().getValue());
 +    assertNull(reporting.getWarning());
 +
 +    // test namenode_cpu
 +    source = nameNodeCpu.getSource();
 +    assertNotNull(source);
 +    reporting = source.getReporting();
 +    assertNotNull(reporting);
 +    assertNotNull(reporting.getOk());
 +    assertNotNull(reporting.getOk().getText());
 +    assertNull(reporting.getOk().getValue());
 +    assertNotNull(reporting.getCritical());
 +    assertNotNull(reporting.getCritical().getText());
 +    assertNotNull(reporting.getCritical().getValue());
 +    assertNotNull(reporting.getWarning());
 +    assertNotNull(reporting.getWarning().getText());
 +    assertNotNull(reporting.getWarning().getValue());
    }
  
-   /**
-    * @throws Exception
-    */
-   @Test
-   public void testAlertReconcile() throws Exception {
-     Clusters clusters = createMock(Clusters.class);
-     Cluster cluster = createMock(Cluster.class);
-     AlertDefinitionDAO dao = createMock(AlertDefinitionDAO.class);
- 
-     metaInfo.alertDefinitionDao = dao;
-     Set<AlertDefinition> alertDefinitions = metaInfo.getAlertDefinitions(
-         STACK_NAME_HDP, "2.0.6", "HDFS");
- 
-     assertEquals(4, alertDefinitions.size());
- 
-     Map<String, Cluster> clustersMap = new HashMap<String, Cluster>();
-     clustersMap.put("c1", cluster);
- 
-     StackId stackId = new StackId(STACK_NAME_HDP, "2.0.6");
-     Map<String, Service> clusterServiceMap = new HashMap<String, Service>();
-     clusterServiceMap.put("HDFS", null);
- 
-     List<AlertDefinitionEntity> entities = new ArrayList<AlertDefinitionEntity>();
- 
-     expect(clusters.getClusters()).andReturn(clustersMap).anyTimes();
-     expect(clusters.getCluster((String) anyObject())).andReturn(cluster).atLeastOnce();
-     expect(cluster.getClusterId()).andReturn(Long.valueOf(1)).anyTimes();
-     expect(cluster.getDesiredStackVersion()).andReturn(stackId).anyTimes();
-     expect(cluster.getServices()).andReturn(clusterServiceMap).anyTimes();
-     expect(dao.findAll(EasyMock.anyInt())).andReturn(entities).atLeastOnce();
-     dao.createOrUpdate(EasyMock.anyObject(AlertDefinitionEntity.class));
-     EasyMock.expectLastCall().times(4);
- 
-     EasyMock.replay(clusters, cluster, dao);
-     metaInfo.reconcileAlertDefinitions(clusters);
-     EasyMock.verify(cluster, cluster, dao);
- 
-     AlertDefinitionFactory alertDefinitionFactory = injector.getInstance(AlertDefinitionFactory.class);
-     for (AlertDefinition definition : alertDefinitions) {
-       entities.add(alertDefinitionFactory.coerce(1, definition));
-     }
- 
-     EasyMock.reset(clusters, cluster, dao);
-     expect(clusters.getClusters()).andReturn(clustersMap).anyTimes();
-     expect(clusters.getCluster((String) anyObject())).andReturn(cluster).atLeastOnce();
-     expect(cluster.getClusterId()).andReturn(Long.valueOf(1)).anyTimes();
-     expect(cluster.getDesiredStackVersion()).andReturn(stackId).anyTimes();
-     expect(cluster.getServices()).andReturn(clusterServiceMap).anyTimes();
-     expect(dao.findAll(EasyMock.anyInt())).andReturn(entities).atLeastOnce();
- 
-     EasyMock.replay(clusters, cluster, dao);
-     metaInfo.reconcileAlertDefinitions(clusters);
-     EasyMock.verify(cluster, cluster, dao);
+   private AmbariMetaInfo setupTempAmbariMetaInfo(String buildDir)
+       throws Exception {
+     File stackRootTmp = new File(buildDir + "/ambari-metaInfo");
+     File stackRoot = new File("src/test/resources/stacks");
+     stackRootTmp.mkdir();
+     FileUtils.copyDirectory(stackRoot, stackRootTmp);
+     AmbariMetaInfo ambariMetaInfo = new AmbariMetaInfo(stackRootTmp, new File(
+         "target/version"));
+     injector.injectMembers(ambariMetaInfo);
+     return ambariMetaInfo;
    }
  }

http://git-wip-us.apache.org/repos/asf/ambari/blob/7f86e75c/ambari-web/app/utils/ajax/ajax.js
----------------------------------------------------------------------


[19/50] [abbrv] git commit: Merge branch 'trunk' into branch-alerts-dev

Posted by jo...@apache.org.
Merge branch 'trunk' into branch-alerts-dev


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

Branch: refs/heads/trunk
Commit: 05da121a58e5768d0d0eda2527bd127c7355a23a
Parents: 1f1059c 813f16c
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Wed Sep 10 09:02:43 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Wed Sep 10 09:02:43 2014 -0400

----------------------------------------------------------------------
 .../main/resources/ui/admin-web/app/index.html  |   2 +
 .../resources/ui/admin-web/app/scripts/app.js   |   1 +
 .../controllers/ambariViews/ViewsEditCtrl.js    |   8 +
 .../clusters/ClustersManageAccessCtrl.js        |   8 +
 .../controllers/groups/GroupsEditCtrl.js        |   9 +
 .../scripts/controllers/users/UsersShowCtrl.js  |  13 +
 .../app/scripts/directives/editableList.js      | 199 ++++++++
 .../ui/admin-web/app/scripts/services/Group.js  |   6 +
 .../ui/admin-web/app/scripts/services/User.js   |   7 +
 .../resources/ui/admin-web/app/styles/main.css  | 212 +++++++-
 .../admin-web/app/views/ambariViews/edit.html   |  29 +-
 .../app/views/clusters/manageAccess.html        |  31 +-
 .../app/views/directives/editableList.html      |  44 ++
 .../ui/admin-web/app/views/groups/edit.html     |  23 +-
 .../ui/admin-web/app/views/leftNavbar.html      |   8 +-
 .../ui/admin-web/app/views/users/show.html      |  22 +-
 .../src/main/resources/ui/admin-web/bower.json  |   3 +-
 .../libraries/script/script.py                  |  23 +-
 ambari-server/conf/unix/ambari.properties       |   3 +
 .../ambari/server/api/AmbariPersistFilter.java  |   1 -
 .../stackadvisor/StackAdvisorHelper.java        |   6 +-
 .../StackAdvisorRequestException.java           |  27 +
 .../stackadvisor/StackAdvisorRunner.java        |  34 +-
 .../commands/StackAdvisorCommand.java           |  14 +-
 .../server/configuration/Configuration.java     |  58 ++-
 .../server/controller/AmbariHandlerList.java    |  43 +-
 .../controller/AmbariManagementController.java  |  16 +-
 .../AmbariManagementControllerImpl.java         |  34 +-
 .../ambari/server/controller/AmbariServer.java  |  52 +-
 .../server/controller/ControllerModule.java     |  69 ++-
 .../controller/FailsafeServletResponse.java     |  22 +-
 .../internal/ControllerResourceProvider.java    |  22 +-
 .../internal/PrivilegeResourceProvider.java     |   6 +-
 .../RecommendationResourceProvider.java         |   9 +-
 .../internal/ValidationResourceProvider.java    |   9 +-
 .../internal/ViewInstanceResourceProvider.java  |  44 +-
 .../ViewPermissionResourceProvider.java         |   8 +-
 .../internal/ViewPrivilegeResourceProvider.java |  28 +-
 .../internal/ViewVersionResourceProvider.java   |   6 +-
 .../apache/ambari/server/orm/dao/GroupDAO.java  |  30 +-
 .../apache/ambari/server/orm/dao/MemberDAO.java |  34 +-
 .../ambari/server/orm/dao/PrincipalDAO.java     |  27 +-
 .../ambari/server/orm/dao/PrincipalTypeDAO.java |  29 +-
 .../apache/ambari/server/orm/dao/UserDAO.java   |  49 +-
 .../server/orm/entities/MemberEntity.java       |   7 +-
 .../server/orm/entities/PrincipalEntity.java    |   2 +-
 .../ambari/server/orm/entities/UserEntity.java  |   5 +-
 .../ambari/server/orm/entities/ViewEntity.java  |   9 +
 .../server/orm/entities/ViewInstanceEntity.java |  89 ++++
 .../ambari/server/security/SecurityFilter.java  |   2 +-
 .../AmbariAuthorizationFilter.java              |  35 +-
 .../authorization/AmbariLdapDataPopulator.java  | 409 ---------------
 .../server/security/authorization/User.java     |   2 +-
 .../server/security/authorization/Users.java    | 158 +++++-
 .../security/ldap/AmbariLdapDataPopulator.java  | 430 ++++++++++++++++
 .../server/security/ldap/LdapBatchDto.java      |  67 +++
 .../server/security/ldap/LdapGroupDto.java      | 113 +++++
 .../server/security/ldap/LdapSyncDto.java       |  72 +++
 .../server/security/ldap/LdapUserDto.java       | 133 +++++
 .../security/ldap/LdapUserGroupMemberDto.java   |  82 +++
 .../ambari/server/state/ConfigHelper.java       |   3 +-
 .../apache/ambari/server/view/ViewRegistry.java |   4 +
 ambari-server/src/main/python/ambari-server.py  |   6 +-
 .../src/main/resources/META-INF/persistence.xml |   4 +
 .../src/main/resources/scripts/stack_advisor.py |   8 +-
 .../1.3.2/hooks/before-START/scripts/params.py  |  23 +-
 .../HDFS/package/scripts/hdfs_client.py         |   6 +
 .../services/HDFS/package/scripts/params.py     |  16 +-
 .../MAPREDUCE/configuration/mapred-env.xml      |  20 +
 .../MAPREDUCE/package/scripts/client.py         |   7 +
 .../MAPREDUCE/package/scripts/params.py         |  13 +
 .../HDP/1.3.2/services/SQOOP/metainfo.xml       |   2 +-
 .../stacks/HDP/1.3.2/services/stack_advisor.py  |  19 +-
 .../2.0.6/services/HIVE/package/scripts/hcat.py |   2 +-
 .../2.0.6/services/HIVE/package/scripts/hive.py | 118 ++---
 .../services/HIVE/package/scripts/params.py     |   9 +-
 .../stacks/HDP/2.0.6/services/stack_advisor.py  |  37 +-
 .../stacks/HDP/2.1/services/stack_advisor.py    |   8 +-
 .../stacks/HDP/2.2.1/repos/repoinfo.xml         |   4 +-
 .../stackadvisor/StackAdvisorRunnerTest.java    |  44 +-
 .../commands/StackAdvisorCommandTest.java       |  29 +-
 .../ViewInstanceResourceProviderTest.java       | 123 +++++
 .../ViewPermissionResourceProviderTest.java     | 133 +++++
 .../ViewPrivilegeResourceProviderTest.java      |   8 +-
 .../server/orm/entities/ViewEntityTest.java     |  17 +
 .../orm/entities/ViewInstanceEntityTest.java    |  16 +
 .../AmbariLdapDataPopulatorTest.java            | 261 ----------
 .../ldap/AmbariLdapDataPopulatorTest.java       | 202 ++++++++
 .../security/ldap/LdapPerformanceTest.java      |  94 ++++
 .../ambari/server/view/ViewRegistryTest.java    |  39 ++
 .../stacks/1.3.2/HDFS/test_hdfs_client.py       |  59 +++
 .../1.3.2/MAPREDUCE/test_mapreduce_client.py    |  36 +-
 .../python/stacks/1.3.2/configs/default.json    |  10 +-
 .../stacks/2.0.6/HIVE/test_hive_client.py       | 286 ++++++-----
 .../stacks/2.0.6/HIVE/test_hive_metastore.py    | 413 +++++++--------
 .../stacks/2.0.6/HIVE/test_hive_server.py       | 504 ++++++++++---------
 .../stacks/2.0.6/common/test_stack_advisor.py   | 157 +++++-
 .../stacks/2.1/HIVE/test_hive_metastore.py      | 304 +++++------
 .../stacks/2.1/common/test_stack_advisor.py     | 132 +++++
 ambari-web/app/app.js                           |   3 +-
 ambari-web/app/assets/licenses/NOTICE.txt       |   6 +-
 .../controllers/global/cluster_controller.js    |  42 --
 .../nameNode/step4_controller.js                |  29 +-
 .../main/dashboard/config_history_controller.js |   6 +-
 ambari-web/app/controllers/main/host/details.js |   7 +-
 ambari-web/app/controllers/main/service/item.js |   6 +-
 .../service/manage_config_groups_controller.js  |  15 +-
 .../app/controllers/main/views_controller.js    |   4 +-
 .../app/controllers/wizard/step7_controller.js  |  19 +-
 .../app/controllers/wizard/step8_controller.js  |   6 +-
 ambari-web/app/messages.js                      |   1 +
 .../app/mixins/common/table_server_mixin.js     |   3 -
 ambari-web/app/models/stack_service.js          |   3 +-
 ambari-web/app/routes/main.js                   |   2 +-
 ambari-web/app/styles/application.less          |   1 +
 .../common/configs/services_config.hbs          |   2 +
 .../admin/highAvailability/nameNode/step4.hbs   |   5 +
 .../views/main/dashboard/config_history_view.js |  11 +-
 ambari-web/app/views/main/menu.js               |  48 +-
 ambari-web/app/views/main/views/details.js      |  28 --
 ambari-web/test/app_test.js                     |  39 +-
 .../main/admin/security/add/step1_test.js       |  69 +--
 .../main/admin/security/add/step4_test.js       | 307 ++++++-----
 .../test/controllers/main/host/details_test.js  |   9 +-
 .../jquery.iframe-auto-height.plugin.1.9.5.js   | 224 ---------
 .../resources/ui/app/assets/data/apps/apps.json | 124 +++++
 .../assets/data/resource/service_status.json    | 107 ++++
 .../app/controllers/slider_apps_controller.js   | 136 ++++-
 .../src/main/resources/ui/app/helpers/ajax.js   |  40 +-
 .../src/main/resources/ui/app/helpers/helper.js |  47 +-
 .../src/main/resources/ui/app/initialize.js     |   4 +-
 .../ui/app/mappers/application_status.js        |  79 ++-
 .../ui/app/mappers/slider_apps_mapper.js        |  79 ++-
 .../main/resources/ui/app/models/slider_app.js  |   5 +
 .../resources/ui/app/models/slider_app_alert.js | 172 +++++++
 .../resources/ui/app/styles/application.less    |  60 +++
 .../ui/app/templates/slider_app/summary.hbs     |  27 +-
 .../src/main/resources/ui/app/translations.js   |  21 +
 .../ui/app/views/slider_app/summary_view.js     |  20 +-
 .../slider/src/main/resources/ui/config.js      |   1 +
 .../ui/vendor/scripts/common/jquery.timeago.js  | 214 ++++++++
 docs/pom.xml                                    |  42 +-
 docs/src/site/site.xml                          |  70 +--
 143 files changed, 5748 insertions(+), 2514 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/05da121a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
----------------------------------------------------------------------


[48/50] [abbrv] git commit: Merge branch 'trunk' into branch-alerts-dev

Posted by jo...@apache.org.
Merge branch 'trunk' into branch-alerts-dev


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

Branch: refs/heads/trunk
Commit: 9919b3f4faf0ead6d7495d28e910f21cbc0f42f5
Parents: 445a53c 76e3bb4
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Mon Oct 6 11:12:39 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Mon Oct 6 11:12:39 2014 -0400

----------------------------------------------------------------------
 .../src/main/python/ambari_agent/Facter.py      | 17 ++--
 .../src/main/python/ambari_commons/os_check.py  | 17 ++++
 .../ambari/server/agent/HeartBeatHandler.java   |  1 +
 .../ViewInstanceResourceDefinition.java         |  5 +-
 .../server/api/services/AmbariMetaInfo.java     |  2 +-
 .../apache/ambari/server/view/ViewRegistry.java | 35 ++++----
 .../src/main/python/ambari_server/utils.py      |  4 +-
 ambari-server/src/main/resources/os_family.json |  6 ++
 .../services/OOZIE/package/scripts/oozie.py     |  2 +-
 .../services/OOZIE/package/scripts/params.py    |  2 -
 .../ZOOKEEPER/configuration/zookeeper-env.xml   |  1 +
 .../ZOOKEEPER/package/scripts/params.py         |  2 +
 .../services/OOZIE/configuration/oozie-site.xml | 75 +++++++++++++++++
 .../ambari/server/view/ViewRegistryTest.java    | 28 +++---
 .../stacks/2.0.6/OOZIE/test_oozie_server.py     | 10 +++
 .../templates/main/service/services/storm.hbs   |  2 +-
 .../app/views/main/service/services/storm.js    |  8 ++
 .../ui/app/controllers/slider_app_controller.js | 89 ++++++++++++--------
 .../main/resources/ui/app/models/slider_app.js  | 33 ++++----
 .../ui/test/integration/pages/index_test.js     | 13 ++-
 .../controllers/slider_app_controller_test.js   | 64 ++++++++++++++
 21 files changed, 322 insertions(+), 94 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/9919b3f4/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/9919b3f4/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
----------------------------------------------------------------------


[20/50] [abbrv] git commit: Merge branch 'trunk' into branch-alerts-dev

Posted by jo...@apache.org.
Merge branch 'trunk' into branch-alerts-dev

Conflicts:
	ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java


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

Branch: refs/heads/trunk
Commit: 2262400c6057aec451027f432b83f2c88ac1d8c3
Parents: 05da121 3035978
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Thu Sep 11 15:02:05 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Thu Sep 11 15:02:05 2014 -0400

----------------------------------------------------------------------
 .../ui/admin-web/app/scripts/services/View.js   |   6 +-
 .../app/views/ambariViews/listTable.html        |   2 +-
 ambari-server/conf/unix/ambari.properties       |   1 +
 .../server/api/services/ComponentService.java   |   5 +-
 .../api/services/HostComponentService.java      |   5 +-
 .../server/configuration/Configuration.java     |   4 +
 .../controller/RequestStatusResponse.java       |  12 +
 .../internal/AbstractResourceProvider.java      |   3 +
 .../AmbariPrivilegeResourceProvider.java        |   8 +-
 .../internal/BaseBlueprintProcessor.java        |   7 +-
 .../internal/ClientConfigResourceProvider.java  |   5 +-
 .../internal/ClusterResourceProvider.java       |  17 +-
 .../internal/ServiceResourceProvider.java       |  14 +-
 .../internal/ViewVersionResourceProvider.java   |   3 +
 .../server/orm/entities/AlertCurrentEntity.java |  19 ++
 .../ambari/server/orm/entities/ViewEntity.java  |  29 +-
 .../server/upgrade/UpgradeCatalog161.java       |   2 +-
 .../server/upgrade/UpgradeCatalog170.java       |  86 ++++++
 .../server/view/configuration/ViewConfig.java   |  14 +
 ambari-server/src/main/python/bootstrap.py      |  24 +-
 .../main/resources/Ambari-DDL-MySQL-CREATE.sql  |   3 +-
 .../main/resources/Ambari-DDL-Oracle-CREATE.sql |   3 +-
 .../resources/Ambari-DDL-Postgres-CREATE.sql    |   3 +-
 .../Ambari-DDL-Postgres-EMBEDDED-CREATE.sql     |   3 +-
 .../services/HIVE/package/scripts/params.py     |   6 +-
 .../services/OOZIE/package/scripts/oozie.py     |   2 +-
 .../OOZIE/package/scripts/oozie_service.py      |   2 +-
 .../services/OOZIE/package/scripts/params.py    |  10 +
 .../2.1.GlusterFS/services/STORM/metainfo.xml   |   5 +
 .../2.1.GlusterFS/services/YARN/metainfo.xml    |   1 +
 .../AmbariPrivilegeResourceProviderTest.java    |   1 +
 .../internal/BlueprintResourceProviderTest.java |  15 +
 .../ClientConfigResourceProviderTest.java       |  16 +-
 .../internal/ClusterResourceProviderTest.java   | 239 ++++++++++++---
 .../internal/RequestResourceProviderTest.java   |  16 +-
 .../internal/ServiceResourceProviderTest.java   | 122 +++++++-
 .../server/orm/entities/ViewEntityTest.java     |  11 +
 .../server/upgrade/UpgradeCatalog161Test.java   |   2 +-
 .../server/upgrade/UpgradeCatalog170Test.java   |  49 +++-
 .../view/configuration/ViewConfigTest.java      |  23 ++
 ambari-server/src/test/python/TestBootstrap.py  |  29 +-
 ambari-web/app/app.js                           |   3 +
 .../app/controllers/wizard/step5_controller.js  |   2 +-
 .../app/controllers/wizard/step6_controller.js  |   2 +-
 .../app/controllers/wizard/step8_controller.js  |   2 +-
 ambari-web/app/data/HDP2/config_mapping.js      |   4 +-
 ambari-web/app/data/config_mapping.js           |   4 +-
 ambari-web/app/data/site_properties.js          |   2 +-
 ambari-web/app/styles/application.less          |   9 +-
 .../common/configs/config_history_flow.hbs      |  12 +-
 .../main/dashboard/widgets/cluster_metrics.hbs  |   2 +-
 .../main/dashboard/widgets/hbase_links.hbs      |   2 +-
 .../main/dashboard/widgets/hdfs_links.hbs       |   2 +-
 .../main/dashboard/widgets/mapreduce_links.hbs  |   2 +-
 .../main/dashboard/widgets/mapreduce_slots.hbs  |   2 +-
 .../main/dashboard/widgets/pie_chart.hbs        |   2 +-
 .../main/dashboard/widgets/simple_text.hbs      |   2 +-
 .../templates/main/dashboard/widgets/uptime.hbs |   2 +-
 ambari-web/app/utils/config.js                  |  19 +-
 .../views/common/configs/config_history_flow.js |   5 +
 ambari-web/app/views/main/dashboard/widget.js   |   4 +-
 ambari-web/app/views/main/dashboard/widgets.js  |  14 +
 ambari-web/vendor/scripts/jquery.hoverIntent.js | 115 ++++++++
 contrib/views/slider/pom.xml                    |   8 -
 .../view/slider/SliderAppsViewController.java   |   5 +
 .../slider/SliderAppsViewControllerImpl.java    | 262 +++++------------
 .../apache/ambari/view/slider/ViewStatus.java   |  33 +--
 .../view/slider/clients/AmbariClient.java       |   3 -
 .../slider/clients/AmbariInternalClient.java    | 292 -------------------
 .../slider/rest/client/JMXMetricHolder.java     |  50 ++++
 .../slider/rest/client/SliderAppJmxHelper.java  |   1 -
 .../resources/ui/app/assets/data/apps/apps.json |  16 +-
 .../assets/data/resource/service_configs.json   |  38 +++
 .../ui/app/components/configSection.js          |  16 +-
 .../createAppWizard/step1_controller.js         |  41 ++-
 .../createAppWizard/step2_controller.js         |   3 +-
 .../createAppWizard/step3_controller.js         | 123 +++++++-
 .../ui/app/controllers/slider_app_controller.js | 127 ++++++--
 .../app/controllers/slider_apps_controller.js   |   8 +-
 .../src/main/resources/ui/app/helpers/ajax.js   |   9 +
 .../src/main/resources/ui/app/initialize.js     |  19 +-
 .../ui/app/mappers/slider_apps_mapper.js        |   4 +-
 .../main/resources/ui/app/mixins/with_panels.js |  50 ++++
 .../resources/ui/app/models/config_property.js  |  44 +++
 .../main/resources/ui/app/models/slider_app.js  |  24 +-
 .../resources/ui/app/models/slider_app_type.js  |   2 +-
 .../resources/ui/app/styles/application.less    |  46 ++-
 .../ui/app/templates/common/config.hbs          |  37 +++
 .../app/templates/components/configSection.hbs  |  95 +++---
 .../ui/app/templates/slider_app/configs.hbs     |  36 ++-
 .../ui/app/templates/slider_app/flex_popup.hbs  |  39 +++
 .../ui/app/templates/slider_app/summary.hbs     |  10 +-
 .../src/main/resources/ui/app/translations.js   |   9 +-
 .../ui/app/views/common/config_set_view.js      |  56 ++++
 .../ui/app/views/slider_app/configs_view.js     |  57 ++++
 .../views/slider/src/main/resources/view.xml    |  23 +-
 96 files changed, 1846 insertions(+), 780 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/2262400c/ambari-server/conf/unix/ambari.properties
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/2262400c/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/2262400c/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertCurrentEntity.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/2262400c/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
----------------------------------------------------------------------
diff --cc ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
index 71cd2d7,0e8aea5..145096d
--- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
@@@ -73,7 -80,7 +80,8 @@@ import org.apache.ambari.server.state.C
  import org.apache.ambari.server.state.Clusters;
  import org.apache.ambari.server.state.Config;
  import org.apache.ambari.server.state.ConfigHelper;
 +import org.apache.ambari.server.state.alert.Scope;
+ import org.apache.ambari.server.utils.StageUtils;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  

http://git-wip-us.apache.org/repos/asf/ambari/blob/2262400c/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/2262400c/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/2262400c/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/2262400c/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
----------------------------------------------------------------------


[10/50] [abbrv] git commit: Merge branch 'trunk' into branch-alerts-dev

Posted by jo...@apache.org.
Merge branch 'trunk' into branch-alerts-dev


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

Branch: refs/heads/trunk
Commit: 8697c91b8309aeb9471585249d20fca6ccfee0f0
Parents: 7a0f509 641e177
Author: Nate Cole <nc...@hortonworks.com>
Authored: Tue Sep 2 16:29:02 2014 -0400
Committer: Nate Cole <nc...@hortonworks.com>
Committed: Tue Sep 2 16:29:02 2014 -0400

----------------------------------------------------------------------
 .../src/main/package/rpm/posttrans_agent.sh     |    6 +
 .../ambari/server/agent/ExecutionCommand.java   |    2 +
 .../AmbariManagementControllerImpl.java         |   11 +
 .../controller/StackConfigurationResponse.java  |   17 +-
 .../StackLevelConfigurationResponse.java        |    7 +-
 .../internal/BlueprintResourceProvider.java     |    3 +-
 .../internal/ClientConfigResourceProvider.java  |   11 +-
 .../internal/ClusterResourceProvider.java       |    2 +-
 .../StackConfigurationResourceProvider.java     |    6 +
 ...StackLevelConfigurationResourceProvider.java |    6 +
 .../server/orm/entities/BlueprintEntity.java    |    4 +-
 .../ambari/server/state/ConfigHelper.java       |   28 +
 .../ambari/server/state/PropertyInfo.java       |   34 +-
 .../server/upgrade/UpgradeCatalog170.java       |    6 +
 .../src/main/package/rpm/posttrans_server.sh    |    6 +
 .../src/main/resources/properties.json          |    2 +
 .../HDP/1.3.2/configuration/cluster-env.xml     |    2 +
 .../1.3.2/hooks/after-INSTALL/scripts/params.py |    1 +
 .../hooks/before-INSTALL/scripts/params.py      |   29 +-
 .../scripts/shared_initialization.py            |  111 +-
 .../GANGLIA/configuration/ganglia-env.xml       |    2 +
 .../services/HBASE/configuration/hbase-env.xml  |    1 +
 .../services/HDFS/configuration/hadoop-env.xml  |   12 +
 .../services/HDFS/configuration/hdfs-log4j.xml  |    1 +
 .../services/HDFS/package/scripts/params.py     |    2 +-
 .../services/HIVE/configuration/hive-env.xml    |    3 +
 .../services/HIVE/configuration/hive-site.xml   |    2 +-
 .../MAPREDUCE/configuration/mapred-env.xml      |    1 +
 .../NAGIOS/configuration/nagios-env.xml         |    4 +-
 .../services/OOZIE/configuration/oozie-env.xml  |    1 +
 .../services/OOZIE/configuration/oozie-site.xml |    2 +-
 .../services/SQOOP/configuration/sqoop-env.xml  |    1 +
 .../ZOOKEEPER/configuration/zookeeper-env.xml   |    1 +
 .../HDP/2.0.6/configuration/cluster-env.xml     |    2 +
 .../2.0.6/hooks/after-INSTALL/scripts/params.py |    1 +
 .../hooks/before-INSTALL/scripts/params.py      |   35 +-
 .../scripts/shared_initialization.py            |  136 +--
 .../services/FLUME/configuration/flume-env.xml  |    1 +
 .../GANGLIA/configuration/ganglia-env.xml       |    2 +
 .../services/HBASE/configuration/hbase-env.xml  |    1 +
 .../services/HDFS/configuration/core-site.xml   |   11 +
 .../services/HDFS/configuration/hadoop-env.xml  |   12 +
 .../services/HDFS/configuration/hdfs-log4j.xml  |    1 +
 .../services/HDFS/package/scripts/params.py     |    2 +-
 .../services/HIVE/configuration/hive-env.xml    |    3 +
 .../services/HIVE/configuration/hive-site.xml   |    2 +-
 .../NAGIOS/configuration/nagios-env.xml         |    4 +-
 .../services/OOZIE/configuration/oozie-env.xml  |    1 +
 .../services/OOZIE/configuration/oozie-site.xml |    2 +-
 .../services/SQOOP/configuration/sqoop-env.xml  |    1 +
 .../YARN/configuration-mapred/mapred-env.xml    |    1 +
 .../services/YARN/configuration/yarn-env.xml    |    1 +
 .../ZOOKEEPER/configuration/zookeeper-env.xml   |    1 +
 .../services/HIVE/configuration/hive-site.xml   |    2 +-
 .../FALCON/configuration/falcon-env.xml         |    1 +
 .../services/HIVE/configuration/hive-site.xml   |    2 +-
 .../services/STORM/configuration/storm-env.xml  |    1 +
 .../2.1/services/TEZ/configuration/tez-env.xml  |    1 +
 .../services/YARN/configuration/yarn-env.xml    |    1 +
 .../server/api/services/AmbariMetaInfoTest.java |    4 +-
 .../api/util/StackExtensionHelperTest.java      |    6 +-
 .../internal/ClusterResourceProviderTest.java   |   10 +-
 .../orm/entities/BlueprintEntityTest.java       |   24 +-
 .../server/upgrade/UpgradeCatalog170Test.java   |    7 +
 .../services/HIVE/configuration/hive-site.xml   |    2 +-
 .../app/assets/data/hosts/HDP2/hosts.json       |  406 ++++++-
 .../app/assets/data/hosts/quick_links.json      |   62 +
 .../app/assets/data/services/HDP2/services.json |   16 +
 .../services/host_component_stale_configs.json  |   62 +-
 .../data/stacks/HDP-2.1/operating_systems.json  |  157 +++
 .../data/stacks/HDP-2.1/service_components.json | 1143 +++++++++++++++---
 ambari-web/app/assets/data/views/instances.json |   40 +
 ambari-web/app/assets/data/views/views.json     |   11 +
 .../app/controllers/global/update_controller.js |    3 +
 .../controllers/main/service/info/configs.js    |    1 +
 .../app/controllers/wizard/step7_controller.js  |   28 +-
 ambari-web/app/data/HDP2/site_properties.js     |   13 +
 ambari-web/app/data/site_properties.js          |   13 +
 .../common/configs/config_history_flow.hbs      |    4 -
 .../common/configs/services_config.hbs          |   37 +-
 ambari-web/app/utils/ajax/ajax.js               |    8 +-
 ambari-web/app/utils/http_client.js             |    2 +-
 .../app/views/common/quick_view_link_view.js    |    2 +-
 .../main/service/info/config_test.js            |    8 +-
 .../service/reassign/step4_controller_test.js   |   21 -
 .../test/controllers/wizard/step8_test.js       |   20 +-
 ambari-web/test/models/stack_service_test.js    |   12 +-
 .../common/configs/config_history_flow_test.js  |    2 +-
 .../capacityscheduler/ConfigurationService.java |    1 +
 .../ui/app/assets/fonts/fontawesome-webfont.svg |   31 +-
 .../fonts/glyphicons-halflings-regular.svg      |  229 ++++
 .../ui/app/components/confirmDelete.js          |    2 +-
 .../src/main/resources/ui/app/router.js         |    2 +-
 .../resources/ui/app/styles/application.less    |   52 +-
 .../ui/app/templates/capacityEditForm.hbs       |    4 +-
 .../app/templates/components/totalCapacity.hbs  |   22 +-
 .../main/resources/ui/app/templates/queue.hbs   |   60 +-
 .../main/resources/ui/app/templates/queues.hbs  |   12 +-
 .../ui/app/templates/schedulerPanel.hbs         |   14 +-
 .../src/main/resources/view.xml                 |    6 +-
 contrib/views/slider/pom.xml                    |   57 +-
 .../slider/SliderAppsViewControllerImpl.java    |    2 +-
 102 files changed, 2435 insertions(+), 738 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/8697c91b/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/8697c91b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/8697c91b/ambari-server/src/main/resources/properties.json
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/8697c91b/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
----------------------------------------------------------------------


[15/50] [abbrv] git commit: AMBARI-7160. Add endpoints for alert data (ncole)

Posted by jo...@apache.org.
AMBARI-7160. Add endpoints for alert data (ncole)


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

Branch: refs/heads/trunk
Commit: 84c16c5c5981559454659d069463a5bbd26e7de6
Parents: e508fe5
Author: Nate Cole <nc...@hortonworks.com>
Authored: Thu Sep 4 18:07:59 2014 -0400
Committer: Nate Cole <nc...@hortonworks.com>
Committed: Sun Sep 7 05:45:13 2014 -0400

----------------------------------------------------------------------
 .../api/resources/AlertResourceDefinition.java  |  41 ++++
 .../resources/ClusterResourceDefinition.java    |   1 +
 .../api/resources/HostResourceDefinition.java   |   7 +-
 .../resources/ResourceInstanceFactoryImpl.java  |   4 +
 .../resources/ServiceResourceDefinition.java    |   5 +-
 .../server/api/services/AlertService.java       |  93 +++++++
 .../server/api/services/ClusterService.java     |  16 ++
 .../ambari/server/api/services/HostService.java |  11 +
 .../server/api/services/ServiceService.java     |   9 +
 .../ambari/server/controller/AmbariServer.java  |   2 +
 .../AbstractControllerResourceProvider.java     |   2 +
 .../internal/AlertResourceProvider.java         | 191 +++++++++++++++
 .../ambari/server/controller/spi/Resource.java  |   2 +
 .../apache/ambari/server/orm/dao/AlertsDAO.java |  21 ++
 .../server/orm/entities/AlertCurrentEntity.java |   5 +-
 .../src/main/resources/key_properties.json      |   6 +
 .../src/main/resources/properties.json          |  16 ++
 .../api/query/render/DefaultRendererTest.java   |   3 +-
 .../api/query/render/MinimalRendererTest.java   |   3 +-
 .../ClusterResourceDefinitionTest.java          |   3 +-
 .../internal/AlertResourceProviderTest.java     | 241 +++++++++++++++++++
 .../ambari/server/orm/dao/AlertsDAOTest.java    |  52 +++-
 22 files changed, 724 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/84c16c5c/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertResourceDefinition.java
new file mode 100644
index 0000000..afdbcfc
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertResourceDefinition.java
@@ -0,0 +1,41 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.api.resources;
+
+import org.apache.ambari.server.controller.spi.Resource;
+
+/**
+ * Definition for alert resources.
+ */
+public class AlertResourceDefinition extends BaseResourceDefinition {
+  
+  public AlertResourceDefinition() {
+    super(Resource.Type.Alert);
+  }
+  
+  @Override
+  public String getPluralName() {
+    return "alerts_data";
+  }
+  
+  @Override
+  public String getSingularName() {
+    return "alert_data";
+  }
+  
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/84c16c5c/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ClusterResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ClusterResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ClusterResourceDefinition.java
index 702bcf8..ef907c0 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ClusterResourceDefinition.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ClusterResourceDefinition.java
@@ -68,6 +68,7 @@ public class ClusterResourceDefinition extends BaseResourceDefinition {
     setChildren.add(new SubResourceDefinition(Resource.Type.ConfigGroup));
     setChildren.add(new SubResourceDefinition(Resource.Type.ClusterPrivilege));
     setChildren.add(new SubResourceDefinition(Resource.Type.AlertDefinition));
+    setChildren.add(new SubResourceDefinition(Resource.Type.Alert));
 
     return setChildren;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/84c16c5c/ambari-server/src/main/java/org/apache/ambari/server/api/resources/HostResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/HostResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/HostResourceDefinition.java
index 8aba287..14ed799 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/HostResourceDefinition.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/HostResourceDefinition.java
@@ -19,7 +19,7 @@
 package org.apache.ambari.server.api.resources;
 
 
-import java.util.Collections;
+import java.util.HashSet;
 import java.util.Set;
 
 import org.apache.ambari.server.controller.spi.Resource;
@@ -48,6 +48,9 @@ public class HostResourceDefinition extends BaseResourceDefinition {
 
   @Override
   public Set<SubResourceDefinition> getSubResourceDefinitions() {
-    return Collections.singleton(new SubResourceDefinition(Resource.Type.HostComponent));
+    Set<SubResourceDefinition> subs = new HashSet<SubResourceDefinition>();
+    subs.add(new SubResourceDefinition(Resource.Type.HostComponent));
+    subs.add(new SubResourceDefinition(Resource.Type.Alert));
+    return subs;
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/84c16c5c/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
index ffbfb29..3b90b30 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
@@ -250,6 +250,10 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
       case Permission:
         resourceDefinition = new PermissionResourceDefinition();
         break;
+        
+      case Alert:
+        resourceDefinition = new AlertResourceDefinition();
+        break;
 
       case AlertDefinition:
         resourceDefinition = new AlertDefResourceDefinition();

http://git-wip-us.apache.org/repos/asf/ambari/blob/84c16c5c/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ServiceResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ServiceResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ServiceResourceDefinition.java
index e1355ad..be8e0b4 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ServiceResourceDefinition.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ServiceResourceDefinition.java
@@ -47,6 +47,9 @@ public class ServiceResourceDefinition extends BaseResourceDefinition {
 
   @Override
   public Set<SubResourceDefinition> getSubResourceDefinitions() {
-    return Collections.singleton(new SubResourceDefinition(Resource.Type.Component));
+    Set<SubResourceDefinition> subs = new HashSet<SubResourceDefinition>();
+    subs.add(new SubResourceDefinition(Resource.Type.Component));
+    subs.add(new SubResourceDefinition(Resource.Type.Alert));
+    return subs;
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/84c16c5c/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertService.java
new file mode 100644
index 0000000..8e163c2
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertService.java
@@ -0,0 +1,93 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.api.services;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.controller.spi.Resource;
+
+/**
+ * Endpoint for alert data.
+ */
+public class AlertService extends BaseService {
+
+  private String clusterName = null;
+  private String serviceName = null;
+  private String hostName = null;
+  
+  AlertService(String clusterName, String serviceName, String hostName) {
+    this.clusterName = clusterName;
+    this.serviceName = serviceName;
+    this.hostName = hostName;
+  }
+
+  /**
+   * Gets all the definitions for the target
+   */
+  @GET
+  @Produces("text/plain")
+  public Response getDefinitions(String body,
+      @Context HttpHeaders headers,
+      @Context UriInfo ui) {
+    return handleRequest(headers, body, ui, Request.Type.GET,
+      createResourceInstance(null));
+  }
+  
+
+  /**
+   * Gets a specific alert's instance
+   */
+  @GET
+  @Path("{alertId}")
+  @Produces("text/plain")
+  public Response getDefinition(String body,
+      @Context HttpHeaders headers,
+      @Context UriInfo ui,
+      @PathParam("alertId") Long id) {
+    return handleRequest(headers, body, ui, Request.Type.GET,
+      createResourceInstance(id));
+  }
+  
+  
+  /**
+   * Create an alert resource instance
+   * @param alertId the alert id, if requesting a specific one
+   * @return the resource instance
+   */
+  private ResourceInstance createResourceInstance(Long alertId) {
+    Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.Cluster, clusterName);
+    mapIds.put(Resource.Type.Service, serviceName);
+    mapIds.put(Resource.Type.Host, hostName);
+    mapIds.put(Resource.Type.Alert, null == alertId ? null : alertId.toString());
+
+    return createResource(Resource.Type.Alert, mapIds);
+  }
+  
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/84c16c5c/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
index 3f1ce36..c76acf7 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
@@ -357,6 +357,22 @@ public class ClusterService extends BaseService {
     hasPermission(Request.Type.valueOf(request.getMethod()), clusterName);
     return new ClusterPrivilegeService(clusterName);
   }
+  
+  /**
+   * Gets the alert definition service
+   *
+   * @param request      the request
+   * @param clusterName  the cluster name
+   *
+   * @return  the alert definition service
+   */
+  @Path("{clusterName}/alerts_data")
+  public AlertService getAlertService(
+      @Context javax.ws.rs.core.Request request, @PathParam("clusterName") String clusterName) {
+
+    hasPermission(Request.Type.valueOf(request.getMethod()), clusterName);
+    return new AlertService(clusterName, null, null);
+  }  
 
 
   // ----- helper methods ----------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/84c16c5c/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostService.java
index db9d3c0..8cec7e1 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostService.java
@@ -207,6 +207,17 @@ public class HostService extends BaseService {
   }
 
   /**
+   * Get the alerts sub-resource.
+   *
+   * @param hostName host id
+   * @return the alerts service
+   */
+  @Path("{hostName}/alerts_data")
+  public AlertService getAlertHandler(@PathParam("hostName") String hostName) {
+    return new AlertService(m_clusterName, null, hostName);
+  }  
+  
+  /**
    * Create a service resource instance.
    *
    *

http://git-wip-us.apache.org/repos/asf/ambari/blob/84c16c5c/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceService.java
index 643ae36..30f4f2f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceService.java
@@ -183,6 +183,15 @@ public class ServiceService extends BaseService {
 
     return new ComponentService(m_clusterName, serviceName);
   }
+  
+  /**
+   * Gets the alerts sub-resource.
+   */
+  @Path("{serviceName}/alerts_data")
+  public AlertService getAlertHandler(
+      @PathParam("serviceName") String serviceName) {
+    return new AlertService(m_clusterName, serviceName, null);
+  }
 
   /**
    * Create a service resource instance.

http://git-wip-us.apache.org/repos/asf/ambari/blob/84c16c5c/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
index 31d6518..73e4013 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
@@ -47,6 +47,7 @@ import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.internal.AbstractControllerResourceProvider;
 import org.apache.ambari.server.controller.internal.AlertDefinitionResourceProvider;
 import org.apache.ambari.server.controller.internal.AlertGroupResourceProvider;
+import org.apache.ambari.server.controller.internal.AlertResourceProvider;
 import org.apache.ambari.server.controller.internal.AlertTargetResourceProvider;
 import org.apache.ambari.server.controller.internal.AmbariPrivilegeResourceProvider;
 import org.apache.ambari.server.controller.internal.BlueprintResourceProvider;
@@ -531,6 +532,7 @@ public class AmbariServer {
         injector.getInstance(Gson.class), ambariMetaInfo);
     StackDependencyResourceProvider.init(ambariMetaInfo);
     ClusterResourceProvider.init(injector.getInstance(BlueprintDAO.class), ambariMetaInfo, injector.getInstance(ConfigHelper.class));
+    AlertResourceProvider.init(injector);
     AlertDefinitionResourceProvider.init(injector);
     AlertGroupResourceProvider.init(injector);
     AlertTargetResourceProvider.init(injector);

http://git-wip-us.apache.org/repos/asf/ambari/blob/84c16c5c/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
index 31c350b..f3f92a1 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
@@ -149,6 +149,8 @@ public abstract class AbstractControllerResourceProvider extends AbstractResourc
         return new RecommendationResourceProvider(propertyIds, keyPropertyIds, managementController);
       case Validation:
         return new ValidationResourceProvider(propertyIds, keyPropertyIds, managementController);
+      case Alert:
+        return new AlertResourceProvider(propertyIds, keyPropertyIds, managementController);
       case AlertDefinition:
         return new AlertDefinitionResourceProvider(propertyIds, keyPropertyIds, managementController);
       case AlertGroup:

http://git-wip-us.apache.org/repos/asf/ambari/blob/84c16c5c/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertResourceProvider.java
new file mode 100644
index 0000000..639a02f
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertResourceProvider.java
@@ -0,0 +1,191 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.controller.internal;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
+import org.apache.ambari.server.controller.spi.NoSuchResourceException;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.orm.dao.AlertsDAO;
+import org.apache.ambari.server.orm.entities.AlertCurrentEntity;
+import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
+import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
+import org.apache.ambari.server.state.Cluster;
+
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+
+/**
+ * ResourceProvider for Alert instances
+ */
+public class AlertResourceProvider extends ReadOnlyResourceProvider {
+
+  protected static final String ALERT_CLUSTER_NAME = "Alert/cluster_name";
+  protected static final String ALERT_ID = "Alert/id";
+  protected static final String ALERT_NAME = "Alert/name";
+  protected static final String ALERT_LATEST_TIMESTAMP = "Alert/latest_timestamp";
+  protected static final String ALERT_MAINTENANCE_STATE = "Alert/maintenance_state";
+  protected static final String ALERT_ORIGINAL_TIMESTAMP = "Alert/original_timestamp";
+  protected static final String ALERT_INSTANCE = "Alert/instance";
+  protected static final String ALERT_LABEL = "Alert/label";
+  protected static final String ALERT_STATE = "Alert/state";
+  protected static final String ALERT_TEXT = "Alert/text";
+  protected static final String ALERT_COMPONENT = "Alert/component_name";
+  protected static final String ALERT_HOST = "Alert/host_name";
+  protected static final String ALERT_SERVICE = "Alert/service_name";
+  protected static final String ALERT_SCOPE = "Alert/scope";
+  
+  private static Set<String> pkPropertyIds = new HashSet<String>(
+      Arrays.asList(ALERT_ID, ALERT_NAME));
+
+  private static AlertsDAO alertsDAO = null;
+
+  /**
+   * @param injector the injector
+   */
+  @Inject
+  public static void init(Injector injector) {
+    alertsDAO = injector.getInstance(AlertsDAO.class);
+  }
+
+  AlertResourceProvider(Set<String> propertyIds,
+      Map<Resource.Type, String> keyPropertyIds,
+      AmbariManagementController managementController) {
+    
+    super(propertyIds, keyPropertyIds, managementController);
+  }
+
+  @Override
+  protected Set<String> getPKPropertyIds() {
+    return pkPropertyIds;
+  }
+
+
+  @Override
+  public Set<Resource> getResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException,
+      NoSuchResourceException, NoSuchParentResourceException {
+
+    Set<String> requestPropertyIds = getRequestPropertyIds(request, predicate);
+    
+    Set<Resource> results = new HashSet<Resource>();
+
+    for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
+      
+      String clusterName = (String) propertyMap.get(ALERT_CLUSTER_NAME);
+
+      if (null == clusterName || clusterName.isEmpty()) {
+        throw new IllegalArgumentException("Invalid argument, cluster name is required");
+      }
+
+      String id = (String) propertyMap.get(ALERT_ID);
+      if (null != id) {
+        AlertCurrentEntity entity = alertsDAO.findCurrentById(Long.parseLong(id));
+        
+        if (null != entity) {
+          results.add(toResource(false, clusterName, entity, requestPropertyIds));
+        }
+        
+      } else {
+        Cluster cluster = null;
+        
+        try {
+          cluster = getManagementController().getClusters().getCluster(clusterName);
+        } catch (AmbariException e) {
+          throw new NoSuchResourceException("Parent Cluster resource doesn't exist", e);
+        }
+        
+        String serviceName = (String) propertyMap.get(ALERT_SERVICE);
+        String hostName = (String) propertyMap.get(ALERT_HOST);
+        
+        List<AlertCurrentEntity> entities = null;
+        
+        if (null != hostName) {
+          entities = alertsDAO.findCurrentByHost(cluster.getClusterId(),
+              hostName);
+        } else if (null != serviceName) {
+          entities = alertsDAO.findCurrentByService(cluster.getClusterId(),
+              serviceName);
+        } else {
+          entities = alertsDAO.findCurrentByCluster(cluster.getClusterId());          
+        }
+        
+        if (null == entities)
+          entities = Collections.emptyList();
+        
+        for (AlertCurrentEntity entity : entities) {
+          results.add(toResource(true, clusterName, entity, requestPropertyIds));
+        }
+      }
+    }
+
+    return results;
+  }
+
+  /**
+   * Converts an entity to a resource.
+   * 
+   * @param isCollection {@code true} if the response is for a collection
+   * @param clusterName the cluster name
+   * @param entity the entity
+   * @param requestedIds the requested ids
+   * @return the resource
+   */
+  private Resource toResource(boolean isCollection, String clusterName,
+      AlertCurrentEntity entity, Set<String> requestedIds) {
+    Resource resource = new ResourceImpl(Resource.Type.Alert);
+
+    setResourceProperty(resource, ALERT_CLUSTER_NAME, clusterName, requestedIds);
+    setResourceProperty(resource, ALERT_ID, entity.getAlertId(), requestedIds);
+    setResourceProperty(resource, ALERT_LATEST_TIMESTAMP, entity.getLatestTimestamp(), requestedIds);
+    setResourceProperty(resource, ALERT_MAINTENANCE_STATE, entity.getMaintenanceState(), requestedIds);
+    setResourceProperty(resource, ALERT_ORIGINAL_TIMESTAMP, entity.getOriginalTimestamp(), requestedIds);
+    
+    AlertHistoryEntity history = entity.getAlertHistory();
+    setResourceProperty(resource, ALERT_INSTANCE, history.getAlertInstance(), requestedIds);
+    setResourceProperty(resource, ALERT_LABEL, history.getAlertLabel(), requestedIds);
+    setResourceProperty(resource, ALERT_STATE, history.getAlertState(), requestedIds);
+    setResourceProperty(resource, ALERT_TEXT, history.getAlertText(), requestedIds);
+    setResourceProperty(resource, ALERT_COMPONENT, history.getComponentName(), requestedIds);
+    setResourceProperty(resource, ALERT_HOST, history.getHostName(), requestedIds);
+    setResourceProperty(resource, ALERT_SERVICE, history.getServiceName(), requestedIds);
+    
+    AlertDefinitionEntity definition = history.getAlertDefinition();
+    setResourceProperty(resource, ALERT_NAME, definition.getDefinitionName(), requestedIds);
+    setResourceProperty(resource, ALERT_SCOPE, definition.getScope(), requestedIds);
+    
+    if (isCollection) {
+      // !!! want name to be populated as if it were a PK when requesting the collection
+      resource.setProperty(ALERT_NAME, definition.getDefinitionName());
+    }
+
+    return resource;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/84c16c5c/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
index 2cf6d99..59f9a89 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
@@ -114,6 +114,7 @@ public interface Resource {
     Validation,
     HostComponentProcess,
     Permission,
+    Alert,
     AlertDefinition,
     AlertGroup,
     AlertTarget,
@@ -198,6 +199,7 @@ public interface Resource {
     public static final Type Validation = InternalType.Validation.getType();
     public static final Type HostComponentProcess = InternalType.HostComponentProcess.getType();
     public static final Type Permission = InternalType.Permission.getType();
+    public static final Type Alert = InternalType.Alert.getType();
     public static final Type AlertDefinition = InternalType.AlertDefinition.getType();
     public static final Type AlertGroup = InternalType.AlertGroup.getType();
     public static final Type AlertTarget = InternalType.AlertTarget.getType();

http://git-wip-us.apache.org/repos/asf/ambari/blob/84c16c5c/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 b43b5b1..5fcc1ec 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
@@ -19,6 +19,7 @@ package org.apache.ambari.server.orm.dao;
 
 import java.util.Collections;
 import java.util.Date;
+import java.util.EnumSet;
 import java.util.List;
 
 import javax.persistence.EntityManager;
@@ -28,6 +29,7 @@ import org.apache.ambari.server.orm.RequiresSession;
 import org.apache.ambari.server.orm.entities.AlertCurrentEntity;
 import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
 import org.apache.ambari.server.state.AlertState;
+import org.apache.ambari.server.state.alert.Scope;
 
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -205,6 +207,23 @@ public class AlertsDAO {
   }
 
   /**
+   * Gets the current alerts for a given cluster.
+   * 
+   * @return the current alerts for the given clusteror an empty list if none
+   *         exist (never {@code null}).
+   */
+  @RequiresSession
+  public List<AlertCurrentEntity> findCurrentByCluster(long clusterId) {
+    TypedQuery<AlertCurrentEntity> query = entityManagerProvider.get().createNamedQuery(
+        "AlertCurrentEntity.findByCluster", AlertCurrentEntity.class);
+
+    query.setParameter("clusterId", Long.valueOf(clusterId));
+
+    return daoUtils.selectList(query);
+  }
+  
+  
+  /**
    * Gets the current alerts for a given service.
    * 
    * @return the current alerts for the given service or an empty list if none
@@ -218,6 +237,7 @@ public class AlertsDAO {
 
     query.setParameter("clusterId", clusterId);
     query.setParameter("serviceName", serviceName);
+    query.setParameter("inlist", EnumSet.of(Scope.ANY, Scope.SERVICE));
 
     return daoUtils.selectList(query);
   }
@@ -236,6 +256,7 @@ public class AlertsDAO {
 
     query.setParameter("clusterId", clusterId);
     query.setParameter("hostName", hostName);
+    query.setParameter("inlist", EnumSet.of(Scope.ANY, Scope.HOST));
 
     return daoUtils.selectList(query);
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/84c16c5c/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 31b1673..6d6073f 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
@@ -47,8 +47,9 @@ import org.apache.ambari.server.state.MaintenanceState;
 @TableGenerator(name = "alert_current_id_generator", table = "ambari_sequences", pkColumnName = "sequence_name", valueColumnName = "sequence_value", pkColumnValue = "alert_current_id_seq", initialValue = 0, allocationSize = 1)
 @NamedQueries({
     @NamedQuery(name = "AlertCurrentEntity.findAll", query = "SELECT alert FROM AlertCurrentEntity alert"),
-    @NamedQuery(name = "AlertCurrentEntity.findByService", query = "SELECT alert FROM AlertCurrentEntity alert JOIN alert.alertHistory history WHERE history.clusterId = :clusterId AND history.serviceName = :serviceName"),
-    @NamedQuery(name = "AlertCurrentEntity.findByHost", query = "SELECT alert FROM AlertCurrentEntity alert JOIN alert.alertHistory history WHERE history.clusterId = :clusterId AND history.hostName = :hostName"),
+    @NamedQuery(name = "AlertCurrentEntity.findByCluster", query = "SELECT alert FROM AlertCurrentEntity alert JOIN alert.alertHistory history WHERE history.clusterId = :clusterId"),
+    @NamedQuery(name = "AlertCurrentEntity.findByService", query = "SELECT alert FROM AlertCurrentEntity alert JOIN alert.alertHistory history WHERE history.clusterId = :clusterId AND history.serviceName = :serviceName AND history.alertDefinition.scope IN :inlist"),
+    @NamedQuery(name = "AlertCurrentEntity.findByHost", query = "SELECT alert FROM AlertCurrentEntity alert JOIN alert.alertHistory history WHERE history.clusterId = :clusterId AND history.hostName = :hostName AND history.alertDefinition.scope IN :inlist"),
     @NamedQuery(name = "AlertCurrentEntity.findByHostAndName", query = "SELECT alert FROM AlertCurrentEntity alert JOIN alert.alertHistory history WHERE history.clusterId = :clusterId AND history.alertDefinition.definitionName = :definitionName AND history.hostName = :hostName"),
     @NamedQuery(name = "AlertCurrentEntity.removeByHistoryId", query = "DELETE FROM AlertCurrentEntity alert WHERE alert.alertHistory.alertId = :historyId"),
     @NamedQuery(name = "AlertCurrentEntity.removeByDefinitionId", query = "DELETE FROM AlertCurrentEntity alert WHERE alert.alertDefinition.definitionId = :definitionId") })

http://git-wip-us.apache.org/repos/asf/ambari/blob/84c16c5c/ambari-server/src/main/resources/key_properties.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/key_properties.json b/ambari-server/src/main/resources/key_properties.json
index db34920..d127bc5 100644
--- a/ambari-server/src/main/resources/key_properties.json
+++ b/ambari-server/src/main/resources/key_properties.json
@@ -145,6 +145,12 @@
     "HostComponent": "HostComponentProcess/component_name",
     "HostComponentProcess": "HostComponentProcess/name"
   },
+  "Alert": {
+    "Cluster": "Alert/cluster_name",
+    "Service": "Alert/service_name",
+    "Host": "Alert/host_name",
+    "Alert": "Alert/id"
+  },
   "AlertDefinition": {
     "Cluster": "AlertDefinition/cluster_name",
     "AlertDefinition": "AlertDefinition/id"

http://git-wip-us.apache.org/repos/asf/ambari/blob/84c16c5c/ambari-server/src/main/resources/properties.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/properties.json b/ambari-server/src/main/resources/properties.json
index accab44..eeef6ec 100644
--- a/ambari-server/src/main/resources/properties.json
+++ b/ambari-server/src/main/resources/properties.json
@@ -419,6 +419,22 @@
       "HostComponentProcess/name",
       "HostComponentProcess/status"
     ],
+    "Alert": [
+      "Alert/cluster_name",
+      "Alert/id",
+      "Alert/name",
+      "Alert/latest_timestamp",
+      "Alert/maintenance_state",
+      "Alert/original_timestamp",
+      "Alert/instance",
+      "Alert/label",
+      "Alert/state",
+      "Alert/text",
+      "Alert/component_name",
+      "Alert/host_name",
+      "Alert/service_name",
+      "Alert/scope"
+    ],
     "AlertDefinition": [
       "AlertDefinition/cluster_name",
       "AlertDefinition/service_name",

http://git-wip-us.apache.org/repos/asf/ambari/blob/84c16c5c/ambari-server/src/test/java/org/apache/ambari/server/api/query/render/DefaultRendererTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/query/render/DefaultRendererTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/query/render/DefaultRendererTest.java
index eb0f28f..3e0617e 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/query/render/DefaultRendererTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/query/render/DefaultRendererTest.java
@@ -50,6 +50,7 @@ public class DefaultRendererTest {
 
     // schema expectations
     expect(schemaFactory.getSchema(Resource.Type.Component)).andReturn(schema).anyTimes();
+    expect(schemaFactory.getSchema(Resource.Type.Alert)).andReturn(schema).anyTimes();
     expect(schema.getKeyPropertyId(Resource.Type.Component)).andReturn("ServiceComponentInfo/component_name").anyTimes();
     expect(schema.getKeyPropertyId(Resource.Type.Service)).andReturn("ServiceComponentInfo/service_name").anyTimes();
 
@@ -63,7 +64,7 @@ public class DefaultRendererTest {
     TreeNode<Set<String>> propertyTree = renderer.finalizeProperties(queryTree, false);
     // no properties should have been added
     assertTrue(propertyTree.getObject().isEmpty());
-    assertEquals(1, propertyTree.getChildren().size());
+    assertEquals(2, propertyTree.getChildren().size());
 
     TreeNode<Set<String>> componentNode = propertyTree.getChild("Component");
     assertEquals(2, componentNode.getObject().size());

http://git-wip-us.apache.org/repos/asf/ambari/blob/84c16c5c/ambari-server/src/test/java/org/apache/ambari/server/api/query/render/MinimalRendererTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/query/render/MinimalRendererTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/query/render/MinimalRendererTest.java
index 16cbb2a..9b03c51 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/query/render/MinimalRendererTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/query/render/MinimalRendererTest.java
@@ -57,6 +57,7 @@ public class MinimalRendererTest {
 
     // schema expectations
     expect(schemaFactory.getSchema(Resource.Type.Component)).andReturn(schema).anyTimes();
+    expect(schemaFactory.getSchema(Resource.Type.Alert)).andReturn(schema).anyTimes();
     expect(schema.getKeyPropertyId(Resource.Type.Component)).andReturn("ServiceComponentInfo/component_name").anyTimes();
 
     replay(schemaFactory, schema);
@@ -69,7 +70,7 @@ public class MinimalRendererTest {
     TreeNode<Set<String>> propertyTree = renderer.finalizeProperties(queryTree, false);
     // no properties should have been added
     assertTrue(propertyTree.getObject().isEmpty());
-    assertEquals(1, propertyTree.getChildren().size());
+    assertEquals(2, propertyTree.getChildren().size());
 
     TreeNode<Set<String>> componentNode = propertyTree.getChild("Component");
     assertEquals(1, componentNode.getObject().size());

http://git-wip-us.apache.org/repos/asf/ambari/blob/84c16c5c/ambari-server/src/test/java/org/apache/ambari/server/api/resources/ClusterResourceDefinitionTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/resources/ClusterResourceDefinitionTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/resources/ClusterResourceDefinitionTest.java
index eabb5ab..7296e8d 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/resources/ClusterResourceDefinitionTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/resources/ClusterResourceDefinitionTest.java
@@ -50,7 +50,7 @@ public class ClusterResourceDefinitionTest {
     ResourceDefinition resource = new ClusterResourceDefinition();
     Set<SubResourceDefinition> subResources = resource.getSubResourceDefinitions();
 
-    assertEquals(9, subResources.size());
+    assertEquals(10, subResources.size());
     assertTrue(includesType(subResources, Resource.Type.Service));
     assertTrue(includesType(subResources, Resource.Type.Host));
     assertTrue(includesType(subResources, Resource.Type.Configuration));
@@ -60,6 +60,7 @@ public class ClusterResourceDefinitionTest {
     assertTrue(includesType(subResources, Resource.Type.AlertDefinition));
     assertTrue(includesType(subResources, Resource.Type.ServiceConfigVersion));
     assertTrue(includesType(subResources, Resource.Type.ClusterPrivilege));
+    assertTrue(includesType(subResources, Resource.Type.Alert));
   }
 
   @Test

http://git-wip-us.apache.org/repos/asf/ambari/blob/84c16c5c/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertResourceProviderTest.java
new file mode 100644
index 0000000..4fd44af
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertResourceProviderTest.java
@@ -0,0 +1,241 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.controller.internal;
+
+import static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.captureLong;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+import javax.persistence.EntityManager;
+
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.utilities.PredicateBuilder;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.orm.dao.AlertsDAO;
+import org.apache.ambari.server.orm.entities.AlertCurrentEntity;
+import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
+import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
+import org.apache.ambari.server.state.AlertState;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.easymock.Capture;
+import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.inject.Binder;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Module;
+
+/**
+ * Test the AlertResourceProvider class
+ */
+public class AlertResourceProviderTest {
+
+  private static final Long ALERT_VALUE_ID = Long.valueOf(1000L);
+  private static final String ALERT_VALUE_LABEL = "My Label";
+  private static final Long ALERT_VALUE_TIMESTAMP = Long.valueOf(1L);
+  private static final String ALERT_VALUE_TEXT = "My Text";
+  private static final String ALERT_VALUE_COMPONENT = "component";
+  private static final String ALERT_VALUE_HOSTNAME = "host";
+  private static final String ALERT_VALUE_SERVICE = "service";
+
+  private AlertsDAO m_dao;
+//  private Injector m_injector;
+  private AmbariManagementController m_amc;
+
+  @Before
+  @SuppressWarnings("boxing")  
+  public void before() throws Exception {
+    Injector m_injector = Guice.createInjector(new MockModule());
+
+    m_amc = m_injector.getInstance(AmbariManagementController.class);
+
+    Cluster cluster = EasyMock.createMock(Cluster.class);
+    Clusters clusters = m_injector.getInstance(Clusters.class);
+    expect(m_amc.getClusters()).andReturn(clusters).atLeastOnce();
+    expect(clusters.getCluster(capture(new Capture<String>()))).andReturn(cluster).atLeastOnce();
+    expect(cluster.getClusterId()).andReturn(Long.valueOf(1L));
+    
+    replay(m_amc, clusters, cluster);
+    
+    m_dao = m_injector.getInstance(AlertsDAO.class);
+    
+    AlertResourceProvider.init(m_injector);
+  }
+
+
+  /**
+   * @throws Exception
+   */
+  @Test
+  public void testGetCluster() throws Exception {
+    expect(m_dao.findCurrentByCluster(
+        captureLong(new Capture<Long>()))).andReturn(getClusterMockEntities()).anyTimes();
+    
+    replay(m_dao);
+
+    Request request = PropertyHelper.getReadRequest(
+        AlertResourceProvider.ALERT_ID,
+        AlertResourceProvider.ALERT_NAME,
+        AlertResourceProvider.ALERT_LABEL);
+    
+    Predicate predicate = new PredicateBuilder().property(
+        AlertResourceProvider.ALERT_CLUSTER_NAME).equals("c1").toPredicate();
+    
+    AlertResourceProvider provider = createProvider();
+    Set<Resource> results = provider.getResources(request, predicate);
+
+    assertEquals(1, results.size());
+
+    Resource r = results.iterator().next();
+    assertEquals("c1", r.getPropertyValue(AlertResourceProvider.ALERT_CLUSTER_NAME));
+    
+    verify(m_dao);
+  }
+  
+  /**
+   * Test for service
+   */
+  @Test
+  public void testGetService() throws Exception {
+    expect(m_dao.findCurrentByService(captureLong(new Capture<Long>()),
+        capture(new Capture<String>()))).andReturn(getClusterMockEntities()).anyTimes();
+    
+    replay(m_dao);
+
+    Request request = PropertyHelper.getReadRequest(
+        AlertResourceProvider.ALERT_ID,
+        AlertResourceProvider.ALERT_NAME,
+        AlertResourceProvider.ALERT_LABEL);
+    
+    Predicate predicate = new PredicateBuilder().property(
+        AlertResourceProvider.ALERT_CLUSTER_NAME).equals("c1").and()
+        .property(AlertResourceProvider.ALERT_SERVICE).equals(ALERT_VALUE_SERVICE).toPredicate();
+    
+    AlertResourceProvider provider = createProvider();
+    Set<Resource> results = provider.getResources(request, predicate);
+
+    assertEquals(1, results.size());
+
+    Resource r = results.iterator().next();
+    assertEquals("c1", r.getPropertyValue(AlertResourceProvider.ALERT_CLUSTER_NAME));
+    assertEquals(ALERT_VALUE_SERVICE, r.getPropertyValue(AlertResourceProvider.ALERT_SERVICE));
+    
+    verify(m_dao);
+  }  
+
+  /**
+   * Test for service
+   */
+  @Test
+  public void testGetHost() throws Exception {
+    expect(m_dao.findCurrentByHost(captureLong(new Capture<Long>()),
+        capture(new Capture<String>()))).andReturn(getClusterMockEntities()).anyTimes();
+    
+    replay(m_dao);
+
+    Request request = PropertyHelper.getReadRequest(
+        AlertResourceProvider.ALERT_ID,
+        AlertResourceProvider.ALERT_NAME,
+        AlertResourceProvider.ALERT_LABEL);
+    
+    Predicate predicate = new PredicateBuilder().property(
+        AlertResourceProvider.ALERT_CLUSTER_NAME).equals("c1").and()
+        .property(AlertResourceProvider.ALERT_HOST).equals(ALERT_VALUE_HOSTNAME).toPredicate();
+    
+    AlertResourceProvider provider = createProvider();
+    Set<Resource> results = provider.getResources(request, predicate);
+
+    assertEquals(1, results.size());
+
+    Resource r = results.iterator().next();
+    assertEquals("c1", r.getPropertyValue(AlertResourceProvider.ALERT_CLUSTER_NAME));
+    assertEquals(ALERT_VALUE_HOSTNAME, r.getPropertyValue(AlertResourceProvider.ALERT_HOST));
+    
+    verify(m_dao);
+  }  
+
+  
+  
+  private AlertResourceProvider createProvider() {
+    return new AlertResourceProvider(
+        PropertyHelper.getPropertyIds(Resource.Type.Alert),
+        PropertyHelper.getKeyPropertyIds(Resource.Type.Alert),
+        m_amc);
+  }
+
+  /**
+   * @return
+   */
+  private List<AlertCurrentEntity> getClusterMockEntities() throws Exception {
+    AlertCurrentEntity current = new AlertCurrentEntity();
+    current.setAlertId(Long.valueOf(1000L));
+    current.setLatestTimestamp(Long.valueOf(1L));
+    current.setOriginalTimestamp(Long.valueOf(2L));
+    
+    AlertHistoryEntity history = new AlertHistoryEntity();
+    history.setAlertId(ALERT_VALUE_ID);
+    history.setAlertInstance(null);
+    history.setAlertLabel(ALERT_VALUE_LABEL);
+    history.setAlertState(AlertState.OK);
+    history.setAlertText(ALERT_VALUE_TEXT);
+    history.setAlertTimestamp(ALERT_VALUE_TIMESTAMP);
+    history.setClusterId(Long.valueOf(1L));
+    history.setComponentName(ALERT_VALUE_COMPONENT);
+    history.setHostName(ALERT_VALUE_HOSTNAME);
+    history.setServiceName(ALERT_VALUE_SERVICE);
+    
+    AlertDefinitionEntity definition = new AlertDefinitionEntity();
+    
+    history.setAlertDefinition(definition);
+    current.setAlertHistory(history);
+    
+    return Arrays.asList(current);
+  }
+
+
+  /**
+  *
+  */
+  private class MockModule implements Module {
+    @Override
+    public void configure(Binder binder) {
+      binder.bind(EntityManager.class).toInstance(EasyMock.createMock(EntityManager.class));
+      binder.bind(AlertsDAO.class).toInstance(EasyMock.createMock(AlertsDAO.class));
+      binder.bind(AmbariManagementController.class).toInstance(createMock(AmbariManagementController.class));
+      
+      Clusters clusters = EasyMock.createNiceMock(Clusters.class);
+      
+      binder.bind(Clusters.class).toInstance(clusters);
+      
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/84c16c5c/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 4500c1c..7c206a2 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
@@ -81,13 +81,13 @@ public class AlertsDAOTest {
       definition.setComponentName(null);
       definition.setClusterId(clusterId);
       definition.setHash(UUID.randomUUID().toString());
-      definition.setScheduleInterval(60);
+      definition.setScheduleInterval(Integer.valueOf(60));
       definition.setScope(Scope.SERVICE);
       definition.setSource("Source " + i);
       definition.setSourceType("SCRIPT");
       definitionDao.create(definition);
     }
-
+    
     List<AlertDefinitionEntity> definitions = definitionDao.findAll();
     assertNotNull(definitions);
     assertEquals(5, definitions.size());
@@ -192,6 +192,54 @@ public class AlertsDAOTest {
     assertNotNull(currentAlerts);
     assertEquals(0, currentAlerts.size());
   }
+  
+  /**
+   * Test looking up current by a host name.
+   */
+  @Test
+  public void testFindCurrentByHost() {
+    // create a host
+    AlertDefinitionEntity hostDef = new AlertDefinitionEntity();
+    hostDef.setDefinitionName("Host Alert Definition ");
+    hostDef.setServiceName("HostService");
+    hostDef.setComponentName(null);
+    hostDef.setClusterId(clusterId);
+    hostDef.setHash(UUID.randomUUID().toString());
+    hostDef.setScheduleInterval(Integer.valueOf(60));
+    hostDef.setScope(Scope.HOST);
+    hostDef.setSource("HostService");
+    hostDef.setSourceType("SCRIPT");
+    definitionDao.create(hostDef);
+    
+    // history for the definition
+    AlertHistoryEntity history = new AlertHistoryEntity();
+    history.setServiceName(hostDef.getServiceName());
+    history.setClusterId(clusterId);
+    history.setAlertDefinition(hostDef);
+    history.setAlertLabel(hostDef.getDefinitionName());
+    history.setAlertText(hostDef.getDefinitionName());
+    history.setAlertTimestamp(Long.valueOf(1L));
+    history.setHostName("h2");
+    history.setAlertState(AlertState.OK);
+    
+    // current for the history
+    AlertCurrentEntity current = new AlertCurrentEntity();
+    current.setOriginalTimestamp(1L);
+    current.setLatestTimestamp(2L);
+    current.setAlertHistory(history);
+    dao.create(current);
+    
+    
+    List<AlertCurrentEntity> currentAlerts = dao.findCurrentByHost(clusterId, history.getHostName());
+
+    assertNotNull(currentAlerts);
+    assertEquals(1, currentAlerts.size());
+
+    currentAlerts = dao.findCurrentByHost(clusterId, "foo");
+
+    assertNotNull(currentAlerts);
+    assertEquals(0, currentAlerts.size());
+  }  
 
   /**
    * 


[38/50] [abbrv] git commit: Merge branch 'trunk' into branch-alerts-dev

Posted by jo...@apache.org.
Merge branch 'trunk' into branch-alerts-dev


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

Branch: refs/heads/trunk
Commit: 73243741b60846264bf6924387719418f04b7089
Parents: 7db82c9 20f112a
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Fri Sep 26 09:47:59 2014 -0700
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Fri Sep 26 09:47:59 2014 -0700

----------------------------------------------------------------------
 .../admin-web/app/views/ambariViews/create.html |   2 +-
 .../admin-web/app/views/ambariViews/edit.html   |   8 +-
 .../resource_management/TestCopyFromLocal.py    |   4 +-
 .../libraries/providers/copy_from_local.py      |   2 +-
 .../controller/AmbariManagementController.java  |  10 +-
 .../AmbariManagementControllerImpl.java         |  40 +-
 .../server/controller/LdapSyncRequest.java      |  94 ++
 .../BlueprintConfigurationProcessor.java        |  60 ++
 .../internal/ControllerResourceProvider.java    |  14 +-
 .../internal/DefaultProviderModule.java         |   2 +-
 .../internal/LdapSyncEventResourceProvider.java | 124 ++-
 .../apache/ambari/server/orm/DBAccessor.java    |   6 +-
 .../ambari/server/orm/DBAccessorImpl.java       |   5 +-
 .../ambari/server/orm/dao/PermissionDAO.java    |   2 +-
 .../orm/entities/LdapSyncEventEntity.java       | 127 ++-
 .../server/orm/entities/LdapSyncSpecEntity.java |  24 +-
 .../server/orm/helpers/dbms/DbmsHelper.java     |   7 +-
 .../server/orm/helpers/dbms/DerbyHelper.java    |   4 +-
 .../orm/helpers/dbms/GenericDbmsHelper.java     |   7 +-
 .../server/orm/helpers/dbms/MySqlHelper.java    |   5 +-
 .../server/orm/helpers/dbms/OracleHelper.java   |   4 +-
 .../server/orm/helpers/dbms/PostgresHelper.java |   4 +-
 .../server/state/cluster/ClusterImpl.java       |  13 +-
 .../server/upgrade/UpgradeCatalog170.java       |  17 +-
 .../HIVE/package/scripts/hive_service.py        |   1 +
 .../HIVE/package/scripts/service_check.py       |   1 +
 .../stacks/HDP/1.3.2/services/stack_advisor.py  |  10 +-
 .../YARN/configuration/capacity-scheduler.xml   |   8 +
 .../scripts/shared_initialization.py            |   5 +-
 .../services/HIVE/configuration/hive-site.xml   |   8 +-
 .../HIVE/package/scripts/hive_service.py        |   4 +-
 .../services/HIVE/package/scripts/params.py     |   2 +-
 .../HIVE/package/scripts/service_check.py       |   1 +
 .../YARN/configuration/capacity-scheduler.xml   |   8 +
 .../stacks/HDP/2.0.6/services/stack_advisor.py  |  10 +-
 .../GLUSTERFS/configuration/core-site.xml       |  11 -
 .../YARN/configuration/capacity-scheduler.xml   |   7 +
 .../FALCON/configuration/oozie-site.xml         |   9 +
 .../stacks/HDP/2.1/services/FLUME/metainfo.xml  |   2 +-
 .../services/OOZIE/configuration/oozie-site.xml |  11 -
 .../YARN/configuration/capacity-scheduler.xml   |   7 +
 .../stacks/HDP/2.1/services/stack_advisor.py    |  39 +-
 .../resources/stacks/HDP/2.2.1/metainfo.xml     |  23 -
 .../stacks/HDP/2.2.1/repos/repoinfo.xml         |  67 --
 .../stacks/HDP/2.2.1/role_command_order.json    |  85 --
 .../HDP/2.2.1/services/FALCON/metainfo.xml      |  26 -
 .../HDP/2.2.1/services/FLUME/metainfo.xml       |  26 -
 .../HDP/2.2.1/services/HBASE/metainfo.xml       |  26 -
 .../stacks/HDP/2.2.1/services/HDFS/metainfo.xml |  26 -
 .../stacks/HDP/2.2.1/services/HIVE/metainfo.xml |  26 -
 .../HDP/2.2.1/services/OOZIE/metainfo.xml       |  26 -
 .../stacks/HDP/2.2.1/services/PIG/metainfo.xml  |  26 -
 .../HDP/2.2.1/services/SQOOP/metainfo.xml       |  26 -
 .../HDP/2.2.1/services/STORM/metainfo.xml       |  27 -
 .../services/TEZ/configuration/tez-site.xml     |  29 -
 .../stacks/HDP/2.2.1/services/TEZ/metainfo.xml  |  26 -
 .../stacks/HDP/2.2.1/services/YARN/metainfo.xml |  39 -
 .../HDP/2.2.1/services/ZOOKEEPER/metainfo.xml   |  26 -
 .../resources/stacks/HDP/2.2/repos/repoinfo.xml |  32 +-
 .../stacks/HDP/2.2/services/FALCON/metainfo.xml |   2 +-
 .../stacks/HDP/2.2/services/FLUME/metainfo.xml  |   4 +-
 .../stacks/HDP/2.2/services/HBASE/metainfo.xml  |   4 +-
 .../services/HDFS/configuration/hadoop-env.xml  |   2 +-
 .../stacks/HDP/2.2/services/HDFS/metainfo.xml   |   6 +-
 .../stacks/HDP/2.2/services/HIVE/metainfo.xml   |   8 +-
 .../stacks/HDP/2.2/services/OOZIE/metainfo.xml  |   6 +-
 .../stacks/HDP/2.2/services/PIG/metainfo.xml    |   4 +-
 .../stacks/HDP/2.2/services/SLIDER/metainfo.xml |  16 +
 .../stacks/HDP/2.2/services/SQOOP/metainfo.xml  |   4 +-
 .../stacks/HDP/2.2/services/STORM/metainfo.xml  |   4 +-
 .../stacks/HDP/2.2/services/TEZ/metainfo.xml    |   4 +-
 .../stacks/HDP/2.2/services/YARN/metainfo.xml   |  10 +-
 .../HDP/2.2/services/ZOOKEEPER/metainfo.xml     |   4 +-
 .../src/main/resources/stacks/stack_advisor.py  |  90 +-
 .../AmbariManagementControllerImplTest.java     | 154 ++-
 .../server/controller/LdapSyncRequestTest.java  |  84 ++
 .../BlueprintConfigurationProcessorTest.java    |   9 +
 .../LdapSyncEventResourceProviderTest.java      |  28 +-
 .../ambari/server/orm/DBAccessorImplTest.java   |   6 +-
 .../orm/entities/LdapSyncEventEntityTest.java   |  47 +-
 .../orm/entities/LdapSyncSpecEntityTest.java    |  40 +-
 .../server/state/cluster/ClusterTest.java       |   5 +
 .../stacks/2.0.6/HIVE/test_hive_metastore.py    |   8 +-
 .../stacks/2.0.6/HIVE/test_hive_server.py       |   8 +-
 .../stacks/2.0.6/common/test_stack_advisor.py   |  12 +-
 .../stacks/2.1/HIVE/test_hive_metastore.py      |   8 +-
 ambari-web/app/assets/test/tests.js             |   1 +
 ambari-web/app/config.js                        |   2 +-
 ambari-web/app/controllers/installer.js         | 253 ++---
 ambari-web/app/controllers/main/host/details.js |  14 +-
 ambari-web/app/controllers/wizard.js            |  30 +-
 .../app/controllers/wizard/step1_controller.js  |  12 +-
 .../app/controllers/wizard/step7_controller.js  |   6 +-
 .../app/controllers/wizard/step8_controller.js  |  56 +-
 ambari-web/app/data/HDP2/site_properties.js     |  30 +-
 ambari-web/app/data/site_properties.js          |  18 -
 ambari-web/app/mappers.js                       |   1 +
 ambari-web/app/mappers/stack_mapper.js          | 114 +++
 ambari-web/app/mappers/stack_service_mapper.js  |   2 +
 ambari-web/app/messages.js                      |   6 +-
 ambari-web/app/models.js                        |   3 +
 ambari-web/app/models/config_group.js           |  15 +-
 ambari-web/app/models/operating_system.js       |  33 +
 ambari-web/app/models/repository.js             |  67 ++
 ambari-web/app/models/service_config.js         |  15 +-
 ambari-web/app/models/stack.js                  |  70 ++
 ambari-web/app/models/stack_service.js          |   1 +
 ambari-web/app/routes/installer.js              |  32 +-
 ambari-web/app/styles/application.less          |   2 +-
 ambari-web/app/templates/wizard/step1.hbs       |  14 +-
 ambari-web/app/utils/components.js              |  12 +
 ambari-web/app/utils/date.js                    |   6 +-
 .../views/common/configs/config_history_flow.js |   3 +
 ambari-web/app/views/common/filter_view.js      |  20 +-
 ambari-web/app/views/common/table_view.js       |   1 +
 .../views/main/dashboard/config_history_view.js |   1 +
 ambari-web/app/views/main/dashboard/widgets.js  |   6 +
 .../dashboard/widgets/uptime_text_widget.js     |   2 +-
 ambari-web/app/views/wizard/step1_view.js       | 214 ++---
 ambari-web/test/controllers/installer_test.js   |  47 +-
 .../main/service/info/config_test.js            |  61 +-
 .../test/controllers/wizard/step7_test.js       |  46 +-
 .../test/controllers/wizard/step8_test.js       |  56 --
 ambari-web/test/mappers/stack_mapper_test.js    | 285 ++++++
 ambari-web/test/models/run_test.js              |  10 -
 ambari-web/test/stack.js                        | 265 ++++++
 ambari-web/test/utils/date_test.js              |  40 -
 ambari-web/test/utils/helper_test.js            |   4 +-
 ambari-web/test/views/wizard/step1_view_test.js | 633 +++++--------
 .../createAppWizard/step1_controller.js         |  52 +-
 .../createAppWizard/step2_controller.js         |  31 +-
 .../app/controllers/slider_apps_controller.js   |  15 +-
 .../ui/app/controllers/slider_controller.js     |   1 +
 .../src/main/resources/ui/app/helpers/ajax.js   |   7 +-
 .../src/main/resources/ui/app/initialize.js     |   7 +-
 .../ui/app/mappers/slider_apps_mapper.js        |  39 +-
 .../resources/ui/app/mixins/run_periodically.js |  37 +-
 .../ui/app/routes/create_app_wizard.js          |  19 +
 .../src/main/resources/ui/app/styles/app.less   | 276 ++++++
 .../resources/ui/app/styles/application.less    | 941 +------------------
 .../resources/ui/app/styles/application.styl    |   3 -
 .../resources/ui/app/styles/apps-table.less     | 320 +++++++
 .../main/resources/ui/app/styles/common.less    | 102 ++
 .../resources/ui/app/styles/old-bootstrap.less  | 164 ++++
 .../main/resources/ui/app/styles/wizard.less    | 205 ++++
 .../resources/ui/app/templates/application.hbs  |   2 +-
 .../ui/app/templates/createAppWizard.hbs        |   1 +
 .../ui/app/templates/createAppWizard/step1.hbs  | 152 ++-
 .../ui/app/templates/createAppWizard/step2.hbs  |  31 +-
 .../ui/app/templates/createAppWizard/step3.hbs  |   8 +-
 .../ui/app/templates/createAppWizard/step4.hbs  |   4 +-
 .../resources/ui/app/templates/slider_apps.hbs  |   2 +-
 .../ui/app/templates/unavailable_apps.hbs       |  19 +
 .../src/main/resources/ui/app/translations.js   |  26 +-
 .../ui/app/views/common/filter_view.js          |   4 +-
 .../ui/app/views/createAppWizard/step1_view.js  |  47 +-
 .../ui/app/views/createAppWizard/step2_view.js  |  15 +-
 .../ui/app/views/create_app_wizard_view.js      |  10 +
 ...test-patch-find-new-patch-available-jiras.sh |   0
 dev-support/test-patch.sh                       |   0
 160 files changed, 3874 insertions(+), 3043 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/73243741/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/73243741/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
----------------------------------------------------------------------


[11/50] [abbrv] git commit: Merge branch 'trunk' into branch-alerts-dev

Posted by jo...@apache.org.
Merge branch 'trunk' into branch-alerts-dev


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

Branch: refs/heads/trunk
Commit: 03a5be1e193d6ade127fe38cd56d63688b9d5598
Parents: 8697c91 ca2106f
Author: Nate Cole <nc...@hortonworks.com>
Authored: Wed Sep 3 07:38:07 2014 -0400
Committer: Nate Cole <nc...@hortonworks.com>
Committed: Wed Sep 3 07:38:07 2014 -0400

----------------------------------------------------------------------
 .../controllers/ambariViews/ViewsEditCtrl.js    |  1 +
 .../clusters/ClustersManageAccessCtrl.js        |  1 +
 .../controllers/groups/GroupsListCtrl.js        |  2 +-
 .../scripts/controllers/users/UsersListCtrl.js  |  2 +-
 .../scripts/controllers/users/UsersShowCtrl.js  |  2 +-
 .../admin-web/app/views/ambariViews/create.html |  2 +-
 .../admin-web/app/views/ambariViews/edit.html   |  4 +-
 .../app/views/clusters/manageAccess.html        |  4 +-
 .../ui/admin-web/app/views/groups/list.html     |  9 ----
 .../ui/admin-web/app/views/users/show.html      |  2 +-
 .../main/resources/ui/admin-web/package.json    |  2 +-
 .../stacks/HDP/2.0.6/services/YARN/metainfo.xml |  2 +-
 .../stacks/HDP/2.1/services/YARN/metainfo.xml   |  1 +
 ambari-web/app/app.js                           | 15 +++---
 .../app/controllers/global/update_controller.js |  3 +-
 .../main/admin/serviceAccounts_controller.js    | 17 ++++--
 .../controllers/main/service/info/configs.js    |  7 +--
 ambari-web/app/data/secure_properties.js        |  1 +
 ambari-web/app/models/service_config.js         |  9 +++-
 ambari-web/app/views/main/service/item.js       |  2 +-
 ambari-web/test/app_test.js                     | 55 --------------------
 .../admin/serviceAccounts_controller_test.js    | 24 ---------
 22 files changed, 49 insertions(+), 118 deletions(-)
----------------------------------------------------------------------



[47/50] [abbrv] git commit: Merge branch 'trunk' into branch-alerts-dev

Posted by jo...@apache.org.
Merge branch 'trunk' into branch-alerts-dev


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

Branch: refs/heads/trunk
Commit: 445a53cf5bcbba89ff04131d9802e205bfc3ab42
Parents: 3e54f95 e069b30
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Fri Oct 3 23:15:57 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Fri Oct 3 23:15:57 2014 -0400

----------------------------------------------------------------------
 ambari-admin/pom.xml                            |   19 +-
 .../main/resources/ui/admin-web/app/index.html  |    4 +-
 .../resources/ui/admin-web/app/scripts/app.js   |    1 -
 .../app/scripts/controllers/NavbarCtrl.js       |    8 +-
 .../ambariViews/CreateViewInstanceCtrl.js       |    8 +-
 .../controllers/ambariViews/ViewsEditCtrl.js    |   22 +-
 .../controllers/ambariViews/ViewsListCtrl.js    |    5 +-
 .../clusters/ClustersManageAccessCtrl.js        |    6 +-
 .../controllers/groups/GroupsCreateCtrl.js      |    7 +-
 .../controllers/groups/GroupsEditCtrl.js        |   34 +-
 .../app/scripts/controllers/mainCtrl.js         |   17 +-
 .../controllers/users/UsersCreateCtrl.js        |    7 +-
 .../scripts/controllers/users/UsersShowCtrl.js  |   49 +-
 .../ui/admin-web/app/scripts/services/Alert.js  |  106 ++
 .../ui/admin-web/app/scripts/services/Auth.js   |    9 +-
 .../ui/admin-web/app/scripts/services/Group.js  |    2 +-
 .../app/scripts/services/PermissionLoader.js    |    8 +-
 .../ui/admin-web/app/scripts/services/User.js   |    2 +-
 .../admin-web/app/scripts/services/uiAlert.js   |  115 --
 .../resources/ui/admin-web/app/styles/main.css  |   96 ++
 .../admin-web/app/views/ambariViews/edit.html   |    2 +-
 .../src/main/resources/ui/admin-web/bower.json  |   15 +-
 .../main/resources/ui/admin-web/package.json    |   19 +
 .../resources/ui/admin-web/test/e2e/signout.js  |   43 +
 .../resources/ui/admin-web/test/karma.conf.js   |   58 +
 .../ui/admin-web/test/protractor-conf.js        |   51 +
 .../resources/ui/admin-web/test/spec/test.js    |   30 -
 .../test/unit/controllers/mainCtrl_test.js      |   54 +
 .../resource_management/TestFileSystem.py       |  117 ++
 .../python/resource_management/core/logger.py   |   18 +-
 .../resource_management/core/providers/mount.py |   86 +-
 .../libraries/functions/dfs_datanode_helper.py  |  149 +++
 .../libraries/functions/file_system.py          |   72 ++
 ambari-server/pom.xml                           |    9 +
 .../internal/AbstractProviderModule.java        |   24 +-
 .../BlueprintConfigurationProcessor.java        |    4 +
 .../controller/internal/ResourceImpl.java       |   19 +-
 .../internal/StackDefinedPropertyProvider.java  |  227 ++--
 .../server/controller/jmx/JMXHostProvider.java  |   13 -
 .../controller/jmx/JMXPropertyProvider.java     |  274 +----
 .../controller/metrics/MetricsHostProvider.java |   38 +
 .../controller/metrics/MetricsProvider.java     |  302 +++++
 .../metrics/RestMetricsPropertyProvider.java    |  448 ++++++++
 .../apache/ambari/server/view/ViewRegistry.java |    2 +-
 .../src/main/package/deb/control/preinst        |    8 +
 .../src/main/package/rpm/preinstall.sh          |    8 +
 ambari-server/src/main/python/ambari-server.py  |    6 +-
 .../YARN/configuration/capacity-scheduler.xml   |    2 +-
 .../0.8/services/YARN/package/scripts/yarn.py   |    9 +-
 .../services/HDFS/configuration/hadoop-env.xml  |    6 +
 .../HDFS/package/scripts/hdfs_datanode.py       |   38 +-
 .../services/HDFS/package/scripts/params.py     |    2 +
 .../configuration/capacity-scheduler.xml        |    2 +-
 .../YARN/configuration/capacity-scheduler.xml   |    2 +-
 .../services/YARN/package/scripts/yarn.py       |   19 +-
 .../HBASE/package/scripts/hbase_decommission.py |   62 +-
 .../services/HBASE/package/scripts/params.py    |    2 +-
 .../services/HDFS/configuration/hadoop-env.xml  |    7 +-
 .../HDFS/package/scripts/hdfs_datanode.py       |   27 +-
 .../services/HDFS/package/scripts/params.py     |   12 +-
 .../services/HDFS/package/scripts/utils.py      |   91 +-
 .../2.0.6/services/HIVE/package/scripts/hive.py |   30 +-
 .../YARN/configuration/capacity-scheduler.xml   |    2 +-
 .../2.0.6/services/YARN/package/scripts/yarn.py |    9 +-
 .../templates/zookeeper_client_jaas.conf.j2     |    1 -
 .../stacks/HDP/2.0.6/services/stack_advisor.py  |   27 +-
 .../YARN/configuration/capacity-scheduler.xml   |    2 +-
 .../services/YARN/package/scripts/yarn.py       |   19 +-
 .../FALCON/configuration/falcon-env.xml         |    2 +-
 .../services/FALCON/package/scripts/falcon.py   |    6 +-
 .../package/templates/startup.properties.j2     |   89 --
 .../stacks/HDP/2.1/services/STORM/metrics.json  |   55 +-
 .../YARN/configuration/capacity-scheduler.xml   |    2 +-
 .../stacks/HDP/2.1/services/stack_advisor.py    |    4 +-
 .../configuration/falcon-startup.properties.xml |   84 ++
 .../services/HDFS/configuration/hadoop-env.xml  |  192 ++++
 .../services/HIVE/configuration/hive-site.xml   |   29 +
 .../stacks/HDP/2.2/services/SLIDER/metainfo.xml |    2 +-
 .../stacks/HDP/2.2/services/STORM/metrics.json  | 1079 ++++++++++++++++++
 .../stacks/HDP/2.2/services/stack_advisor.py    |  151 +++
 .../api/util/StackExtensionHelperTest.java      |    2 +-
 .../BlueprintConfigurationProcessorTest.java    |    6 +
 .../StackDefinedPropertyProviderTest.java       |  357 +++---
 .../controller/jmx/JMXPropertyProviderTest.java |  513 ---------
 .../metrics/JMXPropertyProviderTest.java        |  522 +++++++++
 .../src/test/python/TestAmbariServer.py         |  123 +-
 .../python/stacks/1.3.2/configs/default.json    |    3 +-
 .../python/stacks/1.3.2/configs/secured.json    |    3 +-
 .../stacks/2.0.6/HBASE/test_hbase_master.py     |    6 +-
 .../python/stacks/2.0.6/HDFS/test_datanode.py   |  136 +++
 .../stacks/2.0.6/HIVE/test_hive_client.py       |   16 +-
 .../stacks/2.0.6/HIVE/test_hive_metastore.py    |   52 +-
 .../stacks/2.0.6/HIVE/test_hive_server.py       |   52 +-
 .../stacks/2.0.6/YARN/test_historyserver.py     |   30 -
 .../stacks/2.0.6/YARN/test_mapreduce2_client.py |   30 -
 .../stacks/2.0.6/YARN/test_nodemanager.py       |   60 +-
 .../stacks/2.0.6/YARN/test_resourcemanager.py   |   30 -
 .../stacks/2.0.6/YARN/test_yarn_client.py       |   50 -
 .../python/stacks/2.0.6/configs/default.json    |    3 +-
 .../python/stacks/2.0.6/configs/secured.json    |    3 +-
 .../stacks/2.1/FALCON/test_falcon_server.py     |    2 +
 .../stacks/2.1/HIVE/test_hive_metastore.py      |   52 +-
 .../stacks/2.1/YARN/test_apptimelineserver.py   |   20 -
 .../stacks/2.2/common/test_stack_advisor.py     |  311 +++++
 .../src/test/python/stacks/utils/RMFTestCase.py |   19 +-
 .../YARN/configuration/capacity-scheduler.xml   |    2 +-
 .../HDP/2.1.1/services/STORM/metrics.json       |  209 ++--
 ambari-web/app/assets/test/tests.js             |    1 +
 ambari-web/app/controllers/installer.js         |    7 +-
 .../app/controllers/main/admin/repositories.js  |    7 +-
 .../main/dashboard/config_history_controller.js |    2 +-
 ambari-web/app/controllers/main/host.js         |    4 +-
 ambari-web/app/controllers/main/host/details.js |  281 +++--
 ambari-web/app/controllers/main/service/item.js |    3 +-
 .../app/controllers/main/views_controller.js    |    3 +
 ambari-web/app/data/HDP2/site_properties.js     |   17 +-
 ambari-web/app/data/site_properties.js          |   17 +-
 .../mappers/service_config_version_mapper.js    |   23 +
 ambari-web/app/messages.js                      |    2 +-
 ambari-web/app/models/service_config_version.js |    4 +-
 ambari-web/app/router.js                        |   15 +-
 ambari-web/app/routes/installer.js              |    2 +-
 ambari-web/app/styles/application.less          |    2 +-
 ambari-web/app/templates/main/host/configs.hbs  |   22 +-
 ambari-web/app/utils/config.js                  |    6 +-
 ambari-web/app/views/main/host/configs.js       |    6 +-
 .../app/views/main/host/configs_service_menu.js |   37 +-
 ambari-web/package.json                         |   47 +-
 ambari-web/pom.xml                              |   28 +-
 .../controllers/main/admin/repositories_test.js |   17 +-
 .../dashboard/config_history_controller_test.js |    8 +-
 .../test/controllers/main/host/details_test.js  |   51 +
 .../controllers/main/views_controller_test.js   |   48 +
 .../test/controllers/wizard/step9_test.js       |   26 +-
 ambari-web/test/views/application_test.js       |    2 +-
 .../view/filebrowser/FileOperationService.java  |   37 +
 .../apache/ambari/view/filebrowser/HdfsApi.java |   21 +
 .../files/src/main/resources/ui/app/adapter.js  |   59 +-
 .../resources/ui/app/components/breadCrumbs.js  |   47 +
 .../resources/ui/app/components/bsPopover.js    |   21 +
 .../resources/ui/app/components/bulkCheckbox.js |   40 +
 .../resources/ui/app/components/chmodInput.js   |   79 ++
 .../ui/app/components/confirmDelete.js          |   59 +
 .../resources/ui/app/components/contextMenu.js  |   36 +-
 .../resources/ui/app/components/mkdirInput.js   |   45 +
 .../ui/app/components/popoverDelete.js          |   50 +
 .../resources/ui/app/components/renameInput.js  |    7 +-
 .../resources/ui/app/components/sortArrow.js    |   39 +
 .../ui/app/components/toggleContext.js          |   56 +
 .../resources/ui/app/components/uploader.js     |   13 +-
 .../main/resources/ui/app/controllers/error.js  |    5 +-
 .../main/resources/ui/app/controllers/file.js   |  104 +-
 .../main/resources/ui/app/controllers/files.js  |  103 +-
 .../resources/ui/app/controllers/filesAlert.js  |   10 +
 .../src/main/resources/ui/app/initialize.js     |   24 +-
 .../src/main/resources/ui/app/routes/file.js    |    3 +
 .../resources/ui/app/styles/application.less    |   67 +-
 .../ui/app/templates/components/chmodInput.hbs  |  100 ++
 .../ui/app/templates/components/contextMenu.hbs |   43 +
 .../ui/app/templates/components/deleteBulk.hbs  |   46 +
 .../app/templates/components/deletePopover.hbs  |   38 +
 .../ui/app/templates/components/mkdirInput.hbs  |   37 +
 .../ui/app/templates/components/renameInput.hbs |   38 +
 .../ui/app/templates/components/uploader.hbs    |   35 +
 .../main/resources/ui/app/templates/files.hbs   |  229 ++--
 .../ui/app/templates/util/contextMenu.hbs       |   56 -
 .../ui/app/templates/util/deleteBulk.hbs        |   38 -
 .../ui/app/templates/util/deletePopover.hbs     |   38 -
 .../resources/ui/app/templates/util/fileRow.hbs |   84 ++
 .../ui/app/templates/util/renameInput.hbs       |   38 -
 .../ui/app/templates/util/uploader.hbs          |   35 -
 .../src/main/resources/ui/app/views/file.js     |  182 +--
 .../main/resources/ui/app/views/filesAlert.js   |   23 +
 .../files/src/main/resources/ui/bower.json      |   10 +-
 .../main/resources/ui/vendor/js/bsPopover.js    |  190 +++
 contrib/views/files/src/main/resources/view.xml |    2 +-
 .../resources/ui/app/scripts/helpers/ajax.js    |    6 +
 .../resources/ui/app/scripts/helpers/jobs.js    |    3 +
 .../view/slider/SliderAppsViewController.java   |   19 +-
 .../slider/SliderAppsViewControllerImpl.java    |  245 +++-
 .../apache/ambari/view/slider/ViewStatus.java   |   40 +
 .../slider/rest/client/AmbariHttpClient.java    |   72 +-
 .../data/resource/slider-properties-2.json      |    8 +
 .../src/main/resources/ui/app/assets/index.html |    9 -
 .../app/controllers/application_controller.js   |   27 +
 .../createAppWizard/step3_controller.js         |    9 +-
 .../ui/app/controllers/slider_app_controller.js |    7 +
 .../app/controllers/slider_apps_controller.js   |    2 +-
 .../ui/app/controllers/slider_controller.js     |   50 +-
 .../src/main/resources/ui/app/helpers/ajax.js   |   20 +
 .../src/main/resources/ui/app/helpers/helper.js |   10 +-
 .../src/main/resources/ui/app/initialize.js     |   11 +-
 .../ui/app/mappers/slider_apps_mapper.js        |    3 +
 .../main/resources/ui/app/mixins/with_panels.js |    5 +-
 .../main/resources/ui/app/models/slider_app.js  |    3 +
 .../resources/ui/app/models/slider_config.js    |   14 +-
 .../src/main/resources/ui/app/routes/main.js    |   19 +-
 .../main/resources/ui/app/styles/common.less    |   11 +
 .../main/resources/ui/app/styles/wizard.less    |   19 +-
 .../resources/ui/app/templates/application.hbs  |   27 +-
 .../ui/app/templates/createAppWizard/step1.hbs  |   60 +-
 .../ui/app/templates/slider_app/configs.hbs     |   32 +-
 .../ui/app/templates/slider_app/summary.hbs     |    7 -
 .../src/main/resources/ui/app/translations.js   |   25 +-
 .../resources/ui/app/views/application_view.js  |    7 +-
 .../ui/app/views/createAppWizard/step1_view.js  |    3 +-
 .../ui/app/views/create_app_wizard_view.js      |    2 +
 .../ui/app/views/slider_app/configs_view.js     |    7 +-
 .../ui/app/views/slider_app/summary_view.js     |    7 -
 .../ui/test/integration/pages/index_test.js     |    9 +-
 .../integration/pages/slider_errors_test.js     |   46 +
 .../processes/create_new_app_test.js            |  199 ++++
 .../views/slider/src/main/resources/view.xml    |  117 +-
 docs/pom.xml                                    |   16 +-
 214 files changed, 8147 insertions(+), 3203 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/445a53cf/ambari-server/pom.xml
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/445a53cf/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java
----------------------------------------------------------------------
diff --cc ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java
index f50955c,b5164fe..da6c886
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java
@@@ -41,25 -29,20 +41,26 @@@ import org.apache.ambari.server.control
  import org.apache.ambari.server.controller.ganglia.GangliaComponentPropertyProvider;
  import org.apache.ambari.server.controller.ganglia.GangliaHostComponentPropertyProvider;
  import org.apache.ambari.server.controller.ganglia.GangliaHostPropertyProvider;
 -import org.apache.ambari.server.controller.ganglia.GangliaReportPropertyProvider;
  import org.apache.ambari.server.controller.ganglia.GangliaHostProvider;
 +import org.apache.ambari.server.controller.ganglia.GangliaReportPropertyProvider;
  import org.apache.ambari.server.controller.jmx.JMXHostProvider;
  import org.apache.ambari.server.controller.jmx.JMXPropertyProvider;
+ import org.apache.ambari.server.controller.metrics.MetricsHostProvider;
  import org.apache.ambari.server.controller.nagios.NagiosPropertyProvider;
 -import org.apache.ambari.server.controller.spi.*;
 +import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
 +import org.apache.ambari.server.controller.spi.NoSuchResourceException;
 +import org.apache.ambari.server.controller.spi.Predicate;
 +import org.apache.ambari.server.controller.spi.PropertyProvider;
 +import org.apache.ambari.server.controller.spi.ProviderModule;
 +import org.apache.ambari.server.controller.spi.Request;
 +import org.apache.ambari.server.controller.spi.Resource;
 +import org.apache.ambari.server.controller.spi.ResourceProvider;
 +import org.apache.ambari.server.controller.spi.SystemException;
 +import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
  import org.apache.ambari.server.controller.utilities.PredicateBuilder;
  import org.apache.ambari.server.controller.utilities.PropertyHelper;
 -import org.apache.ambari.server.controller.AmbariManagementController;
 -
 -import com.google.inject.Inject;
 -
  import org.apache.ambari.server.controller.utilities.StreamProvider;
 +import org.apache.ambari.server.state.Cluster;
  import org.apache.ambari.server.state.DesiredConfig;
  import org.apache.ambari.server.state.HostState;
  import org.apache.ambari.server.state.Service;

http://git-wip-us.apache.org/repos/asf/ambari/blob/445a53cf/ambari-web/app/controllers/main/host.js
----------------------------------------------------------------------


[07/50] [abbrv] git commit: AMBARI-7094 - Alerts: Implement Property Updates for Alert Targets (jonathanhurley)

Posted by jo...@apache.org.
AMBARI-7094 - Alerts: Implement Property Updates for Alert Targets (jonathanhurley)


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

Branch: refs/heads/trunk
Commit: 2f5c78e7f90f575ab2c469da1095eaa5d252d872
Parents: 52d1af7
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Sun Aug 31 08:25:14 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Sun Aug 31 08:25:14 2014 -0400

----------------------------------------------------------------------
 .../resources/AlertDefResourceDefinition.java   |   3 -
 .../server/api/services/AlertTargetService.java |  10 ++
 .../services/parsers/JsonRequestBodyParser.java |  14 +-
 .../internal/AlertTargetResourceProvider.java   | 134 ++++++++++++++++--
 .../ambari/server/state/ConfigFactory.java      |   2 -
 .../ambari/server/state/alert/AlertTarget.java  |  10 +-
 .../AlertTargetResourceProviderTest.java        | 140 +++++++++++++------
 7 files changed, 249 insertions(+), 64 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/2f5c78e7/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertDefResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertDefResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertDefResourceDefinition.java
index 1a63097..66e5a83 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertDefResourceDefinition.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertDefResourceDefinition.java
@@ -21,8 +21,6 @@ import org.apache.ambari.server.controller.spi.Resource;
 
 /**
  * Resource Definition for AlertDefinition types.
- * @author ncole
- *
  */
 public class AlertDefResourceDefinition extends BaseResourceDefinition {
 
@@ -32,7 +30,6 @@ public class AlertDefResourceDefinition extends BaseResourceDefinition {
   
   @Override
   public String getPluralName() {
-    // TODO Auto-generated method stub
     return "alert_definitions";
   }
   

http://git-wip-us.apache.org/repos/asf/ambari/blob/2f5c78e7/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertTargetService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertTargetService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertTargetService.java
index 86281b3..2a2ecdf 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertTargetService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertTargetService.java
@@ -23,6 +23,7 @@ import java.util.Map;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
@@ -67,6 +68,15 @@ public class AlertTargetService extends BaseService {
         createAlertTargetResource(null));
   }
 
+  @PUT
+  @Produces("text/plain")
+  @Path("{targetId}")
+  public Response updateGroup(String body, @Context HttpHeaders headers,
+      @Context UriInfo ui, @PathParam("targetId") Long targetId) {
+    return handleRequest(headers, body, ui, Request.Type.PUT,
+        createAlertTargetResource(targetId));
+  }
+
   @DELETE
   @Produces("text/plain")
   @Path("{targetId}")

http://git-wip-us.apache.org/repos/asf/ambari/blob/2f5c78e7/ambari-server/src/main/java/org/apache/ambari/server/api/services/parsers/JsonRequestBodyParser.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/parsers/JsonRequestBodyParser.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/parsers/JsonRequestBodyParser.java
index 59dd1af..bbe7647 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/parsers/JsonRequestBodyParser.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/parsers/JsonRequestBodyParser.java
@@ -18,6 +18,15 @@
 
 package org.apache.ambari.server.api.services.parsers;
 
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
 import org.apache.ambari.server.api.services.NamedPropertySet;
 import org.apache.ambari.server.api.services.RequestBody;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
@@ -26,9 +35,6 @@ import org.codehaus.jackson.map.ObjectMapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.IOException;
-import java.util.*;
-
 /**
  * JSON parser which parses a JSON string into a map of properties and values.
  */
@@ -120,7 +126,7 @@ public class JsonRequestBodyParser implements RequestBodyParser {
 
           if (next.isValueNode()) {
             // All remain nodes will be also primitives
-            primitives.add(next.getTextValue());
+            primitives.add(next.asText());
           } else {
             NamedPropertySet arrayPropertySet = new NamedPropertySet(name,
                 new HashMap<String, Object>());

http://git-wip-us.apache.org/repos/asf/ambari/blob/2f5c78e7/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProvider.java
index e00f60f..f2b82d6 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProvider.java
@@ -17,11 +17,13 @@
  */
 package org.apache.ambari.server.controller.internal;
 
+import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 
 import org.apache.ambari.server.AmbariException;
@@ -36,11 +38,14 @@ import org.apache.ambari.server.controller.spi.Resource.Type;
 import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
 import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
 import org.apache.ambari.server.orm.dao.AlertDispatchDAO;
 import org.apache.ambari.server.orm.entities.AlertTargetEntity;
 import org.apache.ambari.server.state.alert.AlertTarget;
 import org.apache.commons.lang.StringUtils;
 
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
 import com.google.inject.Inject;
 import com.google.inject.Injector;
 
@@ -70,6 +75,11 @@ public class AlertTargetResourceProvider extends
   private static AlertDispatchDAO s_dao;
 
   /**
+   * Used for serializationa and deserialization of some fields.
+   */
+  private static final Gson s_gson = new Gson();
+
+  /**
    * Initializes the injectable members of this class with the specified
    * injector.
    *
@@ -143,11 +153,21 @@ public class AlertTargetResourceProvider extends
   }
 
   @Override
-  public RequestStatus updateResources(Request request, Predicate predicate)
+  public RequestStatus updateResources(final Request request,
+      Predicate predicate)
       throws SystemException, UnsupportedPropertyException,
       NoSuchResourceException, NoSuchParentResourceException {
 
-    throw new UnsupportedOperationException();
+    modifyResources(new Command<Void>() {
+      @Override
+      public Void invoke() throws AmbariException {
+        updateAlertTargets(request.getProperties());
+        return null;
+      }
+    });
+
+    notifyUpdate(Resource.Type.AlertTarget, request, predicate);
+    return getRequestStatus(null);
   }
 
   @Override
@@ -203,7 +223,6 @@ public class AlertTargetResourceProvider extends
       String name = (String) requestMap.get(ALERT_TARGET_NAME);
       String description = (String) requestMap.get(ALERT_TARGET_DESCRIPTION);
       String notificationType = (String) requestMap.get(ALERT_TARGET_NOTIFICATION_TYPE);
-      String properties = (String) requestMap.get(ALERT_TARGET_PROPERTIES);
 
       if (StringUtils.isEmpty(name)) {
         throw new IllegalArgumentException(
@@ -215,6 +234,12 @@ public class AlertTargetResourceProvider extends
             "The type of the alert target is required.");
       }
 
+      String properties = extractProperties(requestMap);
+      if (StringUtils.isEmpty(properties)) {
+        throw new IllegalArgumentException(
+            "Alert targets must be created with their connection properties");
+      }
+
       entity.setDescription(description);
       entity.setNotificationType(notificationType);
       entity.setProperties(properties);
@@ -227,10 +252,65 @@ public class AlertTargetResourceProvider extends
   }
 
   /**
+   * Updates existing {@link AlertTargetEntity}s with the specified properties.
+   *
+   * @param requestMaps
+   *          a set of property maps, one map for each entity.
+   * @throws AmbariException
+   *           if the entity could not be found.
+   */
+  private void updateAlertTargets(Set<Map<String, Object>> requestMaps)
+      throws AmbariException {
+
+    for (Map<String, Object> requestMap : requestMaps) {
+      String stringId = (String) requestMap.get(ALERT_TARGET_ID);
+
+      if (StringUtils.isEmpty(stringId)) {
+        throw new IllegalArgumentException(
+            "The ID of the alert target is required when updating an existing target");
+      }
+
+      long id = Long.parseLong(stringId);
+      AlertTargetEntity entity = s_dao.findTargetById(id);
+
+      if (null == entity) {
+        String message = MessageFormat.format(
+            "The alert target with ID {0} could not be found", id);
+        throw new AmbariException(message);
+      }
+
+      String name = (String) requestMap.get(ALERT_TARGET_NAME);
+      String description = (String) requestMap.get(ALERT_TARGET_DESCRIPTION);
+      String notificationType = (String) requestMap.get(ALERT_TARGET_NOTIFICATION_TYPE);
+
+      if (!StringUtils.isBlank(name)) {
+        entity.setTargetName(name);
+      }
+
+      if (null != description) {
+        entity.setDescription(description);
+      }
+
+      if (!StringUtils.isBlank(notificationType)) {
+        entity.setNotificationType(notificationType);
+      }
+
+      String properties = extractProperties(requestMap);
+      if (!StringUtils.isEmpty(properties)) {
+        entity.setProperties(properties);
+      }
+
+      s_dao.merge(entity);
+    }
+  }
+
+  /**
    * Convert the given {@link AlertTargetEntity} to a {@link Resource}.
    *
    * @param isCollection
-   *          {@code true} if the resource is part of a collection.
+   *          {@code true} if the resource is part of a collection. Some
+   *          properties are not returned when a collection of targets is
+   *          requested.
    * @param entity
    *          the entity to convert.
    * @param requestedIds
@@ -244,15 +324,49 @@ public class AlertTargetResourceProvider extends
     resource.setProperty(ALERT_TARGET_ID, entity.getTargetId());
     resource.setProperty(ALERT_TARGET_NAME, entity.getTargetName());
 
-    setResourceProperty(resource, ALERT_TARGET_DESCRIPTION,
-        entity.getDescription(), requestedIds);
+    resource.setProperty(ALERT_TARGET_DESCRIPTION, entity.getDescription());
+    resource.setProperty(ALERT_TARGET_NOTIFICATION_TYPE,
+        entity.getNotificationType());
 
-    setResourceProperty(resource, ALERT_TARGET_NOTIFICATION_TYPE,
-        entity.getNotificationType(), requestedIds);
+    if (!isCollection) {
+      String properties = entity.getProperties();
+      Map<String, String> map = s_gson.<Map<String, String>> fromJson(
+          properties,
+          Map.class);
 
-    setResourceProperty(resource, ALERT_TARGET_PROPERTIES,
-        entity.getProperties(), requestedIds);
+      resource.setProperty(ALERT_TARGET_PROPERTIES, map);
+    }
 
     return resource;
   }
+
+  /**
+   * Looks through the flat list of propery keys in the supplied map and builds
+   * a JSON string of key:value pairs for the {@link #ALERT_TARGET_PROPERTIES}
+   * key.
+   *
+   * @param requestMap
+   *          the map of flattened properties (not {@code null}).
+   * @return the JSON representing the key/value pairs of all properties, or
+   *         {@code null} if none.
+   */
+  private String extractProperties( Map<String, Object> requestMap ){
+    JsonObject jsonObject = new JsonObject();
+    for (Entry<String, Object> entry : requestMap.entrySet()) {
+      String key = entry.getKey();
+      String propCat = PropertyHelper.getPropertyCategory(key);
+
+      if (propCat.equals(ALERT_TARGET_PROPERTIES)) {
+        String propKey = PropertyHelper.getPropertyName(key);
+        jsonObject.addProperty(propKey, entry.getValue().toString());
+      }
+    }
+
+    String properties = null;
+    if (jsonObject.entrySet().size() > 0) {
+      properties = jsonObject.toString();
+    }
+
+    return properties;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/2f5c78e7/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigFactory.java
index 28dfc1c..eaf68aa 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigFactory.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigFactory.java
@@ -25,8 +25,6 @@ import com.google.inject.assistedinject.Assisted;
 
 /**
  * Factory for creating configuration objects using {@link Assisted} constructor parameters
- *
- * @author ncole
  */
 public interface ConfigFactory {
   

http://git-wip-us.apache.org/repos/asf/ambari/blob/2f5c78e7/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertTarget.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertTarget.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertTarget.java
index f495787..2d10dda 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertTarget.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertTarget.java
@@ -17,6 +17,8 @@
  */
 package org.apache.ambari.server.state.alert;
 
+import java.util.Map;
+
 import org.apache.ambari.server.orm.entities.AlertTargetEntity;
 import org.codehaus.jackson.annotate.JsonProperty;
 
@@ -31,7 +33,7 @@ public class AlertTarget {
   private String m_name;
   private String m_description;
   private String m_notificationType;
-  private String m_properties;
+  private Map<String, String> m_properties;
 
   /**
    * @return the id
@@ -101,7 +103,7 @@ public class AlertTarget {
    * @return the properties
    */
   @JsonProperty("properties")
-  public String getProperties() {
+  public Map<String, String> getProperties() {
     return m_properties;
   }
 
@@ -109,7 +111,7 @@ public class AlertTarget {
    * @param properties
    *          the properties to set
    */
-  public void setProperties(String properties) {
+  public void setProperties(Map<String, String> properties) {
     m_properties = properties;
   }
 
@@ -123,8 +125,6 @@ public class AlertTarget {
     target.setDescription(entity.getDescription());
     target.setName(entity.getTargetName());
     target.setNotificationType(entity.getNotificationType());
-    target.setProperties(entity.getProperties());
-
     return target;
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/2f5c78e7/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProviderTest.java
index 6ca2035..1c964a3 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProviderTest.java
@@ -17,6 +17,8 @@
  */
 package org.apache.ambari.server.controller.internal;
 
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
 import static org.easymock.EasyMock.capture;
 import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.createStrictMock;
@@ -25,7 +27,6 @@ import static org.easymock.EasyMock.expectLastCall;
 import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.resetToStrict;
 import static org.easymock.EasyMock.verify;
-import static org.junit.Assert.assertEquals;
 
 import java.util.Arrays;
 import java.util.Collections;
@@ -68,13 +69,17 @@ public class AlertTargetResourceProviderTest {
   private static final String ALERT_TARGET_NAME = "The Administrators";
   private static final String ALERT_TARGET_DESC = "Admins and Others";
   private static final String ALERT_TARGET_TYPE = TargetType.EMAIL.name();
+  private static final String ALERT_TARGET_PROPS = "{\"foo\":\"bar\",\"foobar\":\"baz\"}";
+  private static final String ALERT_TARGET_PROPS2 = "{\"foobar\":\"baz\"}";
 
   private AlertDispatchDAO m_dao;
   private Injector m_injector;
+  private AmbariManagementController m_amc;
 
   @Before
   public void before() {
     m_dao = createStrictMock(AlertDispatchDAO.class);
+    m_amc = createMock(AmbariManagementController.class);
 
     m_injector = Guice.createInjector(Modules.override(
         new InMemoryDefaultTestModule()).with(new MockModule()));
@@ -96,8 +101,7 @@ public class AlertTargetResourceProviderTest {
     expect(m_dao.findAllTargets()).andReturn(getMockEntities());
     replay(m_dao);
 
-    AmbariManagementController amc = createMock(AmbariManagementController.class);
-    AlertTargetResourceProvider provider = createProvider(amc);
+    AlertTargetResourceProvider provider = createProvider(m_amc);
     Set<Resource> results = provider.getResources(request, null);
 
     assertEquals(1, results.size());
@@ -113,6 +117,7 @@ public class AlertTargetResourceProviderTest {
    * @throws Exception
    */
   @Test
+  @SuppressWarnings("unchecked")
   public void testGetSingleResource() throws Exception {
     Request request = PropertyHelper.getReadRequest(
         AlertTargetResourceProvider.ALERT_TARGET_DESCRIPTION,
@@ -120,8 +125,6 @@ public class AlertTargetResourceProviderTest {
         AlertTargetResourceProvider.ALERT_TARGET_NAME,
         AlertTargetResourceProvider.ALERT_TARGET_NOTIFICATION_TYPE);
 
-    AmbariManagementController amc = createMock(AmbariManagementController.class);
-
     Predicate predicate = new PredicateBuilder().property(
         AlertTargetResourceProvider.ALERT_TARGET_ID).equals(
         ALERT_TARGET_ID.toString()).toPredicate();
@@ -129,9 +132,9 @@ public class AlertTargetResourceProviderTest {
     expect(m_dao.findTargetById(ALERT_TARGET_ID.longValue())).andReturn(
         getMockEntities().get(0));
 
-    replay(amc, m_dao);
+    replay(m_amc, m_dao);
 
-    AlertTargetResourceProvider provider = createProvider(amc);
+    AlertTargetResourceProvider provider = createProvider(m_amc);
     Set<Resource> results = provider.getResources(request, predicate);
 
     assertEquals(1, results.size());
@@ -143,7 +146,11 @@ public class AlertTargetResourceProviderTest {
     Assert.assertEquals(ALERT_TARGET_NAME,
         r.getPropertyValue(AlertTargetResourceProvider.ALERT_TARGET_NAME));
 
-    verify(amc, m_dao);
+    Map<String, String> properties = (Map<String, String>) r.getPropertyValue(AlertTargetResourceProvider.ALERT_TARGET_PROPERTIES);
+    assertEquals( "bar", properties.get("foo") );
+    assertEquals( "baz", properties.get("foobar") );
+
+    verify(m_amc, m_dao);
   }
 
   /**
@@ -151,25 +158,15 @@ public class AlertTargetResourceProviderTest {
    */
   @Test
   public void testCreateResources() throws Exception {
-    AmbariManagementController amc = createMock(AmbariManagementController.class);
     Capture<List<AlertTargetEntity>> listCapture = new Capture<List<AlertTargetEntity>>();
 
     m_dao.createTargets(capture(listCapture));
     expectLastCall();
 
-    replay(amc, m_dao);
-
-    AlertTargetResourceProvider provider = createProvider(amc);
-    Map<String, Object> requestProps = new HashMap<String, Object>();
-    requestProps.put(AlertTargetResourceProvider.ALERT_TARGET_NAME,
-        ALERT_TARGET_NAME);
+    replay(m_amc, m_dao);
 
-    requestProps.put(AlertTargetResourceProvider.ALERT_TARGET_DESCRIPTION,
-        ALERT_TARGET_DESC);
-
-    requestProps.put(
-        AlertTargetResourceProvider.ALERT_TARGET_NOTIFICATION_TYPE,
-        ALERT_TARGET_TYPE);
+    AlertTargetResourceProvider provider = createProvider(m_amc);
+    Map<String, Object> requestProps = getCreationProperties();
 
     Request request = PropertyHelper.getCreateRequest(Collections.singleton(requestProps), null);
     provider.createResources(request);
@@ -178,18 +175,63 @@ public class AlertTargetResourceProviderTest {
     AlertTargetEntity entity = listCapture.getValue().get(0);
     Assert.assertNotNull(entity);
 
-    Assert.assertEquals(ALERT_TARGET_NAME, entity.getTargetName());
-    Assert.assertEquals(ALERT_TARGET_DESC, entity.getDescription());
-    Assert.assertEquals(ALERT_TARGET_TYPE, entity.getNotificationType());
+    assertEquals(ALERT_TARGET_NAME, entity.getTargetName());
+    assertEquals(ALERT_TARGET_DESC, entity.getDescription());
+    assertEquals(ALERT_TARGET_TYPE, entity.getNotificationType());
+    assertEquals(ALERT_TARGET_PROPS, entity.getProperties());
 
-    verify(amc, m_dao);
+    verify(m_amc, m_dao);
   }
 
   /**
    * @throws Exception
    */
   @Test
+  @SuppressWarnings("unchecked")
   public void testUpdateResources() throws Exception {
+    Capture<AlertTargetEntity> entityCapture = new Capture<AlertTargetEntity>();
+
+    m_dao.createTargets(EasyMock.anyObject(List.class));
+    expectLastCall().times(1);
+
+    AlertTargetEntity target = new AlertTargetEntity();
+    expect(m_dao.findTargetById(ALERT_TARGET_ID)).andReturn(target).times(1);
+
+    expect(m_dao.merge(capture(entityCapture))).andReturn(target).once();
+
+    replay(m_amc, m_dao);
+
+    AlertTargetResourceProvider provider = createProvider(m_amc);
+    Map<String, Object> requestProps = getCreationProperties();
+    Request request = PropertyHelper.getCreateRequest(
+        Collections.singleton(requestProps), null);
+    provider.createResources(request);
+
+    // create new properties, and include the ID since we're not going through
+    // a service layer which would add it for us automatically
+    requestProps = new HashMap<String, Object>();
+    requestProps.put(AlertTargetResourceProvider.ALERT_TARGET_ID,
+        ALERT_TARGET_ID.toString());
+
+    String newName = ALERT_TARGET_NAME + " Foo";
+    requestProps.put(AlertTargetResourceProvider.ALERT_TARGET_NAME, newName);
+
+    requestProps.put(AlertTargetResourceProvider.ALERT_TARGET_PROPERTIES
+        + "/foobar", "baz");
+
+    Predicate predicate = new PredicateBuilder().property(
+        AlertTargetResourceProvider.ALERT_TARGET_ID).equals(
+        ALERT_TARGET_ID.toString()).toPredicate();
+
+    request = PropertyHelper.getUpdateRequest(requestProps, null);
+    provider.updateResources(request, predicate);
+
+    assertTrue(entityCapture.hasCaptured());
+
+    AlertTargetEntity entity = entityCapture.getValue();
+    assertEquals(newName, entity.getTargetName());
+    assertEquals(ALERT_TARGET_PROPS2, entity.getProperties());
+    verify(m_amc, m_dao);
   }
 
   /**
@@ -197,28 +239,17 @@ public class AlertTargetResourceProviderTest {
    */
   @Test
   public void testDeleteResources() throws Exception {
-    AmbariManagementController amc = createMock(AmbariManagementController.class);
     Capture<AlertTargetEntity> entityCapture = new Capture<AlertTargetEntity>();
     Capture<List<AlertTargetEntity>> listCapture = new Capture<List<AlertTargetEntity>>();
 
     m_dao.createTargets(capture(listCapture));
     expectLastCall();
 
-    replay(amc, m_dao);
+    replay(m_amc, m_dao);
 
-    AlertTargetResourceProvider provider = createProvider(amc);
-
-    Map<String, Object> requestProps = new HashMap<String, Object>();
-    requestProps.put(AlertTargetResourceProvider.ALERT_TARGET_NAME,
-        ALERT_TARGET_NAME);
-
-    requestProps.put(AlertTargetResourceProvider.ALERT_TARGET_DESCRIPTION,
-        ALERT_TARGET_DESC);
-
-    requestProps.put(
-        AlertTargetResourceProvider.ALERT_TARGET_NOTIFICATION_TYPE,
-        ALERT_TARGET_TYPE);
+    AlertTargetResourceProvider provider = createProvider(m_amc);
 
+    Map<String, Object> requestProps = getCreationProperties();
     Request request = PropertyHelper.getCreateRequest(Collections.singleton(requestProps), null);
     provider.createResources(request);
 
@@ -244,7 +275,7 @@ public class AlertTargetResourceProviderTest {
     AlertTargetEntity entity1 = entityCapture.getValue();
     Assert.assertEquals(ALERT_TARGET_ID, entity1.getTargetId());
 
-    verify(amc, m_dao);
+    verify(m_amc, m_dao);
   }
 
   /**
@@ -267,10 +298,39 @@ public class AlertTargetResourceProviderTest {
     entity.setDescription(ALERT_TARGET_DESC);
     entity.setTargetName(ALERT_TARGET_NAME);
     entity.setNotificationType(ALERT_TARGET_TYPE);
+    entity.setProperties(ALERT_TARGET_PROPS);
     return Arrays.asList(entity);
   }
 
   /**
+   * Gets the maps of properties that simulate a deserialzied JSON request to
+   * create an alert target.
+   *
+   * @return
+   * @throws Exception
+   */
+  private Map<String, Object> getCreationProperties() throws Exception {
+    Map<String, Object> requestProps = new HashMap<String, Object>();
+    requestProps.put(AlertTargetResourceProvider.ALERT_TARGET_NAME,
+        ALERT_TARGET_NAME);
+
+    requestProps.put(AlertTargetResourceProvider.ALERT_TARGET_DESCRIPTION,
+        ALERT_TARGET_DESC);
+
+    requestProps.put(
+        AlertTargetResourceProvider.ALERT_TARGET_NOTIFICATION_TYPE,
+        ALERT_TARGET_TYPE);
+
+    requestProps.put(AlertTargetResourceProvider.ALERT_TARGET_PROPERTIES
+        + "/foo", "bar");
+
+    requestProps.put(AlertTargetResourceProvider.ALERT_TARGET_PROPERTIES
+        + "/foobar", "baz");
+
+    return requestProps;
+  }
+
+  /**
   *
   */
   private class MockModule implements Module {


[26/50] [abbrv] git commit: Merge branch 'trunk' into branch-alerts-dev

Posted by jo...@apache.org.
Merge branch 'trunk' into branch-alerts-dev


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

Branch: refs/heads/trunk
Commit: a4e97aaa2df20b7434676dbdcc8afa9f28bdc84d
Parents: b7ae2d7 24f0b47
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Wed Sep 17 08:33:22 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Wed Sep 17 08:33:22 2014 -0400

----------------------------------------------------------------------
 .../app/scripts/controllers/mainCtrl.js         |   13 +-
 .../resources/ui/admin-web/app/styles/main.css  |   42 +-
 .../resources/ui/admin-web/app/views/main.html  |   41 +-
 .../src/main/python/ambari_jinja2/ext/jinja.el  |  213 -
 .../server/actionmanager/ActionScheduler.java   |   26 +-
 .../ambari/server/actionmanager/Request.java    |   23 +-
 .../server/api/util/StackExtensionHelper.java   |   35 +-
 .../server/controller/ExecuteActionRequest.java |   20 +-
 .../controller/MaintenanceStateHelper.java      |    2 +-
 .../internal/ConfigGroupResourceProvider.java   |   20 +-
 .../internal/RequestResourceProvider.java       |   12 +-
 .../server/orm/entities/RequestEntity.java      |   12 +
 .../server/upgrade/UpgradeCatalog170.java       |    4 +
 .../apache/ambari/server/view/ViewRegistry.java |   67 +-
 ambari-server/src/main/python/ambari-server.py  |   42 +-
 .../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 +-
 .../src/main/resources/properties.json          |    1 +
 .../HDFS/package/scripts/service_check.py       |    2 +-
 .../services/HIVE/configuration/hive-site.xml   |   19 +
 .../HDFS/package/scripts/service_check.py       |    2 +-
 .../services/HIVE/configuration/hive-site.xml   |   19 +
 .../stacks/HDP/2.0/role_command_order.json      |    2 +-
 .../stacks/HDP/2.0/services/HBASE/metainfo.xml  |    3 -
 .../stacks/HDP/2.0/services/HDFS/metainfo.xml   |    1 -
 .../stacks/HDP/2.0/services/HIVE/metainfo.xml   |    6 -
 .../stacks/HDP/2.0/services/OOZIE/metainfo.xml  |    3 -
 .../stacks/HDP/2.0/services/PIG/metainfo.xml    |    1 -
 .../stacks/HDP/2.0/services/SQOOP/metainfo.xml  |    3 -
 .../HDP/2.0/services/WEBHCAT/metainfo.xml       |   27 -
 .../stacks/HDP/2.0/services/YARN/metainfo.xml   |    2 -
 .../HDP/2.0/services/ZOOKEEPER/metainfo.xml     |    1 -
 .../GLUSTERFS/configuration/hadoop-env.xml      |    2 +
 .../services/HIVE/configuration/hive-site.xml   |   19 +
 .../services/YARN/configuration/core-site.xml   |   20 -
 .../stacks/HDP/2.1/services/FLUME/metainfo.xml  |    3 +-
 .../stacks/HDP/2.1/services/HBASE/metainfo.xml  |    3 -
 .../stacks/HDP/2.1/services/HDFS/metainfo.xml   |    1 -
 .../services/HIVE/configuration/hive-site.xml   |   19 +
 .../stacks/HDP/2.1/services/HIVE/metainfo.xml   |    1 -
 .../stacks/HDP/2.1/services/NAGIOS/metainfo.xml |    1 -
 .../stacks/HDP/2.1/services/OOZIE/metainfo.xml  |    2 -
 .../stacks/HDP/2.1/services/PIG/metainfo.xml    |    1 -
 .../stacks/HDP/2.1/services/SQOOP/metainfo.xml  |    3 -
 .../stacks/HDP/2.1/services/YARN/metainfo.xml   |    1 -
 .../HDP/2.1/services/ZOOKEEPER/metainfo.xml     |    2 -
 .../stacks/HDP/2.2.1/repos/repoinfo.xml         |    2 +-
 .../stacks/HDP/2.2.1/services/HDFS/metainfo.xml |    1 -
 .../stacks/HDP/2.2.1/services/HIVE/metainfo.xml |    1 -
 .../stacks/HDP/2.2/services/FALCON/metainfo.xml |    1 -
 .../stacks/HDP/2.2/services/FLUME/metainfo.xml  |    1 -
 .../stacks/HDP/2.2/services/HBASE/metainfo.xml  |    3 -
 .../stacks/HDP/2.2/services/HDFS/metainfo.xml   |    1 -
 .../stacks/HDP/2.2/services/HIVE/metainfo.xml   |    1 -
 .../stacks/HDP/2.2/services/OOZIE/metainfo.xml  |    2 -
 .../stacks/HDP/2.2/services/PIG/metainfo.xml    |    1 -
 .../stacks/HDP/2.2/services/SQOOP/metainfo.xml  |    3 -
 .../stacks/HDP/2.2/services/STORM/metainfo.xml  |    1 -
 .../stacks/HDP/2.2/services/TEZ/metainfo.xml    |    1 -
 .../HDP/2.2/services/WEBHCAT/metainfo.xml       |    1 -
 .../stacks/HDP/2.2/services/YARN/metainfo.xml   |    2 -
 .../HDP/2.2/services/ZOOKEEPER/metainfo.xml     |    1 -
 .../actionmanager/TestActionDBAccessorImpl.java |    2 +-
 .../actionmanager/TestActionScheduler.java      |  264 +-
 .../api/util/StackExtensionHelperTest.java      |   20 +
 .../AmbariCustomCommandExecutionHelperTest.java |    2 +-
 .../AmbariManagementControllerTest.java         |   86 +-
 .../BackgroundCustomCommandExecutionTest.java   |    2 +-
 .../ambari/server/view/ViewRegistryTest.java    |   90 +
 .../view/configuration/ViewConfigTest.java      |    1 +
 .../stacks/1.3.2/HDFS/test_service_check.py     |    2 +-
 .../stacks/2.0.6/HDFS/test_service_check.py     |    2 +-
 .../stacks/HDP/2.0.7/services/HDFS/metrics.json | 7840 ------------------
 ambari-web/app/controllers/installer.js         |   15 +
 .../controllers/main/service/info/configs.js    |  240 +-
 ambari-web/app/controllers/main/service/item.js |   36 +-
 ambari-web/app/data/HDP2/site_properties.js     |    9 +
 ambari-web/app/data/site_properties.js          |    9 +
 ambari-web/app/messages.js                      |    1 +
 ambari-web/app/models/cluster_states.js         |    1 -
 ambari-web/app/models/service_config.js         |    1 +
 ambari-web/app/router.js                        |   84 +-
 ambari-web/app/routes/installer.js              |   12 +-
 ambari-web/app/routes/reassign_master_routes.js |   96 +-
 .../common/configs/compare_property.hbs         |   30 +-
 .../common/configs/service_config_category.hbs  |    6 +-
 ambari-web/app/utils/ajax/ajax.js               |   17 +-
 .../app/utils/batch_scheduled_requests.js       |    6 +-
 contrib/views/slider/pom.xml                    |    2 +-
 .../slider/SliderAppTypesResourceProvider.java  |    6 +-
 .../view/slider/SliderAppsViewController.java   |    4 +
 .../slider/SliderAppsViewControllerImpl.java    |   70 +-
 .../view/slider/rest/SliderAppsResource.java    |   21 +-
 .../ambari/view/slider/rest/client/Metric.java  |    9 +-
 .../ui/app/controllers/slider_app_controller.js |   17 +-
 .../ui/app/controllers/slider_controller.js     |  107 +-
 .../src/main/resources/ui/app/helpers/ajax.js   |    6 +-
 .../src/main/resources/ui/app/initialize.js     |   31 +-
 .../ui/app/mappers/application_status.js        |  115 -
 .../ui/app/models/slider_app_component.js       |   10 +-
 .../resources/ui/app/styles/application.less    |  119 +
 .../resources/ui/app/templates/application.hbs  |    4 +-
 .../ui/app/templates/slider_app/summary.hbs     |    2 +-
 .../ui/app/templates/slider_title_tooltip.hbs   |   27 +
 .../src/main/resources/ui/app/translations.js   |    2 +-
 .../resources/ui/app/views/application_view.js  |   64 +
 108 files changed, 1641 insertions(+), 8622 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/a4e97aaa/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/a4e97aaa/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/a4e97aaa/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/a4e97aaa/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/a4e97aaa/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/a4e97aaa/ambari-server/src/main/resources/properties.json
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/a4e97aaa/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/a4e97aaa/ambari-web/app/utils/ajax/ajax.js
----------------------------------------------------------------------


[33/50] [abbrv] git commit: AMBARI-7443 - Alerts: Implement Email Dispatcher (jonathanhurley)

Posted by jo...@apache.org.
AMBARI-7443 - Alerts: Implement Email Dispatcher (jonathanhurley)


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

Branch: refs/heads/trunk
Commit: d838ca95b644a3222c27b7415f2711373affcd83
Parents: e6cc058
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Mon Sep 22 23:45:06 2014 -0700
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Tue Sep 23 09:02:11 2014 -0700

----------------------------------------------------------------------
 .../internal/AlertTargetResourceProvider.java   |  15 +-
 .../server/events/AlertStateChangeEvent.java    |   2 +-
 .../events/listeners/AlertReceivedListener.java |  46 +++--
 .../listeners/AlertServiceStateListener.java    |   1 -
 .../notifications/DispatchCredentials.java      |  44 +++++
 .../server/notifications/DispatchFactory.java   |  16 ++
 .../server/notifications/Notification.java      |  18 ++
 .../ambari/server/notifications/Recipient.java  |  45 +++++
 .../dispatchers/EmailDispatcher.java            | 129 +++++++++++++-
 .../apache/ambari/server/orm/dao/AlertsDAO.java | 114 +++++++-----
 .../server/orm/entities/AlertCurrentEntity.java |  13 +-
 .../services/AlertNoticeDispatchService.java    | 175 ++++++++++++++++++-
 .../stacks/HDP/2.0.6/services/HDFS/alerts.json  |   2 +-
 .../AlertTargetResourceProviderTest.java        |  58 ++++++
 .../notifications/EmailDispatcherTest.java      | 117 +++++++++++++
 .../server/notifications/MockDispatcher.java    |  46 +++++
 .../ambari/server/orm/dao/AlertsDAOTest.java    | 133 +++++++++-----
 .../alerts/AlertStateChangedEventTest.java      | 139 +++++++++++++++
 18 files changed, 984 insertions(+), 129 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/d838ca95/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProvider.java
index f2b82d6..b0cc52b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProvider.java
@@ -20,6 +20,7 @@ package org.apache.ambari.server.controller.internal;
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -45,7 +46,6 @@ import org.apache.ambari.server.state.alert.AlertTarget;
 import org.apache.commons.lang.StringUtils;
 
 import com.google.gson.Gson;
-import com.google.gson.JsonObject;
 import com.google.inject.Inject;
 import com.google.inject.Injector;
 
@@ -351,22 +351,19 @@ public class AlertTargetResourceProvider extends
    *         {@code null} if none.
    */
   private String extractProperties( Map<String, Object> requestMap ){
-    JsonObject jsonObject = new JsonObject();
+    Map<String, Object> normalizedMap = new HashMap<String, Object>(
+        requestMap.size());
+
     for (Entry<String, Object> entry : requestMap.entrySet()) {
       String key = entry.getKey();
       String propCat = PropertyHelper.getPropertyCategory(key);
 
       if (propCat.equals(ALERT_TARGET_PROPERTIES)) {
         String propKey = PropertyHelper.getPropertyName(key);
-        jsonObject.addProperty(propKey, entry.getValue().toString());
+        normalizedMap.put(propKey, entry.getValue());
       }
     }
 
-    String properties = null;
-    if (jsonObject.entrySet().size() > 0) {
-      properties = jsonObject.toString();
-    }
-
-    return properties;
+    return s_gson.toJson(normalizedMap);
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/d838ca95/ambari-server/src/main/java/org/apache/ambari/server/events/AlertStateChangeEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/AlertStateChangeEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/AlertStateChangeEvent.java
index ab2c3dd..efb7119 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/AlertStateChangeEvent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/AlertStateChangeEvent.java
@@ -25,7 +25,7 @@ import org.apache.ambari.server.state.AlertState;
  * The {@link AlertStateChangeEvent} is fired when an {@link Alert} instance has
  * its {@link AlertState} changed.
  */
-public final class AlertStateChangeEvent extends AlertEvent {
+public class AlertStateChangeEvent extends AlertEvent {
 
   /**
    * The prior alert state.

http://git-wip-us.apache.org/repos/asf/ambari/blob/d838ca95/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java
index fb7a608..e87ba7d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java
@@ -28,8 +28,8 @@ import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
 import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
 import org.apache.ambari.server.state.Alert;
 import org.apache.ambari.server.state.AlertState;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.eventbus.AllowConcurrentEvents;
 import com.google.common.eventbus.Subscribe;
@@ -46,7 +46,7 @@ public class AlertReceivedListener {
   /**
    * Logger.
    */
-  private static Log LOG = LogFactory.getLog(AlertReceivedListener.class);
+  private static final Logger LOG = LoggerFactory.getLogger(AlertReceivedListener.class);
 
   @Inject
   private AlertsDAO m_alertsDao;
@@ -70,30 +70,33 @@ public class AlertReceivedListener {
     m_alertEventPublisher.register(this);
   }
 
-
   /**
-   * Adds an alert.  Checks for a new state before creating a new history record.
+   * Adds an alert. Checks for a new state before creating a new history record.
    *
-   * @param clusterId the id for the cluster
-   * @param alert the alert to add
+   * @param clusterId
+   *          the id for the cluster
+   * @param alert
+   *          the alert to add
    */
   @Subscribe
   @AllowConcurrentEvents
   public void onAlertEvent(AlertReceivedEvent event) {
-    LOG.debug(event);
+    if (LOG.isDebugEnabled()) {
+      LOG.debug(event.toString());
+    }
 
     long clusterId = event.getClusterId();
     Alert alert = event.getAlert();
 
     AlertCurrentEntity current = null;
-    
+
     if (null == alert.getHost()) {
       current = m_alertsDao.findCurrentByNameNoHost(clusterId, alert.getName());
     } else {
       current = m_alertsDao.findCurrentByHostAndName(clusterId, alert.getHost(),
           alert.getName());
     }
-    
+
     if (null == current) {
       AlertDefinitionEntity definition = m_definitionDao.findByName(clusterId,
           alert.getName());
@@ -111,13 +114,20 @@ public class AlertReceivedListener {
       current.setLatestTimestamp(Long.valueOf(alert.getTimestamp()));
       current.setLatestText(alert.getText());
 
-      m_alertsDao.merge(current);
+      current = m_alertsDao.merge(current);
     } else {
-      AlertState oldState = current.getAlertHistory().getAlertState();
+      LOG.debug(
+          "Alert State Changed: CurrentId {}, CurrentTimestamp {}, HistoryId {}, HistoryState {}",
+          current.getAlertId(), current.getLatestTimestamp(),
+          current.getAlertHistory().getAlertId(),
+          current.getAlertHistory().getAlertState());
+
+      AlertHistoryEntity oldHistory = current.getAlertHistory();
+      AlertState oldState = oldHistory.getAlertState();
 
       // insert history, update current
       AlertHistoryEntity history = createHistory(clusterId,
-          current.getAlertHistory().getAlertDefinition(), alert);
+          oldHistory.getAlertDefinition(), alert);
 
       // manually create the new history entity since we are merging into
       // an existing current entity
@@ -127,8 +137,14 @@ public class AlertReceivedListener {
       current.setLatestTimestamp(Long.valueOf(alert.getTimestamp()));
       current.setOriginalTimestamp(Long.valueOf(alert.getTimestamp()));
 
-      m_alertsDao.merge(current);
-      
+      current = m_alertsDao.merge(current);
+
+      LOG.debug(
+          "Alert State Merged: CurrentId {}, CurrentTimestamp {}, HistoryId {}, HistoryState {}",
+          current.getAlertId(), current.getLatestTimestamp(),
+          current.getAlertHistory().getAlertId(),
+          current.getAlertHistory().getAlertState());
+
       // broadcast the alert changed event for other subscribers
       AlertStateChangeEvent alertChangedEvent = new AlertStateChangeEvent(
           event.getClusterId(), event.getAlert(), current.getAlertHistory(),

http://git-wip-us.apache.org/repos/asf/ambari/blob/d838ca95/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertServiceStateListener.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertServiceStateListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertServiceStateListener.java
index f1ce617..6215cc1 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertServiceStateListener.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertServiceStateListener.java
@@ -94,7 +94,6 @@ public class AlertServiceStateListener {
     publisher.register(this);
   }
 
-
   /**
    * Handles service installed events by populating the database with all known
    * alert definitions for the newly installed service and creates the service's

http://git-wip-us.apache.org/repos/asf/ambari/blob/d838ca95/ambari-server/src/main/java/org/apache/ambari/server/notifications/DispatchCredentials.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/notifications/DispatchCredentials.java b/ambari-server/src/main/java/org/apache/ambari/server/notifications/DispatchCredentials.java
new file mode 100644
index 0000000..9514474
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/notifications/DispatchCredentials.java
@@ -0,0 +1,44 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.notifications;
+
+/**
+ * The {@link DispatchCredentials} represent a generic username/password model
+ * that can be passed to a {@link NotificationDispatcher} in order to authentice
+ * with a backend dispatcher.
+ */
+public class DispatchCredentials {
+
+  /**
+   * The username.
+   */
+  public String UserName;
+
+  /**
+   * The password.
+   */
+  public String Password;
+
+  /**
+   * Constructor.
+   *
+   */
+  public DispatchCredentials() {
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/d838ca95/ambari-server/src/main/java/org/apache/ambari/server/notifications/DispatchFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/notifications/DispatchFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/notifications/DispatchFactory.java
index 3414035..13f2da2 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/notifications/DispatchFactory.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/notifications/DispatchFactory.java
@@ -50,6 +50,22 @@ public final class DispatchFactory {
   }
 
   /**
+   * Registers a dispatcher instance with a type.
+   *
+   * @param type
+   *          the type
+   * @param dispatcher
+   *          the dispatcher to register with the type.
+   */
+  public void register(String type, NotificationDispatcher dispatcher) {
+    if (null == dispatcher) {
+      m_dispatchers.remove(type);
+    } else {
+      m_dispatchers.put(type, dispatcher);
+    }
+  }
+
+  /**
    * Gets a dispatcher based on the type.
    *
    * @param type

http://git-wip-us.apache.org/repos/asf/ambari/blob/d838ca95/ambari-server/src/main/java/org/apache/ambari/server/notifications/Notification.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/notifications/Notification.java b/ambari-server/src/main/java/org/apache/ambari/server/notifications/Notification.java
index 08c5242..12dffd7 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/notifications/Notification.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/notifications/Notification.java
@@ -18,6 +18,7 @@
 package org.apache.ambari.server.notifications;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * The {@link Notification} class is a generic way to relay content through an
@@ -36,6 +37,23 @@ public class Notification {
   public String Body;
 
   /**
+   * The optional recipients of the notification. Some dispatchers may not
+   * require explicit recipients.
+   */
+  public List<Recipient> Recipients;
+
+  /**
+   * A map of all of the properties that a {@link NotificationDispatcher} needs
+   * in order to dispatch this notification.
+   */
+  public Map<String, String> DispatchProperties;
+
+  /**
+   * The optional credentials used to authenticate with the dispatcher.
+   */
+  public DispatchCredentials Credentials;
+
+  /**
    * An optional callback implementation that the dispatcher can use to report
    * success/failure on delivery.
    */

http://git-wip-us.apache.org/repos/asf/ambari/blob/d838ca95/ambari-server/src/main/java/org/apache/ambari/server/notifications/Recipient.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/notifications/Recipient.java b/ambari-server/src/main/java/org/apache/ambari/server/notifications/Recipient.java
new file mode 100644
index 0000000..933038b
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/notifications/Recipient.java
@@ -0,0 +1,45 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.notifications;
+
+/**
+ * The {@link Recipient} class represents a target of a {@link Notification}.
+ */
+public class Recipient {
+
+  /**
+   * A string that the concrete {@link NotificationDispatcher} can use to build
+   * a backend recipient that will work with the dispatch mechanism.
+   */
+  public String Identifier;
+
+  /**
+   * Constructor.
+   *
+   */
+  public Recipient() {
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString() {
+    return Identifier;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/d838ca95/ambari-server/src/main/java/org/apache/ambari/server/notifications/dispatchers/EmailDispatcher.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/notifications/dispatchers/EmailDispatcher.java b/ambari-server/src/main/java/org/apache/ambari/server/notifications/dispatchers/EmailDispatcher.java
index d0858d3..a5dad84 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/notifications/dispatchers/EmailDispatcher.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/notifications/dispatchers/EmailDispatcher.java
@@ -17,8 +17,24 @@
  */
 package org.apache.ambari.server.notifications.dispatchers;
 
-import org.apache.ambari.server.notifications.NotificationDispatcher;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.Timer;
+
+import javax.mail.Authenticator;
+import javax.mail.Message;
+import javax.mail.Message.RecipientType;
+import javax.mail.MessagingException;
+import javax.mail.PasswordAuthentication;
+import javax.mail.Session;
+import javax.mail.Transport;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeMessage;
+
+import org.apache.ambari.server.notifications.DispatchCredentials;
 import org.apache.ambari.server.notifications.Notification;
+import org.apache.ambari.server.notifications.NotificationDispatcher;
+import org.apache.ambari.server.notifications.Recipient;
 import org.apache.ambari.server.state.alert.TargetType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -27,7 +43,14 @@ import com.google.inject.Singleton;
 
 /**
  * The {@link EmailDispatcher} class is used to dispatch {@link Notification}
- * via JavaMail.
+ * via JavaMail. This class currently does not attempt to reuse an existing
+ * {@link Session} or {@link Transport} since each {@link Notification} could
+ * have a different target server with different properties.
+ * <p/>
+ * In the future, this class could keep various {@link Transport} instances open
+ * on a {@link Timer}, but those instances would need to be hashed so that the
+ * proper instance is retrieved from the properties of the incoming
+ * {@link Notification}.
  */
 @Singleton
 public class EmailDispatcher implements NotificationDispatcher {
@@ -52,9 +75,105 @@ public class EmailDispatcher implements NotificationDispatcher {
   public void dispatch(Notification notification) {
     LOG.info("Sending email: {}", notification);
 
-    // callback to inform the interested parties about the successful dispatch
-    if (null != notification.Callback) {
-      notification.Callback.onSuccess(notification.CallbackIds);
+    if (null == notification.DispatchProperties) {
+      LOG.error("Unable to dispatch an email notification that does not contain SMTP properties");
+
+      if (null != notification.Callback) {
+        notification.Callback.onFailure(notification.CallbackIds);
+      }
+
+      return;
+    }
+
+    // convert properties to JavaMail properties
+    Properties properties = new Properties();
+    for (Entry<String, String> entry : notification.DispatchProperties.entrySet()) {
+      properties.put(entry.getKey(), entry.getValue());
+    }
+
+    // notifications must have recipients
+    if (null == notification.Recipients) {
+      LOG.error("Unable to dispatch an email notification that does not have recipients");
+
+      if (null != notification.Callback) {
+        notification.Callback.onFailure(notification.CallbackIds);
+      }
+
+      return;
+    }
+
+    // create a simple email authentication for username/password
+    final Session session;
+    EmailAuthenticator authenticator = null;
+
+    if (null != notification.Credentials) {
+      authenticator = new EmailAuthenticator(notification.Credentials);
+    }
+
+    session = Session.getInstance(properties, authenticator);
+
+    try {
+      Message message = new MimeMessage(session);
+
+      for (Recipient recipient : notification.Recipients) {
+        InternetAddress address = new InternetAddress(recipient.Identifier);
+        message.addRecipient(RecipientType.TO, address);
+      }
+
+      message.setSubject(notification.Subject);
+      message.setText(notification.Body);
+
+      Transport.send(message);
+
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("Successfully dispatched email to {}",
+            notification.Recipients);
+      }
+
+      // callback to inform the interested parties about the successful dispatch
+      if (null != notification.Callback) {
+        notification.Callback.onSuccess(notification.CallbackIds);
+      }
+    } catch (Exception exception) {
+      LOG.error("Unable to dispatch notification via Email", exception);
+
+      // callback failure
+      if (null != notification.Callback) {
+        notification.Callback.onFailure(notification.CallbackIds);
+      }
+    } finally {
+      try {
+        session.getTransport().close();
+      } catch (MessagingException me) {
+        LOG.warn("Dispatcher unable to close SMTP transport", me);
+      }
+    }
+  }
+
+  /**
+   * The {@link EmailAuthenticator} class is used to provide a username and
+   * password combination to an SMTP server.
+   */
+  private static final class EmailAuthenticator extends Authenticator{
+
+    private final DispatchCredentials m_credentials;
+
+    /**
+     * Constructor.
+     *
+     * @param credentials
+     */
+    private EmailAuthenticator(DispatchCredentials credentials) {
+      m_credentials = credentials;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected PasswordAuthentication getPasswordAuthentication() {
+      return new PasswordAuthentication(m_credentials.UserName,
+          m_credentials.Password);
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/d838ca95/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 aba41a5..a28b448 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
@@ -30,6 +30,8 @@ import org.apache.ambari.server.orm.entities.AlertCurrentEntity;
 import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
 import org.apache.ambari.server.state.AlertState;
 import org.apache.ambari.server.state.alert.Scope;
+import org.eclipse.persistence.config.HintValues;
+import org.eclipse.persistence.config.QueryHints;
 
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -57,7 +59,7 @@ public class AlertsDAO {
 
   /**
    * Gets an alert with the specified ID.
-   * 
+   *
    * @param alertId
    *          the ID of the alert to retrieve.
    * @return the alert or {@code null} if none exists.
@@ -68,7 +70,7 @@ public class AlertsDAO {
 
   /**
    * Gets all alerts stored in the database across all clusters.
-   * 
+   *
    * @return all alerts or an empty list if none exist (never {@code null}).
    */
   public List<AlertHistoryEntity> findAll() {
@@ -80,7 +82,7 @@ public class AlertsDAO {
 
   /**
    * Gets all alerts stored in the database for the given cluster.
-   * 
+   *
    * @param clusterId
    *          the ID of the cluster.
    * @return all alerts in the specified cluster or an empty list if none exist
@@ -98,7 +100,7 @@ public class AlertsDAO {
   /**
    * Gets all alerts stored in the database for the given cluster that have one
    * of the specified alert states.
-   * 
+   *
    * @param clusterId
    *          the ID of the cluster.
    * @param alertStates
@@ -126,7 +128,7 @@ public class AlertsDAO {
    * Gets all alerts stored in the database for the given cluster and that fall
    * withing the specified date range. Dates are expected to be in milliseconds
    * since the epoch, normalized to UTC time.
-   * 
+   *
    * @param clusterId
    *          the ID of the cluster.
    * @param startDate
@@ -141,8 +143,9 @@ public class AlertsDAO {
    */
   public List<AlertHistoryEntity> findAll(long clusterId, Date startDate,
       Date endDate) {
-    if (null == startDate && null == endDate)
+    if (null == startDate && null == endDate) {
       return Collections.emptyList();
+    }
 
     TypedQuery<AlertHistoryEntity> query = null;
 
@@ -174,15 +177,16 @@ public class AlertsDAO {
       query.setParameter("beforeDate", endDate.getTime());
     }
 
-    if (null == query)
+    if (null == query) {
       return Collections.emptyList();
+    }
 
     return daoUtils.selectList(query);
   }
 
   /**
    * Gets the current alerts.
-   * 
+   *
    * @return the current alerts or an empty list if none exist (never
    *         {@code null}).
    */
@@ -196,7 +200,7 @@ public class AlertsDAO {
 
   /**
    * Gets a current alert with the specified ID.
-   * 
+   *
    * @param alertId
    *          the ID of the alert to retrieve.
    * @return the alert or {@code null} if none exists.
@@ -208,7 +212,7 @@ public class AlertsDAO {
 
   /**
    * Gets the current alerts for a given cluster.
-   * 
+   *
    * @return the current alerts for the given clusteror an empty list if none
    *         exist (never {@code null}).
    */
@@ -218,14 +222,15 @@ public class AlertsDAO {
         "AlertCurrentEntity.findByCluster", AlertCurrentEntity.class);
 
     query.setParameter("clusterId", Long.valueOf(clusterId));
+    query = setQueryRefreshHint(query);
 
     return daoUtils.selectList(query);
   }
-  
+
   /**
    * Retrieves the summary information for a particular scope.  The result is a DTO
    * since the columns are aggregated and don't fit to an entity.
-   * 
+   *
    * @param clusterId the cluster id
    * @param serviceName the service name. Use {@code null} to not filter on service.
    * @param hostName the host name.  Use {@code null} to not filter on host.
@@ -240,41 +245,41 @@ public class AlertsDAO {
     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");
-    
+
     if (null != serviceName) {
       sb.append(" AND history.serviceName = :serviceName");
     }
-    
+
     if (null != hostName) {
       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);
-    
+
     query.setParameter("clusterId", Long.valueOf(clusterId));
-    
+
     if (null != serviceName) {
       query.setParameter("serviceName", serviceName);
     }
-    
+
     if (null != hostName) {
       query.setParameter("hostName", hostName);
     }
-    
+
     return daoUtils.selectSingle(query);
   }
-  
+
   /**
    * Gets the current alerts for a given service.
-   * 
+   *
    * @return the current alerts for the given service or an empty list if none
    *         exist (never {@code null}).
    */
@@ -288,12 +293,13 @@ public class AlertsDAO {
     query.setParameter("serviceName", serviceName);
     query.setParameter("inlist", EnumSet.of(Scope.ANY, Scope.SERVICE));
 
+    query = setQueryRefreshHint(query);
     return daoUtils.selectList(query);
   }
 
   /**
    * Gets the current alerts for a given host.
-   * 
+   *
    * @return the current alerts for the given host or an empty list if none
    *         exist (never {@code null}).
    */
@@ -307,13 +313,14 @@ public class AlertsDAO {
     query.setParameter("hostName", hostName);
     query.setParameter("inlist", EnumSet.of(Scope.ANY, Scope.HOST));
 
+    query = setQueryRefreshHint(query);
     return daoUtils.selectList(query);
   }
-  
+
   @RequiresSession
   public AlertCurrentEntity findCurrentByHostAndName(long clusterId, String hostName,
       String alertName) {
-    
+
     TypedQuery<AlertCurrentEntity> query = entityManagerProvider.get().createNamedQuery(
         "AlertCurrentEntity.findByHostAndName", AlertCurrentEntity.class);
 
@@ -321,6 +328,7 @@ public class AlertsDAO {
     query.setParameter("hostName", hostName);
     query.setParameter("definitionName", alertName);
 
+    query = setQueryRefreshHint(query);
     return daoUtils.selectOne(query);
   }
 
@@ -328,7 +336,7 @@ public class AlertsDAO {
    * Removes alert history and current alerts for the specified alert defintiion
    * ID. This will invoke {@link EntityManager#clear()} when completed since the
    * JPQL statement will remove entries without going through the EM.
-   * 
+   *
    * @param definitionId
    *          the ID of the definition to remove.
    */
@@ -352,7 +360,7 @@ public class AlertsDAO {
 
   /**
    * Remove a current alert whose history entry matches the specfied ID.
-   * 
+   *
    * @param   historyId the ID of the history entry.
    * @return  the number of alerts removed.
    */
@@ -367,7 +375,7 @@ public class AlertsDAO {
 
   /**
    * Persists a new alert.
-   * 
+   *
    * @param alert
    *          the alert to persist (not {@code null}).
    */
@@ -378,7 +386,7 @@ public class AlertsDAO {
 
   /**
    * Refresh the state of the alert from the database.
-   * 
+   *
    * @param alert
    *          the alert to refresh (not {@code null}).
    */
@@ -389,7 +397,7 @@ public class AlertsDAO {
 
   /**
    * Merge the speicified alert with the existing alert in the database.
-   * 
+   *
    * @param alert
    *          the alert to merge (not {@code null}).
    * @return the updated alert with merged content (never {@code null}).
@@ -401,7 +409,7 @@ public class AlertsDAO {
 
   /**
    * Removes the specified alert from the database.
-   * 
+   *
    * @param alert
    *          the alert to remove.
    */
@@ -415,7 +423,7 @@ public class AlertsDAO {
 
   /**
    * Persists a new current alert.
-   * 
+   *
    * @param alert
    *          the current alert to persist (not {@code null}).
    */
@@ -426,7 +434,7 @@ public class AlertsDAO {
 
   /**
    * Refresh the state of the current alert from the database.
-   * 
+   *
    * @param alert
    *          the current alert to refresh (not {@code null}).
    */
@@ -437,7 +445,7 @@ public class AlertsDAO {
 
   /**
    * Merge the speicified current alert with the existing alert in the database.
-   * 
+   *
    * @param alert
    *          the current alert to merge (not {@code null}).
    * @return the updated current alert with merged content (never {@code null}).
@@ -449,7 +457,7 @@ public class AlertsDAO {
 
   /**
    * Removes the specified current alert from the database.
-   * 
+   *
    * @param alert
    *          the current alert to remove.
    */
@@ -457,9 +465,9 @@ public class AlertsDAO {
   public void remove(AlertCurrentEntity alert) {
     entityManagerProvider.get().remove(merge(alert));
   }
-  
+
   /**
-   * Finds the aggregate counts for an alert name, across all hosts. 
+   * Finds the aggregate counts for an alert name, across all hosts.
    * @param clusterId the cluster id
    * @param alertName the name of the alert to find the aggregate
    * @return the summary data
@@ -474,22 +482,22 @@ public class AlertsDAO {
     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.WARNING.name(),
         AlertState.class.getName(), AlertState.CRITICAL.name(),
         AlertState.class.getName(), AlertState.UNKNOWN.name());
-    
+
     TypedQuery<AlertSummaryDTO> query = entityManagerProvider.get().createQuery(
         str, AlertSummaryDTO.class);
-    
+
     query.setParameter("clusterId", Long.valueOf(clusterId));
     query.setParameter("definitionName", alertName);
-    
-    return daoUtils.selectSingle(query);    
+
+    return daoUtils.selectSingle(query);
   }
-  
+
   /**
    * Locate the current alert for the provided service and alert name, but when
    * host is not set ({@code IS NULL}).
@@ -500,7 +508,7 @@ public class AlertsDAO {
    */
   @RequiresSession
   public AlertCurrentEntity findCurrentByNameNoHost(long clusterId, String alertName) {
-    
+
     TypedQuery<AlertCurrentEntity> query = entityManagerProvider.get().createNamedQuery(
         "AlertCurrentEntity.findByNameAndNoHost", AlertCurrentEntity.class);
 
@@ -510,4 +518,22 @@ public class AlertsDAO {
     return daoUtils.selectOne(query);
   }
 
+  /**
+   * Sets {@link QueryHints#REFRESH} on the specified query so that child
+   * entities are not stale.
+   * <p/>
+   * See <a
+   * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=398067">https://bugs
+   * .eclipse.org/bugs/show_bug.cgi?id=398067</a>
+   *
+   * @param query
+   * @return
+   */
+  private <T> TypedQuery<T> setQueryRefreshHint(TypedQuery<T> query) {
+    // !!! https://bugs.eclipse.org/bugs/show_bug.cgi?id=398067
+    // ensure that an associated entity with a JOIN is not stale; this causes
+    // the associated AlertHistoryEntity to be stale
+    query.setHint(QueryHints.REFRESH, HintValues.TRUE);
+    return query;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/d838ca95/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 5b54d57..8ca297b 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
@@ -47,11 +47,11 @@ import org.apache.ambari.server.state.MaintenanceState;
 @TableGenerator(name = "alert_current_id_generator", table = "ambari_sequences", pkColumnName = "sequence_name", valueColumnName = "sequence_value", pkColumnValue = "alert_current_id_seq", initialValue = 0, allocationSize = 1)
 @NamedQueries({
     @NamedQuery(name = "AlertCurrentEntity.findAll", query = "SELECT alert FROM AlertCurrentEntity alert"),
-    @NamedQuery(name = "AlertCurrentEntity.findByCluster", query = "SELECT alert FROM AlertCurrentEntity alert JOIN alert.alertHistory history WHERE history.clusterId = :clusterId"),
-    @NamedQuery(name = "AlertCurrentEntity.findByService", query = "SELECT alert FROM AlertCurrentEntity alert JOIN alert.alertHistory history WHERE history.clusterId = :clusterId AND history.serviceName = :serviceName AND history.alertDefinition.scope IN :inlist"),
-    @NamedQuery(name = "AlertCurrentEntity.findByHost", query = "SELECT alert FROM AlertCurrentEntity alert JOIN alert.alertHistory history WHERE history.clusterId = :clusterId AND history.hostName = :hostName AND history.alertDefinition.scope IN :inlist"),
-    @NamedQuery(name = "AlertCurrentEntity.findByHostAndName", query = "SELECT alert FROM AlertCurrentEntity alert JOIN alert.alertHistory history WHERE history.clusterId = :clusterId AND history.alertDefinition.definitionName = :definitionName AND history.hostName = :hostName"),
-    @NamedQuery(name = "AlertCurrentEntity.findByNameAndNoHost", query = "SELECT alert FROM AlertCurrentEntity alert JOIN alert.alertHistory history WHERE history.clusterId = :clusterId AND history.alertDefinition.definitionName = :definitionName AND history.hostName IS NULL"),
+    @NamedQuery(name = "AlertCurrentEntity.findByCluster", query = "SELECT alert FROM AlertCurrentEntity alert WHERE alert.alertHistory.clusterId = :clusterId"),
+    @NamedQuery(name = "AlertCurrentEntity.findByService", query = "SELECT alert FROM AlertCurrentEntity alert WHERE alert.alertHistory.clusterId = :clusterId AND alert.alertHistory.serviceName = :serviceName AND alert.alertHistory.alertDefinition.scope IN :inlist"),
+    @NamedQuery(name = "AlertCurrentEntity.findByHost", query = "SELECT alert FROM AlertCurrentEntity alert WHERE alert.alertHistory.clusterId = :clusterId AND alert.alertHistory.hostName = :hostName AND alert.alertHistory.alertDefinition.scope IN :inlist"),
+    @NamedQuery(name = "AlertCurrentEntity.findByHostAndName", query = "SELECT alert FROM AlertCurrentEntity alert WHERE alert.alertHistory.clusterId = :clusterId AND alert.alertHistory.alertDefinition.definitionName = :definitionName AND alert.alertHistory.hostName = :hostName"),
+    @NamedQuery(name = "AlertCurrentEntity.findByNameAndNoHost", query = "SELECT alert FROM AlertCurrentEntity alert WHERE alert.alertHistory.clusterId = :clusterId AND alert.alertHistory.alertDefinition.definitionName = :definitionName AND alert.alertHistory.hostName IS NULL"),
     @NamedQuery(name = "AlertCurrentEntity.removeByHistoryId", query = "DELETE FROM AlertCurrentEntity alert WHERE alert.alertHistory.alertId = :historyId"),
     @NamedQuery(name = "AlertCurrentEntity.removeByDefinitionId", query = "DELETE FROM AlertCurrentEntity alert WHERE alert.alertDefinition.definitionId = :definitionId") })
 public class AlertCurrentEntity {
@@ -77,8 +77,7 @@ public class AlertCurrentEntity {
   /**
    * Unidirectional one-to-one association to {@link AlertHistoryEntity}
    */
-  @OneToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE,
-      CascadeType.REFRESH })
+  @OneToOne(cascade = { CascadeType.PERSIST, CascadeType.REFRESH })
   @JoinColumn(name = "history_id", unique = true, nullable = false)
   private AlertHistoryEntity alertHistory;
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/d838ca95/ambari-server/src/main/java/org/apache/ambari/server/state/services/AlertNoticeDispatchService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/services/AlertNoticeDispatchService.java b/ambari-server/src/main/java/org/apache/ambari/server/state/services/AlertNoticeDispatchService.java
index 7025e14..72487b3 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/services/AlertNoticeDispatchService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/services/AlertNoticeDispatchService.java
@@ -17,10 +17,13 @@
  */
 package org.apache.ambari.server.state.services;
 
+import java.lang.reflect.Type;
+import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.ThreadFactory;
@@ -29,19 +32,32 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.ambari.server.events.AlertEvent;
+import org.apache.ambari.server.notifications.DispatchCallback;
+import org.apache.ambari.server.notifications.DispatchCredentials;
 import org.apache.ambari.server.notifications.DispatchFactory;
 import org.apache.ambari.server.notifications.DispatchRunnable;
-import org.apache.ambari.server.notifications.DispatchCallback;
-import org.apache.ambari.server.notifications.NotificationDispatcher;
 import org.apache.ambari.server.notifications.Notification;
+import org.apache.ambari.server.notifications.NotificationDispatcher;
+import org.apache.ambari.server.notifications.Recipient;
 import org.apache.ambari.server.orm.dao.AlertDispatchDAO;
+import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
 import org.apache.ambari.server.orm.entities.AlertNoticeEntity;
 import org.apache.ambari.server.orm.entities.AlertTargetEntity;
+import org.apache.ambari.server.state.AlertState;
 import org.apache.ambari.server.state.NotificationState;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.util.concurrent.AbstractScheduledService;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.reflect.TypeToken;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
@@ -49,6 +65,10 @@ import com.google.inject.Singleton;
  * The {@link AlertNoticeDispatchService} is used to scan the database for
  * {@link AlertNoticeEntity} that are in the {@link NotificationState#PENDING}.
  * It will then process them through the dispatch system.
+ * <p/>
+ * The dispatch system will then make a callback to
+ * {@link AlertNoticeDispatchCallback} so that the {@link NotificationState} can
+ * be updated to its final value.
  */
 @Singleton
 public class AlertNoticeDispatchService extends AbstractScheduledService {
@@ -59,6 +79,26 @@ public class AlertNoticeDispatchService extends AbstractScheduledService {
   private static final Logger LOG = LoggerFactory.getLogger(AlertNoticeDispatchService.class);
 
   /**
+   * The property containing the dispatch authentication username.
+   */
+  private static final String AMBARI_DISPATCH_CREDENTIAL_USERNAME = "ambari.dispatch.credential.username";
+
+  /**
+   * The property containing the dispatch authentication password.
+   */
+  private static final String AMBARI_DISPATCH_CREDENTIAL_PASSWORD = "ambari.dispatch.credential.password";
+
+  /**
+   * The property containing the dispatch recipients
+   */
+  private static final String AMBARI_DISPATCH_RECIPIENTS = "ambari.dispatch.recipients";
+
+  /**
+   * Gson used to convert JSON properties to a map.
+   */
+  private final Gson m_gson;
+
+  /**
    * Dispatch DAO to query pending {@link AlertNoticeEntity} instances from.
    */
   @Inject
@@ -84,6 +124,12 @@ public class AlertNoticeDispatchService extends AbstractScheduledService {
         TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>(),
         new AlertDispatchThreadFactory(),
         new ThreadPoolExecutor.CallerRunsPolicy());
+
+    GsonBuilder gsonBuilder = new GsonBuilder();
+    gsonBuilder.registerTypeAdapter(AlertTargetProperties.class,
+        new AlertTargetPropertyDeserializer());
+
+    m_gson = gsonBuilder.create();
   }
 
   /**
@@ -122,16 +168,82 @@ public class AlertNoticeDispatchService extends AbstractScheduledService {
         continue;
       }
 
+      String propertiesJson = target.getProperties();
+      AlertTargetProperties targetProperties = m_gson.fromJson(propertiesJson,
+          AlertTargetProperties.class);
+
+      Map<String, String> properties = targetProperties.Properties;
+
       Notification notification = new Notification();
-      notification.Subject = target.getTargetName();
-      notification.Body = target.getDescription();
       notification.Callback = new AlertNoticeDispatchCallback();
       notification.CallbackIds = new ArrayList<String>(notices.size());
 
+      // !!! FIXME: temporary until velocity templates are implemented
+      String subject = "OK ({0}), Warning ({1}), Critical ({2})";
+      StringBuilder buffer = new StringBuilder(512);
+
+      int okCount = 0;
+      int warningCount = 0;
+      int criticalCount = 0;
+
       for (AlertNoticeEntity notice : notices) {
+        AlertHistoryEntity history = notice.getAlertHistory();
         notification.CallbackIds.add(notice.getUuid());
+
+        AlertState alertState = history.getAlertState();
+        switch (alertState) {
+          case CRITICAL:
+            criticalCount++;
+            break;
+          case OK:
+            okCount++;
+            break;
+          case UNKNOWN:
+            // !!! hmmmmmm
+            break;
+          case WARNING:
+            warningCount++;
+            break;
+          default:
+            break;
+        }
+
+        buffer.append(history.getAlertLabel());
+        buffer.append(": ");
+        buffer.append(history.getAlertText());
+        buffer.append("\n");
       }
 
+      notification.Subject = MessageFormat.format(subject, okCount,
+          warningCount, criticalCount);
+
+      notification.Body = buffer.toString();
+
+      // set dispatch credentials
+      if (properties.containsKey(AMBARI_DISPATCH_CREDENTIAL_USERNAME)
+          && properties.containsKey(AMBARI_DISPATCH_CREDENTIAL_PASSWORD)) {
+        DispatchCredentials credentials = new DispatchCredentials();
+        credentials.UserName = properties.get(AMBARI_DISPATCH_CREDENTIAL_USERNAME);
+        credentials.Password = properties.get(AMBARI_DISPATCH_CREDENTIAL_PASSWORD);
+        notification.Credentials = credentials;
+      }
+
+      if (null != targetProperties.Recipients) {
+        List<Recipient> recipients = new ArrayList<Recipient>(
+            targetProperties.Recipients.size());
+
+        for (String stringRecipient : targetProperties.Recipients) {
+          Recipient recipient = new Recipient();
+          recipient.Identifier = stringRecipient;
+          recipients.add(recipient);
+        }
+
+        notification.Recipients = recipients;
+      }
+
+      // set all other dispatch properties
+      notification.DispatchProperties = properties;
+
       NotificationDispatcher dispatcher = m_dispatchFactory.getDispatcher(target.getNotificationType());
       DispatchRunnable runnable = new DispatchRunnable(dispatcher, notification);
 
@@ -151,6 +263,61 @@ public class AlertNoticeDispatchService extends AbstractScheduledService {
   }
 
   /**
+   * The {@link AlertTargetProperties} separates out the dispatcher properties
+   * from the list of recipients which is a JSON array and not a String.
+   */
+  private static final class AlertTargetProperties {
+    /**
+     * The properties to pass to the concrete dispatcher.
+     */
+    public Map<String, String> Properties;
+
+    /**
+     * The recipients of the notice.
+     */
+    public List<String> Recipients;
+  }
+
+  /**
+   * The {@link AlertTargetPropertyDeserializer} is used to dump the majority of
+   * JSON serialized properties into a {@link Map} of {@link String} while at
+   * the same time, converting
+   * {@link AlertNoticeDispatchService#AMBARI_DISPATCH_RECIPIENTS} into a list.
+   */
+  private static final class AlertTargetPropertyDeserializer implements
+      JsonDeserializer<AlertTargetProperties> {
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public AlertTargetProperties deserialize(JsonElement json, Type typeOfT,
+        JsonDeserializationContext context) throws JsonParseException {
+
+      AlertTargetProperties properties = new AlertTargetProperties();
+      properties.Properties = new HashMap<String, String>();
+
+      final JsonObject jsonObject = json.getAsJsonObject();
+      Set<Entry<String, JsonElement>> entrySet = jsonObject.entrySet();
+
+      for (Entry<String, JsonElement> entry : entrySet) {
+        String entryKey = entry.getKey();
+        JsonElement entryValue = entry.getValue();
+
+        if (entryKey.equals(AMBARI_DISPATCH_RECIPIENTS)) {
+          Type listType = new TypeToken<List<String>>() {}.getType();
+          JsonArray jsonArray = entryValue.getAsJsonArray();
+          properties.Recipients = context.deserialize(jsonArray, listType);
+        } else {
+          properties.Properties.put(entryKey, entryValue.getAsString());
+        }
+      }
+
+      return properties;
+    }
+  }
+
+  /**
    * A custom {@link ThreadFactory} for the threads that will handle dispatching
    * {@link AlertNoticeEntity} instances. Threads created will have slightly
    * reduced priority since {@link AlertEvent} instances are not critical to the

http://git-wip-us.apache.org/repos/asf/ambari/blob/d838ca95/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HDFS/alerts.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HDFS/alerts.json b/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HDFS/alerts.json
index 88503af..620c89f 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HDFS/alerts.json
+++ b/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/HDFS/alerts.json
@@ -2,7 +2,7 @@
   "service": [
     {
       "name": "percent_datanode",
-      "label": "Percent DataNodes live",
+      "label": "Percent DataNodes Live",
       "interval": 1,
       "scope": "SERVICE",
       "source": {

http://git-wip-us.apache.org/repos/asf/ambari/blob/d838ca95/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProviderTest.java
index 1c964a3..b96a4f3 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProviderTest.java
@@ -187,6 +187,39 @@ public class AlertTargetResourceProviderTest {
    * @throws Exception
    */
   @Test
+  public void testCreateWithRecipientArray() throws Exception {
+    Capture<List<AlertTargetEntity>> listCapture = new Capture<List<AlertTargetEntity>>();
+
+    m_dao.createTargets(capture(listCapture));
+    expectLastCall();
+
+    replay(m_amc, m_dao);
+
+    AlertTargetResourceProvider provider = createProvider(m_amc);
+    Map<String, Object> requestProps = getRecipientCreationProperties();
+
+    Request request = PropertyHelper.getCreateRequest(
+        Collections.singleton(requestProps), null);
+    provider.createResources(request);
+
+    Assert.assertTrue(listCapture.hasCaptured());
+    AlertTargetEntity entity = listCapture.getValue().get(0);
+    Assert.assertNotNull(entity);
+
+    assertEquals(ALERT_TARGET_NAME, entity.getTargetName());
+    assertEquals(ALERT_TARGET_DESC, entity.getDescription());
+    assertEquals(ALERT_TARGET_TYPE, entity.getNotificationType());
+    assertEquals(
+        "{\"ambari.dispatch.recipients\":\"[\\\"ambari@ambari.apache.org\\\"]\"}",
+        entity.getProperties());
+
+    verify(m_amc, m_dao);
+  }
+
+  /**
+   * @throws Exception
+   */
+  @Test
   @SuppressWarnings("unchecked")
   public void testUpdateResources() throws Exception {
     Capture<AlertTargetEntity> entityCapture = new Capture<AlertTargetEntity>();
@@ -331,6 +364,31 @@ public class AlertTargetResourceProviderTest {
   }
 
   /**
+   * Gets the maps of properties that simulate a deserialzied JSON request with
+   * a nested JSON array.
+   *
+   * @return
+   * @throws Exception
+   */
+  private Map<String, Object> getRecipientCreationProperties() throws Exception {
+    Map<String, Object> requestProps = new HashMap<String, Object>();
+    requestProps.put(AlertTargetResourceProvider.ALERT_TARGET_NAME,
+        ALERT_TARGET_NAME);
+
+    requestProps.put(AlertTargetResourceProvider.ALERT_TARGET_DESCRIPTION,
+        ALERT_TARGET_DESC);
+
+    requestProps.put(
+        AlertTargetResourceProvider.ALERT_TARGET_NOTIFICATION_TYPE,
+        ALERT_TARGET_TYPE);
+
+    requestProps.put(AlertTargetResourceProvider.ALERT_TARGET_PROPERTIES
+        + "/ambari.dispatch.recipients", "[\"ambari@ambari.apache.org\"]");
+
+    return requestProps;
+  }
+
+  /**
   *
   */
   private class MockModule implements Module {

http://git-wip-us.apache.org/repos/asf/ambari/blob/d838ca95/ambari-server/src/test/java/org/apache/ambari/server/notifications/EmailDispatcherTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/notifications/EmailDispatcherTest.java b/ambari-server/src/test/java/org/apache/ambari/server/notifications/EmailDispatcherTest.java
new file mode 100644
index 0000000..1e7689f
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/notifications/EmailDispatcherTest.java
@@ -0,0 +1,117 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.notifications;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
+import org.apache.ambari.server.state.alert.TargetType;
+import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.inject.Binder;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Module;
+import com.google.inject.util.Modules;
+
+/**
+ *
+ */
+public class EmailDispatcherTest {
+
+  private Injector m_injector;
+  private DispatchFactory m_dispatchFactory;
+
+  @Before
+  public void before() throws Exception {
+    m_injector = Guice.createInjector(Modules.override(
+        new InMemoryDefaultTestModule()).with(new MockModule()));
+
+    m_dispatchFactory = m_injector.getInstance(DispatchFactory.class);
+  }
+
+  /**
+   * Tests that an email without recipients causes a callback error.
+   */
+  @Test
+  public void testNoRecipients() {
+    Notification notification = new Notification();
+    DispatchCallback callback = EasyMock.createMock(DispatchCallback.class);
+    notification.Callback = callback;
+
+    List<String> callbackIds = new ArrayList<String>();
+    callbackIds.add(UUID.randomUUID().toString());
+    notification.CallbackIds = callbackIds;
+
+    callback.onFailure(callbackIds);
+
+    EasyMock.expectLastCall();
+    EasyMock.replay(callback);
+
+    NotificationDispatcher dispatcher = m_dispatchFactory.getDispatcher(TargetType.EMAIL.name());
+    dispatcher.dispatch(notification);
+
+    EasyMock.verify(callback);
+  }
+
+  /**
+   * Tests that an email without properties causes a callback error.
+   */
+  @Test
+  public void testNoEmailPropeties() {
+    Notification notification = new Notification();
+    DispatchCallback callback = EasyMock.createMock(DispatchCallback.class);
+    notification.Callback = callback;
+    notification.Recipients = new ArrayList<Recipient>();
+
+    Recipient recipient = new Recipient();
+    recipient.Identifier = "foo";
+
+    notification.Recipients.add(recipient);
+
+    List<String> callbackIds = new ArrayList<String>();
+    callbackIds.add(UUID.randomUUID().toString());
+    notification.CallbackIds = callbackIds;
+
+    callback.onFailure(callbackIds);
+
+    EasyMock.expectLastCall();
+    EasyMock.replay(callback);
+
+    NotificationDispatcher dispatcher = m_dispatchFactory.getDispatcher(TargetType.EMAIL.name());
+    dispatcher.dispatch(notification);
+
+    EasyMock.verify(callback);
+  }
+
+  /**
+   *
+   */
+  private class MockModule implements Module {
+    /**
+     *
+     */
+    @Override
+    public void configure(Binder binder) {
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/d838ca95/ambari-server/src/test/java/org/apache/ambari/server/notifications/MockDispatcher.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/notifications/MockDispatcher.java b/ambari-server/src/test/java/org/apache/ambari/server/notifications/MockDispatcher.java
new file mode 100644
index 0000000..616551f
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/notifications/MockDispatcher.java
@@ -0,0 +1,46 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.notifications;
+
+/**
+ *
+ */
+public class MockDispatcher implements NotificationDispatcher {
+
+  /**
+   * Constructor.
+   *
+   */
+  public MockDispatcher() {
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getType() {
+    return "MOCK";
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void dispatch(Notification notification) {
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/d838ca95/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 9e638e8..6e4d4af 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
@@ -22,6 +22,7 @@ package org.apache.ambari.server.orm.dao;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
 import java.util.ArrayList;
 import java.util.Calendar;
@@ -63,7 +64,7 @@ public class AlertsDAOTest {
   private AlertDefinitionDAO definitionDao;
 
   /**
-   * 
+   *
    */
   @Before
   public void setup() throws Exception {
@@ -88,7 +89,7 @@ public class AlertsDAOTest {
       definition.setSourceType(SourceType.SCRIPT);
       definitionDao.create(definition);
     }
-    
+
     List<AlertDefinitionEntity> definitions = definitionDao.findAll();
     assertNotNull(definitions);
     assertEquals(5, definitions.size());
@@ -142,7 +143,7 @@ public class AlertsDAOTest {
   }
 
   /**
-   * 
+   *
    */
   @After
   public void teardown() {
@@ -152,7 +153,7 @@ public class AlertsDAOTest {
 
 
   /**
-   * 
+   *
    */
   @Test
   public void testFindAll() {
@@ -162,7 +163,7 @@ public class AlertsDAOTest {
   }
 
   /**
-   * 
+   *
    */
   @Test
   public void testFindAllCurrent() {
@@ -172,16 +173,16 @@ public class AlertsDAOTest {
   }
 
   /**
-   * 
+   *
    */
   @Test
   public void testFindCurrentByService() {
     List<AlertCurrentEntity> currentAlerts = dao.findCurrent();
     AlertCurrentEntity current = currentAlerts.get(0);
     AlertHistoryEntity history = current.getAlertHistory();
-    
+
     assertNotNull(history);
-    
+
     currentAlerts = dao.findCurrentByService(clusterId,
         history.getServiceName());
 
@@ -193,7 +194,7 @@ public class AlertsDAOTest {
     assertNotNull(currentAlerts);
     assertEquals(0, currentAlerts.size());
   }
-  
+
   /**
    * Test looking up current by a host name.
    */
@@ -211,7 +212,7 @@ public class AlertsDAOTest {
     hostDef.setSource("HostService");
     hostDef.setSourceType(SourceType.SCRIPT);
     definitionDao.create(hostDef);
-    
+
     // history for the definition
     AlertHistoryEntity history = new AlertHistoryEntity();
     history.setServiceName(hostDef.getServiceName());
@@ -222,14 +223,14 @@ public class AlertsDAOTest {
     history.setAlertTimestamp(Long.valueOf(1L));
     history.setHostName("h2");
     history.setAlertState(AlertState.OK);
-    
+
     // current for the history
     AlertCurrentEntity current = new AlertCurrentEntity();
     current.setOriginalTimestamp(1L);
     current.setLatestTimestamp(2L);
     current.setAlertHistory(history);
     dao.create(current);
-    
+
     List<AlertCurrentEntity> currentAlerts = dao.findCurrentByHost(clusterId, history.getHostName());
 
     assertNotNull(currentAlerts);
@@ -239,10 +240,10 @@ public class AlertsDAOTest {
 
     assertNotNull(currentAlerts);
     assertEquals(0, currentAlerts.size());
-  }  
+  }
 
   /**
-   * 
+   *
    */
   @Test
   public void testFindByState() {
@@ -250,7 +251,7 @@ public class AlertsDAOTest {
     allStates.add(AlertState.OK);
     allStates.add(AlertState.WARNING);
     allStates.add(AlertState.CRITICAL);
-        
+
     List<AlertHistoryEntity> history = dao.findAll(clusterId, allStates);
     assertNotNull(history);
     assertEquals(50, history.size());
@@ -263,21 +264,21 @@ public class AlertsDAOTest {
         Collections.singletonList(AlertState.CRITICAL));
     assertNotNull(history);
     assertEquals(10, history.size());
-    
+
     history = dao.findAll(clusterId,
         Collections.singletonList(AlertState.WARNING));
     assertNotNull(history);
-    assertEquals(0, history.size());        
+    assertEquals(0, history.size());
   }
 
   /**
-   * 
+   *
    */
   @Test
   public void testFindByDate() {
     calendar.clear();
     calendar.set(2014, Calendar.JANUARY, 1);
-    
+
     // on or after 1/1/2014
     List<AlertHistoryEntity> history = dao.findAll(clusterId,
         calendar.getTime(), null);
@@ -311,21 +312,21 @@ public class AlertsDAOTest {
     assertNotNull(history);
     assertEquals(0, history.size());
   }
-  
+
   @Test
   public void testFindCurrentByHostAndName() throws Exception {
     AlertCurrentEntity entity = dao.findCurrentByHostAndName(clusterId.longValue(), "h2", "Alert Definition 1");
     assertNull(entity);
-    
+
     entity = dao.findCurrentByHostAndName(clusterId.longValue(), "h1", "Alert Definition 1");
-    
+
     assertNotNull(entity);
     assertNotNull(entity.getAlertHistory());
     assertNotNull(entity.getAlertHistory().getAlertDefinition());
   }
-  
+
   /**
-   * 
+   *
    */
   @Test
   public void testFindCurrentSummary() throws Exception {
@@ -341,12 +342,12 @@ public class AlertsDAOTest {
     dao.merge(h2);
     h3.setAlertState(AlertState.UNKNOWN);
     dao.merge(h3);
-    
+
     int ok = 0;
     int warn = 0;
     int crit = 0;
     int unk = 0;
-    
+
     for (AlertCurrentEntity h : dao.findCurrentByCluster(clusterId.longValue())) {
       switch (h.getAlertHistory().getAlertState()) {
         case CRITICAL:
@@ -362,22 +363,22 @@ public class AlertsDAOTest {
           warn++;
           break;
       }
-        
+
     }
-      
+
     summary = dao.findCurrentCounts(clusterId.longValue(), null, null);
     // !!! db-to-db compare
     assertEquals(ok, summary.getOkCount());
     assertEquals(warn, summary.getWarningCount());
     assertEquals(crit, summary.getCriticalCount());
     assertEquals(unk, summary.getCriticalCount());
-    
+
     // !!! expected
     assertEquals(2, summary.getOkCount());
     assertEquals(1, summary.getWarningCount());
     assertEquals(1, summary.getCriticalCount());
     assertEquals(1, summary.getCriticalCount());
-    
+
     summary = dao.findCurrentCounts(clusterId.longValue(), "Service 0", null);
     assertEquals(1, summary.getOkCount());
     assertEquals(0, summary.getWarningCount());
@@ -389,15 +390,14 @@ public class AlertsDAOTest {
     assertEquals(1, summary.getWarningCount());
     assertEquals(1, summary.getCriticalCount());
     assertEquals(1, summary.getCriticalCount());
-    
+
     summary = dao.findCurrentCounts(clusterId.longValue(), "foo", null);
     assertEquals(0, summary.getOkCount());
     assertEquals(0, summary.getWarningCount());
     assertEquals(0, summary.getCriticalCount());
     assertEquals(0, summary.getCriticalCount());
-    
   }
-  
+
   @Test
   public void testFindAggregates() throws Exception {
     // definition
@@ -412,7 +412,7 @@ public class AlertsDAOTest {
     definition.setSource("SourceScript");
     definition.setSourceType(SourceType.SCRIPT);
     definitionDao.create(definition);
-    
+
     // history record #1 and current
     AlertHistoryEntity history = new AlertHistoryEntity();
     history.setAlertDefinition(definition);
@@ -425,13 +425,13 @@ public class AlertsDAOTest {
     history.setComponentName("");
     history.setHostName("h1");
     history.setServiceName("ServiceName");
-    
+
     AlertCurrentEntity current = new AlertCurrentEntity();
     current.setAlertHistory(history);
     current.setLatestTimestamp(Long.valueOf(1L));
     current.setOriginalTimestamp(Long.valueOf(1L));
     dao.merge(current);
-    
+
     // history record #2 and current
     history = new AlertHistoryEntity();
     history.setAlertDefinition(definition);
@@ -444,35 +444,84 @@ public class AlertsDAOTest {
     history.setComponentName("");
     history.setHostName("h2");
     history.setServiceName("ServiceName");
-    
+
     current = new AlertCurrentEntity();
     current.setAlertHistory(history);
     current.setLatestTimestamp(Long.valueOf(1L));
     current.setOriginalTimestamp(Long.valueOf(1L));
     dao.merge(current);
-    
+
     AlertSummaryDTO summary = dao.findAggregateCounts(clusterId.longValue(), "many_per_cluster");
     assertEquals(2, summary.getOkCount());
     assertEquals(0, summary.getWarningCount());
     assertEquals(0, summary.getCriticalCount());
     assertEquals(0, summary.getUnknownCount());
-    
+
     AlertCurrentEntity c = dao.findCurrentByHostAndName(clusterId.longValue(),
         "h2", "many_per_cluster");
     AlertHistoryEntity h = c.getAlertHistory();
     h.setAlertState(AlertState.CRITICAL);
     dao.merge(h);
-    
+
     summary = dao.findAggregateCounts(clusterId.longValue(), "many_per_cluster");
     assertEquals(2, summary.getOkCount());
     assertEquals(0, summary.getWarningCount());
     assertEquals(1, summary.getCriticalCount());
     assertEquals(0, summary.getUnknownCount());
-    
+
     summary = dao.findAggregateCounts(clusterId.longValue(), "foo");
     assertEquals(0, summary.getOkCount());
     assertEquals(0, summary.getWarningCount());
     assertEquals(0, summary.getCriticalCount());
     assertEquals(0, summary.getUnknownCount());
-  }  
+  }
+
+  /**
+   * Tests <a
+   * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=398067">https:/
+   * /bugs.eclipse.org/bugs/show_bug.cgi?id=398067</a> which causes an inner
+   * entity to be stale.
+   */
+  @Test
+  public void testJPAInnerEntityStaleness() {
+    List<AlertCurrentEntity> currents = dao.findCurrent();
+    AlertCurrentEntity current = currents.get(0);
+    AlertHistoryEntity oldHistory = current.getAlertHistory();
+
+    AlertHistoryEntity newHistory = new AlertHistoryEntity();
+    newHistory.setAlertDefinition(oldHistory.getAlertDefinition());
+    newHistory.setAlertInstance(oldHistory.getAlertInstance());
+    newHistory.setAlertLabel(oldHistory.getAlertLabel());
+
+    if (oldHistory.getAlertState() == AlertState.OK) {
+      newHistory.setAlertState(AlertState.CRITICAL);
+    } else {
+      newHistory.setAlertState(AlertState.OK);
+    }
+
+    newHistory.setAlertText("New History");
+    newHistory.setClusterId(oldHistory.getClusterId());
+    newHistory.setAlertTimestamp(System.currentTimeMillis());
+    newHistory.setComponentName(oldHistory.getComponentName());
+    newHistory.setHostName(oldHistory.getHostName());
+    newHistory.setServiceName(oldHistory.getServiceName());
+
+    dao.create(newHistory);
+
+    assertTrue(newHistory.getAlertId().longValue() != oldHistory.getAlertId().longValue());
+
+    current.setAlertHistory(newHistory);
+    dao.merge(current);
+
+    AlertCurrentEntity newCurrent = dao.findCurrentByHostAndName(
+        newHistory.getClusterId(),
+        newHistory.getHostName(),
+        newHistory.getAlertDefinition().getDefinitionName());
+
+    assertEquals(newHistory.getAlertId(),
+        newCurrent.getAlertHistory().getAlertId());
+
+    assertEquals(newHistory.getAlertState(),
+        newCurrent.getAlertHistory().getAlertState());
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/d838ca95/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertStateChangedEventTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertStateChangedEventTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertStateChangedEventTest.java
new file mode 100644
index 0000000..312f297
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertStateChangedEventTest.java
@@ -0,0 +1,139 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state.alerts;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.ambari.server.events.AlertStateChangeEvent;
+import org.apache.ambari.server.events.listeners.AlertServiceStateListener;
+import org.apache.ambari.server.events.listeners.AlertStateChangedListener;
+import org.apache.ambari.server.events.publishers.AlertEventPublisher;
+import org.apache.ambari.server.orm.GuiceJpaInitializer;
+import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
+import org.apache.ambari.server.orm.dao.AlertDispatchDAO;
+import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
+import org.apache.ambari.server.orm.entities.AlertGroupEntity;
+import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
+import org.apache.ambari.server.orm.entities.AlertNoticeEntity;
+import org.apache.ambari.server.orm.entities.AlertTargetEntity;
+import org.easymock.EasyMock;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.inject.Binder;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Module;
+import com.google.inject.persist.PersistService;
+import com.google.inject.util.Modules;
+
+/**
+ * Tests that {@link AlertStateChangeEvent} instances cause
+ * {@link AlertNoticeEntity} instances to be created.
+ */
+public class AlertStateChangedEventTest {
+
+  private AlertEventPublisher eventPublisher;
+  private AlertDispatchDAO dispatchDao;
+  private Injector injector;
+
+  /**
+   *
+   */
+  @Before
+  public void setup() throws Exception {
+    injector = Guice.createInjector(Modules.override(
+        new InMemoryDefaultTestModule()).with(new MockModule()));
+
+    injector.getInstance(GuiceJpaInitializer.class);
+
+    // force singleton init via Guice so the listener registers with the bus
+    injector.getInstance(AlertServiceStateListener.class);
+    injector.getInstance(AlertStateChangedListener.class);
+
+    dispatchDao = injector.getInstance(AlertDispatchDAO.class);
+    eventPublisher = injector.getInstance(AlertEventPublisher.class);
+  }
+
+  /**
+   * @throws Exception
+   */
+  @After
+  public void teardown() throws Exception {
+    injector.getInstance(PersistService.class).stop();
+    injector = null;
+  }
+
+  /**
+   * Tests that an {@link AlertStateChangeEvent} causes
+   * {@link AlertNoticeEntity} instances to be written.
+   *
+   * @throws Exception
+   */
+  @Test
+  public void testAlertNoticeCreationFromEvent() throws Exception {
+    AlertHistoryEntity history = EasyMock.createNiceMock(AlertHistoryEntity.class);
+    AlertStateChangeEvent event = EasyMock.createNiceMock(AlertStateChangeEvent.class);
+    EasyMock.expect(event.getNewHistoricalEntry()).andReturn(history).atLeastOnce();
+
+    EasyMock.replay(history, event);
+
+    // async publishing
+    eventPublisher.publish(event);
+    Thread.sleep(2000);
+
+    EasyMock.verify(dispatchDao, history, event);
+  }
+
+  /**
+   *
+   */
+  private class MockModule implements Module {
+    /**
+    *
+    */
+    @Override
+    public void configure(Binder binder) {
+      AlertTargetEntity alertTarget = EasyMock.createMock(AlertTargetEntity.class);
+      AlertGroupEntity alertGroup = EasyMock.createMock(AlertGroupEntity.class);
+      List<AlertGroupEntity> groups = new ArrayList<AlertGroupEntity>();
+      Set<AlertTargetEntity> targets = new HashSet<AlertTargetEntity>();
+
+      targets.add(alertTarget);
+      groups.add(alertGroup);
+
+      EasyMock.expect(alertGroup.getAlertTargets()).andReturn(targets).once();
+
+      AlertDispatchDAO dispatchDao = EasyMock.createMock(AlertDispatchDAO.class);
+      EasyMock.expect(
+          dispatchDao.findGroupsByDefinition(EasyMock.anyObject(AlertDefinitionEntity.class))).andReturn(
+          groups).once();
+
+      dispatchDao.create(EasyMock.anyObject(AlertNoticeEntity.class));
+      EasyMock.expectLastCall().once();
+
+      binder.bind(AlertDispatchDAO.class).toInstance(dispatchDao);
+
+      EasyMock.replay(alertTarget, alertGroup, dispatchDao);
+    }
+  }
+}


[02/50] [abbrv] AMBARI-7021 - Alerts: Create Group and Target REST Endpoints (jonathanhurley)

Posted by jo...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProviderTest.java
new file mode 100644
index 0000000..982dd4b
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProviderTest.java
@@ -0,0 +1,290 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.controller.internal;
+
+import static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.createStrictMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.resetToStrict;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.utilities.PredicateBuilder;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.metadata.ActionMetadata;
+import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
+import org.apache.ambari.server.orm.dao.AlertDispatchDAO;
+import org.apache.ambari.server.orm.entities.AlertTargetEntity;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.alert.TargetType;
+import org.easymock.Capture;
+import org.easymock.EasyMock;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.inject.Binder;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Module;
+import com.google.inject.util.Modules;
+
+/**
+ * {@link AlertTargetResourceProvider} tests.
+ */
+public class AlertTargetResourceProviderTest {
+
+  private static final Long ALERT_TARGET_ID = Long.valueOf(28);
+  private static final String ALERT_TARGET_NAME = "The Administrators";
+  private static final String ALERT_TARGET_DESC = "Admins and Others";
+  private static final String ALERT_TARGET_TYPE = TargetType.EMAIL.name();
+
+  private AlertDispatchDAO m_dao;
+  private Injector m_injector;
+
+  @Before
+  public void before() {
+    m_dao = createStrictMock(AlertDispatchDAO.class);
+
+    m_injector = Guice.createInjector(Modules.override(
+        new InMemoryDefaultTestModule()).with(new MockModule()));
+
+    AlertTargetResourceProvider.init(m_injector);
+  }
+
+  /**
+   * @throws Exception
+   */
+  @Test
+  public void testGetResourcesNoPredicate() throws Exception {
+    Request request = PropertyHelper.getReadRequest(
+        AlertTargetResourceProvider.ALERT_TARGET_DESCRIPTION,
+        AlertTargetResourceProvider.ALERT_TARGET_ID,
+        AlertTargetResourceProvider.ALERT_TARGET_NAME,
+        AlertTargetResourceProvider.ALERT_TARGET_NOTIFICATION_TYPE);
+
+    expect(m_dao.findAllTargets()).andReturn(getMockEntities());
+    replay(m_dao);
+
+    AmbariManagementController amc = createMock(AmbariManagementController.class);
+    AlertTargetResourceProvider provider = createProvider(amc);
+    Set<Resource> results = provider.getResources(request, null);
+
+    assertEquals(1, results.size());
+
+    Resource r = results.iterator().next();
+    Assert.assertEquals(ALERT_TARGET_NAME,
+        r.getPropertyValue(AlertTargetResourceProvider.ALERT_TARGET_NAME));
+
+    verify(m_dao);
+  }
+
+  /**
+   * @throws Exception
+   */
+  @Test
+  public void testGetSingleResource() throws Exception {
+    Request request = PropertyHelper.getReadRequest(
+        AlertTargetResourceProvider.ALERT_TARGET_DESCRIPTION,
+        AlertTargetResourceProvider.ALERT_TARGET_ID,
+        AlertTargetResourceProvider.ALERT_TARGET_NAME,
+        AlertTargetResourceProvider.ALERT_TARGET_NOTIFICATION_TYPE);
+
+    AmbariManagementController amc = createMock(AmbariManagementController.class);
+
+    Predicate predicate = new PredicateBuilder().property(
+        AlertTargetResourceProvider.ALERT_TARGET_ID).equals(
+        ALERT_TARGET_ID.toString()).toPredicate();
+
+    expect(m_dao.findTargetById(ALERT_TARGET_ID.longValue())).andReturn(
+        getMockEntities().get(0));
+
+    replay(amc, m_dao);
+
+    AlertTargetResourceProvider provider = createProvider(amc);
+    Set<Resource> results = provider.getResources(request, predicate);
+
+    assertEquals(1, results.size());
+
+    Resource r = results.iterator().next();
+    Assert.assertEquals(ALERT_TARGET_ID,
+        r.getPropertyValue(AlertTargetResourceProvider.ALERT_TARGET_ID));
+
+    Assert.assertEquals(ALERT_TARGET_NAME,
+        r.getPropertyValue(AlertTargetResourceProvider.ALERT_TARGET_NAME));
+
+    verify(amc, m_dao);
+  }
+
+  /**
+   * @throws Exception
+   */
+  @Test
+  public void testCreateResources() throws Exception {
+    AmbariManagementController amc = createMock(AmbariManagementController.class);
+    Capture<List<AlertTargetEntity>> listCapture = new Capture<List<AlertTargetEntity>>();
+
+    m_dao.createTargets(capture(listCapture));
+    expectLastCall();
+
+    replay(amc, m_dao);
+
+    AlertTargetResourceProvider provider = createProvider(amc);
+    Map<String, Object> requestProps = new HashMap<String, Object>();
+    requestProps.put(AlertTargetResourceProvider.ALERT_TARGET_NAME,
+        ALERT_TARGET_NAME);
+
+    requestProps.put(AlertTargetResourceProvider.ALERT_TARGET_DESCRIPTION,
+        ALERT_TARGET_DESC);
+
+    requestProps.put(
+        AlertTargetResourceProvider.ALERT_TARGET_NOTIFICATION_TYPE,
+        ALERT_TARGET_TYPE);
+
+    Request request = PropertyHelper.getCreateRequest(Collections.singleton(requestProps), null);
+    provider.createResources(request);
+
+    Assert.assertTrue(listCapture.hasCaptured());
+    AlertTargetEntity entity = listCapture.getValue().get(0);
+    Assert.assertNotNull(entity);
+
+    Assert.assertEquals(ALERT_TARGET_NAME, entity.getTargetName());
+    Assert.assertEquals(ALERT_TARGET_DESC, entity.getDescription());
+    Assert.assertEquals(ALERT_TARGET_TYPE, entity.getNotificationType());
+
+    verify(amc, m_dao);
+  }
+
+  /**
+   * @throws Exception
+   */
+  @Test
+  public void testUpdateResources() throws Exception {
+  }
+
+  /**
+   * @throws Exception
+   */
+  @Test
+  public void testDeleteResources() throws Exception {
+    AmbariManagementController amc = createMock(AmbariManagementController.class);
+    Capture<AlertTargetEntity> entityCapture = new Capture<AlertTargetEntity>();
+    Capture<List<AlertTargetEntity>> listCapture = new Capture<List<AlertTargetEntity>>();
+
+    m_dao.createTargets(capture(listCapture));
+    expectLastCall();
+
+    replay(amc, m_dao);
+
+    AlertTargetResourceProvider provider = createProvider(amc);
+
+    Map<String, Object> requestProps = new HashMap<String, Object>();
+    requestProps.put(AlertTargetResourceProvider.ALERT_TARGET_NAME,
+        ALERT_TARGET_NAME);
+
+    requestProps.put(AlertTargetResourceProvider.ALERT_TARGET_DESCRIPTION,
+        ALERT_TARGET_DESC);
+
+    requestProps.put(
+        AlertTargetResourceProvider.ALERT_TARGET_NOTIFICATION_TYPE,
+        ALERT_TARGET_TYPE);
+
+    Request request = PropertyHelper.getCreateRequest(Collections.singleton(requestProps), null);
+    provider.createResources(request);
+
+    Assert.assertTrue(listCapture.hasCaptured());
+    AlertTargetEntity entity = listCapture.getValue().get(0);
+    Assert.assertNotNull(entity);
+
+    Predicate p = new PredicateBuilder().property(
+        AlertTargetResourceProvider.ALERT_TARGET_ID).equals(
+        ALERT_TARGET_ID.toString()).toPredicate();
+
+    // everything is mocked, there is no DB
+    entity.setTargetId(ALERT_TARGET_ID);
+
+    resetToStrict(m_dao);
+    expect(m_dao.findTargetById(ALERT_TARGET_ID.longValue())).andReturn(entity).anyTimes();
+    m_dao.remove(capture(entityCapture));
+    expectLastCall();
+    replay(m_dao);
+
+    provider.deleteResources(p);
+
+    AlertTargetEntity entity1 = entityCapture.getValue();
+    Assert.assertEquals(ALERT_TARGET_ID, entity1.getTargetId());
+
+    verify(amc, m_dao);
+  }
+
+  /**
+   * @param amc
+   * @return
+   */
+  private AlertTargetResourceProvider createProvider(
+      AmbariManagementController amc) {
+    return new AlertTargetResourceProvider(
+        PropertyHelper.getPropertyIds(Resource.Type.AlertTarget),
+        PropertyHelper.getKeyPropertyIds(Resource.Type.AlertTarget), amc);
+  }
+
+  /**
+   * @return
+   */
+  private List<AlertTargetEntity> getMockEntities() throws Exception {
+    AlertTargetEntity entity = new AlertTargetEntity();
+    entity.setTargetId(ALERT_TARGET_ID);
+    entity.setDescription(ALERT_TARGET_DESC);
+    entity.setTargetName(ALERT_TARGET_NAME);
+    entity.setNotificationType(TargetType.EMAIL.name());
+    return Arrays.asList(entity);
+  }
+
+  /**
+  *
+  */
+  private class MockModule implements Module {
+    /**
+    *
+    */
+    @Override
+    public void configure(Binder binder) {
+      binder.bind(AlertDispatchDAO.class).toInstance(m_dao);
+      binder.bind(Clusters.class).toInstance(
+          EasyMock.createNiceMock(Clusters.class));
+      binder.bind(Cluster.class).toInstance(
+          EasyMock.createNiceMock(Cluster.class));
+      binder.bind(ActionMetadata.class);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a4644b8/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java
index c0bdaa2..d7c8c54 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java
@@ -105,12 +105,12 @@ public class ServiceComponentHostTest {
     metaInfo.init();
     clusters.mapHostToCluster("h1","C1");
   }
-  
+
   private void setOsFamily(Host host, String osFamily, String osVersion) {
     Map<String, String> hostAttributes = new HashMap<String, String>(2);
     hostAttributes.put("os_family", osFamily);
     hostAttributes.put("os_release_version", osVersion);
-    
+
     host.setHostAttributes(hostAttributes);
   }
 
@@ -118,15 +118,16 @@ public class ServiceComponentHostTest {
   public void teardown() {
     injector.getInstance(PersistService.class).stop();
   }
-  
+
   private ServiceComponentHost createNewServiceComponentHost(
       String svc,
       String svcComponent,
       String hostName, boolean isClient) throws AmbariException{
     Cluster c = clusters.getCluster("C1");
-    
+
     return createNewServiceComponentHost(c, svc, svcComponent, hostName);
   }
+
   private ServiceComponentHost createNewServiceComponentHost(
       Cluster c,
       String svc,
@@ -156,18 +157,22 @@ public class ServiceComponentHostTest {
 
     ServiceComponentHost impl = serviceComponentHostFactory.createNew(
         sc, hostName);
+
     impl.persist();
-    Assert.assertEquals(State.INIT,
-        impl.getState());
-    Assert.assertEquals(State.INIT,
-        impl.getDesiredState());
+
+    Assert.assertEquals(State.INIT, impl.getState());
+    Assert.assertEquals(State.INIT, impl.getDesiredState());
     Assert.assertEquals(c.getClusterName(), impl.getClusterName());
     Assert.assertEquals(c.getClusterId(), impl.getClusterId());
     Assert.assertEquals(s.getName(), impl.getServiceName());
     Assert.assertEquals(sc.getName(), impl.getServiceComponentName());
     Assert.assertEquals(hostName, impl.getHostName());
+
+    Assert.assertNotNull(c.getServiceComponentHosts(hostName));
+
     Assert.assertFalse(
         impl.getDesiredStackVersion().getStackId().isEmpty());
+
     Assert.assertTrue(impl.getStackVersion().getStackId().isEmpty());
 
     return impl;
@@ -264,7 +269,7 @@ public class ServiceComponentHostTest {
 
     ServiceComponentHostEvent installEvent2 = createEvent(impl, ++timestamp,
         startEventType);
-   
+
     boolean exceptionThrown = false;
     LOG.info("Transitioning from " + impl.getState() + " " + installEvent2.getType());
     try {
@@ -503,7 +508,7 @@ public class ServiceComponentHostTest {
     Assert.assertEquals("HDP-1.1.0",
         sch.getDesiredStackVersion().getStackId());
   }
-  
+
   @Test
   public void testActualConfigs() throws Exception {
     ServiceComponentHost sch =
@@ -520,25 +525,25 @@ public class ServiceComponentHostTest {
 
     configGroup.persist();
     cluster.addConfigGroup(configGroup);
-    
+
     Map<String, Map<String,String>> actual =
         new HashMap<String, Map<String, String>>() {{
           put("global", new HashMap<String,String>() {{ put("tag", "version1"); }});
           put("core-site", new HashMap<String,String>() {{ put("tag", "version1");
             put(configGroup.getId().toString(), "version2"); }});
         }};
-        
+
     sch.updateActualConfigs(actual);
-    
+
     Map<String, HostConfig> confirm = sch.getActualConfigs();
-    
+
     Assert.assertEquals(2, confirm.size());
     Assert.assertTrue(confirm.containsKey("global"));
     Assert.assertTrue(confirm.containsKey("core-site"));
     Assert.assertEquals(1, confirm.get("core-site").getConfigGroupOverrides().size());
 
   }
-  
+
   @Test
   public void testConvertToResponse() throws AmbariException {
     ServiceComponentHost sch =
@@ -555,7 +560,7 @@ public class ServiceComponentHostTest {
     Assert.assertEquals(State.INSTALLED.toString(), r.getDesiredState());
     Assert.assertEquals(State.INSTALLING.toString(), r.getLiveState());
     Assert.assertEquals("HDP-1.0.0", r.getStackVersion());
-    
+
     Assert.assertFalse(r.isStaleConfig());
 
     // TODO check configs
@@ -615,62 +620,61 @@ public class ServiceComponentHostTest {
         impl.getState());
   }
 
-   @Test
-   public void TestDisableInVariousStates() throws AmbariException,
-           InvalidStateTransitionException {
-       ServiceComponentHost sch =
-               createNewServiceComponentHost("HDFS", "DATANODE", "h1", false);
-       ServiceComponentHostImpl impl =  (ServiceComponentHostImpl) sch;
-
-       // Test valid states in which host component can be disabled
-       long timestamp = 0;
-       HashSet<State> validStates = new HashSet<State>();
-       validStates.add(State.INSTALLED);
-       validStates.add(State.INSTALL_FAILED);
-       validStates.add(State.UNKNOWN);
-       validStates.add(State.DISABLED);
-       for (State state : validStates)
-       {
-         sch.setState(state);
-         ServiceComponentHostEvent disableEvent = createEvent(
-                   impl, ++timestamp, ServiceComponentHostEventType.HOST_SVCCOMP_DISABLE);
-         impl.handleEvent(disableEvent);
-         // TODO: At present operation timestamps are not getting updated.
-         Assert.assertEquals(-1, impl.getLastOpStartTime());
-         Assert.assertEquals(-1, impl.getLastOpLastUpdateTime());
-         Assert.assertEquals(-1, impl.getLastOpEndTime());
-         Assert.assertEquals(State.DISABLED, impl.getState());
-       }
-
-       // Test invalid states in which host component cannot be disabled
-       HashSet<State> invalidStates = new HashSet<State>();
-       invalidStates.add(State.INIT);
-       invalidStates.add(State.INSTALLING);
-       invalidStates.add(State.STARTING);
-       invalidStates.add(State.STARTED);
-       invalidStates.add(State.STOPPING);
-       invalidStates.add(State.UNINSTALLING);
-       invalidStates.add(State.UNINSTALLED);
-       invalidStates.add(State.UPGRADING);
-
-       for(State state : invalidStates)
-       {
-           sch.setState(state);
-           ServiceComponentHostEvent disableEvent = createEvent(
-                   impl, ++timestamp, ServiceComponentHostEventType.HOST_SVCCOMP_DISABLE);
-           boolean exceptionThrown = false;
-           try {
-               impl.handleEvent(disableEvent);
-           } catch (Exception e) {
-               exceptionThrown = true;
-           }
-           Assert.assertTrue("Exception not thrown on invalid event", exceptionThrown);
-           // TODO: At present operation timestamps are not getting updated.
-           Assert.assertEquals(-1, impl.getLastOpStartTime());
-           Assert.assertEquals(-1, impl.getLastOpLastUpdateTime());
-           Assert.assertEquals(-1, impl.getLastOpEndTime());
-       }
-   }
+  @Test
+  public void testDisableInVariousStates() throws AmbariException,
+      InvalidStateTransitionException {
+    ServiceComponentHost sch = createNewServiceComponentHost("HDFS",
+        "DATANODE", "h1", false);
+    ServiceComponentHostImpl impl = (ServiceComponentHostImpl) sch;
+
+    // Test valid states in which host component can be disabled
+    long timestamp = 0;
+    HashSet<State> validStates = new HashSet<State>();
+    validStates.add(State.INSTALLED);
+    validStates.add(State.INSTALL_FAILED);
+    validStates.add(State.UNKNOWN);
+    validStates.add(State.DISABLED);
+    for (State state : validStates) {
+      sch.setState(state);
+      ServiceComponentHostEvent disableEvent = createEvent(impl, ++timestamp,
+          ServiceComponentHostEventType.HOST_SVCCOMP_DISABLE);
+      impl.handleEvent(disableEvent);
+      // TODO: At present operation timestamps are not getting updated.
+      Assert.assertEquals(-1, impl.getLastOpStartTime());
+      Assert.assertEquals(-1, impl.getLastOpLastUpdateTime());
+      Assert.assertEquals(-1, impl.getLastOpEndTime());
+      Assert.assertEquals(State.DISABLED, impl.getState());
+    }
+
+    // Test invalid states in which host component cannot be disabled
+    HashSet<State> invalidStates = new HashSet<State>();
+    invalidStates.add(State.INIT);
+    invalidStates.add(State.INSTALLING);
+    invalidStates.add(State.STARTING);
+    invalidStates.add(State.STARTED);
+    invalidStates.add(State.STOPPING);
+    invalidStates.add(State.UNINSTALLING);
+    invalidStates.add(State.UNINSTALLED);
+    invalidStates.add(State.UPGRADING);
+
+    for (State state : invalidStates) {
+      sch.setState(state);
+      ServiceComponentHostEvent disableEvent = createEvent(impl, ++timestamp,
+          ServiceComponentHostEventType.HOST_SVCCOMP_DISABLE);
+      boolean exceptionThrown = false;
+      try {
+        impl.handleEvent(disableEvent);
+      } catch (Exception e) {
+        exceptionThrown = true;
+      }
+      Assert.assertTrue("Exception not thrown on invalid event",
+          exceptionThrown);
+      // TODO: At present operation timestamps are not getting updated.
+      Assert.assertEquals(-1, impl.getLastOpStartTime());
+      Assert.assertEquals(-1, impl.getLastOpLastUpdateTime());
+      Assert.assertEquals(-1, impl.getLastOpEndTime());
+    }
+  }
 
   @Test
   public void testCanBeRemoved() throws Exception{
@@ -688,13 +692,13 @@ public class ServiceComponentHostTest {
       }
     }
   }
-  
+
   @Test
   public void testStaleConfigs() throws Exception {
     String stackVersion="HDP-2.0.6";
     String clusterName = "c2";
     String hostName = "h3";
-    
+
     clusters.addCluster(clusterName);
     clusters.addHost(hostName);
     setOsFamily(clusters.getHost(hostName), "redhat", "5.9");
@@ -702,14 +706,14 @@ public class ServiceComponentHostTest {
     clusters.getCluster(clusterName).setDesiredStackVersion(
         new StackId(stackVersion));
     metaInfo.init();
-    clusters.mapHostToCluster(hostName, clusterName);    
-    
+    clusters.mapHostToCluster(hostName, clusterName);
+
     Cluster cluster = clusters.getCluster(clusterName);
-    
+
     ServiceComponentHost sch1 = createNewServiceComponentHost(cluster, "HDFS", "NAMENODE", hostName);
     ServiceComponentHost sch2 = createNewServiceComponentHost(cluster, "HDFS", "DATANODE", hostName);
     ServiceComponentHost sch3 = createNewServiceComponentHost(cluster, "MAPREDUCE2", "HISTORYSERVER", hostName);
-    
+
     sch1.setDesiredState(State.INSTALLED);
     sch1.setState(State.INSTALLING);
     sch1.setStackVersion(new StackId(stackVersion));
@@ -717,10 +721,10 @@ public class ServiceComponentHostTest {
     sch2.setDesiredState(State.INSTALLED);
     sch2.setState(State.INSTALLING);
     sch2.setStackVersion(new StackId(stackVersion));
-    
+
     sch3.setDesiredState(State.INSTALLED);
     sch3.setState(State.INSTALLING);
-    sch3.setStackVersion(new StackId(stackVersion));    
+    sch3.setStackVersion(new StackId(stackVersion));
 
     Assert.assertFalse(sch1.convertToResponse().isStaleConfig());
     Assert.assertFalse(sch2.convertToResponse().isStaleConfig());
@@ -735,7 +739,7 @@ public class ServiceComponentHostTest {
     Map<String, Map<String, String>> actual = new HashMap<String, Map<String, String>>() {{
       put("global", new HashMap<String,String>() {{ put("tag", "version1"); }});
     }};
-    
+
     sch1.updateActualConfigs(actual);
     sch2.updateActualConfigs(actual);
     sch3.updateActualConfigs(actual);
@@ -746,7 +750,7 @@ public class ServiceComponentHostTest {
     // HDP-x/HDFS does not define type 'foo', so changes do not count to stale
     Assert.assertFalse(sch1.convertToResponse().isStaleConfig());
     Assert.assertFalse(sch2.convertToResponse().isStaleConfig());
-    
+
     makeConfig(cluster, "hdfs-site", "version1",
         new HashMap<String,String>() {{ put("a", "b"); }}, new HashMap<String, Map<String,String>>());
 
@@ -755,7 +759,7 @@ public class ServiceComponentHostTest {
     Assert.assertTrue(sch2.convertToResponse().isStaleConfig());
 
     actual.put("hdfs-site", new HashMap<String, String>() {{ put ("tag", "version1"); }});
-    
+
     sch1.updateActualConfigs(actual);
     // previous value from cache
     Assert.assertTrue(sch1.convertToResponse().isStaleConfig());
@@ -765,7 +769,7 @@ public class ServiceComponentHostTest {
     // HDP-x/HDFS/hdfs-site up to date, only for sch1
     Assert.assertFalse(sch1.convertToResponse().isStaleConfig());
     Assert.assertTrue(sch2.convertToResponse().isStaleConfig());
-    
+
     sch2.updateActualConfigs(actual);
     // previous value from cache
     Assert.assertTrue(sch2.convertToResponse().isStaleConfig());
@@ -775,15 +779,15 @@ public class ServiceComponentHostTest {
     // HDP-x/HDFS/hdfs-site up to date for both
     Assert.assertFalse(sch1.convertToResponse().isStaleConfig());
     Assert.assertFalse(sch2.convertToResponse().isStaleConfig());
-    
+
     makeConfig(cluster, "hdfs-site", "version2",
-        new HashMap<String, String>() {{ put("dfs.journalnode.http-address", "http://foo"); }}, 
+        new HashMap<String, String>() {{ put("dfs.journalnode.http-address", "http://foo"); }},
         new HashMap<String, Map<String,String>>());
 
     // HDP-x/HDFS/hdfs-site updated to changed property
     Assert.assertTrue(sch1.convertToResponse().isStaleConfig());
     Assert.assertTrue(sch2.convertToResponse().isStaleConfig());
-    
+
     actual.get("hdfs-site").put("tag", "version2");
     sch1.updateActualConfigs(actual);
     sch2.updateActualConfigs(actual);
@@ -794,13 +798,13 @@ public class ServiceComponentHostTest {
     // HDP-x/HDFS/hdfs-site updated to changed property
     Assert.assertFalse(sch1.convertToResponse().isStaleConfig());
     Assert.assertFalse(sch2.convertToResponse().isStaleConfig());
-    
+
     // make a host override
     final Host host = clusters.getHostsForCluster(cluster.getClusterName()).get(hostName);
     Assert.assertNotNull(host);
-    
+
     final Config c = configFactory.createNew(cluster, "hdfs-site",
-        new HashMap<String, String>() {{ put("dfs.journalnode.http-address", "http://goo"); }}, 
+        new HashMap<String, String>() {{ put("dfs.journalnode.http-address", "http://goo"); }},
         new HashMap<String, Map<String,String>>());
     c.setTag("version3");
     c.persist();
@@ -811,11 +815,11 @@ public class ServiceComponentHostTest {
       new HashMap<String, Host>() {{ put("h3", host); }});
     configGroup.persist();
     cluster.addConfigGroup(configGroup);
-    
+
     // HDP-x/HDFS/hdfs-site updated host to changed property
     Assert.assertTrue(sch1.convertToResponse().isStaleConfig());
     Assert.assertTrue(sch2.convertToResponse().isStaleConfig());
-    
+
     actual.get("hdfs-site").put(configGroup.getId().toString(), "version3");
     sch2.updateActualConfigs(actual);
     // previous value from cache
@@ -826,7 +830,7 @@ public class ServiceComponentHostTest {
     // HDP-x/HDFS/hdfs-site updated host to changed property
     Assert.assertTrue(sch1.convertToResponse().isStaleConfig());
     Assert.assertFalse(sch2.convertToResponse().isStaleConfig());
-    
+
     sch1.updateActualConfigs(actual);
     // previous value from cache
     Assert.assertTrue(sch1.convertToResponse().isStaleConfig());
@@ -836,7 +840,7 @@ public class ServiceComponentHostTest {
     // HDP-x/HDFS/hdfs-site updated host to changed property
     Assert.assertFalse(sch1.convertToResponse().isStaleConfig());
     Assert.assertFalse(sch2.convertToResponse().isStaleConfig());
-    
+
     // change 'global' property only affecting global/HDFS
     makeConfig(cluster, "global", "version2",
       new HashMap<String,String>() {{
@@ -844,7 +848,7 @@ public class ServiceComponentHostTest {
         put("dfs_namenode_name_dir", "/foo3"); // HDFS only
         put("mapred_log_dir_prefix", "/foo2"); // MR2 only
       }}, new HashMap<String, Map<String,String>>());
-    
+
     Assert.assertTrue(sch1.convertToResponse().isStaleConfig());
     Assert.assertTrue(sch2.convertToResponse().isStaleConfig());
     Assert.assertFalse(sch3.convertToResponse().isStaleConfig());
@@ -867,7 +871,7 @@ public class ServiceComponentHostTest {
     sch1.updateActualConfigs(actual);
 
     final Config c1 = configFactory.createNew(cluster, "core-site",
-      new HashMap<String, String>() {{ put("fs.trash.interval", "400"); }}, 
+      new HashMap<String, String>() {{ put("fs.trash.interval", "400"); }},
       new HashMap<String, Map<String,String>>());
     c1.setTag("version2");
     c1.persist();
@@ -912,13 +916,13 @@ public class ServiceComponentHostTest {
     sch3.setRestartRequired(false);
     Assert.assertFalse(sch3.convertToResponse().isStaleConfig());
   }
-  
+
   @Test
   public void testStaleConfigsAttributes() throws Exception {
     String stackVersion="HDP-2.0.6";
     String clusterName = "c2";
     String hostName = "h3";
-    
+
     clusters.addCluster(clusterName);
     clusters.addHost(hostName);
     setOsFamily(clusters.getHost(hostName), "redhat", "5.9");
@@ -926,14 +930,14 @@ public class ServiceComponentHostTest {
     clusters.getCluster(clusterName).setDesiredStackVersion(
         new StackId(stackVersion));
     metaInfo.init();
-    clusters.mapHostToCluster(hostName, clusterName);    
-    
+    clusters.mapHostToCluster(hostName, clusterName);
+
     Cluster cluster = clusters.getCluster(clusterName);
-    
+
     ServiceComponentHost sch1 = createNewServiceComponentHost(cluster, "HDFS", "NAMENODE", hostName);
     ServiceComponentHost sch2 = createNewServiceComponentHost(cluster, "HDFS", "DATANODE", hostName);
     ServiceComponentHost sch3 = createNewServiceComponentHost(cluster, "MAPREDUCE2", "HISTORYSERVER", hostName);
-    
+
     sch1.setDesiredState(State.INSTALLED);
     sch1.setState(State.INSTALLING);
     sch1.setStackVersion(new StackId(stackVersion));
@@ -941,10 +945,10 @@ public class ServiceComponentHostTest {
     sch2.setDesiredState(State.INSTALLED);
     sch2.setState(State.INSTALLING);
     sch2.setStackVersion(new StackId(stackVersion));
-    
+
     sch3.setDesiredState(State.INSTALLED);
     sch3.setState(State.INSTALLING);
-    sch3.setStackVersion(new StackId(stackVersion));    
+    sch3.setStackVersion(new StackId(stackVersion));
 
     Assert.assertFalse(sch1.convertToResponse().isStaleConfig());
     Assert.assertFalse(sch2.convertToResponse().isStaleConfig());
@@ -963,7 +967,7 @@ public class ServiceComponentHostTest {
       put("global", new HashMap<String,String>() {{ put("tag", "version1"); }});
       put("hdfs-site", new HashMap<String,String>() {{ put("tag", "version1"); }});
     }};
-    
+
     sch1.updateActualConfigs(actual);
     sch2.updateActualConfigs(actual);
     sch3.updateActualConfigs(actual);
@@ -972,7 +976,7 @@ public class ServiceComponentHostTest {
       new HashMap<String,String>() {{ put("a", "c"); }},new HashMap<String, Map<String,String>>(){{
        put("final", new HashMap<String, String>(){{
          put("a", "true");
-       }}); 
+       }});
       }});
     // HDP-x/HDFS does not define type 'foo', so changes do not count to stale
     Assert.assertFalse(sch1.convertToResponse().isStaleConfig());
@@ -985,7 +989,7 @@ public class ServiceComponentHostTest {
     sch3.setRestartRequired(false);
     sch3.updateActualConfigs(actual);
     Assert.assertFalse(sch3.convertToResponse().isStaleConfig());
-    
+
     // Now add config-attributes
     Map<String, Map<String, String>> c1PropAttributes = new HashMap<String, Map<String,String>>();
     c1PropAttributes.put("final", new HashMap<String, String>());
@@ -1000,7 +1004,7 @@ public class ServiceComponentHostTest {
     Assert.assertTrue(sch1.convertToResponse().isStaleConfig());
     Assert.assertTrue(sch2.convertToResponse().isStaleConfig());
     Assert.assertFalse(sch3.convertToResponse().isStaleConfig());
-    
+
     // Now change config-attributes
     Map<String, Map<String, String>> c2PropAttributes = new HashMap<String, Map<String,String>>();
     c2PropAttributes.put("final", new HashMap<String, String>());
@@ -1015,7 +1019,7 @@ public class ServiceComponentHostTest {
     Assert.assertTrue(sch1.convertToResponse().isStaleConfig());
     Assert.assertTrue(sch2.convertToResponse().isStaleConfig());
     Assert.assertFalse(sch3.convertToResponse().isStaleConfig());
-    
+
     // Now change config-attributes
     makeConfig(cluster, "hdfs-site", "version4",
         new HashMap<String,String>() {{
@@ -1043,13 +1047,13 @@ public class ServiceComponentHostTest {
     cluster.addConfig(config);
     cluster.addDesiredConfig("user", config);
   }
-  
+
   @Test
   public void testMaintenance() throws Exception {
     String stackVersion="HDP-2.0.6";
     String clusterName = "c2";
     String hostName = "h3";
-    
+
     clusters.addCluster(clusterName);
     clusters.addHost(hostName);
     setOsFamily(clusters.getHost(hostName), "redhat", "5.9");
@@ -1057,10 +1061,10 @@ public class ServiceComponentHostTest {
     clusters.getCluster(clusterName).setDesiredStackVersion(
         new StackId(stackVersion));
     metaInfo.init();
-    clusters.mapHostToCluster(hostName, clusterName);    
-    
+    clusters.mapHostToCluster(hostName, clusterName);
+
     Cluster cluster = clusters.getCluster(clusterName);
-    
+
     ServiceComponentHost sch1 = createNewServiceComponentHost(cluster, "HDFS", "NAMENODE", hostName);
     ServiceComponentHost sch2 = createNewServiceComponentHost(cluster, "HDFS", "DATANODE", hostName);
     ServiceComponentHost sch3 = createNewServiceComponentHost(cluster, "MAPREDUCE2", "HISTORYSERVER", hostName);
@@ -1070,20 +1074,20 @@ public class ServiceComponentHostTest {
     pk.setComponentName(sch1.getServiceComponentName());
     pk.setServiceName(sch1.getServiceName());
     pk.setHostName(hostName);
-    
+
     HostComponentDesiredStateDAO dao = injector.getInstance(HostComponentDesiredStateDAO.class);
     HostComponentDesiredStateEntity entity = dao.findByPK(pk);
     Assert.assertEquals(MaintenanceState.OFF, entity.getMaintenanceState());
     Assert.assertEquals(MaintenanceState.OFF, sch1.getMaintenanceState());
-    
+
     sch1.setMaintenanceState(MaintenanceState.ON);
     Assert.assertEquals(MaintenanceState.ON, sch1.getMaintenanceState());
-    
+
     entity = dao.findByPK(pk);
     Assert.assertEquals(MaintenanceState.ON, entity.getMaintenanceState());
 
   }
 
-  
-  
+
+
 }


[18/50] [abbrv] git commit: AMBARI-7221 - Ambari Server REST API Memory Leak (jonathanhurley)

Posted by jo...@apache.org.
AMBARI-7221 - Ambari Server REST API Memory Leak (jonathanhurley)


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

Branch: refs/heads/trunk
Commit: 813f16c0c731d6f6a35d8462d16194a3abac9f98
Parents: c91fab7
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Tue Sep 9 21:30:46 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Wed Sep 10 09:01:51 2014 -0400

----------------------------------------------------------------------
 ambari-server/conf/unix/ambari.properties       |  3 ++
 .../server/configuration/Configuration.java     | 44 ++++++++++++++------
 .../ambari/server/controller/AmbariServer.java  | 22 +++++++---
 3 files changed, 52 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/813f16c0/ambari-server/conf/unix/ambari.properties
----------------------------------------------------------------------
diff --git a/ambari-server/conf/unix/ambari.properties b/ambari-server/conf/unix/ambari.properties
index b77ae32..a0557b7 100644
--- a/ambari-server/conf/unix/ambari.properties
+++ b/ambari-server/conf/unix/ambari.properties
@@ -52,3 +52,6 @@ agent.threadpool.size.max=25
 
 # linux open-file limit
 ulimit.open.files=10000
+
+# Server HTTP settings
+server.http.session.inactive_timeout=60

http://git-wip-us.apache.org/repos/asf/ambari/blob/813f16c0/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
index a21f98c..2839c2c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
@@ -260,12 +260,11 @@ public class Configuration {
   private static final String RESOURCES_DIR_DEFAULT =
       "/var/lib/ambari-server/resources/";
   private static final String ANONYMOUS_AUDIT_NAME_KEY = "anonymous.audit.name";
-  private static final String CLIENT_SECURITY_DEFAULT = "local";
+
   private static final int CLIENT_API_PORT_DEFAULT = 8080;
   private static final int CLIENT_API_SSL_PORT_DEFAULT = 8443;
-  private static final String USER_ROLE_NAME_DEFAULT = "user";
-  private static final String ADMIN_ROLE_NAME_DEFAULT = "admin";
   private static final String LDAP_BIND_ANONYMOUSLY_DEFAULT = "true";
+
   //TODO For embedded server only - should be removed later
   private static final String LDAP_PRIMARY_URL_DEFAULT = "localhost:33389";
   private static final String LDAP_BASE_DN_DEFAULT = "dc=ambari,dc=apache,dc=org";
@@ -309,6 +308,8 @@ public class Configuration {
   private static final String VIEW_EXTRACTION_THREADPOOL_TIMEOUT_KEY = "view.extraction.threadpool.timeout";
   private static final long VIEW_EXTRACTION_THREADPOOL_TIMEOUT_DEFAULT = 100000L;
 
+  private static final String SERVER_HTTP_SESSION_INACTIVE_TIMEOUT = "server.http.session.inactive_timeout";
+
   private static final Logger LOG = LoggerFactory.getLogger(
       Configuration.class);
   private Properties properties;
@@ -401,7 +402,7 @@ public class Configuration {
     }
     configsMap.put(SRVR_CRT_PASS_KEY, password);
 
-    if (this.getApiSSLAuthentication()) {
+    if (getApiSSLAuthentication()) {
       LOG.info("API SSL Authentication is turned on.");
       File httpsPassFile = new File(configsMap.get(CLIENT_API_SSL_KSTR_DIR_NAME_KEY)
         + File.separator + configsMap.get(CLIENT_API_SSL_CRT_PASS_FILE_NAME_KEY));
@@ -464,14 +465,14 @@ public class Configuration {
   private synchronized void loadCredentialProvider() {
     if (!credentialProviderInitialized) {
       try {
-        this.credentialProvider = new CredentialProvider(null,
+        credentialProvider = new CredentialProvider(null,
           getMasterKeyLocation(), isMasterKeyPersisted());
       } catch (Exception e) {
         LOG.info("Credential provider creation failed. Reason: " + e.getMessage());
         if (LOG.isDebugEnabled()) {
           e.printStackTrace();
         }
-        this.credentialProvider = null;
+        credentialProvider = null;
       }
       credentialProviderInitialized = true;
     }
@@ -487,8 +488,9 @@ public class Configuration {
     //Get property file stream from classpath
     InputStream inputStream = Configuration.class.getClassLoader().getResourceAsStream(CONFIG_FILE);
 
-    if (inputStream == null)
+    if (inputStream == null) {
       throw new RuntimeException(CONFIG_FILE + " not found in classpath");
+    }
 
     // load the properties
     try {
@@ -531,8 +533,9 @@ public class Configuration {
   public String getBootSetupAgentPassword() {
     String pass = configsMap.get(PASSPHRASE_KEY);
 
-    if (null != pass)
+    if (null != pass) {
       return pass;
+    }
 
     // fallback
     return properties.getProperty(BOOTSTRAP_SETUP_AGENT_PASSWORD, "password");
@@ -685,8 +688,9 @@ public class Configuration {
 
   public String getLocalDatabaseUrl() {
     String dbName = properties.getProperty(SERVER_DB_NAME_KEY);
-    if(dbName == null || dbName.isEmpty())
+    if(dbName == null || dbName.isEmpty()) {
       throw new RuntimeException("Server DB Name is not configured!");
+    }
 
     return JDBC_LOCAL_URL + dbName;
   }
@@ -702,10 +706,11 @@ public class Configuration {
       dbpasswd = readPasswordFromStore(passwdProp);
     }
 
-    if (dbpasswd != null)
+    if (dbpasswd != null) {
       return dbpasswd;
-    else
+    } else {
       return readPasswordFromFile(passwdProp, SERVER_JDBC_USER_PASSWD_DEFAULT);
+    }
   }
 
   public String getRcaDatabaseDriver() {
@@ -724,8 +729,9 @@ public class Configuration {
     String passwdProp = properties.getProperty(SERVER_JDBC_RCA_USER_PASSWD_KEY);
     if (passwdProp != null) {
       String dbpasswd = readPasswordFromStore(passwdProp);
-      if (dbpasswd != null)
+      if (dbpasswd != null) {
         return dbpasswd;
+      }
     }
     return readPasswordFromFile(passwdProp, SERVER_JDBC_RCA_USER_PASSWD_DEFAULT);
   }
@@ -1081,4 +1087,18 @@ public class Configuration {
     return Long.parseLong(properties.getProperty(
         VIEW_EXTRACTION_THREADPOOL_TIMEOUT_KEY, String.valueOf(VIEW_EXTRACTION_THREADPOOL_TIMEOUT_DEFAULT)));
   }
+
+  /**
+   * Gets the inactivity timeout value, in seconds, for sessions created in
+   * Jetty by Spring Security. Without this timeout value, each request to the
+   * REST APIs will create new sessions that are never reaped since their
+   * default time is -1.
+   *
+   * @return the time value or {@code 60} seconds for default.
+   */
+  public int getHttpSessionInactiveTimeout() {
+    return Integer.parseInt(properties.getProperty(
+        SERVER_HTTP_SESSION_INACTIVE_TIMEOUT,
+        "60"));
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/813f16c0/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
index fc74e00..e109f7e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
@@ -230,8 +230,18 @@ public class AmbariServer {
       root.setErrorHandler(injector.getInstance(AmbariErrorHandler.class));
       root.getSessionHandler().setSessionManager(sessionManager);
 
-      //Changing session cookie name to avoid conflicts
-      root.getSessionHandler().getSessionManager().setSessionCookie("AMBARISESSIONID");
+      SessionManager jettySessionManager = root.getSessionHandler().getSessionManager();
+
+      // use AMBARISESSIONID instead of JSESSIONID to avoid conflicts with
+      // other services (like HDFS) that run on the same context but a different
+      // port
+      jettySessionManager.setSessionCookie("AMBARISESSIONID");
+
+      // each request that does not use AMBARISESSIONID will create a new
+      // HashedSession in Jetty; these MUST be reaped after inactivity in order
+      // to prevent a memory leak
+      int sessionInactivityTimeout = configs.getHttpSessionInactiveTimeout();
+      jettySessionManager.setMaxInactiveInterval(sessionInactivityTimeout);
 
       GenericWebApplicationContext springWebAppContext = new GenericWebApplicationContext();
       springWebAppContext.setServletContext(root.getServletContext());
@@ -246,8 +256,10 @@ public class AmbariServer {
 
       certMan.initRootCert();
 
-      ServletContextHandler agentroot = new ServletContextHandler(serverForAgent,
-          "/", ServletContextHandler.SESSIONS );
+      // the agent communication (heartbeats, registration, etc) is stateless
+      // and does not use sessions.
+      ServletContextHandler agentroot = new ServletContextHandler(
+          serverForAgent, "/", ServletContextHandler.NO_SESSIONS);
 
       ServletHolder rootServlet = root.addServlet(DefaultServlet.class, "/");
       rootServlet.setInitParameter("dirAllowed", "false");
@@ -262,8 +274,8 @@ public class AmbariServer {
       root.addFilter(new FilterHolder(injector.getInstance(AmbariPersistFilter.class)), "/proxy/*", 1);
       root.addFilter(new FilterHolder(new MethodOverrideFilter()), "/api/*", 1);
       root.addFilter(new FilterHolder(new MethodOverrideFilter()), "/proxy/*", 1);
-      agentroot.addFilter(new FilterHolder(injector.getInstance(AmbariPersistFilter.class)), "/agent/*", 1);
 
+      agentroot.addFilter(new FilterHolder(injector.getInstance(AmbariPersistFilter.class)), "/agent/*", 1);
       agentroot.addFilter(SecurityFilter.class, "/*", 1);
 
       if (configs.getApiAuthentication()) {


[24/50] [abbrv] git commit: Merge branch 'trunk' into branch-alerts-dev

Posted by jo...@apache.org.
Merge branch 'trunk' into branch-alerts-dev

Conflicts:
	ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
	ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java


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

Branch: refs/heads/trunk
Commit: 17b8e799048b96c7fb1074a21c52e2e7ecaaf607
Parents: 760bedf bd04a28
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Tue Sep 16 08:50:14 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Tue Sep 16 08:50:14 2014 -0400

----------------------------------------------------------------------
 .../ui/admin-web/app/views/leftNavbar.html      |   2 +-
 ambari-agent/src/main/package/rpm/preremove.sh  |   2 +-
 .../ambari_agent/TestActualConfigHandler.py     |   6 +-
 .../test/python/ambari_agent/TestLiveStatus.py  |   4 +-
 .../TestExecuteHadoopResource.py                |  37 ++-
 ambari-server/docs/api/v1/services.md           |   7 -
 .../stackadvisor/StackAdvisorRunner.java        |  10 +-
 .../server/controller/AmbariHandlerList.java    |  33 +-
 .../AmbariPrivilegeResourceProvider.java        |   2 +-
 .../internal/BaseBlueprintProcessor.java        |   2 +-
 .../BlueprintConfigurationProcessor.java        |  30 +-
 .../RecommendationResourceProvider.java         |   6 +-
 .../internal/ValidationResourceProvider.java    |   6 +-
 .../internal/ViewInstanceResourceProvider.java  |  10 +-
 .../ViewPermissionResourceProvider.java         |   4 +-
 .../internal/ViewPrivilegeResourceProvider.java |   8 +-
 .../ambari/server/metadata/ActionMetadata.java  |   1 -
 .../ambari/server/orm/entities/ViewEntity.java  |   8 +-
 .../org/apache/ambari/server/state/Service.java |   8 +-
 .../server/upgrade/UpgradeCatalog170.java       | 142 +++++++-
 .../apache/ambari/server/view/ViewRegistry.java |  10 +-
 ambari-server/src/main/package/rpm/preremove.sh |   2 +-
 .../custom_actions/validate_configs.py          |   2 -
 .../scripts/shared_initialization.py            |   3 +-
 .../stacks/HDP/1.3.2/role_command_order.json    |   4 +-
 .../services/HIVE/configuration/webhcat-env.xml |  54 +++
 .../HIVE/configuration/webhcat-site.xml         | 156 +++++++++
 .../stacks/HDP/1.3.2/services/HIVE/metainfo.xml | 154 +++++----
 .../HIVE/package/files/templetonSmoke.sh        |  96 ++++++
 .../services/HIVE/package/scripts/params.py     |  31 +-
 .../HIVE/package/scripts/service_check.py       |   2 +
 .../HIVE/package/scripts/status_params.py       |   3 +
 .../services/HIVE/package/scripts/webhcat.py    | 107 ++++++
 .../HIVE/package/scripts/webhcat_server.py      |  53 +++
 .../HIVE/package/scripts/webhcat_service.py     |  40 +++
 .../package/scripts/webhcat_service_check.py    |  42 +++
 .../HDP/1.3.2/services/NAGIOS/metainfo.xml      |   2 +-
 .../templates/hadoop-servicegroups.cfg.j2       |   6 -
 .../package/templates/hadoop-services.cfg.j2    |   2 +-
 .../WEBHCAT/configuration/webhcat-env.xml       |  54 ---
 .../WEBHCAT/configuration/webhcat-site.xml      | 156 ---------
 .../HDP/1.3.2/services/WEBHCAT/metainfo.xml     | 103 ------
 .../WEBHCAT/package/files/templetonSmoke.sh     |  96 ------
 .../WEBHCAT/package/scripts/__init__.py         |  20 --
 .../services/WEBHCAT/package/scripts/params.py  |  78 -----
 .../WEBHCAT/package/scripts/service_check.py    |  44 ---
 .../WEBHCAT/package/scripts/status_params.py    |  26 --
 .../services/WEBHCAT/package/scripts/webhcat.py | 107 ------
 .../WEBHCAT/package/scripts/webhcat_server.py   |  53 ---
 .../WEBHCAT/package/scripts/webhcat_service.py  |  40 ---
 .../stacks/HDP/1.3/role_command_order.json      |   4 +-
 .../stacks/HDP/1.3/services/HIVE/metainfo.xml   |   5 -
 .../services/HDFS/configuration/core-site.xml   |   9 +
 .../scripts/shared_initialization.py            |   3 +-
 .../stacks/HDP/2.0.6/role_command_order.json    |   4 +-
 .../services/HDFS/configuration/core-site.xml   |  10 +
 .../services/HIVE/configuration/webhcat-env.xml |  54 +++
 .../HIVE/configuration/webhcat-site.xml         | 138 ++++++++
 .../stacks/HDP/2.0.6/services/HIVE/metainfo.xml | 165 +++++-----
 .../HIVE/package/files/templetonSmoke.sh        |  96 ++++++
 .../services/HIVE/package/scripts/params.py     |  44 ++-
 .../HIVE/package/scripts/service_check.py       |   2 +
 .../HIVE/package/scripts/status_params.py       |   1 +
 .../services/HIVE/package/scripts/webhcat.py    | 112 +++++++
 .../HIVE/package/scripts/webhcat_server.py      |  53 +++
 .../HIVE/package/scripts/webhcat_service.py     |  40 +++
 .../package/scripts/webhcat_service_check.py    |  41 +++
 .../HDP/2.0.6/services/NAGIOS/metainfo.xml      |   2 +-
 .../templates/hadoop-servicegroups.cfg.j2       |   8 +-
 .../package/templates/hadoop-services.cfg.j2    |   2 +-
 .../services/OOZIE/package/scripts/params.py    |   3 +-
 .../services/SQOOP/package/scripts/params.py    |  12 +-
 .../WEBHCAT/configuration/webhcat-env.xml       |  54 ---
 .../WEBHCAT/configuration/webhcat-site.xml      | 138 --------
 .../HDP/2.0.6/services/WEBHCAT/metainfo.xml     | 110 -------
 .../WEBHCAT/package/files/templetonSmoke.sh     |  96 ------
 .../WEBHCAT/package/scripts/__init__.py         |  20 --
 .../services/WEBHCAT/package/scripts/params.py  | 102 ------
 .../WEBHCAT/package/scripts/service_check.py    |  45 ---
 .../WEBHCAT/package/scripts/status_params.py    |  26 --
 .../services/WEBHCAT/package/scripts/webhcat.py | 112 -------
 .../WEBHCAT/package/scripts/webhcat_server.py   |  53 ---
 .../WEBHCAT/package/scripts/webhcat_service.py  |  40 ---
 .../HDP/2.1.GlusterFS/role_command_order.json   |   4 +-
 .../2.1.GlusterFS/services/HIVE/metainfo.xml    | 100 +++---
 .../WEBHCAT/configuration/webhcat-site.xml      | 143 --------
 .../2.1.GlusterFS/services/WEBHCAT/metainfo.xml |  46 ---
 .../stacks/HDP/2.1/role_command_order.json      |   3 +-
 .../services/FALCON/package/scripts/params.py   |   9 +-
 .../stacks/HDP/2.1/services/HIVE/metainfo.xml   |  62 +++-
 .../services/STORM/configuration/storm-env.xml  |   2 +-
 .../WEBHCAT/configuration/webhcat-site.xml      | 143 --------
 .../HDP/2.1/services/WEBHCAT/metainfo.xml       |  47 ---
 .../stacks/HDP/2.2.1/services/HIVE/metainfo.xml |   4 -
 .../HDP/2.2.1/services/WEBHCAT/metainfo.xml     |  26 --
 .../resources/stacks/HDP/2.2/repos/repoinfo.xml |  27 +-
 .../stacks/HDP/2.2/services/FALCON/metainfo.xml |  12 +-
 .../stacks/HDP/2.2/services/FLUME/metainfo.xml  |   2 +-
 .../stacks/HDP/2.2/services/HBASE/metainfo.xml  |   2 +-
 .../services/HDFS/configuration/hadoop-env.xml  |   2 +-
 .../services/HDFS/configuration/hdfs-site.xml   |   2 +-
 .../stacks/HDP/2.2/services/HDFS/metainfo.xml   |   4 +-
 .../HIVE/configuration/webhcat-site.xml         |  59 ++++
 .../stacks/HDP/2.2/services/HIVE/metainfo.xml   |  48 ++-
 .../services/OOZIE/configuration/oozie-site.xml |   2 +-
 .../stacks/HDP/2.2/services/OOZIE/metainfo.xml  |  27 +-
 .../stacks/HDP/2.2/services/PIG/metainfo.xml    |   5 +-
 .../stacks/HDP/2.2/services/SQOOP/metainfo.xml  |  15 +-
 .../stacks/HDP/2.2/services/STORM/metainfo.xml  |  12 +-
 .../stacks/HDP/2.2/services/TEZ/metainfo.xml    |   2 +-
 .../WEBHCAT/configuration/webhcat-site.xml      |  59 ----
 .../HDP/2.2/services/WEBHCAT/metainfo.xml       |   2 +-
 .../YARN/configuration-mapred/mapred-site.xml   |   2 +-
 .../services/YARN/configuration/yarn-site.xml   |   2 +-
 .../stacks/HDP/2.2/services/YARN/metainfo.xml   |   6 +-
 .../HDP/2.2/services/ZOOKEEPER/metainfo.xml     |   2 +-
 .../api/util/StackExtensionHelperTest.java      |  29 +-
 .../AmbariManagementControllerTest.java         |   6 +-
 .../AmbariPrivilegeResourceProviderTest.java    |   2 +-
 .../internal/BaseBlueprintProcessorTest.java    |  27 +-
 .../BlueprintConfigurationProcessorTest.java    |  21 ++
 .../ViewInstanceResourceProviderTest.java       |  10 +-
 .../ViewPermissionResourceProviderTest.java     |   4 +-
 .../ViewPrivilegeResourceProviderTest.java      |   2 +-
 .../server/orm/entities/ViewEntityTest.java     |  22 +-
 .../server/upgrade/UpgradeCatalog170Test.java   | 241 ++++++++++----
 .../ambari/server/view/ViewRegistryTest.java    |  28 +-
 .../1.3.2/HIVE/test_hive_service_check.py       |  20 ++
 .../stacks/1.3.2/HIVE/test_webhcat_server.py    | 258 +++++++++++++++
 .../stacks/1.3.2/WEBHCAT/test_webhcat_server.py | 258 ---------------
 .../1.3.2/WEBHCAT/test_webhcat_service_check.py |  61 ----
 .../hooks/before-START/test_before_start.py     |   6 +-
 .../2.0.6/HIVE/test_hive_service_check.py       |  21 ++
 .../stacks/2.0.6/HIVE/test_webhcat_server.py    | 270 +++++++++++++++
 .../stacks/2.0.6/WEBHCAT/test_webhcat_server.py | 273 ---------------
 .../2.0.6/WEBHCAT/test_webhcat_service_check.py |  61 ----
 .../hooks/before-START/test_before_start.py     |   6 +-
 .../stacks/HDP/2.0.5/services/HIVE/metainfo.xml |  74 +++++
 .../WEBHCAT/configuration/webhcat-site.xml      | 126 -------
 .../HDP/2.0.5/services/WEBHCAT/metainfo.xml     | 102 ------
 .../HDP/2.0.6/services/WEBHCAT/metainfo.xml     |  28 --
 .../org/apache/ambari/view/ViewDefinition.java  |   8 +-
 ambari-web/app/assets/data/alerts/alerts.json   |   2 +-
 .../app/assets/data/dashboard/services.json     | 117 -------
 .../app/assets/data/hosts/HDP2/hosts.json       |  11 +-
 .../data/services/HDP2/components_state.json    |   9 -
 .../app/assets/data/services/HDP2/services.json |  16 -
 .../services/host_component_actual_configs.json | 118 +------
 .../data/stacks/HDP-2.1/recommendations.json    |   2 +-
 .../stacks/HDP-2.1/recommendations_configs.json |   2 +-
 .../data/stacks/HDP-2.1/service_components.json | 218 +++++-------
 .../data/wizard/stack/hdp/version/1.2.0.json    |  18 -
 .../data/wizard/stack/hdp/version/1.2.1.json    |  11 -
 .../data/wizard/stack/hdp/version/1.3.0.json    |  11 -
 .../data/wizard/stack/hdp/version/1.3.1.json    |  11 -
 .../data/wizard/stack/hdp/version/2.0.1.json    |  11 -
 .../data/wizard/stack/hdp/version/2.0.5.json    |  11 -
 .../data/wizard/stack/hdp/version0.1.json       |  17 -
 .../wizard/stack/hdp/version01/HCATALOG.json    |  20 --
 .../wizard/stack/hdp/version1.2.1/HCATALOG.json |   4 -
 .../wizard/stack/hdp/version1.3.0/HCATALOG.json |   4 -
 .../wizard/stack/hdp/version131/HCATALOG.json   |   4 -
 .../wizard/stack/hdp/version2.0.1/HCATALOG.json |   4 -
 .../app/assets/data/wizard/stack/stacks.json    |  55 ----
 .../main/admin/security/add/step2.js            |   4 +-
 .../main/admin/serviceAccounts_controller.js    |   2 +-
 .../controllers/main/service/info/configs.js    | 130 +++++---
 ambari-web/app/controllers/main/service/item.js |   2 +-
 .../app/controllers/wizard/step5_controller.js  |  92 ++++--
 .../app/controllers/wizard/step6_controller.js  |  31 +-
 .../app/controllers/wizard/step7_controller.js  |  18 +-
 .../app/controllers/wizard/step8_controller.js  |   3 +-
 ambari-web/app/data/HDP2/secure_configs.js      |  15 +-
 ambari-web/app/data/HDP2/secure_mapping.js      |  12 +-
 ambari-web/app/data/HDP2/secure_properties.js   |   8 +-
 ambari-web/app/data/HDP2/site_properties.js     |  22 +-
 ambari-web/app/data/secure_configs.js           |  15 +-
 ambari-web/app/data/secure_mapping.js           |  12 +-
 ambari-web/app/data/secure_properties.js        |   8 +-
 ambari-web/app/data/site_properties.js          |  22 +-
 ambari-web/app/mixins/common/serverValidator.js |   8 +-
 .../app/mixins/wizard/addSecurityConfigs.js     |   2 +-
 ambari-web/app/models/service.js                |  12 -
 ambari-web/app/models/stack_service.js          |  15 +-
 ambari-web/app/styles/application.less          |  14 +
 ambari-web/app/templates/application.hbs        |   2 +-
 .../app/templates/main/service/info/configs.hbs |   2 +-
 .../app/templates/main/service/info/summary.hbs |  26 +-
 ambari-web/app/utils/ajax/ajax.js               |   9 +
 .../app/utils/batch_scheduled_requests.js       |   1 -
 ambari-web/app/utils/config.js                  |   2 +-
 ambari-web/app/utils/helper.js                  |   1 -
 .../views/common/configs/config_history_flow.js |   2 +-
 .../app/views/common/quick_view_link_view.js    |   6 +-
 .../app/views/main/host/configs_service_menu.js |   2 +-
 .../app/views/main/service/info/summary.js      |  64 +++-
 ambari-web/app/views/main/service/item.js       |   7 +-
 ambari-web/app/views/main/service/menu.js       |   8 +-
 .../security/add/addSecurity_controller_test.js |   2 -
 .../main/service/info/config_test.js            |   8 +-
 .../test/controllers/wizard/step4_test.js       |  34 +-
 .../test/controllers/wizard/step8_test.js       |  14 +-
 ambari-web/test/models/service_test.js          |   8 -
 ambari-web/test/models/stack_service_test.js    |   8 -
 ambari-web/test/service_components.js           | 229 +++++--------
 ambari-web/test/utils/helper_test.js            |   1 -
 .../src/addOns/nagios/scripts/nagios_alerts.php |   8 +-
 .../apache/ambari/msi/ClusterDefinition.java    |   2 +-
 .../ambari/msi/ClusterDefinitionTest.java       |   4 -
 .../Scripts/HostComponentsDiscovery.ps1         |   3 +-
 .../slider-core/0.41.0/slider-core-0.41.0.jar   | Bin 1125710 -> 0 bytes
 .../slider-core/0.41.0/slider-core-0.41.0.pom   |  25 --
 .../slider-core/0.51.0/slider-core-0.51.0.jar   | Bin 0 -> 1144236 bytes
 .../slider-core/0.51.0/slider-core-0.51.0.pom   |  25 ++
 .../slider/slider-core/maven-metadata-local.xml |   6 +-
 contrib/views/slider/lib/slider-agent.tar.gz    | Bin 0 -> 480985 bytes
 contrib/views/slider/pom.xml                    |  10 +-
 .../view/slider/SliderAppsResourceProvider.java |  15 +-
 .../view/slider/SliderAppsViewController.java   |   9 +-
 .../slider/SliderAppsViewControllerImpl.java    | 329 +++++++++++--------
 .../view/slider/rest/SliderAppsResource.java    |   2 +-
 .../ambari/view/slider/rest/client/Metric.java  |   3 +
 .../assets/data/resource/service_status.json    |  12 -
 .../main/resources/ui/app/models/slider_app.js  |   2 +-
 .../resources/ui/app/styles/application.less    |   1 -
 225 files changed, 3669 insertions(+), 4671 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/17b8e799/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
----------------------------------------------------------------------
diff --cc ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
index 4ee2ac2,75635cc..435dd37
--- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
@@@ -18,75 -18,30 +18,88 @@@
  
  package org.apache.ambari.server.upgrade;
  
 -import com.google.common.reflect.TypeToken;
 -import com.google.inject.Inject;
 -import com.google.inject.Injector;
 +import java.lang.reflect.Type;
- 
 +import java.sql.Connection;
 +import java.sql.PreparedStatement;
 +import java.sql.ResultSet;
 +import java.sql.SQLException;
 +import java.util.ArrayList;
 +import java.util.Collections;
++import java.util.Date;
 +import java.util.HashMap;
 +import java.util.HashSet;
++import java.util.Iterator;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.Map.Entry;
 +import java.util.Set;
- import java.util.Date;
 +
 +import javax.persistence.EntityManager;
 +import javax.persistence.TypedQuery;
 +import javax.persistence.criteria.CriteriaBuilder;
 +import javax.persistence.criteria.CriteriaQuery;
 +import javax.persistence.criteria.Expression;
 +import javax.persistence.criteria.Predicate;
 +import javax.persistence.criteria.Root;
 +
- import com.google.common.reflect.TypeToken;
  import org.apache.ambari.server.AmbariException;
  import org.apache.ambari.server.configuration.Configuration;
  import org.apache.ambari.server.controller.AmbariManagementController;
  import org.apache.ambari.server.orm.DBAccessor.DBColumnInfo;
 -import org.apache.ambari.server.orm.dao.*;
 -import org.apache.ambari.server.orm.entities.*;
 -import org.apache.ambari.server.state.*;
 +import org.apache.ambari.server.orm.dao.ClusterDAO;
++import org.apache.ambari.server.orm.dao.ClusterServiceDAO;
++import org.apache.ambari.server.orm.dao.ConfigGroupConfigMappingDAO;
 +import org.apache.ambari.server.orm.dao.DaoUtils;
++import org.apache.ambari.server.orm.dao.HostComponentDesiredStateDAO;
++import org.apache.ambari.server.orm.dao.HostComponentStateDAO;
 +import org.apache.ambari.server.orm.dao.HostRoleCommandDAO;
 +import org.apache.ambari.server.orm.dao.KeyValueDAO;
 +import org.apache.ambari.server.orm.dao.PermissionDAO;
 +import org.apache.ambari.server.orm.dao.PrincipalDAO;
 +import org.apache.ambari.server.orm.dao.PrincipalTypeDAO;
 +import org.apache.ambari.server.orm.dao.PrivilegeDAO;
 +import org.apache.ambari.server.orm.dao.ResourceDAO;
 +import org.apache.ambari.server.orm.dao.ResourceTypeDAO;
- import org.apache.ambari.server.orm.dao.ConfigGroupConfigMappingDAO;
++import org.apache.ambari.server.orm.dao.ServiceComponentDesiredStateDAO;
++import org.apache.ambari.server.orm.dao.ServiceDesiredStateDAO;
 +import org.apache.ambari.server.orm.dao.UserDAO;
 +import org.apache.ambari.server.orm.dao.ViewDAO;
 +import org.apache.ambari.server.orm.dao.ViewInstanceDAO;
++import org.apache.ambari.server.orm.entities.ClusterConfigEntity;
 +import org.apache.ambari.server.orm.entities.ClusterEntity;
- import org.apache.ambari.server.orm.entities.HostRoleCommandEntity;
++import org.apache.ambari.server.orm.entities.ClusterServiceEntity;
++import org.apache.ambari.server.orm.entities.ClusterServiceEntityPK;
 +import org.apache.ambari.server.orm.entities.ConfigGroupConfigMappingEntity;
- import org.apache.ambari.server.orm.entities.ClusterConfigEntity;
++import org.apache.ambari.server.orm.entities.HostComponentDesiredStateEntity;
++import org.apache.ambari.server.orm.entities.HostComponentStateEntity;
++import org.apache.ambari.server.orm.entities.HostRoleCommandEntity;
 +import org.apache.ambari.server.orm.entities.HostRoleCommandEntity_;
 +import org.apache.ambari.server.orm.entities.KeyValueEntity;
 +import org.apache.ambari.server.orm.entities.PermissionEntity;
 +import org.apache.ambari.server.orm.entities.PrincipalEntity;
 +import org.apache.ambari.server.orm.entities.PrincipalTypeEntity;
 +import org.apache.ambari.server.orm.entities.PrivilegeEntity;
 +import org.apache.ambari.server.orm.entities.ResourceEntity;
 +import org.apache.ambari.server.orm.entities.ResourceTypeEntity;
++import org.apache.ambari.server.orm.entities.ServiceComponentDesiredStateEntity;
++import org.apache.ambari.server.orm.entities.ServiceComponentDesiredStateEntityPK;
++import org.apache.ambari.server.orm.entities.ServiceDesiredStateEntity;
++import org.apache.ambari.server.orm.entities.ServiceDesiredStateEntityPK;
 +import org.apache.ambari.server.orm.entities.UserEntity;
 +import org.apache.ambari.server.orm.entities.ViewEntity;
 +import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
 +import org.apache.ambari.server.state.Cluster;
 +import org.apache.ambari.server.state.Clusters;
 +import org.apache.ambari.server.state.Config;
 +import org.apache.ambari.server.state.ConfigHelper;
 +import org.apache.ambari.server.state.alert.Scope;
  import org.apache.ambari.server.utils.StageUtils;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
 -import javax.persistence.EntityManager;
 -import javax.persistence.TypedQuery;
 -import javax.persistence.criteria.*;
 -import java.lang.reflect.Type;
 -import java.sql.Connection;
 -import java.sql.PreparedStatement;
 -import java.sql.ResultSet;
 -import java.sql.SQLException;
 -import java.util.*;
 -import java.util.Map.Entry;
++import com.google.common.reflect.TypeToken;
 +import com.google.inject.Inject;
 +import com.google.inject.Injector;
  
  /**
   * Upgrade catalog for version 1.7.0.
@@@ -598,6 -556,117 +614,118 @@@ public class UpgradeCatalog170 extends 
      moveConfigGroupsGlobalToEnv();
    }
  
+   public void moveHcatalogIntoHiveService() throws AmbariException {
+     final String serviceName = "HIVE";
+     final String serviceNameToBeDeleted = "HCATALOG";
+     final String componentName = "HCAT";
+     moveComponentsIntoService(serviceName, serviceNameToBeDeleted, componentName);
+   }
+ 
+   private void moveWebHcatIntoHiveService() throws AmbariException {
+     final String serviceName = "HIVE";
+     final String serviceNameToBeDeleted = "WEBHCAT";
+     final String componentName = "WEBHCAT_SERVER";
+     moveComponentsIntoService(serviceName, serviceNameToBeDeleted, componentName);
+   }
+ 
+   private void moveComponentsIntoService(String serviceName, String serviceNameToBeDeleted, String componentName) throws AmbariException {
+     /**
+      * 1. ADD servicecomponentdesiredstate: Add HCAT HIVE entry:
+      * 2. Update hostcomponentdesiredstate: service_name to HIVE where service_name is HCATALOG:
+      * 3. Update hostcomponentstate: service_name to HIVE where service_name is HCATALOG:
+      * 4. DELETE servicecomponentdesiredstate: where component_name is HCAT and service_name is HCATALOG :
+      * 5. Delete servicedesiredstate where  service_name is HCATALOG:
+      * 6. Delete clusterservices where service_name is  HCATALOG:
+      */
+     ClusterDAO clusterDAO = injector.getInstance(ClusterDAO.class);
+     ClusterServiceDAO clusterServiceDAO = injector.getInstance(ClusterServiceDAO.class);
+     ServiceDesiredStateDAO serviceDesiredStateDAO = injector.getInstance(ServiceDesiredStateDAO.class);
+     ServiceComponentDesiredStateDAO serviceComponentDesiredStateDAO = injector.getInstance(ServiceComponentDesiredStateDAO.class);
+     HostComponentDesiredStateDAO hostComponentDesiredStateDAO = injector.getInstance(HostComponentDesiredStateDAO.class);
+     HostComponentStateDAO hostComponentStateDAO = injector.getInstance(HostComponentStateDAO.class);
+ 
+     List<ClusterEntity> clusterEntities = clusterDAO.findAll();
+     for (final ClusterEntity clusterEntity : clusterEntities) {
+       ServiceComponentDesiredStateEntityPK pkHCATInHcatalog = new ServiceComponentDesiredStateEntityPK();
+       pkHCATInHcatalog.setComponentName(componentName);
+       pkHCATInHcatalog.setClusterId(clusterEntity.getClusterId());
+       pkHCATInHcatalog.setServiceName(serviceNameToBeDeleted);
+       ServiceComponentDesiredStateEntity serviceComponentDesiredStateEntityToDelete = serviceComponentDesiredStateDAO.findByPK(pkHCATInHcatalog);
+ 
 -      if (serviceComponentDesiredStateEntityToDelete == null)
++      if (serviceComponentDesiredStateEntityToDelete == null) {
+         continue;
++      }
+ 
+       ServiceDesiredStateEntityPK serviceDesiredStateEntityPK = new ServiceDesiredStateEntityPK();
+       serviceDesiredStateEntityPK.setClusterId(clusterEntity.getClusterId());
+       serviceDesiredStateEntityPK.setServiceName(serviceNameToBeDeleted);
+       ServiceDesiredStateEntity serviceDesiredStateEntity = serviceDesiredStateDAO.findByPK(serviceDesiredStateEntityPK);
+ 
+       ClusterServiceEntityPK clusterServiceEntityToBeDeletedPK = new ClusterServiceEntityPK();
+       clusterServiceEntityToBeDeletedPK.setClusterId(clusterEntity.getClusterId());
+       clusterServiceEntityToBeDeletedPK.setServiceName(serviceNameToBeDeleted);
+       ClusterServiceEntity clusterServiceEntityToBeDeleted = clusterServiceDAO.findByPK(clusterServiceEntityToBeDeletedPK);
+ 
+       ClusterServiceEntityPK clusterServiceEntityPK = new ClusterServiceEntityPK();
+       clusterServiceEntityPK.setClusterId(clusterEntity.getClusterId());
+       clusterServiceEntityPK.setServiceName(serviceName);
+ 
+ 
+       ClusterServiceEntity clusterServiceEntity = clusterServiceDAO.findByPK(clusterServiceEntityPK);
+ 
+       ServiceComponentDesiredStateEntity serviceComponentDesiredStateEntity = new ServiceComponentDesiredStateEntity();
+       serviceComponentDesiredStateEntity.setServiceName(serviceName);
+       serviceComponentDesiredStateEntity.setComponentName(serviceComponentDesiredStateEntityToDelete.getComponentName());
+       serviceComponentDesiredStateEntity.setClusterId(clusterEntity.getClusterId());
+       serviceComponentDesiredStateEntity.setDesiredStackVersion(serviceComponentDesiredStateEntityToDelete.getDesiredStackVersion());
+       serviceComponentDesiredStateEntity.setDesiredState(serviceComponentDesiredStateEntityToDelete.getDesiredState());
+       serviceComponentDesiredStateEntity.setClusterServiceEntity(clusterServiceEntity);
+       //serviceComponentDesiredStateDAO.create(serviceComponentDesiredStateEntity);
+ 
+       Iterator<HostComponentDesiredStateEntity> hostComponentDesiredStateIterator = serviceComponentDesiredStateEntityToDelete.getHostComponentDesiredStateEntities().iterator();
+       Iterator<HostComponentStateEntity> hostComponentStateIterator = serviceComponentDesiredStateEntityToDelete.getHostComponentStateEntities().iterator();
+ 
+       while (hostComponentDesiredStateIterator.hasNext()) {
+         HostComponentDesiredStateEntity hcDesiredStateEntityToBeDeleted = hostComponentDesiredStateIterator.next();
+         HostComponentDesiredStateEntity hostComponentDesiredStateEntity = new HostComponentDesiredStateEntity();
+         hostComponentDesiredStateEntity.setClusterId(clusterEntity.getClusterId());
+         hostComponentDesiredStateEntity.setComponentName(hcDesiredStateEntityToBeDeleted.getComponentName());
+         hostComponentDesiredStateEntity.setDesiredStackVersion(hcDesiredStateEntityToBeDeleted.getDesiredStackVersion());
+         hostComponentDesiredStateEntity.setDesiredState(hcDesiredStateEntityToBeDeleted.getDesiredState());
+         hostComponentDesiredStateEntity.setHostName(hcDesiredStateEntityToBeDeleted.getHostName());
+         hostComponentDesiredStateEntity.setHostEntity(hcDesiredStateEntityToBeDeleted.getHostEntity());
+         hostComponentDesiredStateEntity.setAdminState(hcDesiredStateEntityToBeDeleted.getAdminState());
+         hostComponentDesiredStateEntity.setMaintenanceState(hcDesiredStateEntityToBeDeleted.getMaintenanceState());
+         hostComponentDesiredStateEntity.setRestartRequired(hcDesiredStateEntityToBeDeleted.isRestartRequired());
+         hostComponentDesiredStateEntity.setServiceName(serviceName);
+         hostComponentDesiredStateEntity.setServiceComponentDesiredStateEntity(serviceComponentDesiredStateEntity);
+         hostComponentDesiredStateDAO.merge(hostComponentDesiredStateEntity);
+         hostComponentDesiredStateDAO.remove(hcDesiredStateEntityToBeDeleted);
+       }
+ 
+       while (hostComponentStateIterator.hasNext()) {
+         HostComponentStateEntity hcStateToBeDeleted = hostComponentStateIterator.next();
+         HostComponentStateEntity hostComponentStateEntity = new HostComponentStateEntity();
+         hostComponentStateEntity.setClusterId(clusterEntity.getClusterId());
+         hostComponentStateEntity.setComponentName(hcStateToBeDeleted.getComponentName());
+         hostComponentStateEntity.setCurrentStackVersion(hcStateToBeDeleted.getCurrentStackVersion());
+         hostComponentStateEntity.setCurrentState(hcStateToBeDeleted.getCurrentState());
+         hostComponentStateEntity.setHostName(hcStateToBeDeleted.getHostName());
+         hostComponentStateEntity.setHostEntity(hcStateToBeDeleted.getHostEntity());
+         hostComponentStateEntity.setServiceName(serviceName);
+         hostComponentStateEntity.setServiceComponentDesiredStateEntity(serviceComponentDesiredStateEntity);
+         hostComponentStateDAO.merge(hostComponentStateEntity);
+         hostComponentStateDAO.remove(hcStateToBeDeleted);
+       }
+       serviceComponentDesiredStateEntity.setClusterServiceEntity(clusterServiceEntity);
+       serviceComponentDesiredStateDAO.merge(serviceComponentDesiredStateEntity);
+       serviceComponentDesiredStateDAO.remove(serviceComponentDesiredStateEntityToDelete);
+       serviceDesiredStateDAO.remove(serviceDesiredStateEntity);
+       clusterServiceDAO.remove(clusterServiceEntityToBeDeleted);
+     }
+   }
+ 
+ 
    private void moveConfigGroupsGlobalToEnv() throws AmbariException {
      final ConfigGroupConfigMappingDAO confGroupConfMappingDAO = injector.getInstance(ConfigGroupConfigMappingDAO.class);
      ConfigHelper configHelper = injector.getInstance(ConfigHelper.class);

http://git-wip-us.apache.org/repos/asf/ambari/blob/17b8e799/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
----------------------------------------------------------------------
diff --cc ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
index 6c868b4,8a3e270..8966fc0
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
@@@ -3131,7 -3059,7 +3131,7 @@@ public class AmbariManagementController
      Assert.assertNull(stage1.getExecutionCommandWrapper(host2, "DATANODE"));
      Assert.assertNotNull(stage3.getExecutionCommandWrapper(host1, "HBASE_SERVICE_CHECK"));
      Assert.assertNotNull(stage2.getExecutionCommandWrapper(host2, "HDFS_SERVICE_CHECK"));
-- 
++
      Type type = new TypeToken<Map<String, String>>() {}.getType();
  
  
@@@ -6516,7 -6442,7 +6516,7 @@@
          }
        }
      }
-- 
++
      Type type = new TypeToken<Map<String, String>>(){}.getType();
      for (Stage stage : actionDB.getAllStages(requestId)){
        Map<String, String> hostParamsStage = StageUtils.getGson().fromJson(stage.getHostParamsStage(), type);

http://git-wip-us.apache.org/repos/asf/ambari/blob/17b8e799/ambari-web/app/utils/ajax/ajax.js
----------------------------------------------------------------------


[06/50] [abbrv] git commit: Merge branch 'trunk' into branch-alerts-dev

Posted by jo...@apache.org.
Merge branch 'trunk' into branch-alerts-dev


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

Branch: refs/heads/trunk
Commit: 52d1af7634e4a13ea4f9b94e34a1734c2bcd416c
Parents: 76fc94e 869b00c
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Thu Aug 28 13:49:15 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Thu Aug 28 13:49:15 2014 -0400

----------------------------------------------------------------------
 .../resource_management/TestPackageResource.py  |   6 +-
 .../core/providers/package/apt.py               |  11 +-
 .../libraries/script/script.py                  |   9 +-
 ambari-server/pom.xml                           |  22 ++
 .../ambari/server/api/query/QueryImpl.java      |   1 -
 .../resources/ResourceInstanceFactoryImpl.java  |   4 +
 ...ackLevelConfigurationResourceDefinition.java |  53 +++
 .../StackVersionResourceDefinition.java         |   1 +
 .../server/api/services/AmbariMetaInfo.java     |  34 +-
 .../server/api/services/StacksService.java      |  35 +-
 .../server/api/util/StackExtensionHelper.java   | 105 ++++--
 .../controller/AmbariManagementController.java  |   8 +
 .../AmbariManagementControllerImpl.java         |  44 +++
 .../StackLevelConfigurationRequest.java         |  42 +++
 .../StackLevelConfigurationResponse.java        |  37 +++
 .../server/controller/StackVersionResponse.java |  14 +-
 .../AbstractControllerResourceProvider.java     |   2 +
 ...StackLevelConfigurationResourceProvider.java | 159 +++++++++
 .../internal/StackVersionResourceProvider.java  |   6 +
 .../ambari/server/controller/spi/Resource.java  |   4 +-
 .../apache/ambari/server/state/ServiceInfo.java |   1 +
 .../apache/ambari/server/state/StackInfo.java   |  26 +-
 .../ambari/server/view/ViewContextImpl.java     |   9 +
 .../apache/ambari/server/view/ViewRegistry.java |  30 +-
 .../main/resources/custom_actions/check_host.py |   2 +-
 .../src/main/resources/key_properties.json      |   5 +
 .../src/main/resources/properties.json          |  11 +
 .../src/main/resources/scripts/stack_advisor.py |   2 +-
 .../HDP/1.3.2/configuration/cluster-env.xml     |  49 +++
 .../1.3.2/hooks/before-START/scripts/params.py  |   4 +-
 .../HDP/1.3.2/services/HBASE/metainfo.xml       |   2 +-
 .../stacks/HDP/1.3.2/services/HDFS/metainfo.xml |   4 +-
 .../HIVE/package/scripts/hive_service.py        |   2 +-
 .../HDP/1.3.2/services/MAPREDUCE/metainfo.xml   |   9 +-
 .../OOZIE/package/scripts/oozie_service.py      |   2 +-
 .../stacks/HDP/1.3.2/services/PIG/metainfo.xml  |   2 +-
 .../HDP/1.3.2/services/ZOOKEEPER/metainfo.xml   |   2 +-
 .../stacks/HDP/1.3.2/services/stack_advisor.py  |   4 +-
 .../HDP/2.0.6/configuration/cluster-env.xml     |  49 +++
 .../HDP/2.0.6/services/HBASE/metainfo.xml       |   2 +-
 .../stacks/HDP/2.0.6/services/HDFS/metainfo.xml |   4 +-
 .../HIVE/package/scripts/hive_service.py        |   2 +-
 .../OOZIE/package/scripts/oozie_service.py      |   2 +-
 .../stacks/HDP/2.0.6/services/PIG/metainfo.xml  |  10 +-
 .../stacks/HDP/2.0.6/services/YARN/metainfo.xml |   4 +-
 .../HDP/2.0.6/services/ZOOKEEPER/metainfo.xml   |   2 +-
 .../stacks/HDP/2.0.6/services/stack_advisor.py  |  60 ++--
 .../services/FALCON/configuration/global.xml    |  63 ----
 .../2.1.GlusterFS/services/FALCON/metainfo.xml  |  19 +-
 .../GLUSTERFS/configuration/core-site.xml       | 169 ----------
 .../services/GLUSTERFS/configuration/global.xml |  59 ----
 .../services/GLUSTERFS/metainfo.xml             |   1 +
 .../services/STORM/configuration/global.xml     |  39 ---
 .../2.1.GlusterFS/services/STORM/metainfo.xml   |   1 +
 .../services/TEZ/configuration/global.xml       |  29 --
 .../HDP/2.1.GlusterFS/services/TEZ/metainfo.xml |  22 +-
 .../stacks/HDP/2.1/services/FALCON/metainfo.xml |  10 +
 .../stacks/HDP/2.1/services/stack_advisor.py    |  14 +-
 .../main/resources/stacks/HDP/stack_advisor.py  |  37 ---
 .../src/main/resources/stacks/stack_advisor.py  |  37 +++
 .../ambari/server/api/query/QueryImplTest.java  |   2 +-
 .../server/api/services/AmbariMetaInfoTest.java |   4 +-
 .../api/util/StackExtensionHelperTest.java      |  23 +-
 .../AmbariManagementControllerTest.java         |   2 +-
 .../internal/AbstractResourceProviderTest.java  |  45 +++
 ...kLevelConfigurationResourceProviderTest.java | 181 +++++++++++
 .../ambari/server/view/ViewRegistryTest.java    |  50 +++
 ambari-server/src/test/python/TestCheckHost.py  |   2 +-
 .../src/test/python/TestResourceFilesKeeper.py  |   2 +-
 .../src/test/python/TestStackAdvisor.py         |  93 ++++++
 .../stacks/1.3.2/HIVE/test_hive_metastore.py    |   4 +-
 .../stacks/1.3.2/HIVE/test_hive_server.py       |   4 +-
 .../hooks/before-START/test_before_start.py     |   2 +-
 .../stacks/2.0.6/HDFS/test_hdfs_client.py       |   4 +
 .../stacks/2.0.6/HIVE/test_hive_metastore.py    |   4 +-
 .../stacks/2.0.6/HIVE/test_hive_server.py       |   4 +-
 .../stacks/2.0.6/common/test_stack_advisor.py   |  38 ++-
 .../python/stacks/2.0.6/configs/default.json    |   2 +-
 .../stacks/2.1/HIVE/test_hive_metastore.py      |   4 +-
 .../HIVE/package/scripts/hive_service.py        |   2 +-
 .../stacks/XYZ/1.0.0/services/stack_advisor.py  |  67 ++++
 .../stacks/XYZ/1.0.1/services/stack_advisor.py  |  30 ++
 .../org/apache/ambari/view/ViewController.java  |  19 ++
 .../controllers/global/cluster_controller.js    |  44 ---
 .../main/dashboard/config_history_controller.js |  28 +-
 .../controllers/main/service/add_controller.js  |  24 +-
 .../controllers/main/service/info/configs.js    |  24 +-
 .../app/controllers/wizard/step3_controller.js  |   1 +
 .../app/controllers/wizard/step4_controller.js  |  42 ++-
 .../app/controllers/wizard/step8_controller.js  |  30 +-
 .../mappers/service_config_version_mapper.js    |   5 +-
 ambari-web/app/mappers/stack_service_mapper.js  |   2 +-
 ambari-web/app/messages.js                      |  12 +-
 ambari-web/app/mixins/common/serverValidator.js |   4 +-
 ambari-web/app/models/service_config.js         |   4 +
 ambari-web/app/models/service_config_version.js |  16 +-
 ambari-web/app/models/stack_service.js          |  63 +---
 ambari-web/app/router.js                        |  14 +-
 ambari-web/app/routes/add_host_routes.js        |   2 +
 ambari-web/app/routes/add_service_routes.js     |   2 +
 ambari-web/app/routes/installer.js              |   2 +
 ambari-web/app/routes/main.js                   |   1 +
 ambari-web/app/routes/views.js                  |  15 +-
 ambari-web/app/styles/application.less          |  29 +-
 ambari-web/app/styles/apps.less                 |   6 +
 .../common/configs/compare_property.hbs         |   8 +
 .../common/configs/config_history_flow.hbs      | 142 ++++----
 .../common/configs/service_config_category.hbs  |  30 +-
 ambari-web/app/utils/ajax/ajax.js               |   8 +-
 .../views/common/configs/config_history_flow.js |  29 +-
 ambari-web/app/views/main/menu.js               |   4 +-
 ambari-web/app/views/main/views_view.js         |   2 +-
 .../dashboard/config_history_controller_test.js |  38 +--
 .../main/service/add_controller_test.js         |  10 +
 .../test/controllers/wizard/step3_test.js       | 325 +++++++++++++++++++
 .../test/controllers/wizard/step4_test.js       |  38 ++-
 .../test/controllers/wizard/step5_test.js       |  19 --
 .../test/controllers/wizard/step6_test.js       |  34 --
 .../test/controllers/wizard/step7_test.js       |  92 +-----
 ambari-web/test/models/stack_service_test.js    |  52 +--
 ambari-web/test/service_components.js           |  58 +++-
 .../src/main/resources/ui/app/scripts/app.js    |   2 +-
 .../app/scripts/controllers/job_controller.js   |   2 +-
 .../app/scripts/controllers/jobs_controller.js  |  14 +-
 .../resources/ui/app/scripts/helpers/ajax.js    |  17 +-
 .../resources/ui/app/scripts/helpers/jobs.js    |  78 ++---
 .../mappers/application_status_mapper.js        |  47 +++
 contrib/views/jobs/src/main/resources/view.xml  |  10 +
 .../ui/app/components/configSection.js          | 150 +++++++++
 .../createAppWizard/step1_controller.js         |  31 ++
 .../createAppWizard/step3_controller.js         |  55 +++-
 .../controllers/create_app_wizard_controller.js |  27 +-
 .../src/main/resources/ui/app/helpers/ajax.js   |  27 +-
 .../src/main/resources/ui/app/helpers/helper.js |  37 ++-
 .../src/main/resources/ui/app/initialize.js     |   2 +
 .../ui/app/mappers/application_status.js        |  25 ++
 .../ui/app/mappers/slider_apps_mapper.js        |   2 +-
 .../app/templates/components/configSection.hbs  |  76 +++++
 .../ui/app/templates/createAppWizard/step3.hbs  |   8 +-
 .../resources/ui/app/templates/slider_app.hbs   |   2 +-
 .../ui/app/templates/slider_app/summary.hbs     |   2 +-
 .../src/main/resources/ui/app/translations.js   |   6 +
 142 files changed, 2717 insertions(+), 1148 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/52d1af76/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/52d1af76/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/52d1af76/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/52d1af76/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/52d1af76/ambari-server/src/main/resources/key_properties.json
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/52d1af76/ambari-server/src/main/resources/properties.json
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/52d1af76/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/52d1af76/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
----------------------------------------------------------------------


[34/50] [abbrv] git commit: Merge branch 'trunk' into branch-alerts-dev

Posted by jo...@apache.org.
Merge branch 'trunk' into branch-alerts-dev


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

Branch: refs/heads/trunk
Commit: 090ed5143c3869e070c0df91d15c3f77fffcd8f8
Parents: d838ca9 efa0fa6
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Tue Sep 23 09:02:47 2014 -0700
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Tue Sep 23 09:02:47 2014 -0700

----------------------------------------------------------------------
 .../resources/ui/admin-web/app/styles/main.css  |   5 +
 .../BlueprintConfigurationProcessor.java        | 184 +++-
 ambari-server/src/main/python/ambari-server.py  |  53 +-
 .../services/HIVE/package/scripts/params.py     |   4 +
 .../services/HIVE/package/scripts/webhcat.py    |   4 +-
 .../stacks/HDP/2.2/services/HIVE/metainfo.xml   |   6 -
 .../BlueprintConfigurationProcessorTest.java    | 906 ++++++++++++++++++-
 .../src/test/python/TestAmbariServer.py         |  72 +-
 ambari-web/app/messages.js                      |   4 +-
 ambari-web/app/styles/application.less          |   8 +-
 .../common/configs/config_history_flow.hbs      | 124 +--
 .../common/configs/service_version_box.hbs      |   3 +-
 .../views/common/configs/config_history_flow.js |  14 +-
 ambari-web/app/views/main/host.js               |  10 +-
 contrib/views/slider/docs/index.md              |  20 +-
 .../view/slider/SliderAppsViewController.java   |   1 +
 .../slider/SliderAppsViewControllerImpl.java    |   2 +-
 .../rest/client/SliderAppMasterClient.java      |   2 +-
 .../resources/ui/app/assets/data/apps/apps.json |   2 +-
 .../assets/data/resource/slider-properties.json |   1 +
 .../ui/app/controllers/slider_app_controller.js | 139 ++-
 .../ui/app/mappers/slider_apps_mapper.js        |   9 +-
 .../ui/app/models/slider_app_component.js       |  16 +-
 .../src/main/resources/ui/app/routes/main.js    |  21 +-
 .../resources/ui/app/styles/application.less    |  32 +
 .../resources/ui/app/templates/slider_app.hbs   |   9 +-
 .../slider_app/destroy/destroy_popup.hbs        |  20 +
 .../slider_app/destroy/destroy_popup_footer.hbs |  28 +
 .../ui/app/templates/slider_app/summary.hbs     |   8 +-
 .../src/main/resources/ui/app/translations.js   |   5 +
 .../slider_app/destroy_modal_footer_view.js     |  41 +
 .../app/views/slider_app/destroy_popup_view.js  |  37 +
 .../views/slider/src/main/resources/view.xml    |   7 +-
 33 files changed, 1613 insertions(+), 184 deletions(-)
----------------------------------------------------------------------



[35/50] [abbrv] git commit: AMBARI-7480 - Alerts: data collection starts on install before config values are available (jonathanhurley)

Posted by jo...@apache.org.
AMBARI-7480 - Alerts: data collection starts on install before config values are available (jonathanhurley)


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

Branch: refs/heads/trunk
Commit: ae9bf4c38705074821c853301c079f2f2c484ed7
Parents: 090ed51
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Wed Sep 24 12:56:54 2014 -0700
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Wed Sep 24 13:49:59 2014 -0700

----------------------------------------------------------------------
 .../server/agent/AlertDefinitionCommand.java    | 15 ++--
 .../ambari/server/agent/HeartBeatHandler.java   |  2 +-
 .../server/api/services/AmbariMetaInfo.java     | 45 ++++++----
 .../server/controller/ControllerModule.java     |  4 +
 .../AlertDefinitionResourceProvider.java        | 11 ++-
 .../AlertDefinitionRegistrationEvent.java       | 57 ++++++++++++
 .../ambari/server/events/AmbariEvent.java       | 24 ++---
 .../ambari/server/events/ClusterEvent.java      | 50 +++++++++++
 .../ambari/server/events/ServiceEvent.java      |  2 +-
 .../listeners/AlertAggregateListener.java       | 92 ++++++++------------
 .../listeners/AlertLifecycleListener.java       | 73 ++++++++++++++++
 .../server/orm/dao/AlertDefinitionDAO.java      | 40 +++++++++
 .../state/alert/AggregateDefinitionMapping.java | 88 +++++++++++++++++++
 .../server/state/alert/AlertDefinition.java     | 20 +++++
 .../state/alert/AlertDefinitionFactory.java     |  3 +-
 .../server/state/alert/AlertDefinitionHash.java | 19 +++-
 .../AlertGroupResourceProviderTest.java         |  2 +-
 .../apache/ambari/server/orm/OrmTestHelper.java |  2 +-
 .../server/orm/dao/AlertDefinitionDAOTest.java  |  2 +-
 .../server/orm/dao/AlertDispatchDAOTest.java    |  2 +-
 .../ambari/server/orm/dao/AlertsDAOTest.java    |  6 +-
 .../state/cluster/AlertDataManagerTest.java     | 59 ++++++++-----
 22 files changed, 482 insertions(+), 136 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/ae9bf4c3/ambari-server/src/main/java/org/apache/ambari/server/agent/AlertDefinitionCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/AlertDefinitionCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/AlertDefinitionCommand.java
index 5ae1741..fdd7f1d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/AlertDefinitionCommand.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/AlertDefinitionCommand.java
@@ -34,6 +34,12 @@ import com.google.gson.annotations.SerializedName;
  * The {@link AlertDefinitionCommand} class is used to encapsulate the
  * {@link AlertDefinition}s that will be returned to an agent given a requested
  * hash.
+ * <p/>
+ * Commands must have {@link #addConfigs(ConfigHelper, Cluster)} invoked before
+ * being sent to the agent so that the definitions will have the required
+ * configuration data when they run. Failure to do this will cause the alerts to
+ * be scheduled and run, but the result will always be a failure since the
+ * parameterized properties they depend on will not be available.
  */
 public class AlertDefinitionCommand extends AgentCommand {
   @SerializedName("clusterName")
@@ -47,7 +53,7 @@ public class AlertDefinitionCommand extends AgentCommand {
 
   @SerializedName("alertDefinitions")
   private final List<AlertDefinition> m_definitions;
-  
+
   @SerializedName("configurations")
   private Map<String, Map<String, String>> m_configurations;
 
@@ -118,7 +124,7 @@ public class AlertDefinitionCommand extends AgentCommand {
 
   /**
    * Adds cluster configuration properties as required by commands sent to agent.
-   * 
+   *
    * @param configHelper the helper
    * @param cluster the cluster, matching the cluster name specified by the command
    */
@@ -129,7 +135,7 @@ public class AlertDefinitionCommand extends AgentCommand {
 
     Map<String, Map<String, String>> allConfigTags =
         configHelper.getEffectiveDesiredTags(cluster, m_hostName);
-    
+
     for(Config clusterConfig: cluster.getAllConfigs()) {
       if (null == clusterConfig) {
         // !!! hard to believe
@@ -158,8 +164,5 @@ public class AlertDefinitionCommand extends AgentCommand {
 
       m_configurations.put(clusterConfig.getType(), props);
     }
-    
   }
-  
-  
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae9bf4c3/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
index a366301..c826153 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
@@ -831,8 +831,8 @@ public class HeartBeatHandler {
       String hash = alertDefinitionHash.getHash(clusterName, hostname);
       AlertDefinitionCommand command = new AlertDefinitionCommand(clusterName,
           hostname, hash, definitions);
-      command.addConfigs(configHelper, cluster);
 
+      command.addConfigs(configHelper, cluster);
       commands.add(command);
     }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae9bf4c3/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
index ec53afc..c15f73b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
@@ -47,7 +47,8 @@ import org.apache.ambari.server.api.util.StackExtensionHelper;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.customactions.ActionDefinition;
 import org.apache.ambari.server.customactions.ActionDefinitionManager;
-import org.apache.ambari.server.events.listeners.AlertAggregateListener;
+import org.apache.ambari.server.events.AlertDefinitionRegistrationEvent;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
 import org.apache.ambari.server.orm.dao.MetainfoDAO;
 import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
@@ -66,7 +67,6 @@ import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.StackInfo;
 import org.apache.ambari.server.state.alert.AlertDefinition;
 import org.apache.ambari.server.state.alert.AlertDefinitionFactory;
-import org.apache.ambari.server.state.alert.SourceType;
 import org.apache.ambari.server.state.stack.LatestRepoCallable;
 import org.apache.ambari.server.state.stack.MetricDefinition;
 import org.apache.ambari.server.state.stack.RepositoryXml;
@@ -149,6 +149,16 @@ public class AmbariMetaInfo {
    */
   private AlertDefinitionFactory alertDefinitionFactory;
 
+  /**
+   * Publishes the following events:
+   * <ul>
+   * <li>{@link AlertDefinitionRegistrationEvent} when new alerts are merged
+   * from the stack</li>
+   * </ul>
+   */
+  @Inject
+  private AmbariEventPublisher eventPublisher;
+
   // Required properties by stack version
   private final Map<StackId, Map<String, Map<String, PropertyInfo>>> requiredProperties =
     new HashMap<StackId, Map<String, Map<String, PropertyInfo>>>();
@@ -704,7 +714,7 @@ public class AmbariMetaInfo {
 
     return propertiesResult;
   }
-  
+
   public Set<PropertyInfo> getStackProperties(String stackName, String version)
       throws AmbariException {
     StackInfo stackInfo = getStackInfo(stackName, version);
@@ -742,27 +752,30 @@ public class AmbariMetaInfo {
 
     return propertyResult;
   }
-  
+
   public Set<PropertyInfo> getStackPropertiesByName(String stackName, String version, String propertyName)
       throws AmbariException {
     Set<PropertyInfo> properties = getStackProperties(stackName, version);
 
-    if (properties.size() == 0)
+    if (properties.size() == 0) {
       throw new StackAccessException("stackName=" + stackName
           + ", stackVersion=" + version
           + ", propertyName=" + propertyName);
+    }
 
     Set<PropertyInfo> propertyResult = new HashSet<PropertyInfo>();
 
     for (PropertyInfo property : properties) {
-      if (property.getName().equals(propertyName))
+      if (property.getName().equals(propertyName)) {
         propertyResult.add(property);
+      }
     }
 
-    if (propertyResult.isEmpty())
+    if (propertyResult.isEmpty()) {
       throw new StackAccessException("stackName=" + stackName
           + ", stackVersion=" + version
           + ", propertyName=" + propertyName);
+    }
 
     return propertyResult;
   }
@@ -1280,18 +1293,16 @@ public class AmbariMetaInfo {
         }
         alertDefinitionDao.createOrUpdate(entity);
       }
-      
-      // all definitions have been resolved.  pull and initialize the aggregates
+
+      // all definition resolved; publish their registration
       for (AlertDefinitionEntity def : alertDefinitionDao.findAll(cluster.getClusterId())) {
-        if (def.getSourceType().equals(SourceType.AGGREGATE)) {
-          AlertDefinition realDef = alertDefinitionFactory.coerce(def);
-          
-          AlertAggregateListener listener = injector.getInstance(AlertAggregateListener.class);
-          
-          listener.addAggregateType(cluster.getClusterId(), realDef); 
-        }
+        AlertDefinition realDef = alertDefinitionFactory.coerce(def);
+
+        AlertDefinitionRegistrationEvent event = new AlertDefinitionRegistrationEvent(
+            cluster.getClusterId(), realDef);
+
+        eventPublisher.publish(event);
       }
-      
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae9bf4c3/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
index cfab1f8..da78639 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
@@ -53,6 +53,8 @@ import org.apache.ambari.server.controller.internal.HostResourceProvider;
 import org.apache.ambari.server.controller.internal.MemberResourceProvider;
 import org.apache.ambari.server.controller.internal.ServiceResourceProvider;
 import org.apache.ambari.server.controller.spi.ResourceProvider;
+import org.apache.ambari.server.events.listeners.AlertAggregateListener;
+import org.apache.ambari.server.events.listeners.AlertLifecycleListener;
 import org.apache.ambari.server.events.listeners.AlertReceivedListener;
 import org.apache.ambari.server.events.listeners.AlertServiceStateListener;
 import org.apache.ambari.server.events.listeners.AlertStateChangedListener;
@@ -337,5 +339,7 @@ public class ControllerModule extends AbstractModule {
     bind(AlertReceivedListener.class).asEagerSingleton();
     bind(AlertStateChangedListener.class).asEagerSingleton();
     bind(AlertServiceStateListener.class).asEagerSingleton();
+    bind(AlertLifecycleListener.class).asEagerSingleton();
+    bind(AlertAggregateListener.class).asEagerSingleton();
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae9bf4c3/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java
index 7cb9886..e2d2837 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java
@@ -330,7 +330,7 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
     if (null != desiredScope && desiredScope.length() > 0) {
       scope = Scope.valueOf(desiredScope);
     }
-    
+
     SourceType sourceType = null;
     if (null != type && type.length() > 0) {
       sourceType = SourceType.valueOf(type);
@@ -473,18 +473,17 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
   private Resource toResource(boolean isCollection, String clusterName,
       AlertDefinitionEntity entity, Set<String> requestedIds) {
     Resource resource = new ResourceImpl(Resource.Type.AlertDefinition);
+    resource.setProperty(ALERT_DEF_ID, entity.getDefinitionId());
+    resource.setProperty(ALERT_DEF_CLUSTER_NAME, clusterName);
+    resource.setProperty(ALERT_DEF_NAME, entity.getDefinitionName());
+    resource.setProperty(ALERT_DEF_LABEL, entity.getLabel());
 
-    setResourceProperty(resource, ALERT_DEF_CLUSTER_NAME, clusterName, requestedIds);
-    setResourceProperty(resource, ALERT_DEF_ID, entity.getDefinitionId(), requestedIds);
-    setResourceProperty(resource, ALERT_DEF_NAME, entity.getDefinitionName(), requestedIds);
     setResourceProperty(resource, ALERT_DEF_INTERVAL, entity.getScheduleInterval(), requestedIds);
     setResourceProperty(resource, ALERT_DEF_SERVICE_NAME, entity.getServiceName(), requestedIds);
     setResourceProperty(resource, ALERT_DEF_COMPONENT_NAME, entity.getComponentName(), requestedIds);
     setResourceProperty(resource, ALERT_DEF_ENABLED, Boolean.valueOf(entity.getEnabled()), requestedIds);
     setResourceProperty(resource, ALERT_DEF_SCOPE, entity.getScope(), requestedIds);
     setResourceProperty(resource, ALERT_DEF_SOURCE_TYPE, entity.getSourceType(), requestedIds);
-    setResourceProperty(resource, ALERT_DEF_LABEL, entity.getLabel(),
-        requestedIds);
 
     if (!isCollection && null != resource.getPropertyValue(ALERT_DEF_SOURCE_TYPE)) {
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae9bf4c3/ambari-server/src/main/java/org/apache/ambari/server/events/AlertDefinitionRegistrationEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/AlertDefinitionRegistrationEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/AlertDefinitionRegistrationEvent.java
new file mode 100644
index 0000000..4b68ae9
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/AlertDefinitionRegistrationEvent.java
@@ -0,0 +1,57 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.events;
+
+import org.apache.ambari.server.state.alert.AlertDefinition;
+
+/**
+ * The {@link AlertDefinitionRegistrationEvent} is used to represent that an
+ * {@link AlertDefinition} is now a part of the system. This usually happens at
+ * startup when the alerts are being merged from the stack. It also occurs when
+ * a new alert is created via the REST APIs or when a new service is installed.
+ */
+public class AlertDefinitionRegistrationEvent extends ClusterEvent {
+
+  /**
+   * The newly registered alert defintiion
+   */
+  private final AlertDefinition m_definition;
+
+  /**
+   * Constructor.
+   *
+   * @param clusterId
+   *          the ID of the cluster that the definition is in.
+   * @param definition
+   *          the alert definition being registered.
+   */
+  public AlertDefinitionRegistrationEvent(
+      long clusterId, AlertDefinition definition) {
+    super(AmbariEventType.ALERT_DEFINITION_REGISTRATION, clusterId);
+    m_definition = definition;
+  }
+
+  /**
+   * Get the registered alert definition.
+   *
+   * @return the alert definition (not {@code null}).
+   */
+  public AlertDefinition getDefinition() {
+    return m_definition;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae9bf4c3/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java
index dda18c7..6cf752e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java
@@ -30,7 +30,12 @@ public abstract class AmbariEvent {
     /**
      * A service was successfully installed.
      */
-    SERVICE_INSTALL_SUCCESS;
+    SERVICE_INSTALL_SUCCESS,
+
+    /**
+     * An alert definition is registered with the system.
+     */
+    ALERT_DEFINITION_REGISTRATION;
   }
 
   /**
@@ -39,29 +44,14 @@ public abstract class AmbariEvent {
   protected final AmbariEventType m_eventType;
 
   /**
-   * The cluster ID.
-   */
-  protected final long m_clusterId;
-
-  /**
    * Constructor.
    *
    * @param eventType
    *          the type of event (not {@code null}).
    * @param clusterId
    */
-  public AmbariEvent(AmbariEventType eventType, long clusterId) {
+  public AmbariEvent(AmbariEventType eventType) {
     m_eventType = eventType;
-    m_clusterId = clusterId;
-  }
-
-  /**
-   * Gets the cluster ID that the event belongs to.
-   *
-   * @return the ID of the cluster.
-   */
-  public long getClusterId() {
-    return m_clusterId;
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae9bf4c3/ambari-server/src/main/java/org/apache/ambari/server/events/ClusterEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/ClusterEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/ClusterEvent.java
new file mode 100644
index 0000000..8f39ac3
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/ClusterEvent.java
@@ -0,0 +1,50 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.events;
+
+/**
+ * The {@link ClusterEvent} represents all events in Ambari that can be scoped
+ * within a cluster.
+ */
+public class ClusterEvent extends AmbariEvent {
+  /**
+   * The cluster ID.
+   */
+  protected final long m_clusterId;
+
+  /**
+   * Constructor.
+   *
+   * @param eventType
+   * @param clusterId
+   */
+  public ClusterEvent(AmbariEventType eventType, long clusterId) {
+    super(eventType);
+    m_clusterId = clusterId;
+  }
+
+  /**
+   * Gets the cluster ID that the event belongs to.
+   *
+   * @return the ID of the cluster.
+   */
+  public long getClusterId() {
+    return m_clusterId;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae9bf4c3/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceEvent.java
index 5e01431..3bc5c17 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceEvent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceEvent.java
@@ -21,7 +21,7 @@ package org.apache.ambari.server.events;
 /**
  * The {@link ServiceEvent} class is the base for all service events in Ambari.
  */
-public abstract class ServiceEvent extends AmbariEvent {
+public abstract class ServiceEvent extends ClusterEvent {
 
   /**
    * The name of the service.

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae9bf4c3/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertAggregateListener.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertAggregateListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertAggregateListener.java
index 8340c26..a0c8e46 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertAggregateListener.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertAggregateListener.java
@@ -18,10 +18,6 @@
 package org.apache.ambari.server.events.listeners;
 
 import java.text.MessageFormat;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 import org.apache.ambari.server.events.AlertReceivedEvent;
 import org.apache.ambari.server.events.publishers.AlertEventPublisher;
@@ -29,116 +25,100 @@ import org.apache.ambari.server.orm.dao.AlertSummaryDTO;
 import org.apache.ambari.server.orm.dao.AlertsDAO;
 import org.apache.ambari.server.state.Alert;
 import org.apache.ambari.server.state.AlertState;
+import org.apache.ambari.server.state.alert.AggregateDefinitionMapping;
 import org.apache.ambari.server.state.alert.AggregateSource;
 import org.apache.ambari.server.state.alert.AlertDefinition;
 import org.apache.ambari.server.state.alert.Reporting;
-import org.apache.ambari.server.state.alert.Reporting.ReportTemplate;
+import org.apache.ambari.server.state.alert.SourceType;
 
 import com.google.common.eventbus.Subscribe;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 /**
- * Used to aggregate alerts. 
+ * The {@link AlertAggregateListener} is used to listen for all incoming
+ * {@link AlertReceivedEvent} instances and determine if there exists a
+ * {@link SourceType#AGGREGATE} alert that needs to run.
  */
+@Singleton
 public class AlertAggregateListener {
 
   @Inject
   private AlertsDAO m_alertsDao = null;
 
-  private AlertEventPublisher m_publisher = null;
-  private Map<Long, Map<String, AlertDefinition>> m_aggregateMap = 
-      new HashMap<Long, Map<String, AlertDefinition>>();
-  
+  /**
+   * The event publisher used to receive incoming events and publish new events
+   * when an aggregate alert is run.
+   */
+  private final AlertEventPublisher m_publisher;
+
+  /**
+   * Used for quick lookups of aggregate alerts.
+   */
+  @Inject
+  private AggregateDefinitionMapping m_aggregateMapping;
+
   @Inject
   public AlertAggregateListener(AlertEventPublisher publisher) {
     m_publisher = publisher;
-
-    publisher.register(this);
+    m_publisher.register(this);
   }
-  
+
   /**
    * Consume an alert that was received.
    */
   @Subscribe
   public void onAlertEvent(AlertReceivedEvent event) {
-    AlertDefinition def = getAggregateDefinition(event.getClusterId(), event.getAlert().getName());
-    
+    AlertDefinition def = m_aggregateMapping.getAggregateDefinition(
+        event.getClusterId(), event.getAlert().getName());
+
     if (null == def || null == m_alertsDao) {
       return;
     }
-    
+
     AggregateSource as = (AggregateSource) def.getSource();
-    
+
     AlertSummaryDTO summary = m_alertsDao.findAggregateCounts(
         event.getClusterId(), as.getAlertName());
-    
+
     Alert alert = new Alert(def.getName(), null, def.getServiceName(),
         null, null, AlertState.UNKNOWN);
+
     alert.setLabel(def.getLabel());
     alert.setTimestamp(System.currentTimeMillis());
-    
+
     if (0 == summary.getOkCount()) {
       alert.setText("Cannot determine, there are no records");
     } else if (summary.getUnknownCount() > 0) {
       alert.setText("There are alerts with status UNKNOWN.");
     } else {
       Reporting reporting = as.getReporting();
-      
+
       int numerator = summary.getCriticalCount() + summary.getWarningCount();
       int denominator = summary.getOkCount();
       double value = (double)(numerator) / denominator;
-      
+
       if (value > reporting.getCritical().getValue().doubleValue()) {
         alert.setState(AlertState.CRITICAL);
         alert.setText(MessageFormat.format(reporting.getCritical().getText(),
             Integer.valueOf(denominator), Integer.valueOf(numerator)));
-        
+
       } else if (value > reporting.getWarning().getValue().doubleValue()) {
         alert.setState(AlertState.WARNING);
         alert.setText(MessageFormat.format(reporting.getWarning().getText(),
             Integer.valueOf(denominator), Integer.valueOf(numerator)));
-        
+
       } else {
         alert.setState(AlertState.OK);
         alert.setText(MessageFormat.format(reporting.getOk().getText(),
             Integer.valueOf(denominator), Integer.valueOf(numerator)));
       }
-      
+
     }
-    
+
     // make a new event and allow others to consume it
     AlertReceivedEvent aggEvent = new AlertReceivedEvent(event.getClusterId(), alert);
-    
-    m_publisher.publish(aggEvent);
-  }
-  
-  private AlertDefinition getAggregateDefinition(long clusterId, String name) {
-    Long id = Long.valueOf(clusterId);
-    if (!m_aggregateMap.containsKey(id))
-      return null;
-    
-    if (!m_aggregateMap.get(id).containsKey(name))
-      return null;
-    
-    return m_aggregateMap.get(id).get(name);
-  }
 
-  /**
-   * @param source the aggregate source
-   */
-  public void addAggregateType(long clusterId, AlertDefinition definition) {
-    Long id = Long.valueOf(clusterId);
-    
-    if (!m_aggregateMap.containsKey(id)) {
-      m_aggregateMap.put(id, new HashMap<String, AlertDefinition>());
-    }
-    
-    Map<String, AlertDefinition> map = m_aggregateMap.get(id);
-    
-    AggregateSource as = (AggregateSource) definition.getSource();
-    
-    map.put(as.getAlertName(), definition);
+    m_publisher.publish(aggEvent);
   }
-  
-  
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae9bf4c3/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertLifecycleListener.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertLifecycleListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertLifecycleListener.java
new file mode 100644
index 0000000..43d4b35
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertLifecycleListener.java
@@ -0,0 +1,73 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.events.listeners;
+
+import org.apache.ambari.server.events.AlertDefinitionRegistrationEvent;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
+import org.apache.ambari.server.state.alert.AggregateDefinitionMapping;
+import org.apache.ambari.server.state.alert.AlertDefinition;
+import org.apache.ambari.server.state.alert.SourceType;
+
+import com.google.common.eventbus.AllowConcurrentEvents;
+import com.google.common.eventbus.Subscribe;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+/**
+ * The {@link AlertLifecycleListener} handles events that are part of the alert
+ * infrastructure lifecycle such as definition registration events.
+ */
+@Singleton
+public class AlertLifecycleListener {
+
+  /**
+   * Used for quick lookups of aggregate alerts.
+   */
+  @Inject
+  private AggregateDefinitionMapping m_aggregateMapping;
+
+  /**
+   * Constructor.
+   *
+   * @param publisher
+   */
+  @Inject
+  public AlertLifecycleListener(AmbariEventPublisher publisher) {
+    publisher.register(this);
+  }
+
+  /**
+   * Handles {@link AlertDefinitionRegistrationEvent} by performing the
+   * following tasks:
+   * <ul>
+   * <li>Registration with {@link AggregateDefinitionMapping}</li>
+   * </ul>
+   *
+   * @param event
+   *          the event being handled.
+   */
+  @Subscribe
+  @AllowConcurrentEvents
+  public void onAmbariEvent(AlertDefinitionRegistrationEvent event) {
+    AlertDefinition definition = event.getDefinition();
+
+    if (definition.getSource().getType() == SourceType.AGGREGATE) {
+      m_aggregateMapping.addAggregateType(event.getClusterId(), definition);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae9bf4c3/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java
index 570f268..075ee04 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java
@@ -25,9 +25,15 @@ import javax.persistence.EntityManager;
 import javax.persistence.TypedQuery;
 
 import org.apache.ambari.server.controller.RootServiceResponseFactory;
+import org.apache.ambari.server.events.AlertDefinitionRegistrationEvent;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
 import org.apache.ambari.server.orm.entities.AlertGroupEntity;
+import org.apache.ambari.server.state.alert.AlertDefinition;
+import org.apache.ambari.server.state.alert.AlertDefinitionFactory;
 import org.apache.ambari.server.state.alert.Scope;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -41,6 +47,11 @@ import com.google.inject.persist.Transactional;
 @Singleton
 public class AlertDefinitionDAO {
   /**
+   * Logger.
+   */
+  private static Logger LOG = LoggerFactory.getLogger(AlertDefinitionDAO.class);
+
+  /**
    * JPA entity manager
    */
   @Inject
@@ -65,6 +76,23 @@ public class AlertDefinitionDAO {
   AlertDispatchDAO dispatchDao;
 
   /**
+   * Publishes the following events:
+   * <ul>
+   * <li>{@link AlertDefinitionRegistrationEvent} when new alerts are merged
+   * from the stack</li>
+   * </ul>
+   */
+  @Inject
+  private AmbariEventPublisher eventPublisher;
+
+  /**
+   * A factory that assists in the creation of {@link AlertDefinition} and
+   * {@link AlertDefinitionEntity}.
+   */
+  @Inject
+  private AlertDefinitionFactory alertDefinitionFactory;
+
+  /**
    * Gets an alert definition with the specified ID.
    *
    * @param definitionId
@@ -264,6 +292,18 @@ public class AlertDefinitionDAO {
       group.addAlertDefinition(alertDefinition);
       dispatchDao.merge(group);
     }
+
+    // publish the alert definition registration
+    AlertDefinition coerced = alertDefinitionFactory.coerce(alertDefinition);
+    if (null != coerced) {
+      AlertDefinitionRegistrationEvent event = new AlertDefinitionRegistrationEvent(
+          alertDefinition.getClusterId(), coerced);
+
+      eventPublisher.publish(event);
+    } else {
+      LOG.warn("Unable to broadcast alert registration event for {}",
+          alertDefinition.getDefinitionName());
+    }
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae9bf4c3/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AggregateDefinitionMapping.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AggregateDefinitionMapping.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AggregateDefinitionMapping.java
new file mode 100644
index 0000000..04f20f9
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AggregateDefinitionMapping.java
@@ -0,0 +1,88 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state.alert;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.google.inject.Singleton;
+
+/**
+ * The {@link AggregateDefinitionMapping} is used to keep an in-memory mapping
+ * of all of the {@link AlertDefinition}s that have aggregate definitions
+ * associated with them.
+ */
+@Singleton
+public final class AggregateDefinitionMapping {
+  /**
+   * In-memory mapping of cluster ID to definition name / aggregate definition.
+   * This is used for fast lookups when receiving events.
+   */
+  private Map<Long, Map<String, AlertDefinition>> m_aggregateMap = new HashMap<Long, Map<String, AlertDefinition>>();
+
+  /**
+   * Constructor.
+   *
+   */
+  public AggregateDefinitionMapping() {
+  }
+
+  /**
+   * Gets an aggregate definition based on a given alert definition name.
+   *
+   * @param clusterId
+   *          the ID of the cluster that the definition is bound to.
+   * @param name
+   *          the unique name of the definition.
+   * @return the aggregate definition, or {@code null} if none.
+   */
+  public AlertDefinition getAggregateDefinition(long clusterId, String name) {
+    Long id = Long.valueOf(clusterId);
+    if (!m_aggregateMap.containsKey(id)) {
+      return null;
+    }
+
+    if (!m_aggregateMap.get(id).containsKey(name)) {
+      return null;
+    }
+
+    return m_aggregateMap.get(id).get(name);
+  }
+
+  /**
+   * Adds a mapping for a new aggregate definition.
+   *
+   * @param clusterId
+   *          the ID of the cluster that the definition is bound to.
+   * @param name
+   *          the unique name of the definition.
+   */
+  public void addAggregateType(long clusterId, AlertDefinition definition) {
+    Long id = Long.valueOf(clusterId);
+
+    if (!m_aggregateMap.containsKey(id)) {
+      m_aggregateMap.put(id, new HashMap<String, AlertDefinition>());
+    }
+
+    Map<String, AlertDefinition> map = m_aggregateMap.get(id);
+
+    AggregateSource as = (AggregateSource) definition.getSource();
+
+    map.put(as.getAlertName(), definition);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae9bf4c3/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinition.java
index f227c0a..5058e91 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinition.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinition.java
@@ -43,6 +43,7 @@ public class AlertDefinition {
   private boolean enabled = true;
   private Source source = null;
   private String label = null;
+  private String uuid = null;
 
   /**
    * @return the service name
@@ -150,6 +151,25 @@ public class AlertDefinition {
   }
 
   /**
+   * Sets the UUID of the definition
+   *
+   * @param definitionUuid
+   */
+  public void setUuid(String definitionUuid) {
+    uuid = definitionUuid;
+  }
+
+  /**
+   * Gets the UUID of the definition. The UUID is a unique identifier that is
+   * generated every time the definition's state changes.
+   *
+   * @return the UUID
+   */
+  public String getUuid() {
+    return uuid;
+  }
+
+  /**
    * Compares {@link #equals(Object)} of every field. This is used mainly for
    * reconciling the stack versus the database.
    *

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae9bf4c3/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionFactory.java
index f8e44bd..4f6a9a3 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionFactory.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionFactory.java
@@ -132,6 +132,7 @@ public class AlertDefinitionFactory {
     definition.setScope(entity.getScope());
     definition.setServiceName(entity.getServiceName());
     definition.setLabel(entity.getLabel());
+    definition.setUuid(entity.getHash());
 
     try{
       String sourceJson = entity.getSource();
@@ -139,7 +140,7 @@ public class AlertDefinitionFactory {
       definition.setSource(source);
     } catch (Exception exception) {
       LOG.error(
-          "Unable to deserialized the alert definition source during coercion",
+          "Unable to deserialize the alert definition source during coercion",
           exception);
 
       return null;

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae9bf4c3/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java
index 0a1c73a..9ea039c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java
@@ -42,6 +42,7 @@ import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
 import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.ConfigHelper;
 import org.apache.ambari.server.state.Host;
 import org.apache.ambari.server.state.Service;
 import org.apache.ambari.server.state.ServiceComponent;
@@ -51,6 +52,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.inject.Inject;
+import com.google.inject.Provider;
 import com.google.inject.Singleton;
 
 /**
@@ -91,6 +93,14 @@ public class AlertDefinitionHash {
   private ActionQueue m_actionQueue;
 
   /**
+   * Used to add configurations to the {@link AlertDefinitionCommand} instances
+   * so that alerts can be scheduled to run with access to the properties they
+   * need.
+   */
+  @Inject
+  private Provider<ConfigHelper> m_configHelper;
+
+  /**
    * !!! TODO: this class needs some thoughts on locking
    */
   private ReadWriteLock m_lock = new ReentrantReadWriteLock();
@@ -489,7 +499,7 @@ public class AlertDefinitionHash {
    * This method is typically called after
    * {@link #invalidateHosts(AlertDefinitionEntity)} has caused a cache
    * invalidation of the alert definition hash.
-   * 
+   *
    * @param clusterName
    *          the name of the cluster (not {@code null}).
    * @param hosts
@@ -514,6 +524,13 @@ public class AlertDefinitionHash {
       AlertDefinitionCommand command = new AlertDefinitionCommand(clusterName,
           hostName, hash, definitions);
 
+      try {
+        Cluster cluster = m_clusters.getCluster(clusterName);
+        command.addConfigs(m_configHelper.get(), cluster);
+      } catch (AmbariException ae) {
+        LOG.warn("Unable to add configurations to alert definition command", ae);
+      }
+
       // unlike other commands, the alert definitions commands are really
       // designed to be 1:1 per change; if multiple invalidations happened
       // before the next heartbeat, there would be several commands that would

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae9bf4c3/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java
index d2ce6fb..5583617 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java
@@ -479,7 +479,7 @@ public class AlertGroupResourceProviderTest {
     entity.setScheduleInterval(Integer.valueOf(2));
     entity.setServiceName(null);
     entity.setSourceType(SourceType.METRIC);
-    entity.setSource(null);
+    entity.setSource("{\"type\" : \"METRIC\"}");
 
     Set<AlertDefinitionEntity> definitions = new HashSet<AlertDefinitionEntity>();
     definitions.add(entity);

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae9bf4c3/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java b/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
index 08cd7b8..dc71862 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
@@ -330,7 +330,7 @@ public class OrmTestHelper {
     definition.setHash(UUID.randomUUID().toString());
     definition.setScheduleInterval(60);
     definition.setScope(Scope.SERVICE);
-    definition.setSource("Source " + System.currentTimeMillis());
+    definition.setSource("{\"type\" : \"SCRIPT\"}");
     definition.setSourceType(SourceType.SCRIPT);
 
     alertDefinitionDAO.create(definition);

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae9bf4c3/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
index 3e20cd6..4d182cc 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
@@ -97,7 +97,7 @@ public class AlertDefinitionDAOTest {
       definition.setHash(UUID.randomUUID().toString());
       definition.setScheduleInterval(60);
       definition.setScope(Scope.SERVICE);
-      definition.setSource("Source " + i);
+      definition.setSource("{\"type\" : \"SCRIPT\"}");
       definition.setSourceType(SourceType.SCRIPT);
       dao.create(definition);
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae9bf4c3/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDispatchDAOTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDispatchDAOTest.java b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDispatchDAOTest.java
index 7f4deda..015acc0 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDispatchDAOTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDispatchDAOTest.java
@@ -431,7 +431,7 @@ public class AlertDispatchDAOTest {
       definition.setHash(UUID.randomUUID().toString());
       definition.setScheduleInterval(60);
       definition.setScope(Scope.SERVICE);
-      definition.setSource("Source " + i);
+      definition.setSource("{\"type\" : \"SCRIPT\"}");
       definition.setSourceType(SourceType.SCRIPT);
       definitionDao.create(definition);
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae9bf4c3/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 6e4d4af..0cc2ae7 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
@@ -85,7 +85,7 @@ public class AlertsDAOTest {
       definition.setHash(UUID.randomUUID().toString());
       definition.setScheduleInterval(Integer.valueOf(60));
       definition.setScope(Scope.SERVICE);
-      definition.setSource("Source " + i);
+      definition.setSource("{\"type\" : \"SCRIPT\"}");
       definition.setSourceType(SourceType.SCRIPT);
       definitionDao.create(definition);
     }
@@ -209,7 +209,7 @@ public class AlertsDAOTest {
     hostDef.setHash(UUID.randomUUID().toString());
     hostDef.setScheduleInterval(Integer.valueOf(60));
     hostDef.setScope(Scope.HOST);
-    hostDef.setSource("HostService");
+    hostDef.setSource("{\"type\" : \"SCRIPT\"}");
     hostDef.setSourceType(SourceType.SCRIPT);
     definitionDao.create(hostDef);
 
@@ -409,7 +409,7 @@ public class AlertsDAOTest {
     definition.setHash(UUID.randomUUID().toString());
     definition.setScheduleInterval(Integer.valueOf(60));
     definition.setScope(Scope.SERVICE);
-    definition.setSource("SourceScript");
+    definition.setSource("{\"type\" : \"SCRIPT\"}");
     definition.setSourceType(SourceType.SCRIPT);
     definitionDao.create(definition);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/ae9bf4c3/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java
index 00ba942..85a6e9b 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java
@@ -50,7 +50,9 @@ import org.apache.ambari.server.orm.entities.AlertNoticeEntity;
 import org.apache.ambari.server.orm.entities.AlertTargetEntity;
 import org.apache.ambari.server.state.Alert;
 import org.apache.ambari.server.state.AlertState;
+import org.apache.ambari.server.state.alert.AggregateDefinitionMapping;
 import org.apache.ambari.server.state.alert.AggregateSource;
+import org.apache.ambari.server.state.alert.AlertDefinition;
 import org.apache.ambari.server.state.alert.AlertDefinitionFactory;
 import org.apache.ambari.server.state.alert.Reporting;
 import org.apache.ambari.server.state.alert.Reporting.ReportTemplate;
@@ -108,7 +110,7 @@ public class AlertDataManagerTest {
       definition.setHash(UUID.randomUUID().toString());
       definition.setScheduleInterval(Integer.valueOf(60));
       definition.setScope(Scope.SERVICE);
-      definition.setSource("Source " + i);
+      definition.setSource("{\"type\" : \"SCRIPT\"}");
       definition.setSourceType(SourceType.SCRIPT);
       definitionDao.create(definition);
     }
@@ -268,7 +270,7 @@ public class AlertDataManagerTest {
     notices = dispatchDao.findAllNotices();
     assertEquals(1, notices.size());
   }
-  
+
   @Test
   public void testAggregateAlerts() throws Exception {
     // create definition
@@ -281,10 +283,10 @@ public class AlertDataManagerTest {
     definition.setHash(UUID.randomUUID().toString());
     definition.setScheduleInterval(Integer.valueOf(60));
     definition.setScope(Scope.HOST);
-    definition.setSource("Source");
+    definition.setSource("{\"type\" : \"SCRIPT\"}");
     definition.setSourceType(SourceType.SCRIPT);
     definitionDao.create(definition);
-    
+
     // create aggregate of definition
     AlertDefinitionEntity aggDef = new AlertDefinitionEntity();
     aggDef.setDefinitionName("aggregate_test");
@@ -294,7 +296,7 @@ public class AlertDataManagerTest {
     aggDef.setHash(UUID.randomUUID().toString());
     aggDef.setScheduleInterval(Integer.valueOf(60));
     aggDef.setScope(Scope.SERVICE);
-    
+
     AggregateSource source = new AggregateSource();
 
     source.setAlertName("to_aggregate");
@@ -304,7 +306,7 @@ public class AlertDataManagerTest {
     field.set(source, SourceType.AGGREGATE);
 
     Reporting reporting = new Reporting();
-    
+
     ReportTemplate template = new ReportTemplate();
     template.setText("You are good {1}/{0}");
     reporting.setOk(template);
@@ -313,20 +315,20 @@ public class AlertDataManagerTest {
     template.setText("Going bad {1}/{0}");
     template.setValue(Double.valueOf(0.33d));
     reporting.setWarning(template);
-    
+
     template = new ReportTemplate();
     template.setText("On fire! {1}/{0}");
     template.setValue(Double.valueOf(0.66d));
     reporting.setCritical(template);
-    
+
     source.setReporting(reporting);
 
     Gson gson = new Gson();
-    
+
     aggDef.setSource(gson.toJson(source));
     aggDef.setSourceType(SourceType.AGGREGATE);
     definitionDao.create(aggDef);
-    
+
     // add current and history across four hosts
     for (int i = 0; i < 4; i++) {
       AlertHistoryEntity history = new AlertHistoryEntity();
@@ -341,7 +343,7 @@ public class AlertDataManagerTest {
       history.setHostName("h" + (i+1));
       history.setServiceName(definition.getServiceName());
       dao.create(history);
-     
+
       AlertCurrentEntity current = new AlertCurrentEntity();
       current.setAlertHistory(history);
       current.setLatestText(history.getAlertText());
@@ -349,7 +351,7 @@ public class AlertDataManagerTest {
       current.setOriginalTimestamp(Long.valueOf(1L));
       dao.merge(current);
     }
-    
+
     AlertEventPublisher publisher = injector.getInstance(AlertEventPublisher.class);
 
     // !!! need a synchronous op for testing
@@ -357,17 +359,28 @@ public class AlertDataManagerTest {
     field.setAccessible(true);
     field.set(publisher, new EventBus());
 
-    final AtomicReference<Alert> ref = new AtomicReference<Alert>();    
+    final AtomicReference<Alert> ref = new AtomicReference<Alert>();
     publisher.register(new TestListener() {
+      @Override
       @Subscribe
       public void catchIt(AlertReceivedEvent event) {
         ref.set(event.getAlert());
       }
     });
-    
+
     AlertAggregateListener listener = injector.getInstance(AlertAggregateListener.class);
     AlertDefinitionFactory factory = new AlertDefinitionFactory();
-    listener.addAggregateType(clusterId.longValue(), factory.coerce(aggDef));
+    AggregateDefinitionMapping aggregateMapping = injector.getInstance(AggregateDefinitionMapping.class);
+
+    AlertDefinition aggregateDefinition = factory.coerce(aggDef);
+    aggregateMapping.addAggregateType(clusterId.longValue(),
+        aggregateDefinition );
+
+    AggregateSource as = (AggregateSource) aggregateDefinition.getSource();
+    AlertDefinition aggregatedDefinition = aggregateMapping.getAggregateDefinition(
+        clusterId.longValue(), as.getAlertName());
+
+    assertNotNull(aggregatedDefinition);
 
     // any alert and event will do that is for the definition since an aggregate
     // checks them all regardless of state
@@ -379,12 +392,12 @@ public class AlertDataManagerTest {
         "h1",
         AlertState.OK);
     AlertReceivedEvent event = new AlertReceivedEvent(clusterId.longValue(), alert);
-    
+
     listener.onAlertEvent(event);
     assertNotNull(ref.get());
     assertEquals(AlertState.OK, ref.get().getState());
     assertTrue(ref.get().getText().indexOf("0/4") > -1);
-    
+
     // check if one is critical, still ok
     AlertCurrentEntity current = dao.findCurrentByHostAndName(
         clusterId.longValue(), "h1", definition.getDefinitionName());
@@ -392,7 +405,7 @@ public class AlertDataManagerTest {
     dao.merge(current.getAlertHistory());
 
     listener.onAlertEvent(event);
-    assertEquals("aggregate_test", ref.get().getName());    
+    assertEquals("aggregate_test", ref.get().getName());
     assertEquals(AlertState.OK, ref.get().getState());
     assertTrue(ref.get().getText().indexOf("1/4") > -1);
 
@@ -401,7 +414,7 @@ public class AlertDataManagerTest {
         clusterId.longValue(), "h2", definition.getDefinitionName());
     current.getAlertHistory().setAlertState(AlertState.WARNING);
     dao.merge(current.getAlertHistory());
-    
+
     listener.onAlertEvent(event);
     assertEquals("aggregate_test", ref.get().getName());
     assertEquals(AlertState.WARNING, ref.get().getState());
@@ -412,15 +425,15 @@ public class AlertDataManagerTest {
         clusterId.longValue(), "h3", definition.getDefinitionName());
     current.getAlertHistory().setAlertState(AlertState.CRITICAL);
     dao.merge(current.getAlertHistory());
-    
+
     listener.onAlertEvent(event);
-    assertEquals("aggregate_test", ref.get().getName());    
+    assertEquals("aggregate_test", ref.get().getName());
     assertEquals(AlertState.CRITICAL, ref.get().getState());
     assertTrue(ref.get().getText().indexOf("3/4") > -1);
   }
-  
+
   /**
-   * Test interface collects aggregate alert invocations 
+   * Test interface collects aggregate alert invocations
    */
   private static interface TestListener {
     public void catchIt(AlertReceivedEvent event);


[49/50] [abbrv] git commit: Merge branch 'trunk' into branch-alerts-dev

Posted by jo...@apache.org.
Merge branch 'trunk' into branch-alerts-dev

Conflicts:
	ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
	ambari-server/src/main/resources/key_properties.json
	ambari-server/src/main/resources/properties.json


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

Branch: refs/heads/trunk
Commit: cc2d9341336218878af81bea0cc8ee7fc2a7d9ec
Parents: 9919b3f 811ea58
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Mon Oct 6 16:27:12 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Mon Oct 6 16:27:12 2014 -0400

----------------------------------------------------------------------
 .../resources/ControllerResourceDefinition.java |  60 ----
 .../resources/ResourceInstanceFactoryImpl.java  |   6 -
 .../server/api/services/ControllerService.java  |  98 -------
 .../server/api/util/StackExtensionHelper.java   |  14 +-
 .../AbstractControllerResourceProvider.java     |   2 -
 .../internal/ControllerResourceProvider.java    | 282 -------------------
 .../controller/internal/ControllerType.java     |  65 -----
 .../internal/StackDefinedPropertyProvider.java  |  10 +-
 .../metrics/RestMetricsPropertyProvider.java    |  19 +-
 .../ambari/server/controller/spi/Resource.java  |   2 -
 ambari-server/src/main/python/ambari-server.py  |  13 +-
 .../src/main/resources/key_properties.json      |   3 -
 .../src/main/resources/properties.json          |   9 -
 .../stacks/HDP/2.2/services/HIVE/metainfo.xml   |   5 +
 .../stacks/HDP/2.2/services/stack_advisor.py    |   5 +-
 .../api/util/StackExtensionHelperTest.java      |  27 ++
 .../stacks/2.2/common/test_stack_advisor.py     | 137 +++++++--
 .../single_stack/ABC/1.0.0/metainfo.xml         |  22 ++
 .../ABC/1.0.0/services/HDFS/metainfo.xml        | 193 +++++++++++++
 .../ui/app/scripts/models/jobs/tez_dag.js       |   4 +-
 .../main/resources/ui/app/models/slider_app.js  |  16 ++
 .../resources/ui/app/templates/slider_apps.hbs  |   4 +-
 .../ui/app/views/common/filter_view.js          |   4 +-
 .../resources/ui/app/views/common/table_view.js |   2 +-
 .../resources/ui/app/views/slider_apps_view.js  |  15 +-
 .../ui/test/unit/views/slider_apps_view_test.js |  37 +++
 26 files changed, 469 insertions(+), 585 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/cc2d9341/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc2d9341/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
----------------------------------------------------------------------
diff --cc ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
index f3f92a1,17df861..5810633
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
@@@ -149,16 -149,8 +149,14 @@@ public abstract class AbstractControlle
          return new RecommendationResourceProvider(propertyIds, keyPropertyIds, managementController);
        case Validation:
          return new ValidationResourceProvider(propertyIds, keyPropertyIds, managementController);
 +      case Alert:
 +        return new AlertResourceProvider(propertyIds, keyPropertyIds, managementController);
        case AlertDefinition:
          return new AlertDefinitionResourceProvider(propertyIds, keyPropertyIds, managementController);
 +      case AlertGroup:
 +        return new AlertGroupResourceProvider(propertyIds, keyPropertyIds, managementController);
 +      case AlertTarget:
 +        return new AlertTargetResourceProvider(propertyIds, keyPropertyIds, managementController);
-       case Controller:
-         return new ControllerResourceProvider(propertyIds, keyPropertyIds, managementController);
        case ClientConfig:
          return new ClientConfigResourceProvider(propertyIds, keyPropertyIds, managementController);
        default:

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc2d9341/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc2d9341/ambari-server/src/main/resources/key_properties.json
----------------------------------------------------------------------
diff --cc ambari-server/src/main/resources/key_properties.json
index d127bc5,b4dfbf7..085dc11
--- a/ambari-server/src/main/resources/key_properties.json
+++ b/ambari-server/src/main/resources/key_properties.json
@@@ -155,16 -149,6 +155,13 @@@
      "Cluster": "AlertDefinition/cluster_name",
      "AlertDefinition": "AlertDefinition/id"
    },
 +  "AlertTarget": {
 +    "AlertTarget": "AlertTarget/id"
 +  },
 +  "AlertGroup": {
 +    "Cluster": "AlertGroup/cluster_name",
 +    "AlertGroup": "AlertGroup/id"
 +  },  
-   "Controller": {
-     "Controller": "Controllers/name"
-   },
    "ClientConfig": {
      "Cluster": "ServiceComponentInfo/cluster_name",
      "Service": "ServiceComponentInfo/service_name",

http://git-wip-us.apache.org/repos/asf/ambari/blob/cc2d9341/ambari-server/src/main/resources/properties.json
----------------------------------------------------------------------
diff --cc ambari-server/src/main/resources/properties.json
index 96f44c4,bff0c94..8a0a58a
--- a/ambari-server/src/main/resources/properties.json
+++ b/ambari-server/src/main/resources/properties.json
@@@ -447,34 -431,8 +447,25 @@@
        "AlertDefinition/interval",
        "AlertDefinition/enabled",
        "AlertDefinition/scope",
 -      "AlertDefinition/source"
 -    ],      
 +      "AlertDefinition/source",
 +      "AlertDefinition/run_now"
 +    ],
 +    "AlertGroup": [
 +      "AlertGroup/id",
 +      "AlertGroup/name",
 +      "AlertGroup/cluster_name",
 +      "AlertGroup/default",
 +      "AlertGroup/definitions",
 +      "AlertGroup/targets"
 +    ],
 +    "AlertTarget": [
 +      "AlertTarget/id",
 +      "AlertTarget/name",
 +      "AlertTarget/description",      
 +      "AlertTarget/notification_type",
 +      "AlertTarget/properties",
 +      "AlertTarget/groups"
 +    ],
-     "Controller":[
-         "Controllers/name",
-         "LDAP/configured",
-         "LDAP/users",
-         "LDAP/groups",
-         "LDAP/synced_users",
-         "LDAP/synced_groups",
-         "_"
-     ],
      "ClientConfig":[
          "ServiceComponentInfo/service_name",
          "ServiceComponentInfo/component_name",


[23/50] [abbrv] git commit: AMBARI-7316 - Alerts: Create Alert Notices For Incoming Alert State Changes (jonathanhurley)

Posted by jo...@apache.org.
AMBARI-7316 - Alerts: Create Alert Notices For Incoming Alert State Changes (jonathanhurley)


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

Branch: refs/heads/trunk
Commit: 760bedfe32f2a673a14cc14e7f2d41794ca3db98
Parents: aaf0513
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Mon Sep 15 14:04:42 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Mon Sep 15 14:04:42 2014 -0400

----------------------------------------------------------------------
 .../ambari/server/agent/HeartBeatHandler.java   |  20 ++-
 .../server/controller/ControllerModule.java     |  15 ++
 .../apache/ambari/server/events/AlertEvent.java |  58 +++++++
 .../server/events/AlertReceivedEvent.java       |  50 +++++++
 .../server/events/AlertStateChangeEvent.java    |  85 +++++++++++
 .../events/listeners/AlertReceivedListener.java | 150 +++++++++++++++++++
 .../listeners/AlertStateChangedListener.java    |  98 ++++++++++++
 .../events/publishers/AlertEventPublisher.java  | 100 +++++++++++++
 .../ambari/server/orm/dao/AlertDispatchDAO.java |  22 +++
 .../server/orm/entities/AlertGroupEntity.java   |   7 +-
 .../org/apache/ambari/server/state/Alert.java   |  55 ++++---
 .../server/state/cluster/AlertDataManager.java  | 111 --------------
 .../server/orm/dao/AlertDispatchDAOTest.java    |  29 ++++
 .../state/cluster/AlertDataManagerTest.java     | 129 ++++++++++++----
 14 files changed, 753 insertions(+), 176 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/760bedfe/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
index 492d832..a366301 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
@@ -39,6 +39,9 @@ import org.apache.ambari.server.actionmanager.HostRoleStatus;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.MaintenanceStateHelper;
+import org.apache.ambari.server.events.AlertEvent;
+import org.apache.ambari.server.events.AlertReceivedEvent;
+import org.apache.ambari.server.events.publishers.AlertEventPublisher;
 import org.apache.ambari.server.metadata.ActionMetadata;
 import org.apache.ambari.server.state.AgentVersion;
 import org.apache.ambari.server.state.Alert;
@@ -60,7 +63,6 @@ import org.apache.ambari.server.state.StackInfo;
 import org.apache.ambari.server.state.State;
 import org.apache.ambari.server.state.alert.AlertDefinition;
 import org.apache.ambari.server.state.alert.AlertDefinitionHash;
-import org.apache.ambari.server.state.cluster.AlertDataManager;
 import org.apache.ambari.server.state.fsm.InvalidStateTransitionException;
 import org.apache.ambari.server.state.host.HostHealthyHeartbeatEvent;
 import org.apache.ambari.server.state.host.HostRegistrationRequestEvent;
@@ -115,9 +117,12 @@ public class HeartBeatHandler {
 
   @Inject
   private AlertDefinitionHash alertDefinitionHash;
-  
+
+  /**
+   * Publishes {@link AlertEvent} instances.
+   */
   @Inject
-  private AlertDataManager alertManager;
+  private AlertEventPublisher alertEventPublisher;
 
   private Map<String, Long> hostResponseIds = new ConcurrentHashMap<String, Long>();
 
@@ -236,13 +241,16 @@ public class HeartBeatHandler {
     if (null == hostname || null == heartbeat) {
       return;
     }
-    
+
     if (null != heartbeat.getAlerts()) {
       for (Alert alert : heartbeat.getAlerts()) {
-        if (null == alert.getHost())
+        if (null == alert.getHost()) {
           alert.setHost(hostname);
+        }
+
         Cluster cluster = clusterFsm.getCluster(alert.getCluster());
-        alertManager.add(cluster.getClusterId(), alert);
+        AlertEvent event = new AlertReceivedEvent(cluster.getClusterId(), alert);
+        alertEventPublisher.publish(event);
       }
     }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/760bedfe/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
index c395df6..8413762 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
@@ -51,6 +51,8 @@ import org.apache.ambari.server.controller.internal.HostResourceProvider;
 import org.apache.ambari.server.controller.internal.MemberResourceProvider;
 import org.apache.ambari.server.controller.internal.ServiceResourceProvider;
 import org.apache.ambari.server.controller.spi.ResourceProvider;
+import org.apache.ambari.server.events.listeners.AlertReceivedListener;
+import org.apache.ambari.server.events.listeners.AlertStateChangedListener;
 import org.apache.ambari.server.orm.DBAccessor;
 import org.apache.ambari.server.orm.DBAccessorImpl;
 import org.apache.ambari.server.orm.PersistenceType;
@@ -222,6 +224,8 @@ public class ControllerModule extends AbstractModule {
     bind(ViewInstanceHandlerList.class).to(AmbariHandlerList.class);
 
     requestStaticInjection(ExecutionCommandWrapper.class);
+
+    bindEagerSingletons();
   }
 
 
@@ -299,4 +303,15 @@ public class ControllerModule extends AbstractModule {
     bind(HostRoleCommandFactory.class).to(HostRoleCommandFactoryImpl.class);
     bind(SecurityHelper.class).toInstance(SecurityHelperImpl.getInstance());
   }
+
+  /**
+   * Initializes all eager singletons that should be instantiated as soon as
+   * possible and not wait for injection.
+   */
+  private void bindEagerSingletons() {
+    // alert subscribers are "headless" and have no guice references; created
+    // them as eager singletons to have them register with the eventbus
+    bind(AlertReceivedListener.class).asEagerSingleton();
+    bind(AlertStateChangedListener.class).asEagerSingleton();
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/760bedfe/ambari-server/src/main/java/org/apache/ambari/server/events/AlertEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/AlertEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/AlertEvent.java
new file mode 100644
index 0000000..a75477d
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/AlertEvent.java
@@ -0,0 +1,58 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.events;
+
+import org.apache.ambari.server.state.Alert;
+
+/**
+ * The {@link AlertEvent} class the base for all events related to alerts.
+ */
+public abstract class AlertEvent {
+
+  protected long m_clusterId;
+  protected Alert m_alert;
+
+  /**
+   * Constructor.
+   *
+   * @param clusterId
+   * @param alert
+   */
+  public AlertEvent(long clusterId, Alert alert) {
+    m_clusterId = clusterId;
+    m_alert = alert;
+  }
+
+  /**
+   * Gets the cluster ID that the alert belongs to.
+   *
+   * @return the ID of the cluster.
+   */
+  public long getClusterId() {
+    return m_clusterId;
+  }
+
+  /**
+   * Gets the alert that this event is created for.
+   *
+   * @return the alert (never {@code null}).
+   */
+  public Alert getAlert(){
+    return m_alert;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/760bedfe/ambari-server/src/main/java/org/apache/ambari/server/events/AlertReceivedEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/AlertReceivedEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/AlertReceivedEvent.java
new file mode 100644
index 0000000..558c9da
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/AlertReceivedEvent.java
@@ -0,0 +1,50 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.events;
+
+import org.apache.ambari.server.state.Alert;
+
+/**
+ * The {@link AlertReceivedEvent} is fired when an {@link Alert} is received or
+ * generated.
+ */
+public final class AlertReceivedEvent extends AlertEvent {
+
+  /**
+   * Constructor.
+   *
+   * @param clusterId
+   * @param alert
+   */
+  public AlertReceivedEvent(long clusterId, Alert alert) {
+    super(clusterId, alert);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString() {
+    StringBuilder buffer = new StringBuilder("AlertReceivedEvent{ ");
+    buffer.append("cluserId=").append(m_clusterId);
+    buffer.append(", alert=").append(m_alert);
+
+    buffer.append("}");
+    return buffer.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/760bedfe/ambari-server/src/main/java/org/apache/ambari/server/events/AlertStateChangeEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/AlertStateChangeEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/AlertStateChangeEvent.java
new file mode 100644
index 0000000..ab2c3dd
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/AlertStateChangeEvent.java
@@ -0,0 +1,85 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.events;
+
+import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
+import org.apache.ambari.server.state.Alert;
+import org.apache.ambari.server.state.AlertState;
+
+/**
+ * The {@link AlertStateChangeEvent} is fired when an {@link Alert} instance has
+ * its {@link AlertState} changed.
+ */
+public final class AlertStateChangeEvent extends AlertEvent {
+
+  /**
+   * The prior alert state.
+   */
+  private final AlertState m_fromState;
+
+  /**
+   * The newly created historical entry.
+   */
+  private final AlertHistoryEntity m_newEntity;
+
+  /**
+   * Constructor.
+   *
+   * @param clusterId
+   * @param alert
+   */
+  public AlertStateChangeEvent(long clusterId, Alert alert,
+      AlertHistoryEntity newEntity, AlertState fromState) {
+    super(clusterId, alert);
+
+    m_newEntity = newEntity;
+    m_fromState = fromState;
+  }
+
+  /**
+   * Gets the newly created item in alert history.
+   *
+   * @return the newly created historical item.
+   */
+  public AlertHistoryEntity getNewHistoricalEntry() {
+    return m_newEntity;
+  }
+
+  /**
+   * Gets the prior state of the alert.
+   *
+   * @return the prior state of the alert.
+   */
+  public AlertState getFromState() {
+    return m_fromState;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString() {
+    StringBuilder buffer = new StringBuilder("AlertStateChangeEvent{ ");
+    buffer.append("cluserId=").append(m_clusterId);
+    buffer.append(", fromState=").append(m_fromState);
+    buffer.append(", alert=").append(m_alert);
+
+    buffer.append("}");
+    return buffer.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/760bedfe/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java
new file mode 100644
index 0000000..1bdd7e2
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertReceivedListener.java
@@ -0,0 +1,150 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.events.listeners;
+
+import org.apache.ambari.server.events.AlertEvent;
+import org.apache.ambari.server.events.AlertReceivedEvent;
+import org.apache.ambari.server.events.AlertStateChangeEvent;
+import org.apache.ambari.server.events.publishers.AlertEventPublisher;
+import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
+import org.apache.ambari.server.orm.dao.AlertsDAO;
+import org.apache.ambari.server.orm.entities.AlertCurrentEntity;
+import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
+import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
+import org.apache.ambari.server.state.Alert;
+import org.apache.ambari.server.state.AlertState;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import com.google.common.eventbus.AllowConcurrentEvents;
+import com.google.common.eventbus.Subscribe;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+/**
+ * The {@link AlertReceivedListener} class handles {@link AlertReceivedEvent}
+ * and updates the appropirate DAOs. It may also fire new
+ * {@link AlertStateChangeEvent} when an {@link AlertState} change is detected.
+ */
+@Singleton
+public class AlertReceivedListener {
+  /**
+   * Logger.
+   */
+  private static Log LOG = LogFactory.getLog(AlertReceivedListener.class);
+
+  @Inject
+  private AlertsDAO m_alertsDao;
+
+  @Inject
+  private AlertDefinitionDAO m_definitionDao;
+
+  /**
+   * Receives and publishes {@link AlertEvent} instances.
+   */
+  private AlertEventPublisher m_alertEventPublisher;
+
+  /**
+   * Constructor.
+   *
+   * @param publisher
+   */
+  @Inject
+  public AlertReceivedListener(AlertEventPublisher publisher) {
+    m_alertEventPublisher = publisher;
+    m_alertEventPublisher.register(this);
+  }
+
+
+  /**
+   * Adds an alert.  Checks for a new state before creating a new history record.
+   *
+   * @param clusterId the id for the cluster
+   * @param alert the alert to add
+   */
+  @Subscribe
+  @AllowConcurrentEvents
+  public void onAlertEvent(AlertReceivedEvent event) {
+    long clusterId = event.getClusterId();
+    Alert alert = event.getAlert();
+
+    AlertCurrentEntity current = m_alertsDao.findCurrentByHostAndName(clusterId,
+        alert.getHost(), alert.getName());
+
+    if (null == current) {
+      AlertDefinitionEntity definition = m_definitionDao.findByName(clusterId,
+          alert.getName());
+
+      AlertHistoryEntity history = createHistory(clusterId, definition, alert);
+
+      current = new AlertCurrentEntity();
+      current.setAlertHistory(history);
+      current.setLatestTimestamp(Long.valueOf(alert.getTimestamp()));
+      current.setOriginalTimestamp(Long.valueOf(alert.getTimestamp()));
+
+      m_alertsDao.create(current);
+
+    } else if (alert.getState() == current.getAlertHistory().getAlertState()) {
+      current.setLatestTimestamp(Long.valueOf(alert.getTimestamp()));
+      current.setLatestText(alert.getText());
+
+      m_alertsDao.merge(current);
+    } else {
+      AlertState oldState = current.getAlertHistory().getAlertState();
+
+      // insert history, update current
+      AlertHistoryEntity history = createHistory(clusterId,
+          current.getAlertHistory().getAlertDefinition(), alert);
+
+      current.setAlertHistory(history);
+      current.setLatestTimestamp(Long.valueOf(alert.getTimestamp()));
+      current.setOriginalTimestamp(Long.valueOf(alert.getTimestamp()));
+
+      m_alertsDao.merge(current);
+
+      // broadcast the alert changed event for other subscribers
+      AlertStateChangeEvent alertChangedEvent = new AlertStateChangeEvent(
+          event.getClusterId(), event.getAlert(), history, oldState);
+
+      m_alertEventPublisher.publish(alertChangedEvent);
+    }
+  }
+
+  /**
+   * Convenience to create a new alert.
+   * @param clusterId the cluster id
+   * @param definition the definition
+   * @param alert the alert data
+   * @return the new history record
+   */
+  private AlertHistoryEntity createHistory(long clusterId, AlertDefinitionEntity definition, Alert alert) {
+    AlertHistoryEntity history = new AlertHistoryEntity();
+    history.setAlertDefinition(definition);
+    history.setAlertInstance(alert.getInstance());
+    history.setAlertLabel(alert.getLabel());
+    history.setAlertState(alert.getState());
+    history.setAlertText(alert.getText());
+    history.setAlertTimestamp(Long.valueOf(alert.getTimestamp()));
+    history.setClusterId(Long.valueOf(clusterId));
+    history.setComponentName(alert.getComponent());
+    history.setHostName(alert.getHost());
+    history.setServiceName(alert.getService());
+
+    return history;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/760bedfe/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertStateChangedListener.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertStateChangedListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertStateChangedListener.java
new file mode 100644
index 0000000..a327110
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/AlertStateChangedListener.java
@@ -0,0 +1,98 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.events.listeners;
+
+import java.util.List;
+import java.util.Set;
+
+import org.apache.ambari.server.events.AlertStateChangeEvent;
+import org.apache.ambari.server.events.publishers.AlertEventPublisher;
+import org.apache.ambari.server.orm.dao.AlertDispatchDAO;
+import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
+import org.apache.ambari.server.orm.entities.AlertGroupEntity;
+import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
+import org.apache.ambari.server.orm.entities.AlertNoticeEntity;
+import org.apache.ambari.server.orm.entities.AlertTargetEntity;
+import org.apache.ambari.server.state.NotificationState;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import com.google.common.eventbus.AllowConcurrentEvents;
+import com.google.common.eventbus.Subscribe;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+/**
+ * The {@link AlertStateChangedListener} class response to
+ * {@link AlertStateChangeEvent} and updates {@link AlertNoticeEntity} instances
+ * in the database.
+ */
+@Singleton
+public class AlertStateChangedListener {
+
+  /**
+   * Logger.
+   */
+  private static Log LOG = LogFactory.getLog(AlertStateChangedListener.class);
+
+  /**
+   * Used for looking up groups and targets.
+   */
+  @Inject
+  private AlertDispatchDAO m_alertsDispatchDao;
+
+  /**
+   * Constructor.
+   *
+   * @param publisher
+   */
+  @Inject
+  public AlertStateChangedListener(AlertEventPublisher publisher) {
+    publisher.register(this);
+  }
+
+  /**
+   * Listens for when an alert's state has changed.
+   */
+  @Subscribe
+  @AllowConcurrentEvents
+  public void onAlertEvent(AlertStateChangeEvent event) {
+    AlertHistoryEntity history = event.getNewHistoricalEntry();
+    AlertDefinitionEntity definition = history.getAlertDefinition();
+
+    List<AlertGroupEntity> groups = m_alertsDispatchDao.findGroupsByDefinition(definition);
+
+    // for each group, determine if there are any targets that need to receive
+    // a notification about the alert state change event
+    for (AlertGroupEntity group : groups) {
+      Set<AlertTargetEntity> targets = group.getAlertTargets();
+      if (null == targets || targets.size() == 0) {
+        continue;
+      }
+
+      for (AlertTargetEntity target : targets) {
+        AlertNoticeEntity notice = new AlertNoticeEntity();
+        notice.setAlertTarget(target);
+        notice.setAlertHistory(event.getNewHistoricalEntry());
+        notice.setNotifyState(NotificationState.PENDING);
+
+        m_alertsDispatchDao.merge(notice);
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/760bedfe/ambari-server/src/main/java/org/apache/ambari/server/events/publishers/AlertEventPublisher.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/publishers/AlertEventPublisher.java b/ambari-server/src/main/java/org/apache/ambari/server/events/publishers/AlertEventPublisher.java
new file mode 100644
index 0000000..e42e317
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/publishers/AlertEventPublisher.java
@@ -0,0 +1,100 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.events.publishers;
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.ambari.server.events.AlertEvent;
+
+import com.google.common.eventbus.AsyncEventBus;
+import com.google.common.eventbus.EventBus;
+import com.google.common.eventbus.Subscribe;
+import com.google.inject.Singleton;
+
+/**
+ * The {@link AlertEventPublisher} is used to wrap a customized instance of an
+ * {@link AsyncEventBus} that is only used for alerts. In general, Ambari should
+ * have its own application-wide event bus for application events (session
+ * information, state changes, etc), but since alerts can contain many events
+ * being published concurrently, it makes sense to encapsulate a specific alert
+ * bus in this publisher.
+ */
+@Singleton
+public final class AlertEventPublisher {
+
+  /**
+   * A multi-threaded event bus that can handle dispatching {@link AlertEvent}s.
+   */
+  private final EventBus s_eventBus;
+
+  /**
+   * Constructor.
+   */
+  public AlertEventPublisher() {
+    s_eventBus = new AsyncEventBus(Executors.newFixedThreadPool(2,
+        new AlertEventBusThreadFactory()));
+  }
+
+  /**
+   * Publishes the specified event to all registered listeners that
+   * {@link Subscribe} to any of the {@link AlertEvent} instances.
+   *
+   * @param event
+   */
+  public void publish(AlertEvent event) {
+    s_eventBus.post(event);
+  }
+
+  /**
+   * Register a listener to receive events. The listener should use the
+   * {@link Subscribe} annotation.
+   *
+   * @param object
+   *          the listener to receive events.
+   */
+  public void register(Object object) {
+    s_eventBus.register(object);
+  }
+
+  /**
+   * A custom {@link ThreadFactory} for the threads that will handle published
+   * {@link AlertEvent}. Threads created will have slightly reduced priority
+   * since {@link AlertEvent} instances are not critical to the system.
+   */
+  private static final class AlertEventBusThreadFactory implements
+      ThreadFactory {
+
+    private static final AtomicInteger s_threadIdPool = new AtomicInteger(1);
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Thread newThread(Runnable r) {
+      Thread thread = new Thread(r, "alert-event-bus-"
+          + s_threadIdPool.getAndIncrement());
+
+      thread.setDaemon(false);
+      thread.setPriority(Thread.NORM_PRIORITY - 1);
+
+      return thread;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/760bedfe/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDispatchDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDispatchDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDispatchDAO.java
index e08c948..6d4d19b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDispatchDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDispatchDAO.java
@@ -22,9 +22,11 @@ import java.util.List;
 import javax.persistence.EntityManager;
 import javax.persistence.TypedQuery;
 
+import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
 import org.apache.ambari.server.orm.entities.AlertGroupEntity;
 import org.apache.ambari.server.orm.entities.AlertNoticeEntity;
 import org.apache.ambari.server.orm.entities.AlertTargetEntity;
+import org.apache.ambari.server.state.alert.AlertGroup;
 
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -192,6 +194,26 @@ public class AlertDispatchDAO {
   }
 
   /**
+   * Gets all of the {@link AlertGroup} instances that include the specified
+   * alert definition.
+   *
+   * @param definitionEntity
+   *          the definition that the group must include (not {@code null}).
+   * @return all alert groups that have an association with the specified
+   *         definition or empty list if none exist (never {@code null}).
+   */
+  public List<AlertGroupEntity> findGroupsByDefinition(
+      AlertDefinitionEntity definitionEntity) {
+
+    TypedQuery<AlertGroupEntity> query = entityManagerProvider.get().createNamedQuery(
+        "AlertGroupEntity.findByAssociatedDefinition", AlertGroupEntity.class);
+
+    query.setParameter("alertDefinition", definitionEntity);
+
+    return daoUtils.selectList(query);
+  }
+
+  /**
    * Gets all alert notifications stored in the database.
    *
    * @return all alert notifications or empty list if none exist (never

http://git-wip-us.apache.org/repos/asf/ambari/blob/760bedfe/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertGroupEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertGroupEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertGroupEntity.java
index f97a0eb..e7fa9c6 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertGroupEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertGroupEntity.java
@@ -48,7 +48,8 @@ import javax.persistence.UniqueConstraint;
     @NamedQuery(name = "AlertGroupEntity.findAll", query = "SELECT alertGroup FROM AlertGroupEntity alertGroup"),
     @NamedQuery(name = "AlertGroupEntity.findAllInCluster", query = "SELECT alertGroup FROM AlertGroupEntity alertGroup WHERE alertGroup.clusterId = :clusterId"),
     @NamedQuery(name = "AlertGroupEntity.findByName", query = "SELECT alertGroup FROM AlertGroupEntity alertGroup WHERE alertGroup.groupName = :groupName"),
-    @NamedQuery(name = "AlertGroupEntity.findByNameInCluster", query = "SELECT alertGroup FROM AlertGroupEntity alertGroup WHERE alertGroup.groupName = :groupName AND alertGroup.clusterId = :clusterId"), })
+    @NamedQuery(name = "AlertGroupEntity.findByNameInCluster", query = "SELECT alertGroup FROM AlertGroupEntity alertGroup WHERE alertGroup.groupName = :groupName AND alertGroup.clusterId = :clusterId"),
+    @NamedQuery(name = "AlertGroupEntity.findByAssociatedDefinition", query = "SELECT alertGroup FROM AlertGroupEntity alertGroup WHERE :alertDefinition MEMBER OF alertGroup.alertDefinitions"), })
 public class AlertGroupEntity {
 
   @Id
@@ -224,7 +225,7 @@ public class AlertGroupEntity {
   /**
    * Adds the specified definition to the definitions that this group will
    * dispatch to.
-   * 
+   *
    * @param definition
    *          the definition to add (not {@code null}).
    */
@@ -240,7 +241,7 @@ public class AlertGroupEntity {
   /**
    * Removes the specified definition from the definitions that this group will
    * dispatch to.
-   * 
+   *
    * @param definition
    *          the definition to remove (not {@code null}).
    */

http://git-wip-us.apache.org/repos/asf/ambari/blob/760bedfe/ambari-server/src/main/java/org/apache/ambari/server/state/Alert.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/Alert.java b/ambari-server/src/main/java/org/apache/ambari/server/state/Alert.java
index 7b8aabd..3675f87 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/Alert.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/Alert.java
@@ -32,8 +32,8 @@ public class Alert {
   private String label = null;
   private String text = null;
   private long timestamp = 0L;
-  
- 
+
+
   /**
    * Constructor.
    * @param alertName the name of the alert
@@ -56,32 +56,32 @@ public class Alert {
 
   public Alert() {
   }
- 
+
   /**
    * @return the name
    */
 
-  @JsonProperty("name")     
+  @JsonProperty("name")
   public String getName() {
     return name;
   }
- 
+
   /**
    * @return the service
    */
-  @JsonProperty("service")    
+  @JsonProperty("service")
   public String getService() {
     return service;
   }
-  
+
   /**
    * @return the component
    */
-  @JsonProperty("component")  
+  @JsonProperty("component")
   public String getComponent() {
     return component;
   }
- 
+
   /**
    * @return the host
    */
@@ -89,7 +89,7 @@ public class Alert {
   public String getHost() {
     return host;
   }
- 
+
   /**
    * @return the state
    */
@@ -101,7 +101,7 @@ public class Alert {
   /**
    * @return a short descriptive label for the alert
    */
-  @JsonProperty("label")  
+  @JsonProperty("label")
   public String getLabel() {
     return label;
   }
@@ -109,32 +109,32 @@ public class Alert {
   /**
    * @param alertLabel a short descriptive label for the alert
    */
-  @JsonProperty("label")   
+  @JsonProperty("label")
   public void setLabel(String alertLabel) {
     label = alertLabel;
   }
- 
+
   /**
    * @return detail text about the alert
    */
-  @JsonProperty("text")   
+  @JsonProperty("text")
   public String getText() {
     return text;
   }
-  
+
   /**
    * @param alertText detail text about the alert
    */
-  @JsonProperty("text")   
+  @JsonProperty("text")
   public void setText(String alertText) {
     text = alertText;
   }
 
-  @JsonProperty("instance")  
+  @JsonProperty("instance")
   public String getInstance() {
     return instance;
   }
-  
+
   @JsonProperty("instance")
   public void setInstance(String instance) {
     this.instance = instance;
@@ -164,24 +164,24 @@ public class Alert {
   public void setState(AlertState state) {
     this.state = state;
   }
-  
+
   @JsonProperty("timestamp")
   public void setTimestamp(long ts) {
     timestamp = ts;
   }
-  
+
   @JsonProperty("timestamp")
   public long getTimestamp() {
     return timestamp;
   }
-  
+
   /**
    * @return
    */
   public String getCluster() {
     return cluster;
   }
-  
+
   @Override
   public int hashCode() {
     int result = alertHashCode();
@@ -197,8 +197,9 @@ public class Alert {
    */
   @Override
   public boolean equals(Object o) {
-    if (null == o || !Alert.class.isInstance(o))
+    if (null == o || !Alert.class.isInstance(o)) {
       return false;
+    }
 
     return hashCode() == o.hashCode();
   }
@@ -217,7 +218,7 @@ public class Alert {
 
   /**
    * Checks equality with another alert, not taking into account instance info
-   * 
+   *
    * @param that
    *          the other alert to compare against
    * @return <code>true</code> when the alert is equal in every way except the
@@ -226,8 +227,7 @@ public class Alert {
   public boolean almostEquals(Alert that) {
     return alertHashCode() == that.alertHashCode();
   }
-  
-  
+
   @Override
   public String toString() {
     StringBuilder sb = new StringBuilder();
@@ -242,7 +242,4 @@ public class Alert {
     sb.append('}');
     return sb.toString();
   }
-
-  
-
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/760bedfe/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/AlertDataManager.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/AlertDataManager.java b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/AlertDataManager.java
deleted file mode 100644
index 4a65d5a..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/AlertDataManager.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.server.state.cluster;
-
-import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
-import org.apache.ambari.server.orm.dao.AlertsDAO;
-import org.apache.ambari.server.orm.entities.AlertCurrentEntity;
-import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
-import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
-import org.apache.ambari.server.state.Alert;
-
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-
-/**
- * The AlertManager is reponsible for tracking all alerts generated for a cluster. 
- */
-@Singleton
-public class AlertDataManager {
-
-  @Inject
-  private AlertsDAO m_alertsDao;
-  @Inject
-  private AlertDefinitionDAO m_definitionDao;
-
-  
-  AlertDataManager() {
-  }
-  
-  /**
-   * Adds an alert.  Checks for a new state before creating a new history record.
-   * 
-   * @param clusterId the id for the cluster
-   * @param alert the alert to add
-   */
-  public void add(long clusterId, Alert alert) {
-    
-    AlertCurrentEntity current = m_alertsDao.findCurrentByHostAndName(clusterId,
-        alert.getHost(), alert.getName());
-    
-    if (null == current) {
-      AlertDefinitionEntity definition = m_definitionDao.findByName(clusterId,
-          alert.getName());
-      
-      AlertHistoryEntity history = createHistory(clusterId, definition, alert);
-      
-      current = new AlertCurrentEntity();
-      current.setAlertHistory(history);
-      current.setLatestTimestamp(Long.valueOf(alert.getTimestamp()));
-      current.setOriginalTimestamp(Long.valueOf(alert.getTimestamp()));
-      
-      m_alertsDao.create(current);
-      
-    } else if (alert.getState() == current.getAlertHistory().getAlertState()) {
-      current.setLatestTimestamp(Long.valueOf(alert.getTimestamp()));
-      current.setLatestText(alert.getText());
-      
-      m_alertsDao.merge(current);
-    } else {
-      // insert history, update current
-      AlertHistoryEntity history = createHistory(clusterId,
-          current.getAlertHistory().getAlertDefinition(), alert);
-      
-      current.setAlertHistory(history);
-      current.setLatestTimestamp(Long.valueOf(alert.getTimestamp()));
-      current.setOriginalTimestamp(Long.valueOf(alert.getTimestamp()));
-      
-      m_alertsDao.merge(current);
-    }
-    
-  }
-  /**
-   * Convenience to create a new alert.
-   * @param clusterId the cluster id
-   * @param definition the definition
-   * @param alert the alert data
-   * @return the new history record
-   */
-  private AlertHistoryEntity createHistory(long clusterId, AlertDefinitionEntity definition, Alert alert) {
-    AlertHistoryEntity history = new AlertHistoryEntity();
-    history.setAlertDefinition(definition);
-    history.setAlertInstance(alert.getInstance());
-    history.setAlertLabel(alert.getLabel());
-    history.setAlertState(alert.getState());
-    history.setAlertText(alert.getText());
-    history.setAlertTimestamp(Long.valueOf(alert.getTimestamp()));
-    history.setClusterId(Long.valueOf(clusterId));
-    history.setComponentName(alert.getComponent());
-    history.setHostName(alert.getHost());
-    history.setServiceName(alert.getService());
-    
-    return history;
-  }
-  
-
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/760bedfe/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDispatchDAOTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDispatchDAOTest.java b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDispatchDAOTest.java
index 8451c9b..1103961 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDispatchDAOTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDispatchDAOTest.java
@@ -351,6 +351,35 @@ public class AlertDispatchDAOTest {
   }
 
   /**
+   * Tests finding groups by a definition ID that they are associatd with.
+   * 
+   * @throws Exception
+   */
+  @Test
+  public void testFindGroupsByDefinition() throws Exception {
+    List<AlertDefinitionEntity> definitions = createDefinitions();
+    AlertGroupEntity group = helper.createAlertGroup(clusterId, null);
+
+    group = dao.findGroupById(group.getGroupId());
+    assertNotNull(group);
+
+    for (AlertDefinitionEntity definition : definitions) {
+      group.addAlertDefinition(definition);
+    }
+
+    dao.merge(group);
+
+    group = dao.findGroupByName(group.getGroupName());
+    assertEquals(definitions.size(), group.getAlertDefinitions().size());
+
+    for (AlertDefinitionEntity definition : definitions) {
+      List<AlertGroupEntity> groups = dao.findGroupsByDefinition(definition);
+      assertEquals(1, groups.size());
+      assertEquals(group.getGroupId(), groups.get(0).getGroupId());
+    }
+  }
+
+  /**
    * @return
    */
   private List<AlertDefinitionEntity> createDefinitions() throws Exception {

http://git-wip-us.apache.org/repos/asf/ambari/blob/760bedfe/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java
index eae1de6..bbf7774 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/AlertDataManagerTest.java
@@ -21,17 +21,28 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 import java.util.UUID;
 
+import org.apache.ambari.server.events.AlertEvent;
+import org.apache.ambari.server.events.AlertReceivedEvent;
+import org.apache.ambari.server.events.AlertStateChangeEvent;
+import org.apache.ambari.server.events.listeners.AlertReceivedListener;
+import org.apache.ambari.server.events.listeners.AlertStateChangedListener;
 import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
 import org.apache.ambari.server.orm.OrmTestHelper;
 import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
+import org.apache.ambari.server.orm.dao.AlertDispatchDAO;
 import org.apache.ambari.server.orm.dao.AlertsDAO;
 import org.apache.ambari.server.orm.entities.AlertCurrentEntity;
 import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
+import org.apache.ambari.server.orm.entities.AlertGroupEntity;
 import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
+import org.apache.ambari.server.orm.entities.AlertNoticeEntity;
+import org.apache.ambari.server.orm.entities.AlertTargetEntity;
 import org.apache.ambari.server.state.Alert;
 import org.apache.ambari.server.state.AlertState;
 import org.apache.ambari.server.state.alert.Scope;
@@ -44,22 +55,24 @@ import com.google.inject.Injector;
 import com.google.inject.persist.PersistService;
 
 /**
- * Tests the alert manager.
+ * Tests the management of {@link AlertEvent}s in the system.
  */
 public class AlertDataManagerTest {
-  
+
   private static final String ALERT_DEFINITION = "Alert Definition 1";
   private static final String SERVICE = "service1";
   private static final String COMPONENT = "component1";
   private static final String HOST1 = "h1";
   private static final String HOST2 = "h2";
   private static final String ALERT_LABEL = "My Label";
-  
+
   private Long clusterId;
   private Injector injector;
   private OrmTestHelper helper;
   private AlertsDAO dao;
-  
+  private AlertDispatchDAO dispatchDao;
+  private AlertDefinitionDAO definitionDao;
+
   @Before
   public void setup() throws Exception {
     injector = Guice.createInjector(new InMemoryDefaultTestModule());
@@ -67,7 +80,8 @@ public class AlertDataManagerTest {
     helper = injector.getInstance(OrmTestHelper.class);
     clusterId = helper.createCluster();
     dao = injector.getInstance(AlertsDAO.class);
-    AlertDefinitionDAO definitionDao = injector.getInstance(AlertDefinitionDAO.class);
+    dispatchDao = injector.getInstance(AlertDispatchDAO.class);
+    definitionDao = injector.getInstance(AlertDefinitionDAO.class);
 
     // create 5 definitions
     for (int i = 0; i < 5; i++) {
@@ -83,18 +97,16 @@ public class AlertDataManagerTest {
       definition.setSourceType("SCRIPT");
       definitionDao.create(definition);
     }
-  
   }
-  
+
   @After
   public void teardown() {
     injector.getInstance(PersistService.class).stop();
     injector = null;
   }
-  
+
   @Test
   public void testAlertRecords() {
-    
     Alert alert1 = new Alert(ALERT_DEFINITION, null, SERVICE, COMPONENT, HOST1, AlertState.OK);
     alert1.setLabel(ALERT_LABEL);
     alert1.setText("Component component1 is OK");
@@ -103,18 +115,24 @@ public class AlertDataManagerTest {
     Alert alert2 = new Alert(ALERT_DEFINITION, null, SERVICE, COMPONENT, HOST2, AlertState.CRITICAL);
     alert2.setLabel(ALERT_LABEL);
     alert2.setText("Component component2 is not OK");
-    
-    AlertDataManager am = injector.getInstance(AlertDataManager.class);
-    
-    am.add(clusterId.longValue(), alert1);
-    am.add(clusterId.longValue(), alert2);
-    
+
+    AlertReceivedListener listener = injector.getInstance(AlertReceivedListener.class);
+
+    AlertReceivedEvent event1 = new AlertReceivedEvent(clusterId.longValue(),
+        alert1);
+
+    AlertReceivedEvent event2 = new AlertReceivedEvent(clusterId.longValue(),
+        alert2);
+
+    listener.onAlertEvent(event1);
+    listener.onAlertEvent(event2);
+
     List<AlertCurrentEntity> allCurrent = dao.findCurrentByService(clusterId.longValue(), SERVICE);
     assertEquals(2, allCurrent.size());
-    
+
     List<AlertHistoryEntity> allHistory = dao.findAll(clusterId.longValue());
     assertEquals(2, allHistory.size());
-    
+
     AlertCurrentEntity current = dao.findCurrentByHostAndName(clusterId.longValue(), HOST1, ALERT_DEFINITION);
     assertNotNull(current);
     assertEquals(HOST1, current.getAlertHistory().getHostName());
@@ -124,17 +142,21 @@ public class AlertDataManagerTest {
     assertEquals(current.getAlertHistory().getAlertState(), AlertState.OK);
     assertEquals(1L, current.getOriginalTimestamp().longValue());
     assertEquals(1L, current.getLatestTimestamp().longValue());
-    
+
     Long currentId = current.getAlertId();
     Long historyId = current.getAlertHistory().getAlertId();
-    
+
     // no new history since the state is the same
     Alert alert3 = new Alert(ALERT_DEFINITION, null, SERVICE, COMPONENT, HOST1, AlertState.OK);
     alert3.setLabel(ALERT_LABEL);
     alert3.setText("Component component1 is OK");
     alert3.setTimestamp(2L);
-    am.add(clusterId.longValue(), alert3);
-    
+
+    AlertReceivedEvent event3 = new AlertReceivedEvent(clusterId.longValue(),
+        alert3);
+
+    listener.onAlertEvent(event3);
+
     current = dao.findCurrentByHostAndName(clusterId.longValue(), HOST1, ALERT_DEFINITION);
     assertNotNull(current);
     assertEquals(currentId, current.getAlertId());
@@ -146,24 +168,28 @@ public class AlertDataManagerTest {
     assertEquals(current.getAlertHistory().getAlertState(), AlertState.OK);
     assertEquals(1L, current.getOriginalTimestamp().longValue());
     assertEquals(2L, current.getLatestTimestamp().longValue());
-   
+
     allCurrent = dao.findCurrentByService(clusterId.longValue(), SERVICE);
     assertEquals(2, allCurrent.size());
-    
+
     allHistory = dao.findAll(clusterId.longValue());
     assertEquals(2, allHistory.size());
-    
+
     // change to warning
     Alert alert4 = new Alert(ALERT_DEFINITION, null, SERVICE, COMPONENT, HOST1, AlertState.WARNING);
     alert4.setLabel(ALERT_LABEL);
     alert4.setText("Component component1 is about to go down");
     alert4.setTimestamp(3L);
-    am.add(clusterId.longValue(), alert4);
+
+    AlertReceivedEvent event4 = new AlertReceivedEvent(clusterId.longValue(),
+        alert4);
+
+    listener.onAlertEvent(event4);
 
     current = dao.findCurrentByHostAndName(clusterId.longValue(), HOST1, ALERT_DEFINITION);
     assertNotNull(current);
     assertEquals(current.getAlertId(), currentId);
-    assertFalse(historyId.equals(current.getAlertHistory().getAlertId()));    
+    assertFalse(historyId.equals(current.getAlertHistory().getAlertId()));
     assertEquals(HOST1, current.getAlertHistory().getHostName());
     assertEquals(ALERT_DEFINITION, current.getAlertHistory().getAlertDefinition().getDefinitionName());
     assertEquals(ALERT_LABEL, current.getAlertHistory().getAlertLabel());
@@ -174,8 +200,57 @@ public class AlertDataManagerTest {
 
     allCurrent = dao.findCurrentByService(clusterId.longValue(), SERVICE);
     assertEquals(2, allCurrent.size());
-    
+
     allHistory = dao.findAll(clusterId.longValue());
     assertEquals(3, allHistory.size());
   }
+
+  /**
+   * Tests that {@link AlertStateChangeEvent} cause an {@link AlertNoticeEntity}
+   * entry.
+   *
+   * @throws Exception
+   */
+  @Test
+  public void testAlertNotices() throws Exception {
+    List<AlertNoticeEntity> notices = dispatchDao.findAllNotices();
+    assertEquals( 0, notices.size() );
+
+    List<AlertDefinitionEntity> definitions = definitionDao.findAll(clusterId);
+    AlertDefinitionEntity definition = definitions.get(0);
+
+    AlertHistoryEntity history = new AlertHistoryEntity();
+    history.setServiceName(definition.getServiceName());
+    history.setClusterId(clusterId);
+    history.setAlertDefinition(definition);
+    history.setAlertLabel(definition.getDefinitionName());
+    history.setAlertText(definition.getDefinitionName());
+    history.setAlertTimestamp(System.currentTimeMillis());
+    history.setHostName(HOST1);
+    history.setAlertState(AlertState.OK);
+    dao.create(history);
+
+    List<AlertHistoryEntity> histories = dao.findAll(clusterId);
+    assertEquals(1, histories.size());
+
+    AlertTargetEntity target = helper.createAlertTarget();
+    Set<AlertTargetEntity> targets = new HashSet<AlertTargetEntity>();
+    targets.add(target);
+
+    AlertGroupEntity group = helper.createAlertGroup(clusterId, targets);
+    group.addAlertDefinition( definitions.get(0) );
+    dispatchDao.merge(group);
+
+    Alert alert1 = new Alert(ALERT_DEFINITION, null, SERVICE, COMPONENT, HOST1,
+        AlertState.OK);
+
+    AlertStateChangeEvent event = new AlertStateChangeEvent(clusterId, alert1,
+        histories.get(0), AlertState.CRITICAL);
+
+    AlertStateChangedListener listener = injector.getInstance(AlertStateChangedListener.class);
+    listener.onAlertEvent(event);
+
+    notices = dispatchDao.findAllNotices();
+    assertEquals(1, notices.size());
+  }
 }