/*
* 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], 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.product.util;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import org.hyperic.hq.agent.AgentConfig;
import org.hyperic.hq.appdef.shared.AIPlatformValue;
import org.hyperic.hq.appdef.shared.AIServerExtValue;
import org.hyperic.hq.appdef.shared.AIServerValue;
import org.hyperic.hq.appdef.shared.AIServiceValue;
import org.hyperic.hq.autoinventory.AutoinventoryException;
import org.hyperic.hq.autoinventory.ScanConfiguration;
import org.hyperic.hq.autoinventory.ScanListener;
import org.hyperic.hq.autoinventory.ScanManager;
import org.hyperic.hq.autoinventory.ScanMethod;
import org.hyperic.hq.autoinventory.ScanState;
import org.hyperic.hq.autoinventory.Scanner;
import org.hyperic.hq.autoinventory.ServerSignature;
import org.hyperic.hq.autoinventory.scanimpl.FileScan;
import org.hyperic.hq.autoinventory.scanimpl.NullScan;
import org.hyperic.hq.autoinventory.scanimpl.WindowsRegistryScan;
import org.hyperic.hq.common.SystemException;
import org.hyperic.hq.product.AutoServerDetector;
import org.hyperic.hq.product.AutoinventoryPluginManager;
import org.hyperic.hq.product.FileServerDetector;
import org.hyperic.hq.product.PlatformDetector;
import org.hyperic.hq.product.PlatformResource;
import org.hyperic.hq.product.PlatformTypeInfo;
import org.hyperic.hq.product.PluginException;
import org.hyperic.hq.product.PluginNotFoundException;
import org.hyperic.hq.product.ProductPlugin;
import org.hyperic.hq.product.RegistryServerDetector;
import org.hyperic.hq.product.RuntimeDiscoverer;
import org.hyperic.hq.product.RuntimeResourceReport;
import org.hyperic.hq.product.ServerDetector;
import org.hyperic.hq.product.ServiceResource;
import org.hyperic.hq.product.TypeInfo;
import org.hyperic.util.ArrayUtil;
import org.hyperic.util.PluginLoader;
import org.hyperic.util.config.ConfigOption;
import org.hyperic.util.config.ConfigResponse;
import org.hyperic.util.config.EncodingException;
import org.hyperic.util.file.FileUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperic.util.AutoApproveConfig;
public class PluginDiscoverer implements ScanListener {
private static final boolean IS_WIN32 = PlatformDetector.IS_WIN32;
private AutoinventoryPluginManager pm;
private ScanManager scanManager;
private Log log;
private ArrayList autoSignatures = new ArrayList();
private ArrayList rgySignatures = new ArrayList();
private ArrayList fileSignatures = new ArrayList();
private Set servers;
private PluginDumper pd;
private boolean dumpProps = false;
private boolean fetchMetrics = false;
private ConfigResponse platformConfig;
private String os;
public PluginDiscoverer(PluginDumper pd) {
this.pd = pd;
this.log = LogFactory.getLog(PluginDiscoverer.class);
this.pm = pd.apm;
this.platformConfig = getPlatformConfig();
String aacPath = System.getProperty("autoapproveconfig.path", "config");
AutoApproveConfig aac = null;
try{
aac = new AutoApproveConfig(aacPath, AgentConfig.DEFAULT_PROP_ENC_KEY_FILE);
} catch(IllegalArgumentException ex){
}
this.scanManager = new ScanManager(this, this.pm, null, aac);
this.scanManager.startup();
this.fetchMetrics =
PluginDumper.METHOD_METRIC.equals(this.pd.config.action);
this.dumpProps =
this.fetchMetrics ||
"properties".equals(this.pd.config.action);
}
private ServerDetector getPlugin(String name)
throws PluginNotFoundException {
ServerDetector detector =
(ServerDetector)this.pm.getPlatformPlugin(this.os, name);
return detector;
}
public void scanComplete(ScanState state)
throws AutoinventoryException, SystemException {
this.servers = state.getAllServers();
}
private void addScanners(ScanConfiguration scanConfig,
ScanMethod method, List sigList,
ConfigResponse config) {
ServerSignature[] sigs =
(ServerSignature[])sigList.toArray(new ServerSignature[0]);
ServerSignature[] signatures = scanConfig.getServerSignatures();
signatures =
(ServerSignature[])ArrayUtil.combine(signatures, sigs);
scanConfig.setServerSignatures(signatures);
scanConfig.setScanMethodConfig(method, config);
}
public void add(String name) {
ServerDetector plugin;
try {
plugin = getPlugin(name);
} catch (PluginNotFoundException e) {
this.log.debug("No detector for " + name);
return;
}
ServerSignature sig = plugin.getServerSignature();
if (plugin instanceof FileServerDetector) {
this.fileSignatures.add(sig);
}
if (plugin instanceof AutoServerDetector) {
this.autoSignatures.add(sig);
}
if (IS_WIN32) {
if (plugin instanceof RegistryServerDetector) {
this.rgySignatures.add(sig);
}
}
}
private ConfigResponse getFileScanConfig(FileScan fileScan) {
List options;
ConfigResponse config = new ConfigResponse();
Properties props = pm.getProperties();
//if we find any property from this ConfigSchema
//(fileScan.scanDirs, fileScan.depth, etc.)
//then we will run a file scan.
try {
options = fileScan.getConfigSchema().getOptions();
} catch (AutoinventoryException e) {
e.printStackTrace(); //notgonnahappen
return null;
}
for (int i=0; i<options.size(); i++) {
ConfigOption option = (ConfigOption)options.get(i);
String key = option.getName();
String propName = "fileScan." + key;
String value = props.getProperty(propName);
if (value != null) {
config.setValue(key, value);
}
}
if (config.getKeys().size() > 0) {
//set defaults for any not specified
for (int i=0; i<options.size(); i++) {
ConfigOption option = (ConfigOption)options.get(i);
String key = option.getName();
if (config.getValue(key) == null) {
config.setValue(key, option.getDefault());
}
}
return config;
}
else {
return null;
}
}
private ConfigResponse getPlatformConfig() {
ConfigResponse config = new ConfigResponse();
String name = this.pd.config.plugin;
String configType = this.pd.config.type;
if (name != null) {
//for device plugins when given -p name, change the default platform.type
ProductPlugin plugin = this.pd.ppm.getProductPlugin(name);
TypeInfo[] types = plugin.getTypes();
for (int i=0; i<types.length; i++) {
if (types[i] instanceof PlatformTypeInfo) {
PlatformTypeInfo type = (PlatformTypeInfo)types[i];
if (!type.isDevice()) {
continue;
}
if ((configType != null) && !type.getName().equals(configType)) {
continue; //if given -t type param for another type
}
config.setValue(ProductPlugin.PROP_PLATFORM_TYPE,
type.getName());
log.debug("Set " + ProductPlugin.PROP_PLATFORM_TYPE +
"=" + type.getName());
//propagate platform config
String[] props =
plugin.getConfigSchema(type, config).getOptionNames();
for (int j=0; j<props.length; j++) {
String val = pd.getProperty(props[j]);
if (val != null) {
config.setValue(props[j], val);
}
}
}
}
}
Properties props = this.pm.getProperties();
String[][] platformProps = {
{ ProductPlugin.PROP_PLATFORM_TYPE, PluginDumper.OS },
{ ProductPlugin.PROP_PLATFORM_FQDN, "localhost" },
{ ProductPlugin.PROP_PLATFORM_NAME, "localhost" },
{ ProductPlugin.PROP_PLATFORM_IP, "127.0.0.1" },
};
for (int i=0; i<platformProps.length; i++) {
String key = platformProps[i][0];
String defval = platformProps[i][1];
String value =
props.getProperty(key, config.getValue(key, defval));
if (value != null) {
config.setValue(key, value);
}
}
this.os = config.getValue(ProductPlugin.PROP_PLATFORM_TYPE);
return config;
}
public void start() {
ScanConfiguration scanConfig = new ScanConfiguration();
scanConfig.setConfigResponse(this.platformConfig);
FileScan fileScan = new FileScan();
ConfigResponse config = getFileScanConfig(fileScan);
if (config != null) {
this.log.debug("FileScan config=" + config);
addScanners(scanConfig, fileScan,
this.fileSignatures, config);
}
else {
scanConfig.setIsDefaultScan(true);
addScanners(scanConfig, new NullScan(),
this.autoSignatures, config);
this.log.debug("Adding Auto Scanners=" + this.autoSignatures);
if (IS_WIN32) {
this.log.debug("Adding Registry Scanners=" +
this.rgySignatures);
addScanners(scanConfig, new WindowsRegistryScan(),
this.rgySignatures, config);
}
}
// clear the plugin shared data, caches, etc.
this.pm.endScan();
synchronized (this.scanManager) {
this.scanManager.queueScan(scanConfig);
}
while (this.scanManager.isScanQueued() ||
this.scanManager.isScanRunning())
{
try { Thread.sleep(1000); } catch (InterruptedException e) { }
}
if (this.servers == null) {
System.out.println("No servers detected");
return;
}
else {
System.out.println(this.servers.size() + " servers detected");
}
String discoverServices =
this.pm.getProperties().getProperty("discover-services", "true");
runtimeScan(discoverServices.equals("true"));
}
private void dumpConfig(ConfigResponse config,
ConfigResponse metricConfig,
ConfigResponse controlConfig,
ConfigResponse cprops,
String indent) {
System.out.println(indent + "config...");
System.out.println(indent + "product.." + config);
System.out.println(indent + "metric..." + metricConfig);
System.out.println(indent + "control.." + controlConfig);
if (cprops != null) {
System.out.println(indent + "cprops..." + cprops);
}
}
private ConfigResponse decodeConfig(byte[] config) {
if (config == null) {
return null;
}
try {
return ConfigResponse.decode(config);
} catch (EncodingException e) {
return null; //notgonnahappen
}
}
private void dumpConfig(ConfigResponse config,
ConfigResponse metricConfig,
ConfigResponse controlConfig,
ConfigResponse cprops,
ConfigResponse rtConfig,
String indent) {
dumpConfig(config, metricConfig, controlConfig, cprops, indent);
System.out.println(indent + "rt......." + rtConfig);
}
private void dumpProperties(Properties props, String type, String name) {
if (this.fetchMetrics) {
TypeInfo info =
this.pd.ppm.getTypeInfo(this.os, type);
if (info == null) {
this.log.error("No TypeInfo found for: " + type);
return;
}
//add command line props for stuff like passwords
props.putAll(this.pd.getProperties());
ConfigResponse config = new ConfigResponse(props);
try {
this.pd.fetchMetrics(info, false, config);
} catch (PluginException e) {
e.printStackTrace();
}
return;
}
PrintStream ps = null;
String file = FileUtil.escape(name);
String dir =
"plugin-properties" + File.separator + TypeInfo.formatName(type);
String plugin = (String)this.pd.productTypes.get(type);
try {
ps = PluginDumper.openFile(dir, file + ".properties");
ps.println("# same as '-p \"" + plugin + "\"'");
ps.println(PluginDumper.PROP_PLUGIN+ "=" + plugin);
ps.println("# same as '-t \"" + type + "\"'");
ps.println(PluginDumper.PROP_TYPE + "=" + type);
props.store(ps, name);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ps != null) {
ps.close();
}
}
}
private void dumpProperties(Properties props,
ConfigResponse pConfig,
ConfigResponse mConfig,
ConfigResponse cConfig,
String type,
String name)
{
if (pConfig != null) {
props.putAll(pConfig.toProperties());
}
if (mConfig != null) {
props.putAll(mConfig.toProperties());
}
if (cConfig != null) {
props.putAll(cConfig.toProperties());
}
dumpProperties(props, type, name);
}
private String getDescription(String desc) {
if (desc == null) {
return "";
}
return " (" + desc + ")";
}
private void dumpService(Properties serverProps,
AIServiceValue service, String indent) {
System.out.println(indent + service.getName() +
getDescription(service.getDescription()));
ConfigResponse config =
decodeConfig(service.getProductConfig());
ConfigResponse metricConfig =
decodeConfig(service.getMeasurementConfig());
ConfigResponse controlConfig =
decodeConfig(service.getControlConfig());
ConfigResponse rtConfig =
decodeConfig(service.getResponseTimeConfig());
ConfigResponse cprops =
decodeConfig(service.getCustomProperties());
dumpConfig(config, metricConfig,
controlConfig, cprops, rtConfig, indent + " ");
if (this.dumpProps) {
Properties props = new Properties();
props.putAll(serverProps);
dumpProperties(props,
config, metricConfig, controlConfig,
service.getServiceTypeName(),
service.getName());
}
}
private ConfigResponse dumpServer(AIServerValue server,
Properties serverProps,
ServerDetector detector) {
ConfigResponse config =
decodeConfig(server.getProductConfig());
ConfigResponse metricConfig =
decodeConfig(server.getMeasurementConfig());
ConfigResponse controlConfig =
decodeConfig(server.getControlConfig());
ConfigResponse cprops =
decodeConfig(server.getCustomProperties());
System.out.println("\nServer: " + server.getName() +
" [" + server.getInstallPath() + "]" +
getDescription(server.getDescription()));
System.out.println(" AIID....." + server.getAutoinventoryIdentifier());
dumpConfig(config, metricConfig, controlConfig, cprops, " ");
if (config == null) {
return null;
}
if (this.dumpProps) {
dumpProperties(serverProps,
config, metricConfig, controlConfig,
server.getServerTypeName(),
server.getName());
}
if (detector == null) {
return null;
}
if (metricConfig != null) {
config.merge(metricConfig, true);
}
//merge config from command line -Dprop=value
if (this.pd.config.plugin != null) {
ProductPlugin pPlugin =
this.pd.ppm.getProductPlugin(this.pd.config.plugin);
try {
config.merge(this.pd.getPluginConfig(pPlugin,
detector.getTypeInfo()),
false);
} catch (PluginException e) {
e.printStackTrace();
}
}
config.setValue(ProductPlugin.PROP_INSTALLPATH,
server.getInstallPath());
return config;
}
private void runtimeScan(boolean discoverServices) {
PlatformResource platform;
HashMap serviceNames = new HashMap();
try {
platform = Scanner.detectPlatform(this.pm, this.platformConfig);
} catch (AutoinventoryException e) {
e.printStackTrace();
return;
}
String fqdn =
this.platformConfig.getValue(ProductPlugin.PROP_PLATFORM_FQDN);
if ("localhost".equals(fqdn)) {
this.platformConfig.setValue(ProductPlugin.PROP_PLATFORM_FQDN,
platform.getFqdn());
}
ConfigResponse platformMeasurementConfig =
decodeConfig(platform.getMeasurementConfig());
boolean useDelim = (this.servers.size() > 1);
for (Iterator it=this.servers.iterator(); it.hasNext();) {
AIServerValue server = (AIServerValue)it.next();
String typeName = server.getServerTypeName();
String name = server.getName();
RuntimeResourceReport report;
ServerDetector detector;
ConfigResponse config;
Properties serverProps = new Properties();
if (useDelim) {
System.out.println("\n=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-" +
"=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
}
try {
detector = getPlugin(typeName);
} catch (PluginNotFoundException e) {
detector = null;
}
config = dumpServer(server, serverProps, detector);
if (!discoverServices) {
continue;
}
if (detector == null) {
continue;
}
if (!detector.isRuntimeDiscoverySupported()) {
continue;
}
if (config == null) {
continue;
}
this.log.debug("Runtime discover for " + name +
", config=" + config);
config.merge(this.platformConfig, false);
if (platformMeasurementConfig != null) {
//snmp based platform device plugins use platform.ip
//to auto-configure snmpIp
config.merge(platformMeasurementConfig, false);
}
try {
PluginLoader.setClassLoader(detector);
RuntimeDiscoverer discoverer = detector.getRuntimeDiscoverer();
//flush old values so we dont have to run
//PlatformDetector everytime
platform.cleanAIServerValue();
platform.cleanAIIpValue();
platform.removeAllAIServerValues();
platform.removeAllAIIpValues();
try {
report =
discoverer.discoverResources(0, platform, config);
} catch (PluginException e) {
String msg = detector.getName() + "-->" + e;
if (server.measurementConfigHasBeenSet()) {
this.log.error(msg, e);
}
else {
this.log.debug(msg, e);
}
continue;
}
} catch (NoClassDefFoundError e) {
this.log.debug(detector.getName() + "-->" + e, e);
continue;
} finally {
PluginLoader.resetClassLoader(detector);
}
System.out.print("\nRuntime Resource Report...");
if (report == null) {
System.out.println("none");
continue;
}
System.out.print("\n");
AIPlatformValue[] platforms = report.getAIPlatforms();
if (platforms == null) {
System.out.println("No platforms discovered");
continue;
}
for (int i=0; i<platforms.length; i++) {
System.out.println("Platform=" + platforms[i].getPlatformTypeName() +
", fqdn=" + platforms[i].getFqdn() +
getDescription(platforms[i].getDescription()));
System.out.println("config...");
System.out.println("product.." +
decodeConfig(platforms[i].getProductConfig()));
System.out.println("metric..." +
decodeConfig(platforms[i].getMeasurementConfig()));
System.out.println("control.." +
decodeConfig(platforms[i].getControlConfig()));
System.out.println("cprops..." +
decodeConfig(platforms[i].getCustomProperties()));
AIServerValue[] servers = platforms[i].getAIServerValues();
for (int j=0; j<servers.length; j++) {
if (!(servers[j] instanceof AIServerExtValue)) {
continue;
}
AIServerExtValue s = (AIServerExtValue)servers[j];
String sName;
if (s.getName() == null) {
sName = server.getName();
}
else {
//e.g. iPlanet, WebLogic, WebSphere discover servers
sName = s.getName();
if (!server.getName().equals(sName)) {
dumpServer(s, new Properties(), null);
}
}
if (s.getCustomProperties() != null) {
System.out.println(" " + sName + " cprops: " +
decodeConfig(s.getCustomProperties()));
}
AIServiceValue[] services = s.getAIServiceValues();
if ((services == null) || (services.length == 0)) {
System.out.println(" [No services discovered]");
continue;
}
System.out.println(" " + sName + " services:");
for (int k=0; k<services.length; k++) {
String svcName = services[k].getName();
String prefix = ServiceResource.SERVER_NAME_PREFIX;
if (svcName.startsWith(prefix)) {
svcName = svcName.substring(prefix.length()-1);
svcName = sName + svcName;
services[k].setName(svcName);
}
if (serviceNames.get(svcName) == null) {
serviceNames.put(svcName, Boolean.TRUE);
}
else {
String msg =
"!!!ERROR!!! duplicate service name=" +
svcName;
System.out.println(msg);
}
dumpService(serverProps, services[k], " ");
}
}
}
}
}
}