/*
* RHQ Management Platform
* Copyright (C) 2005-2011 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.setup;
import static org.testng.Assert.assertTrue;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.rhq.core.clientapi.server.discovery.InventoryReport;
import org.rhq.core.domain.discovery.AvailabilityReport;
import org.rhq.core.domain.resource.InventoryStatus;
import org.rhq.core.domain.resource.Resource;
import org.rhq.core.domain.resource.ResourceError;
import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.pc.ServerServices;
import org.rhq.core.pc.upgrade.FakeServerInventory;
import org.rhq.core.system.SystemInfoFactory;
import org.rhq.core.util.TokenReplacingReader;
import org.rhq.core.util.file.FileUtil;
import org.rhq.plugins.apache.ApacheServerComponent;
import org.rhq.plugins.apache.ApacheServerDiscoveryComponent;
import org.rhq.plugins.apache.ApacheVirtualHostServiceComponent;
import org.rhq.plugins.apache.ApacheVirtualHostServiceDiscoveryComponent;
import org.rhq.plugins.apache.parser.ApacheDirectiveTree;
import org.rhq.plugins.apache.util.ApacheBinaryInfo;
import org.rhq.plugins.apache.util.ApacheDeploymentUtil;
import org.rhq.plugins.apache.util.ApacheDeploymentUtil.DeploymentConfig;
import org.rhq.plugins.apache.util.ApacheExecutionUtil;
import org.rhq.plugins.apache.util.ApacheExecutionUtil.ExpectedApacheState;
import org.rhq.plugins.apache.util.HttpdAddressUtility;
import org.rhq.plugins.apache.util.ResourceTypes;
import org.rhq.plugins.apache.util.VHostSpec;
import org.rhq.test.ObjectCollectionSerializer;
import org.rhq.test.pc.PluginContainerTest;
public class ApacheTestSetup {
private String configurationName;
private FakeServerInventory fakeInventory = new FakeServerInventory();
private String inventoryFile;
private Resource platform;
private ApacheSetup apacheSetup = new ApacheSetup();
private DeploymentConfig deploymentConfig;
private Map<String, String> defaultOverrides = new HashMap<String, String>();
private Map<String, String> inventoryFileReplacements;
private Mockery context;
private ResourceTypes apacheResourceTypes;
private String testId;
public class ApacheSetup {
private String serverRoot;
private String exePath;
private Collection<String> configurationFiles;
private ApacheExecutionUtil execution;
private boolean deploy = true;
private ApacheSetup() {
}
public ApacheSetup withServerRoot(String serverRoot) {
this.serverRoot = serverRoot;
//auto-define the server root property as if it was passed on the commandline
System.getProperties().put(configurationName + ".server.root", serverRoot);
deploymentConfig = ApacheDeploymentUtil.getDeploymentConfigurationFromSystemProperties(configurationName, defaultOverrides);
return this;
}
public ApacheSetup withExePath(String exePath) {
this.exePath = exePath;
return this;
}
public ApacheSetup withConfigurationFiles(String... classPathUris) {
return withConfigurationFiles(Arrays.asList(classPathUris));
}
public ApacheSetup withConfigurationFiles(Collection<String> classPathUris) {
this.configurationFiles = classPathUris;
return this;
}
public ApacheSetup withDeploymentOnSetup() {
this.deploy = true;
return this;
}
public ApacheSetup withNoDeploymentOnSetup() {
this.deploy = false;
return this;
}
public void startApache() throws Exception {
//clear the error log
File errorLog = new File(new File(new File(serverRoot), "logs"), "error_log");
errorLog.delete();
getExecutionUtil().invokeOperation(ExpectedApacheState.RUNNING, "start");
}
public void stopApache() throws Exception {
getExecutionUtil().invokeOperation(ExpectedApacheState.STOPPED, "stop");
//save a copy of the error log
File errorLog = new File(new File(new File(serverRoot), "logs"), "error_log");
if (errorLog.exists() && errorLog.canRead()) {
String copyName = testId + ".httpd.error_log";
FileUtil.copyFile(errorLog, new File(new File("target"), copyName));
}
}
public void reloadApache() {
}
public ApacheServerComponent getServerComponent() {
return getExecutionUtil().getServerComponent();
}
public ApacheDirectiveTree getRuntimeConfiguration() {
return getExecutionUtil().getRuntimeConfiguration();
}
public ApacheExecutionUtil getExecutionUtil() {
return execution;
}
public void init() throws Exception {
File serverRootDir = new File(serverRoot);
assertTrue(serverRootDir.exists(), "The configured server root denotes a non-existant directory: '"
+ serverRootDir + "'.");
File logsDir = new File(serverRootDir, "logs");
assertTrue(logsDir.exists(), "The configured server root denotes a directory that doesn't have a 'logs' subdirectory. This is unexpected.");
File confDir = new File(serverRootDir, "conf");
assertTrue(confDir.exists(),
"The configured server root denotes a directory that doesn't have a 'conf' subdirectory. This is unexpected.");
String confFilePath = confDir.getAbsolutePath() + File.separatorChar + "httpd.conf";
String snmpHost = null;
int snmpPort = 0;
String pingUrl = null;
if (configurationName != null) {
if (deploy) {
File binDir = new File(serverRootDir, "bin");
List<File> additionalFilesToProcess = Arrays.asList(
new File(binDir, "apachectl"),
new File(binDir, "envvars"),
new File(binDir, "envvars-std"));
ApacheDeploymentUtil.deployConfiguration(confDir, configurationFiles, additionalFilesToProcess, deploymentConfig);
}
//ok, now try to find the ping URL. The best thing is to actually invoke
//the same code the apache server discovery does.
ApacheDirectiveTree tree = ApacheServerDiscoveryComponent.parseRuntimeConfiguration(confFilePath, null, ApacheBinaryInfo.getInfo(exePath, SystemInfoFactory.createSystemInfo()));
//XXX this hardcodes apache2 as the only option we have...
HttpdAddressUtility.Address addrToUse = HttpdAddressUtility.APACHE_2_x.getMainServerSampleAddress(tree, null, -1);
pingUrl = addrToUse.toString();
snmpHost = deploymentConfig.snmpHost;
snmpPort = deploymentConfig.snmpPort;
}
execution = new ApacheExecutionUtil(apacheResourceTypes.findByName("Apache HTTP Server"),
serverRoot, exePath, confFilePath, pingUrl,
snmpHost, snmpPort);
execution.init();
}
private void doSetup() throws Exception {
init();
startApache();
}
public ApacheTestSetup setup() throws Exception {
return ApacheTestSetup.this.setup();
}
}
public ApacheTestSetup(String testId, String configurationName, Mockery context,
ResourceTypes apacheResourceTypes) {
this.testId = testId;
this.configurationName = configurationName;
this.context = context;
this.apacheResourceTypes = apacheResourceTypes;
deploymentConfig = ApacheDeploymentUtil.getDeploymentConfigurationFromSystemProperties(configurationName, defaultOverrides);
}
public ApacheTestSetup withInventoryFrom(String classPathUri) {
inventoryFile = classPathUri;
return this;
}
public ApacheTestSetup withDefaultOverrides(Map<String, String> defaultOverrides) {
this.defaultOverrides = defaultOverrides == null ? new HashMap<String, String>() : defaultOverrides;
deploymentConfig = ApacheDeploymentUtil.getDeploymentConfigurationFromSystemProperties(configurationName, this.defaultOverrides);
return this;
}
public ApacheTestSetup withPlatformResource(Resource platform) {
this.platform = platform;
return this;
}
public ApacheSetup withApacheSetup() {
return apacheSetup;
}
public ApacheTestSetup withDefaultExpectations() throws Exception {
context.checking(new Expectations() {
{
addDefaultExpectations(this);
}
});
return this;
}
@SuppressWarnings("unchecked")
public void addDefaultExpectations(Expectations expectations) throws Exception {
ServerServices ss = PluginContainerTest.getCurrentPluginContainerConfiguration().getServerServices();
//only import the apache servers we actually care about - we can't assume another apache won't be present
//on the machine running the test...
final ResourceType serverResourceType = apacheResourceTypes.findByName("Apache HTTP Server");
expectations.allowing(ss.getDiscoveryServerService()).mergeInventoryReport(
expectations.with(Expectations.any(InventoryReport.class)));
expectations.will(fakeInventory.mergeInventoryReport(new FakeServerInventory.InventoryStatusJudge() {
@Override
public InventoryStatus judge(Resource resource) {
if (serverResourceType.equals(resource.getResourceType())) {
return deploymentConfig.serverRoot.equals(resource.getPluginConfiguration().getSimpleValue(
ApacheServerComponent.PLUGIN_CONFIG_PROP_SERVER_ROOT)) ? InventoryStatus.COMMITTED
: InventoryStatus.IGNORED;
} else {
return InventoryStatus.COMMITTED;
}
}
}));
expectations.allowing(ss.getDiscoveryServerService()).getResourceSyncInfo(
expectations.with(Expectations.any(Integer.class)));
expectations.will(fakeInventory.getResourceSyncInfo());
expectations.allowing(ss.getDiscoveryServerService()).upgradeResources(
expectations.with(Expectations.any(Set.class)));
expectations.will(fakeInventory.upgradeResources());
expectations.allowing(ss.getDiscoveryServerService()).getResources(
expectations.with(Expectations.any(Set.class)), expectations.with(Expectations.any(boolean.class)));
expectations.will(fakeInventory.getResources());
expectations.allowing(ss.getDiscoveryServerService()).setResourceError(expectations.with(Expectations.any(ResourceError.class)));
expectations.will(fakeInventory.setResourceError());
expectations.allowing(ss.getDiscoveryServerService()).mergeAvailabilityReport(
expectations.with(Expectations.any(AvailabilityReport.class)));
expectations.allowing(ss.getDiscoveryServerService()).postProcessNewlyCommittedResources(
expectations.with(Expectations.any(Set.class)));
expectations.allowing(ss.getDiscoveryServerService()).clearResourceConfigError(
expectations.with(Expectations.any(int.class)));
expectations.allowing(ss.getDiscoveryServerService()).setResourceEnablement(
expectations.with(Expectations.any(int.class)), expectations.with(Expectations.any(boolean.class)));
expectations.allowing(ss.getDiscoveryServerService()).updateResourceVersion(
expectations.with(Expectations.any(int.class)), expectations.with(Expectations.any(String.class)));
expectations.allowing(ss.getDriftServerService()).getDriftDefinitions(expectations.with(Expectations.any(Set.class)));
expectations.will(Expectations.returnValue(Collections.emptyMap()));
expectations.allowing(ss.getDiscoveryServerService()).getResourcesAsList(expectations.with(Expectations.any(Integer[].class)));
expectations.will(fakeInventory.getResourcesAsList());
expectations.ignoring(ss.getBundleServerService());
expectations.ignoring(ss.getConfigurationServerService());
expectations.ignoring(ss.getContentServerService());
expectations.ignoring(ss.getCoreServerService());
expectations.ignoring(ss.getEventServerService());
expectations.ignoring(ss.getMeasurementServerService());
expectations.ignoring(ss.getOperationServerService());
expectations.ignoring(ss.getResourceFactoryServerService());
}
public FakeServerInventory getFakeInventory() {
return fakeInventory;
}
public DeploymentConfig getDeploymentConfig() {
return deploymentConfig;
}
public ApacheTestSetup setup() throws Exception {
apacheSetup.doSetup();
Map<String, String> replacements = deploymentConfig.getTokenReplacements();
replacements.put("server.root", apacheSetup.serverRoot);
replacements.put("exe.path", apacheSetup.exePath);
ApacheDeploymentUtil.addDefaultVariables(replacements, null);
HttpdAddressUtility addressUtility = apacheSetup.getServerComponent()
.getAddressUtility();
ApacheDirectiveTree runtimeConfig = apacheSetup.getRuntimeConfiguration();
replacements.put("snmp.identifier",
addressUtility.getHttpdInternalMainServerAddressRepresentation(runtimeConfig).toString(false, false));
replacements.put("main.rhq4.resource.key", ApacheVirtualHostServiceComponent.MAIN_SERVER_RESOURCE_KEY);
VHostSpec vhost1 = deploymentConfig.vhost1 == null ? null : deploymentConfig.vhost1.getVHostSpec(replacements);
VHostSpec vhost2 = deploymentConfig.vhost2 == null ? null : deploymentConfig.vhost2.getVHostSpec(replacements);
VHostSpec vhost3 = deploymentConfig.vhost3 == null ? null : deploymentConfig.vhost3.getVHostSpec(replacements);
VHostSpec vhost4 = deploymentConfig.vhost4 == null ? null : deploymentConfig.vhost4.getVHostSpec(replacements);
if (vhost1 != null) {
replacements.put(
"vhost1.snmp.identifier",
addressUtility.getHttpdInternalVirtualHostAddressRepresentation(runtimeConfig, vhost1.hosts.get(0),
vhost1.serverName).toString(false, false));
replacements.put(
"vhost1.rhq4.resource.key",
ApacheVirtualHostServiceDiscoveryComponent.createResourceKey(
vhost1.serverName, vhost1.hosts));
}
if (vhost2 != null) {
replacements.put(
"vhost2.snmp.identifier",
addressUtility.getHttpdInternalVirtualHostAddressRepresentation(runtimeConfig, vhost2.hosts.get(0),
vhost2.serverName).toString(false, false));
replacements.put(
"vhost2.rhq4.resource.key",
ApacheVirtualHostServiceDiscoveryComponent.createResourceKey(
vhost2.serverName, vhost2.hosts));
}
if (vhost3 != null) {
replacements.put(
"vhost3.snmp.identifier",
addressUtility.getHttpdInternalVirtualHostAddressRepresentation(runtimeConfig, vhost3.hosts.get(0),
vhost3.serverName).toString(false, false));
replacements.put(
"vhost3.rhq4.resource.key",
ApacheVirtualHostServiceDiscoveryComponent.createResourceKey(
vhost3.serverName, vhost3.hosts));
}
if (vhost4 != null) {
replacements.put(
"vhost4.snmp.identifier",
addressUtility.getHttpdInternalVirtualHostAddressRepresentation(runtimeConfig, vhost4.hosts.get(0),
vhost4.serverName).toString(false, false));
replacements.put(
"vhost4.rhq4.resource.key",
ApacheVirtualHostServiceDiscoveryComponent.createResourceKey(
vhost4.serverName, vhost4.hosts));
}
//let the user override everything we just did
replacements.putAll(defaultOverrides);
inventoryFileReplacements = replacements;
if (inventoryFile != null) {
InputStream dataStream = getClass().getResourceAsStream(inventoryFile);
Reader rdr = new TokenReplacingReader(new InputStreamReader(dataStream), replacements);
@SuppressWarnings("unchecked")
List<Resource> inventory = (List<Resource>) new ObjectCollectionSerializer().deserialize(rdr);
//fix up the parent relationships, because they might not be reconstructed correctly by
//JAXB - we're missing XmlID and XmlIDRef annotations in our model
fixupParent(null, inventory);
fakeInventory.prepopulateInventory(platform, inventory);
}
return this;
}
/**
* After the setup, this returns all the variables used to update the tokens in the inventory file.
*
* @return
*/
public Map<String, String> getInventoryFileReplacements() {
return inventoryFileReplacements;
}
private void fixupParent(Resource parent, Collection<Resource> children) {
for (Resource child : children) {
child.setParentResource(parent);
if (child.getChildResources() != null) {
fixupParent(child, child.getChildResources());
}
}
}
}