/*******************************************************************************
* 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.net.InetAddress;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.opennms.core.utils.InetAddressUtils;
import org.opennms.core.utils.LogUtils;
import org.opennms.netmgt.EventConstants;
import org.opennms.netmgt.capsd.EventUtils;
import org.opennms.netmgt.capsd.InsufficientInformationException;
import org.opennms.netmgt.config.PollerConfig;
import org.opennms.netmgt.dao.DemandPollDao;
import org.opennms.netmgt.eventd.EventIpcManager;
import org.opennms.netmgt.model.events.EventListener;
import org.opennms.netmgt.poller.pollables.PollableInterface;
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.utils.XmlrpcUtil;
import org.opennms.netmgt.xml.event.Event;
import org.opennms.netmgt.xml.event.Parm;
import org.opennms.netmgt.xml.event.Value;
/**
*
* @author <a href="mailto:jamesz@opennms.com">James Zuo </a>
* @author <a href="mailto:weave@oculan.com">Brian Weaver </a>
* @author <a href="http://www.opennms.org/">OpenNMS </a>
*/
final class PollerEventProcessor implements EventListener {
private final Poller m_poller;
private volatile DemandPollDao m_demandPollDao;
/**
* Create message selector to set to the subscription
*/
private void createMessageSelectorAndSubscribe() {
// Create the selector for the UEIs this service is interested in
//
List<String> ueiList = new ArrayList<String>();
// nodeGainedService
ueiList.add(EventConstants.NODE_GAINED_SERVICE_EVENT_UEI);
// serviceDeleted
// deleteService
/*
* NOTE: deleteService is only generated by the PollableService itself.
* Therefore, we ignore it. If future implementations allow other
* subsystems to generate this event, we may have to listen for it as
* well. 'serviceDeleted' is the response event that the outage manager
* generates. We ignore this as well, since the PollableService has
* already taken action at the time it generated 'deleteService'
*/
ueiList.add(EventConstants.SERVICE_DELETED_EVENT_UEI);
// ueiList.add(EventConstants.DELETE_SERVICE_EVENT_UEI);
// serviceManaged
// serviceUnmanaged
// interfaceManaged
// interfaceUnmanaged
/*
* NOTE: These are all ignored because the responsibility is currently
* on the class generating the event to restart the poller service. If
* that implementation is ever changed, this message selector should
* listen for these and act on them.
*/
// ueiList.add(EventConstants.SERVICE_MANAGED_EVENT_UEI);
// ueiList.add(EventConstants.SERVICE_UNMANAGED_EVENT_UEI);
// ueiList.add(EventConstants.INTERFACE_MANAGED_EVENT_UEI);
// ueiList.add(EventConstants.INTERFACE_UNMANAGED_EVENT_UEI);
// interfaceIndexChanged
// NOTE: No longer interested in this event...if Capsd detects
// that in interface's index has changed a
// 'reinitializePrimarySnmpInterface' event is generated.
// ueiList.add(EventConstants.INTERFACE_INDEX_CHANGED_EVENT_UEI);
// interfaceReparented
ueiList.add(EventConstants.INTERFACE_REPARENTED_EVENT_UEI);
// reloadPollerConfig
/*
* NOTE: This is ignored because the reload is handled through an
* autoaction.
*/
// ueiList.add(EventConstants.RELOAD_POLLER_CONFIG_EVENT_UEI);
// NODE OUTAGE RELATED EVENTS
//
// nodeAdded
/*
* NOTE: This is ignored. The real trigger will be the first
* nodeGainedService event, at which time the interface and node will be
* created
*/
// ueiList.add(EventConstants.NODE_ADDED_EVENT_UEI);
// nodeDeleted
ueiList.add(EventConstants.NODE_DELETED_EVENT_UEI);
// nodeLabelChanged
ueiList.add(EventConstants.NODE_LABEL_CHANGED_EVENT_UEI);
// duplicateNodeDeleted
ueiList.add(EventConstants.DUP_NODE_DELETED_EVENT_UEI);
// nodeGainedInterface
/*
* NOTE: This is ignored. The real trigger will be the first
* nodeGainedService event, at which time the interface and node will be
* created
*/
// ueiList.add(EventConstants.NODE_GAINED_INTERFACE_EVENT_UEI);
// interfaceDeleted
ueiList.add(EventConstants.INTERFACE_DELETED_EVENT_UEI);
// suspendPollingService
ueiList.add(EventConstants.SUSPEND_POLLING_SERVICE_EVENT_UEI);
// resumePollingService
ueiList.add(EventConstants.RESUME_POLLING_SERVICE_EVENT_UEI);
// scheduled outage configuration change
ueiList.add(EventConstants.SCHEDOUTAGES_CHANGED_EVENT_UEI);
// demand poll
ueiList.add(EventConstants.DEMAND_POLL_SERVICE_EVENT_UEI);
// update threshold configuration
ueiList.add(EventConstants.THRESHOLDCONFIG_CHANGED_EVENT_UEI);
// asset information updated
ueiList.add(EventConstants.ASSET_INFO_CHANGED_EVENT_UEI);
// categories updated
ueiList.add(EventConstants.NODE_CATEGORY_MEMBERSHIP_CHANGED_EVENT_UEI);
// Subscribe to eventd
getEventManager().addEventListener(this, ueiList);
}
/**
* Process the event, construct a new PollableService object representing
* the node/interface/service/pkg combination, and schedule the service for
* polling.
*
* If any errors occur scheduling the interface no error is returned.
*
* @param event
* The event to process.
*
*/
private void nodeGainedServiceHandler(final Event event) {
// First make sure the service gained is in active state before trying to schedule
final String ipAddr = event.getInterface();
final Long nodeId = event.getNodeid();
final String svcName = event.getService();
String nodeLabel = EventUtils.getParm(event, EventConstants.PARM_NODE_LABEL);
try {
nodeLabel = getPoller().getQueryManager().getNodeLabel(nodeId.intValue());
} catch (final Exception e) {
LogUtils.errorf(this, e, "Unable to retrieve nodeLabel for node %d", nodeId);
}
getPoller().scheduleService(nodeId.intValue(), nodeLabel, ipAddr, svcName);
}
/**
* This method is responsible for processing 'interfacReparented' events. An
* 'interfaceReparented' event will have old and new nodeId parms associated
* with it. Node outage processing hierarchy will be updated to reflect the
* new associations.
*
* @param event
* The event to process.
*
*/
private void interfaceReparentedHandler(Event event) {
LogUtils.debugf(this, "interfaceReparentedHandler: processing interfaceReparented event for %s", event.getInterface());
// Verify that the event has an interface associated with it
if (event.getInterfaceAddress() == null)
return;
InetAddress ipAddr = event.getInterfaceAddress();
// Extract the old and new nodeId's from the event parms
String oldNodeIdStr = null;
String newNodeIdStr = null;
String parmName = null;
Value parmValue = null;
String parmContent = null;
for (Parm parm : event.getParmCollection()) {
parmName = parm.getParmName();
parmValue = parm.getValue();
if (parmValue == null)
continue;
else
parmContent = parmValue.getContent();
// old nodeid
if (parmName.equals(EventConstants.PARM_OLD_NODEID)) {
oldNodeIdStr = parmContent;
}
// new nodeid
else if (parmName.equals(EventConstants.PARM_NEW_NODEID)) {
newNodeIdStr = parmContent;
}
}
// Only proceed provided we have both an old and a new nodeId
//
if (oldNodeIdStr == null || newNodeIdStr == null) {
LogUtils.errorf(this, "interfaceReparentedHandler: old and new nodeId parms are required, unable to process.");
return;
}
PollableNode oldNode;
PollableNode newNode;
try {
oldNode = getNetwork().getNode(Integer.parseInt(oldNodeIdStr));
if (oldNode == null) {
LogUtils.errorf(this, "interfaceReparentedHandler: Cannot locate old node %s belonging to interface %s", oldNodeIdStr, ipAddr);
return;
}
newNode = getNetwork().getNode(Integer.parseInt(newNodeIdStr));
if (newNode == null) {
LogUtils.errorf(this, "interfaceReparentedHandler: Cannot locate new node %s to move interface to. Also, grammar error: ended a sentence with a preposition.", newNodeIdStr);
return;
}
PollableInterface iface = oldNode.getInterface(ipAddr);
if (iface == null) {
LogUtils.errorf(this, "interfaceReparentedHandler: Cannot locate interface with ipAddr %s to reparent.", ipAddr);
return;
}
iface.reparentTo(newNode);
} catch (final NumberFormatException nfe) {
LogUtils.errorf(this, "interfaceReparentedHandler: failed converting old/new nodeid parm to integer, unable to process.");
return;
}
}
/**
* This method is responsible for removing a node's pollable service from
* the pollable services list
*/
private void nodeRemovePollableServiceHandler(Event event) {
Long nodeId = event.getNodeid();
InetAddress ipAddr = event.getInterfaceAddress();
String svcName = event.getService();
if (svcName == null) {
LogUtils.errorf(this, "nodeRemovePollableServiceHandler: service name is null, ignoring event");
return;
}
PollableService svc = getNetwork().getService(nodeId.intValue(), ipAddr, svcName);
svc.delete();
}
/**
* This method is responsible for removing the node specified in the
* nodeDeleted event from the Poller's pollable node map.
*/
private void nodeDeletedHandler(Event event) {
Long nodeId = event.getNodeid();
final String sourceUei = event.getUei();
// Extract node label and transaction No. from the event parms
long txNo = -1L;
String parmName = null;
Value parmValue = null;
String parmContent = null;
for (Parm parm : event.getParmCollection()) {
parmName = parm.getParmName();
parmValue = parm.getValue();
if (parmValue == null)
continue;
else
parmContent = parmValue.getContent();
// get the external transaction number
if (parmName.equals(EventConstants.PARM_TRANSACTION_NO)) {
String temp = parmContent;
LogUtils.debugf(this, "nodeDeletedHandler: parmName: %s /parmContent: %s", parmName, parmContent);
try {
txNo = Long.valueOf(temp).longValue();
} catch (final NumberFormatException nfe) {
LogUtils.warnf(this, nfe, "nodeDeletedHandler: Parameter %s cannot be non-numeric", EventConstants.PARM_TRANSACTION_NO);
txNo = -1;
}
}
}
Date closeDate;
try {
closeDate = EventConstants.parseToDate(event.getTime());
} catch (ParseException e) {
closeDate = new Date();
}
getPoller().closeOutagesForNode(closeDate, event.getDbid(), nodeId.intValue());
PollableNode node = getNetwork().getNode(nodeId.intValue());
if (node == null) {
LogUtils.errorf(this, "Nodeid %d does not exist in pollable node map, unable to delete node.", nodeId);
if (isXmlRPCEnabled()) {
int status = EventConstants.XMLRPC_NOTIFY_FAILURE;
XmlrpcUtil.createAndSendXmlrpcNotificationEvent(txNo, sourceUei, "Node does not exist in pollable node map.", status, "OpenNMS.Poller");
}
return;
}
node.delete();
}
private void nodeLabelChangedHandler(Event event) {
Long nodeId = event.getNodeid();
// Extract node label from the event parms
for (Parm parm : event.getParmCollection()) {
String parmName = parm.getParmName();
Value parmValue = parm.getValue();
if (parmValue == null) {
continue;
} else {
if (parmName.equals(EventConstants.PARM_NODE_LABEL)) {
String label = parmValue.getContent();
LogUtils.debugf(this, "nodeLabelChangedHandler: parmName: %s /parmContent: %s", parmName, label);
PollableNode node = getNetwork().getNode(nodeId.intValue());
if (node == null) {
LogUtils.warnf(this, "nodeLabelChangedHandler: nodeid %d does not exist in pollable node map, unable to update node label.", nodeId);
} else {
node.setNodeLabel(label);
return;
}
}
}
}
}
/**
*
*/
private void interfaceDeletedHandler(Event event) {
Long nodeId = event.getNodeid();
String sourceUei = event.getUei();
InetAddress ipAddr = event.getInterfaceAddress();
// Extract node label and transaction No. from the event parms
long txNo = -1L;
String parmName = null;
Value parmValue = null;
String parmContent = null;
for (Parm parm : event.getParmCollection()) {
parmName = parm.getParmName();
parmValue = parm.getValue();
if (parmValue == null)
continue;
else
parmContent = parmValue.getContent();
// get the external transaction number
if (parmName.equals(EventConstants.PARM_TRANSACTION_NO)) {
String temp = parmContent;
LogUtils.debugf(this, "interfaceDeletedHandlerHandler: parmName: %s /parmContent: %s", parmName, parmContent);
try {
txNo = Long.valueOf(temp).longValue();
} catch (final NumberFormatException nfe) {
LogUtils.warnf(this, nfe, "interfaceDeletedHandlerHandler: Parameter %s cannot be non-numberic", EventConstants.PARM_TRANSACTION_NO);
txNo = -1;
}
}
}
Date closeDate;
try {
closeDate = EventConstants.parseToDate(event.getTime());
} catch (ParseException e) {
closeDate = new Date();
}
getPoller().closeOutagesForInterface(closeDate, event.getDbid(), nodeId.intValue(), InetAddressUtils.str(ipAddr));
PollableInterface iface = getNetwork().getInterface(nodeId.intValue(), ipAddr);
if (iface == null) {
LogUtils.errorf(this, "Interface %d/%s does not exist in pollable node map, unable to delete node.", nodeId, event.getInterface());
if (isXmlRPCEnabled()) {
int status = EventConstants.XMLRPC_NOTIFY_FAILURE;
XmlrpcUtil.createAndSendXmlrpcNotificationEvent(txNo, sourceUei, "Interface does not exist in pollable node map.", status, "OpenNMS.Poller");
}
return;
}
iface.delete();
}
/**
* <p>
* This method remove a deleted service from the pollable service list of
* the specified interface, so that it will not be scheduled by the poller.
* </p>
*/
private void serviceDeletedHandler(Event event) {
Long nodeId = event.getNodeid();
InetAddress ipAddr = event.getInterfaceAddress();
String service = event.getService();
Date closeDate;
try {
closeDate = EventConstants.parseToDate(event.getTime());
} catch (ParseException e) {
closeDate = new Date();
}
getPoller().closeOutagesForService(closeDate, event.getDbid(), nodeId.intValue(), InetAddressUtils.str(ipAddr), service);
PollableService svc = getNetwork().getService(nodeId.intValue(), ipAddr, service);
if (svc == null) {
LogUtils.errorf(this, "Interface %d/%s does not exist in pollable node map, unable to delete node.", nodeId, event.getInterface());
return;
}
svc.delete();
}
/**
* Constructor
*
* @param pollableServices
* List of all the PollableService objects scheduled for polling
*/
PollerEventProcessor(Poller poller) {
m_poller = poller;
createMessageSelectorAndSubscribe();
LogUtils.debugf(this, "Subscribed to eventd");
}
/**
* Unsubscribe from eventd
*/
public void close() {
getEventManager().removeEventListener(this);
}
/**
* @return
*/
private EventIpcManager getEventManager() {
return getPoller().getEventManager();
}
/**
* This method is invoked by the EventIpcManager when a new event is
* available for processing. Each message is examined for its Universal
* Event Identifier and the appropriate action is taking based on each UEI.
*
* @param event
* The event
*/
public void onEvent(Event event) {
if (event == null)
return;
// print out the uei
LogUtils.debugf(this, "PollerEventProcessor: received event, uei = %s", event.getUei());
if(event.getUei().equals(EventConstants.SCHEDOUTAGES_CHANGED_EVENT_UEI)) {
LogUtils.infof(this, "Reloading poller config factory and polloutages config factory");
scheduledOutagesChangeHandler();
} else if(event.getUei().equals(EventConstants.THRESHOLDCONFIG_CHANGED_EVENT_UEI)) {
LogUtils.infof(this, "Reloading thresholding configuration in pollerd");
thresholdsConfigChangeHandler();
} else if(!event.hasNodeid()) {
// For all other events, if the event doesn't have a nodeId it can't be processed.
LogUtils.infof(this, "PollerEventProcessor: no database node id found, discarding event");
} else if (event.getUei().equals(EventConstants.NODE_GAINED_SERVICE_EVENT_UEI)) {
// If there is no interface then it cannot be processed
if (event.getInterface() == null) {
LogUtils.infof(this, "PollerEventProcessor: no interface found, discarding event");
} else {
nodeGainedServiceHandler(event);
}
} else if (event.getUei().equals(EventConstants.RESUME_POLLING_SERVICE_EVENT_UEI)) {
// If there is no interface then it cannot be processed
if (event.getInterface() == null) {
LogUtils.infof(this, "PollerEventProcessor: no interface found, cannot resume polling service, discarding event");
} else {
nodeGainedServiceHandler(event);
}
} else if (event.getUei().equals(EventConstants.SUSPEND_POLLING_SERVICE_EVENT_UEI)) {
// If there is no interface then it cannot be processed
if (event.getInterface() == null) {
LogUtils.infof(this, "PollerEventProcessor: no interface found, cannot suspend polling service, discarding event");
} else {
nodeRemovePollableServiceHandler(event);
}
} else if (event.getUei().equals(EventConstants.INTERFACE_REPARENTED_EVENT_UEI)) {
// If there is no interface then it cannot be processed
if (event.getInterface() == null) {
LogUtils.infof(this, "PollerEventProcessor: no interface found, discarding event");
} else {
interfaceReparentedHandler(event);
}
} else if (event.getUei().equals(EventConstants.NODE_LABEL_CHANGED_EVENT_UEI)) {
if (event.getNodeid() < 0) {
LogUtils.infof(this, "PollerEventProcessor: no node or interface found, discarding event");
}
nodeLabelChangedHandler(event);
} else if (event.getUei().equals(EventConstants.NODE_DELETED_EVENT_UEI) || event.getUei().equals(EventConstants.DUP_NODE_DELETED_EVENT_UEI)) {
if (event.getNodeid() < 0) {
LogUtils.infof(this, "PollerEventProcessor: no node or interface found, discarding event");
}
// NEW NODE OUTAGE EVENTS
nodeDeletedHandler(event);
} else if (event.getUei().equals(EventConstants.INTERFACE_DELETED_EVENT_UEI)) {
// If there is no interface then it cannot be processed
if (event.getNodeid() < 0 || event.getInterface() == null) {
LogUtils.infof(this, "PollerEventProcessor: invalid nodeid or no interface found, discarding event");
} else {
interfaceDeletedHandler(event);
}
} else if (event.getUei().equals(EventConstants.SERVICE_DELETED_EVENT_UEI)) {
// If there is no interface then it cannot be processed
if ((event.getNodeid() < 0) || (event.getInterface() == null) || (event.getService() == null)) {
LogUtils.infof(this, "PollerEventProcessor: invalid nodeid or no nodeinterface " + "or service found, discarding event");
} else {
serviceDeletedHandler(event);
}
} else if (event.getUei().equals(EventConstants.NODE_CATEGORY_MEMBERSHIP_CHANGED_EVENT_UEI)){
if (!(event.getNodeid() < 0)) {
serviceReschedule(event);
}
} else if (event.getUei().equals(EventConstants.ASSET_INFO_CHANGED_EVENT_UEI)){
if (!(event.getNodeid() < 0)) {
serviceReschedule(event);
}
} // end single event process
} // end onEvent()
private void serviceReschedule(Event event) {
PollableNode pnode = getNetwork().getNode(event.getNodeid().intValue());
Long nodeId = event.getNodeid();
String nodeLabel = pnode.getNodeLabel();
//pnode.delete();
//nodeDeletedHandler(event);
/*while(pnode.isDeleted()==false){
LogUtils.debugf(this,"Waiting for node to delete...");
}*/
List<String[]> list = getPoller().getQueryManager().getNodeServices(nodeId.intValue());
for(String[] row : list){
LogUtils.debugf(this," Removing the following from the list: %s:%s", row[0],row[1]);
InetAddress addr;
addr = InetAddressUtils.addr(row[0]);
if (addr == null) {
LogUtils.warnf(this,"Rescheduler: Could not convert "+row[0]+" to an InetAddress");
return;
}
Date closeDate;
try {
closeDate = EventConstants.parseToDate(event.getTime());
} catch (ParseException e) {
closeDate = new Date();
}
getPoller().closeOutagesForService(closeDate, event.getDbid(), nodeId.intValue(), row[0], row[1]);
PollableService svc = getNetwork().getService(nodeId.intValue(),addr,row[1]);
if (svc != null) {
svc.delete();
while(svc.isDeleted()==false){
LogUtils.debugf(this,"Waiting for the service to delete...");
}
}
else {
LogUtils.debugf(this, "Service Not Found");
}
}
getPoller().getPollerConfig().rebuildPackageIpListMap();
for(String[] row : list){
LogUtils.debugf(this," Re-adding the following to the list: %s:%s", row[0],row[1]);
getPoller().scheduleService(nodeId.intValue(),nodeLabel,row[0],row[1]);
}
}
@SuppressWarnings("unused")
private void demandPollServiceHandler(Event e) throws InsufficientInformationException {
EventUtils.checkNodeId(e);
EventUtils.checkInterface(e);
EventUtils.checkService(e);
EventUtils.requireParm(e, EventConstants.PARM_DEMAND_POLL_ID);
m_demandPollDao.get(EventUtils.getIntParm(e, EventConstants.PARM_DEMAND_POLL_ID, -1));
}
private void scheduledOutagesChangeHandler() {
try {
getPollerConfig().update();
getPoller().getPollOutagesConfig().update();
} catch (Throwable e) {
LogUtils.errorf(this, e, "Failed to reload PollerConfigFactory");
}
getPoller().refreshServicePackages();
}
private void thresholdsConfigChangeHandler() {
getPoller().refreshServiceThresholds();
}
/**
* Return an id for this event listener
*/
public String getName() {
return "Poller:PollerEventProcessor";
}
/**
* @return
*/
private Poller getPoller() {
return m_poller;
}
/**
* @return
*/
private PollerConfig getPollerConfig() {
return getPoller().getPollerConfig();
}
private PollableNetwork getNetwork() {
return getPoller().getNetwork();
}
/**
* @return Returns the XMLRPC.
*/
private boolean isXmlRPCEnabled() {
return getPollerConfig().shouldNotifyXmlrpc();
}
} // end class