/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.ambari.server.events.listeners.alerts; import java.util.List; import org.apache.ambari.server.EagerSingleton; import org.apache.ambari.server.events.AggregateAlertRecalculateEvent; import org.apache.ambari.server.events.AlertEvent; import org.apache.ambari.server.events.MaintenanceModeEvent; import org.apache.ambari.server.events.publishers.AlertEventPublisher; import org.apache.ambari.server.events.publishers.AmbariEventPublisher; 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.AlertHistoryEntity; import org.apache.ambari.server.orm.entities.AlertNoticeEntity; import org.apache.ambari.server.state.AlertState; import org.apache.ambari.server.state.Host; import org.apache.ambari.server.state.MaintenanceState; import org.apache.ambari.server.state.Service; import org.apache.ambari.server.state.ServiceComponentHost; import org.apache.ambari.server.state.alert.AggregateDefinitionMapping; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.eventbus.AllowConcurrentEvents; import com.google.common.eventbus.Subscribe; import com.google.inject.Inject; import com.google.inject.Singleton; /** * The {@link AlertMaintenanceModeListener} handles events that relate to * Maintenance Mode changes. */ @Singleton @EagerSingleton public class AlertMaintenanceModeListener { /** * Logger. */ private static Logger LOG = LoggerFactory.getLogger(AlertMaintenanceModeListener.class); /** * Publishes {@link AlertEvent} instances. */ @Inject private AlertEventPublisher m_alertEventPublisher; /** * Used for updating the MM of current alerts. */ @Inject private AlertsDAO m_alertsDao = null; /** * Used for quick lookups of aggregate alerts. */ @Inject private AggregateDefinitionMapping m_aggregateMapping; private long clusterId = -1; /** * Constructor. * * @param publisher */ @Inject public AlertMaintenanceModeListener(AmbariEventPublisher publisher) { publisher.register(this); } /** * Handles {@link MaintenanceModeEvent} by performing the following tasks: * <ul> * <li>Iterates through all {@link AlertNoticeEntity}, updating the MM state</li> * </ul> * * @param event * the event being handled. */ @Subscribe @AllowConcurrentEvents public void onEvent(MaintenanceModeEvent event) { LOG.debug("Received event {}", event); boolean recalculateAggregateAlert = false; List<AlertCurrentEntity> currentAlerts = m_alertsDao.findCurrent(); MaintenanceState newMaintenanceState = MaintenanceState.OFF; if (event.getMaintenanceState() != MaintenanceState.OFF) { newMaintenanceState = MaintenanceState.ON; } for( AlertCurrentEntity currentAlert : currentAlerts ){ AlertHistoryEntity history = currentAlert.getAlertHistory(); String alertHostName = history.getHostName(); String alertServiceName = history.getServiceName(); String alertComponentName = history.getComponentName(); try { Host host = event.getHost(); Service service = event.getService(); ServiceComponentHost serviceComponentHost = event.getServiceComponentHost(); // host level maintenance if( null != host ){ String hostName = host.getHostName(); if( hostName.equals( alertHostName ) ){ if (updateMaintenanceStateAndRecalculateAggregateAlert(history, currentAlert, newMaintenanceState)) recalculateAggregateAlert = true; continue; } } else if( null != service ){ // service level maintenance String serviceName = service.getName(); if( serviceName.equals(alertServiceName)){ if (updateMaintenanceStateAndRecalculateAggregateAlert(history, currentAlert, newMaintenanceState)) recalculateAggregateAlert = true; continue; } } else if( null != serviceComponentHost ){ // component level maintenance String hostName = serviceComponentHost.getHostName(); String serviceName = serviceComponentHost.getServiceName(); String componentName = serviceComponentHost.getServiceComponentName(); // match on all 3 for a service component if (hostName.equals(alertHostName) && serviceName.equals(alertServiceName) && componentName.equals(alertComponentName)) { if (updateMaintenanceStateAndRecalculateAggregateAlert(history, currentAlert, newMaintenanceState)) recalculateAggregateAlert = true; continue; } } } catch (Exception exception) { AlertDefinitionEntity definition = history.getAlertDefinition(); LOG.error("Unable to put alert '{}' for host {} into maintenance mode", definition.getDefinitionName(), alertHostName, exception); } } if (recalculateAggregateAlert) { // publish the event to recalculate aggregates m_alertEventPublisher.publish(new AggregateAlertRecalculateEvent(clusterId)); } } /** * Updates the maintenance state of the specified alert if different than the * supplied maintenance state. And recalcualte aggregates if the maintenance state * is changed and there is an aggregate alert for the specified alert if it is * in CRITICAL or WARNING state. * * @param historyAlert * the alert to check if having an aggregate alert associated with it. * @param currentAlert * the alert to update (not {@code null}). * @param maintenanceState * the maintenance state to change to, either * {@link MaintenanceState#OFF} or {@link MaintenanceState#ON}. */ private boolean updateMaintenanceStateAndRecalculateAggregateAlert (AlertHistoryEntity historyAlert, AlertCurrentEntity currentAlert, MaintenanceState maintenanceState) { // alerts only care about OFF or ON if (maintenanceState != MaintenanceState.OFF && maintenanceState != MaintenanceState.ON) { LOG.warn("Unable to set invalid maintenance state of {} on the alert {}", maintenanceState, currentAlert.getAlertHistory().getAlertDefinition().getDefinitionName()); return false; } MaintenanceState currentState = currentAlert.getMaintenanceState(); if (currentState == maintenanceState) { return false; } currentAlert.setMaintenanceState(maintenanceState); m_alertsDao.merge(currentAlert); AlertState alertState = historyAlert.getAlertState(); if (AlertState.RECALCULATE_AGGREGATE_ALERT_STATES.contains(alertState)){ clusterId = historyAlert.getClusterId(); String alertName = historyAlert.getAlertDefinition().getDefinitionName(); if (m_aggregateMapping.getAggregateDefinition(clusterId, alertName) != null){ return true; } } return false; } }