org.rhq.plugins.apache.ApacheVirtualHostServiceDiscoveryComponent Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rhq-apache-plugin Show documentation
Show all versions of rhq-apache-plugin Show documentation
a plugin for managing Apache web servers (1.3 and later)
/*
* RHQ Management Platform
* Copyright (C) 2005-2008 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 as published by
* the Free Software Foundation version 2 of the License.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.rhq.plugins.apache;
import java.io.File;
import java.net.InetAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.domain.resource.ResourceUpgradeReport;
import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
import org.rhq.core.pluginapi.upgrade.ResourceUpgradeContext;
import org.rhq.core.pluginapi.upgrade.ResourceUpgradeFacet;
import org.rhq.plugins.apache.parser.ApacheDirectiveTree;
import org.rhq.plugins.apache.util.HttpdAddressUtility;
import org.rhq.plugins.apache.util.RuntimeApacheConfiguration;
import org.rhq.plugins.apache.util.VHostSpec;
import org.rhq.plugins.apache.util.VirtualHostLegacyResourceKeyUtil;
import org.rhq.plugins.apache.util.HttpdAddressUtility.Address;
import org.rhq.plugins.www.snmp.SNMPException;
import org.rhq.plugins.www.snmp.SNMPSession;
import org.rhq.plugins.www.snmp.SNMPValue;
/**
* Discovers VirtualHosts under the Apache server by reading them out from Augeas tree constructed
* in the parent component. If Augeas is not present, an attempt is made to discover the vhosts using
* SNMP module.
*
* @author Ian Springer
* @author Lukas Krejci
*/
public class ApacheVirtualHostServiceDiscoveryComponent implements ResourceDiscoveryComponent,
ResourceUpgradeFacet {
private static final String COULD_NOT_DETERMINE_THE_VIRTUAL_HOST_ADDRESS =
"*** Could not determine the virtual host address ***";
public static final String LOGS_DIRECTORY_NAME = "logs";
private static final String RT_LOG_FILE_NAME_SUFFIX = "_rt.log";
private static final String LEGACY_SNMP_SERVICE_INDEX_CONFIG_PROP = "snmpWwwServiceIndex";
private static final Log log = LogFactory.getLog(ApacheVirtualHostServiceDiscoveryComponent.class);
public Set discoverResources(ResourceDiscoveryContext context)
throws InvalidPluginConfigurationException, Exception {
Set discoveredResources = new LinkedHashSet();
ApacheServerComponent serverComponent = context.getParentResourceComponent();
ApacheDirectiveTree tree = serverComponent.parseRuntimeConfiguration(false);
//first define the root server as one virtual host
discoverMainServer(context, tree, discoveredResources);
ResourceType resourceType = context.getResourceType();
File configPath = serverComponent.getServerRoot();
File logsDir = new File(configPath, LOGS_DIRECTORY_NAME);
for (VHostSpec vhost : VHostSpec.detect(tree)) {
String firstAddress = vhost.hosts.get(0);
String resourceKey = createResourceKey(vhost.serverName, vhost.hosts);
String resourceName = resourceKey; //this'll get overridden below if we find a better value using the address variable
Configuration pluginConfiguration = context.getDefaultPluginConfiguration();
Address address =
serverComponent.getAddressUtility().getVirtualHostSampleAddress(tree, firstAddress, vhost.serverName,
false);
if (address != null) {
String scheme = address.scheme;
String hostToPing = address.host;
int portToPing = address.port;
if (address.isPortWildcard() || !address.isPortDefined()) {
Address serverAddress =
serverComponent.getAddressUtility().getMainServerSampleAddress(tree, hostToPing, 0);
if (serverAddress != null) {
portToPing = serverAddress.port;
} else {
portToPing = Address.PORT_WILDCARD_VALUE;
}
}
if (address.isHostDefault() || address.isHostWildcard()) {
Address serverAddress =
serverComponent.getAddressUtility().getMainServerSampleAddress(tree, null, portToPing);
if (serverAddress != null) {
hostToPing = serverAddress.host;
} else {
hostToPing = null;
}
}
String url;
if (hostToPing != null && portToPing != Address.PORT_WILDCARD_VALUE
&& portToPing != Address.NO_PORT_SPECIFIED_VALUE) {
url = scheme + "://" + hostToPing + ":" + portToPing + "/";
} else {
url = COULD_NOT_DETERMINE_THE_VIRTUAL_HOST_ADDRESS;
}
PropertySimple urlProp = new PropertySimple(ApacheVirtualHostServiceComponent.URL_CONFIG_PROP, url);
pluginConfiguration.put(urlProp);
File rtLogFile = new File(logsDir, address.host + address.port + RT_LOG_FILE_NAME_SUFFIX);
PropertySimple rtLogProp =
new PropertySimple(ApacheVirtualHostServiceComponent.RESPONSE_TIME_LOG_FILE_CONFIG_PROP,
rtLogFile.toString());
pluginConfiguration.put(rtLogProp);
//redefine the resourcename using the virtual host sample address
resourceName = address.toString(false, true);
}
discoveredResources.add(new DiscoveredResourceDetails(resourceType, resourceKey, resourceName, null, null,
pluginConfiguration, null));
}
return discoveredResources;
}
public ResourceUpgradeReport upgrade(ResourceUpgradeContext inventoriedResource) {
String resourceKey = inventoriedResource.getResourceKey();
if (ApacheVirtualHostServiceComponent.MAIN_SERVER_RESOURCE_KEY.equals(resourceKey) || resourceKey.contains("|")) {
//a new style resource key. we're done.
return null;
}
String newResourceKey = null;
ApacheServerComponent serverComponent = inventoriedResource.getParentResourceComponent();
ApacheDirectiveTree tree = serverComponent.parseRuntimeConfiguration(false);
List vhosts = VHostSpec.detect(tree);
VirtualHostLegacyResourceKeyUtil legacyResourceKeyUtil =
new VirtualHostLegacyResourceKeyUtil(serverComponent, tree);
//first, let's see if the inventoried resource has the snmpWwwServiceIndex property set
//if it does, use that to determine what vhost this corresponds to.
String snmpServiceIndexString =
inventoriedResource.getPluginConfiguration().getSimpleValue(LEGACY_SNMP_SERVICE_INDEX_CONFIG_PROP, null);
if (snmpServiceIndexString != null) {
Integer snmpServiceIndex = null;
try {
snmpServiceIndex = Integer.parseInt(snmpServiceIndexString);
} catch (NumberFormatException e) {
log.warn("Invalid format of the " + LEGACY_SNMP_SERVICE_INDEX_CONFIG_PROP
+ " property value. It should be an integer but is '" + snmpServiceIndexString
+ "'. The upgrade will continue using the resource key matching.", e);
}
if (snmpServiceIndex != null) {
if (snmpServiceIndex > 0) {
//yay, we can use the snmpService index to determine which vhost we're dealing with
if (snmpServiceIndex == 1) {
//k, looks the vhost was representing the main server. Let's do a cross-check.
Set legacyResourceKeys = legacyResourceKeyUtil.getLegacyMainServerResourceKeys();
if (legacyResourceKeys.contains(resourceKey)) {
newResourceKey = ApacheVirtualHostServiceComponent.MAIN_SERVER_RESOURCE_KEY;
} else {
log.debug("The cross-check of the SNMP WWW Service Index value and resource key failed for virtual host with old resource key: "
+ resourceKey + ". The upgrade will continue using resource key matching.");
}
} else {
if (vhosts.size() + 1 < snmpServiceIndex) {
log.debug("The "
+ LEGACY_SNMP_SERVICE_INDEX_CONFIG_PROP
+ " property contains incorrect value ("
+ snmpServiceIndex
+ "), which is larger than the total number of active virtual hosts in the configuration files ("
+ (vhosts.size() + 1) + ". The upgrade will continue using the resource key matching.");
} else {
//k, this seems to be a correct value
//the SNMP indices are in the reverse order of the definitions in the config files
//+1, where the main server is always on index 1.
VHostSpec vhost = vhosts.get(vhosts.size() - snmpServiceIndex + 1);
//right, let's do a cross-check before we actually create the resource key so
//that we catch user-generated errors.
Set legacyResourceKeys =
legacyResourceKeyUtil.getLegacyVirtualHostResourceKeys(vhost);
if (legacyResourceKeys.contains(resourceKey)) {
newResourceKey = createResourceKey(vhost.serverName, vhost.hosts);
} else {
log.debug("The cross-check of the SNMP WWW Service Index value and resource key failed for virtual host with old resource key: "
+ resourceKey + ". The upgrade will continue using resource key matching.");
}
}
}
} else {
log.warn("The " + LEGACY_SNMP_SERVICE_INDEX_CONFIG_PROP
+ " property should be a positive integer greater than zero but is " + snmpServiceIndex
+ " instead. The upgrade will continue using the resource key matching.");
}
}
}
if (newResourceKey != null) {
ResourceUpgradeReport report = new ResourceUpgradeReport();
report.setNewResourceKey(newResourceKey);
return report;
}
Map> possibleMatchesPerRK = new HashMap>();
for (VHostSpec vhost : vhosts) {
Set legacyResourceKeys = legacyResourceKeyUtil.getLegacyVirtualHostResourceKeys(vhost);
for (String legacyRK : legacyResourceKeys) {
addPossibleRKMatch(legacyRK, vhost, possibleMatchesPerRK);
}
}
for (String legacyRK : legacyResourceKeyUtil.getLegacyMainServerResourceKeys()) {
addPossibleRKMatch(legacyRK, null, possibleMatchesPerRK);
}
Set matchingVhosts = possibleMatchesPerRK.get(resourceKey);
if (matchingVhosts == null || matchingVhosts.isEmpty()) {
throw new IllegalArgumentException(
"Failed to identify the vhost resource with the old-style resource key '"
+ resourceKey
+ "' with any of the vhosts in the apache configuration files. This means that the vhost resource is stale and you can safely uninventory it.");
} else if (matchingVhosts.size() > 1) {
String message =
"Failed to uniquely identify the vhost from the old-style resource key. The old resource key is '"
+ resourceKey
+ "' which could be matched with any of the following possible new-style resource keys: "
+ matchingVhosts
+ ". The plugin does not have enough information to successfully upgrade this resource."
+ " Please take note of any alert definitions or operation schedules that you have defined for this resource and manually uninventory it.";
throw new IllegalArgumentException(message);
} else {
VHostSpec vhost = matchingVhosts.iterator().next();
if (vhost == null) {
newResourceKey = ApacheVirtualHostServiceComponent.MAIN_SERVER_RESOURCE_KEY;
} else {
newResourceKey = createResourceKey(vhost.serverName, vhost.hosts);
}
}
ResourceUpgradeReport report = new ResourceUpgradeReport();
report.setNewResourceKey(newResourceKey);
return report;
}
private void discoverMainServer(ResourceDiscoveryContext context,
ApacheDirectiveTree runtimeConfig, Set discoveredResources) throws Exception {
ResourceType resourceType = context.getResourceType();
Configuration mainServerPluginConfig = context.getDefaultPluginConfiguration();
File configPath = context.getParentResourceComponent().getServerRoot();
File logsDir = new File(configPath, LOGS_DIRECTORY_NAME);
String mainServerUrl =
context.getParentResourceContext().getPluginConfiguration()
.getSimple(ApacheServerComponent.PLUGIN_CONFIG_PROP_URL).getStringValue();
if (mainServerUrl == null || mainServerUrl.trim().isEmpty()) {
HttpdAddressUtility.Address addr =
context.getParentResourceComponent().getAddressUtility()
.getMainServerSampleAddress(runtimeConfig, null, 0);
mainServerUrl = addr.toString();
}
PropertySimple mainServerUrlProp =
new PropertySimple(ApacheVirtualHostServiceComponent.URL_CONFIG_PROP, mainServerUrl);
mainServerPluginConfig.put(mainServerUrlProp);
URI mainServerUri = new URI(mainServerUrl);
String host = mainServerUri.getHost();
int port = mainServerUri.getPort();
if (port == -1) {
port = 80;
}
File rtLogFile = new File(logsDir, host + port + RT_LOG_FILE_NAME_SUFFIX);
PropertySimple rtLogProp =
new PropertySimple(ApacheVirtualHostServiceComponent.RESPONSE_TIME_LOG_FILE_CONFIG_PROP,
rtLogFile.toString());
mainServerPluginConfig.put(rtLogProp);
String key = ApacheVirtualHostServiceComponent.MAIN_SERVER_RESOURCE_KEY;
DiscoveredResourceDetails mainServer =
new DiscoveredResourceDetails(resourceType, key, "Main", null, null, mainServerPluginConfig, null);
discoveredResources.add(mainServer);
}
public static String createResourceKey(String serverName, List hosts) {
StringBuilder keyBuilder = new StringBuilder();
if (serverName != null) {
keyBuilder.append(serverName);
}
keyBuilder.append("|"); //always do this so that we have a clear distinction between old and new style resource keys
keyBuilder.append(hosts.get(0));
for (int i = 1; i < hosts.size(); ++i) {
keyBuilder.append(" ").append(hosts.get(i));
}
return keyBuilder.toString();
}
private static void addPossibleRKMatch(String resourceKey, VHostSpec vhost,
Map> possibleMatches) {
Set matches = possibleMatches.get(resourceKey);
if (matches == null) {
matches = new HashSet();
possibleMatches.put(resourceKey, matches);
}
matches.add(vhost);
}
}