/**
* 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);
}
}