Skip to content
This repository has been archived by the owner on Jul 11, 2022. It is now read-only.

Commit

Permalink
Add BMX support.
Browse files Browse the repository at this point in the history
  • Loading branch information
jfclere committed Aug 21, 2014
1 parent c025874 commit 9a875c6
Show file tree
Hide file tree
Showing 4 changed files with 318 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,17 @@
import static org.rhq.core.domain.measurement.AvailabilityType.DOWN;
import static org.rhq.core.domain.measurement.AvailabilityType.UP;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.net.URLConnection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -56,10 +62,12 @@
import org.rhq.core.domain.configuration.Property;
import org.rhq.core.domain.configuration.PropertyList;
import org.rhq.core.domain.configuration.PropertyMap;
import org.rhq.core.domain.configuration.Property;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.domain.configuration.definition.ConfigurationDefinition;
import org.rhq.core.domain.event.EventSeverity;
import org.rhq.core.domain.measurement.AvailabilityType;
import org.rhq.core.domain.measurement.DataType;
import org.rhq.core.domain.measurement.MeasurementDataNumeric;
import org.rhq.core.domain.measurement.MeasurementDataTrait;
import org.rhq.core.domain.measurement.MeasurementReport;
Expand Down Expand Up @@ -105,6 +113,7 @@
*
* @author Ian Springer
* @author Lukas Krejci
* @author Maxime Beck (Remplacement of the SNMP Module with mod_bmx)
*/
public class ApacheServerComponent implements AugeasRHQComponent, ResourceComponent<PlatformComponent>,
MeasurementFacet, OperationFacet, ConfigurationFacet, CreateChildResourceFacet {
Expand All @@ -121,6 +130,7 @@ public class ApacheServerComponent implements AugeasRHQComponent, ResourceCompon
public static final String PLUGIN_CONFIG_PROP_EXECUTABLE_PATH = "executablePath";
public static final String PLUGIN_CONFIG_PROP_CONTROL_SCRIPT_PATH = "controlScriptPath";
public static final String PLUGIN_CONFIG_PROP_URL = "url";
public static final String PLUGIN_CONFIG_PROP_BMX_URL = "bmxUrl";
public static final String PLUGIN_CONFIG_PROP_HTTPD_CONF = "configFile";
public static final String AUGEAS_HTTP_MODULE_NAME = "Httpd";

Expand Down Expand Up @@ -166,6 +176,12 @@ public class ApacheServerComponent implements AugeasRHQComponent, ResourceCompon
private static final String[] CONTROL_SCRIPT_PATHS = { "bin/apachectl", "sbin/apachectl", "bin/apachectl2",
"sbin/apachectl2" };

private static final String DEFAULT_BMX_HANDLER_URL = "http://localhost:8000/bmx";

private static String bmxUrl;
private static boolean useBMX = false;
static Pattern typePattern = Pattern.compile(".*Type=([\\w-]+),.*");

private ResourceContext<PlatformComponent> resourceContext;
private EventContext eventContext;
private SNMPClient snmpClient;
Expand All @@ -175,7 +191,6 @@ public class ApacheServerComponent implements AugeasRHQComponent, ResourceCompon
private boolean augeasErrorLogged;

private Map<String, String> moduleNames;

/**
* Delegate instance for handling all calls to invoke operations on this component.
*/
Expand All @@ -190,8 +205,9 @@ public void start(ResourceContext<PlatformComponent> resourceContext) throws Exc
this.eventContext = resourceContext.getEventContext();
this.snmpClient = new SNMPClient();

boolean configured = false;

try {
boolean configured = false;

SNMPSession snmpSession = getSNMPSession();
if (!snmpSession.ping()) {
Expand All @@ -201,18 +217,21 @@ public void start(ResourceContext<PlatformComponent> resourceContext) throws Exc
+ ". Make sure\n1) the managed Apache server has been instrumented with the JON SNMP module,\n"
+ "2) the Apache server is running, and\n"
+ "3) the SNMP agent host, port, and community are set correctly in this resource's connection properties.\n"
+ "The agent will not be able to record metrics from apache httpd without SNMP");
+ "The agent might not be able to record metrics from apache httpd without SNMP");
} else {
configured = true;
}

