/******************************************************************************* * 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; } }