AMBARI-8460 - Alerts: AlertDefinition and AlertGroup Automatic Creation On Startup (jonathanhurley)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/9159421b Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/9159421b Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/9159421b Branch: refs/heads/trunk Commit: 9159421b39c4ef677a0bdc9445afe2ca2bd545ee Parents: 378cf13 Author: Jonathan Hurley <[email protected]> Authored: Wed Nov 26 15:32:04 2014 -0500 Committer: Jonathan Hurley <[email protected]> Committed: Fri Nov 28 08:04:39 2014 -0500 ---------------------------------------------------------------------- .../ambari/server/events/AmbariEvent.java | 5 + .../ambari/server/events/HostAddedEvent.java | 51 ++++ .../server/events/HostRegisteredEvent.java | 44 +++ .../ambari/server/events/HostRemovedEvent.java | 2 +- .../alerts/AlertHashInvalidationListener.java | 3 +- .../listeners/alerts/AlertHostListener.java | 119 +++++++- .../alerts/AlertServiceStateListener.java | 12 +- .../server/orm/dao/AlertDefinitionDAO.java | 31 ++- .../ambari/server/orm/dao/AlertDispatchDAO.java | 77 +++++- .../apache/ambari/server/orm/dao/AlertsDAO.java | 3 +- .../server/orm/dao/ClusterServiceDAO.java | 21 +- .../dao/ServiceComponentDesiredStateDAO.java | 21 +- .../orm/entities/AlertDefinitionEntity.java | 18 ++ .../server/orm/entities/AlertGroupEntity.java | 17 +- .../server/orm/entities/AlertHistoryEntity.java | 17 ++ .../server/orm/entities/AlertTargetEntity.java | 13 + .../server/state/alert/AlertDefinitionHash.java | 66 +++-- .../server/state/cluster/ClustersImpl.java | 15 +- .../apache/ambari/server/orm/OrmTestHelper.java | 146 +++++++++- .../server/orm/dao/AlertDispatchDAOTest.java | 276 ++++++++++++------- .../ambari/server/orm/dao/AlertsDAOTest.java | 259 +++++++---------- .../state/alerts/AlertReceivedListenerTest.java | 194 ++++++------- .../state/cluster/AlertDataManagerTest.java | 185 ++++++++----- 23 files changed, 1043 insertions(+), 552 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/9159421b/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 de9b6dc..e708473 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 @@ -68,6 +68,11 @@ public abstract class AmbariEvent { ALERT_DEFINITION_DISABLED, /** + * A host was registered with the server. + */ + HOST_REGISTERED, + + /** * A host was added to the cluster. */ HOST_ADDED, http://git-wip-us.apache.org/repos/asf/ambari/blob/9159421b/ambari-server/src/main/java/org/apache/ambari/server/events/HostAddedEvent.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/HostAddedEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/HostAddedEvent.java new file mode 100644 index 0000000..7832c16 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/events/HostAddedEvent.java @@ -0,0 +1,51 @@ +/** + * 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 HostAddedEvent} is fired when a host is added to a cluster. + */ +public class HostAddedEvent extends ClusterEvent { + + /** + * The host's name. + */ + protected final String m_hostName; + + /** + * Constructor. + * + * @param clusterId + * the ID of the cluster. + * @param hostName + * the name of the host. + */ + public HostAddedEvent(long clusterId, String hostName) { + super(AmbariEventType.HOST_ADDED, clusterId); + m_hostName = hostName; + } + + /** + * Gets the host's name that the event belongs to. + * + * @return the hostName + */ + public String getHostName() { + return m_hostName; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/9159421b/ambari-server/src/main/java/org/apache/ambari/server/events/HostRegisteredEvent.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/HostRegisteredEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/HostRegisteredEvent.java new file mode 100644 index 0000000..07ff526 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/events/HostRegisteredEvent.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.events; + +/** + * The {@link HostRegisteredEvent} class is fired when a host registered with + * the server. + */ +public class HostRegisteredEvent extends HostEvent { + /** + * Constructor. + * + * @param hostName + */ + public HostRegisteredEvent(String hostName) { + super(AmbariEventType.HOST_REGISTERED, hostName); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + StringBuilder buffer = new StringBuilder("HostRegistered{ "); + buffer.append("hostName=").append(m_hostName); + buffer.append("}"); + return buffer.toString(); + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/9159421b/ambari-server/src/main/java/org/apache/ambari/server/events/HostRemovedEvent.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/HostRemovedEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/HostRemovedEvent.java index a0aae66..e005754 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/events/HostRemovedEvent.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/events/HostRemovedEvent.java @@ -28,7 +28,7 @@ public class HostRemovedEvent extends HostEvent { * @param hostName */ public HostRemovedEvent(String hostName) { - super(AmbariEventType.HOST_ADDED, hostName); + super(AmbariEventType.HOST_REMOVED, hostName); } /** http://git-wip-us.apache.org/repos/asf/ambari/blob/9159421b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertHashInvalidationListener.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertHashInvalidationListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertHashInvalidationListener.java index 0accaf9..655352f 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertHashInvalidationListener.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertHashInvalidationListener.java @@ -91,7 +91,8 @@ public class AlertHashInvalidationListener { return; } - m_alertDefinitionHash.get().enqueueAgentCommands(clusterId, hosts); + AlertDefinitionHash hash = m_alertDefinitionHash.get(); + hash.enqueueAgentCommands(clusterId, hosts); } /** http://git-wip-us.apache.org/repos/asf/ambari/blob/9159421b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertHostListener.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertHostListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertHostListener.java index 51e5e67..d478bf5 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertHostListener.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertHostListener.java @@ -17,13 +17,26 @@ */ package org.apache.ambari.server.events.listeners.alerts; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.EagerSingleton; +import org.apache.ambari.server.events.AlertHashInvalidationEvent; +import org.apache.ambari.server.events.HostAddedEvent; import org.apache.ambari.server.events.HostRemovedEvent; import org.apache.ambari.server.events.publishers.AmbariEventPublisher; +import org.apache.ambari.server.metadata.AgentAlertDefinitions; +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.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.apache.ambari.server.orm.entities.AlertDefinitionEntity; +import org.apache.ambari.server.state.alert.AlertDefinition; +import org.apache.ambari.server.state.alert.AlertDefinitionFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.common.eventbus.AllowConcurrentEvents; import com.google.common.eventbus.Subscribe; @@ -31,8 +44,9 @@ import com.google.inject.Inject; import com.google.inject.Singleton; /** - * The {@link AlertHostListener} class handles {@link HostRemovedEvent} and - * ensures that {@link AlertCurrentEntity} instances are properly cleaned up + * The {@link AlertHostListener} class handles {@link HostAddedEvent} and + * {@link HostRemovedEvent} and ensures that {@link AlertCurrentEntity} + * instances are properly cleaned up */ @Singleton @EagerSingleton @@ -40,7 +54,7 @@ public class AlertHostListener { /** * Logger. */ - private static Log LOG = LogFactory.getLog(AlertHostListener.class); + private final static Logger LOG = LoggerFactory.getLogger(AlertHostListener.class); /** * Used for removing current alerts when a service is removed. @@ -49,6 +63,37 @@ public class AlertHostListener { private AlertsDAO m_alertsDao; /** + * Used for checking to see if definitions already exist for a cluster. + */ + @Inject + private AlertDefinitionDAO m_alertDefinitionDao; + + /** + * Used to publish events when an alert definition has a lifecycle event. + */ + @Inject + private AmbariEventPublisher m_eventPublisher; + + /** + * All of the {@link AlertDefinition}s that are scoped for the agents. + */ + @Inject + private AgentAlertDefinitions m_agentAlertDefinitions; + + /** + * Used when a host is added to a cluster to coerce an {@link AlertDefinition} + * into an {@link AlertDefinitionEntity}. + */ + @Inject + private AlertDefinitionFactory m_alertDefinitionFactory; + + /** + * Used to prevent multiple threads from trying to create host alerts + * simultaneously. + */ + private Lock m_hostAlertLock = new ReentrantLock(); + + /** * Constructor. * * @param publisher @@ -59,15 +104,69 @@ public class AlertHostListener { } /** - * Removes any current alerts associated with the specified host. - * - * @param event - * the published event being handled (not {@code null}). + * Handles the {@link HostAddedEvent} by performing the following actions: + * <ul> + * <li>Ensures that all host-level alerts are loaded for the cluster. This is + * especially useful when creating a cluster and no alerts were loaded on + * Ambari startup</li> + * <li>Broadcasts the {@link AlertHashInvalidationEvent} in order to push host + * alert definitions</li> + * </ul> + */ + @Subscribe + @AllowConcurrentEvents + public void onAmbariEvent(HostAddedEvent event) { + LOG.debug("Received event {}", event); + + long clusterId = event.getClusterId(); + + // load the host-only alert definitions + List<AlertDefinition> agentDefinitions = m_agentAlertDefinitions.getDefinitions(); + + // lock to prevent multiple threads from trying to create alert + // definitions at the same time + m_hostAlertLock.lock(); + + try { + for (AlertDefinition agentDefinition : agentDefinitions) { + AlertDefinitionEntity definition = m_alertDefinitionDao.findByName( + clusterId, agentDefinition.getName()); + + // this host definition does not exist, add it + if (null == definition) { + definition = m_alertDefinitionFactory.coerce(clusterId, + agentDefinition); + + try { + m_alertDefinitionDao.create(definition); + } catch (AmbariException ambariException) { + LOG.error( + "Unable to create a host alert definition name {} in cluster {}", + definition.getDefinitionName(), definition.getClusterId(), + ambariException); + } + } + } + } finally { + m_hostAlertLock.unlock(); + } + + AlertHashInvalidationEvent invalidationEvent = new AlertHashInvalidationEvent( + event.getClusterId(), Collections.singletonList(event.getHostName())); + + m_eventPublisher.publish(invalidationEvent); + } + + /** + * Handles the {@link HostRemovedEvent} by performing the following actions: + * <ul> + * <li>Removes all {@link AlertCurrentEntity} for the removed host</li> + * </ul> */ @Subscribe @AllowConcurrentEvents public void onAmbariEvent(HostRemovedEvent event) { - LOG.debug(event); + LOG.debug("Received event {}", event); // remove any current alerts for the removed host m_alertsDao.removeCurrentByHost(event.getHostName()); http://git-wip-us.apache.org/repos/asf/ambari/blob/9159421b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertServiceStateListener.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertServiceStateListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertServiceStateListener.java index b56f23d..fd7035d 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertServiceStateListener.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertServiceStateListener.java @@ -126,13 +126,11 @@ public class AlertServiceStateListener { // 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); + try { + m_alertDispatchDao.createDefaultGroup(clusterId, serviceName); + } catch (AmbariException ambariException) { + LOG.error(ambariException); + } // populate alert definitions for the new service from the database, but // don't worry about sending down commands to the agents; the host http://git-wip-us.apache.org/repos/asf/ambari/blob/9159421b/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 8e8c808..23de17e 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 @@ -24,6 +24,7 @@ import java.util.Set; import javax.persistence.EntityManager; import javax.persistence.TypedQuery; +import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.controller.RootServiceResponseFactory; import org.apache.ambari.server.events.AlertDefinitionDeleteEvent; import org.apache.ambari.server.events.AlertDefinitionRegistrationEvent; @@ -56,25 +57,25 @@ public class AlertDefinitionDAO { * JPA entity manager */ @Inject - Provider<EntityManager> entityManagerProvider; + private Provider<EntityManager> entityManagerProvider; /** * DAO utilities for dealing mostly with {@link TypedQuery} results. */ @Inject - DaoUtils daoUtils; + private DaoUtils daoUtils; /** * Alert history DAO. */ @Inject - AlertsDAO alertsDao; + private AlertsDAO alertsDao; /** * Alert dispatch DAO. */ @Inject - AlertDispatchDAO dispatchDao; + private AlertDispatchDAO dispatchDao; /** * Publishes the following events: @@ -284,16 +285,25 @@ public class AlertDefinitionDAO { * the definition to persist (not {@code null}). */ @Transactional - public void create(AlertDefinitionEntity alertDefinition) { + public void create(AlertDefinitionEntity alertDefinition) + throws AmbariException { entityManagerProvider.get().persist(alertDefinition); - AlertGroupEntity group = dispatchDao.findDefaultServiceGroup(alertDefinition.getServiceName()); + AlertGroupEntity group = dispatchDao.findDefaultServiceGroup( + alertDefinition.getClusterId(), alertDefinition.getServiceName()); - if (null != group) { - group.addAlertDefinition(alertDefinition); - dispatchDao.merge(group); + if (null == group) { + // 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 + String serviceName = alertDefinition.getServiceName(); + group = dispatchDao.createDefaultGroup(alertDefinition.getClusterId(), + serviceName); } + group.addAlertDefinition(alertDefinition); + dispatchDao.merge(group); + // publish the alert definition registration AlertDefinition coerced = alertDefinitionFactory.coerce(alertDefinition); if (null != coerced) { @@ -339,7 +349,8 @@ public class AlertDefinitionDAO { * @param alertDefinition * the definition to create or update (not {@code null}). */ - public void createOrUpdate(AlertDefinitionEntity alertDefinition) { + public void createOrUpdate(AlertDefinitionEntity alertDefinition) + throws AmbariException { if (null == alertDefinition.getDefinitionId()) { create(alertDefinition); } else { http://git-wip-us.apache.org/repos/asf/ambari/blob/9159421b/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 b6c1e90..3a3ad15 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 @@ -17,7 +17,11 @@ */ package org.apache.ambari.server.orm.dao; +import java.text.MessageFormat; import java.util.List; +import java.util.Map; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import javax.persistence.EntityManager; import javax.persistence.TypedQuery; @@ -25,9 +29,11 @@ import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Order; import javax.persistence.metamodel.SingularAttribute; +import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.api.query.JpaPredicateVisitor; import org.apache.ambari.server.api.query.JpaSortBuilder; import org.apache.ambari.server.controller.AlertNoticeRequest; +import org.apache.ambari.server.controller.RootServiceResponseFactory.Services; import org.apache.ambari.server.controller.spi.Predicate; import org.apache.ambari.server.controller.utilities.PredicateHelper; import org.apache.ambari.server.orm.entities.AlertDefinitionEntity; @@ -35,7 +41,10 @@ import org.apache.ambari.server.orm.entities.AlertGroupEntity; import org.apache.ambari.server.orm.entities.AlertNoticeEntity; import org.apache.ambari.server.orm.entities.AlertNoticeEntity_; 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.NotificationState; +import org.apache.ambari.server.state.Service; import org.apache.ambari.server.state.alert.AlertGroup; import com.google.inject.Inject; @@ -53,13 +62,26 @@ public class AlertDispatchDAO { * JPA entity manager */ @Inject - Provider<EntityManager> entityManagerProvider; + private Provider<EntityManager> entityManagerProvider; /** * DAO utilities for dealing mostly with {@link TypedQuery} results. */ @Inject - DaoUtils daoUtils; + private DaoUtils daoUtils; + + /** + * Used to retrieve a cluster and its services when creating a default + * {@link AlertGroupEntity} for a service. + */ + @Inject + private Provider<Clusters> m_clusters; + + /** + * A lock that ensures that group writes are protected. This is useful since + * groups can be created through different events/threads in the system. + */ + private final Lock m_groupLock = new ReentrantLock(); /** * Gets an alert group with the specified ID. @@ -256,18 +278,22 @@ public class AlertDispatchDAO { } /** - * Gets the default group for the specified service. + * Gets the default group for the specified cluster and service. * + * @param clusterId + * the cluster that the group belongs to * @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) { + public AlertGroupEntity findDefaultServiceGroup(long clusterId, + String serviceName) { TypedQuery<AlertGroupEntity> query = entityManagerProvider.get().createNamedQuery( "AlertGroupEntity.findServiceDefaultGroup", AlertGroupEntity.class); + query.setParameter("clusterId", clusterId); query.setParameter("serviceName", serviceName); return daoUtils.selectSingle(query); } @@ -364,6 +390,49 @@ public class AlertDispatchDAO { } /** + * Creates a default group in the specified cluster and service. If the + * service is not valid, then this will throw an {@link AmbariException}. + * + * @param clusterId + * the cluster that the group is in. + * @param serviceName + * the name of the group which is also the service name. + */ + public AlertGroupEntity createDefaultGroup(long clusterId, String serviceName) + throws AmbariException { + // AMBARI is a special service that we let through, otherwise we need to + // verify that the service exists before we create the default group + String ambariServiceName = Services.AMBARI.name(); + if (!ambariServiceName.equals(serviceName)) { + Cluster cluster = m_clusters.get().getClusterById(clusterId); + Map<String, Service> services = cluster.getServices(); + + if (!services.containsKey(serviceName)) { + String message = MessageFormat.format( + "Unable to create a default alert group for unknown service {0} in cluster {1}", + serviceName, cluster.getClusterName()); + throw new AmbariException(message); + } + } + + AlertGroupEntity group = new AlertGroupEntity(); + + m_groupLock.lock(); + try { + group.setClusterId(clusterId); + group.setDefault(true); + group.setGroupName(serviceName); + group.setServiceName(serviceName); + + create(group); + } finally { + m_groupLock.unlock(); + } + + return group; + } + + /** * Refresh the state of the alert group from the database. * * @param alertGroup http://git-wip-us.apache.org/repos/asf/ambari/blob/9159421b/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 1127dd1..4908eea 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 @@ -503,8 +503,7 @@ public class AlertsDAO { */ @Transactional public int removeCurrentByServiceComponentHost(String serviceName, - String componentName, - String hostName) { + String componentName, String hostName) { TypedQuery<AlertCurrentEntity> query = entityManagerProvider.get().createNamedQuery( "AlertCurrentEntity.removeByHostComponent", AlertCurrentEntity.class); http://git-wip-us.apache.org/repos/asf/ambari/blob/9159421b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ClusterServiceDAO.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ClusterServiceDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ClusterServiceDAO.java index dcad56e..1306c6c 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ClusterServiceDAO.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ClusterServiceDAO.java @@ -18,18 +18,20 @@ package org.apache.ambari.server.orm.dao; -import com.google.inject.Inject; -import com.google.inject.Provider; -import com.google.inject.Singleton; -import com.google.inject.persist.Transactional; -import org.apache.ambari.server.orm.RequiresSession; -import org.apache.ambari.server.orm.entities.ClusterServiceEntity; -import org.apache.ambari.server.orm.entities.ClusterServiceEntityPK; +import java.util.List; import javax.persistence.EntityManager; import javax.persistence.NoResultException; import javax.persistence.TypedQuery; -import java.util.List; + +import org.apache.ambari.server.orm.RequiresSession; +import org.apache.ambari.server.orm.entities.ClusterServiceEntity; +import org.apache.ambari.server.orm.entities.ClusterServiceEntityPK; + +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.Singleton; +import com.google.inject.persist.Transactional; @Singleton public class ClusterServiceDAO { @@ -84,7 +86,8 @@ public class ClusterServiceDAO { @Transactional public void removeByPK(ClusterServiceEntityPK clusterServiceEntityPK) { - remove(findByPK(clusterServiceEntityPK)); + ClusterServiceEntity entity = findByPK(clusterServiceEntityPK); + entityManagerProvider.get().remove(entity); } } http://git-wip-us.apache.org/repos/asf/ambari/blob/9159421b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ServiceComponentDesiredStateDAO.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ServiceComponentDesiredStateDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ServiceComponentDesiredStateDAO.java index 8cf7ec3..341d1fd 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ServiceComponentDesiredStateDAO.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ServiceComponentDesiredStateDAO.java @@ -18,18 +18,20 @@ package org.apache.ambari.server.orm.dao; -import com.google.inject.Inject; -import com.google.inject.Provider; -import com.google.inject.Singleton; -import com.google.inject.persist.Transactional; -import org.apache.ambari.server.orm.RequiresSession; -import org.apache.ambari.server.orm.entities.ServiceComponentDesiredStateEntityPK; -import org.apache.ambari.server.orm.entities.ServiceComponentDesiredStateEntity; +import java.util.List; import javax.persistence.EntityManager; import javax.persistence.NoResultException; import javax.persistence.TypedQuery; -import java.util.List; + +import org.apache.ambari.server.orm.RequiresSession; +import org.apache.ambari.server.orm.entities.ServiceComponentDesiredStateEntity; +import org.apache.ambari.server.orm.entities.ServiceComponentDesiredStateEntityPK; + +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.Singleton; +import com.google.inject.persist.Transactional; @Singleton public class ServiceComponentDesiredStateDAO { @@ -75,6 +77,7 @@ public class ServiceComponentDesiredStateDAO { @Transactional public void removeByPK(ServiceComponentDesiredStateEntityPK primaryKey) { - remove(findByPK(primaryKey)); + ServiceComponentDesiredStateEntity entity = findByPK(primaryKey); + entityManagerProvider.get().remove(entity); } } http://git-wip-us.apache.org/repos/asf/ambari/blob/9159421b/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 a330c90..81fb133 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 @@ -536,4 +536,22 @@ public class AlertDefinitionEntity { int result = null != definitionId ? definitionId.hashCode() : 0; return result; } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + StringBuilder buffer = new StringBuilder(); + buffer.append(getClass().getSimpleName()); + buffer.append("{"); + buffer.append("id=").append(definitionId); + buffer.append(", name=").append(definitionName); + buffer.append(", serviceName=").append(serviceName); + buffer.append(", componentName=").append(componentName); + buffer.append(", enabled=").append(enabled); + buffer.append(", hash=").append(hash); + buffer.append("}"); + return buffer.toString(); + } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/9159421b/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 ac3586d..6607fb0 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 @@ -51,7 +51,7 @@ import javax.persistence.UniqueConstraint; @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.findServiceDefaultGroup", query = "SELECT alertGroup FROM AlertGroupEntity alertGroup WHERE alertGroup.serviceName = :serviceName AND alertGroup.isDefault = 1") }) + @NamedQuery(name = "AlertGroupEntity.findServiceDefaultGroup", query = "SELECT alertGroup FROM AlertGroupEntity alertGroup WHERE alertGroup.clusterId = :clusterId AND alertGroup.serviceName = :serviceName AND alertGroup.isDefault = 1") }) public class AlertGroupEntity { @Id @@ -353,4 +353,19 @@ public class AlertGroupEntity { int result = null != groupId ? groupId.hashCode() : 0; return result; } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + StringBuilder buffer = new StringBuilder(); + buffer.append(getClass().getSimpleName()); + buffer.append("{"); + buffer.append("id=").append(groupId); + buffer.append(", name=").append(groupName); + buffer.append(", default=").append(isDefault); + buffer.append("}"); + return buffer.toString(); + } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/9159421b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertHistoryEntity.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertHistoryEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertHistoryEntity.java index a671ae1..8e96aca 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertHistoryEntity.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertHistoryEntity.java @@ -355,4 +355,21 @@ public class AlertHistoryEntity { return result; } + /** + * {@inheritDoc} + */ + @Override + public String toString() { + StringBuilder buffer = new StringBuilder(); + buffer.append(getClass().getSimpleName()); + buffer.append("{"); + buffer.append("id=").append(alertId); + buffer.append(", serviceName=").append(serviceName); + buffer.append(", componentName=").append(componentName); + buffer.append(", state=").append(alertState); + buffer.append(", label=").append(alertLabel); + buffer.append("}"); + return buffer.toString(); + } + } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/9159421b/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 d18ec68..9f24dc3 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 @@ -295,4 +295,17 @@ public class AlertTargetEntity { return result; } + /** + * {@inheritDoc} + */ + @Override + public String toString() { + StringBuilder buffer = new StringBuilder(); + buffer.append(getClass().getSimpleName()); + buffer.append("{"); + buffer.append("id=").append(targetId); + buffer.append(", name=").append(targetName); + buffer.append("}"); + return buffer.toString(); + } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/9159421b/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 abffa5d..c8b78a0 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 @@ -584,8 +584,8 @@ public class AlertDefinitionHash { * {@code null}). */ private Set<AlertDefinitionEntity> getAlertDefinitionEntities( - String clusterName, - String hostName) { + String clusterName, String hostName) { + Set<AlertDefinitionEntity> definitions = new HashSet<AlertDefinitionEntity>(); try { @@ -598,45 +598,41 @@ public class AlertDefinitionHash { } 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)); - } + // services and components + List<ServiceComponentHost> serviceComponents = cluster.getServiceComponentHosts(hostName); + if (null == serviceComponents || !serviceComponents.isEmpty()) { + 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()); + // 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 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) http://git-wip-us.apache.org/repos/asf/ambari/blob/9159421b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java index 991d289..d2c7428 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java @@ -39,11 +39,12 @@ import org.apache.ambari.server.HostNotFoundException; import org.apache.ambari.server.agent.DiskInfo; import org.apache.ambari.server.api.services.AmbariMetaInfo; import org.apache.ambari.server.configuration.Configuration; +import org.apache.ambari.server.events.HostAddedEvent; +import org.apache.ambari.server.events.HostRegisteredEvent; import org.apache.ambari.server.events.HostRemovedEvent; import org.apache.ambari.server.events.publishers.AmbariEventPublisher; import org.apache.ambari.server.orm.dao.ClusterDAO; import org.apache.ambari.server.orm.dao.ClusterVersionDAO; -import org.apache.ambari.server.orm.dao.ConfigGroupHostMappingDAO; import org.apache.ambari.server.orm.dao.HostDAO; import org.apache.ambari.server.orm.dao.HostVersionDAO; import org.apache.ambari.server.orm.dao.ResourceDAO; @@ -121,8 +122,6 @@ public class ClustersImpl implements Clusters { @Inject Gson gson; @Inject - private ConfigGroupHostMappingDAO configGroupHostMappingDAO; - @Inject private SecurityHelper securityHelper; /** @@ -341,12 +340,14 @@ public class ClustersImpl implements Clusters { @Override public void addHost(String hostname) throws AmbariException { checkLoaded(); + String duplicateMessage = "Duplicate entry for Host" + ", hostName= " + hostname; if (hosts.containsKey(hostname)) { throw new AmbariException(duplicateMessage); } + r.lock(); try { @@ -371,6 +372,10 @@ public class ClustersImpl implements Clusters { } finally { r.unlock(); } + + // publish the event + HostRegisteredEvent event = new HostRegisteredEvent(hostname); + eventPublisher.publish(event); } private boolean isOsSupportedByClusterStack(Cluster c, Host h) throws AmbariException { @@ -558,6 +563,10 @@ public class ClustersImpl implements Clusters { clusterDAO.merge(clusterEntity); hostDAO.merge(hostEntity); + + // publish the event for adding a host to a cluster + HostAddedEvent event = new HostAddedEvent(clusterId, hostName); + eventPublisher.publish(event); } @Override http://git-wip-us.apache.org/repos/asf/ambari/blob/9159421b/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 dc71862..0c93ec2 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 @@ -20,12 +20,15 @@ package org.apache.ambari.server.orm; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; 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; @@ -59,11 +62,22 @@ import org.apache.ambari.server.orm.entities.ResourceEntity; import org.apache.ambari.server.orm.entities.ResourceTypeEntity; import org.apache.ambari.server.orm.entities.StageEntity; import org.apache.ambari.server.orm.entities.UserEntity; +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.RepositoryVersionState; +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.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.util.Assert; import com.google.inject.Inject; import com.google.inject.Injector; @@ -289,11 +303,131 @@ public class OrmTestHelper { clusterDAO.create(clusterEntity); clusterEntity = clusterDAO.findByName(clusterEntity.getClusterName()); - Assert.notNull(clusterEntity); - Assert.isTrue(clusterEntity.getClusterId() > 0); + assertNotNull(clusterEntity); + assertTrue(clusterEntity.getClusterId() > 0); return clusterEntity.getClusterId(); } + public Cluster buildNewCluster(Clusters clusters, + ServiceFactory serviceFactory, ServiceComponentFactory componentFactory, + ServiceComponentHostFactory schFactory, String hostName) throws Exception { + String clusterName = "cluster-" + System.currentTimeMillis(); + clusters.addCluster(clusterName); + Cluster cluster = clusters.getCluster(clusterName); + cluster = initializeClusterWithStack(cluster); + + addHost(clusters, cluster, hostName); + + installHdfsService(cluster, serviceFactory, componentFactory, schFactory, hostName); + installYarnService(cluster, serviceFactory, componentFactory, schFactory, + hostName); + return cluster; + } + + public Cluster initializeClusterWithStack(Cluster cluster) throws Exception { + StackId stackId = new StackId("HDP", "2.0.6"); + cluster.setDesiredStackVersion(stackId); + cluster.createClusterVersion(stackId.getStackName(), + stackId.getStackVersion(), "admin", RepositoryVersionState.CURRENT); + return cluster; + } + + /** + * @throws Exception + */ + public void addHost(Clusters clusters, Cluster cluster, String hostName) + throws Exception { + clusters.addHost(hostName); + + Host host = 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(); + + clusters.mapHostToCluster(hostName, cluster.getClusterName()); + } + + /** + * Calls {@link Service#persist()} to mock a service install along with + * creating a single {@link Host} and {@link ServiceComponentHost}. + */ + public void installHdfsService(Cluster cluster, + ServiceFactory serviceFactory, ServiceComponentFactory componentFactory, + ServiceComponentHostFactory schFactory, String hostName) throws Exception { + String serviceName = "HDFS"; + Service service = serviceFactory.createNew(cluster, serviceName); + cluster.addService(service); + service.persist(); + service = cluster.getService(serviceName); + assertNotNull(service); + + ServiceComponent datanode = componentFactory.createNew(service, "DATANODE"); + + service.addServiceComponent(datanode); + datanode.setDesiredState(State.INSTALLED); + datanode.persist(); + + ServiceComponentHost sch = 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 = componentFactory.createNew(service, "NAMENODE"); + + service.addServiceComponent(namenode); + namenode.setDesiredState(State.INSTALLED); + namenode.persist(); + + sch = 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(); + } + + /** + * Calls {@link Service#persist()} to mock a service install along with + * creating a single {@link Host} and {@link ServiceComponentHost}. + */ + public void installYarnService(Cluster cluster, + ServiceFactory serviceFactory, ServiceComponentFactory componentFactory, + ServiceComponentHostFactory schFactory, String hostName) throws Exception { + String serviceName = "YARN"; + Service service = serviceFactory.createNew(cluster, serviceName); + cluster.addService(service); + service.persist(); + service = cluster.getService(serviceName); + assertNotNull(service); + + ServiceComponent resourceManager = componentFactory.createNew(service, + "RESOURCEMANAGER"); + + service.addServiceComponent(resourceManager); + resourceManager.setDesiredState(State.INSTALLED); + resourceManager.persist(); + + ServiceComponentHost sch = schFactory.createNew(resourceManager, hostName); + + resourceManager.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(); + } + /** * Creates an alert target. * @@ -324,7 +458,7 @@ public class OrmTestHelper { AlertDefinitionEntity definition = new AlertDefinitionEntity(); definition.setDefinitionName("Alert Definition " + System.currentTimeMillis()); - definition.setServiceName("Service " + System.currentTimeMillis()); + definition.setServiceName("AMBARI"); definition.setComponentName(null); definition.setClusterId(clusterId); definition.setHash(UUID.randomUUID().toString()); @@ -385,8 +519,8 @@ public class OrmTestHelper { List<AlertGroupEntity> defaultGroups = alertDispatchDAO.findAllGroups(clusterId); assertEquals(2, defaultGroups.size()); - assertNotNull(alertDispatchDAO.findDefaultServiceGroup("HDFS")); - assertNotNull(alertDispatchDAO.findDefaultServiceGroup("OOZIE")); + assertNotNull(alertDispatchDAO.findDefaultServiceGroup(clusterId, "HDFS")); + assertNotNull(alertDispatchDAO.findDefaultServiceGroup(clusterId, "OOZIE")); return defaultGroups; } http://git-wip-us.apache.org/repos/asf/ambari/blob/9159421b/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 0d2d305..3d8f898 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 @@ -19,21 +19,20 @@ package org.apache.ambari.server.orm.dao; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; 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.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.UUID; -import junit.framework.Assert; - +import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.controller.AlertNoticeRequest; import org.apache.ambari.server.controller.internal.AlertNoticeResourceProvider; import org.apache.ambari.server.controller.internal.PageRequestImpl; @@ -44,6 +43,8 @@ import org.apache.ambari.server.controller.spi.SortRequest; import org.apache.ambari.server.controller.spi.SortRequest.Order; import org.apache.ambari.server.controller.spi.SortRequestProperty; import org.apache.ambari.server.controller.utilities.PredicateBuilder; +import org.apache.ambari.server.events.listeners.alerts.AlertServiceStateListener; +import org.apache.ambari.server.events.publishers.AmbariEventPublisher; import org.apache.ambari.server.orm.AlertDaoHelper; import org.apache.ambari.server.orm.GuiceJpaInitializer; import org.apache.ambari.server.orm.InMemoryDefaultTestModule; @@ -55,25 +56,18 @@ 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.Cluster; -import org.apache.ambari.server.state.RepositoryVersionState; 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.NotificationState; -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; @@ -86,7 +80,7 @@ public class AlertDispatchDAOTest { private final static String HOSTNAME = "c6401.ambari.apache.org"; private Clusters m_clusters; - private Long m_clusterId; + private Cluster m_cluster; private Injector m_injector; private AlertDispatchDAO m_dao; private AlertDefinitionDAO m_definitionDao; @@ -97,6 +91,8 @@ public class AlertDispatchDAOTest { private ServiceComponentFactory m_componentFactory; private ServiceComponentHostFactory m_schFactory; private AlertDaoHelper m_alertHelper; + private AmbariEventPublisher m_eventPublisher; + private EventBus m_synchronizedBus; /** * @@ -114,15 +110,24 @@ public class AlertDispatchDAOTest { m_schFactory = m_injector.getInstance(ServiceComponentHostFactory.class); m_clusters = m_injector.getInstance(Clusters.class); m_alertHelper = m_injector.getInstance(AlertDaoHelper.class); + m_eventPublisher = m_injector.getInstance(AmbariEventPublisher.class); + + // !!! need a synchronous op for testing + m_synchronizedBus = new EventBus(); + Field field = AmbariEventPublisher.class.getDeclaredField("m_eventBus"); + field.setAccessible(true); + field.set(m_eventPublisher, m_synchronizedBus); + + m_cluster = m_clusters.getClusterById(m_helper.createCluster()); + m_helper.initializeClusterWithStack(m_cluster); - m_clusterId = m_helper.createCluster(); Set<AlertTargetEntity> targets = createTargets(); for (int i = 0; i < 10; i++) { AlertGroupEntity group = new AlertGroupEntity(); group.setDefault(false); group.setGroupName("Group Name " + i); - group.setClusterId(m_clusterId); + group.setClusterId(m_cluster.getClusterId()); for (AlertTargetEntity alertTarget : targets) { group.addAlertTarget(alertTarget); } @@ -214,7 +219,8 @@ public class AlertDispatchDAOTest { Set<AlertTargetEntity> targets = new HashSet<AlertTargetEntity>(); targets.add(target); - AlertGroupEntity group = m_helper.createAlertGroup(m_clusterId, targets); + AlertGroupEntity group = m_helper.createAlertGroup( + m_cluster.getClusterId(), targets); AlertGroupEntity actual = m_dao.findGroupById(group.getGroupId()); assertNotNull(group); @@ -231,7 +237,8 @@ public class AlertDispatchDAOTest { public void testGroupDefinitions() throws Exception { List<AlertDefinitionEntity> definitions = createDefinitions(); - AlertGroupEntity group = m_helper.createAlertGroup(m_clusterId, null); + AlertGroupEntity group = m_helper.createAlertGroup( + m_cluster.getClusterId(), null); group = m_dao.findGroupById(group.getGroupId()); assertNotNull(group); @@ -272,7 +279,8 @@ public class AlertDispatchDAOTest { Set<AlertTargetEntity> targets = new HashSet<AlertTargetEntity>(); targets.add(target); - AlertGroupEntity group = m_helper.createAlertGroup(m_clusterId, targets); + AlertGroupEntity group = m_helper.createAlertGroup( + m_cluster.getClusterId(), targets); AlertTargetEntity actual = m_dao.findTargetById(target.getTargetId()); assertNotNull(actual); @@ -297,7 +305,8 @@ public class AlertDispatchDAOTest { public void testDeleteGroup() throws Exception { int targetCount = m_dao.findAllTargets().size(); - AlertGroupEntity group = m_helper.createAlertGroup(m_clusterId, null); + AlertGroupEntity group = m_helper.createAlertGroup( + m_cluster.getClusterId(), null); AlertTargetEntity target = m_helper.createAlertTarget(); assertEquals(targetCount + 1, m_dao.findAllTargets().size()); @@ -347,7 +356,8 @@ public class AlertDispatchDAOTest { Set<AlertTargetEntity> targets = new HashSet<AlertTargetEntity>(); targets.add(target); - AlertGroupEntity group = m_helper.createAlertGroup(m_clusterId, targets); + AlertGroupEntity group = m_helper.createAlertGroup( + m_cluster.getClusterId(), targets); assertEquals(1, group.getAlertTargets().size()); target = m_dao.findTargetById(target.getTargetId()); @@ -377,7 +387,8 @@ public class AlertDispatchDAOTest { String groupName = "Group Name " + System.currentTimeMillis(); - AlertGroupEntity group = m_helper.createAlertGroup(m_clusterId, null); + AlertGroupEntity group = m_helper.createAlertGroup( + m_cluster.getClusterId(), null); group = m_dao.findGroupById(group.getGroupId()); group.setGroupName(groupName + "FOO"); @@ -406,7 +417,8 @@ public class AlertDispatchDAOTest { @Test public void testFindGroupsByDefinition() throws Exception { List<AlertDefinitionEntity> definitions = createDefinitions(); - AlertGroupEntity group = m_helper.createAlertGroup(m_clusterId, null); + AlertGroupEntity group = m_helper.createAlertGroup( + m_cluster.getClusterId(), null); group = m_dao.findGroupById(group.getGroupId()); assertNotNull(group); @@ -420,10 +432,11 @@ public class AlertDispatchDAOTest { group = m_dao.findGroupByName(group.getGroupName()); assertEquals(definitions.size(), group.getAlertDefinitions().size()); + // assert that the definition is now part of 2 groups (the default group + // and the newly associated group from above) for (AlertDefinitionEntity definition : definitions) { List<AlertGroupEntity> groups = m_dao.findGroupsByDefinition(definition); - assertEquals(1, groups.size()); - assertEquals(group.getGroupId(), groups.get(0).getGroupId()); + assertEquals(2, groups.size()); } } @@ -437,7 +450,7 @@ public class AlertDispatchDAOTest { AlertHistoryEntity history = new AlertHistoryEntity(); history.setServiceName(definition.getServiceName()); - history.setClusterId(m_clusterId); + history.setClusterId(m_cluster.getClusterId()); history.setAlertDefinition(definition); history.setAlertLabel("Label"); history.setAlertState(AlertState.OK); @@ -468,7 +481,9 @@ public class AlertDispatchDAOTest { */ @Test public void testAlertNoticePredicate() throws Exception { - Cluster cluster = initializeNewCluster(); + Cluster cluster = m_helper.buildNewCluster(m_clusters, m_serviceFactory, + m_componentFactory, m_schFactory, HOSTNAME); + m_alertHelper.populateData(cluster); Predicate clusterPredicate = null; @@ -544,7 +559,9 @@ public class AlertDispatchDAOTest { */ @Test public void testAlertNoticePagination() throws Exception { - Cluster cluster = initializeNewCluster(); + Cluster cluster = m_helper.buildNewCluster(m_clusters, m_serviceFactory, + m_componentFactory, m_schFactory, HOSTNAME); + m_alertHelper.populateData(cluster); AlertNoticeRequest request = new AlertNoticeRequest(); @@ -583,7 +600,9 @@ public class AlertDispatchDAOTest { */ @Test public void testAlertNoticeSorting() throws Exception { - Cluster cluster = initializeNewCluster(); + Cluster cluster = m_helper.buildNewCluster(m_clusters, m_serviceFactory, + m_componentFactory, m_schFactory, HOSTNAME); + m_alertHelper.populateData(cluster); List<SortRequestProperty> sortProperties = new ArrayList<SortRequestProperty>(); @@ -640,15 +659,135 @@ public class AlertDispatchDAOTest { } /** + * + */ + @Test + public void testFindDefaultGroup() throws Exception { + m_synchronizedBus.register(m_injector.getInstance(AlertServiceStateListener.class)); + + List<AlertGroupEntity> groups = m_dao.findAllGroups(); + assertNotNull(groups); + assertEquals(10, groups.size()); + + for (AlertGroupEntity group : groups) { + assertFalse(group.isDefault()); + } + + Cluster cluster = m_helper.buildNewCluster(m_clusters, m_serviceFactory, + m_componentFactory, m_schFactory, HOSTNAME); + + AlertGroupEntity hdfsGroup = m_dao.findDefaultServiceGroup( + cluster.getClusterId(), "HDFS"); + + assertNotNull(hdfsGroup); + assertTrue(hdfsGroup.isDefault()); + } + + /** + * Tests that when creating a new {@link AlertDefinitionEntity}, if the group + * for its service does not exist, then it will be created. + */ + @Test + public void testDefaultGroupAutomaticCreation() throws Exception { + m_synchronizedBus.register(m_injector.getInstance(AlertServiceStateListener.class)); + + List<AlertGroupEntity> groups = m_dao.findAllGroups(); + assertNotNull(groups); + assertEquals(10, groups.size()); + + for (AlertGroupEntity group : groups) { + assertFalse(group.isDefault()); + } + + Cluster cluster = m_helper.buildNewCluster(m_clusters, m_serviceFactory, + m_componentFactory, m_schFactory, HOSTNAME); + + AlertGroupEntity hdfsGroup = m_dao.findDefaultServiceGroup( + cluster.getClusterId(), "HDFS"); + + // remove the HDFS default group + m_dao.remove(hdfsGroup); + hdfsGroup = m_dao.findDefaultServiceGroup(cluster.getClusterId(), "HDFS"); + assertNull(hdfsGroup); + + AlertDefinitionEntity datanodeProcess = new AlertDefinitionEntity(); + datanodeProcess.setClusterId(cluster.getClusterId()); + datanodeProcess.setDefinitionName("datanode_process"); + datanodeProcess.setServiceName("HDFS"); + datanodeProcess.setComponentName("DATANODE"); + datanodeProcess.setHash(UUID.randomUUID().toString()); + datanodeProcess.setScheduleInterval(60); + datanodeProcess.setScope(Scope.SERVICE); + datanodeProcess.setSource("{\"type\" : \"SCRIPT\"}"); + datanodeProcess.setSourceType(SourceType.SCRIPT); + m_definitionDao.create(datanodeProcess); + + // the group should be created and should be default + hdfsGroup = m_dao.findDefaultServiceGroup(cluster.getClusterId(), "HDFS"); + assertNotNull(hdfsGroup); + assertTrue(hdfsGroup.isDefault()); + } + + /** + * Tests that when creating a new {@link AlertDefinitionEntity}, if the group + * for its service does not exist, then it will not be created if the service + * is invalid. + */ + @Test(expected = AmbariException.class) + public void testDefaultGroupInvalidServiceNoCreation() throws Exception { + m_synchronizedBus.register(m_injector.getInstance(AlertServiceStateListener.class)); + + List<AlertGroupEntity> groups = m_dao.findAllGroups(); + assertNotNull(groups); + assertEquals(10, groups.size()); + + for (AlertGroupEntity group : groups) { + assertFalse(group.isDefault()); + } + + Cluster cluster = m_helper.buildNewCluster(m_clusters, m_serviceFactory, + m_componentFactory, m_schFactory, HOSTNAME); + + assertEquals(12, m_dao.findAllGroups().size()); + + // create a definition with an invalid service + AlertDefinitionEntity datanodeProcess = new AlertDefinitionEntity(); + datanodeProcess.setClusterId(cluster.getClusterId()); + datanodeProcess.setDefinitionName("datanode_process"); + datanodeProcess.setServiceName("INVALID"); + datanodeProcess.setComponentName("DATANODE"); + datanodeProcess.setHash(UUID.randomUUID().toString()); + datanodeProcess.setScheduleInterval(60); + datanodeProcess.setScope(Scope.SERVICE); + datanodeProcess.setSource("{\"type\" : \"SCRIPT\"}"); + datanodeProcess.setSourceType(SourceType.SCRIPT); + + try { + m_definitionDao.create(datanodeProcess); + } finally { + // assert no group was added + assertEquals(12, m_dao.findAllGroups().size()); + } + } + + /** * @return */ private List<AlertDefinitionEntity> createDefinitions() throws Exception { + // add a host to the cluster + m_helper.addHost(m_clusters, m_cluster, HOSTNAME); + + // install YARN (which doesn't have any alerts defined in the test JSON) + // so that the definitions get created correctly + m_helper.installYarnService(m_cluster, m_serviceFactory, + m_componentFactory, m_schFactory, HOSTNAME); + for (int i = 0; i < 8; i++) { AlertDefinitionEntity definition = new AlertDefinitionEntity(); definition.setDefinitionName("Alert Definition " + i); - definition.setServiceName("HDFS"); + definition.setServiceName("YARN"); definition.setComponentName(null); - definition.setClusterId(m_clusterId); + definition.setClusterId(m_cluster.getClusterId()); definition.setHash(UUID.randomUUID().toString()); definition.setScheduleInterval(60); definition.setScope(Scope.SERVICE); @@ -680,81 +819,4 @@ public class AlertDispatchDAOTest { return targets; } - - private Cluster initializeNewCluster() throws Exception { - String clusterName = "cluster-" + System.currentTimeMillis(); - m_clusters.addCluster(clusterName); - - Cluster cluster = m_clusters.getCluster(clusterName); - StackId stackId = new StackId("HDP", "2.0.6"); - cluster.setDesiredStackVersion(stackId); - cluster.createClusterVersion(stackId.getStackName(), stackId.getStackVersion(), "admin", RepositoryVersionState.CURRENT); - - 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(); - } }
