/*******************************************************************************
* 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.monitors;
import java.io.IOException;
import java.lang.reflect.UndeclaredThrowableException;
import java.net.InetAddress;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.log4j.Level;
import org.opennms.core.utils.InetAddressUtils;
import org.opennms.core.utils.ParameterMap;
import org.opennms.core.utils.PropertiesUtils;
import org.opennms.netmgt.config.SnmpPeerFactory;
import org.opennms.netmgt.model.PollStatus;
import org.opennms.netmgt.poller.Distributable;
import org.opennms.netmgt.poller.DistributionContext;
import org.opennms.netmgt.poller.MonitoredService;
import org.opennms.netmgt.poller.NetworkInterface;
import org.opennms.netmgt.snmp.SnmpAgentConfig;
import org.opennms.netmgt.snmp.SnmpObjId;
import org.opennms.netmgt.snmp.SnmpUtils;
import org.opennms.netmgt.snmp.SnmpValue;
/**
* <P>
* This class is designed to be used by the service poller framework to test the
* availability of the SNMP service on remote interfaces. The class implements
* the ServiceMonitor interface that allows it to be used along with other
* plug-ins by the service poller framework.
* </P>
* <p>
* This does SNMP and therefore relies on the SNMP configuration so it is not distributable.
* </p>
*
* @author <A HREF="mailto:tarus@opennms.org">Tarus Balog </A>
* @author <A HREF="mailto:mike@opennms.org">Mike Davidson </A>
* @author <A HREF="http://www.opennms.org/">OpenNMS </A>
*/
@Distributable(DistributionContext.DAEMON)
public class SnmpMonitor extends SnmpMonitorStrategy {
/**
* Name of monitored service.
*/
private static final String SERVICE_NAME = "SNMP";
/**
* Default object to collect if "oid" property not available.
*/
private static final String DEFAULT_OBJECT_IDENTIFIER = ".1.3.6.1.2.1.1.2.0"; // MIB-II
// System
// Object
// Id
private static final String DEFAULT_REASON_TEMPLATE = "Observed value '${observedValue}' does not meet criteria '${operator} ${operand}'";
/**
* <P>
* Returns the name of the service that the plug-in monitors ("SNMP").
* </P>
*
* @return The service that the plug-in monitors.
*/
public String serviceName() {
return SERVICE_NAME;
}
/**
* {@inheritDoc}
*
* <P>
* Initialize the service monitor.
* </P>
* @exception RuntimeException
* Thrown if an unrecoverable error occurs that prevents the
* plug-in from functioning.
*/
public void initialize(Map<String, Object> parameters) {
// Initialize the SnmpPeerFactory
//
try {
SnmpPeerFactory.init();
} catch (IOException ex) {
log().fatal("initialize: Failed to load SNMP configuration", ex);
throw new UndeclaredThrowableException(ex);
}
return;
}
/**
* <P>
* Called by the poller framework when an interface is being added to the
* scheduler. Here we perform any necessary initialization to prepare the
* NetworkInterface object for polling.
* </P>
*
* @exception RuntimeException
* Thrown if an unrecoverable error occurs that prevents the
* interface from being monitored.
* @param svc a {@link org.opennms.netmgt.poller.MonitoredService} object.
*/
public void initialize(MonitoredService svc) {
super.initialize(svc);
return;
}
/**
* {@inheritDoc}
*
* <P>
* The poll() method is responsible for polling the specified address for
* SNMP service availability.
* </P>
* @exception RuntimeException
* Thrown for any unrecoverable errors.
*/
public PollStatus poll(MonitoredService svc, Map<String, Object> parameters) {
NetworkInterface<InetAddress> iface = svc.getNetInterface();
PollStatus status = PollStatus.unavailable();
InetAddress ipaddr = iface.getAddress();
// Retrieve this interface's SNMP peer object
//
SnmpAgentConfig agentConfig = SnmpPeerFactory.getInstance().getAgentConfig(ipaddr);
if (agentConfig == null) throw new RuntimeException("SnmpAgentConfig object not available for interface " + ipaddr);
final String hostAddress = InetAddressUtils.str(ipaddr);
log().debug("poll: setting SNMP peer attribute for interface " + hostAddress);
// Get configuration parameters
//
String oid = ParameterMap.getKeyedString(parameters, "oid", DEFAULT_OBJECT_IDENTIFIER);
String operator = ParameterMap.getKeyedString(parameters, "operator", null);
String operand = ParameterMap.getKeyedString(parameters, "operand", null);
String walkstr = ParameterMap.getKeyedString(parameters, "walk", "false");
String matchstr = ParameterMap.getKeyedString(parameters, "match-all", "true");
int countMin = ParameterMap.getKeyedInteger(parameters, "minimum", 0);
int countMax = ParameterMap.getKeyedInteger(parameters, "maximum", 0);
String reasonTemplate = ParameterMap.getKeyedString(parameters, "reason-template", DEFAULT_REASON_TEMPLATE);
// set timeout and retries on SNMP peer object
//
agentConfig.setTimeout(ParameterMap.getKeyedInteger(parameters, "timeout", agentConfig.getTimeout()));
agentConfig.setRetries(ParameterMap.getKeyedInteger(parameters, "retry", ParameterMap.getKeyedInteger(parameters, "retries", agentConfig.getRetries())));
agentConfig.setPort(ParameterMap.getKeyedInteger(parameters, "port", agentConfig.getPort()));
// Squirrel the configuration parameters away in a Properties for later expansion if service is down
Properties svcParams = new Properties();
svcParams.setProperty("oid", oid);
svcParams.setProperty("operator", String.valueOf(operator));
svcParams.setProperty("operand", String.valueOf(operand));
svcParams.setProperty("walk", walkstr);
svcParams.setProperty("matchAll", matchstr);
svcParams.setProperty("minimum", String.valueOf(countMin));
svcParams.setProperty("maximum", String.valueOf(countMax));
svcParams.setProperty("timeout", String.valueOf(agentConfig.getTimeout()));
svcParams.setProperty("retry", String.valueOf(agentConfig.getRetries()));
svcParams.setProperty("retries", svcParams.getProperty("retry"));
svcParams.setProperty("ipaddr", hostAddress);
svcParams.setProperty("port", String.valueOf(agentConfig.getPort()));
if (log().isDebugEnabled()) log().debug("poll: service= SNMP address= " + agentConfig);
// Establish SNMP session with interface
//
try {
if (log().isDebugEnabled()) {
log().debug("SnmpMonitor.poll: SnmpAgentConfig address: " +agentConfig);
}
SnmpObjId snmpObjectId = SnmpObjId.get(oid);
// This if block will count the number of matches within a walk and mark the service
// as up if it is between the minimum and maximum number, down if otherwise. Setting
// the parameter "matchall" to "count" will act as if "walk" has been set to "true".
if ("count".equals(matchstr)) {
if (DEFAULT_REASON_TEMPLATE.equals(reasonTemplate)) {
reasonTemplate = "Value: ${matchCount} outside of range Min: ${minimum} to Max: ${maximum}";
}
int matchCount = 0;
List<SnmpValue> results = SnmpUtils.getColumns(agentConfig, "snmpPoller", snmpObjectId);
for(SnmpValue result : results) {
if (result != null) {
log().debug("poll: SNMPwalk poll succeeded, addr=" + hostAddress + " oid=" + oid + " value=" + result);
if (meetsCriteria(result, operator, operand)) {
matchCount++;
}
}
}
svcParams.setProperty("matchCount", String.valueOf(matchCount));
log().debug("poll: SNMPwalk count succeeded, total=" + matchCount + " min=" + countMin + " max=" + countMax);
if ((countMin <= matchCount) && (matchCount <= countMax)) {
status = PollStatus.available();
} else {
status = logDown(Level.DEBUG, PropertiesUtils.substitute(reasonTemplate, svcParams));
return status;
}
} else if ("true".equals(walkstr)) {
if (DEFAULT_REASON_TEMPLATE.equals(reasonTemplate)) {
reasonTemplate = "SNMP poll failed, addr=${ipaddr} oid=${oid}";
}
List<SnmpValue> results = SnmpUtils.getColumns(agentConfig, "snmpPoller", snmpObjectId);
for(SnmpValue result : results) {
svcParams.setProperty("observedValue", result.toString());
if (result != null) {
log().debug("poll: SNMPwalk poll succeeded, addr=" + hostAddress + " oid=" + oid + " value=" + result);
if (meetsCriteria(result, operator, operand)) {
status = PollStatus.available();
if ("false".equals(matchstr)) {
return status;
}
} else if ("true".equals(matchstr)) {
status = logDown(Level.DEBUG, PropertiesUtils.substitute(reasonTemplate, svcParams));
return status;
}
}
}
} else {
if (DEFAULT_REASON_TEMPLATE.equals(reasonTemplate)) {
if (operator != null) {
reasonTemplate = "Observed value '${observedValue}' does not meet criteria '${operator} ${operand}'";
} else {
reasonTemplate = "Observed value '${observedValue}' was null";
}
}
SnmpValue result = SnmpUtils.get(agentConfig, snmpObjectId);
if (result != null) {
svcParams.setProperty("observedValue", result.toString());
log().debug("poll: SNMP poll succeeded, addr=" + hostAddress + " oid=" + oid + " value=" + result);
if (meetsCriteria(result, operator, operand)) {
status = PollStatus.available();
} else {
status = PollStatus.unavailable(PropertiesUtils.substitute(reasonTemplate, svcParams));
}
} else {
status = logDown(Level.DEBUG, "SNMP poll failed, addr=" + hostAddress + " oid=" + oid);
}
}
} catch (NumberFormatException e) {
status = logDown(Level.ERROR, "Number operator used on a non-number " + e.getMessage());
} catch (IllegalArgumentException e) {
status = logDown(Level.ERROR, "Invalid SNMP Criteria: " + e.getMessage());
} catch (Throwable t) {
status = logDown(Level.WARN, "Unexpected exception during SNMP poll of interface " + hostAddress, t);
}
return status;
}
}