Configuration pluginConfig = this.resourceContext.getPluginConfiguration();
String url = pluginConfig.getSimpleValue(PLUGIN_CONFIG_PROP_URL, null);
if (url != null) {
if (LOG.isDebugEnabled()) {
LOG.debug("Checking url " + bmxUrl);
}
try {
this.url = new URL(url);
if (this.url.getPort() == 0) {
LOG.error("The 'url' connection property is invalid - 0 is not a valid port; please change the value to the "
LOG.error("The 'URL' connection property is invalid - 0 is not a valid port; please change the value to the "
+ "port the \"main\" Apache server is listening on. NOTE: If the 'url' property was set this way "
+ "after autodiscovery, you most likely did not include the port in the ServerName directive for "
+ "the \"main\" Apache server in httpd.conf.");
Expand All @@ -225,9 +244,52 @@ public void start(ResourceContext<PlatformComponent> resourceContext) throws Exc
}
}

bmxUrl = pluginConfig.getSimpleValue(PLUGIN_CONFIG_PROP_BMX_URL, null);
if (bmxUrl != null) {
if (LOG.isDebugEnabled()) {
LOG.debug("Checking BMX url " + bmxUrl);
}
try {
URL uurl = new URL(bmxUrl);
if (uurl.getPort() == 0) {
LOG.error("The 'BMX Handler' connection property is invalid - 0 is not a valid port; please change the value to the "
+ "port the Apache server is listening on.");
} else {
if (this.url == null) {
this.url = uurl;
configured = true;
}
}
} catch (MalformedURLException e) {
throw new InvalidPluginConfigurationException("Value of '" + PLUGIN_CONFIG_PROP_BMX_URL
+ "' connection property ('" + bmxUrl + "') is not a valid URL.");
}
}
if (bmxUrl != null) {
if (LOG.isDebugEnabled()) {
LOG.debug("Testing BMX connection on " + bmxUrl);
}
try {
/* Check the BMX URL and use it if available */
URL uurl = new URL(bmxUrl);
HttpURLConnection conn = (HttpURLConnection) uurl.openConnection();
conn.connect();
if (conn.getResponseCode() == 200) {
useBMX = true;
LOG.info("BMX will be used to check availability");
}
conn.disconnect();
} catch (Exception ex) {
if (LOG.isDebugEnabled()) {
LOG.debug("BMX connection fails on " + bmxUrl + " with " + ex);
}
}
}


if (!configured) {
throw new InvalidPluginConfigurationException(
"Neither SNMP nor an URL for checking availability has been configured");
"Neither SNMP, BMX nor an URL for checking availability has been configured");
}

File executablePath = getExecutablePath();
Expand Down Expand Up @@ -268,6 +330,9 @@ public void start(ResourceContext<PlatformComponent> resourceContext) throws Exc

startEventPollers();
} catch (Exception e) {
if (LOG.isDebugEnabled()) {
LOG.debug("Initializing Resource component for Apache Server failed: " + e);
}
if (this.snmpClient != null) {
this.snmpClient.close();
}
Expand All @@ -286,6 +351,14 @@ public void stop() {
this.lastKnownAvailability = null;
}

public static String getBMXUrl() {
return bmxUrl;
}

public static boolean getUseBMX() {
return useBMX;
}

public AvailabilityType getAvailability() {
lastKnownAvailability = getAvailabilityInternal();
return lastKnownAvailability;
Expand Down Expand Up @@ -346,6 +419,12 @@ private AvailabilityType getAvailabilityInternal() {
}

public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest> schedules) throws Exception {
if (useBMX)
getBMXValues(report, schedules);
else
getSNMPValues(report, schedules);
}
private void getSNMPValues(MeasurementReport report, Set<MeasurementScheduleRequest> schedules) throws Exception {
SNMPSession snmpSession = getSNMPSession();
boolean snmpPresent = snmpSession.ping();

Expand Down Expand Up @@ -387,6 +466,123 @@ public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest>
}
}
}
private void getBMXValues(MeasurementReport report, Set<MeasurementScheduleRequest> schedules) throws Exception {
Map<String,String> values = parseBMXInput(null);
if (LOG.isDebugEnabled()) {
LOG.debug("BMX map: " + values);
}

for (MeasurementScheduleRequest schedule : schedules) {
String metricName = convertStringToBMX(schedule.getName());
if (LOG.isDebugEnabled()) {
LOG.debug("Collecting BMX metric [" + metricName + "]");
}
if (metricName.equals(SERVER_BUILT_TRAIT)) {
MeasurementDataTrait trait = new MeasurementDataTrait(schedule, this.binaryInfo.getBuilt());
report.addData(trait);
} else if (metricName.equals("rhq_avail_ping_time")) {
if (availPingTime == -1)
continue; // Skip if we have no data
MeasurementDataNumeric num = new MeasurementDataNumeric(schedule, (double) availPingTime);
report.addData(num);
} else if (values.containsKey(metricName)) {
if (schedule.getDataType()== DataType.TRAIT) {
String val = values.get(metricName);
MeasurementDataTrait mdt = new MeasurementDataTrait(schedule,val);
if (LOG.isDebugEnabled()) {
LOG.debug("Collected BMX metric [" + metricName + "], value = " + val);
}
report.addData(mdt);
} else {
Double val = Double.valueOf(values.get(metricName));
if (LOG.isDebugEnabled()) {
LOG.debug("Collected BMX metric [" + metricName + "], value = " + val);
}
MeasurementDataNumeric mdn = new MeasurementDataNumeric(schedule,val);
report.addData(mdn);
}
}
}
}

