AMBARI-20851 - Provide Alert For Component OUT_OF_SYNC Issues (jonathanhurley)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/6a0b2a0e Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/6a0b2a0e Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/6a0b2a0e Branch: refs/heads/branch-feature-AMBARI-12556 Commit: 6a0b2a0e2be6901b13db0787fa70ff98905b19da Parents: bd1b2c9 Author: Jonathan Hurley <jhur...@hortonworks.com> Authored: Tue Apr 25 18:56:02 2017 -0400 Committer: Jonathan Hurley <jhur...@hortonworks.com> Committed: Wed Apr 26 13:21:01 2017 -0400 ---------------------------------------------------------------------- .../ambari/server/alerts/AlertRunnable.java | 27 ++ .../alerts/ComponentVersionAlertRunnable.java | 195 ++++++++++ ambari-server/src/main/resources/alerts.json | 12 + .../ComponentVersionAlertRunnableTest.java | 362 +++++++++++++++++++ .../server/api/services/AmbariMetaInfoTest.java | 14 +- .../metadata/AgentAlertDefinitionsTest.java | 2 +- 6 files changed, 604 insertions(+), 8 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/6a0b2a0e/ambari-server/src/main/java/org/apache/ambari/server/alerts/AlertRunnable.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/alerts/AlertRunnable.java b/ambari-server/src/main/java/org/apache/ambari/server/alerts/AlertRunnable.java index ea583e4..057a273 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/alerts/AlertRunnable.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/alerts/AlertRunnable.java @@ -27,6 +27,7 @@ import org.apache.ambari.server.events.publishers.AlertEventPublisher; import org.apache.ambari.server.orm.dao.AlertDefinitionDAO; import org.apache.ambari.server.orm.entities.AlertDefinitionEntity; import org.apache.ambari.server.state.Alert; +import org.apache.ambari.server.state.AlertState; import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.Clusters; import org.apache.commons.lang.math.NumberUtils; @@ -162,4 +163,30 @@ public abstract class AlertRunnable implements Runnable { Number number = NumberUtils.createNumber((String) value); return number.intValue(); } + + /** + * Builds an {@link Alert} instance. + * + * @param cluster + * the cluster the alert is for (not {@code null}). + * @param myDefinition + * the alert's definition (not {@code null}). + * @param alertState + * the state of the alert (not {@code null}). + * @param message + * the alert text. + * @return and alert. + */ + protected Alert buildAlert(Cluster cluster, AlertDefinitionEntity myDefinition, + AlertState alertState, String message) { + Alert alert = new Alert(myDefinition.getDefinitionName(), null, myDefinition.getServiceName(), + myDefinition.getComponentName(), null, alertState); + + alert.setLabel(myDefinition.getLabel()); + alert.setText(message); + alert.setTimestamp(System.currentTimeMillis()); + alert.setCluster(cluster.getClusterName()); + + return alert; + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/6a0b2a0e/ambari-server/src/main/java/org/apache/ambari/server/alerts/ComponentVersionAlertRunnable.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/alerts/ComponentVersionAlertRunnable.java b/ambari-server/src/main/java/org/apache/ambari/server/alerts/ComponentVersionAlertRunnable.java new file mode 100644 index 0000000..7dfbe47 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/alerts/ComponentVersionAlertRunnable.java @@ -0,0 +1,195 @@ +/** + * 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.alerts; + +import java.text.MessageFormat; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.TreeMap; + +import org.apache.ambari.server.AmbariException; +import org.apache.ambari.server.api.services.AmbariMetaInfo; +import org.apache.ambari.server.orm.entities.AlertDefinitionEntity; +import org.apache.ambari.server.orm.entities.ClusterVersionEntity; +import org.apache.ambari.server.orm.entities.RepositoryVersionEntity; +import org.apache.ambari.server.orm.entities.UpgradeEntity; +import org.apache.ambari.server.state.Alert; +import org.apache.ambari.server.state.AlertState; +import org.apache.ambari.server.state.Cluster; +import org.apache.ambari.server.state.ComponentInfo; +import org.apache.ambari.server.state.Host; +import org.apache.ambari.server.state.ServiceComponentHost; +import org.apache.ambari.server.state.StackId; +import org.apache.ambari.server.state.State; +import org.apache.commons.lang.StringUtils; + +import com.google.inject.Inject; + +/** + * The {@link ComponentVersionAlertRunnable} is used to determine if the + * reported version of host components match what is expected. If there is a + * mismatch, then an alert will be triggered indicating which components are in + * need of attention. + * <p/> + * This alert will not run during upgrades or when the cluster is still being + * provisioned. + */ +public class ComponentVersionAlertRunnable extends AlertRunnable { + + /** + * The message for the alert when all components are reporting correct + * versions. + */ + private static final String ALL_COMPONENTS_CORRECT_MSG = "All components are reporting their expected versions."; + + /** + * The message for the alert when there is an upgrade in progress. + */ + private static final String UPGRADE_IN_PROGRESS_MSG = "This alert will be suspended while the upgrade to {0} is in progress."; + + /** + * The unknown component error message. + */ + private static final String UNKNOWN_COMPONENT_MSG_TEMPLATE = "Unable to retrieve component information for {0}/{1}"; + + /** + * The version mismatch message. + */ + private static final String MISMATCHED_VERSIONS_MSG = "The following components are reporting unexpected versions: "; + + /** + * The message when there is no CURRENT cluster version, but the cluster is + * still being setup. + */ + private static final String CLUSTER_PROVISIONING_MSG = "The cluster is currently being provisioned. This alert will be skipped."; + + /** + * The message when there is no CURRENT cluster version. + */ + private static final String CLUSTER_OUT_OF_SYNC_MSG = "The cluster's CURRENT version could not be determined."; + + @Inject + private AmbariMetaInfo m_metaInfo; + + /** + * Constructor. + * + * @param definitionName + */ + public ComponentVersionAlertRunnable(String definitionName) { + super(definitionName); + } + + /** + * {@inheritDoc} + */ + @Override + List<Alert> execute(Cluster cluster, AlertDefinitionEntity myDefinition) { + // if there is an upgrade in progress, then skip running this alert + UpgradeEntity upgrade = cluster.getUpgradeInProgress(); + if (null != upgrade) { + String message = MessageFormat.format(UPGRADE_IN_PROGRESS_MSG, upgrade.getToVersion()); + + return Collections.singletonList( + buildAlert(cluster, myDefinition, AlertState.SKIPPED, message)); + } + + TreeMap<Host, Set<ServiceComponentHost>> versionMismatches = new TreeMap<>(); + Collection<Host> hosts = cluster.getHosts(); + + // no cluster version is very bad ... + ClusterVersionEntity clusterVersionEntity = cluster.getCurrentClusterVersion(); + if (null == clusterVersionEntity) { + if (cluster.getProvisioningState() == State.INIT + || cluster.getAllClusterVersions().size() == 1) { + return Collections.singletonList( + buildAlert(cluster, myDefinition, AlertState.SKIPPED, CLUSTER_PROVISIONING_MSG)); + } else { + return Collections.singletonList( + buildAlert(cluster, myDefinition, AlertState.CRITICAL, CLUSTER_OUT_OF_SYNC_MSG)); + } + } + + RepositoryVersionEntity repositoryVersionEntity = clusterVersionEntity.getRepositoryVersion(); + String clusterVersion = repositoryVersionEntity.getVersion(); + + for (Host host : hosts) { + List<ServiceComponentHost> hostComponents = cluster.getServiceComponentHosts( + host.getHostName()); + for (ServiceComponentHost hostComponent : hostComponents) { + StackId desiredStackId = hostComponent.getDesiredStackVersion(); + + final ComponentInfo componentInfo; + try { + componentInfo = m_metaInfo.getComponent(desiredStackId.getStackName(), + desiredStackId.getStackVersion(), hostComponent.getServiceName(), + hostComponent.getServiceComponentName()); + } catch (AmbariException ambariException) { + // throw an UNKNOWN response if we can't load component info + String message = MessageFormat.format(UNKNOWN_COMPONENT_MSG_TEMPLATE, + hostComponent.getServiceName(), hostComponent.getServiceComponentName()); + + return Collections.singletonList( + buildAlert(cluster, myDefinition, AlertState.UNKNOWN, message)); + } + + // skip components that don't advertise a version + if (!componentInfo.isVersionAdvertised()) { + continue; + } + + String version = hostComponent.getVersion(); + if (!StringUtils.equals(version, clusterVersion)) { + Set<ServiceComponentHost> mismatchedComponents = versionMismatches.get(host); + if (null == mismatchedComponents) { + mismatchedComponents = new HashSet<>(); + versionMismatches.put(host, mismatchedComponents); + } + + mismatchedComponents.add(hostComponent); + } + } + } + + AlertState alertState = AlertState.OK; + String alertText = ALL_COMPONENTS_CORRECT_MSG; + + // if there are any components reporting the wrong version, fire off a warning + if (!versionMismatches.isEmpty()) { + StringBuilder buffer = new StringBuilder(MISMATCHED_VERSIONS_MSG); + buffer.append(System.lineSeparator()); + + for (Host host : versionMismatches.keySet()) { + buffer.append(" ").append(host.getHostName()); + buffer.append(System.lineSeparator()); + for (ServiceComponentHost hostComponent : versionMismatches.get(host)) { + buffer.append(" ").append(hostComponent.getServiceComponentName()).append(": ").append( + hostComponent.getVersion()).append(System.lineSeparator()); + } + } + + alertText = buffer.toString(); + alertState = AlertState.WARNING; + } + + return Collections.singletonList(buildAlert(cluster, myDefinition, alertState, alertText)); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/6a0b2a0e/ambari-server/src/main/resources/alerts.json ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/alerts.json b/ambari-server/src/main/resources/alerts.json index d646401..732aae0 100644 --- a/ambari-server/src/main/resources/alerts.json +++ b/ambari-server/src/main/resources/alerts.json @@ -106,6 +106,18 @@ } ] } + }, + { + "name": "ambari_server_component_version", + "label": "Component Version", + "description": "This alert is triggered if the server detects that there is a problem with the expected and reported version of a component. The alert is suppressed automatically during an upgrade.", + "interval": 5, + "scope": "SERVICE", + "enabled": true, + "source": { + "type": "SERVER", + "class": "org.apache.ambari.server.alerts.ComponentVersionAlertRunnable" + } } ], "AMBARI_AGENT" : [ http://git-wip-us.apache.org/repos/asf/ambari/blob/6a0b2a0e/ambari-server/src/test/java/org/apache/ambari/server/alerts/ComponentVersionAlertRunnableTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/alerts/ComponentVersionAlertRunnableTest.java b/ambari-server/src/test/java/org/apache/ambari/server/alerts/ComponentVersionAlertRunnableTest.java new file mode 100644 index 0000000..98f6f44 --- /dev/null +++ b/ambari-server/src/test/java/org/apache/ambari/server/alerts/ComponentVersionAlertRunnableTest.java @@ -0,0 +1,362 @@ +/** + * 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.alerts; + +import static junit.framework.Assert.assertEquals; +import static org.easymock.EasyMock.expect; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.persistence.EntityManager; + +import org.apache.ambari.server.api.services.AmbariMetaInfo; +import org.apache.ambari.server.events.AlertEvent; +import org.apache.ambari.server.events.AlertReceivedEvent; +import org.apache.ambari.server.events.MockEventListener; +import org.apache.ambari.server.events.publishers.AlertEventPublisher; +import org.apache.ambari.server.orm.DBAccessor; +import org.apache.ambari.server.orm.dao.AlertDefinitionDAO; +import org.apache.ambari.server.orm.entities.AlertDefinitionEntity; +import org.apache.ambari.server.orm.entities.ClusterVersionEntity; +import org.apache.ambari.server.orm.entities.RepositoryVersionEntity; +import org.apache.ambari.server.orm.entities.UpgradeEntity; +import org.apache.ambari.server.stack.StackManagerFactory; +import org.apache.ambari.server.state.Alert; +import org.apache.ambari.server.state.AlertState; +import org.apache.ambari.server.state.Cluster; +import org.apache.ambari.server.state.Clusters; +import org.apache.ambari.server.state.ComponentInfo; +import org.apache.ambari.server.state.Host; +import org.apache.ambari.server.state.ServiceComponentHost; +import org.apache.ambari.server.state.StackId; +import org.apache.ambari.server.state.stack.OsFamily; +import org.easymock.EasyMock; +import org.easymock.EasyMockSupport; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.google.common.eventbus.EventBus; +import com.google.inject.Binder; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.Module; + +/** + * Tests {@link ComponentVersionAlertRunnable}. + */ +public class ComponentVersionAlertRunnableTest extends EasyMockSupport { + + private final static long CLUSTER_ID = 1; + private final static String CLUSTER_NAME = "c1"; + private final static String HOSTNAME_1 = "c6401.ambari.apache.org"; + private final static String HOSTNAME_2 = "c6402.ambari.apache.org"; + + private final static String EXPECTED_VERSION = "2.6.0.0-1234"; + private final static String WRONG_VERSION = "9.9.9.9-9999"; + + private final static String DEFINITION_NAME = "ambari_server_component_version"; + private final static String DEFINITION_SERVICE = "AMBARI"; + private final static String DEFINITION_COMPONENT = "AMBARI_SERVER"; + private final static String DEFINITION_LABEL = "Mock Definition"; + + private Clusters m_clusters; + private Cluster m_cluster; + private Injector m_injector; + private AlertDefinitionDAO m_definitionDao; + private AlertDefinitionEntity m_definition; + private MockEventListener m_listener; + private AmbariMetaInfo m_metaInfo; + + private AlertEventPublisher m_eventPublisher; + private EventBus m_synchronizedBus; + + private Collection<Host> m_hosts; + private Map<String, List<ServiceComponentHost>> m_hostComponentMap = new HashMap<>(); + private StackId m_desidredStackId; + + /** + * + */ + @Before + public void setup() throws Exception { + m_injector = Guice.createInjector(new MockModule()); + m_definitionDao = m_injector.getInstance(AlertDefinitionDAO.class); + m_clusters = m_injector.getInstance(Clusters.class); + m_cluster = m_injector.getInstance(Cluster.class); + m_eventPublisher = m_injector.getInstance(AlertEventPublisher.class); + m_listener = m_injector.getInstance(MockEventListener.class); + m_definition = createNiceMock(AlertDefinitionEntity.class); + m_metaInfo = m_injector.getInstance(AmbariMetaInfo.class); + + // !!! need a synchronous op for testing + m_synchronizedBus = new EventBus(); + Field field = AlertEventPublisher.class.getDeclaredField("m_eventBus"); + field.setAccessible(true); + field.set(m_eventPublisher, m_synchronizedBus); + + // register mock listener + m_synchronizedBus.register(m_listener); + + // create the cluster map + Map<String,Cluster> clusterMap = new HashMap<>(); + clusterMap.put(CLUSTER_NAME, m_cluster); + + // hosts + m_hosts = new ArrayList<>(); + Host host1 = createNiceMock(Host.class); + Host host2 = createNiceMock(Host.class); + expect(host1.getHostName()).andReturn(HOSTNAME_1).atLeastOnce(); + expect(host2.getHostName()).andReturn(HOSTNAME_2).atLeastOnce(); + m_hosts.add(host1); + m_hosts.add(host2); + + m_hostComponentMap.put(HOSTNAME_1, new ArrayList<ServiceComponentHost>()); + m_hostComponentMap.put(HOSTNAME_2, new ArrayList<ServiceComponentHost>()); + + // desired stack + m_desidredStackId = createNiceMock(StackId.class); + expect(m_desidredStackId.getStackName()).andReturn("SOME-STACK").atLeastOnce(); + expect(m_desidredStackId.getStackVersion()).andReturn("STACK-VERSION").atLeastOnce(); + + // components + ServiceComponentHost sch1_1 = createNiceMock(ServiceComponentHost.class); + ServiceComponentHost sch1_2 = createNiceMock(ServiceComponentHost.class); + ServiceComponentHost sch2_1 = createNiceMock(ServiceComponentHost.class); + ServiceComponentHost sch2_2 = createNiceMock(ServiceComponentHost.class); + + expect(sch1_1.getServiceName()).andReturn("FOO").atLeastOnce(); + expect(sch1_1.getServiceComponentName()).andReturn("FOO_COMPONENT").atLeastOnce(); + expect(sch1_1.getVersion()).andReturn(EXPECTED_VERSION).atLeastOnce(); + expect(sch1_1.getDesiredStackVersion()).andReturn(m_desidredStackId).atLeastOnce(); + expect(sch1_2.getServiceName()).andReturn("BAR").atLeastOnce(); + expect(sch1_2.getServiceComponentName()).andReturn("BAR_COMPONENT").atLeastOnce(); + expect(sch1_2.getVersion()).andReturn(EXPECTED_VERSION).atLeastOnce(); + expect(sch1_2.getDesiredStackVersion()).andReturn(m_desidredStackId).atLeastOnce(); + expect(sch2_1.getServiceName()).andReturn("FOO").atLeastOnce(); + expect(sch2_1.getServiceComponentName()).andReturn("FOO_COMPONENT").atLeastOnce(); + expect(sch2_1.getVersion()).andReturn(EXPECTED_VERSION).atLeastOnce(); + expect(sch2_1.getDesiredStackVersion()).andReturn(m_desidredStackId).atLeastOnce(); + expect(sch2_2.getServiceName()).andReturn("BAZ").atLeastOnce(); + expect(sch2_2.getServiceComponentName()).andReturn("BAZ_COMPONENT").atLeastOnce(); + expect(sch2_2.getVersion()).andReturn(EXPECTED_VERSION).atLeastOnce(); + expect(sch2_2.getDesiredStackVersion()).andReturn(m_desidredStackId).atLeastOnce(); + + m_hostComponentMap.get(HOSTNAME_1).add(sch1_1); + m_hostComponentMap.get(HOSTNAME_1).add(sch1_2); + m_hostComponentMap.get(HOSTNAME_2).add(sch2_1); + m_hostComponentMap.get(HOSTNAME_2).add(sch2_2); + + // mock the definition for the alert + expect(m_definition.getDefinitionName()).andReturn(DEFINITION_NAME).atLeastOnce(); + expect(m_definition.getServiceName()).andReturn(DEFINITION_SERVICE).atLeastOnce(); + expect(m_definition.getComponentName()).andReturn(DEFINITION_COMPONENT).atLeastOnce(); + expect(m_definition.getLabel()).andReturn(DEFINITION_LABEL).atLeastOnce(); + expect(m_definition.getEnabled()).andReturn(true).atLeastOnce(); + + // mock the cluster + expect(m_cluster.getClusterId()).andReturn(CLUSTER_ID).atLeastOnce(); + expect(m_cluster.getClusterName()).andReturn(CLUSTER_NAME).atLeastOnce(); + expect(m_cluster.getHosts()).andReturn(m_hosts).atLeastOnce(); + + ClusterVersionEntity clusterVersionEntity = createNiceMock(ClusterVersionEntity.class); + RepositoryVersionEntity repositoryVersionEntity = createNiceMock(RepositoryVersionEntity.class); + expect(clusterVersionEntity.getRepositoryVersion()).andReturn( + repositoryVersionEntity).anyTimes(); + + expect(repositoryVersionEntity.getVersion()).andReturn(EXPECTED_VERSION).anyTimes(); + expect(m_cluster.getCurrentClusterVersion()).andReturn(clusterVersionEntity).anyTimes(); + + // mock clusters + expect(m_clusters.getClusters()).andReturn(clusterMap).atLeastOnce(); + + // mock the definition DAO + expect(m_definitionDao.findByName(CLUSTER_ID, DEFINITION_NAME)).andReturn( + m_definition).atLeastOnce(); + + m_metaInfo.init(); + EasyMock.expectLastCall().anyTimes(); + + // expect the cluster host mapping + expect(m_cluster.getServiceComponentHosts(HOSTNAME_1)).andReturn( + m_hostComponentMap.get(HOSTNAME_1)).once(); + expect(m_cluster.getServiceComponentHosts(HOSTNAME_2)).andReturn( + m_hostComponentMap.get(HOSTNAME_2)).once(); + + // expect the component from metainfo + ComponentInfo componentInfo = createNiceMock(ComponentInfo.class); + expect(componentInfo.isVersionAdvertised()).andReturn(true).atLeastOnce(); + expect(m_metaInfo.getComponent(EasyMock.anyString(), EasyMock.anyString(), EasyMock.anyString(), + EasyMock.anyString())).andReturn(componentInfo).atLeastOnce(); + } + + /** + * @throws Exception + */ + @After + public void teardown() throws Exception { + } + + /** + * Tests that the alert is SKIPPED when there is an upgrade in progress. + */ + @Test + public void testUpgradeInProgress() throws Exception { + UpgradeEntity upgrade = createNiceMock(UpgradeEntity.class); + expect(upgrade.getToVersion()).andReturn("VERSION").once(); + expect(m_cluster.getUpgradeInProgress()).andReturn(upgrade).once(); + + replayAll(); + + m_metaInfo.init(); + + // precondition that no events were fired + assertEquals(0, m_listener.getAlertEventReceivedCount(AlertReceivedEvent.class)); + + // instantiate and inject mocks + ComponentVersionAlertRunnable runnable = new ComponentVersionAlertRunnable( + m_definition.getDefinitionName()); + + m_injector.injectMembers(runnable); + + // run the alert + runnable.run(); + + assertEquals(1, m_listener.getAlertEventReceivedCount(AlertReceivedEvent.class)); + + List<AlertEvent> events = m_listener.getAlertEventInstances(AlertReceivedEvent.class); + assertEquals(1, events.size()); + + AlertReceivedEvent event = (AlertReceivedEvent) events.get(0); + Alert alert = event.getAlert(); + assertEquals("AMBARI", alert.getService()); + assertEquals("AMBARI_SERVER", alert.getComponent()); + assertEquals(AlertState.SKIPPED, alert.getState()); + assertEquals(DEFINITION_NAME, alert.getName()); + } + + /** + * Tests the alert that fires when all components are reporting correct + * versions. + */ + @Test + public void testAllComponentVersionsCorrect() throws Exception { + replayAll(); + + m_metaInfo.init(); + + // precondition that no events were fired + assertEquals(0, m_listener.getAlertEventReceivedCount(AlertReceivedEvent.class)); + + // instantiate and inject mocks + ComponentVersionAlertRunnable runnable = new ComponentVersionAlertRunnable( + m_definition.getDefinitionName()); + + m_injector.injectMembers(runnable); + + // run the alert + runnable.run(); + + assertEquals(1, m_listener.getAlertEventReceivedCount(AlertReceivedEvent.class)); + + List<AlertEvent> events = m_listener.getAlertEventInstances(AlertReceivedEvent.class); + assertEquals(1, events.size()); + + AlertReceivedEvent event = (AlertReceivedEvent) events.get(0); + Alert alert = event.getAlert(); + assertEquals("AMBARI", alert.getService()); + assertEquals("AMBARI_SERVER", alert.getComponent()); + assertEquals(AlertState.OK, alert.getState()); + assertEquals(DEFINITION_NAME, alert.getName()); + + verifyAll(); + } + + /** + * Tests that the alert which fires when there is a mismatch is a WARNING. + */ + @Test + public void testomponentVersionMismatch() throws Exception { + // reset expectation so that it returns a wrong version + ServiceComponentHost sch = m_hostComponentMap.get(HOSTNAME_1).get(0); + EasyMock.reset(sch); + expect(sch.getServiceName()).andReturn("FOO").atLeastOnce(); + expect(sch.getServiceComponentName()).andReturn("FOO_COMPONENT").atLeastOnce(); + expect(sch.getVersion()).andReturn(WRONG_VERSION).atLeastOnce(); + expect(sch.getDesiredStackVersion()).andReturn(m_desidredStackId).atLeastOnce(); + + replayAll(); + + m_metaInfo.init(); + + // precondition that no events were fired + assertEquals(0, m_listener.getAlertEventReceivedCount(AlertReceivedEvent.class)); + + // instantiate and inject mocks + ComponentVersionAlertRunnable runnable = new ComponentVersionAlertRunnable( + m_definition.getDefinitionName()); + + m_injector.injectMembers(runnable); + + // run the alert + runnable.run(); + + assertEquals(1, m_listener.getAlertEventReceivedCount(AlertReceivedEvent.class)); + + List<AlertEvent> events = m_listener.getAlertEventInstances(AlertReceivedEvent.class); + assertEquals(1, events.size()); + + AlertReceivedEvent event = (AlertReceivedEvent) events.get(0); + Alert alert = event.getAlert(); + assertEquals("AMBARI", alert.getService()); + assertEquals("AMBARI_SERVER", alert.getComponent()); + assertEquals(AlertState.WARNING, alert.getState()); + assertEquals(DEFINITION_NAME, alert.getName()); + + verifyAll(); + } + + + /** + * + */ + private class MockModule implements Module { + /** + * + */ + @Override + public void configure(Binder binder) { + Cluster cluster = createNiceMock(Cluster.class); + + binder.bind(Clusters.class).toInstance(createNiceMock(Clusters.class)); + binder.bind(OsFamily.class).toInstance(createNiceMock(OsFamily.class)); + binder.bind(DBAccessor.class).toInstance(createNiceMock(DBAccessor.class)); + binder.bind(Cluster.class).toInstance(cluster); + binder.bind(AlertDefinitionDAO.class).toInstance(createNiceMock(AlertDefinitionDAO.class)); + binder.bind(EntityManager.class).toInstance(createNiceMock(EntityManager.class)); + binder.bind(AmbariMetaInfo.class).toInstance(createNiceMock(AmbariMetaInfo.class)); + binder.bind(StackManagerFactory.class).toInstance(createNiceMock(StackManagerFactory.class)); + } + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/6a0b2a0e/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java index 884777d..c9acfe9 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java @@ -1942,7 +1942,7 @@ public class AmbariMetaInfoTest { AlertDefinitionDAO dao = injector.getInstance(AlertDefinitionDAO.class); List<AlertDefinitionEntity> definitions = dao.findAll(clusterId); - assertEquals(12, definitions.size()); + assertEquals(13, definitions.size()); // figure out how many of these alerts were merged into from the // non-stack alerts.json @@ -1955,7 +1955,7 @@ public class AmbariMetaInfoTest { } assertEquals(3, hostAlertCount); - assertEquals(9, definitions.size() - hostAlertCount); + assertEquals(10, definitions.size() - hostAlertCount); for (AlertDefinitionEntity definition : definitions) { definition.setScheduleInterval(28); @@ -1965,7 +1965,7 @@ public class AmbariMetaInfoTest { metaInfo.reconcileAlertDefinitions(clusters); definitions = dao.findAll(); - assertEquals(12, definitions.size()); + assertEquals(13, definitions.size()); for (AlertDefinitionEntity definition : definitions) { assertEquals(28, definition.getScheduleInterval().intValue()); @@ -1974,7 +1974,7 @@ public class AmbariMetaInfoTest { // find all enabled for the cluster should find 6 (the ones from HDFS; // it will not find the agent alert since it's not bound to the cluster) definitions = dao.findAllEnabled(cluster.getClusterId()); - assertEquals(11, definitions.size()); + assertEquals(12, definitions.size()); // create new definition AlertDefinitionEntity entity = new AlertDefinitionEntity(); @@ -1993,19 +1993,19 @@ public class AmbariMetaInfoTest { // verify the new definition is found (6 HDFS + 1 new one) definitions = dao.findAllEnabled(cluster.getClusterId()); - assertEquals(12, definitions.size()); + assertEquals(13, definitions.size()); // reconcile, which should disable our bad definition metaInfo.reconcileAlertDefinitions(clusters); // find all enabled for the cluster should find 6 definitions = dao.findAllEnabled(cluster.getClusterId()); - assertEquals(11, definitions.size()); + assertEquals(12, definitions.size()); // find all should find 6 HDFS + 1 disabled + 1 agent alert + 2 server // alerts definitions = dao.findAll(); - assertEquals(13, definitions.size()); + assertEquals(14, definitions.size()); entity = dao.findById(entity.getDefinitionId()); assertFalse(entity.getEnabled()); http://git-wip-us.apache.org/repos/asf/ambari/blob/6a0b2a0e/ambari-server/src/test/java/org/apache/ambari/server/metadata/AgentAlertDefinitionsTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/metadata/AgentAlertDefinitionsTest.java b/ambari-server/src/test/java/org/apache/ambari/server/metadata/AgentAlertDefinitionsTest.java index 7378b8c..e893503f 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/metadata/AgentAlertDefinitionsTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/metadata/AgentAlertDefinitionsTest.java @@ -77,7 +77,7 @@ public class AgentAlertDefinitionsTest { public void testLoadingServertAlerts() { AmbariServiceAlertDefinitions ambariServiceAlertDefinitions = m_injector.getInstance(AmbariServiceAlertDefinitions.class); List<AlertDefinition> definitions = ambariServiceAlertDefinitions.getServerDefinitions(); - Assert.assertEquals(3, definitions.size()); + Assert.assertEquals(4, definitions.size()); for (AlertDefinition definition : definitions) { Assert.assertEquals(Components.AMBARI_SERVER.name(),