/** * 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.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import org.apache.ambari.server.EagerSingleton; import org.apache.ambari.server.events.AlertHashInvalidationEvent; import org.apache.ambari.server.events.HostsAddedEvent; import org.apache.ambari.server.events.HostsRemovedEvent; import org.apache.ambari.server.events.publishers.AmbariEventPublisher; import org.apache.ambari.server.metadata.AmbariServiceAlertDefinitions; import org.apache.ambari.server.orm.dao.AlertDefinitionDAO; 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.state.alert.AlertDefinition; import org.apache.ambari.server.state.alert.AlertDefinitionFactory; 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 AlertHostListener} class handles {@link HostsAddedEvent} and * {@link HostsRemovedEvent} and ensures that {@link AlertCurrentEntity} * instances are properly cleaned up */ @Singleton @EagerSingleton public class AlertHostListener { /** * Logger. */ private final static Logger LOG = LoggerFactory.getLogger(AlertHostListener.class); /** * Used for removing current alerts when a service is removed. */ @Inject private AlertsDAO m_alertsDao; /** * Used for checking to see if definitions already exist for a cluster. */ @Inject private AlertDefinitionDAO m_alertDefinitionDao; /** * Used to publish events when an alert definition has a lifecycle event. */ @Inject private AmbariEventPublisher m_eventPublisher; /** * All of the {@link AlertDefinition}s that are scoped for the agents. */ @Inject private AmbariServiceAlertDefinitions m_ambariServiceAlertDefinitions; /** * Used when a host is added to a cluster to coerce an {@link AlertDefinition} * into an {@link AlertDefinitionEntity}. */ @Inject private AlertDefinitionFactory m_alertDefinitionFactory; /** * Used to prevent multiple threads from trying to create host alerts * simultaneously. */ private Lock m_hostAlertLock = new ReentrantLock(); /** * Constructor. * * @param publisher */ @Inject public AlertHostListener(AmbariEventPublisher publisher) { publisher.register(this); } /** * Handles the {@link HostsAddedEvent} by performing the following actions: * <ul> * <li>Ensures that all host-level alerts are loaded for the cluster. This is * especially useful when creating a cluster and no alerts were loaded on * Ambari startup</li> * <li>Broadcasts the {@link AlertHashInvalidationEvent} in order to push host * alert definitions</li> * </ul> */ @Subscribe @AllowConcurrentEvents public void onAmbariEvent(HostsAddedEvent event) { LOG.debug("Received event {}", event); long clusterId = event.getClusterId(); // load the host-only alert definitions List<AlertDefinition> agentDefinitions = m_ambariServiceAlertDefinitions.getAgentDefinitions(); List<AlertDefinition> serverDefinitions = m_ambariServiceAlertDefinitions.getServerDefinitions(); List<AlertDefinition> ambariServiceDefinitions = new ArrayList<>(); ambariServiceDefinitions.addAll(agentDefinitions); ambariServiceDefinitions.addAll(serverDefinitions); // lock to prevent multiple threads from trying to create alert // definitions at the same time m_hostAlertLock.lock(); try { for (AlertDefinition agentDefinition : ambariServiceDefinitions) { AlertDefinitionEntity definition = m_alertDefinitionDao.findByName( clusterId, agentDefinition.getName()); // this host definition does not exist, add it if (null == definition) { definition = m_alertDefinitionFactory.coerce(clusterId, agentDefinition); try { m_alertDefinitionDao.create(definition); } catch (Exception e) { LOG.error( "Unable to create an alert definition named {} in cluster {}", definition.getDefinitionName(), definition.getClusterId(), e); } } } } finally { m_hostAlertLock.unlock(); } for (String hostName : event.getHostNames()) { AlertHashInvalidationEvent invalidationEvent = new AlertHashInvalidationEvent( event.getClusterId(), Collections.singletonList(hostName)); m_eventPublisher.publish(invalidationEvent); } } /** * Handles the {@link HostsRemovedEvent} by performing the following actions: * <ul> * <li>Removes all {@link AlertCurrentEntity} for the removed hosts</li> * </ul> */ @Subscribe @AllowConcurrentEvents public void onAmbariEvent(HostsRemovedEvent event) { LOG.debug("Received event {}", event); // remove any current alerts for the removed hosts for (String hostName : event.getHostNames()) { m_alertsDao.removeCurrentByHost(hostName); } } }