/*
* 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;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperic.util.StringUtil;
import org.hyperic.util.config.ConfigResponse;
/**
* Generic detector for use by pure-xml plugins.
*/
public class DaemonDetector
extends ServerDetector
implements AutoServerDetector,
FileServerDetector {
private static final Log log =
LogFactory.getLog(DaemonDetector.class.getName());
private ConfigResponse _platformConfig;
protected String getProcessQuery() {
String res=null;
if (isWin32()) {
res = getTypeProperty("WIN32_PROC_QUERY");
}
if (res == null) {
res = getTypeProperty("PROC_QUERY");
}
return res;
}
protected boolean isSwitch(String arg) {
return arg.startsWith("-");
}
private void addDefine(Map opts, String opt, int ix) {
String key = opt.substring(2, ix);
String val = opt.substring(ix+1);
opts.put(key, val);
//HQ_AUTOINVENTORY_NAME -> AUTOINVENTORY_NAME
//hq.autoinventory.name -> AUTOINVENTORY_NAME
if (key.startsWith("hq.")) {
key = StringUtil.replace(key.toUpperCase(), ".", "_");
}
else if (!key.startsWith("HQ_")) {
return;
}
opts.put(key.substring(3), val);
}
/**
* Convert getopt-style process arguments into a Map.
* @param pid Process id
* @return Map of -switch => value arguments
*/
protected Map getProcOpts(long pid) {
String[] args = getProcArgs(pid);
int len = args.length;
Map opts = new HashMap();
for (int i=0; i<len; i++) {
String opt = args[i];
String val;
if (!isSwitch(opt)) {
continue;
}
//"-p=22122"
int ix = opt.indexOf('=');
if (ix != -1) {
//java -Dfoo=bar or getopt cmd -d -- -Dfoo=bar
if (opt.startsWith("-D")) {
addDefine(opts, opt, ix);
}
val = opt.substring(ix+1);
opt = opt.substring(ix);
}
//"-p 22122"
else if (i+1 < len) {
val = args[i+1];
if (isSwitch(val)) {
continue;
}
i++;
}
else {
continue;
}
opts.put(opt, val);
}
return opts;
}
/**
* Auto-discover server configuration
* @param server Auto-discovered server
* @param pid Process id
*/
protected void discoverServerConfig(ServerResource server, long pid) {
Map opts = getProcOpts(pid);
boolean isDebug = log.isDebugEnabled();
boolean hasOpts = false;
ConfigResponse config = server.getProductConfig();
if (config == null) {
config = new ConfigResponse();
//start by setting the defaults
setProductConfig(server, config);
}
for (Iterator it=config.getKeys().iterator(); it.hasNext();) {
String key = (String)it.next();
//<property name="port.opt" value="-p"/>
String opt = getTypeProperty(key + ".opt");
if (opt == null) {
continue;
}
String val = (String)opts.get(opt);
if (val != null) {
config.setValue(key, val);
hasOpts = true;
if (isDebug) {
log.debug("Set " + key + "=" + val +
", using " + opt + " from pid=" + pid);
}
}
}
if (hasOpts) {
server.setProductConfig(config);
}
ConfigResponse
pconfig = getPlatformConfig(),
sconfig = server.getProductConfig(),
oconfig = new ConfigResponse(opts);
String name =
formatAutoInventoryName(server.getType(),
pconfig, sconfig, oconfig);
if (name != null) {
server.setName(name);
}
String id = (String)opts.get(INVENTORY_ID);
if (id == null) {
id = server.getIdentifier(); //might be defined in plugin.xml
}
server.setIdentifier(formatName(id, pconfig, sconfig, oconfig));
String installpath = (String)opts.get(INSTALLPATH);
if (installpath == null) {
installpath = server.getInstallPath();
}
server.setInstallPath(formatName(installpath, pconfig, sconfig, oconfig));
}
protected ServerResource newServerResource(long pid, String exe) {
ServerResource server = newServerResource(exe);
discoverServerConfig(server, pid);
return server;
}
protected ServerResource newServerResource(String exe) {
ServerResource server = createServerResource(exe);
//try the defaults
setProductConfig(server, new ConfigResponse());
setMeasurementConfig(server, new ConfigResponse());
return server;
}
//XXX should be in ServerDetector?
protected void setPlatformConfig(ConfigResponse config) {
_platformConfig = config;
}
protected ConfigResponse getPlatformConfig() {
return _platformConfig;
}
public List getServerResources(ConfigResponse platformConfig)
throws PluginException {
setPlatformConfig(platformConfig);
List servers = getFileResources(platformConfig);
if (servers.size() != 0) {
return servers;
}
List processes = getProcessResources(platformConfig);
for (int i=0; i<processes.size(); i++) {
ServerResource server =
(ServerResource)processes.get(i);
if (isInstallTypeVersion(server.getInstallPath())) {
servers.add(server);
}
}
return servers;
}
public List getServerResources(ConfigResponse platformConfig,
String path)
throws PluginException {
List servers = new ArrayList();
servers.add(newServerResource(path));
return servers;
}
protected List discoverServices(ConfigResponse config)
throws PluginException {
//e.g. qmail plugin has 1 instance of each service
String hasBuiltinServices =
getTypeProperty("HAS_BUILTIN_SERVICES");
if (!"true".equals(hasBuiltinServices)) {
return super.discoverServices(config);
}
List services = new ArrayList();
TypeInfo[] types = this.data.getTypes();
for (int i=0; i<types.length; i++) {
TypeInfo type = types[i];
if (type.getType() != TypeInfo.TYPE_SERVICE) {
continue;
}
if (!this.getTypeInfo().getVersion().equals(type.getVersion())) {
continue;
}
ServiceResource service = new ServiceResource();
service.setType(type.getName());
String name = getTypeNameProperty(type.getName());
service.setServiceName(name);
//try the defaults
setProductConfig(service, new ConfigResponse());
setMeasurementConfig(service, new ConfigResponse());
services.add(service);
}
return services;
}
/**
* Check for installed files using the file-scan config without
* running a full file-scan.
*/
protected List getFileResources(ConfigResponse platformConfig)
throws PluginException {
List servers = new ArrayList();
String type = getTypeInfo().getName();
List includes = this.data.getFileScanIncludes(type);
if (includes == null) {
return servers;
}
for (int i=0; i<includes.size(); i++) {
String file = (String)includes.get(i);
if (new File(file).exists()) {
servers.add(newServerResource(file));
}
}
return servers;
}
/**
* Process table scan
*/
protected List getProcessResources(ConfigResponse platformConfig)
throws PluginException {
List servers = new ArrayList();
String query = getProcessQuery();
if (query == null) {
log.debug("No PROC_QUERY defined for: " +
getTypeInfo().getName());
return servers;
}
else {
log.debug("Using PROC_QUERY=" + query + " for " +
getTypeInfo().getName());
}
long[] pids = getPids(query);
log.debug("'" + query + "' matched " +
pids.length + " processes");
for (int i=0; i<pids.length; i++) {
long pid = pids[i];
String exe = getProcExe(pid);
if (exe == null) {
log.debug("Unable to determine exe for " +
query + " pid=" + pid);
exe = query;
}
servers.add(newServerResource(pid, exe));
}
return servers;
}
}