Repository: ambari Updated Branches: refs/heads/branch-2.2 8cae8092d -> 7cb6382d1
AMBARI-15620 - Orphaned Host Alerts Cause Stale Alert Notifications After Removing Hosts (jonathanhurley) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/7cb6382d Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/7cb6382d Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/7cb6382d Branch: refs/heads/branch-2.2 Commit: 7cb6382d1087fcae4b6ea79b3264a76e57976334 Parents: 8cae809 Author: Jonathan Hurley <[email protected]> Authored: Tue Mar 29 15:29:18 2016 -0400 Committer: Jonathan Hurley <[email protected]> Committed: Wed Mar 30 16:00:01 2016 -0400 ---------------------------------------------------------------------- .../server/alerts/StaleAlertRunnable.java | 33 +++-- .../listeners/alerts/AlertReceivedListener.java | 75 ++++++++++-- .../apache/ambari/server/orm/dao/HostDAO.java | 27 ++-- .../apache/ambari/server/state/Clusters.java | 66 ++++++---- .../server/state/cluster/ClustersImpl.java | 59 ++++++--- .../state/alerts/AlertReceivedListenerTest.java | 122 +++++++++++++++++++ 6 files changed, 300 insertions(+), 82 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/7cb6382d/ambari-server/src/main/java/org/apache/ambari/server/alerts/StaleAlertRunnable.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/alerts/StaleAlertRunnable.java b/ambari-server/src/main/java/org/apache/ambari/server/alerts/StaleAlertRunnable.java index 83abc8e..54abd62 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/alerts/StaleAlertRunnable.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/alerts/StaleAlertRunnable.java @@ -19,10 +19,10 @@ package org.apache.ambari.server.alerts; import java.text.MessageFormat; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TreeSet; import org.apache.ambari.server.events.AlertEvent; import org.apache.ambari.server.events.AlertReceivedEvent; @@ -74,11 +74,11 @@ public class StaleAlertRunnable implements Runnable { /** * The message to use when alerts are detected as stale. */ - private static final String STALE_ALERTS_MSG = "There are {0} stale alerts from {1} host(s): {2}"; + private static final String STALE_ALERTS_MSG = "There are {0} stale alerts from {1} host(s):\n{2}"; private static final String TIMED_LABEL_MSG = "{0} ({1})"; - private static final String HOST_LABEL_MSG = "{0}[{1}]"; + private static final String HOST_LABEL_MSG = "{0}\n [{1}]"; /** * Convert the minutes for the delay of an alert into milliseconds. @@ -134,9 +134,9 @@ public class StaleAlertRunnable implements Runnable { } long now = System.currentTimeMillis(); - Set<String> staleAlerts = new HashSet<String>(); + Set<String> staleAlerts = new TreeSet<String>(); Map<String, Set<String>> staleHostAlerts = new HashMap<>(); - Set<String> hostsWithStaleAlerts = new HashSet<String>(); + Set<String> hostsWithStaleAlerts = new TreeSet<>(); // get the cluster's current alerts List<AlertCurrentEntity> currentAlerts = m_alertsDao.findCurrentByCluster(cluster.getClusterId()); @@ -174,13 +174,20 @@ public class StaleAlertRunnable implements Runnable { // if the last time it was run is >= 2x the interval, it's stale long timeDifference = now - current.getLatestTimestamp(); if (timeDifference >= 2 * intervalInMillis) { + + // it is technically possible to have a null/blank label; if so, + // default to the name of the definition String label = definition.getLabel(); + if (StringUtils.isEmpty(label)) { + label = definition.getDefinitionName(); + } + if (null != history.getHostName()) { // keep track of the host, if not null String hostName = history.getHostName(); hostsWithStaleAlerts.add(hostName); if(!staleHostAlerts.containsKey(hostName)) { - staleHostAlerts.put(hostName, new HashSet<String>()); + staleHostAlerts.put(hostName, new TreeSet<String>()); } staleHostAlerts.get(hostName).add(MessageFormat.format(TIMED_LABEL_MSG, label, @@ -193,7 +200,8 @@ public class StaleAlertRunnable implements Runnable { } for(String host : staleHostAlerts.keySet()) { - staleAlerts.add(MessageFormat.format(HOST_LABEL_MSG, host, StringUtils.join(staleHostAlerts.get(host), ", "))); + staleAlerts.add(MessageFormat.format(HOST_LABEL_MSG, host, + StringUtils.join(staleHostAlerts.get(host), ",\n "))); } AlertState alertState = AlertState.OK; @@ -205,7 +213,7 @@ public class StaleAlertRunnable implements Runnable { alertState = AlertState.CRITICAL; alertText = MessageFormat.format(STALE_ALERTS_MSG, staleAlerts.size(), hostsWithStaleAlerts.size(), - StringUtils.join(staleAlerts, ", ")); + StringUtils.join(staleAlerts, ",\n")); } Alert alert = new Alert(entity.getDefinitionName(), null, @@ -245,12 +253,15 @@ public class StaleAlertRunnable implements Runnable { hour = min / MINUTES_PER_HOUR; min = min % MINUTES_PER_HOUR; String result = ""; - if(days > 0) + if(days > 0) { result += days + "d "; - if(hour > 0) + } + if(hour > 0) { result += hour + "h "; - if(min > 0) + } + if(min > 0) { result += min + "m "; + } return result.trim(); } } http://git-wip-us.apache.org/repos/asf/ambari/blob/7cb6382d/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertReceivedListener.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertReceivedListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertReceivedListener.java index 8dc8e1e..f6aa1aa 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertReceivedListener.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertReceivedListener.java @@ -25,6 +25,7 @@ import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.EagerSingleton; import org.apache.ambari.server.configuration.Configuration; import org.apache.ambari.server.controller.MaintenanceStateHelper; +import org.apache.ambari.server.controller.RootServiceResponseFactory.Components; import org.apache.ambari.server.controller.RootServiceResponseFactory.Services; import org.apache.ambari.server.events.AlertEvent; import org.apache.ambari.server.events.AlertReceivedEvent; @@ -318,9 +319,15 @@ public class AlertReceivedListener { /** * Gets whether the specified alert is valid for its reported cluster, - * service, component, and host. This method is necessary for the case where a - * component has been removed from a host, but the alert data is going to be - * returned before the agent alert job can be unscheduled. + * service, component, and host. This method is necessary for the following + * cases + * <ul> + * <li>A service/component is removed, but an alert queued for reporting is + * received after that event.</li> + * <li>A host is removed from the cluster but the agent is still running and + * reporting</li> + * <li>A cluster is renamed</li> + * </ul> * * @param alert * the alert. @@ -333,18 +340,36 @@ public class AlertReceivedListener { String componentName = alert.getComponent(); String hostName = alert.getHostName(); - // if the alert is not bound to a cluster, then it's most likely a - // host alert and is always valid - if( null == clusterName ){ + // AMBARI/AMBARI_SERVER is always a valid service/component combination + String ambariServiceName = Services.AMBARI.name(); + String ambariServerComponentName = Components.AMBARI_SERVER.name(); + String ambariAgentComponentName = Components.AMBARI_AGENT.name(); + if (ambariServiceName.equals(serviceName) && ambariServerComponentName.equals(componentName)) { return true; } - // AMBARI is always a valid service - String ambariServiceName = Services.AMBARI.name(); - if (ambariServiceName.equals(serviceName)) { + // if the alert is not bound to a cluster, then it's most likely a + // host alert and is always valid as long as the host exists + if (StringUtils.isBlank(clusterName)) { + // no cluster, no host; return true out of respect for the unknown alert + if (StringUtils.isBlank(hostName)) { + return true; + } + + // if a host is reported, it must be registered to some cluster somewhere + if (!m_clusters.get().hostExists(hostName)) { + LOG.error("Unable to process alert {} for an invalid host named {}", + alert.getName(), hostName); + return false; + } + + // no cluster, valid host; return true return true; } + // at this point the following criteria is guaranteed, so get the cluster + // - a cluster exists + // - this is not for AMBARI_SERVER component final Cluster cluster; try { cluster = m_clusters.get().getCluster(clusterName); @@ -366,24 +391,50 @@ public class AlertReceivedListener { return false; } + // at this point the following criteria is guaranteed + // - a cluster exists + // - this is not for AMBARI_SERVER component + // + // if the alert is for AMBARI/AMBARI_AGENT, then it's valid IFF + // the agent's host is still a part of the reported cluster + if (ambariServiceName.equals(serviceName) && ambariAgentComponentName.equals(componentName)) { + // agents MUST report a hostname + if (StringUtils.isBlank(hostName) || !m_clusters.get().hostExists(hostName) + || !m_clusters.get().isHostMappedToCluster(clusterName, hostName)) { + LOG.warn( + "Unable to process alert {} for cluster {} and host {} because the host is not a part of the cluster.", + alert.getName(), clusterName, hostName); + + return false; + } + + // AMBARI/AMBARI_AGENT and valid host; return true + return true; + } + + // at this point the following criteria is guaranteed + // - a cluster exists + // - not for the AMBARI service if (StringUtils.isNotBlank(hostName)) { // if valid hostname if (!m_clusters.get().hostExists(hostName)) { - LOG.error("Unable to process alert {} for an invalid host named {}", + LOG.warn("Unable to process alert {} for an invalid host named {}", alert.getName(), hostName); return false; } + if (!cluster.getServices().containsKey(serviceName)) { - LOG.error("Unable to process alert {} for an invalid service named {}", + LOG.warn("Unable to process alert {} for an invalid service named {}", alert.getName(), serviceName); return false; } + // if the alert is for a host/component then verify that the component // is actually installed on that host if (null != componentName && !cluster.getHosts(serviceName, componentName).contains(hostName)) { - LOG.error( + LOG.warn( "Unable to process alert {} for an invalid service {} and component {} on host {}", alert.getName(), serviceName, componentName, hostName); return false; http://git-wip-us.apache.org/repos/asf/ambari/blob/7cb6382d/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostDAO.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostDAO.java index ebd29e3..d367eb3 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostDAO.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostDAO.java @@ -18,20 +18,22 @@ 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.HostEntity; -import org.apache.ambari.server.orm.entities.StageEntity; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import javax.persistence.EntityManager; import javax.persistence.NoResultException; import javax.persistence.TypedQuery; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; + +import org.apache.ambari.server.orm.RequiresSession; +import org.apache.ambari.server.orm.entities.HostEntity; +import org.apache.ambari.server.orm.entities.StageEntity; + +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.Singleton; +import com.google.inject.persist.Transactional; @Singleton public class HostDAO { @@ -113,11 +115,6 @@ public class HostDAO { entityManagerProvider.get().remove(merge(hostEntity)); } - @Transactional - public void removeByName(String hostName) { - remove(findByName(hostName)); - } - public List<String> getHostNamesByHostIds(List<Long> hostIds) { List<String> hostNames = new ArrayList<String>(); if (hostIds != null) { http://git-wip-us.apache.org/repos/asf/ambari/blob/7cb6382d/ambari-server/src/main/java/org/apache/ambari/server/state/Clusters.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/Clusters.java b/ambari-server/src/main/java/org/apache/ambari/server/state/Clusters.java index a1ebaba..59dcaf8 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/Clusters.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/Clusters.java @@ -18,12 +18,12 @@ package org.apache.ambari.server.state; -import org.apache.ambari.server.AmbariException; - import java.util.List; import java.util.Map; import java.util.Set; +import org.apache.ambari.server.AmbariException; + /** * Single entity that tracks all clusters and hosts that are managed * by the Ambari server @@ -37,7 +37,7 @@ public interface Clusters { * @param stackId * the stack for the cluster (not {@code null}). */ - public void addCluster(String clusterName, StackId stackId) + void addCluster(String clusterName, StackId stackId) throws AmbariException; /** @@ -50,7 +50,7 @@ public interface Clusters { * the cluster will be created with this security type. * @throws AmbariException */ - public void addCluster(String clusterName, StackId stackId, SecurityType securityType) + void addCluster(String clusterName, StackId stackId, SecurityType securityType) throws AmbariException; /** @@ -58,20 +58,20 @@ public interface Clusters { * @param clusterName Name of the Cluster to retrieve * @return <code>Cluster</code> identified by the given name */ - public Cluster getCluster(String clusterName) + Cluster getCluster(String clusterName) throws AmbariException; /** * Get all clusters * @return <code>Map</code> of clusters with cluster name as key */ - public Map<String, Cluster> getClusters(); + Map<String, Cluster> getClusters(); /** * Get all hosts being tracked by the Ambari server * @return <code>List</code> of <code>Host</code> */ - public List<Host> getHosts(); + List<Host> getHosts(); /** * Returns all the cluster names for this hostname @@ -79,7 +79,7 @@ public interface Clusters { * @return List of cluster names * @throws AmbariException */ - public Set<Cluster> getClustersForHost(String hostname) + Set<Cluster> getClustersForHost(String hostname) throws AmbariException; @@ -89,14 +89,26 @@ public interface Clusters { * @return Host object * @throws AmbariException */ - public Host getHost(String hostname) throws AmbariException; + Host getHost(String hostname) throws AmbariException; /** * Check if host exists * @param hostname Name of the host requested * @return is host exists */ - public boolean hostExists(String hostname); + boolean hostExists(String hostname); + + /** + * Gets whether the specified cluster has a mapping for the specified host. + * + * @param clusterName + * the cluster (not {@code null}). + * @param hostName + * the host (not {@code null}). + * @return {@code true} if the host belongs to the cluster, {@code false} + * otherwise. + */ + boolean isHostMappedToCluster(String clusterName, String hostName); /** * Get a Host object managed by this server @@ -104,14 +116,14 @@ public interface Clusters { * @return Host object * @throws AmbariException */ - public Host getHostById(Long hostId) throws AmbariException; + Host getHostById(Long hostId) throws AmbariException; /** * Add a Host object to be managed by this server * @param hostname Host to be added * @throws AmbariException */ - public void addHost(String hostname) throws AmbariException; + void addHost(String hostname) throws AmbariException; /** * Map host to the given cluster. @@ -120,7 +132,7 @@ public interface Clusters { * @param clusterName * @throws AmbariException */ - public void mapHostToCluster(String hostname, String clusterName) + void mapHostToCluster(String hostname, String clusterName) throws AmbariException; /** @@ -129,7 +141,7 @@ public interface Clusters { * @param clusterName * @throws AmbariException */ - public void mapHostsToCluster(Set<String> hostnames, String clusterName) + void mapHostsToCluster(Set<String> hostnames, String clusterName) throws AmbariException; /** @@ -138,7 +150,7 @@ public interface Clusters { * @param newName * @throws AmbariException */ - public void updateClusterName(String oldName, String newName); + void updateClusterName(String oldName, String newName); /** * Gets the cluster using the id. @@ -146,13 +158,13 @@ public interface Clusters { * @return <code>Cluster</code> identified by the identifier * @throws AmbariException */ - public Cluster getClusterById(long id) throws AmbariException; + Cluster getClusterById(long id) throws AmbariException; /** * Produces a debug dump into the supplied string buffer * @param sb The string buffer to add the debug dump to */ - public void debugDump(StringBuilder sb); + void debugDump(StringBuilder sb); /** * Gets all the hosts associated with the cluster @@ -160,7 +172,7 @@ public interface Clusters { * @return <code>Map</code> containing host name and <code>Host</code> * @throws AmbariException */ - public Map<String, Host> getHostsForCluster(String clusterName) + Map<String, Host> getHostsForCluster(String clusterName) throws AmbariException; /** @@ -169,7 +181,7 @@ public interface Clusters { * @return <code>Map</code> containing host id and <code>Host</code> * @throws AmbariException */ - public Map<Long, Host> getHostIdsForCluster(String clusterName) + Map<Long, Host> getHostIdsForCluster(String clusterName) throws AmbariException; /** @@ -177,7 +189,7 @@ public interface Clusters { * @param clusterName The name of the cluster * @throws AmbariException */ - public void deleteCluster(String clusterName) + void deleteCluster(String clusterName) throws AmbariException; /** @@ -186,7 +198,7 @@ public interface Clusters { * @param stackId The identifier for the stack * @throws AmbariException */ - public void setCurrentStackVersion(String clusterName, StackId stackId) + void setCurrentStackVersion(String clusterName, StackId stackId) throws AmbariException; /** @@ -195,7 +207,7 @@ public interface Clusters { * @param hostAttributes * @throws AmbariException */ - public void updateHostWithClusterAndAttributes( + void updateHostWithClusterAndAttributes( Map<String, Set<String>> hostsClusters, Map<String, Map<String, String>> hostAttributes) throws AmbariException; @@ -204,14 +216,14 @@ public interface Clusters { * @param hostname * @param clusterName */ - public void unmapHostFromCluster(String hostname, String clusterName) + void unmapHostFromCluster(String hostname, String clusterName) throws AmbariException; /** * Removes a host. Inverts {@link #addHost(String)} * @param hostname */ - public void deleteHost(String hostname) + void deleteHost(String hostname) throws AmbariException; /** @@ -224,7 +236,7 @@ public interface Clusters { * * @return true if access to the cluster is allowed */ - public boolean checkPermission(String clusterName, boolean readOnly); + boolean checkPermission(String clusterName, boolean readOnly); /** * Add the given map of attributes to the session for the cluster identified by the given name. @@ -232,7 +244,7 @@ public interface Clusters { * @param name the cluster name * @param attributes the session attributes */ - public void addSessionAttributes(String name, Map<String, Object> attributes); + void addSessionAttributes(String name, Map<String, Object> attributes); /** * Get the map of session attributes for the cluster identified by the given name. @@ -241,5 +253,5 @@ public interface Clusters { * * @return the map of session attributes for the cluster; never null */ - public Map<String, Object> getSessionAttributes(String name); + Map<String, Object> getSessionAttributes(String name); } http://git-wip-us.apache.org/repos/asf/ambari/blob/7cb6382d/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 8d1b7bd..68b125f 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 @@ -18,10 +18,20 @@ package org.apache.ambari.server.state.cluster; -import com.google.common.collect.Sets; -import com.google.inject.Inject; -import com.google.inject.Singleton; -import com.google.inject.persist.Transactional; +import java.util.ArrayList; +import java.util.Collection; +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.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import javax.persistence.RollbackException; + import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.ClusterNotFoundException; import org.apache.ambari.server.DuplicateResourceException; @@ -81,18 +91,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.core.GrantedAuthority; -import javax.persistence.RollbackException; -import java.util.ArrayList; -import java.util.Collection; -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.concurrent.ConcurrentHashMap; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantReadWriteLock; +import com.google.common.collect.Sets; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.google.inject.persist.Transactional; @Singleton public class ClustersImpl implements Clusters { @@ -377,6 +379,28 @@ public class ClustersImpl implements Clusters { return hosts.containsKey(hostname); } + /** + * {@inheritDoc} + */ + @Override + public boolean isHostMappedToCluster(String clusterName, String hostName) { + checkLoaded(); + + r.lock(); + try { + Set<Cluster> clusters = hostClusterMap.get(hostName); + for (Cluster cluster : clusters) { + if (clusterName.equals(cluster.getClusterName())) { + return true; + } + } + } finally { + r.unlock(); + } + + return false; + } + @Override public Host getHostById(Long hostId) throws AmbariException { checkLoaded(); @@ -859,8 +883,9 @@ public class ClustersImpl implements Clusters { // This will also remove from kerberos_principal_hosts, hostconfigmapping, and configgrouphostmapping Set<Cluster> clusters = hostClusterMap.get(hostname); Set<Long> clusterIds = Sets.newHashSet(); - for (Cluster cluster: clusters) + for (Cluster cluster: clusters) { clusterIds.add(cluster.getClusterId()); + } http://git-wip-us.apache.org/repos/asf/ambari/blob/7cb6382d/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertReceivedListenerTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertReceivedListenerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertReceivedListenerTest.java index 136a756..775fe83 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertReceivedListenerTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertReceivedListenerTest.java @@ -22,6 +22,8 @@ import static org.junit.Assert.assertEquals; import java.util.List; import java.util.UUID; +import org.apache.ambari.server.controller.RootServiceResponseFactory.Components; +import org.apache.ambari.server.controller.RootServiceResponseFactory.Services; import org.apache.ambari.server.events.AlertReceivedEvent; import org.apache.ambari.server.events.listeners.alerts.AlertReceivedListener; import org.apache.ambari.server.orm.GuiceJpaInitializer; @@ -306,4 +308,124 @@ public class AlertReceivedListenerTest { current = allCurrent.get(0); assertEquals(MaintenanceState.ON, current.getMaintenanceState()); } + + /** + * Tests that an invalid host from a host-level agent alert is rejected. + */ + @Test + public void testAgentAlertFromInvalidHost() { + String definitionName = ALERT_DEFINITION + "1"; + String serviceName = Services.AMBARI.name(); + String componentName = Components.AMBARI_AGENT.name(); + + Alert alert1 = new Alert(definitionName, null, serviceName, componentName, HOST1, + AlertState.OK); + + alert1.setCluster(m_cluster.getClusterName()); + alert1.setLabel(ALERT_LABEL); + alert1.setText(serviceName + " " + componentName + " is OK"); + alert1.setTimestamp(1L); + + // verify that the listener works with a regular alert + AlertReceivedListener listener = m_injector.getInstance(AlertReceivedListener.class); + AlertReceivedEvent event1 = new AlertReceivedEvent(m_cluster.getClusterId(), alert1); + listener.onAlertEvent(event1); + + List<AlertCurrentEntity> allCurrent = m_dao.findCurrent(); + assertEquals(1, allCurrent.size()); + + // invalid host + alert1.setHostName("INVALID"); + + // remove all + m_dao.removeCurrentByHost(HOST1); + allCurrent = m_dao.findCurrent(); + assertEquals(0, allCurrent.size()); + + // verify no new alerts received + listener.onAlertEvent(event1); + allCurrent = m_dao.findCurrent(); + assertEquals(0, allCurrent.size()); + } + + /** + * Tests that an alert for AMBARI/AMBARI_SERVER is always valid. + */ + @Test + public void testAmbariServerValidAlerts() { + String definitionName = ALERT_DEFINITION + "1"; + String serviceName = Services.AMBARI.name(); + String componentName = Components.AMBARI_SERVER.name(); + + Alert alert1 = new Alert(definitionName, null, serviceName, componentName, HOST1, + AlertState.OK); + + alert1.setCluster(m_cluster.getClusterName()); + alert1.setLabel(ALERT_LABEL); + alert1.setText(serviceName + " " + componentName + " is OK"); + alert1.setTimestamp(1L); + + // verify that the listener works with a regular alert + AlertReceivedListener listener = m_injector.getInstance(AlertReceivedListener.class); + AlertReceivedEvent event1 = new AlertReceivedEvent(m_cluster.getClusterId(), alert1); + listener.onAlertEvent(event1); + + List<AlertCurrentEntity> allCurrent = m_dao.findCurrent(); + assertEquals(1, allCurrent.size()); + + // invalid host, invalid cluster + alert1.setHostName("INVALID"); + alert1.setCluster("INVALID"); + + // remove all + m_dao.removeCurrentByHost(HOST1); + allCurrent = m_dao.findCurrent(); + assertEquals(0, allCurrent.size()); + + // verify that the alert was still received + listener.onAlertEvent(event1); + allCurrent = m_dao.findCurrent(); + assertEquals(1, allCurrent.size()); + } + + /** + * Tests that an invalid host from an invalid cluster does not trigger an + * alert. + */ + @Test + public void testMissingClusterAndInvalidHost() { + String definitionName = ALERT_DEFINITION + "1"; + String serviceName = Services.AMBARI.name(); + String componentName = Components.AMBARI_AGENT.name(); + + Alert alert1 = new Alert(definitionName, null, serviceName, componentName, HOST1, + AlertState.OK); + + alert1.setCluster(m_cluster.getClusterName()); + alert1.setLabel(ALERT_LABEL); + alert1.setText(serviceName + " " + componentName + " is OK"); + alert1.setTimestamp(1L); + + // verify that the listener works with a regular alert + AlertReceivedListener listener = m_injector.getInstance(AlertReceivedListener.class); + AlertReceivedEvent event1 = new AlertReceivedEvent(m_cluster.getClusterId(), alert1); + listener.onAlertEvent(event1); + + List<AlertCurrentEntity> allCurrent = m_dao.findCurrent(); + assertEquals(1, allCurrent.size()); + + // missing cluster, invalid host + alert1.setCluster(null); + alert1.setHostName("INVALID"); + + // remove all + m_dao.removeCurrentByHost(HOST1); + allCurrent = m_dao.findCurrent(); + assertEquals(0, allCurrent.size()); + + // verify no new alerts received + listener.onAlertEvent(event1); + allCurrent = m_dao.findCurrent(); + assertEquals(0, allCurrent.size()); + } }