/* Convert the snmp name into the BMX one */
public static String convertStringToBMX(String string) {
if (string.equals("wwwServiceName"))
return "global:ServerName";
if (string.equals("wwwServiceStartTime"))
return "global:RestartTime";
if (string.startsWith("wwwSummary")) {
return "forever:" + string.substring(10);
} else if (string.startsWith("wwwRequest")) {
int index = string.indexOf('.');
return "restart:" + string.substring(10, index) + string.substring(index+1);
} else if (string.startsWith("wwwResponse")) {
int index = string.indexOf('.');
return "restart:" + string.substring(11, index) + string.substring(index+1);
}
return string;
}

public static Map<String, String> parseBMXInput(String vHost) throws Exception {
Map<String,String> ret = new HashMap<String, String>();
// TODO do some clever caching of data here, so that we won't hammer mod_bmx
URL url = new URL(bmxUrl);
URLConnection conn = url.openConnection();
BufferedInputStream in = new BufferedInputStream(conn.getInputStream());
BufferedReader reader = new BufferedReader(new InputStreamReader(in));

String line;

while ((line = reader.readLine())!=null) {

if (!line.startsWith("Name: mod_bmx_"))
continue;

// Skip over sample data - this is no real module
if (line.contains("mod_bmx_example"))
continue;

// Now we have a modules output

// check for the status module
if (line.contains("mod_bmx_status")) {
slurpSection(ret,reader,"global");
continue;
}


// If the section does not match our vhost, ignore it.
// TODO the vHost of RHQ needs to be ajusted to the BMX ones.
if (vHost == null)
vHost = "_GLOBAL_";
if (!line.contains("Host="+vHost))
continue;

// Now some global data
Matcher m = typePattern.matcher(line);

if (m.matches()) {
String type = m.group(1);
if (type.contains("-"))
type= type.substring(type.indexOf("-")+1);

slurpSection(ret, reader, type);
}
}

in.close();
return ret;
}

private static void slurpSection(Map<String, String> ret, BufferedReader reader, String type) throws IOException {
String line;
while (!(line = reader.readLine()).equals("")) {
int pos = line.indexOf(":");
String key = line.substring(0,pos);
String val = line.substring(pos+2);
ret.put(type + ":" + key , val);
}
}

private boolean isValueTimestamp(String mibName) {
return (mibName.equals("wwwServiceStartTime"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ public DiscoveryFailureException(String message, Throwable cause) {
MODULE_SOURCE_FILE_TO_MODULE_NAME_20.put("mod-snmpcommon.c", "snmpcommon_module");
MODULE_SOURCE_FILE_TO_MODULE_NAME_20.put("mod-snmpagt.c", "snmpagt_module");
MODULE_SOURCE_FILE_TO_MODULE_NAME_20.put("covalent-snmp-v20.c", "snmp_agt_module");
MODULE_SOURCE_FILE_TO_MODULE_NAME_20.put("mod_bmx.c", "bmx_module");

//this list is for apache 1.3
MODULE_SOURCE_FILE_TO_MODULE_NAME_13 = new LinkedHashMap<String, String>();
Expand Down Expand Up @@ -364,6 +365,9 @@ private DiscoveredResourceDetails discoverSingleProcess(
pluginConfig.put(new PropertySimple(ApacheServerComponent.PLUGIN_CONFIG_PROP_SNMP_AGENT_HOST, host
.getHostAddress()));
pluginConfig.put(new PropertySimple(ApacheServerComponent.PLUGIN_CONFIG_PROP_SNMP_AGENT_PORT, port));
} else {
/* try mod_bmx VirtualHost and Location */
snmpAddresses = findBMXAddresses(serverConfig, new File(serverRoot));
}

return createResourceDetails(discoveryContext, pluginConfig, process.getProcessInfo(), binaryInfo);
Expand Down Expand Up @@ -806,6 +810,18 @@ private static List<InetSocketAddress> findSNMPAddresses(ApacheDirectiveTree tre
return ret;
}

/* TODO: try to find the VirtualHost containing something like:
* <Location /bmx>
* SetHandler bmx-handler
* </Location>
*/
private static List<InetSocketAddress> findBMXAddresses(ApacheDirectiveTree tree, File serverRoot) {
List<InetSocketAddress> ret = new ArrayList<InetSocketAddress>();

return ret;
}
/* TODO: We need also the Location */

private static String findSNMPAgentAddressConfigLine(File snmpdConf) throws IOException {
BufferedReader rdr = new BufferedReader(new FileReader(snmpdConf));

Expand Down

0 comments on commit 9a875c6

Please sign in to comment.