/*******************************************************************************
* 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.capsd;
import java.net.InetAddress;
import org.opennms.core.utils.InetAddressUtils;
import org.opennms.core.utils.ThreadCategory;
import org.opennms.netmgt.capsd.snmp.IfTable;
import org.opennms.netmgt.capsd.snmp.IfXTable;
import org.opennms.netmgt.capsd.snmp.IpAddrTable;
import org.opennms.netmgt.capsd.snmp.SystemGroup;
import org.opennms.netmgt.config.SnmpPeerFactory;
import org.opennms.netmgt.snmp.CollectionTracker;
import org.opennms.netmgt.snmp.SnmpAgentConfig;
import org.opennms.netmgt.snmp.SnmpUtils;
import org.opennms.netmgt.snmp.SnmpWalker;
/**
* This class is designed to collect the necessary SNMP information from the
* target address and store the collected information. When the class is
* initially constructed no information is collected. The SNMP Session creating
* and colletion occurs in the main run method of the instance. This allows the
* collection to occur in a thread if necessary.
*
* @author <a href="mailto:brozow@opennms.org">brozow </a>
*/
public final class IfSnmpCollector implements Runnable {
/**
* The IP address to used to collect the SNMP information
*/
private final InetAddress m_address;
/**
* The system group information
*/
private SystemGroup m_sysGroup;
/**
* The interface table information
*/
private IfTable m_ifTable;
/**
* The IP address table
*/
private IpAddrTable m_ipAddrTable;
/**
* The interface extensions table information
*/
private IfXTable m_ifXTable;
/**
* Constructs a new snmp collector for a node using the passed interface as
* the collection point. The collection does not occur until the
* <code>run</code> method is invoked.
*
* @param address a {@link java.net.InetAddress} object.
*/
public IfSnmpCollector(InetAddress address) {
m_address = address;
m_sysGroup = null;
m_ifTable = null;
m_ifXTable = null;
m_ipAddrTable = null;
}
/**
* Returns true if any part of the collection failed.
*
* @return a boolean.
*/
public boolean failed() {
return !hasSystemGroup() || !hasIfTable() || !hasIpAddrTable();
}
/**
* Returns true if the system group was collected successfully
*
* @return a boolean.
*/
public boolean hasSystemGroup() {
if (m_sysGroup == null) {
log().debug("hasSystemGroup: No system group present.");
}
return (m_sysGroup != null && !m_sysGroup.failed());
}
/**
* Returns the collected system group.
*
* @return a {@link org.opennms.netmgt.capsd.snmp.SystemGroup} object.
*/
public SystemGroup getSystemGroup() {
return m_sysGroup;
}
/**
* Returns true if the interface table was collected.
*
* @return a boolean.
*/
public boolean hasIfTable() {
// FIXME What should we do if the table had no error but was empty
if (m_ifTable == null) {
log().debug("hasIfTable: No interface table present.");
}
return (m_ifTable != null && !m_ifTable.failed());
}
/**
* Returns the collected interface table.
*
* @return a {@link org.opennms.netmgt.capsd.snmp.IfTable} object.
*/
public IfTable getIfTable() {
return m_ifTable;
}
/**
* Returns true if the IP Interface Address table was collected.
*
* @return a boolean.
*/
public boolean hasIpAddrTable() {
// FIXME What should we do if the table had no error but was empty
if (m_ipAddrTable == null) {
log().debug("hasIpAddrTable: No IP interface address table present.");
}
return (m_ipAddrTable != null && !m_ipAddrTable.failed());
}
/**
* Returns the collected IP Interface Address table.
*
* @return a {@link org.opennms.netmgt.capsd.snmp.IpAddrTable} object.
*/
public IpAddrTable getIpAddrTable() {
return m_ipAddrTable;
}
/**
* Returns true if the interface extensions table was collected.
*
* @return a boolean.
*/
public boolean hasIfXTable() {
// FIXME What should we do if the table had no error but was empty
if (m_ifXTable == null) {
log().debug("hasIfXTable: No interface extensions table present.");
}
return (m_ifXTable != null && !m_ifXTable.failed());
}
/**
* Returns the collected interface extensions table.
*
* @return a {@link org.opennms.netmgt.capsd.snmp.IfXTable} object.
*/
public IfXTable getIfXTable() {
return m_ifXTable;
}
/**
* Returns the target address that the collection occured for.
*
* @return a {@link java.net.InetAddress} object.
*/
public InetAddress getCollectorTargetAddress() {
return m_address;
}
/**
* Returns the Internet address at the corresponding index. If the address
* cannot be resolved then a null reference is returned.
*
* @param ifIndex
* The index to search for.
* @throws java.lang.IndexOutOfBoundsException
* Thrown if the index cannot be resolved due to an incomplete
* table.
* @return an array of {@link java.net.InetAddress} objects.
*/
public InetAddress[] getIfAddressAndMask(int ifIndex) {
if (!hasIpAddrTable()) {
throw new IndexOutOfBoundsException("Illegal Index, no table present");
}
return m_ipAddrTable.getIfAddressAndMask(ifIndex);
}
/**
* <p>getAdminStatus</p>
*
* @param ifIndex a int.
* @return a int.
*/
public int getAdminStatus(int ifIndex) {
if (!hasIfTable()) {
throw new IndexOutOfBoundsException("Illegal Index, no table present");
}
return m_ifTable.getAdminStatus(ifIndex);
}
/**
* <p>getOperStatus</p>
*
* @param ifIndex a int.
* @return a int.
*/
public int getOperStatus(int ifIndex) {
if (!hasIfTable()) {
throw new IndexOutOfBoundsException("Illegal Index, no table present");
}
return m_ifTable.getOperStatus(ifIndex);
}
/**
* <p>getIfType</p>
*
* @param ifIndex a int.
* @return a int.
*/
public int getIfType(int ifIndex) {
if (!hasIfTable()) {
throw new IndexOutOfBoundsException("Illegal Index, no table present");
}
return m_ifTable.getIfType(ifIndex);
}
/**
* <p>getIfIndex</p>
*
* @param address a {@link java.net.InetAddress} object.
* @return a int.
*/
public int getIfIndex(InetAddress address) {
log().debug("getIfIndex: retrieving ifIndex for " + InetAddressUtils.str(address));
if (!hasIpAddrTable()) {
log().debug("getIfIndex: Illegal index, no table present.");
throw new IndexOutOfBoundsException("Illegal Index, no table present");
}
return m_ipAddrTable.getIfIndex(address);
}
/**
* <p>getIfName</p>
*
* @param ifIndex a int.
* @return a {@link java.lang.String} object.
*/
public String getIfName(int ifIndex) {
String snmpIfName = null;
if (hasIfXTable()) {
snmpIfName = m_ifXTable.getIfName(ifIndex);
}
// Debug
if (snmpIfName != null) {
log().debug("getIfName: ifIndex " + ifIndex + " has ifName '" + snmpIfName);
} else {
log().debug("getIfName: no ifName found for ifIndex " + ifIndex);
}
return snmpIfName;
}
/**
* <p>getIfDescr</p>
*
* @param ifIndex a int.
* @return a {@link java.lang.String} object.
*/
public String getIfDescr(final int ifIndex) {
String ifDescr = null;
if (hasIfTable()) {
ifDescr = m_ifTable.getIfDescr(ifIndex);
}
return ifDescr;
}
/**
* <p>getInterfaceSpeed</p>
*
* @param ifIndex a int.
* @return a {@link java.lang.Long} object.
*/
public Long getInterfaceSpeed(final int ifIndex) {
Long ifSpeed = null;
try {
if (hasIfXTable() && getIfXTable().getIfHighSpeed(ifIndex) != null && getIfXTable().getIfHighSpeed(ifIndex) > 4294) {
ifSpeed = getIfXTable().getIfHighSpeed(ifIndex)*1000000L;
log().debug("getInterfaceSpeed: Using ifHighSpeed for ifIndex "+ifIndex+": "+ ifSpeed);
} else if (hasIfTable()) {
ifSpeed = m_ifTable.getIfSpeed(ifIndex);
log().debug("getInterfaceSpeed: Using ifSpeed for ifIndex "+ifIndex+": "+ ifSpeed);
}
} catch(Throwable e) {
log().warn("getInterfaceSpeed: exception retrieving interface speed for ifIndex " + ifIndex);
}
return ifSpeed;
}
/**
* <p>getPhysAddr</p>
*
* @param ifIndex a int.
* @return a {@link java.lang.String} object.
*/
public String getPhysAddr(final int ifIndex) {
String physAddr = null;
if (hasIfTable()) {
physAddr = m_ifTable.getPhysAddr(ifIndex);
}
return physAddr;
}
/**
* <p>getIfAlias</p>
*
* @param ifIndex a int.
* @return a {@link java.lang.String} object.
*/
public String getIfAlias(int ifIndex) {
String snmpIfAlias = null;
if (hasIfXTable()) {
snmpIfAlias = m_ifXTable.getIfAlias(ifIndex);
if (log().isDebugEnabled()) {
if (snmpIfAlias != null) {
log().debug("getIfAlias: ifIndex " + ifIndex + " has ifAlias '" + snmpIfAlias + "'");
} else {
log().debug("getIfAlias: no ifAlias found for ifIndex " + ifIndex);
}
}
} else {
if (log().isDebugEnabled()) {
log().debug("getIfAlias: no ifXTable retrieved from " + m_address);
}
}
return snmpIfAlias;
}
/**
* <p>
* Preforms the collection for the targeted internet address. The success or
* failure of the collection should be tested via the <code>failed</code>
* method.
* </p>
*
* <p>
* No synchronization is preformed, so if this is used in a separate thread
* context synchornization must be added.
* </p>
*/
public void run() {
m_sysGroup = new SystemGroup(m_address);
m_ifTable = new IfTable(m_address);
m_ipAddrTable = new IpAddrTable(m_address);
m_ifXTable = new IfXTable(m_address);
SnmpAgentConfig agentConfig = SnmpPeerFactory.getInstance().getAgentConfig(m_address);
if (log().isDebugEnabled())
log().debug("run: collecting for: "+m_address+" with agentConfig: "+agentConfig);
SnmpWalker walker = SnmpUtils.createWalker(agentConfig, "system/ifTable/ifXTable/ipAddrTable", new CollectionTracker[] { m_sysGroup, m_ifTable, m_ipAddrTable, m_ifXTable});
walker.start();
try {
// wait a maximum of five minutes!
//
// FIXME: Why do we do this. If we are successfully processing responses shouldn't we keep going?
walker.waitFor(300000);
} catch (InterruptedException e) {
m_sysGroup = null;
m_ifTable = null;
m_ipAddrTable = null;
m_ifXTable = null;
log().warn("IfSnmpCollector: collection interrupted, exiting", e);
return;
}
if (walker.failed()) {
log().info("IfSnmpCollector: walker failed with error message:" + walker.getErrorMessage());
}
// Log any failures
//
if (!this.hasSystemGroup())
log().info("IfSnmpCollector: failed to collect System group for " + InetAddressUtils.str(m_address));
if (!this.hasIfTable())
log().info("IfSnmpCollector: failed to collect ifTable for " + InetAddressUtils.str(m_address));
if (!this.hasIpAddrTable())
log().info("IfSnmpCollector: failed to collect ipAddrTable for " + InetAddressUtils.str(m_address));
if (!this.hasIfXTable())
log().info("IfSnmpCollector: failed to collect ifXTable for " + InetAddressUtils.str(m_address));
}
private ThreadCategory log() {
return ThreadCategory.getInstance(getClass()+"."+m_address);
}
}