/*******************************************************************************
* 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.poller;
import java.lang.reflect.UndeclaredThrowableException;
import java.net.InetAddress;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;
import java.util.Enumeration;
import java.util.concurrent.atomic.AtomicInteger;
import javax.sql.DataSource;
import org.opennms.core.utils.InetAddressUtils;
import org.opennms.core.utils.LogUtils;
import org.opennms.core.utils.ThreadCategory;
import org.opennms.netmgt.config.OpennmsServerConfigFactory;
import org.opennms.netmgt.config.PollOutagesConfig;
import org.opennms.netmgt.config.PollerConfig;
import org.opennms.netmgt.config.poller.Package;
import org.opennms.netmgt.daemon.AbstractServiceDaemon;
import org.opennms.netmgt.eventd.EventIpcManager;
import org.opennms.netmgt.model.PollStatus;
import org.opennms.netmgt.poller.pollables.DbPollEvent;
import org.opennms.netmgt.poller.pollables.PollEvent;
import org.opennms.netmgt.poller.pollables.PollableNetwork;
import org.opennms.netmgt.poller.pollables.PollableNode;
import org.opennms.netmgt.poller.pollables.PollableService;
import org.opennms.netmgt.poller.pollables.PollableServiceConfig;
import org.opennms.netmgt.poller.pollables.PollableVisitor;
import org.opennms.netmgt.poller.pollables.PollableVisitorAdaptor;
import org.opennms.netmgt.scheduler.LegacyScheduler;
import org.opennms.netmgt.scheduler.Schedule;
import org.opennms.netmgt.scheduler.Scheduler;
import org.opennms.netmgt.utils.Querier;
import org.opennms.netmgt.utils.Updater;
/**
* <p>Poller class.</p>
*
* @author ranger
* @version $Id: $
*/
public class Poller extends AbstractServiceDaemon {
private final static Poller m_singleton = new Poller();
private boolean m_initialized = false;
private LegacyScheduler m_scheduler = null;
private PollerEventProcessor m_eventProcessor;
private PollableNetwork m_network;
private QueryManager m_queryManager;
private PollerConfig m_pollerConfig;
private PollOutagesConfig m_pollOutagesConfig;
private EventIpcManager m_eventMgr;
private DataSource m_dataSource;
/**
* <p>Constructor for Poller.</p>
*/
public Poller() {
super("OpenNMS.Poller");
}
/* Getters/Setters used for dependency injection */
/**
* <p>setDataSource</p>
*
* @param dataSource a {@link javax.sql.DataSource} object.
*/
public void setDataSource(DataSource dataSource) {
m_dataSource = dataSource;
}
/**
* <p>getEventManager</p>
*
* @return a {@link org.opennms.netmgt.eventd.EventIpcManager} object.
*/
public EventIpcManager getEventManager() {
return m_eventMgr;
}
/**
* <p>setEventManager</p>
*
* @param eventMgr a {@link org.opennms.netmgt.eventd.EventIpcManager} object.
*/
public void setEventManager(EventIpcManager eventMgr) {
m_eventMgr = eventMgr;
}
/**
* <p>getEventProcessor</p>
*
* @return a {@link org.opennms.netmgt.poller.PollerEventProcessor} object.
*/
public PollerEventProcessor getEventProcessor() {
return m_eventProcessor;
}
/**
* <p>setEventProcessor</p>
*
* @param eventProcessor a {@link org.opennms.netmgt.poller.PollerEventProcessor} object.
*/
public void setEventProcessor(PollerEventProcessor eventProcessor) {
m_eventProcessor = eventProcessor;
}
/**
* <p>getNetwork</p>
*
* @return a {@link org.opennms.netmgt.poller.pollables.PollableNetwork} object.
*/
public PollableNetwork getNetwork() {
return m_network;
}
/**
* <p>setNetwork</p>
*
* @param network a {@link org.opennms.netmgt.poller.pollables.PollableNetwork} object.
*/
public void setNetwork(PollableNetwork network) {
m_network = network;
}
/**
* <p>setQueryManager</p>
*
* @param queryManager a {@link org.opennms.netmgt.poller.QueryManager} object.
*/
public void setQueryManager(QueryManager queryManager) {
m_queryManager = queryManager;
}
/**
* <p>getQueryManager</p>
*
* @return a {@link org.opennms.netmgt.poller.QueryManager} object.
*/
public QueryManager getQueryManager() {
return m_queryManager;
}
/**
* <p>getPollerConfig</p>
*
* @return a {@link org.opennms.netmgt.config.PollerConfig} object.
*/
public PollerConfig getPollerConfig() {
return m_pollerConfig;
}
/**
* <p>setPollerConfig</p>
*
* @param pollerConfig a {@link org.opennms.netmgt.config.PollerConfig} object.
*/
public void setPollerConfig(PollerConfig pollerConfig) {
m_pollerConfig = pollerConfig;
}
/**
* <p>getPollOutagesConfig</p>
*
* @return a {@link org.opennms.netmgt.config.PollOutagesConfig} object.
*/
public PollOutagesConfig getPollOutagesConfig() {
return m_pollOutagesConfig;
}
/**
* <p>setPollOutagesConfig</p>
*
* @param pollOutagesConfig a {@link org.opennms.netmgt.config.PollOutagesConfig} object.
*/
public void setPollOutagesConfig(PollOutagesConfig pollOutagesConfig) {
m_pollOutagesConfig = pollOutagesConfig;
}
/**
* <p>getScheduler</p>
*
* @return a {@link org.opennms.netmgt.scheduler.Scheduler} object.
*/
public Scheduler getScheduler() {
return m_scheduler;
}
/**
* <p>setScheduler</p>
*
* @param scheduler a {@link org.opennms.netmgt.scheduler.LegacyScheduler} object.
*/
public void setScheduler(LegacyScheduler scheduler) {
m_scheduler = scheduler;
}
/**
* <p>onInit</p>
*/
protected void onInit() {
// serviceUnresponsive behavior enabled/disabled?
log().debug("init: serviceUnresponsive behavior: " + (getPollerConfig().isServiceUnresponsiveEnabled() ? "enabled" : "disabled"));
createScheduler();
try {
log().debug("init: Closing outages for unmanaged services");
closeOutagesForUnmanagedServices();
} catch (Throwable e) {
log().error("init: Failed to close ouates for unmanage services", e);
}
// Schedule the interfaces currently in the database
//
try {
log().debug("start: Scheduling existing interfaces");
scheduleExistingServices();
} catch (Throwable sqlE) {
log().error("start: Failed to schedule existing interfaces", sqlE);
}
// Create an event receiver. The receiver will
// receive events, process them, creates network
// interfaces, and schedulers them.
//
try {
log().debug("start: Creating event broadcast event processor");
setEventProcessor(new PollerEventProcessor(this));
} catch (Throwable t) {
log().fatal("start: Failed to initialized the broadcast event receiver", t);
throw new UndeclaredThrowableException(t);
}
m_initialized = true;
}
/**
*
*/
private void closeOutagesForUnmanagedServices() {
Timestamp closeTime = new Timestamp((new java.util.Date()).getTime());
final String DB_CLOSE_OUTAGES_FOR_UNMANAGED_SERVICES = "UPDATE outages set ifregainedservice = ? where outageid in (select outages.outageid from outages, ifservices where ((outages.nodeid = ifservices.nodeid) AND (outages.ipaddr = ifservices.ipaddr) AND (outages.serviceid = ifservices.serviceid) AND ((ifservices.status = 'D') OR (ifservices.status = 'F') OR (ifservices.status = 'U')) AND (outages.ifregainedservice IS NULL)))";
Updater svcUpdater = new Updater(m_dataSource, DB_CLOSE_OUTAGES_FOR_UNMANAGED_SERVICES);
svcUpdater.execute(closeTime);
final String DB_CLOSE_OUTAGES_FOR_UNMANAGED_INTERFACES = "UPDATE outages set ifregainedservice = ? where outageid in (select outages.outageid from outages, ipinterface where ((outages.nodeid = ipinterface.nodeid) AND (outages.ipaddr = ipinterface.ipaddr) AND ((ipinterface.ismanaged = 'F') OR (ipinterface.ismanaged = 'U')) AND (outages.ifregainedservice IS NULL)))";
Updater ifUpdater = new Updater(m_dataSource, DB_CLOSE_OUTAGES_FOR_UNMANAGED_INTERFACES);
ifUpdater.execute(closeTime);
}
/**
* <p>closeOutagesForNode</p>
*
* @param closeDate a {@link java.util.Date} object.
* @param eventId a int.
* @param nodeId a int.
*/
public void closeOutagesForNode(Date closeDate, int eventId, int nodeId) {
Timestamp closeTime = new Timestamp(closeDate.getTime());
final String DB_CLOSE_OUTAGES_FOR_NODE = "UPDATE outages set ifregainedservice = ?, svcRegainedEventId = ? where outages.nodeId = ? AND (outages.ifregainedservice IS NULL)";
Updater svcUpdater = new Updater(m_dataSource, DB_CLOSE_OUTAGES_FOR_NODE);
svcUpdater.execute(closeTime, new Integer(eventId), new Integer(nodeId));
}
/**
* <p>closeOutagesForInterface</p>
*
* @param closeDate a {@link java.util.Date} object.
* @param eventId a int.
* @param nodeId a int.
* @param ipAddr a {@link java.lang.String} object.
*/
public void closeOutagesForInterface(Date closeDate, int eventId, int nodeId, String ipAddr) {
Timestamp closeTime = new Timestamp(closeDate.getTime());
final String DB_CLOSE_OUTAGES_FOR_IFACE = "UPDATE outages set ifregainedservice = ?, svcRegainedEventId = ? where outages.nodeId = ? AND outages.ipAddr = ? AND (outages.ifregainedservice IS NULL)";
Updater svcUpdater = new Updater(m_dataSource, DB_CLOSE_OUTAGES_FOR_IFACE);
svcUpdater.execute(closeTime, new Integer(eventId), new Integer(nodeId), ipAddr);
}
/**
* <p>closeOutagesForService</p>
*
* @param closeDate a {@link java.util.Date} object.
* @param eventId a int.
* @param nodeId a int.
* @param ipAddr a {@link java.lang.String} object.
* @param serviceName a {@link java.lang.String} object.
*/
public void closeOutagesForService(Date closeDate, int eventId, int nodeId, String ipAddr, String serviceName) {
Timestamp closeTime = new Timestamp(closeDate.getTime());
final String DB_CLOSE_OUTAGES_FOR_SERVICE = "UPDATE outages set ifregainedservice = ?, svcRegainedEventId = ? where outageid in (select outages.outageid from outages, service where outages.nodeid = ? AND outages.ipaddr = ? AND outages.serviceid = service.serviceId AND service.servicename = ? AND outages.ifregainedservice IS NULL)";
Updater svcUpdater = new Updater(m_dataSource, DB_CLOSE_OUTAGES_FOR_SERVICE);
svcUpdater.execute(closeTime, new Integer(eventId), new Integer(nodeId), ipAddr, serviceName);
}
private void createScheduler() {
ThreadCategory log = ThreadCategory.getInstance(getClass());
// Create a scheduler
//
try {
log.debug("init: Creating poller scheduler");
setScheduler(new LegacyScheduler("Poller", getPollerConfig().getThreads()));
} catch (RuntimeException e) {
log.fatal("init: Failed to create poller scheduler", e);
throw e;
}
}
/**
* <p>onStart</p>
*/
protected void onStart() {
// get the category logger
// start the scheduler
//
try {
if (log().isDebugEnabled())
log().debug("start: Starting poller scheduler");
getScheduler().start();
} catch (RuntimeException e) {
if (log().isEnabledFor(ThreadCategory.Level.FATAL))
log().fatal("start: Failed to start scheduler", e);
throw e;
}
}
/**
* <p>onStop</p>
*/
protected void onStop() {
if(getScheduler()!=null) {
getScheduler().stop();
}
if(getEventProcessor()!=null) {
getEventProcessor().close();
}
releaseServiceMonitors();
setScheduler(null);
}
private void releaseServiceMonitors() {
getPollerConfig().releaseAllServiceMonitors();
}
/**
* <p>onPause</p>
*/
protected void onPause() {
getScheduler().pause();
}
/**
* <p>onResume</p>
*/
protected void onResume() {
getScheduler().resume();
}
/**
* <p>getInstance</p>
*
* @return a {@link org.opennms.netmgt.poller.Poller} object.
*/
public static Poller getInstance() {
return m_singleton;
}
/**
* <p>getServiceMonitor</p>
*
* @param svcName a {@link java.lang.String} object.
* @return a {@link org.opennms.netmgt.poller.ServiceMonitor} object.
*/
public ServiceMonitor getServiceMonitor(String svcName) {
return getPollerConfig().getServiceMonitor(svcName);
}
private void scheduleExistingServices() throws Exception {
ThreadCategory log = ThreadCategory.getInstance(getClass());
scheduleMatchingServices(null);
getNetwork().recalculateStatus();
getNetwork().propagateInitialCause();
getNetwork().resetStatusChanged();
// Debug dump pollable network
//
if (log.isDebugEnabled()) {
log.debug("scheduleExistingServices: dumping content of pollable network: ");
getNetwork().dump();
}
}
/**
* <p>scheduleService</p>
*
* @param nodeId a int.
* @param nodeLabel a {@link java.lang.String} object.
* @param ipAddr a {@link java.lang.String} object.
* @param svcName a {@link java.lang.String} object.
*/
public void scheduleService(final int nodeId, final String nodeLabel, final String ipAddr, final String svcName) {
final String normalizedAddress = InetAddressUtils.normalize(ipAddr);
try {
/*
* Do this here so that we can use the treeLock for this node as we
* add its service and schedule it
*/
PollableNode node;
synchronized (getNetwork()) {
node = getNetwork().getNode(nodeId);
if (node == null) {
node = getNetwork().createNode(nodeId, nodeLabel);
}
}
final PollableNode svcNode = node;
final Runnable r = new Runnable() {
public void run() {
final int matchCount = scheduleMatchingServices("ifServices.nodeId = "+nodeId+" AND ifServices.ipAddr = '"+normalizedAddress+"' AND service.serviceName = '"+svcName+"'");
if (matchCount > 0) {
svcNode.recalculateStatus();
svcNode.processStatusChange(new Date());
} else {
LogUtils.warnf(this, "Attempt to schedule service %d/%s/%s found no active service", nodeId, normalizedAddress, svcName);
}
}
};
node.withTreeLock(r);
} catch (final Throwable e) {
LogUtils.errorf(this, e, "Unable to schedule service %d/%s/%s", nodeId, normalizedAddress, svcName);
}
}
private int scheduleMatchingServices(String criteria) {
String sql = "SELECT ifServices.nodeId AS nodeId, node.nodeLabel AS nodeLabel, ifServices.ipAddr AS ipAddr, " +
"ifServices.serviceId AS serviceId, service.serviceName AS serviceName, ifServices.status as status, " +
"outages.svcLostEventId AS svcLostEventId, events.eventUei AS svcLostEventUei, " +
"outages.ifLostService AS ifLostService, outages.ifRegainedService AS ifRegainedService " +
"FROM ifServices " +
"JOIN node ON ifServices.nodeId = node.nodeId " +
"JOIN service ON ifServices.serviceId = service.serviceId " +
"LEFT OUTER JOIN outages ON " +
"ifServices.nodeId = outages.nodeId AND " +
"ifServices.ipAddr = outages.ipAddr AND " +
"ifServices.serviceId = outages.serviceId AND " +
"ifRegainedService IS NULL " +
"LEFT OUTER JOIN events ON outages.svcLostEventId = events.eventid " +
"WHERE ifServices.status in ('A','N')" +
(criteria == null ? "" : " AND "+criteria);
final AtomicInteger count = new AtomicInteger(0);
Querier querier = new Querier(m_dataSource, sql) {
public void processRow(ResultSet rs) throws SQLException {
if (scheduleService(rs.getInt("nodeId"), rs.getString("nodeLabel"), rs.getString("ipAddr"), rs.getString("serviceName"),
"A".equals(rs.getString("status")), (Number)rs.getObject("svcLostEventId"), rs.getTimestamp("ifLostService"),
rs.getString("svcLostEventUei"))) {
count.incrementAndGet();
}
}
};
querier.execute();
return count.get();
}
private void updateServiceStatus(int nodeId, String ipAddr, String serviceName, String status) {
final String sql = "UPDATE ifservices SET status = ? WHERE id " +
" IN (SELECT ifs.id FROM ifservices AS ifs JOIN service AS svc ON ifs.serviceid = svc.serviceid " +
" WHERE ifs.nodeId = ? AND ifs.ipAddr = ? AND svc.servicename = ?)";
Updater updater = new Updater(m_dataSource, sql);
updater.execute(status, nodeId, ipAddr, serviceName);
}
private boolean scheduleService(int nodeId, String nodeLabel, String ipAddr, String serviceName, boolean active, Number svcLostEventId, Date date, String svcLostUei) {
ThreadCategory log = ThreadCategory.getInstance(getClass());
// We don't want to adjust the management state of the service if we're
// on a machine that uses multiple servers with access to the same database
// so check the value of OpennmsServerConfigFactory.getInstance().verifyServer()
// before doing any updates.
Package pkg = findPackageForService(ipAddr, serviceName);
if (pkg == null) {
if(active && !OpennmsServerConfigFactory.getInstance().verifyServer()){
log.warn("Active service "+serviceName+" on "+ipAddr+" not configured for any package. Marking as Not Polled.");
updateServiceStatus(nodeId, ipAddr, serviceName, "N");
}
return false;
} else if (!active && !OpennmsServerConfigFactory.getInstance().verifyServer()) {
log.info("Active service "+serviceName+" on "+ipAddr+" is now configured for any package. Marking as active.");
updateServiceStatus(nodeId, ipAddr, serviceName, "A");
}
ServiceMonitor monitor = m_pollerConfig.getServiceMonitor(serviceName);
if (monitor == null) {
log.info("Could not find service monitor associated with service "+serviceName);
return false;
}
InetAddress addr;
addr = InetAddressUtils.addr(ipAddr);
if (addr == null) {
log.error("Could not convert "+ipAddr+" as an InetAddress "+ipAddr);
return false;
}
PollableService svc = getNetwork().createService(nodeId, nodeLabel, addr, serviceName);
PollableServiceConfig pollConfig = new PollableServiceConfig(svc, m_pollerConfig, m_pollOutagesConfig, pkg, getScheduler());
svc.setPollConfig(pollConfig);
synchronized(svc) {
if (svc.getSchedule() == null) {
Schedule schedule = new Schedule(svc, pollConfig, getScheduler());
svc.setSchedule(schedule);
}
}
if (svcLostEventId == null)
if (svc.getParent().getStatus().isUnknown()) {
svc.updateStatus(PollStatus.up());
} else {
svc.updateStatus(svc.getParent().getStatus());
}
else {
svc.updateStatus(PollStatus.down());
PollEvent cause = new DbPollEvent(svcLostEventId.intValue(), svcLostUei, date);
svc.setCause(cause);
}
svc.schedule();
return true;
}
private Package findPackageForService(String ipAddr, String serviceName) {
Enumeration<Package> en = m_pollerConfig.enumeratePackage();
Package lastPkg = null;
while (en.hasMoreElements()) {
Package pkg = (Package)en.nextElement();
if (pollableServiceInPackage(ipAddr, serviceName, pkg))
lastPkg = pkg;
}
return lastPkg;
}
/**
* <p>pollableServiceInPackage</p>
*
* @param ipAddr a {@link java.lang.String} object.
* @param serviceName a {@link java.lang.String} object.
* @param pkg a {@link org.opennms.netmgt.config.poller.Package} object.
* @return a boolean.
*/
protected boolean pollableServiceInPackage(String ipAddr, String serviceName, Package pkg) {
if (pkg.getRemote()) {
log().debug("pollableServiceInPackage: this package: "+pkg.getName()+", is a remote monitor package.");
return false;
}
if (!m_pollerConfig.isServiceInPackageAndEnabled(serviceName, pkg)) return false;
boolean inPkg = m_pollerConfig.isInterfaceInPackage(ipAddr, pkg);
if (inPkg) return true;
if (m_initialized) {
m_pollerConfig.rebuildPackageIpListMap();
return m_pollerConfig.isInterfaceInPackage(ipAddr, pkg);
}
return false;
}
/**
* <p>packageIncludesIfAndSvc</p>
*
* @param pkg a {@link org.opennms.netmgt.config.poller.Package} object.
* @param ipAddr a {@link java.lang.String} object.
* @param svcName a {@link java.lang.String} object.
* @return a boolean.
*/
public boolean packageIncludesIfAndSvc(Package pkg, String ipAddr, String svcName) {
ThreadCategory log = ThreadCategory.getInstance(getClass());
if (!getPollerConfig().isServiceInPackageAndEnabled(svcName, pkg)) {
if (log.isDebugEnabled())
log.debug("packageIncludesIfAndSvc: address/service: " + ipAddr + "/" + svcName + " not scheduled, service is not enabled or does not exist in package: " + pkg.getName());
return false;
}
// Is the interface in the package?
//
if (!getPollerConfig().isInterfaceInPackage(ipAddr, pkg)) {
if (m_initialized) {
getPollerConfig().rebuildPackageIpListMap();
if (!getPollerConfig().isInterfaceInPackage(ipAddr, pkg)) {
if (log.isDebugEnabled())
log.debug("packageIncludesIfAndSvc: interface " + ipAddr + " gained service " + svcName + ", but the interface was not in package: " + pkg.getName());
return false;
}
} else {
if (log.isDebugEnabled())
log.debug("packageIncludesIfAndSvc: address/service: " + ipAddr + "/" + svcName + " not scheduled, interface does not belong to package: " + pkg.getName());
return false;
}
}
return true;
}
/**
* <p>refreshServicePackages</p>
*/
public void refreshServicePackages() {
PollableVisitor visitor = new PollableVisitorAdaptor() {
public void visitService(PollableService service) {
service.refreshConfig();
}
};
getNetwork().visit(visitor);
}
/**
* <p>refreshServiceThresholds</p>
*/
public void refreshServiceThresholds() {
PollableVisitor visitor = new PollableVisitorAdaptor() {
public void visitService(PollableService service) {
service.refreshThresholds();
}
};
getNetwork().visit(visitor);
}
}