/*
* RHQ Management Platform
* Copyright (C) 2005-2012 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation, and/or the GNU Lesser
* General Public License, version 2.1, also 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 and the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* and the GNU Lesser General Public License along with this program;
* if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.rhq.plugins.cassandra;
import java.io.File;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mc4j.ems.connection.support.metadata.J2SE5ConnectionTypeDescriptor;
import org.rhq.cassandra.util.ConfigEditor;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.domain.resource.ResourceUpgradeReport;
import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
import org.rhq.core.pluginapi.inventory.ProcessScanResult;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
import org.rhq.core.pluginapi.upgrade.ResourceUpgradeContext;
import org.rhq.core.system.ProcessInfo;
import org.rhq.plugins.jmx.JMXDiscoveryComponent;
/**
* @author John Sanda
*/
public class CassandraNodeDiscoveryComponent extends JMXDiscoveryComponent {
private static final Log log = LogFactory.getLog(CassandraNodeDiscoveryComponent.class);
protected static final String HOST_PROPERTY = "host";
protected static final String CLUSTER_NAME_PROPERTY = "clusterName";
protected static final String JMX_PORT_PROPERTY = "jmxPort";
protected static final String AUTHENTICATOR_PROPERTY = "authenticator";
protected static final String YAML_PROPERTY = "yamlConfiguration";
protected static final String BASEDIR_PROPERTY = "baseDir";
protected static final String DEFAULT_RHQ_CLUSTER = "rhq";
private static final String RESOURCE_NAME = "Cassandra";
@SuppressWarnings({ "rawtypes" })
@Override
public Set<DiscoveredResourceDetails> discoverResources(ResourceDiscoveryContext context) {
Set<DiscoveredResourceDetails> cassandraNodes = new HashSet<DiscoveredResourceDetails>();
for (DiscoveredResourceDetails discoveredResource : this.scanForResources(context)) {
if (isCassandraNode(discoveredResource)) {
cassandraNodes.add(discoveredResource);
}
}
return cassandraNodes;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
protected Set<DiscoveredResourceDetails> scanForResources(ResourceDiscoveryContext context) {
Set<DiscoveredResourceDetails> details = new HashSet<DiscoveredResourceDetails>();
List<ProcessScanResult> processScanResults = context.getAutoDiscoveredProcesses();
for (ProcessScanResult processScanResult : processScanResults) {
DiscoveredResourceDetails discoveredDetails = getDetails(context, processScanResult);
if (discoveredDetails != null) {
details.add(discoveredDetails);
}
}
return details;
}
protected boolean isCassandraNode(DiscoveredResourceDetails discoveredResource) {
if (DEFAULT_RHQ_CLUSTER.equals(discoveredResource.getPluginConfiguration()
.getSimpleValue(CLUSTER_NAME_PROPERTY))) {
return false;
}
return true;
}
@SuppressWarnings({ "deprecation" })
private DiscoveredResourceDetails getDetails(ResourceDiscoveryContext<?> context,
ProcessScanResult processScanResult) {
Configuration pluginConfig = context.getDefaultPluginConfiguration();
String jmxPort = null;
StringBuilder commandLineBuilder = new StringBuilder(400);
int classpathIndex = -1;
ProcessInfo processInfo = processScanResult.getProcessInfo();
String[] arguments = processInfo.getCommandLine();
for (int i = 0; i < arguments.length; i++) {
String arg = arguments[i];
if (arg.startsWith("-Dcassandra.jmx.local.port") ||
arg.startsWith("-Dcom.sun.management.jmxremote.port")) {
String[] jmxPortArg = arg.split("=");
jmxPort = jmxPortArg[1];
}
if (arg.startsWith("-cp") || (arg.startsWith("-classpath"))) {
classpathIndex = i;
}
commandLineBuilder.append(arg);
commandLineBuilder.append(' ');
}
pluginConfig.put(new PropertySimple(COMMAND_LINE_CONFIG_PROPERTY, commandLineBuilder.toString()));
if (classpathIndex != -1 && classpathIndex + 1 < arguments.length) {
String[] classpathEntries = arguments[classpathIndex + 1].split(File.pathSeparator);
File yamlConfigurationPath = null;
for (String classpathEntry : classpathEntries) {
if (classpathEntry.endsWith("conf")) {
yamlConfigurationPath = new File(classpathEntry);
if (!yamlConfigurationPath.isAbsolute()) {
try {
//relative path, use process CWD to find absolute path of the conf directory
yamlConfigurationPath = new File(processInfo.getExecutable().getCwd(), classpathEntry);
} catch (Exception e) {
log.error("Error creating path for yaml file.", e);
}
}
}
}
if (yamlConfigurationPath != null) {
File yamlConfigurationFile = new File(yamlConfigurationPath, "cassandra.yaml");
ConfigEditor yamlEditor = new ConfigEditor(yamlConfigurationFile);
yamlEditor.load();
pluginConfig.put(new PropertySimple(YAML_PROPERTY, yamlConfigurationFile.getAbsolutePath()));
pluginConfig.put(new PropertySimple(CLUSTER_NAME_PROPERTY, yamlEditor.getClusterName()));
pluginConfig.put(new PropertySimple(HOST_PROPERTY, yamlEditor.getListenAddress()));
pluginConfig.put(new PropertySimple(AUTHENTICATOR_PROPERTY, yamlEditor.getAuthenticator()));
}
}
if (jmxPort != null) {
pluginConfig.put(new PropertySimple(JMX_PORT_PROPERTY, jmxPort));
pluginConfig.put(new PropertySimple(JMXDiscoveryComponent.CONNECTION_TYPE,
J2SE5ConnectionTypeDescriptor.class.getName()));
pluginConfig.put(new PropertySimple(JMXDiscoveryComponent.CONNECTOR_ADDRESS_CONFIG_PROPERTY,
"service:jmx:rmi:///jndi/rmi://" + pluginConfig.getSimpleValue(HOST_PROPERTY) + ":" + jmxPort
+ "/jmxrmi"));
}
String resourceKey = "Cassandra (" + pluginConfig.getSimpleValue(HOST_PROPERTY) + ") " + jmxPort;
String resourceName = RESOURCE_NAME;
String path = processInfo.getExecutable().getCwd();
pluginConfig.put(new PropertySimple(BASEDIR_PROPERTY, new File(path).getParentFile().getAbsolutePath()));
return new DiscoveredResourceDetails(context.getResourceType(), resourceKey, resourceName, null, null,
pluginConfig, processInfo);
}
@SuppressWarnings("rawtypes")
@Override
public ResourceUpgradeReport upgrade(ResourceUpgradeContext inventoriedResource) {
// don't use super's impl because the resource key is not a JvmResourceKey
return null;
}
}