/******************************************************************************* * 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.Map; import java.util.regex.Pattern; import org.apache.log4j.Level; import org.opennms.core.utils.InetAddressUtils; import org.opennms.core.utils.ParameterMap; 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.SnmpInstId; import org.opennms.netmgt.snmp.SnmpObjId; import org.opennms.netmgt.snmp.SnmpUtils; import org.opennms.netmgt.snmp.SnmpValue; /** * <p> * Check for disks via HOST-RESOURCES-MIB. This should be extended to * support BOTH UCD-SNMP-MIB and HOST-RESOURCES-MIB * </p> * <p> * This does SNMP and therefore relies on the SNMP configuration so it is not distributable. * </p> * * @author <A HREF="mailto:jason.aras@gmail.com">Jason Aras</A> * @version $Id: $ */ @Distributable(DistributionContext.DAEMON) final public class DiskUsageMonitor extends SnmpMonitorStrategy { private static final String m_serviceName = "DISK-USAGE"; private static final String hrStorageDescr = ".1.3.6.1.2.1.25.2.3.1.3"; private static final String hrStorageSize = ".1.3.6.1.2.1.25.2.3.1.5"; private static final String hrStorageUsed = ".1.3.6.1.2.1.25.2.3.1.6"; /** * The available match-types for this monitor */ private static final int MATCH_TYPE_EXACT = 0; private static final int MATCH_TYPE_STARTSWITH = 1; private static final int MATCH_TYPE_ENDSWITH = 2; private static final int MATCH_TYPE_REGEX = 3; /** * <P> * Returns the name of the service that the plug-in monitors ("DISK-USAGE"). * </P> * * @return The service that the plug-in monitors. */ public String serviceName() { return m_serviceName; } /** * {@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 uncrecoverable errors. */ public PollStatus poll(MonitoredService svc, Map<String, Object> parameters) { int matchType = MATCH_TYPE_EXACT; NetworkInterface<InetAddress> iface = svc.getNetInterface(); PollStatus status = PollStatus.available(); InetAddress ipaddr = (InetAddress) 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); 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())); String diskName = ParameterMap.getKeyedString(parameters, "disk", null); Integer percentFree = ParameterMap.getKeyedInteger(parameters, "free", 15); String matchTypeStr = ParameterMap.getKeyedString(parameters, "match-type", "exact"); if (matchTypeStr.equalsIgnoreCase("exact")) { matchType = MATCH_TYPE_EXACT; } else if (matchTypeStr.equalsIgnoreCase("startswith")) { matchType = MATCH_TYPE_STARTSWITH; } else if (matchTypeStr.equalsIgnoreCase("endswith")) { matchType = MATCH_TYPE_ENDSWITH; } else if (matchTypeStr.equalsIgnoreCase("regex")) { matchType = MATCH_TYPE_REGEX; } else { throw new RuntimeException("Unknown value '" + matchTypeStr + "' for parameter 'match-type'"); } log().debug("diskName=" + diskName); log().debug("percentfree=" + percentFree); log().debug("matchType=" + matchTypeStr); if (log().isDebugEnabled()) log().debug("poll: service= SNMP address= " + agentConfig); try { if (log().isDebugEnabled()) { log().debug("DiskUsageMonitor.poll: SnmpAgentConfig address: " +agentConfig); } SnmpObjId hrStorageDescrSnmpObject = SnmpObjId.get(hrStorageDescr); Map<SnmpInstId, SnmpValue> flagResults = SnmpUtils.getOidValues(agentConfig, "DiskUsagePoller", hrStorageDescrSnmpObject); if(flagResults.size() == 0) { log().debug("SNMP poll failed: no results, addr=" + hostAddress + " oid=" + hrStorageDescrSnmpObject); return PollStatus.unavailable(); } for (Map.Entry<SnmpInstId, SnmpValue> e : flagResults.entrySet()) { log().debug("poll: SNMPwalk poll succeeded, addr=" + hostAddress + " oid=" + hrStorageDescrSnmpObject + " instance=" + e.getKey() + " value=" + e.getValue()); if (isMatch(e.getValue().toString(), diskName, matchType)) { log().debug("DiskUsageMonitor.poll: found disk=" + diskName); SnmpObjId hrStorageSizeSnmpObject = SnmpObjId.get(hrStorageSize + "." + e.getKey().toString()); SnmpObjId hrStorageUsedSnmpObject = SnmpObjId.get(hrStorageUsed + "." + e.getKey().toString()); SnmpValue snmpSize = SnmpUtils.get(agentConfig, hrStorageSizeSnmpObject); SnmpValue snmpUsed = SnmpUtils.get(agentConfig, hrStorageUsedSnmpObject); float calculatedPercentage = ( (( (float)snmpSize.toLong() - (float)snmpUsed.toLong() ) / (float)snmpSize.toLong() ) ) * 100; log().debug("DiskUsageMonitor: calculatedPercentage=" + calculatedPercentage + " percentFree="+percentFree); if (calculatedPercentage < percentFree) { return PollStatus.unavailable(diskName + " usage high (" + (100 - (int)calculatedPercentage) + "%)"); } else { return status; } } } // if we get here.. it means we did not find the disk... which means we should not be monitoring it. log().debug("DiskUsageMonitor: no disks found"); return PollStatus.unavailable("could not find " + diskName + "in table"); } 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; } private boolean isMatch(String candidate, String target, int matchType) { boolean matches = false; log().debug("isMessage: candidate is '" + candidate + "', matching against target '" + target + "'"); if (matchType == MATCH_TYPE_EXACT) { log().debug("Attempting equality match: candidate '" + candidate + "', target '" + target + "'"); matches = candidate.equals(target); } else if (matchType == MATCH_TYPE_STARTSWITH) { log().debug("Attempting startsWith match: candidate '" + candidate + "', target '" + target + "'"); matches = candidate.startsWith(target); } else if (matchType == MATCH_TYPE_ENDSWITH) { log().debug("Attempting endsWith match: candidate '" + candidate + "', target '" + target + "'"); matches = candidate.endsWith(target); } else if (matchType == MATCH_TYPE_REGEX) { log().debug("Attempting endsWith match: candidate '" + candidate + "', target '" + target + "'"); matches = Pattern.compile(target).matcher(candidate).find(); } log().debug("isMatch: Match is positive"); return matches; } }