/*
* 'NetworkDeviceDetector.java' NOTE: This copyright does *not* cover user
* programs that use HQ program services by normal system calls through the
* application program interfaces provided as part of the Hyperic Plug-in
* Development Kit or the Hyperic Client Development Kit - this is merely
* considered normal use of the program, and does *not* fall under the heading
* of "derived work". Copyright (C) [2004, 2005, 2006, 2007, 2008, 2009],
* Hyperic, Inc. This file is part of HQ. HQ is free software; you can
* redistribute it and/or modify it under the terms version 2 of the GNU General
* Public License as published by the Free Software Foundation. This program 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 this
* program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA.
*/
package org.hyperic.hq.plugin.netdevice;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.hyperic.hq.product.MeasurementPlugin;
import org.hyperic.hq.product.PlatformServiceDetector;
import org.hyperic.hq.product.PluginException;
import org.hyperic.hq.product.ProductPlugin;
import org.hyperic.hq.product.ProductPluginManager;
import org.hyperic.hq.product.SNMPDetector;
import org.hyperic.hq.product.ServerResource;
import org.hyperic.hq.product.ServiceResource;
import org.hyperic.snmp.SNMPClient;
import org.hyperic.snmp.SNMPException;
import org.hyperic.snmp.SNMPSession;
import org.hyperic.snmp.SNMPValue;
import org.hyperic.util.config.ConfigResponse;
public class NetworkDeviceDetector
extends PlatformServiceDetector
{
private static final String SVC_NAME = "Interface";
private static final String PROP_IF = SVC_NAME.toLowerCase();
static final String PROP_IF_IX = PROP_IF + ".index";
static final String IF_DESCR = "ifDescr";
static final String IF_NAME = "ifName";
private static final String IF_MAC = "ifPhysAddress";
private static final String IP_IF_IX = "ipAdEntIfIndex";
private static final String IP_NETMASK = "ipAdEntNetMask";
private static final String PROP_IP = "ipaddress";
private static final String PROP_NETMASK = "netmask";
private static final String[] FILTER_PROPS = { PROP_IP, PROP_NETMASK };
private SNMPSession session;
public List discoverServices(ConfigResponse serverConfig) throws PluginException {
Log log = getLog();
List services = new ArrayList();
openSession(serverConfig);
if (log.isDebugEnabled()) {
log.debug("Using snmp config=" + serverConfig);
}
services.addAll(discoverInterfaces(serverConfig));
List extServices = SNMPDetector.discoverServices(this, serverConfig, this.session);
services.addAll(extServices);
closeSession();
return services;
}
protected boolean hasInterfaceService() {
String type = getServiceTypeName(SVC_NAME);
ProductPluginManager manager = (ProductPluginManager) getManager().getParent();
MeasurementPlugin plugin = manager.getMeasurementPlugin(type);
if (plugin == null) {
// Interface service is not defined...
return false;
} else {
// Check that ifMtu cprop exists, if so assume standard IF-MIB
// interface...
return plugin.getCustomPropertiesSchema().getOption("ifMtu") != null;
}
}
protected List discoverInterfaces(ConfigResponse serverConfig) throws PluginException {
Log log = getLog();
List services = new ArrayList();
String type = getServiceTypeName(SVC_NAME);
if (!hasInterfaceService()) {
log.debug("Skipping discovery of " + type);
return services;
}
String[] keys = getCustomPropertiesSchema(type).getOptionNames();
HashMap cpropColumns = new HashMap();
for (int i = 0; i < keys.length; i++) {
String key = keys[i];
if (Arrays.binarySearch(FILTER_PROPS, key) != -1) {
continue;
}
try {
cpropColumns.put(key, getIfColumn(key));
} catch (PluginException e) {
log.warn("Error getting '" + key + "': " + e.getMessage());
}
}
String columnName = serverConfig.getValue(PROP_IF_IX);
if (columnName == null) {
columnName = IF_DESCR;
}
Map interfaces = getIfColumn(columnName);
log.debug("Found " + interfaces.size() + " interfaces using " + columnName);
String descrColumn = columnName.equals(IF_DESCR) ? IF_NAME : IF_DESCR;
Map descriptions;
try {
descriptions = getIfColumn(descrColumn);
} catch (PluginException e) {
descriptions = new HashMap();
String msg = "Error getting descriptions from " + descrColumn + ": " + e;
log.warn(msg);
}
List ip_if_ix = getColumn(IP_IF_IX);
HashMap ips = new HashMap();
HashMap netmasks = new HashMap();
final String IF_IX_OID = SNMPClient.getOID(IP_IF_IX) + ".";
final String NETMASK_OID = SNMPClient.getOID(IP_NETMASK) + ".";
String ip, netmask;
for (int i = 0; i < ip_if_ix.size(); i++) {
SNMPValue value = (SNMPValue) ip_if_ix.get(i);
String oid = value.getOID();
String ix = value.toString();
if (oid.startsWith(IF_IX_OID)) {
ip = oid.substring(IF_IX_OID.length());
ips.put(ix, ip);
try {
netmask = this.session.getSingleValue(NETMASK_OID + ip).toString();
netmasks.put(ix, netmask);
} catch (SNMPException e) {
log.debug("Failed to get netmask for " + ip);
}
}
}
for (Iterator it = interfaces.entrySet().iterator(); it.hasNext();) {
ConfigResponse config = new ConfigResponse();
ConfigResponse cprops = new ConfigResponse();
Map.Entry entry = (Map.Entry) it.next();
String ix = (String) entry.getKey();
String name = (String) entry.getValue();
String mac = null;
ServiceResource service = createServiceResource(SVC_NAME);
config.setValue(PROP_IF, name);
config.setValue(PROP_IF_IX, columnName);
service.setProductConfig(config);
// required to auto-enable metric
service.setMeasurementConfig();
for (int j = 0; j < keys.length; j++) {
String key = keys[j];
Map data = (Map) cpropColumns.get(key);
if (data == null) {
continue;
}
String val = (String) data.get(ix);
if (val == null) {
continue;
}
cprops.setValue(key, val);
if (key.equals(IF_MAC)) {
mac = val;
}
}
ip = (String) ips.get(ix);
netmask = (String) netmasks.get(ix);
if (ip == null) {
ip = "0.0.0.0";
}
if (netmask == null) {
netmask = "0.0.0.0";
}
cprops.setValue(PROP_IP, ip);
cprops.setValue(PROP_NETMASK, netmask);
service.setCustomProperties(cprops);
// Might be more than 1 interface w/ the same name,
// so append the mac address to make it unique...
name = name + " " + SVC_NAME;
if ((mac != null) && !mac.equals("0:0:0:0:0:0")) {
name += " (" + mac + ")";
}
service.setServiceName(name);
Object obj = descriptions.get(ix);
if (obj != null) {
service.setDescription(obj.toString());
}
services.add(service);
}
return services;
}
static SNMPSession getSession(ConfigResponse config) throws PluginException {
try {
return new SNMPClient().getSession(config);
} catch (SNMPException e) {
throw new PluginException("Error getting SNMP session: " + e.getMessage(), e);
}
}
// These could be in a base class of some sort...
protected void openSession(ConfigResponse config) throws PluginException {
this.session = getSession(config);
}
protected void closeSession() {
this.session = null;
}
private String getIfIndex(SNMPValue val) {
String oid = val.getOID();
int last = oid.lastIndexOf('.');
return oid.substring(last + 1);
}
protected Map getIfColumn(String name) throws PluginException {
Map map = new LinkedHashMap();
List column = getColumn(name);
for (int i = 0; i < column.size(); i++) {
SNMPValue ent = (SNMPValue) column.get(i);
String ix = getIfIndex(ent);
String val;
if (name.equals(IF_MAC)) {
val = ent.toPhysAddressString();
} else {
val = ent.toString().trim();
}
map.put(ix, val);
}
return map;
}
protected List getColumn(String name) throws PluginException {
try {
return this.session.getColumn(name);
} catch (SNMPException e) {
throw new PluginException("Error getting SNMP column: " + name + ":" + e, e);
}
}
// Use platform.name instead of the generic type name...
protected String getServerName(ConfigResponse config) {
String fqdn = config.getValue(ProductPlugin.PROP_PLATFORM_FQDN);
String name = config.getValue(ProductPlugin.PROP_PLATFORM_NAME);
return fqdn + " " + name;
}
public List getServerResources(ConfigResponse config) {
Log log = getLog();
if (log.isDebugEnabled()) {
log.debug("Testing snmp config=" + config);
}
if (config.getValue(SNMPClient.PROP_IP) == null) {
log.debug("snmp config incomplete, defering server creation");
return null;
}
try {
getSession(config).getSingleValue("sysName");
} catch (Exception e) {
// Wait till we have valid snmp config at the platform level...
log.debug("snmp config invalid, defering server creation");
return null;
}
log.debug("snmp config valid, creating server");
return super.getServerResources(config);
}
protected ServerResource getServer(ConfigResponse config) {
ServerResource server = super.getServer(config);
server.setName(getServerName(config));
return server;
}
}