/******************************************************************************* * This file is part of OpenNMS(R). * * Copyright (C) 2006-2011 The OpenNMS Group, Inc. * OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * * OpenNMS(R) is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * OpenNMS(R) is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenNMS(R). If not, see: * http://www.gnu.org/licenses/ * * For more information contact: * OpenNMS(R) Licensing <license@opennms.org> * http://www.opennms.org/ * http://www.opennms.com/ *******************************************************************************/ package org.opennms.netmgt.threshd; import java.lang.reflect.UndeclaredThrowableException; import java.net.InetAddress; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentSkipListMap; import org.opennms.core.utils.InetAddressUtils; import org.opennms.core.utils.ThreadCategory; import org.opennms.netmgt.capsd.DbIfServiceEntry; import org.opennms.netmgt.config.DataSourceFactory; import org.opennms.netmgt.config.ThreshdConfigManager; import org.opennms.netmgt.config.threshd.Package; import org.opennms.netmgt.config.threshd.Thresholder; import org.opennms.netmgt.daemon.AbstractServiceDaemon; import org.opennms.netmgt.scheduler.LegacyScheduler; import org.opennms.netmgt.scheduler.ReadyRunnable; import org.opennms.netmgt.utils.Querier; import org.springframework.dao.DataRetrievalFailureException; /** * <p>Threshd class.</p> * * @author ranger * @version $Id: $ */ public final class Threshd extends AbstractServiceDaemon { /** * SQL used to retrieve all the interfaces which support a particular * service. * * @see DbIfServiceEntry#STATUS_ACTIVE */ private final static String SQL_RETRIEVE_INTERFACES = "SELECT nodeid,ipaddr FROM ifServices, service WHERE ifServices.status = 'A' AND ifServices.serviceid = service.serviceid AND service.servicename = ?"; /** * Singleton instance of the Threshd class */ private final static Threshd m_singleton = new Threshd(); /** * List of all ThresholdableService objects. */ private final List<ThresholdableService> m_thresholdableServices; /** * Reference to the threshd scheduler */ private volatile LegacyScheduler m_scheduler; /** * Indicates if all the existing interfaces have been scheduled */ private volatile boolean m_schedulingCompleted = false; /** * Reference to the event processor */ private volatile BroadcastEventProcessor m_receiver; /** * Map of all available ServiceThresholder objects indexed by service name */ private static volatile Map<String, ServiceThresholder> m_svcThresholders; private ThreshdConfigManager m_threshdConfig; /** * Constructor. */ Threshd() { super("OpenNMS.Threshd"); m_scheduler = null; m_svcThresholders = new ConcurrentSkipListMap<String, ServiceThresholder>(); m_thresholdableServices = Collections.synchronizedList(new LinkedList<ThresholdableService>()); } /** * <p>onInit</p> */ protected void onInit() { log().debug("start: Initializing thresholding daemon"); log().debug("start: Loading thresholders"); // Threshd configuration // // Load up an instance of each thresholder from the config // so that the event processor will have them for // new incoming events to create collectable service objects. // initializeThresholders(); // Create a scheduler // initializeScheduler(); if (log().isDebugEnabled()) log().debug("start: Scheduling existing interfaces"); // Schedule existing interfaces for thresholding // scheduleBackgroundInitTask(); // Create an event receiver. The receiver will // receive events, process them, creates network // interfaces, and schedulers them. // createBroadcastEventProcessor(); } private void createBroadcastEventProcessor() { try { if (log().isDebugEnabled()) log().debug("start: Creating event broadcast event processor"); m_receiver = new BroadcastEventProcessor(this, m_thresholdableServices); } catch (Throwable t) { if (log().isEnabledFor(ThreadCategory.Level.FATAL)) log().fatal("start: Failed to initialized the broadcast event receiver", t); throw new UndeclaredThrowableException(t); } } private void scheduleBackgroundInitTask() { ReadyRunnable interfaceScheduler = new ReadyRunnable() { public boolean isReady() { return true; } public void run() { // try { scheduleExistingInterfaces(); } catch (DataRetrievalFailureException sqlE) { log().error("start: Failed to schedule existing interfaces", sqlE); } finally { setSchedulingCompleted(true); } } }; m_scheduler.schedule(interfaceScheduler, 0); } private void initializeScheduler() { try { log().debug("start: Creating threshd scheduler"); m_scheduler = new LegacyScheduler("Threshd", m_threshdConfig.getConfiguration().getThreads()); } catch (RuntimeException e) { log().fatal("start: Failed to create threshd scheduler", e); throw e; } } private void initializeThresholders() { Enumeration<Thresholder> eiter = m_threshdConfig.getConfiguration().enumerateThresholder(); while (eiter.hasMoreElements()) { Thresholder thresholder = eiter.nextElement(); try { if (log().isDebugEnabled()) { log().debug("start: Loading thresholder " + thresholder.getService() + ", classname " + thresholder.getClassName()); } Class<?> tc = Class.forName(thresholder.getClassName()); ServiceThresholder st = (ServiceThresholder) tc.newInstance(); // Attempt to initialize the service thresholder // // Store service name in map keyed by "svcName" Map<String, String> properties = new HashMap<String, String>(); properties.put("svcName", thresholder.getService()); st.initialize(properties); m_svcThresholders.put(thresholder.getService(), st); } catch (Throwable t) { log().warn("start: Failed to load thresholder " + thresholder.getClassName() + " for service " + thresholder.getService(), t); } } } /** * <p>reinitializeThresholders</p> */ public void reinitializeThresholders() { for(String key: m_svcThresholders.keySet()) { ServiceThresholder thresholder=m_svcThresholders.get(key); if(log().isDebugEnabled()) { log().debug("reinitializeThresholders: About to reinitialize thresholder "+key); } thresholder.reinitialize(); } } /** * <p>onStart</p> */ protected void onStart() { log().debug("start: Initializing thresholding daemon"); // start the scheduler // try { log().debug("start: Starting threshd scheduler"); m_scheduler.start(); } catch (RuntimeException e) { log().fatal("start: Failed to start scheduler", e); throw e; } log().debug("start: Threshd running"); } /** * <p>onStop</p> */ protected void onStop() { m_scheduler.stop(); m_receiver.close(); m_scheduler = null; } /** * <p>onPause</p> */ protected void onPause() { m_scheduler.pause(); } /** * <p>onResume</p> */ protected void onResume() { m_scheduler.resume(); } /** * Returns singleton instance of the thresholding daemon. * * @return a {@link org.opennms.netmgt.threshd.Threshd} object. */ public static Threshd getInstance() { return m_singleton; } /** * Returns reference to the scheduler * * @return a {@link org.opennms.netmgt.scheduler.LegacyScheduler} object. */ public LegacyScheduler getScheduler() { return m_scheduler; } /** * Returns the loaded ServiceThresholder for the specified service name. * * @param svcName * Service name to lookup. * @return ServiceThresholder responsible for performing thresholding on the * specified service. */ public ServiceThresholder getServiceThresholder(String svcName) { return m_svcThresholders.get(svcName); } /** * Schedule existing interfaces for thresholding. * * @throws SQLException * if database errors encountered. */ private void scheduleExistingInterfaces() { // Loop through loaded thresholders and schedule for each one // present // for(final String svcName : m_svcThresholders.keySet()) { // find the monitored services for each thresholder and schedule them Querier querier = new Querier(DataSourceFactory.getDataSource(), SQL_RETRIEVE_INTERFACES) { @Override public void processRow(ResultSet rs) throws SQLException { int nodeId = rs.getInt(1); String ipAddress = rs.getString(2); log().debug("Scheduling service nodeId/ipAddress/svcName "+nodeId+'/'+ipAddress+'/'+svcName); scheduleService(nodeId, ipAddress, svcName, true); } }; querier.execute(svcName); } } /** * This method is responsible for scheduling the specified * node/address/svcname tuple for thresholding. * * @param nodeId * Node id * @param ipAddress * IP address * @param svcName * Service name * @param existing * True if called by scheduleExistingInterfaces(), false * otheriwse */ void scheduleService(int nodeId, String ipAddress, String svcName, boolean existing) { Enumeration<org.opennms.netmgt.config.threshd.Package> epkgs = m_threshdConfig.getConfiguration().enumeratePackage(); // Compare interface/service pair against each threshd package // For each match, create new ThresholdableService object and // schedule it for collection // while (epkgs.hasMoreElements()) { org.opennms.netmgt.config.threshd.Package pkg = epkgs.nextElement(); // Make certain the the current service is in the package // and enabled! // if (!m_threshdConfig.serviceInPackageAndEnabled(svcName, pkg)) { if (log().isDebugEnabled()) log().debug("scheduleService: address/service: " + ipAddress + "/" + svcName + " not scheduled, service is not enabled or does not exist in package: " + pkg.getName()); continue; } // Is the interface in the package? // log().debug("scheduleService: checking ipaddress " + ipAddress + " for inclusion in pkg " + pkg.getName()); boolean foundInPkg = m_threshdConfig.interfaceInPackage(ipAddress, pkg); if (!foundInPkg && existing == false) { // The interface might be a newly added one, rebuild the package // to ipList mapping and again to verify if the interface is in // the package. m_threshdConfig.rebuildPackageIpListMap(); foundInPkg = m_threshdConfig.interfaceInPackage(ipAddress, pkg); } if (!foundInPkg) { if (log().isDebugEnabled()) log().debug("scheduleInterface: address/service: " + ipAddress + "/" + svcName + " not scheduled, interface does not belong to package: " + pkg.getName()); continue; } log().debug("scheduleService: ipaddress " + ipAddress + " IS in pkg " + pkg.getName()); if (existing == false) { // It is possible that both a nodeGainedService and a // primarySnmpInterfaceChanged // event are generated for an interface during a rescan. To // handle // this scenario we must verify that the ipAddress/pkg pair // identified by // this event does not already exist in the thresholdable // services list. // if (alreadyScheduled(ipAddress, pkg.getName())) { if (log().isDebugEnabled()) { log().debug("scheduleService: ipAddr/pkgName " + ipAddress + "/" + pkg.getName() + " already in thresholdable service list, skipping."); } continue; } } try { // Criteria checks have all passed. The interface/service pair // can be scheduled. // ThresholdableService tSvc = null; // Create a new SnmpThresholder object representing this node, // interface, // service and package pairing // tSvc = new ThresholdableService(this, nodeId, InetAddressUtils.addr(ipAddress), svcName, pkg); // Initialize the thresholder with the service. // ServiceThresholder thresholder = this.getServiceThresholder(svcName); if (thresholder == null) { // no thresholder exists for this service so go on to the next one log().warn("Unable to find a Thresholder for service "+svcName+"! But it is configured for Thresholding!"); continue; } thresholder.initialize(tSvc, tSvc.getPropertyMap()); // Add new service to the thresholdable service list. // m_thresholdableServices.add(tSvc); // Schedule the service for threshold checking // // NOTE: Service will be scheduled at the configured // interval (default is 5 minutes). This should give // the collector a chance to update the RRD file so // there is data available to be fetched. m_scheduler.schedule(tSvc, tSvc.getInterval()); if (log().isDebugEnabled()) log().debug("scheduleService: " + nodeId + "/" + ipAddress + " scheduled for " + svcName + " threshold checking"); } catch (RuntimeException rE) { log().warn("scheduleService: Unable to schedule " + ipAddress + " for service " + svcName + ", reason: " + rE.getMessage(), rE); } catch (Throwable t) { log().error("scheduleService: Uncaught exception, failed to schedule interface " + ipAddress + " for service " + svcName, t); } } // end while more packages exist } /** * Returns true if specified address/pkg pair is already represented in the * thresholdable services list. False otherwise. */ private boolean alreadyScheduled(String ipAddress, String pkgName) { synchronized (m_thresholdableServices) { for (ThresholdableService tSvc : m_thresholdableServices) { InetAddress addr = (InetAddress) tSvc.getAddress(); if (InetAddressUtils.str(addr).equals(InetAddressUtils.normalize(ipAddress)) && tSvc.getPackageName().equals(pkgName)) { return true; } } } return false; } /** * <p>isSchedulingCompleted</p> * * @return Returns the schedulingCompleted. */ public boolean isSchedulingCompleted() { return m_schedulingCompleted; } /** * <p>setSchedulingCompleted</p> * * @param schedulingCompleted * The schedulingCompleted to set. */ public void setSchedulingCompleted(boolean schedulingCompleted) { m_schedulingCompleted = schedulingCompleted; } /** * <p>refreshServicePackages</p> */ public void refreshServicePackages() { for (ThresholdableService thisService : m_thresholdableServices) { thisService.refreshPackage(); } } /** * <p>setThreshdConfig</p> * * @param threshdConfig a {@link org.opennms.netmgt.config.ThreshdConfigManager} object. */ public void setThreshdConfig(ThreshdConfigManager threshdConfig) { m_threshdConfig = threshdConfig; } /** * <p>getPackage</p> * * @param name a {@link java.lang.String} object. * @return a {@link org.opennms.netmgt.config.threshd.Package} object. */ public Package getPackage(String name) { return m_threshdConfig.getPackage(name); } }