/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.ambari.server.state.cluster; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.lang.reflect.Field; import java.sql.SQLException; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.UUID; import java.util.concurrent.atomic.AtomicReference; import javax.persistence.EntityManager; import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.H2DatabaseCleaner; import org.apache.ambari.server.events.AlertEvent; import org.apache.ambari.server.events.AlertReceivedEvent; import org.apache.ambari.server.events.AlertStateChangeEvent; import org.apache.ambari.server.events.listeners.alerts.AlertAggregateListener; import org.apache.ambari.server.events.listeners.alerts.AlertReceivedListener; import org.apache.ambari.server.events.listeners.alerts.AlertStateChangedListener; import org.apache.ambari.server.events.publishers.AlertEventPublisher; import org.apache.ambari.server.orm.GuiceJpaInitializer; import org.apache.ambari.server.orm.InMemoryDefaultTestModule; import org.apache.ambari.server.orm.OrmTestHelper; import org.apache.ambari.server.orm.dao.AlertDefinitionDAO; import org.apache.ambari.server.orm.dao.AlertDispatchDAO; import org.apache.ambari.server.orm.dao.AlertsDAO; import org.apache.ambari.server.orm.entities.AlertCurrentEntity; import org.apache.ambari.server.orm.entities.AlertDefinitionEntity; import org.apache.ambari.server.orm.entities.AlertGroupEntity; import org.apache.ambari.server.orm.entities.AlertHistoryEntity; import org.apache.ambari.server.orm.entities.AlertNoticeEntity; import org.apache.ambari.server.orm.entities.AlertTargetEntity; import org.apache.ambari.server.state.Alert; import org.apache.ambari.server.state.AlertFirmness; 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.MaintenanceState; import org.apache.ambari.server.state.ServiceComponentFactory; import org.apache.ambari.server.state.ServiceComponentHostFactory; import org.apache.ambari.server.state.ServiceFactory; import org.apache.ambari.server.state.alert.AggregateDefinitionMapping; import org.apache.ambari.server.state.alert.AggregateSource; import org.apache.ambari.server.state.alert.AlertDefinition; import org.apache.ambari.server.state.alert.AlertDefinitionFactory; import org.apache.ambari.server.state.alert.Reporting; import org.apache.ambari.server.state.alert.Reporting.ReportTemplate; import org.apache.ambari.server.state.alert.Scope; import org.apache.ambari.server.state.alert.Source; import org.apache.ambari.server.state.alert.SourceType; import org.apache.ambari.server.utils.EventBusSynchronizer; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.google.common.eventbus.Subscribe; import com.google.gson.Gson; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.persist.UnitOfWork; import junit.framework.Assert; /** * Tests the management of {@link AlertEvent}s in the system. */ public class AlertDataManagerTest { private static final String ALERT_DEFINITION = "Alert Definition 1"; private static final String SERVICE = "HDFS"; private static final String COMPONENT = "DATANODE"; private static final String HOST1 = "h1"; private static final String HOST2 = "h2"; private static final String ALERT_LABEL = "My Label"; private Injector m_injector; private OrmTestHelper m_helper; private Clusters m_clusters; private Cluster m_cluster; private AlertsDAO m_dao; private AlertDispatchDAO m_dispatchDao; private AlertDefinitionDAO m_definitionDao; private ServiceFactory m_serviceFactory; private ServiceComponentFactory m_componentFactory; private ServiceComponentHostFactory m_schFactory; @Before public void setup() throws Exception { m_injector = Guice.createInjector(new InMemoryDefaultTestModule()); EventBusSynchronizer.synchronizeAlertEventPublisher(m_injector); EventBusSynchronizer.synchronizeAmbariEventPublisher(m_injector); m_injector.getInstance(GuiceJpaInitializer.class); m_injector.getInstance(UnitOfWork.class).begin(); m_helper = m_injector.getInstance(OrmTestHelper.class); m_dao = m_injector.getInstance(AlertsDAO.class); m_dispatchDao = m_injector.getInstance(AlertDispatchDAO.class); m_definitionDao = m_injector.getInstance(AlertDefinitionDAO.class); m_clusters = m_injector.getInstance(Clusters.class); m_serviceFactory = m_injector.getInstance(ServiceFactory.class); m_componentFactory = m_injector.getInstance(ServiceComponentFactory.class); m_schFactory = m_injector.getInstance(ServiceComponentHostFactory.class); // install YARN so there is at least 1 service installed and no // unexpected alerts since the test YARN service doesn't have any alerts m_cluster = m_helper.buildNewCluster(m_clusters, m_serviceFactory, m_componentFactory, m_schFactory, HOST1); m_helper.addHost(m_clusters, m_cluster, HOST2); m_helper.addHostComponent(m_cluster, HOST2, SERVICE, COMPONENT); // create 5 definitions for (int i = 0; i < 5; i++) { AlertDefinitionEntity definition = new AlertDefinitionEntity(); definition.setDefinitionName("Alert Definition " + i); definition.setServiceName(SERVICE); definition.setComponentName(COMPONENT); definition.setClusterId(m_cluster.getClusterId()); definition.setHash(UUID.randomUUID().toString()); definition.setScheduleInterval(Integer.valueOf(60)); definition.setScope(Scope.SERVICE); definition.setSource("{\"type\" : \"SCRIPT\"}"); definition.setSourceType(SourceType.SCRIPT); definition.setLabel(ALERT_LABEL); m_definitionDao.create(definition); } } @After public void teardown() throws AmbariException, SQLException { m_injector.getInstance(UnitOfWork.class).end(); H2DatabaseCleaner.clearDatabase(m_injector.getProvider(EntityManager.class).get()); m_injector = null; } @Test public void testAlertRecords() { Alert alert1 = new Alert(ALERT_DEFINITION, null, SERVICE, COMPONENT, HOST1, AlertState.OK); alert1.setLabel(ALERT_LABEL); alert1.setText("Component component1 is OK"); alert1.setTimestamp(1L); alert1.setCluster(m_cluster.getClusterName()); Alert alert2 = new Alert(ALERT_DEFINITION, null, SERVICE, COMPONENT, HOST2, AlertState.CRITICAL); alert2.setLabel(ALERT_LABEL); alert2.setText("Component component2 is not OK"); alert2.setCluster(m_cluster.getClusterName()); AlertReceivedListener listener = m_injector.getInstance(AlertReceivedListener.class); AlertReceivedEvent event1 = new AlertReceivedEvent( m_cluster.getClusterId(), alert1); AlertReceivedEvent event2 = new AlertReceivedEvent( m_cluster.getClusterId(), alert2); listener.onAlertEvent(event1); listener.onAlertEvent(event2); List<AlertCurrentEntity> allCurrent = m_dao.findCurrentByService( m_cluster.getClusterId(), SERVICE); assertEquals(2, allCurrent.size()); List<AlertHistoryEntity> allHistory = m_dao.findAll(m_cluster.getClusterId()); assertEquals(2, allHistory.size()); AlertCurrentEntity current = m_dao.findCurrentByHostAndName( m_cluster.getClusterId(), HOST1, ALERT_DEFINITION); assertNotNull(current); assertEquals(HOST1, current.getAlertHistory().getHostName()); assertEquals(ALERT_DEFINITION, current.getAlertHistory().getAlertDefinition().getDefinitionName()); assertEquals(ALERT_LABEL, current.getAlertHistory().getAlertLabel()); assertEquals("Component component1 is OK", current.getAlertHistory().getAlertText()); assertEquals(current.getAlertHistory().getAlertState(), AlertState.OK); assertEquals(1L, current.getOriginalTimestamp().longValue()); assertEquals(1L, current.getLatestTimestamp().longValue()); Long currentId = current.getAlertId(); Long historyId = current.getAlertHistory().getAlertId(); // no new history since the state is the same Alert alert3 = new Alert(ALERT_DEFINITION, null, SERVICE, COMPONENT, HOST1, AlertState.OK); alert3.setLabel(ALERT_LABEL); alert3.setText("Component component1 is OK"); alert3.setTimestamp(2L); alert3.setCluster(m_cluster.getClusterName()); AlertReceivedEvent event3 = new AlertReceivedEvent( m_cluster.getClusterId(), alert3); listener.onAlertEvent(event3); current = m_dao.findCurrentByHostAndName(m_cluster.getClusterId(), HOST1, ALERT_DEFINITION); assertNotNull(current); assertEquals(currentId, current.getAlertId()); assertEquals(historyId, current.getAlertHistory().getAlertId()); assertEquals(HOST1, current.getAlertHistory().getHostName()); assertEquals(ALERT_DEFINITION, current.getAlertHistory().getAlertDefinition().getDefinitionName()); assertEquals(ALERT_LABEL, current.getAlertHistory().getAlertLabel()); assertEquals("Component component1 is OK", current.getAlertHistory().getAlertText()); assertEquals(current.getAlertHistory().getAlertState(), AlertState.OK); assertEquals(1L, current.getOriginalTimestamp().longValue()); assertEquals(2L, current.getLatestTimestamp().longValue()); allCurrent = m_dao.findCurrentByService(m_cluster.getClusterId(), SERVICE); assertEquals(2, allCurrent.size()); allHistory = m_dao.findAll(m_cluster.getClusterId()); assertEquals(2, allHistory.size()); // change to warning Alert alert4 = new Alert(ALERT_DEFINITION, null, SERVICE, COMPONENT, HOST1, AlertState.WARNING); alert4.setLabel(ALERT_LABEL); alert4.setText("Component component1 is about to go down"); alert4.setTimestamp(3L); alert4.setCluster(m_cluster.getClusterName()); AlertReceivedEvent event4 = new AlertReceivedEvent( m_cluster.getClusterId(), alert4); listener.onAlertEvent(event4); current = m_dao.findCurrentByHostAndName(m_cluster.getClusterId(), HOST1, ALERT_DEFINITION); assertNotNull(current); assertEquals(current.getAlertId(), currentId); assertFalse(historyId.equals(current.getAlertHistory().getAlertId())); assertEquals(HOST1, current.getAlertHistory().getHostName()); assertEquals(ALERT_DEFINITION, current.getAlertHistory().getAlertDefinition().getDefinitionName()); assertEquals(ALERT_LABEL, current.getAlertHistory().getAlertLabel()); assertEquals("Component component1 is about to go down", current.getAlertHistory().getAlertText()); assertEquals(current.getAlertHistory().getAlertState(), AlertState.WARNING); assertEquals(3L, current.getOriginalTimestamp().longValue()); assertEquals(3L, current.getLatestTimestamp().longValue()); allCurrent = m_dao.findCurrentByService(m_cluster.getClusterId(), SERVICE); assertEquals(2, allCurrent.size()); allHistory = m_dao.findAll(m_cluster.getClusterId()); assertEquals(3, allHistory.size()); } /** * Tests that {@link AlertStateChangeEvent} cause an {@link AlertNoticeEntity} * entry. * * @throws Exception */ @Test public void testAlertNotices() throws Exception { List<AlertNoticeEntity> notices = m_dispatchDao.findAllNotices(); assertEquals( 0, notices.size() ); List<AlertDefinitionEntity> definitions = m_definitionDao.findAll(m_cluster.getClusterId()); AlertDefinitionEntity definition = definitions.get(0); AlertHistoryEntity history = new AlertHistoryEntity(); history.setServiceName(definition.getServiceName()); history.setClusterId(m_cluster.getClusterId()); history.setAlertDefinition(definition); history.setAlertLabel(definition.getDefinitionName()); history.setAlertText(definition.getDefinitionName()); history.setAlertTimestamp(System.currentTimeMillis()); history.setHostName(HOST1); history.setAlertState(AlertState.OK); m_dao.create(history); List<AlertHistoryEntity> histories = m_dao.findAll(m_cluster.getClusterId()); assertEquals(1, histories.size()); AlertCurrentEntity currentAlert = new AlertCurrentEntity(); currentAlert.setAlertHistory(histories.get(0)); currentAlert.setMaintenanceState(MaintenanceState.OFF); currentAlert.setOriginalTimestamp(System.currentTimeMillis()); currentAlert.setLatestTimestamp(System.currentTimeMillis()); m_dao.create(currentAlert); AlertTargetEntity target = m_helper.createAlertTarget(); Set<AlertTargetEntity> targets = new HashSet<>(); targets.add(target); AlertGroupEntity group = m_helper.createAlertGroup( m_cluster.getClusterId(), targets); group.addAlertDefinition( definitions.get(0) ); m_dispatchDao.merge(group); Alert alert1 = new Alert(ALERT_DEFINITION, null, SERVICE, COMPONENT, HOST1, AlertState.OK); AlertStateChangeEvent event = new AlertStateChangeEvent( m_cluster.getClusterId(), alert1, currentAlert, AlertState.CRITICAL, AlertFirmness.HARD); AlertStateChangedListener listener = m_injector.getInstance(AlertStateChangedListener.class); listener.onAlertEvent(event); notices = m_dispatchDao.findAllNotices(); assertEquals(1, notices.size()); } @Test public void testAggregateAlerts() throws Exception { // create definition AlertDefinitionEntity definition = new AlertDefinitionEntity(); definition.setDefinitionName("to_aggregate"); definition.setLabel("My Label"); definition.setLabel("My Description"); definition.setServiceName(SERVICE); definition.setComponentName(null); definition.setClusterId(m_cluster.getClusterId()); definition.setHash(UUID.randomUUID().toString()); definition.setScheduleInterval(Integer.valueOf(60)); definition.setScope(Scope.HOST); definition.setSource("{\"type\" : \"SCRIPT\"}"); definition.setSourceType(SourceType.SCRIPT); m_definitionDao.create(definition); // create aggregate of definition AlertDefinitionEntity aggDef = new AlertDefinitionEntity(); aggDef.setDefinitionName("aggregate_test"); aggDef.setServiceName(SERVICE); aggDef.setComponentName(null); aggDef.setClusterId(m_cluster.getClusterId()); aggDef.setHash(UUID.randomUUID().toString()); aggDef.setScheduleInterval(Integer.valueOf(60)); aggDef.setScope(Scope.SERVICE); AggregateSource source = new AggregateSource(); source.setAlertName("to_aggregate"); // !!! type is protected Field field = Source.class.getDeclaredField("type"); field.setAccessible(true); field.set(source, SourceType.AGGREGATE); Reporting reporting = new Reporting(); ReportTemplate template = new ReportTemplate(); template.setText("You are good {1}/{0}"); reporting.setOk(template); template = new ReportTemplate(); template.setText("Going bad {1}/{0}"); template.setValue(Double.valueOf(0.33d)); reporting.setWarning(template); template = new ReportTemplate(); template.setText("On fire! {1}/{0}"); template.setValue(Double.valueOf(0.66d)); reporting.setCritical(template); source.setReporting(reporting); Gson gson = new Gson(); aggDef.setSource(gson.toJson(source)); aggDef.setSourceType(SourceType.AGGREGATE); m_definitionDao.create(aggDef); // add current and history across four hosts for (int i = 0; i < 4; i++) { AlertHistoryEntity history = new AlertHistoryEntity(); history.setAlertDefinition(definition); history.setAlertInstance(null); history.setAlertLabel(definition.getLabel()); history.setAlertState(AlertState.OK); history.setAlertText("OK"); history.setAlertTimestamp(Long.valueOf(1)); history.setClusterId(m_cluster.getClusterId()); history.setComponentName(definition.getComponentName()); history.setHostName("h" + (i+1)); history.setServiceName(definition.getServiceName()); m_dao.create(history); AlertCurrentEntity current = new AlertCurrentEntity(); current.setAlertHistory(history); current.setLatestText(history.getAlertText()); current.setLatestTimestamp(Long.valueOf(1L)); current.setOriginalTimestamp(Long.valueOf(1L)); m_dao.merge(current); } // !!! need a synchronous op for testing AlertEventPublisher publisher = m_injector.getInstance(AlertEventPublisher.class); EventBusSynchronizer.synchronizeAlertEventPublisher(m_injector); final AtomicReference<Alert> ref = new AtomicReference<>(); publisher.register(new TestListener() { @Override @Subscribe public void catchIt(AlertReceivedEvent event) { ref.set(event.getAlert()); } }); AlertAggregateListener listener = m_injector.getInstance(AlertAggregateListener.class); AlertDefinitionFactory factory = new AlertDefinitionFactory(); // get the aggregate cache and test it a little bit AggregateDefinitionMapping aggregateMapping = m_injector.getInstance(AggregateDefinitionMapping.class); AlertDefinition aggregateDefinition = factory.coerce(aggDef); aggregateMapping.registerAggregate(m_cluster.getClusterId(), aggregateDefinition ); // make sure the aggregate has the correct associations Assert.assertEquals(aggregateDefinition, aggregateMapping.getAggregateDefinitions(m_cluster.getClusterId()).get(0)); Assert.assertEquals(definition.getDefinitionName(), aggregateMapping.getAlertsWithAggregates(m_cluster.getClusterId()).get(0)); AggregateSource as = (AggregateSource) aggregateDefinition.getSource(); AlertDefinition aggregatedDefinition = aggregateMapping.getAggregateDefinition( m_cluster.getClusterId(), as.getAlertName()); assertNotNull(aggregatedDefinition); Alert alert = new Alert( definition.getDefinitionName(), null, definition.getServiceName(), definition.getComponentName(), "h1", AlertState.OK); AlertCurrentEntity current = m_dao.findCurrentByHostAndName( m_cluster.getClusterId(), "h1", definition.getDefinitionName()); AlertStateChangeEvent event = new AlertStateChangeEvent( m_cluster.getClusterId(), alert, current, AlertState.OK, AlertFirmness.HARD); listener.onAlertStateChangeEvent(event); assertNotNull(ref.get()); assertEquals(AlertState.OK, ref.get().getState()); assertTrue(ref.get().getText().indexOf("0/4") > -1); // check if one is critical, still ok current.getAlertHistory().setAlertState(AlertState.CRITICAL); m_dao.merge(current.getAlertHistory()); listener.onAlertStateChangeEvent(event); assertEquals("aggregate_test", ref.get().getName()); assertEquals(AlertState.OK, ref.get().getState()); assertTrue(ref.get().getText().indexOf("1/4") > -1); // two are either warning or critical, warning current = m_dao.findCurrentByHostAndName(m_cluster.getClusterId(), "h2", definition.getDefinitionName()); current.getAlertHistory().setAlertState(AlertState.WARNING); m_dao.merge(current.getAlertHistory()); listener.onAlertStateChangeEvent(event); assertEquals("aggregate_test", ref.get().getName()); assertEquals(AlertState.WARNING, ref.get().getState()); assertTrue(ref.get().getText().indexOf("2/4") > -1); // three make it critical current = m_dao.findCurrentByHostAndName(m_cluster.getClusterId(), "h3", definition.getDefinitionName()); current.getAlertHistory().setAlertState(AlertState.CRITICAL); m_dao.merge(current.getAlertHistory()); listener.onAlertStateChangeEvent(event); assertEquals("aggregate_test", ref.get().getName()); assertEquals(AlertState.CRITICAL, ref.get().getState()); assertTrue(ref.get().getText().indexOf("3/4") > -1); } /** * Test interface collects aggregate alert invocations */ private interface TestListener { void catchIt(AlertReceivedEvent event); } }