All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.rhq.plugins.apache.ApacheVirtualHostServiceDiscoveryComponent Maven / Gradle / Ivy

There is a newer version: 4.13.0
Show newest version
/*
 * 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);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy