/*
* Copyright 2009 LinkedIn, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package voldemort.utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import voldemort.VoldemortException;
/**
* Testing on EC2 requires quite a few configuration properties; these are
* provided in a *.properties file, the path of which is provided in the
* "ec2PropertiesFile" System property. Below is a table of the properties:
*
* <table>
* <th>Name</th>
* <th>Description</th>
* <tr>
* <td>ec2AccessId</td>
* <td>EC2 access ID, provided by Amazon</td>
* </tr>
* <tr>
* <td>ec2SecretKey</td>
* <td>EC2 secret key, provided by Amazon</td>
* </tr>
* <tr>
* <td>ec2Ami</td>
* <td>ID of the EC2 AMI used for the instances that are started</td>
* </tr>
* <tr>
* <td>ec2KeyPairId</td>
* <td>Key pair ID</td>
* </tr>
* <tr>
* <td>ec2SshPrivateKeyPath</td>
* <td>SSH private key path to key used to connect to instances (optional)</td>
* </tr>
* <tr>
* <td>ec2HostUserId</td>
* <td>User ID on the hosts; for EC2 this is usually "root"</td>
* </tr>
* <tr>
* <td>ec2VoldemortRootDirectory</td>
* <td>Root directory on remote instances that points to the the Voldemort
* "distribution" directory; relative to the host user ID's home directory. For
* example, if the remote user's home directory is /root and the Voldemort
* distribution directory is /root/voldemort, ec2VoldemortRootDirectory would be
* "voldemort"</td>
* </tr>
* <tr>
* <td>ec2VoldemortHomeDirectory</td>
* <td>Home directory on remote instances that points to the configuration
* directory, relative to the host user ID's home directory. For example, if the
* remote user's home directory is /root and the Voldemort configuration
* directory is /root/voldemort/config/single_node_cluster,
* ec2VoldemortHomeDirectory would be "voldemort/config/single_node_cluster"</td>
* </tr>
* <tr>
* <td>ec2SourceDirectory</td>
* <td>Source directory on <b>local</b> machine from which to copy the Voldemort
* "distribution" to the remote hosts; e.g. "/home/kirk/voldemortdev/voldemort"</td>
* </tr>
* <tr>
* <td>ec2ParentDirectory</td>
* <td>Parent directory on the <b>remote</b> machine into which to copy the
* Voldemort "distribution". For example, if the remote user's home directory is
* /root and the Voldemort distribution directory is /root/voldemort,
* ec2ParentDirectory would be "." or "/root".</td>
* </tr>
* <tr>
* <td>ec2ClusterXmlFile</td>
* <td><b>Local</b> path to which cluster.xml will be written with EC2 hosts;
* this needs to live under the ec2SourceDirectory's configuration directory
* that is copied to the remote host.</td>
* </tr>
* <tr>
* <td>ec2InstanceCount</td>
* <td>The number of instances to create.</td>
* </tr>
* <tr>
* <td>ec2InstanceIdFile</td>
* <td>File in which to list the instances that are created; used by external
* tools to stop instances in case of catastrophic test failure</td>
* </tr>
* </table>
*
*/
public class Ec2RemoteTestConfig extends RemoteTestConfig {
protected String accessId;
protected String secretKey;
protected String ami;
protected String keyPairId;
protected int instanceCount;
protected File instanceIdFile;
public Ec2RemoteTestConfig() {
Properties properties = getEc2Properties();
init(properties);
}
public String getAccessId() {
return accessId;
}
public void setAccessId(String accessId) {
this.accessId = accessId;
}
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public String getAmi() {
return ami;
}
public void setAmi(String ami) {
this.ami = ami;
}
public String getKeyPairId() {
return keyPairId;
}
public void setKeyPairId(String keyPairId) {
this.keyPairId = keyPairId;
}
public int getInstanceCount() {
return instanceCount;
}
public void setInstanceCount(int instanceCount) {
this.instanceCount = instanceCount;
}
public File getInstanceIdFile() {
return instanceIdFile;
}
public void setInstanceIdFile(File instanceIdFile) {
this.instanceIdFile = instanceIdFile;
}
protected void init(Properties properties) {
setAccessId(properties.getProperty("ec2AccessId"));
setSecretKey(properties.getProperty("ec2SecretKey"));
setAmi(properties.getProperty("ec2Ami"));
setKeyPairId(properties.getProperty("ec2KeyPairId"));
setHostUserId(properties.getProperty("ec2HostUserId"));
setSshPrivateKey(getFileProperty(properties, "ec2SshPrivateKeyPath"));
setVoldemortRootDirectory(properties.getProperty("ec2VoldemortRootDirectory"));
setVoldemortHomeDirectory(properties.getProperty("ec2VoldemortHomeDirectory"));
setSourceDirectory(getFileProperty(properties, "ec2SourceDirectory"));
setParentDirectory(properties.getProperty("ec2ParentDirectory"));
setClusterXmlFile(getFileProperty(properties, "ec2ClusterXmlFile"));
setInstanceCount(getIntProperty(properties, "ec2InstanceCount"));
setInstanceIdFile(getFileProperty(properties, "ec2InstanceIdFile"));
}
protected File getFileProperty(Properties properties, String propertyName) {
String value = properties.getProperty(propertyName);
return value != null ? new File(value) : null;
}
protected int getIntProperty(Properties properties, String propertyName) {
String value = properties.getProperty(propertyName);
return value != null ? Integer.parseInt(value) : 0;
}
protected int getIntProperty(Properties properties, String propertyName, int defaultValue) {
String value = properties.getProperty(propertyName);
return value != null ? Integer.parseInt(value) : defaultValue;
}
protected Properties getEc2Properties() {
String propertiesFileName = System.getProperty("ec2PropertiesFile");
List<String> requireds = getRequiredPropertyNames();
if(propertiesFileName == null)
throw new VoldemortException("ec2PropertiesFile system property must be defined that "
+ "provides the path to file containing the following "
+ "required properties: "
+ StringUtils.join(requireds, ", "));
Properties properties = new Properties();
InputStream in = null;
try {
in = new FileInputStream(propertiesFileName);
properties.load(in);
} catch(IOException e) {
throw new VoldemortException(e);
} finally {
IOUtils.closeQuietly(in);
}
for(String required: requireds) {
// Allow system properties to override
if(System.getProperties().containsKey(required))
properties.put(required, System.getProperty(required));
if(!properties.containsKey(required))
throw new VoldemortException("Required properties: "
+ StringUtils.join(requireds, ", ") + "; missing "
+ required);
}
return properties;
}
protected List<String> getRequiredPropertyNames() {
// There's a reason we're making two lists: Arrays.asList makes an
// immutable list. However, we want to return a mutable list to the
// caller as subclasses may modify the list "in place."
return new ArrayList<String>(Arrays.asList("ec2AccessId",
"ec2SecretKey",
"ec2Ami",
"ec2KeyPairId",
"ec2HostUserId",
"ec2VoldemortRootDirectory",
"ec2VoldemortHomeDirectory",
"ec2SourceDirectory",
"ec2ParentDirectory",
"ec2ClusterXmlFile",
"ec2InstanceCount",
"ec2InstanceIdFile"));
}
}