Issue 29: added support for elastic block store ami

git-svn-id: http://jclouds.googlecode.com/svn/trunk@2540 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
adrian.f.cole 2009-12-30 05:43:44 +00:00
parent 7300c0db77
commit 18201f319f
52 changed files with 2094 additions and 311 deletions

View File

@ -120,19 +120,19 @@ public class EC2ComputeService implements ComputeService {
1,
withKeyName(keyPair.getKeyName()).asType(type).withSecurityGroup(
securityGroupName).withAdditionalInfo(name)).getRunningInstances());
logger.debug("<< started instance(%s)", runningInstance.getInstanceId());
logger.debug("<< started instance(%s)", runningInstance.getId());
instanceStateRunning.apply(runningInstance);
logger.debug("<< running instance(%s)", runningInstance.getInstanceId());
logger.debug("<< running instance(%s)", runningInstance.getId());
// refresh to get IP address
runningInstance = getRunningInstance(runningInstance.getInstanceId());
runningInstance = getRunningInstance(runningInstance.getId());
Set<InetAddress> publicAddresses = runningInstance.getIpAddress() == null ? ImmutableSet
.<InetAddress> of() : ImmutableSet.<InetAddress> of(runningInstance.getIpAddress());
Set<InetAddress> privateAddresses = runningInstance.getPrivateIpAddress() == null ? ImmutableSet
.<InetAddress> of()
: ImmutableSet.<InetAddress> of(runningInstance.getPrivateIpAddress());
return new CreateServerResponseImpl(runningInstance.getInstanceId(), name,
return new CreateServerResponseImpl(runningInstance.getId(), name,
instanceToServerState.get(runningInstance.getInstanceState()), publicAddresses,
privateAddresses, 22, LoginType.SSH, new Credentials("root", keyPair
.getKeyMaterial()));
@ -194,7 +194,7 @@ public class EC2ComputeService implements ComputeService {
@Override
public ServerMetadata apply(RunningInstance from) {
return new ServerMetadataImpl(from.getInstanceId(), from.getKeyName(),
return new ServerMetadataImpl(from.getId(), from.getKeyName(),
instanceToServerState.get(from.getInstanceState()), nullSafeSet(from
.getIpAddress()), nullSafeSet(from.getPrivateIpAddress()), 22,
LoginType.SSH);
@ -239,7 +239,7 @@ public class EC2ComputeService implements ComputeService {
new Function<RunningInstance, ServerIdentity>() {
@Override
public ServerIdentity apply(RunningInstance from) {
return new ServerIdentityImpl(from.getInstanceId(), from.getKeyName());
return new ServerIdentityImpl(from.getId(), from.getKeyName());
}
}));
}
@ -252,9 +252,9 @@ public class EC2ComputeService implements ComputeService {
RunningInstance runningInstance = getRunningInstance(id);
// grab the old keyname
String name = runningInstance.getKeyName();
logger.debug(">> terminating instance(%s)", runningInstance.getInstanceId());
logger.debug(">> terminating instance(%s)", runningInstance.getId());
ec2Client.getInstanceServices().terminateInstancesInRegion(Region.DEFAULT, id);
logger.debug("<< terminated instance(%s)", runningInstance.getInstanceId());
logger.debug("<< terminated instance(%s)", runningInstance.getId());
logger.debug(">> deleting keyPair(%s)", name);
ec2Client.getKeyPairServices().deleteKeyPairInRegion(Region.DEFAULT, name);
logger.debug("<< deleted keyPair(%s)", name);

View File

@ -34,9 +34,9 @@ import java.util.Date;
* />
* @author Adrian Cole
*/
public class Attachment {
public class Attachment implements Comparable<Attachment> {
public static enum Status {
ATTACHING, ATTACHED, DETACHING, DETACHED;
ATTACHING, ATTACHED, DETACHING, DETACHED, BUSY;
public String value() {
return name().toLowerCase();
}
@ -86,7 +86,7 @@ public class Attachment {
/**
* The ID of the instance.
*/
public String getInstanceId() {
public String getId() {
return instanceId;
}
@ -173,4 +173,9 @@ public class Attachment {
+ status + "]";
}
@Override
public int compareTo(Attachment o) {
return attachTime.compareTo(o.attachTime);
}
}

View File

@ -28,7 +28,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import java.util.Set;
import com.google.common.base.CaseFormat;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
@ -70,8 +69,8 @@ public class Image implements Comparable<Image> {
@Nullable String description, String imageId, String imageLocation,
String imageOwnerId, ImageState imageState, ImageType imageType, boolean isPublic,
Iterable<String> productCodes, @Nullable String kernelId, @Nullable String platform,
@Nullable String ramdiskId, RootDeviceType rootDeviceType, String rootDeviceName,
Map<String, EbsBlockDevice> ebsBlockDevices) {
@Nullable String ramdiskId, RootDeviceType rootDeviceType,
@Nullable String rootDeviceName, Map<String, EbsBlockDevice> ebsBlockDevices) {
this.region = checkNotNull(region, "region");
this.architecture = checkNotNull(architecture, "architecture");
this.imageId = checkNotNull(imageId, "imageId");
@ -112,25 +111,6 @@ public class Image implements Comparable<Image> {
}
}
/**
* The root device type used by the AMI. The AMI can use an Amazon EBS or instance store root
* device.
*/
public static enum RootDeviceType {
INSTANCE_STORE,
EBS;
public String value() {
return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_HYPHEN, name());
}
public static RootDeviceType fromValue(String v) {
return valueOf(CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_UNDERSCORE, v));
}
}
public static enum Architecture {
I386, X86_64;
public String value() {
@ -237,7 +217,7 @@ public class Image implements Comparable<Image> {
/**
* The ID of the AMI.
*/
public String getImageId() {
public String getId() {
return imageId;
}
@ -311,7 +291,32 @@ public class Image implements Comparable<Image> {
* {@inheritDoc}
*/
public int compareTo(Image o) {
return (this == o) ? 0 : getImageId().compareTo(o.getImageId());
return (this == o) ? 0 : getId().compareTo(o.getId());
}
/**
*
* @return The root device type used by the AMI. The AMI can use an Amazon EBS or instance store
* root device.
*/
public RootDeviceType getRootDeviceType() {
return rootDeviceType;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public String getRootDeviceName() {
return rootDeviceName;
}
public Map<String, EbsBlockDevice> getEbsBlockDevices() {
return ebsBlockDevices;
}
@Override
@ -432,27 +437,6 @@ public class Image implements Comparable<Image> {
return true;
}
/**
*
* @return The root device type used by the AMI. The AMI can use an Amazon EBS or instance store
* root device.
*/
public RootDeviceType getRootDeviceType() {
return rootDeviceType;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public String getRootDeviceName() {
return rootDeviceName;
}
@Override
public String toString() {
return "Image [architecture=" + architecture + ", description=" + description
@ -465,8 +449,4 @@ public class Image implements Comparable<Image> {
+ rootDeviceType + "]";
}
public Map<String, EbsBlockDevice> getEbsBlockDevices() {
return ebsBlockDevices;
}
}

View File

@ -56,7 +56,15 @@ public enum InstanceState {
/**
* the instance terminated
*/
TERMINATED;
TERMINATED,
/**
* the instance is stopping
*/
STOPPING,
/**
* the instance is stopped
*/
STOPPED;
public String value() {
return name().toLowerCase().replaceAll("_", "-");
@ -81,6 +89,10 @@ public enum InstanceState {
return SHUTTING_DOWN;
case 48:
return TERMINATED;
case 64:
return STOPPING;
case 80:
return STOPPED;
default:
throw new IllegalArgumentException("invalid state:" + v);
}

View File

@ -32,22 +32,22 @@ import static com.google.common.base.Preconditions.checkNotNull;
* />
* @author Adrian Cole
*/
public class TerminatedInstance implements Comparable<TerminatedInstance> {
public class InstanceStateChange implements Comparable<InstanceStateChange> {
private final Region region;
private final String instanceId;
private final InstanceState shutdownState;
private final InstanceState currentState;
private final InstanceState previousState;
public int compareTo(TerminatedInstance o) {
public int compareTo(InstanceStateChange o) {
return (this == o) ? 0 : getInstanceId().compareTo(o.getInstanceId());
}
public TerminatedInstance(Region region, String instanceId, InstanceState shutdownState,
public InstanceStateChange(Region region, String instanceId, InstanceState currentState,
InstanceState previousState) {
this.region = checkNotNull(region, "region");
this.instanceId = instanceId;
this.shutdownState = shutdownState;
this.currentState = currentState;
this.previousState = previousState;
}
@ -62,8 +62,8 @@ public class TerminatedInstance implements Comparable<TerminatedInstance> {
return instanceId;
}
public InstanceState getShutdownState() {
return shutdownState;
public InstanceState getCurrentState() {
return currentState;
}
public InstanceState getPreviousState() {
@ -77,7 +77,7 @@ public class TerminatedInstance implements Comparable<TerminatedInstance> {
result = prime * result + ((instanceId == null) ? 0 : instanceId.hashCode());
result = prime * result + ((previousState == null) ? 0 : previousState.hashCode());
result = prime * result + ((region == null) ? 0 : region.hashCode());
result = prime * result + ((shutdownState == null) ? 0 : shutdownState.hashCode());
result = prime * result + ((currentState == null) ? 0 : currentState.hashCode());
return result;
}
@ -89,7 +89,7 @@ public class TerminatedInstance implements Comparable<TerminatedInstance> {
return false;
if (getClass() != obj.getClass())
return false;
TerminatedInstance other = (TerminatedInstance) obj;
InstanceStateChange other = (InstanceStateChange) obj;
if (instanceId == null) {
if (other.instanceId != null)
return false;
@ -105,12 +105,18 @@ public class TerminatedInstance implements Comparable<TerminatedInstance> {
return false;
} else if (!region.equals(other.region))
return false;
if (shutdownState == null) {
if (other.shutdownState != null)
if (currentState == null) {
if (other.currentState != null)
return false;
} else if (!shutdownState.equals(other.shutdownState))
} else if (!currentState.equals(other.currentState))
return false;
return true;
}
@Override
public String toString() {
return "InstanceStateChange [currentState=" + currentState + ", instanceId=" + instanceId
+ ", previousState=" + previousState + ", region=" + region + "]";
}
}

View File

@ -0,0 +1,47 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.jclouds.aws.ec2.domain;
import com.google.common.base.CaseFormat;
/**
* The root device type used by the AMI. The AMI can use an Amazon EBS or instance store root
* device.
*
* @author Adrian Cole
*/
public enum RootDeviceType {
INSTANCE_STORE,
EBS;
public String value() {
return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_HYPHEN, name());
}
public static RootDeviceType fromValue(String v) {
return valueOf(CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_UNDERSCORE, v));
}
}

View File

@ -27,8 +27,12 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.net.InetAddress;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import org.jclouds.aws.ec2.domain.Attachment.Status;
import com.google.common.collect.Maps;
import com.google.inject.internal.Nullable;
/**
@ -38,6 +42,81 @@ import com.google.inject.internal.Nullable;
* @author Adrian Cole
*/
public class RunningInstance implements Comparable<RunningInstance> {
public static class EbsBlockDevice {
private final String volumeId;
private final Attachment.Status attachmentStatus;
private final Date attachTime;
private final boolean deleteOnTermination;
public EbsBlockDevice(String volumeId, Status attachmentStatus, Date attachTime,
boolean deleteOnTermination) {
super();
this.volumeId = volumeId;
this.attachmentStatus = attachmentStatus;
this.attachTime = attachTime;
this.deleteOnTermination = deleteOnTermination;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((attachTime == null) ? 0 : attachTime.hashCode());
result = prime * result + ((attachmentStatus == null) ? 0 : attachmentStatus.hashCode());
result = prime * result + (deleteOnTermination ? 1231 : 1237);
result = prime * result + ((volumeId == null) ? 0 : volumeId.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
EbsBlockDevice other = (EbsBlockDevice) obj;
if (attachTime == null) {
if (other.attachTime != null)
return false;
} else if (!attachTime.equals(other.attachTime))
return false;
if (attachmentStatus == null) {
if (other.attachmentStatus != null)
return false;
} else if (!attachmentStatus.equals(other.attachmentStatus))
return false;
if (deleteOnTermination != other.deleteOnTermination)
return false;
if (volumeId == null) {
if (other.volumeId != null)
return false;
} else if (!volumeId.equals(other.volumeId))
return false;
return true;
}
public String getVolumeId() {
return volumeId;
}
public Attachment.Status getAttachmentStatus() {
return attachmentStatus;
}
public Date getAttachTime() {
return attachTime;
}
public boolean isDeleteOnTermination() {
return deleteOnTermination;
}
}
private final Region region;
private final String amiLaunchIndex;
@Nullable
private final String dnsName;
@ -69,22 +148,28 @@ public class RunningInstance implements Comparable<RunningInstance> {
private final String subnetId;
@Nullable
private final String vpcId;
private final RootDeviceType rootDeviceType;
@Nullable
private final String rootDeviceName;
private final Map<String, EbsBlockDevice> ebsBlockDevices = Maps.newHashMap();
public int compareTo(RunningInstance o) {
return (this == o) ? 0 : getInstanceId().compareTo(o.getInstanceId());
return (this == o) ? 0 : getId().compareTo(o.getId());
}
public RunningInstance(String amiLaunchIndex, @Nullable String dnsName, String imageId,
String instanceId, InstanceState instanceState, InstanceType instanceType,
@Nullable InetAddress ipAddress, @Nullable String kernelId, @Nullable String keyName,
Date launchTime, boolean monitoring, AvailabilityZone availabilityZone,
@Nullable String platform, @Nullable String privateDnsName,
@Nullable InetAddress privateIpAddress, Set<String> productCodes,
@Nullable String ramdiskId, @Nullable String reason, @Nullable String subnetId,
@Nullable String vpcId) {
this.amiLaunchIndex = checkNotNull(amiLaunchIndex, "amiLaunchIndex");
public RunningInstance(Region region, @Nullable String amiLaunchIndex, @Nullable String dnsName,
String imageId, String instanceId, InstanceState instanceState,
InstanceType instanceType, @Nullable InetAddress ipAddress, @Nullable String kernelId,
@Nullable String keyName, Date launchTime, boolean monitoring,
AvailabilityZone availabilityZone, @Nullable String platform,
@Nullable String privateDnsName, @Nullable InetAddress privateIpAddress,
Set<String> productCodes, @Nullable String ramdiskId, @Nullable String reason,
@Nullable String subnetId, @Nullable String vpcId, RootDeviceType rootDeviceType,
@Nullable String rootDeviceName, Map<String, EbsBlockDevice> ebsBlockDevices) {
this.region = checkNotNull(region, "region");
this.amiLaunchIndex = amiLaunchIndex; // nullable on runinstances.
this.dnsName = dnsName; // nullable on runinstances.
this.imageId = checkNotNull(imageId, "imageId");
this.imageId = imageId; // nullable on runinstances.
this.instanceId = checkNotNull(instanceId, "instanceId");
this.instanceState = checkNotNull(instanceState, "instanceState");
this.instanceType = checkNotNull(instanceType, "instanceType");
@ -102,6 +187,16 @@ public class RunningInstance implements Comparable<RunningInstance> {
this.reason = reason;
this.subnetId = subnetId;
this.vpcId = vpcId;
this.rootDeviceType = checkNotNull(rootDeviceType, "rootDeviceType");
this.rootDeviceName = rootDeviceName;
this.getEbsBlockDevices().putAll(checkNotNull(ebsBlockDevices, "ebsBlockDevices"));
}
/**
* Instance Ids are scoped to the region.
*/
public Region getRegion() {
return region;
}
/**
@ -133,7 +228,7 @@ public class RunningInstance implements Comparable<RunningInstance> {
/**
* Unique ID of the instance launched.
*/
public String getInstanceId() {
public String getId() {
return instanceId;
}
@ -250,6 +345,21 @@ public class RunningInstance implements Comparable<RunningInstance> {
return vpcId;
}
public RootDeviceType getRootDeviceType() {
return rootDeviceType;
}
public String getRootDeviceName() {
return rootDeviceName;
}
/**
* EBS volumes associated with the instance.
*/
public Map<String, EbsBlockDevice> getEbsBlockDevices() {
return ebsBlockDevices;
}
@Override
public int hashCode() {
final int prime = 31;
@ -257,6 +367,7 @@ public class RunningInstance implements Comparable<RunningInstance> {
result = prime * result + ((amiLaunchIndex == null) ? 0 : amiLaunchIndex.hashCode());
result = prime * result + ((availabilityZone == null) ? 0 : availabilityZone.hashCode());
result = prime * result + ((dnsName == null) ? 0 : dnsName.hashCode());
result = prime * result + ((ebsBlockDevices == null) ? 0 : ebsBlockDevices.hashCode());
result = prime * result + ((imageId == null) ? 0 : imageId.hashCode());
result = prime * result + ((instanceId == null) ? 0 : instanceId.hashCode());
result = prime * result + ((instanceState == null) ? 0 : instanceState.hashCode());
@ -272,6 +383,7 @@ public class RunningInstance implements Comparable<RunningInstance> {
result = prime * result + ((productCodes == null) ? 0 : productCodes.hashCode());
result = prime * result + ((ramdiskId == null) ? 0 : ramdiskId.hashCode());
result = prime * result + ((reason == null) ? 0 : reason.hashCode());
result = prime * result + ((region == null) ? 0 : region.hashCode());
result = prime * result + ((subnetId == null) ? 0 : subnetId.hashCode());
result = prime * result + ((vpcId == null) ? 0 : vpcId.hashCode());
return result;
@ -301,6 +413,11 @@ public class RunningInstance implements Comparable<RunningInstance> {
return false;
} else if (!dnsName.equals(other.dnsName))
return false;
if (ebsBlockDevices == null) {
if (other.ebsBlockDevices != null)
return false;
} else if (!ebsBlockDevices.equals(other.ebsBlockDevices))
return false;
if (imageId == null) {
if (other.imageId != null)
return false;
@ -373,6 +490,11 @@ public class RunningInstance implements Comparable<RunningInstance> {
return false;
} else if (!reason.equals(other.reason))
return false;
if (region == null) {
if (other.region != null)
return false;
} else if (!region.equals(other.region))
return false;
if (subnetId == null) {
if (other.subnetId != null)
return false;
@ -386,4 +508,5 @@ public class RunningInstance implements Comparable<RunningInstance> {
return true;
}
}

View File

@ -0,0 +1,59 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.jclouds.aws.ec2.functions;
import java.lang.reflect.Constructor;
import javax.inject.Singleton;
import org.jclouds.aws.AWSResponseException;
import com.google.common.base.Function;
@Singleton
public class ReturnVoidOnVolumeAvailable implements Function<Exception, Void> {
static final Void v;
static {
Constructor<Void> cv;
try {
cv = Void.class.getDeclaredConstructor();
cv.setAccessible(true);
v = cv.newInstance();
} catch (Exception e) {
throw new Error("Error setting up class", e);
}
}
public Void apply(Exception from) {
if (from instanceof AWSResponseException) {
AWSResponseException e = (AWSResponseException) from;
if (e.getError().getCode().equals("IncorrectState")
&& e.getError().getCode().contains("available"))
return v;
}
return null;
}
}

View File

@ -72,23 +72,6 @@ public class DetachVolumeOptions extends BaseEC2RequestOptions {
}
/**
* Forces detachment if the previous detachment attempt did not occur cleanly (logging into an
* instance, unmounting the volume, and detaching normally). This option can lead to data loss or
* a corrupted file system. Use this option only as a last resort to detach a volume from a
* failed instance. The instance will not have an opportunity to flush file system caches nor
* file system meta data. If you use this option, you must perform file system check and repair
* procedures.
*/
public DetachVolumeOptions force() {
formParameters.put("Force", "true");
return this;
}
public boolean getForce() {
return getFirstFormOrNull("Force") != null;
}
public static class Builder {
/**
* @see DetachVolumeOptions#fromInstance(String )
@ -106,13 +89,5 @@ public class DetachVolumeOptions extends BaseEC2RequestOptions {
return options.fromDevice(device);
}
/**
* @see DetachVolumeOptions#force()
*/
public static DetachVolumeOptions force() {
DetachVolumeOptions options = new DetachVolumeOptions();
return options.force();
}
}
}

View File

@ -3,6 +3,7 @@ package org.jclouds.aws.ec2.predicates;
import javax.annotation.Resource;
import javax.inject.Singleton;
import org.jclouds.aws.AWSResponseException;
import org.jclouds.aws.ec2.domain.InstanceState;
import org.jclouds.aws.ec2.domain.Region;
import org.jclouds.aws.ec2.domain.RunningInstance;
@ -34,16 +35,20 @@ public class InstanceStateRunning implements Predicate<RunningInstance> {
public boolean apply(RunningInstance instance) {
logger.trace("looking for state on instance %s", instance);
instance = refresh(instance.getInstanceId());
logger.trace("%s: looking for instance state %s: currently: %s", instance.getInstanceId(),
InstanceState.RUNNING, instance.getInstanceState());
return instance.getInstanceState() == InstanceState.RUNNING;
try {
instance = refresh(instance.getId());
logger.trace("%s: looking for instance state %s: currently: %s", instance.getId(),
InstanceState.RUNNING, instance.getInstanceState());
return instance.getInstanceState() == InstanceState.RUNNING;
} catch (AWSResponseException e) {
if (e.getError().getCode().equals("InvalidInstanceID.NotFound"))
return false;
throw e;
}
}
private RunningInstance refresh(String instanceId) {
return Iterables.getLast(Iterables.getLast(client.describeInstancesInRegion(
Region.DEFAULT,instanceId))
.getRunningInstances());
return Iterables.getLast(Iterables.getLast(
client.describeInstancesInRegion(Region.DEFAULT, instanceId)).getRunningInstances());
}
}

View File

@ -0,0 +1,49 @@
package org.jclouds.aws.ec2.predicates;
import javax.annotation.Resource;
import javax.inject.Singleton;
import org.jclouds.aws.ec2.domain.InstanceState;
import org.jclouds.aws.ec2.domain.Region;
import org.jclouds.aws.ec2.domain.RunningInstance;
import org.jclouds.aws.ec2.services.InstanceClient;
import org.jclouds.logging.Logger;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.inject.Inject;
/**
*
* Tests to see if a task succeeds.
*
* @author Adrian Cole
*/
@Singleton
public class InstanceStateStopped implements Predicate<RunningInstance> {
private final InstanceClient client;
@Resource
protected Logger logger = Logger.NULL;
@Inject
public InstanceStateStopped(InstanceClient client) {
this.client = client;
}
public boolean apply(RunningInstance instance) {
logger.trace("looking for state on instance %s", instance);
instance = refresh(instance.getId());
logger.trace("%s: looking for instance state %s: currently: %s", instance.getId(),
InstanceState.STOPPED, instance.getInstanceState());
return instance.getInstanceState() == InstanceState.STOPPED;
}
private RunningInstance refresh(String instanceId) {
return Iterables.getLast(Iterables.getLast(client.describeInstancesInRegion(
Region.DEFAULT,instanceId))
.getRunningInstances());
}
}

View File

@ -0,0 +1,48 @@
package org.jclouds.aws.ec2.predicates;
import javax.annotation.Resource;
import javax.inject.Singleton;
import org.jclouds.aws.ec2.domain.InstanceState;
import org.jclouds.aws.ec2.domain.Region;
import org.jclouds.aws.ec2.domain.RunningInstance;
import org.jclouds.aws.ec2.services.InstanceClient;
import org.jclouds.logging.Logger;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.inject.Inject;
/**
*
* Tests to see if a task succeeds.
*
* @author Adrian Cole
*/
@Singleton
public class InstanceStateTerminated implements Predicate<RunningInstance> {
private final InstanceClient client;
@Resource
protected Logger logger = Logger.NULL;
@Inject
public InstanceStateTerminated(InstanceClient client) {
this.client = client;
}
public boolean apply(RunningInstance instance) {
logger.trace("looking for state on instance %s", instance);
instance = refresh(instance.getId());
logger.trace("%s: looking for instance state %s: currently: %s", instance.getId(),
InstanceState.TERMINATED, instance.getInstanceState());
return instance.getInstanceState() == InstanceState.TERMINATED;
}
private RunningInstance refresh(String instanceId) {
return Iterables.getLast(Iterables.getLast(
client.describeInstancesInRegion(Region.DEFAULT, instanceId)).getRunningInstances());
}
}

View File

@ -1,13 +1,10 @@
package org.jclouds.aws.ec2.predicates;
import java.util.Map;
import static org.jclouds.aws.ec2.options.DescribeSnapshotsOptions.Builder.snapshotIds;
import javax.annotation.Resource;
import javax.inject.Singleton;
import static org.jclouds.aws.ec2.options.DescribeSnapshotsOptions.Builder.snapshotIds;
import org.jclouds.aws.ec2.domain.AvailabilityZone;
import org.jclouds.aws.ec2.domain.Region;
import org.jclouds.aws.ec2.domain.Snapshot;
import org.jclouds.aws.ec2.services.ElasticBlockStoreClient;
import org.jclouds.logging.Logger;
@ -30,8 +27,7 @@ public class SnapshotCompleted implements Predicate<Snapshot> {
protected Logger logger = Logger.NULL;
@Inject
public SnapshotCompleted(ElasticBlockStoreClient client,
Map<AvailabilityZone, Region> availabilityZoneToRegion) {
public SnapshotCompleted(ElasticBlockStoreClient client) {
this.client = client;
}

View File

@ -0,0 +1,47 @@
package org.jclouds.aws.ec2.predicates;
import javax.annotation.Resource;
import javax.inject.Singleton;
import org.jclouds.aws.ec2.domain.Attachment;
import org.jclouds.aws.ec2.domain.Volume;
import org.jclouds.aws.ec2.services.ElasticBlockStoreClient;
import org.jclouds.logging.Logger;
import com.google.common.base.Predicate;
import com.google.common.collect.Sets;
import com.google.inject.Inject;
import com.google.inject.internal.Iterables;
/**
*
* Tests to see if a volume is attached.
*
* @author Adrian Cole
*/
@Singleton
public class VolumeAttached implements Predicate<Attachment> {
private final ElasticBlockStoreClient client;
@Resource
protected Logger logger = Logger.NULL;
@Inject
public VolumeAttached(ElasticBlockStoreClient client) {
this.client = client;
}
public boolean apply(Attachment attachment) {
logger.trace("looking for volume %s", attachment.getVolumeId());
Volume volume = Iterables.getOnlyElement(client.describeVolumesInRegion(attachment
.getRegion(), attachment.getVolumeId()));
if (volume.getAttachments().size() == 0) {
return false;
}
Attachment lastAttachment = Sets.newTreeSet(volume.getAttachments()).last();
logger.trace("%s: looking for status %s: currently: %s", lastAttachment,
Attachment.Status.ATTACHED, lastAttachment.getStatus());
return lastAttachment.getStatus() == Attachment.Status.ATTACHED;
}
}

View File

@ -1,12 +1,8 @@
package org.jclouds.aws.ec2.predicates;
import java.util.Map;
import javax.annotation.Resource;
import javax.inject.Singleton;
import org.jclouds.aws.ec2.domain.AvailabilityZone;
import org.jclouds.aws.ec2.domain.Region;
import org.jclouds.aws.ec2.domain.Volume;
import org.jclouds.aws.ec2.services.ElasticBlockStoreClient;
import org.jclouds.logging.Logger;
@ -29,14 +25,12 @@ public class VolumeAvailable implements Predicate<Volume> {
protected Logger logger = Logger.NULL;
@Inject
public VolumeAvailable(ElasticBlockStoreClient client,
Map<AvailabilityZone, Region> availabilityZoneToRegion) {
public VolumeAvailable(ElasticBlockStoreClient client) {
this.client = client;
}
public boolean apply(Volume volume) {
logger.trace("looking for status on volume %s", volume.getId());
volume = Iterables.getOnlyElement(client.describeVolumesInRegion(volume.getRegion(), volume
.getId()));
logger.trace("%s: looking for status %s: currently: %s", volume, Volume.Status.AVAILABLE,

View File

@ -116,14 +116,14 @@ public interface AMIAsyncClient {
RegisterImageOptions... options);
/**
* @see AMIClient#registerImageBackedByEbsInRegion
* @see AMIClient#registerUnixImageBackedByEbsInRegion
*/
@POST
@Path("/")
@FormParams(keys = { ACTION, "RootDeviceName", "BlockDeviceMapping.0.DeviceName" }, values = {
"RegisterImage", "/dev/sda1", "/dev/sda1" })
@XMLResponseParser(ImageIdHandler.class)
Future<String> registerImageBackedByEbsInRegion(
Future<String> registerUnixImageBackedByEbsInRegion(
@EndpointParam(parser = RegionToEndpoint.class) Region region,
@FormParam("Name") String imageName,
@FormParam("BlockDeviceMapping.0.Ebs.SnapshotId") String ebsSnapshotId,

View File

@ -202,7 +202,7 @@ public interface AMIClient {
* "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-RegisterImage.html"
* />
*/
String registerImageBackedByEbsInRegion(Region region, String name, String ebsSnapshotId,
String registerUnixImageBackedByEbsInRegion(Region region, String name, String ebsSnapshotId,
RegisterImageBackedByEbsOptions... options);
/**

View File

@ -45,6 +45,7 @@ import org.jclouds.aws.ec2.domain.Volume;
import org.jclouds.aws.ec2.filters.FormSigner;
import org.jclouds.aws.ec2.functions.AvailabilityZoneToEndpoint;
import org.jclouds.aws.ec2.functions.RegionToEndpoint;
import org.jclouds.aws.ec2.functions.ReturnVoidOnVolumeAvailable;
import org.jclouds.aws.ec2.options.CreateSnapshotOptions;
import org.jclouds.aws.ec2.options.DescribeSnapshotsOptions;
import org.jclouds.aws.ec2.options.DetachVolumeOptions;
@ -56,6 +57,7 @@ import org.jclouds.aws.ec2.xml.PermissionHandler;
import org.jclouds.aws.ec2.xml.SnapshotHandler;
import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.EndpointParam;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.FormParams;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.VirtualHost;
@ -120,10 +122,11 @@ public interface ElasticBlockStoreAsyncClient {
@POST
@Path("/")
@FormParams(keys = ACTION, values = "DetachVolume")
@XMLResponseParser(AttachmentHandler.class)
Future<Attachment> detachVolumeInRegion(
@ExceptionParser(ReturnVoidOnVolumeAvailable.class)
Future<Void> detachVolumeInRegion(
@EndpointParam(parser = RegionToEndpoint.class) Region region,
@FormParam("VolumeId") String volumeId, DetachVolumeOptions... options);
@FormParam("VolumeId") String volumeId, @FormParam("Force") boolean force,
DetachVolumeOptions... options);
/**
* @see ElasticBlockStoreClient#attachVolumeInRegion
@ -212,7 +215,8 @@ public interface ElasticBlockStoreAsyncClient {
*/
@POST
@Path("/")
@FormParams(keys = { ACTION, "Attribute" }, values = { "ResetSnapshotAttribute", "createVolumePermission" })
@FormParams(keys = { ACTION, "Attribute" }, values = { "ResetSnapshotAttribute",
"createVolumePermission" })
Future<Void> resetCreateVolumePermissionsOnSnapshotInRegion(
@EndpointParam(parser = RegionToEndpoint.class) Region region,
@FormParam("SnapshotId") String snapshotId);

View File

@ -152,6 +152,14 @@ public interface ElasticBlockStoreClient {
* @param volumeId
* The ID of the volume to delete. The volume remains in the deleting state for several
* minutes after entering this command.
* @param force
* Forces detachment if the previous detachment attempt did not occur cleanly (logging
* into an instance, unmounting the volume, and detaching normally). This option can
* lead to data loss or a corrupted file system. Use this option only as a last resort
* to detach a volume from a failed instance. The instance will not have an opportunity
* to flush file system caches nor file system meta data. If you use this option, you
* must perform file system check and repair procedures.
*
* @param options
* options like force()
*
@ -164,7 +172,8 @@ public interface ElasticBlockStoreClient {
* "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DetachVolume.html"
* />
*/
Attachment detachVolumeInRegion(Region region, String volumeId, DetachVolumeOptions... options);
void detachVolumeInRegion(Region region, String volumeId, boolean force,
DetachVolumeOptions... options);
/**
* Attaches an Amazon EBS volume to a running instance and exposes it as the specified device.

View File

@ -37,15 +37,15 @@ import javax.ws.rs.Path;
import org.jclouds.aws.ec2.binders.BindInstanceIdsToIndexedFormParams;
import org.jclouds.aws.ec2.binders.IfNotNullBindAvailabilityZoneToFormParam;
import org.jclouds.aws.ec2.domain.AvailabilityZone;
import org.jclouds.aws.ec2.domain.InstanceStateChange;
import org.jclouds.aws.ec2.domain.Region;
import org.jclouds.aws.ec2.domain.Reservation;
import org.jclouds.aws.ec2.domain.TerminatedInstance;
import org.jclouds.aws.ec2.filters.FormSigner;
import org.jclouds.aws.ec2.functions.RegionToEndpoint;
import org.jclouds.aws.ec2.options.RunInstancesOptions;
import org.jclouds.aws.ec2.xml.DescribeInstancesResponseHandler;
import org.jclouds.aws.ec2.xml.InstanceStateChangeHandler;
import org.jclouds.aws.ec2.xml.RunInstancesResponseHandler;
import org.jclouds.aws.ec2.xml.TerminateInstancesResponseHandler;
import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.EndpointParam;
import org.jclouds.rest.annotations.FormParams;
@ -54,7 +54,7 @@ import org.jclouds.rest.annotations.VirtualHost;
import org.jclouds.rest.annotations.XMLResponseParser;
/**
* Provides access to EC2 via their REST API.
* Provides access to EC2 Instance Services via their REST API.
* <p/>
*
* @author Adrian Cole
@ -65,7 +65,7 @@ import org.jclouds.rest.annotations.XMLResponseParser;
public interface InstanceAsyncClient {
/**
* @see BaseEC2Client#describeInstancesInRegion
* @see InstanceClient#describeInstancesInRegion
*/
@POST
@Path("/")
@ -76,7 +76,7 @@ public interface InstanceAsyncClient {
@BinderParam(BindInstanceIdsToIndexedFormParams.class) String... instanceIds);
/**
* @see BaseEC2Client#runInstancesInRegion
* @see InstanceClient#runInstancesInRegion
*/
@POST
@Path("/")
@ -89,15 +89,37 @@ public interface InstanceAsyncClient {
@FormParam("MaxCount") int maxCount, RunInstancesOptions... options);
/**
* @see BaseEC2Client#terminateInstancesInRegion
* @see InstanceClient#terminateInstancesInRegion
*/
@POST
@Path("/")
@FormParams(keys = ACTION, values = "TerminateInstances")
@XMLResponseParser(TerminateInstancesResponseHandler.class)
Future<? extends Set<TerminatedInstance>> terminateInstancesInRegion(
@XMLResponseParser(InstanceStateChangeHandler.class)
Future<? extends Set<InstanceStateChange>> terminateInstancesInRegion(
@EndpointParam(parser = RegionToEndpoint.class) Region region,
@BinderParam(BindInstanceIdsToIndexedFormParams.class) String... instanceIds);
/**
* @see InstanceClient#stopInstancesInRegion
*/
@POST
@Path("/")
@FormParams(keys = ACTION, values = "StopInstances")
@XMLResponseParser(InstanceStateChangeHandler.class)
Future<? extends Set<InstanceStateChange>> stopInstancesInRegion(
@EndpointParam(parser = RegionToEndpoint.class) Region region,
@FormParam("Force") boolean force,
@BinderParam(BindInstanceIdsToIndexedFormParams.class) String... instanceIds);
/**
* @see InstanceClient#startInstancesInRegion
*/
@POST
@Path("/")
@FormParams(keys = ACTION, values = "StartInstances")
@XMLResponseParser(InstanceStateChangeHandler.class)
Future<? extends Set<InstanceStateChange>> startInstancesInRegion(
@EndpointParam(parser = RegionToEndpoint.class) Region region,
@FormParam("InstanceId.0") String instanceId,
@BinderParam(BindInstanceIdsToIndexedFormParams.class) String... instanceIds);
}

View File

@ -29,9 +29,9 @@ import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
import org.jclouds.aws.ec2.domain.AvailabilityZone;
import org.jclouds.aws.ec2.domain.InstanceStateChange;
import org.jclouds.aws.ec2.domain.Region;
import org.jclouds.aws.ec2.domain.Reservation;
import org.jclouds.aws.ec2.domain.TerminatedInstance;
import org.jclouds.aws.ec2.options.RunInstancesOptions;
import org.jclouds.concurrent.Timeout;
@ -60,8 +60,8 @@ public interface InstanceClient {
* Instances are tied to Availability Zones. However, the instance ID is tied to the
* Region.
*
* @see #runInstances
* @see #terminateInstances
* @see #runInstancesInRegion
* @see #terminateInstancesInRegion
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeInstances.html"
* />
*/
@ -126,13 +126,13 @@ public interface InstanceClient {
* launch, the largest possible number above minCount will be launched instead.
* Constraints: Between 1 and the maximum number allowed for your account (default:
* 20).
* @see #describeInstances
* @see #terminateInstances
* @see #authorizeSecurityGroupIngress
* @see #revokeSecurityGroupIngress
* @see #describeSecurityGroups
* @see #createSecurityGroup
* @see #createKeyPair
* @see #describeInstancesInRegion
* @see #terminateInstancesInRegion
* @see #authorizeSecurityGroupIngressInRegion
* @see #revokeSecurityGroupIngressInRegion
* @see #describeSecurityGroupsInRegion
* @see #createSecurityGroupInRegion
* @see #createKeyPairInRegion
* @see <a href=
* "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-RunInstances.html"
* />
@ -151,14 +151,78 @@ public interface InstanceClient {
* @param region
* Instances are tied to Availability Zones. However, the instance ID is tied to the
* Region.
*
* @param instanceIds
* Instance ID to terminate.
* @see #describeInstances
* @see #describeInstancesInRegion
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-TerminateInstances.html"
* />
*/
Set<TerminatedInstance> terminateInstancesInRegion(Region region, String instanceId,
Set<InstanceStateChange> terminateInstancesInRegion(Region region, String... instanceIds);
/**
* Stops an instance that uses an Amazon EBS volume as its root device.
* <p/>
* Instances that use Amazon EBS volumes as their root devices can be quickly stopped and
* started. When an instance is stopped, the compute resources are released and you are not
* billed for hourly instance usage. However, your root partition Amazon EBS volume remains,
* continues to persist your data, and you are charged for Amazon EBS volume usage. You can
* restart your instance at any time.
* <h3>Note</h3>
* Before stopping an instance, make sure it is in a state from which it can be restarted.
* Stopping an instance does not preserve data stored in RAM.
* <p/>
* Performing this operation on an instance that uses an instance store as its root device
* returns an error.
*
* @param region
* Instances are tied to Availability Zones. However, the instance ID is tied to the
* Region.
* @param force
* Forces the instance to stop. The instance will not have an opportunity to flush file
* system caches nor file system meta data. If you use this option, you must perform
* file system check and repair procedures. This option is not recommended for Windows
* instances.
* @param instanceIds
* Instance ID to stop.
*
* @see #startInstancesInRegion
* @see #runInstancesInRegion
* @see #describeInstancesInRegion
* @see #terminateeInstancesInRegion
* @see <a href=
* "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-StopInstances.html"
* />
*/
Set<InstanceStateChange> stopInstancesInRegion(Region region, boolean force,
String... instanceIds);
/**
* Starts an instance that uses an Amazon EBS volume as its root device.
* <p/>
* Instances that use Amazon EBS volumes as their root devices can be quickly stopped and
* started. When an instance is stopped, the compute resources are released and you are not
* billed for hourly instance usage. However, your root partition Amazon EBS volume remains,
* continues to persist your data, and you are charged for Amazon EBS volume usage. You can
* restart your instance at any time.
* <h3>Note</h3>
* Before stopping an instance, make sure it is in a state from which it can be restarted.
* Stopping an instance does not preserve data stored in RAM.
* <p/>
* Performing this operation on an instance that uses an instance store as its root device
* returns an error.
*
* @param region
* Instances are tied to Availability Zones. However, the instance ID is tied to the
* Region.
* @param instanceIds
* Instance ID to start.
*
* @see #stopInstancesInRegion
* @see #runInstancesInRegion
* @see #describeInstancesInRegion
* @see #terminateeInstancesInRegion
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-StartInstances.html"
* />
*/
Set<InstanceStateChange> startInstancesInRegion(Region region, String... instanceIds);
}

View File

@ -26,15 +26,18 @@ package org.jclouds.aws.ec2.xml;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import javax.annotation.Resource;
import org.jclouds.aws.ec2.domain.Attachment;
import org.jclouds.aws.ec2.domain.AvailabilityZone;
import org.jclouds.aws.ec2.domain.InstanceState;
import org.jclouds.aws.ec2.domain.InstanceType;
import org.jclouds.aws.ec2.domain.Reservation;
import org.jclouds.aws.ec2.domain.RootDeviceType;
import org.jclouds.aws.ec2.domain.RunningInstance;
import org.jclouds.aws.ec2.util.EC2Utils;
import org.jclouds.date.DateService;
@ -42,6 +45,7 @@ import org.jclouds.http.functions.ParseSax.HandlerWithResult;
import org.jclouds.logging.Logger;
import org.xml.sax.Attributes;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
public abstract class BaseReservationHandler<T> extends HandlerWithResult<T> {
@ -83,6 +87,16 @@ public abstract class BaseReservationHandler<T> extends HandlerWithResult<T> {
protected boolean inInstances;
protected boolean inProductCodes;
protected boolean inGroups;
private boolean inBlockDeviceMapping;
private Map<String, RunningInstance.EbsBlockDevice> ebsBlockDevices = Maps.newHashMap();
private String volumeId;
private Attachment.Status attachmentStatus;
private Date attachTime;
private boolean deleteOnTermination;
private RootDeviceType rootDeviceType = RootDeviceType.INSTANCE_STORE;
private String deviceName;
private String rootDeviceName;
public void startElement(String uri, String name, String qName, Attributes attrs) {
if (qName.equals("instancesSet")) {
@ -91,6 +105,8 @@ public abstract class BaseReservationHandler<T> extends HandlerWithResult<T> {
inProductCodes = true;
} else if (qName.equals("groupSet")) {
inGroups = true;
} else if (qName.equals("blockDeviceMapping")) {
inBlockDeviceMapping = true;
}
}
@ -154,6 +170,22 @@ public abstract class BaseReservationHandler<T> extends HandlerWithResult<T> {
inInstances = false;
} else if (qName.equals("groupSet")) {
inGroups = false;
} else if (qName.equals("blockDeviceMapping")) {
inBlockDeviceMapping = false;
} else if (qName.equals("deviceName")) {
deviceName = currentOrNull();
} else if (qName.equals("rootDeviceType")) {
rootDeviceType = RootDeviceType.fromValue(currentOrNull());
} else if (qName.equals("volumeId")) {
volumeId = currentOrNull();
} else if (qName.equals("status")) {
attachmentStatus = Attachment.Status.fromValue(currentText.toString().trim());
} else if (qName.equals("attachTime")) {
attachTime = dateService.iso8601DateParse(currentText.toString().trim());
} else if (qName.equals("deleteOnTermination")) {
deleteOnTermination = Boolean.parseBoolean(currentText.toString().trim());
} else if (qName.equals("rootDeviceName")) {
rootDeviceName = currentOrNull();
} else if (qName.equals("item")) {
inItem();
}
@ -161,11 +193,20 @@ public abstract class BaseReservationHandler<T> extends HandlerWithResult<T> {
}
protected void inItem() {
if (inInstances && !inProductCodes) {
instances.add(new RunningInstance(amiLaunchIndex, dnsName, imageId, instanceId,
instanceState, instanceType, ipAddress, kernelId, keyName, launchTime,
monitoring, availabilityZone, platform, privateDnsName, privateIpAddress,
productCodes, ramdiskId, reason, subnetId, vpcId));
if (inBlockDeviceMapping) {
ebsBlockDevices.put(deviceName, new RunningInstance.EbsBlockDevice(volumeId,
attachmentStatus, attachTime, deleteOnTermination));
this.deviceName = null;
this.volumeId = null;
this.attachmentStatus = null;
this.attachTime = null;
this.deleteOnTermination = true;
} else if (inInstances && !inProductCodes && !inBlockDeviceMapping) {
instances.add(new RunningInstance(EC2Utils.findRegionInArgsOrNull(request),
amiLaunchIndex, dnsName, imageId, instanceId, instanceState, instanceType,
ipAddress, kernelId, keyName, launchTime, monitoring, availabilityZone, platform,
privateDnsName, privateIpAddress, productCodes, ramdiskId, reason, subnetId,
vpcId, rootDeviceType, rootDeviceName, ebsBlockDevices));
this.amiLaunchIndex = null;
this.dnsName = null;
this.imageId = null;
@ -186,6 +227,9 @@ public abstract class BaseReservationHandler<T> extends HandlerWithResult<T> {
this.reason = null;
this.subnetId = null;
this.vpcId = null;
this.rootDeviceType = RootDeviceType.INSTANCE_STORE;
this.rootDeviceName = null;
this.ebsBlockDevices = Maps.newHashMap();
}
}

View File

@ -29,11 +29,11 @@ import java.util.Set;
import javax.annotation.Resource;
import org.jclouds.aws.ec2.domain.Image;
import org.jclouds.aws.ec2.domain.RootDeviceType;
import org.jclouds.aws.ec2.domain.Image.Architecture;
import org.jclouds.aws.ec2.domain.Image.EbsBlockDevice;
import org.jclouds.aws.ec2.domain.Image.ImageState;
import org.jclouds.aws.ec2.domain.Image.ImageType;
import org.jclouds.aws.ec2.domain.Image.RootDeviceType;
import org.jclouds.aws.ec2.util.EC2Utils;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.logging.Logger;
@ -141,6 +141,7 @@ public class DescribeImagesResponseHandler extends ParseSax.HandlerWithResult<Se
if (inBlockDeviceMapping) {
ebsBlockDevices.put(deviceName, new Image.EbsBlockDevice(snapshotId, volumeSize,
deleteOnTermination));
this.deviceName = null;
this.snapshotId = null;
this.volumeSize = 0;
this.deleteOnTermination = true;

View File

@ -26,7 +26,7 @@ package org.jclouds.aws.ec2.xml;
import java.util.SortedSet;
import org.jclouds.aws.ec2.domain.InstanceState;
import org.jclouds.aws.ec2.domain.TerminatedInstance;
import org.jclouds.aws.ec2.domain.InstanceStateChange;
import org.jclouds.aws.ec2.util.EC2Utils;
import org.jclouds.http.functions.ParseSax.HandlerWithResult;
import org.xml.sax.Attributes;
@ -36,33 +36,38 @@ import com.google.common.collect.Sets;
/**
* Parses the following XML document:
* <p/>
* TerminateInstancesResponse xmlns="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-ItemType-TerminateInstancesResponseInfoType.html"
* TerminateInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2009-11-30/"
* StartInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2009-11-30/" StopInstancesResponse
* xmlns="http://ec2.amazonaws.com/doc/2009-11-30/"
*
* @author Adrian Cole
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-ItemType-TerminateInstancesResponseInfoType.html"
* />
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-ItemType-StartInstancesResponseInfoType.html"
* />
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-ItemType-StopInstancesResponseInfoType.html"
* />
*/
public class TerminateInstancesResponseHandler extends
HandlerWithResult<SortedSet<TerminatedInstance>> {
public class InstanceStateChangeHandler extends HandlerWithResult<SortedSet<InstanceStateChange>> {
private StringBuilder currentText = new StringBuilder();
SortedSet<TerminatedInstance> instances = Sets.newTreeSet();
SortedSet<InstanceStateChange> instances = Sets.newTreeSet();
private InstanceState shutdownState;
private InstanceState previousState;
private String instanceId;
private boolean inShutdownState;
private boolean inCurrentState;
private boolean inPreviousState;
@Override
public SortedSet<TerminatedInstance> getResult() {
public SortedSet<InstanceStateChange> getResult() {
return instances;
}
public void startElement(String uri, String name, String qName, Attributes attrs) {
if (qName.equals("shutdownState")) {
inShutdownState = true;
if (qName.equals("shutdownState") || qName.equals("currentState")) {
inCurrentState = true;
} else if (qName.equals("previousState")) {
inPreviousState = true;
}
@ -72,19 +77,19 @@ public class TerminateInstancesResponseHandler extends
if (qName.equals("instanceId")) {
this.instanceId = currentOrNull();
} else if (qName.equals("shutdownState")) {
inShutdownState = false;
} else if (qName.equals("shutdownState") || qName.equals("currentState")) {
inCurrentState = false;
} else if (qName.equals("previousState")) {
inPreviousState = false;
} else if (qName.equals("name")) {
if (inShutdownState) {
if (inCurrentState) {
shutdownState = InstanceState.fromValue(currentOrNull());
} else if (inPreviousState) {
previousState = InstanceState.fromValue(currentOrNull());
}
} else if (qName.equals("item")) {
instances.add(new TerminatedInstance(EC2Utils.findRegionInArgsOrNull(request), instanceId,
shutdownState, previousState));
instances.add(new InstanceStateChange(EC2Utils.findRegionInArgsOrNull(request),
instanceId, shutdownState, previousState));
this.instanceId = null;
this.shutdownState = null;
this.previousState = null;

View File

@ -62,13 +62,14 @@ import com.google.inject.Injector;
/**
* Follows the book Cloud Application Architectures ISBN: 978-0-596-15636-7
* <p/>
*
* Generally disabled, as it incurs higher fees.
*
* @author Adrian Cole
*/
@Test(groups = "live", enabled = true, sequential = true, testName = "ec2.ExpensiveEC2ClientLiveTest")
public class ExpensiveEC2ClientLiveTest {
@Test(groups = "live", enabled = true, sequential = true, testName = "ec2.CloudApplicationArchitecturesEC2ClientLiveTest")
public class CloudApplicationArchitecturesEC2ClientLiveTest {
private EC2Client client;
protected SshClient.Factory sshFactory;
@ -154,8 +155,8 @@ public class ExpensiveEC2ClientLiveTest {
throw htpe;
}
}
assertNotNull(server.getInstanceId());
serverId = server.getInstanceId();
assertNotNull(server.getId());
serverId = server.getId();
assertEquals(server.getInstanceState(), InstanceState.PENDING);
server = blockUntilRunningInstanceActive(serverId);
@ -244,7 +245,7 @@ public class ExpensiveEC2ClientLiveTest {
RunningInstance currentDetails = null;
for (currentDetails = getRunningInstance(serverId); currentDetails.getInstanceState() != InstanceState.RUNNING; currentDetails = getRunningInstance(serverId)) {
System.out.printf("%s blocking on status active: currently: %s%n", currentDetails
.getInstanceId(), currentDetails.getInstanceState());
.getId(), currentDetails.getInstanceState());
Thread.sleep(5 * 1000);
}

View File

@ -0,0 +1,542 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.jclouds.aws.ec2;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.aws.ec2.options.CreateSnapshotOptions.Builder.withDescription;
import static org.jclouds.aws.ec2.options.DescribeImagesOptions.Builder.imageIds;
import static org.jclouds.aws.ec2.options.RegisterImageBackedByEbsOptions.Builder.withKernelId;
import static org.jclouds.aws.ec2.options.RunInstancesOptions.Builder.withKeyName;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import java.io.ByteArrayInputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.jclouds.aws.AWSResponseException;
import org.jclouds.aws.ec2.domain.Attachment;
import org.jclouds.aws.ec2.domain.Image;
import org.jclouds.aws.ec2.domain.InstanceState;
import org.jclouds.aws.ec2.domain.InstanceType;
import org.jclouds.aws.ec2.domain.IpProtocol;
import org.jclouds.aws.ec2.domain.KeyPair;
import org.jclouds.aws.ec2.domain.Region;
import org.jclouds.aws.ec2.domain.RootDeviceType;
import org.jclouds.aws.ec2.domain.RunningInstance;
import org.jclouds.aws.ec2.domain.Snapshot;
import org.jclouds.aws.ec2.domain.Volume;
import org.jclouds.aws.ec2.domain.Image.Architecture;
import org.jclouds.aws.ec2.domain.Image.ImageType;
import org.jclouds.aws.ec2.predicates.InstanceStateRunning;
import org.jclouds.aws.ec2.predicates.InstanceStateStopped;
import org.jclouds.aws.ec2.predicates.InstanceStateTerminated;
import org.jclouds.aws.ec2.predicates.SnapshotCompleted;
import org.jclouds.aws.ec2.predicates.VolumeAttached;
import org.jclouds.aws.ec2.predicates.VolumeAvailable;
import org.jclouds.http.HttpResponseException;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.predicates.SocketOpen;
import org.jclouds.scriptbuilder.InitBuilder;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.ssh.ExecResponse;
import org.jclouds.ssh.SshClient;
import org.jclouds.ssh.SshException;
import org.jclouds.ssh.jsch.config.JschSshClientModule;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.inject.Injector;
import com.google.inject.internal.ImmutableMap;
/**
* Adapted from the following sources: {@link http://gist.github.com/249915}, {@link http
* ://www.capsunlock.net/2009/12/create-ebs-boot-ami.html}
* <p/>
*
* Generally disabled, as it incurs higher fees.
*
* @author Adrian Cole
*/
@Test(groups = "live", sequential = true, testName = "ec2.EBSBootEC2ClientLiveTest")
public class EBSBootEC2ClientLiveTest {
// don't need a lot of space. 2GB should be more than enough for testing
private static final int VOLUME_SIZE = 2;
private static final String SCRIPT_END = "----COMPLETE----";
private static final String INSTANCE_PREFIX = System.getProperty("user.name") + ".ec2ebs";
private static final String IMAGE_ID = "ami-7e28ca17";
private EC2Client client;
private SshClient.Factory sshFactory;
private KeyPair keyPair;
private String securityGroupName;
private RetryablePredicate<InetSocketAddress> socketTester;
private RetryablePredicate<Attachment> attachTester;
private RetryablePredicate<Volume> volumeTester;
private RunningInstance instance;
private RetryablePredicate<RunningInstance> runningTester;
private RetryablePredicate<RunningInstance> stoppedTester;
private RetryablePredicate<RunningInstance> terminatedTester;
private Volume volume;
private RetryablePredicate<Snapshot> snapshotTester;
private Snapshot snapshot;
private Image ebsImage;
private RunningInstance ebsInstance;
private Attachment attachment;
private String mkEbsBoot;
@BeforeGroups(groups = { "live" })
public void setupClient() {
String user = checkNotNull(System.getProperty("jclouds.test.user"), "jclouds.test.user");
String password = checkNotNull(System.getProperty("jclouds.test.key"), "jclouds.test.key");
Injector injector = new EC2ContextBuilder(new EC2PropertiesBuilder(user, password).build())
.withModules(new Log4JLoggingModule(), new JschSshClientModule()).buildInjector();
client = injector.getInstance(EC2Client.class);
sshFactory = injector.getInstance(SshClient.Factory.class);
SocketOpen socketOpen = injector.getInstance(SocketOpen.class);
socketTester = new RetryablePredicate<InetSocketAddress>(socketOpen, 120, 1, TimeUnit.SECONDS);
VolumeAvailable volumeAvailable = injector.getInstance(VolumeAvailable.class);
volumeTester = new RetryablePredicate<Volume>(volumeAvailable, 60, 1, TimeUnit.SECONDS);
SnapshotCompleted snapshotCompleted = injector.getInstance(SnapshotCompleted.class);
snapshotTester = new RetryablePredicate<Snapshot>(snapshotCompleted, 120, 3, TimeUnit.SECONDS);
VolumeAttached volumeAttached = injector.getInstance(VolumeAttached.class);
attachTester = new RetryablePredicate<Attachment>(volumeAttached, 60, 1, TimeUnit.SECONDS);
InstanceStateRunning instanceStateRunning = injector.getInstance(InstanceStateRunning.class);
runningTester = new RetryablePredicate<RunningInstance>(instanceStateRunning, 180, 5,
TimeUnit.SECONDS);
InstanceStateStopped instanceStateStopped = injector.getInstance(InstanceStateStopped.class);
stoppedTester = new RetryablePredicate<RunningInstance>(instanceStateStopped, 60, 1,
TimeUnit.SECONDS);
InstanceStateTerminated instanceStateTerminated = injector
.getInstance(InstanceStateTerminated.class);
terminatedTester = new RetryablePredicate<RunningInstance>(instanceStateTerminated, 60, 1,
TimeUnit.SECONDS);
injector.injectMembers(socketOpen); // add logger
}
@Test(enabled = true)
void testCreateSecurityGroupIngressCidr() throws InterruptedException, ExecutionException,
TimeoutException {
securityGroupName = INSTANCE_PREFIX + "ingress";
try {
client.getSecurityGroupServices().deleteSecurityGroupInRegion(Region.DEFAULT,
securityGroupName);
} catch (Exception e) {
}
client.getSecurityGroupServices().createSecurityGroupInRegion(Region.DEFAULT,
securityGroupName, securityGroupName);
client.getSecurityGroupServices().authorizeSecurityGroupIngressInRegion(Region.DEFAULT,
securityGroupName, IpProtocol.TCP, 80, 80, "0.0.0.0/0");
client.getSecurityGroupServices().authorizeSecurityGroupIngressInRegion(Region.DEFAULT,
securityGroupName, IpProtocol.TCP, 443, 443, "0.0.0.0/0");
client.getSecurityGroupServices().authorizeSecurityGroupIngressInRegion(Region.DEFAULT,
securityGroupName, IpProtocol.TCP, 22, 22, "0.0.0.0/0");
}
@Test(enabled = true)
void testCreateKeyPair() {
String keyName = INSTANCE_PREFIX + "1";
try {
client.getKeyPairServices().deleteKeyPairInRegion(Region.DEFAULT, keyName);
} catch (Exception e) {
}
keyPair = client.getKeyPairServices().createKeyPairInRegion(Region.DEFAULT, keyName);
assertNotNull(keyPair);
assertNotNull(keyPair.getKeyMaterial());
assertNotNull(keyPair.getKeyFingerprint());
assertEquals(keyPair.getKeyName(), keyName);
}
@Test(dependsOnMethods = { "testCreateKeyPair", "testCreateSecurityGroupIngressCidr" })
public void testCreateRunningInstance() throws Exception {
instance = createInstance(IMAGE_ID);
}
private RunningInstance createInstance(String imageId) throws UnknownHostException {
RunningInstance instance = null;
while (instance == null) {
try {
System.out.printf("%d: running instance%n", System.currentTimeMillis());
instance = client.getInstanceServices().runInstancesInRegion(
Region.DEFAULT,
null,
imageId,
1,
1,
withKeyName(keyPair.getKeyName()).asType(InstanceType.M1_SMALL)
.withSecurityGroup(securityGroupName)).getRunningInstances()
.iterator().next();
} catch (HttpResponseException htpe) {
if (htpe.getResponse().getStatusCode() == 400)
continue;
throw htpe;
}
}
assertNotNull(instance.getId());
assertEquals(instance.getInstanceState(), InstanceState.PENDING);
instance = blockUntilWeCanSshIntoInstance(instance);
return instance;
}
@Test(dependsOnMethods = "testCreateRunningInstance")
void testCreateAndAttachVolume() {
volume = client.getElasticBlockStoreServices().createVolumeInAvailabilityZone(
instance.getAvailabilityZone(), VOLUME_SIZE);
System.out.printf("%d: %s awaiting volume to become available%n", System.currentTimeMillis(),
volume.getId());
assert volumeTester.apply(volume);
Attachment attachment = client.getElasticBlockStoreServices().attachVolumeInRegion(
instance.getRegion(), volume.getId(), instance.getId(), "/dev/sdh");
System.out.printf("%d: %s awaiting attachment to complete%n", System.currentTimeMillis(),
attachment.getId());
assert attachTester.apply(attachment);
System.out.printf("%d: %s attachment complete%n", System.currentTimeMillis(), attachment
.getId());
}
@BeforeTest
void makeScript() {
mkEbsBoot = new InitBuilder(
"mkebsboot",// name of the script
"/tmp",// working directory
"/tmp/logs",// location of stdout.log and stderr.log
ImmutableMap.of("imageDir", "/mnt/tmp", "ebsDevice", "/dev/sdh", "ebsMountPoint",
"/mnt/ebs"),// variables used inside of the script
"echo creating a filesystem and mounting the ebs volume",// what to execute
"{md} {varl}IMAGE_DIR{varr} {varl}EBS_MOUNT_POINT{varr}",
"rm -rf {varl}IMAGE_DIR{varr}/*",
"yes| mkfs -t ext3 {varl}EBS_DEVICE{varr} 2>&-",
"mount {varl}EBS_DEVICE{varr} {varl}EBS_MOUNT_POINT{varr}",
"echo making a local working copy of the boot disk",
"rsync -ax --exclude /ubuntu/.bash_history --exclude /home/*/.bash_history --exclude /etc/ssh/ssh_host_* --exclude /etc/ssh/moduli --exclude /etc/udev/rules.d/*persistent-net.rules --exclude /var/lib/ec2/* --exclude=/mnt/* --exclude=/proc/* --exclude=/tmp/* --exclude=/dev/log / {varl}IMAGE_DIR{varr}",
"echo preparing the local working copy",
"touch {varl}IMAGE_DIR{varr}/etc/init.d/ec2-init-user-data",
"echo copying the local working copy to the ebs mount",
"{cd} {varl}IMAGE_DIR{varr}",
"tar -cSf - * | tar xf - -C {varl}EBS_MOUNT_POINT{varr}", "echo size of ebs",
"du -sk {varl}EBS_MOUNT_POINT{varr}", "echo size of source",
"du -sk {varl}IMAGE_DIR{varr}", "rm -rf {varl}IMAGE_DIR{varr}/*",
"umount {varl}EBS_MOUNT_POINT{varr}", "echo " + SCRIPT_END).build(OsFamily.UNIX);
}
@Test(dependsOnMethods = "testCreateAndAttachVolume")
void testBundleInstance() {
SshClient ssh = sshFactory.create(new InetSocketAddress(instance.getIpAddress(), 22), "ubuntu",
keyPair.getKeyMaterial().getBytes());
try {
ssh.connect();
} catch (SshException e) {// try twice in case there is a network timeout
try {
Thread.sleep(10 * 1000);
} catch (InterruptedException e1) {
}
ssh.connect();
}
try {
System.out.printf("%d: %s writing ebs script%n", System.currentTimeMillis(), instance
.getId());
String script = "/tmp/mkebsboot-init.sh";
ssh.put(script, new ByteArrayInputStream(mkEbsBoot.getBytes()));
System.out.printf("%d: %s launching ebs script%n", System.currentTimeMillis(), instance
.getId());
ssh.exec("chmod 755 " + script);
ssh.exec(script + " init");
ExecResponse output = ssh.exec("sudo "+script + " start");
System.out.println(output);
output = ssh.exec(script + " status");
assert !output.getOutput().trim().equals("") : output;
RetryablePredicate<String> scriptTester = new RetryablePredicate<String>(new ScriptTester(
ssh, SCRIPT_END), 600, 10, TimeUnit.SECONDS);
scriptTester.apply(script);
} finally {
if (ssh != null)
ssh.disconnect();
}
}
public static class ScriptTester implements Predicate<String> {
private final SshClient ssh;
private final String endMatches;
public ScriptTester(SshClient ssh, String endMatches) {
this.ssh = ssh;
this.endMatches = endMatches;
}
@Override
public boolean apply(String script) {
System.out.printf("%d: %s testing status%n", System.currentTimeMillis(), script);
ExecResponse output = ssh.exec(script + " status");
if (output.getOutput().trim().equals("")) {
output = ssh.exec(script + " tail");
String stdout = output.getOutput().trim();
if (stdout.contains(endMatches)) {
return true;
} else {
output = ssh.exec(script + " tailerr");
String stderr = output.getOutput().trim();
throw new RuntimeException(String.format(
"script %s ended without token: stdout.log: [%s]; stderr.log: [%s]; ",
script, stdout, stderr));
}
}
return false;
}
}
@Test(dependsOnMethods = "testBundleInstance")
void testAMIFromBundle() {
volume = Iterables.getOnlyElement(client.getElasticBlockStoreServices()
.describeVolumesInRegion(volume.getRegion(), volume.getId()));
if (volume.getAttachments().size() > 0) {
// should be cleanly unmounted, so force is not necessary.
client.getElasticBlockStoreServices().detachVolumeInRegion(instance.getRegion(),
volume.getId(), false);
System.out.printf("%d: %s awaiting detachment to complete%n", System.currentTimeMillis(),
volume.getId());
assert volumeTester.apply(volume);
} else {
attachment = null; // protect test closer so that it doesn't try to detach
}
snapshot = client.getElasticBlockStoreServices().createSnapshotInRegion(volume.getRegion(),
volume.getId(), withDescription("EBS Ubuntu Hardy"));
System.out.printf("%d: %s awaiting snapshot to complete%n", System.currentTimeMillis(),
snapshot.getId());
assert snapshotTester.apply(snapshot);
Image image = Iterables.getOnlyElement(client.getAMIServices().describeImagesInRegion(
snapshot.getRegion(), imageIds(IMAGE_ID)));
String description = image.getDescription() == null ? "jclouds" : image.getDescription();
System.out.printf("%d: %s creating ami from snapshot%n", System.currentTimeMillis(), snapshot
.getId());
String amiId = client.getAMIServices().registerUnixImageBackedByEbsInRegion(
snapshot.getRegion(),
"ebsboot-" + image.getId(),
snapshot.getId(),
withKernelId(image.getKernelId()).withRamdisk(image.getRamdiskId()).withDescription(
description).asArchitecture(Architecture.I386));
try {
ebsImage = Iterables.getOnlyElement(client.getAMIServices().describeImagesInRegion(
snapshot.getRegion(), imageIds(amiId)));
} catch (AWSResponseException e) {
// TODO add a retry handler for this HTTP code 400 and the below error
if (e.getError().getClass().equals("InvalidAMIID.NotFound"))
ebsImage = Iterables.getOnlyElement(client.getAMIServices().describeImagesInRegion(
snapshot.getRegion(), imageIds(amiId)));
else
throw e;
}
verifyImage();
}
@Test(dependsOnMethods = { "testAMIFromBundle" })
public void testInstanceFromEBS() throws Exception {
System.out.printf("%d: %s creating instance from ebs-backed ami%n", System
.currentTimeMillis(), ebsImage.getId());
ebsInstance = createInstance(ebsImage.getId());
client.getInstanceServices().stopInstancesInRegion(ebsInstance.getRegion(), true,
ebsInstance.getId());
System.out.printf("%d: %s awaiting instance to stop %n", System.currentTimeMillis(),
ebsInstance.getId());
stoppedTester.apply(ebsInstance);
System.out.printf("%d: %s awaiting instance to start %n", System.currentTimeMillis(),
ebsInstance.getId());
client.getInstanceServices().startInstancesInRegion(ebsInstance.getRegion(),
ebsInstance.getId());
ebsInstance = blockUntilWeCanSshIntoInstance(ebsInstance);
}
private void verifyImage() {
assertEquals(ebsImage.getImageType(), ImageType.MACHINE);
assertEquals(ebsImage.getRootDeviceType(), RootDeviceType.EBS);
assertEquals(ebsImage.getRootDeviceName(), "/dev/sda1");
assertEquals(ebsImage.getEbsBlockDevices().entrySet(), ImmutableMap.of("/dev/sda1",
new Image.EbsBlockDevice(snapshot.getId(), VOLUME_SIZE, true)).entrySet());
}
/**
* this tests "personality" as the file looked up was sent during instance creation
*
* @throws UnknownHostException
*/
private void sshPing(RunningInstance newDetails) throws UnknownHostException {
try {
doCheckKey(newDetails);
} catch (SshException e) {// try twice in case there is a network timeout
try {
Thread.sleep(10 * 1000);
} catch (InterruptedException e1) {
}
doCheckKey(newDetails);
}
}
private void doCheckKey(RunningInstance newDetails) throws UnknownHostException {
doCheckKey(newDetails.getIpAddress());
}
private void doCheckKey(InetAddress address) {
SshClient ssh = sshFactory.create(new InetSocketAddress(address, 22), "ubuntu", keyPair
.getKeyMaterial().getBytes());
try {
ssh.connect();
ExecResponse hello = ssh.exec("echo hello");
assertEquals(hello.getOutput().trim(), "hello");
} finally {
if (ssh != null)
ssh.disconnect();
}
}
private RunningInstance blockUntilWeCanSshIntoInstance(RunningInstance instance)
throws UnknownHostException {
System.out.printf("%d: %s awaiting instance to run %n", System.currentTimeMillis(), instance
.getId());
assert runningTester.apply(instance);
instance = Iterables.getOnlyElement(Iterables.getOnlyElement(
client.getInstanceServices().describeInstancesInRegion(instance.getRegion(),
instance.getId())).getRunningInstances());
System.out.printf("%d: %s awaiting ssh service to start%n", System.currentTimeMillis(),
instance.getIpAddress());
assert socketTester.apply(new InetSocketAddress(instance.getIpAddress(), 22));
System.out.printf("%d: %s ssh service started%n", System.currentTimeMillis(), instance
.getDnsName());
sshPing(instance);
System.out.printf("%d: %s ssh connection made%n", System.currentTimeMillis(), instance
.getId());
return instance;
}
@AfterTest
void cleanup() {
if (ebsInstance != null) {
try {
client.getInstanceServices().terminateInstancesInRegion(ebsInstance.getRegion(),
ebsInstance.getId());
terminatedTester.apply(ebsInstance);
} catch (Exception e) {
e.printStackTrace();
}
}
if (ebsImage != null) {
try {
client.getAMIServices().deregisterImageInRegion(ebsImage.getRegion(), ebsImage.getId());
} catch (Exception e) {
e.printStackTrace();
}
}
if (snapshot != null) {
try {
client.getElasticBlockStoreServices().deleteSnapshotInRegion(snapshot.getRegion(),
snapshot.getId());
} catch (Exception e) {
e.printStackTrace();
}
}
if (attachment != null) {
try {
client.getElasticBlockStoreServices().detachVolumeInRegion(volume.getRegion(),
volume.getId(), true);
assert volumeTester.apply(volume);
} catch (Exception e) {
e.printStackTrace();
}
}
if (instance != null) {
try {
client.getInstanceServices().terminateInstancesInRegion(instance.getRegion(),
instance.getId());
terminatedTester.apply(instance);
} catch (Exception e) {
e.printStackTrace();
}
}
if (volume != null) {
try {
client.getElasticBlockStoreServices().deleteVolumeInRegion(volume.getRegion(),
volume.getId());
} catch (Exception e) {
e.printStackTrace();
}
}
if (keyPair != null) {
try {
client.getKeyPairServices().deleteKeyPairInRegion(keyPair.getRegion(),
keyPair.getKeyName());
} catch (Exception e) {
e.printStackTrace();
}
}
if (securityGroupName != null) {
try {
client.getSecurityGroupServices().deleteSecurityGroupInRegion(Region.DEFAULT,
securityGroupName);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

View File

@ -23,7 +23,6 @@
*/
package org.jclouds.aws.ec2.options;
import static org.jclouds.aws.ec2.options.DetachVolumeOptions.Builder.force;
import static org.jclouds.aws.ec2.options.DetachVolumeOptions.Builder.fromDevice;
import static org.jclouds.aws.ec2.options.DetachVolumeOptions.Builder.fromInstance;
import static org.testng.Assert.assertEquals;
@ -96,17 +95,4 @@ public class DetachVolumeOptionsTest {
fromInstance(null);
}
@Test
public void testForce() {
DetachVolumeOptions options = new DetachVolumeOptions();
options.force();
assertEquals(options.buildFormParameters().get("Force"), Collections.singletonList("true"));
}
@Test
public void testForceStatic() {
DetachVolumeOptions options = force();
assertEquals(options.buildFormParameters().get("Force"), Collections.singletonList("true"));
}
}

View File

@ -39,8 +39,8 @@ import org.jclouds.aws.ec2.EC2Client;
import org.jclouds.aws.ec2.EC2ContextFactory;
import org.jclouds.aws.ec2.domain.Image;
import org.jclouds.aws.ec2.domain.Region;
import org.jclouds.aws.ec2.domain.RootDeviceType;
import org.jclouds.aws.ec2.domain.Image.ImageType;
import org.jclouds.aws.ec2.domain.Image.RootDeviceType;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.rest.RestContext;
import org.testng.annotations.AfterTest;
@ -85,15 +85,15 @@ public class AMIClientLiveTest {
assertNotNull(allResults);
assert allResults.size() >= 2 : allResults.size();
Iterator<Image> iterator = allResults.iterator();
String id1 = iterator.next().getImageId();
String id2 = iterator.next().getImageId();
String id1 = iterator.next().getId();
String id2 = iterator.next().getId();
SortedSet<Image> twoResults = Sets.newTreeSet(client.describeImagesInRegion(region,
imageIds(id1, id2)));
assertNotNull(twoResults);
assertEquals(twoResults.size(), 2);
iterator = twoResults.iterator();
assertEquals(iterator.next().getImageId(), id1);
assertEquals(iterator.next().getImageId(), id2);
assertEquals(iterator.next().getId(), id1);
assertEquals(iterator.next().getId(), id2);
}
}
@ -128,7 +128,7 @@ public class AMIClientLiveTest {
@Test(enabled = false)
// awaiting EBS functionality to be added to jclouds
public void testRegisterImageBackedByEBS() {
String imageRegisteredId = client.registerImageBackedByEbsInRegion(Region.DEFAULT,
String imageRegisteredId = client.registerUnixImageBackedByEbsInRegion(Region.DEFAULT,
"jcloudstest1", DEFAULT_MANIFEST);
imagesToDeregister.add(imageRegisteredId);
Image imageRegistered = Iterables.getOnlyElement(client.describeImagesInRegion(
@ -142,7 +142,7 @@ public class AMIClientLiveTest {
@Test(enabled = false)
// awaiting EBS functionality to be added to jclouds
public void testRegisterImageBackedByEBSOptions() {
String imageRegisteredWithOptionsId = client.registerImageBackedByEbsInRegion(Region.DEFAULT,
String imageRegisteredWithOptionsId = client.registerUnixImageBackedByEbsInRegion(Region.DEFAULT,
"jcloudstest2", DEFAULT_SNAPSHOT, addNewBlockDevice("/dev/sda2", "myvirtual", 1)
.withDescription("adrian"));
imagesToDeregister.add(imageRegisteredWithOptionsId);

View File

@ -191,15 +191,16 @@ public class ElasticBlockStoreAsyncClientTest extends RestClientTest<ElasticBloc
public void testDetachVolume() throws SecurityException, NoSuchMethodException, IOException {
Method method = ElasticBlockStoreAsyncClient.class.getMethod("detachVolumeInRegion",
Region.class, String.class, Array.newInstance(DetachVolumeOptions.class, 0)
.getClass());
Region.class, String.class, boolean.class, Array.newInstance(
DetachVolumeOptions.class, 0).getClass());
GeneratedHttpRequest<ElasticBlockStoreAsyncClient> httpMethod = processor.createRequest(
method, Region.DEFAULT, "id");
method, Region.DEFAULT, "id", false);
assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1");
assertHeadersEqual(httpMethod,
"Content-Length: 50\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n");
assertPayloadEquals(httpMethod, "Version=2009-11-30&Action=DetachVolume&VolumeId=id");
"Content-Length: 62\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n");
assertPayloadEquals(httpMethod,
"Version=2009-11-30&Action=DetachVolume&Force=false&VolumeId=id");
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
assertSaxResponseParserClassEquals(method, AttachmentHandler.class);
@ -211,18 +212,18 @@ public class ElasticBlockStoreAsyncClientTest extends RestClientTest<ElasticBloc
public void testDetachVolumeOptions() throws SecurityException, NoSuchMethodException,
IOException {
Method method = ElasticBlockStoreAsyncClient.class.getMethod("detachVolumeInRegion",
Region.class, String.class, Array.newInstance(DetachVolumeOptions.class, 0)
.getClass());
GeneratedHttpRequest<ElasticBlockStoreAsyncClient> httpMethod = processor.createRequest(
method, Region.DEFAULT, "id", fromInstance("instanceId").fromDevice("/device")
.force());
Region.class, String.class, boolean.class, Array.newInstance(
DetachVolumeOptions.class, 0).getClass());
GeneratedHttpRequest<ElasticBlockStoreAsyncClient> httpMethod = processor
.createRequest(method, Region.DEFAULT, "id", true, fromInstance("instanceId")
.fromDevice("/device"));
assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1");
assertHeadersEqual(httpMethod,
"Content-Length: 100\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n");
assertPayloadEquals(
httpMethod,
"Version=2009-11-30&Action=DetachVolume&VolumeId=id&InstanceId=instanceId&Device=%2Fdevice&Force=true");
"Version=2009-11-30&Action=DetachVolume&Force=true&VolumeId=id&InstanceId=instanceId&Device=%2Fdevice");
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
assertSaxResponseParserClassEquals(method, AttachmentHandler.class);

View File

@ -28,8 +28,6 @@ import static org.jclouds.aws.ec2.options.DescribeSnapshotsOptions.Builder.snaps
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import java.net.URI;
import java.util.Map;
import java.util.SortedSet;
import java.util.concurrent.TimeUnit;
@ -38,7 +36,6 @@ import org.jclouds.aws.ec2.EC2AsyncClient;
import org.jclouds.aws.ec2.EC2Client;
import org.jclouds.aws.ec2.EC2ContextFactory;
import org.jclouds.aws.ec2.domain.AvailabilityZone;
import org.jclouds.aws.ec2.domain.AvailabilityZoneInfo;
import org.jclouds.aws.ec2.domain.Region;
import org.jclouds.aws.ec2.domain.Snapshot;
import org.jclouds.aws.ec2.domain.Volume;
@ -54,7 +51,6 @@ import org.testng.annotations.Test;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
/**
@ -64,7 +60,6 @@ import com.google.common.collect.Sets;
*/
@Test(groups = "live", sequential = true, testName = "ec2.ElasticBlockStoreClientLiveTest")
public class ElasticBlockStoreClientLiveTest {
private AvailabilityZoneAndRegionClient aclient;
private ElasticBlockStoreClient client;
private RestContext<EC2AsyncClient, EC2Client> context;
private String volumeId;
@ -77,7 +72,6 @@ public class ElasticBlockStoreClientLiveTest {
context = EC2ContextFactory.createContext(user, password, new Log4JLoggingModule());
client = context.getApi().getElasticBlockStoreServices();
aclient = context.getApi().getAvailabilityZoneAndRegionServices();
}
@Test
@ -114,27 +108,11 @@ public class ElasticBlockStoreClientLiveTest {
assertEquals(volume.getId(), expected.getId());
}
Map<Region, URI> provideRegions(AvailabilityZoneAndRegionClient client) {
return client.describeRegions();
}
Map<AvailabilityZone, Region> provideAvailabilityZoneToRegions(
AvailabilityZoneAndRegionClient client, Map<Region, URI> regions) {
Map<AvailabilityZone, Region> map = Maps.newHashMap();
for (Region region : regions.keySet()) {
for (AvailabilityZoneInfo zoneInfo : client.describeAvailabilityZonesInRegion(region)) {
map.put(zoneInfo.getZone(), region);
}
}
return map;
}
@Test(dependsOnMethods = "testCreateVolumeInAvailabilityZone")
void testCreateSnapshotInRegion() {
Snapshot snapshot = client.createSnapshotInRegion(Region.DEFAULT, volumeId);
Predicate<Snapshot> snapshotted = new RetryablePredicate<Snapshot>(new SnapshotCompleted(
client, provideAvailabilityZoneToRegions(aclient, aclient.describeRegions())), 600,
10, TimeUnit.SECONDS);
client), 600, 10, TimeUnit.SECONDS);
assert snapshotted.apply(snapshot);
Snapshot result = Iterables.getOnlyElement(client.describeSnapshotsInRegion(snapshot
@ -150,9 +128,8 @@ public class ElasticBlockStoreClientLiveTest {
AvailabilityZone.US_EAST_1A, snapshot.getId());
assertNotNull(volume);
Predicate<Volume> availabile = new RetryablePredicate<Volume>(new VolumeAvailable(client,
provideAvailabilityZoneToRegions(aclient, aclient.describeRegions())), 600, 10,
TimeUnit.SECONDS);
Predicate<Volume> availabile = new RetryablePredicate<Volume>(new VolumeAvailable(client),
600, 10, TimeUnit.SECONDS);
assert availabile.apply(volume);
Volume result = Iterables.getOnlyElement(client.describeVolumesInRegion(snapshot.getRegion(),

View File

@ -40,7 +40,7 @@ import org.jclouds.aws.ec2.filters.FormSigner;
import org.jclouds.aws.ec2.options.RunInstancesOptions;
import org.jclouds.aws.ec2.xml.DescribeInstancesResponseHandler;
import org.jclouds.aws.ec2.xml.RunInstancesResponseHandler;
import org.jclouds.aws.ec2.xml.TerminateInstancesResponseHandler;
import org.jclouds.aws.ec2.xml.InstanceStateChangeHandler;
import org.jclouds.aws.reference.AWSConstants;
import org.jclouds.date.TimeStamp;
import org.jclouds.http.functions.ParseSax;
@ -107,18 +107,18 @@ public class InstanceAsyncClientTest extends RestClientTest<InstanceAsyncClient>
public void testTerminateInstances() throws SecurityException, NoSuchMethodException,
IOException {
Method method = InstanceAsyncClient.class.getMethod("terminateInstancesInRegion",
Region.class, String.class, Array.newInstance(String.class, 0).getClass());
Region.class, Array.newInstance(String.class, 0).getClass());
GeneratedHttpRequest<InstanceAsyncClient> httpMethod = processor.createRequest(method,
Region.DEFAULT, "1", "2");
assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1");
assertHeadersEqual(httpMethod,
"Content-Length: 59\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n");
"Content-Length: 44\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n");
assertPayloadEquals(httpMethod,
"Version=2009-11-30&Action=TerminateInstances&InstanceId.0=1&InstanceId.1=2");
"Version=2009-11-30&Action=TerminateInstances&InstanceId.1=1&InstanceId.2=2");
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
assertSaxResponseParserClassEquals(method, TerminateInstancesResponseHandler.class);
assertSaxResponseParserClassEquals(method, InstanceStateChangeHandler.class);
assertExceptionParserClassEquals(method, null);
checkFilters(httpMethod);
@ -168,6 +168,44 @@ public class InstanceAsyncClientTest extends RestClientTest<InstanceAsyncClient>
checkFilters(httpMethod);
}
public void testStopInstances() throws SecurityException, NoSuchMethodException, IOException {
Method method = InstanceAsyncClient.class.getMethod("stopInstancesInRegion", Region.class,
boolean.class, Array.newInstance(String.class, 0).getClass());
GeneratedHttpRequest<InstanceAsyncClient> httpMethod = processor.createRequest(method,
Region.DEFAULT, true, "1", "2");
assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1");
assertHeadersEqual(httpMethod,
"Content-Length: 50\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n");
assertPayloadEquals(httpMethod,
"Version=2009-11-30&Action=StopInstances&Force=true&InstanceId.1=1&InstanceId.2=2");
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
assertSaxResponseParserClassEquals(method, InstanceStateChangeHandler.class);
assertExceptionParserClassEquals(method, null);
checkFilters(httpMethod);
}
public void testStartInstances() throws SecurityException, NoSuchMethodException, IOException {
Method method = InstanceAsyncClient.class.getMethod("startInstancesInRegion", Region.class,
Array.newInstance(String.class, 0).getClass());
GeneratedHttpRequest<InstanceAsyncClient> httpMethod = processor.createRequest(method,
Region.DEFAULT, "1", "2");
assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1");
assertHeadersEqual(httpMethod,
"Content-Length: 40\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n");
assertPayloadEquals(httpMethod,
"Version=2009-11-30&Action=StartInstances&InstanceId.1=1&InstanceId.2=2");
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
assertSaxResponseParserClassEquals(method, InstanceStateChangeHandler.class);
assertExceptionParserClassEquals(method, null);
checkFilters(httpMethod);
}
@Override
protected void checkFilters(GeneratedHttpRequest<InstanceAsyncClient> httpMethod) {
assertEquals(httpMethod.getFilters().size(), 1);

View File

@ -72,18 +72,18 @@ public class InstanceClientLiveTest {
if (allResults.size() >= 2) {
Iterator<Reservation> iterator = allResults.iterator();
String id1 = Sets.newTreeSet(iterator.next().getRunningInstances()).first()
.getInstanceId();
.getId();
String id2 = Sets.newTreeSet(iterator.next().getRunningInstances()).first()
.getInstanceId();
.getId();
SortedSet<Reservation> twoResults = Sets.newTreeSet(client.describeInstancesInRegion(
region, id1, id2));
assertNotNull(twoResults);
assertEquals(twoResults.size(), 2);
iterator = allResults.iterator();
assertEquals(Sets.newTreeSet(iterator.next().getRunningInstances()).first()
.getInstanceId(), id1);
.getId(), id1);
assertEquals(Sets.newTreeSet(iterator.next().getRunningInstances()).first()
.getInstanceId(), id2);
.getId(), id2);
}
}
}

View File

@ -64,9 +64,10 @@ public class KeyPairClientLiveTest {
}
@Test
void testDescribeAddresses() {
void testDescribeKeyPairs() {
for (Region region : ImmutableSet.of(Region.DEFAULT, Region.EU_WEST_1, Region.US_EAST_1,
Region.US_WEST_1)) {
SortedSet<KeyPair> allResults = Sets.newTreeSet(client.describeKeyPairsInRegion(region));
assertNotNull(allResults);
if (allResults.size() >= 1) {

View File

@ -34,6 +34,7 @@ import java.util.SortedSet;
import org.jclouds.aws.ec2.domain.Image;
import org.jclouds.aws.ec2.domain.Region;
import org.jclouds.aws.ec2.domain.RootDeviceType;
import org.jclouds.aws.ec2.domain.Image.Architecture;
import org.jclouds.aws.ec2.domain.Image.EbsBlockDevice;
import org.jclouds.aws.ec2.domain.Image.ImageState;
@ -62,9 +63,8 @@ public class DescribeImagesResponseHandlerTest extends BaseHandlerTest {
"ec2-public-images/fedora-8-i386-base-v1.04.manifest.xml", "206029621532",
ImageState.AVAILABLE, ImageType.MACHINE, false,
Sets.<String> newHashSet("9961934F"), "aki-4438dd2d", null, "ari-4538dd2c",
Image.RootDeviceType.INSTANCE_STORE, null, ImmutableMap
.<String, EbsBlockDevice> of()));
RootDeviceType.INSTANCE_STORE, null, ImmutableMap.<String, EbsBlockDevice> of()));
Set<Image> result = parseImages(is);
assertEquals(result, contents);
@ -78,8 +78,7 @@ public class DescribeImagesResponseHandlerTest extends BaseHandlerTest {
"aws-solutions-amis/SqlSvrStd2003r2-x86_64-Win_SFWBasic5.1-v1.0.manifest.xml",
"771350841976", ImageState.AVAILABLE, ImageType.MACHINE, true, Sets
.<String> newHashSet("5771E9A6"), null, "windows", null,
Image.RootDeviceType.INSTANCE_STORE, null, ImmutableMap
.<String, EbsBlockDevice> of()));
RootDeviceType.INSTANCE_STORE, null, ImmutableMap.<String, EbsBlockDevice> of()));
Set<Image> result = parseImages(is);
@ -93,7 +92,7 @@ public class DescribeImagesResponseHandlerTest extends BaseHandlerTest {
contents.add(new Image(Region.DEFAULT, Architecture.I386, "websrv_2009-12-10",
"Web Server AMI", "ami-246f8d4d", "706093390852/websrv_2009-12-10", "706093390852",
ImageState.AVAILABLE, ImageType.MACHINE, true, Sets.<String> newHashSet(), null,
"windows", null, Image.RootDeviceType.EBS, "/dev/sda1", ImmutableMap
"windows", null, RootDeviceType.EBS, "/dev/sda1", ImmutableMap
.<String, EbsBlockDevice> of("/dev/sda1", new EbsBlockDevice(
"snap-d01272b9", 30, true), "xvdf", new EbsBlockDevice(
"snap-d31272ba", 250, false))));

View File

@ -33,12 +33,15 @@ import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Set;
import org.jclouds.aws.ec2.domain.Attachment;
import org.jclouds.aws.ec2.domain.AvailabilityZone;
import org.jclouds.aws.ec2.domain.InstanceState;
import org.jclouds.aws.ec2.domain.InstanceType;
import org.jclouds.aws.ec2.domain.Region;
import org.jclouds.aws.ec2.domain.Reservation;
import org.jclouds.aws.ec2.domain.RootDeviceType;
import org.jclouds.aws.ec2.domain.RunningInstance;
import org.jclouds.aws.ec2.domain.RunningInstance.EbsBlockDevice;
import org.jclouds.date.DateService;
import org.jclouds.http.functions.BaseHandlerTest;
import org.jclouds.http.functions.ParseSax;
@ -46,6 +49,7 @@ import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
@ -73,14 +77,16 @@ public class DescribeInstancesResponseHandlerTest extends BaseHandlerTest {
Set<Reservation> contents = Sets.newTreeSet();
contents.add(new Reservation(Region.DEFAULT, ImmutableSet.of("adriancole.ec2ingress"),
ImmutableSet.of(new RunningInstance("0",
ImmutableSet.of(new RunningInstance(Region.DEFAULT, "0",
"ec2-174-129-81-68.compute-1.amazonaws.com", "ami-1fd73376", "i-0799056f",
InstanceState.RUNNING, InstanceType.M1_SMALL, InetAddress
.getByName("174.129.81.68"), "aki-a71cf9ce", "adriancole.ec21",
dateService.iso8601DateParse("2009-11-09T03:00:34.000Z"), false,
AvailabilityZone.US_EAST_1C, null, "ip-10-243-42-70.ec2.internal",
InetAddress.getByName("10.243.42.70"), ImmutableSet.<String> of(),
"ari-a51cf9cc", null, null, null)), "993194456877", null, "r-a3c508cb"));
"ari-a51cf9cc", null, null, null, RootDeviceType.INSTANCE_STORE, null,
ImmutableMap.<String, EbsBlockDevice> of())), "993194456877", null,
"r-a3c508cb"));
Set<Reservation> result = getReservations(is);
@ -93,18 +99,22 @@ public class DescribeInstancesResponseHandlerTest extends BaseHandlerTest {
Set<Reservation> contents = Sets.newTreeSet();
contents.add(new Reservation(Region.DEFAULT, ImmutableSet.of("default"), ImmutableSet.of(
new RunningInstance("23", "ec2-72-44-33-4.compute-1.amazonaws.com", "ami-6ea54007",
"i-28a64341", InstanceState.RUNNING, InstanceType.M1_LARGE,
new RunningInstance(Region.DEFAULT, "23", "ec2-72-44-33-4.compute-1.amazonaws.com",
"ami-6ea54007", "i-28a64341", InstanceState.RUNNING, InstanceType.M1_LARGE,
(InetAddress) null, "aki-ba3adfd3", "example-key-name", dateService
.iso8601DateParse("2007-08-07T11:54:42.000Z"), false,
AvailabilityZone.US_EAST_1B, null, "10-251-50-132.ec2.internal", null,
ImmutableSet.of("774F4FF8"), "ari-badbad00", null, null, null),
new RunningInstance("23", "ec2-72-44-33-6.compute-1.amazonaws.com", "ami-6ea54007",
"i-28a64435", InstanceState.RUNNING, InstanceType.M1_LARGE,
ImmutableSet.of("774F4FF8"), "ari-badbad00", null, null, null,
RootDeviceType.INSTANCE_STORE, null, ImmutableMap
.<String, EbsBlockDevice> of()), new RunningInstance(
Region.DEFAULT, "23", "ec2-72-44-33-6.compute-1.amazonaws.com",
"ami-6ea54007", "i-28a64435", InstanceState.RUNNING, InstanceType.M1_LARGE,
(InetAddress) null, "aki-ba3adfd3", "example-key-name", dateService
.iso8601DateParse("2007-08-07T11:54:42.000Z"), false,
AvailabilityZone.US_EAST_1B, null, "10-251-50-134.ec2.internal", null,
ImmutableSet.of("774F4FF8"), "ari-badbad00", null, null, null)),
ImmutableSet.of("774F4FF8"), "ari-badbad00", null, null, null,
RootDeviceType.INSTANCE_STORE, null, ImmutableMap
.<String, EbsBlockDevice> of())),
"UYY3TLBUXIEON5NQVUUX6OMPWBZIQNFM", null, "r-44a5402d"));
Set<Reservation> result = getReservations(is);
@ -112,6 +122,32 @@ public class DescribeInstancesResponseHandlerTest extends BaseHandlerTest {
assertEquals(result, contents);
}
public void testEBS() throws UnknownHostException {
InputStream is = getClass().getResourceAsStream("/ec2/describe_instances_ebs.xml");
Set<Reservation> contents = Sets.newTreeSet();
contents.add(new Reservation(Region.DEFAULT, ImmutableSet.of("adriancole.ec2ebsingress"),
ImmutableSet.of(new RunningInstance(Region.DEFAULT, "0",
"ec2-75-101-203-146.compute-1.amazonaws.com", "ami-849875ed", "i-e564438d",
InstanceState.RUNNING, InstanceType.M1_SMALL, InetAddress
.getByName("75.101.203.146"), "aki-a71cf9ce",
"adriancole.ec2ebs1", dateService
.iso8601DateParse("2009-12-30T04:06:23.000Z"), false,
AvailabilityZone.US_EAST_1B, null,
"domU-12-31-39-09-CE-53.compute-1.internal", InetAddress
.getByName("10.210.209.157"), ImmutableSet.<String> of(),
"ari-a51cf9cc", null, null, null, RootDeviceType.EBS, "/dev/sda1",
ImmutableMap.<String, EbsBlockDevice> of("/dev/sda1", new EbsBlockDevice(
"vol-dc6ca8b5", Attachment.Status.ATTACHED, dateService
.iso8601DateParse("2009-12-30T04:06:29.000Z"), true)))),
"993194456877", null, "r-596dd731"));
Set<Reservation> result = getReservations(is);
assertEquals(result, contents);
}
private Set<Reservation> getReservations(InputStream is) {
DescribeInstancesResponseHandler handler = injector
.getInstance(DescribeInstancesResponseHandler.class);
@ -122,7 +158,7 @@ public class DescribeInstancesResponseHandlerTest extends BaseHandlerTest {
private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) {
GeneratedHttpRequest<?> request = createMock(GeneratedHttpRequest.class);
expect(request.getArgs()).andReturn(new Object[] { Region.DEFAULT });
expect(request.getArgs()).andReturn(new Object[] { Region.DEFAULT }).atLeastOnce();
replay(request);
handler.setContext(request);
}

View File

@ -32,8 +32,8 @@ import java.io.InputStream;
import java.util.Set;
import org.jclouds.aws.ec2.domain.InstanceState;
import org.jclouds.aws.ec2.domain.InstanceStateChange;
import org.jclouds.aws.ec2.domain.Region;
import org.jclouds.aws.ec2.domain.TerminatedInstance;
import org.jclouds.date.DateService;
import org.jclouds.http.functions.BaseHandlerTest;
import org.jclouds.http.functions.ParseSax;
@ -44,12 +44,12 @@ import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
/**
* Tests behavior of {@code TerminateInstancesResponseHandler}
* Tests behavior of {@code InstanceStateChangeHandler}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "ec2.TerminateInstancesResponseHandlerTest")
public class TerminateInstancesResponseHandlerTest extends BaseHandlerTest {
@Test(groups = "unit", testName = "ec2.InstanceStateChangeHandlerTest")
public class InstanceStateChangeHandlerTest extends BaseHandlerTest {
private DateService dateService;
@ -61,17 +61,41 @@ public class TerminateInstancesResponseHandlerTest extends BaseHandlerTest {
assert dateService != null;
}
public void testApplyInputStream() {
public void testTerminate() {
InputStream is = getClass().getResourceAsStream("/ec2/terminate_instances.xml");
Set<TerminatedInstance> expected = ImmutableSet.of(new TerminatedInstance(Region.DEFAULT,
Set<InstanceStateChange> expected = ImmutableSet.of(new InstanceStateChange(Region.DEFAULT,
"i-3ea74257", InstanceState.SHUTTING_DOWN, InstanceState.RUNNING));
TerminateInstancesResponseHandler handler = injector
.getInstance(TerminateInstancesResponseHandler.class);
InstanceStateChangeHandler handler = injector.getInstance(InstanceStateChangeHandler.class);
addDefaultRegionToHandler(handler);
Set<TerminatedInstance> result = factory.create(handler).parse(is);
Set<InstanceStateChange> result = factory.create(handler).parse(is);
assertEquals(result, expected);
}
public void testStart() {
InputStream is = getClass().getResourceAsStream("/ec2/start_instances.xml");
Set<InstanceStateChange> expected = ImmutableSet.of(new InstanceStateChange(Region.DEFAULT,
"i-10a64379", InstanceState.PENDING, InstanceState.STOPPED));
InstanceStateChangeHandler handler = injector.getInstance(InstanceStateChangeHandler.class);
addDefaultRegionToHandler(handler);
Set<InstanceStateChange> result = factory.create(handler).parse(is);
assertEquals(result, expected);
}
public void testStop() {
InputStream is = getClass().getResourceAsStream("/ec2/stop_instances.xml");
Set<InstanceStateChange> expected = ImmutableSet.of(new InstanceStateChange(Region.DEFAULT,
"i-10a64379", InstanceState.STOPPING, InstanceState.RUNNING));
InstanceStateChangeHandler handler = injector.getInstance(InstanceStateChangeHandler.class);
addDefaultRegionToHandler(handler);
Set<InstanceStateChange> result = factory.create(handler).parse(is);
assertEquals(result, expected);
}

View File

@ -36,7 +36,9 @@ import org.jclouds.aws.ec2.domain.InstanceState;
import org.jclouds.aws.ec2.domain.InstanceType;
import org.jclouds.aws.ec2.domain.Region;
import org.jclouds.aws.ec2.domain.Reservation;
import org.jclouds.aws.ec2.domain.RootDeviceType;
import org.jclouds.aws.ec2.domain.RunningInstance;
import org.jclouds.aws.ec2.domain.RunningInstance.EbsBlockDevice;
import org.jclouds.date.DateService;
import org.jclouds.http.functions.BaseHandlerTest;
import org.jclouds.http.functions.ParseSax;
@ -44,6 +46,7 @@ import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Sets;
@ -70,24 +73,30 @@ public class RunInstancesResponseHandlerTest extends BaseHandlerTest {
InputStream is = getClass().getResourceAsStream("/ec2/run_instances.xml");
Reservation expected = new Reservation(Region.DEFAULT, ImmutableSortedSet.of("default"),
ImmutableSortedSet.of(new RunningInstance("0", null, "ami-60a54009", "i-2ba64342",
ImmutableSortedSet.of(new RunningInstance(Region.DEFAULT, "0", null, "ami-60a54009",
"i-2ba64342", InstanceState.PENDING, InstanceType.M1_SMALL,
(InetAddress) null, null, "example-key-name", dateService
.iso8601DateParse("2007-08-07T11:51:50.000Z"), true,
AvailabilityZone.US_EAST_1B, null, null, (InetAddress) null, Sets
.<String> newTreeSet(), null, null, null, null,
RootDeviceType.INSTANCE_STORE, null, ImmutableMap
.<String, EbsBlockDevice> of()), new RunningInstance(
Region.DEFAULT, "0", null, "ami-60a54009", "i-2bc64242",
InstanceState.PENDING, InstanceType.M1_SMALL, (InetAddress) null, null,
"example-key-name", dateService
.iso8601DateParse("2007-08-07T11:51:50.000Z"), true,
AvailabilityZone.US_EAST_1B, null, null, (InetAddress) null, Sets
.<String> newTreeSet(), null, null, null, null),
new RunningInstance("0", null, "ami-60a54009", "i-2bc64242",
InstanceState.PENDING, InstanceType.M1_SMALL, (InetAddress) null,
null, "example-key-name", dateService
.iso8601DateParse("2007-08-07T11:51:50.000Z"), true,
AvailabilityZone.US_EAST_1B, null, null, (InetAddress) null, Sets
.<String> newTreeSet(), null, null, null, null),
new RunningInstance("0", null, "ami-60a54009", "i-2be64332",
InstanceState.PENDING, InstanceType.M1_SMALL, (InetAddress) null,
null, "example-key-name", dateService
.iso8601DateParse("2007-08-07T11:51:50.000Z"), true,
AvailabilityZone.US_EAST_1B, null, null, (InetAddress) null, Sets
.<String> newTreeSet(), null, null, null, null)
.<String> newTreeSet(), null, null, null, null,
RootDeviceType.INSTANCE_STORE, null, ImmutableMap
.<String, EbsBlockDevice> of()), new RunningInstance(
Region.DEFAULT, "0", null, "ami-60a54009", "i-2be64332",
InstanceState.PENDING, InstanceType.M1_SMALL, (InetAddress) null, null,
"example-key-name", dateService
.iso8601DateParse("2007-08-07T11:51:50.000Z"), true,
AvailabilityZone.US_EAST_1B, null, null, (InetAddress) null, Sets
.<String> newTreeSet(), null, null, null, null,
RootDeviceType.INSTANCE_STORE, null, ImmutableMap
.<String, EbsBlockDevice> of())
), "AIDADH4IGTRXXKCD", null, "r-47a5402e");

View File

@ -0,0 +1,60 @@
<?xml version="1.0"?>
<DescribeInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2009-11-30/">
<requestId>423068c0-523e-41a7-877c-7123e91d85e2</requestId>
<reservationSet>
<item>
<reservationId>r-596dd731</reservationId>
<ownerId>993194456877</ownerId>
<groupSet>
<item>
<groupId>adriancole.ec2ebsingress</groupId>
</item>
</groupSet>
<instancesSet>
<item>
<instanceId>i-e564438d</instanceId>
<imageId>ami-849875ed</imageId>
<instanceState>
<code>16</code>
<name>running</name>
</instanceState>
<privateDnsName>domU-12-31-39-09-CE-53.compute-1.internal
</privateDnsName>
<dnsName>ec2-75-101-203-146.compute-1.amazonaws.com
</dnsName>
<reason />
<keyName>adriancole.ec2ebs1</keyName>
<amiLaunchIndex>0</amiLaunchIndex>
<productCodes />
<instanceType>m1.small</instanceType>
<launchTime>2009-12-30T04:06:23.000Z</launchTime>
<placement>
<availabilityZone>us-east-1b</availabilityZone>
</placement>
<kernelId>aki-a71cf9ce</kernelId>
<ramdiskId>ari-a51cf9cc</ramdiskId>
<monitoring>
<state>disabled</state>
</monitoring>
<privateIpAddress>10.210.209.157</privateIpAddress>
<ipAddress>75.101.203.146</ipAddress>
<rootDeviceType>ebs</rootDeviceType>
<rootDeviceName>/dev/sda1</rootDeviceName>
<blockDeviceMapping>
<item>
<deviceName>/dev/sda1</deviceName>
<ebs>
<volumeId>vol-dc6ca8b5</volumeId>
<status>attached</status>
<attachTime>2009-12-30T04:06:29.000Z
</attachTime>
<deleteOnTermination>true
</deleteOnTermination>
</ebs>
</item>
</blockDeviceMapping>
</item>
</instancesSet>
</item>
</reservationSet>
</DescribeInstancesResponse>

View File

@ -0,0 +1,15 @@
<StartInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2009-11-30/">
<instancesSet>
<item>
<instanceId>i-10a64379</instanceId>
<currentState>
<code>0</code>
<name>pending</name>
</currentState>
<previousState>
<code>80</code>
<name>stopped</name>
</previousState>
</item>
</instancesSet>
</StartInstancesResponse>

View File

@ -0,0 +1,15 @@
<StopInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2009-11-30/">
<instancesSet>
<item>
<instanceId>i-10a64379</instanceId>
<currentState>
<code>64</code>
<name>stopping</name>
</currentState>
<previousState>
<code>16</code>
<name>running</name>
</previousState>
</item>
</instancesSet>
</StopInstancesResponse>

View File

@ -47,6 +47,12 @@
<jclouds.test.initializer>org.jclouds.aws.s3.blobstore.integration.S3TestInitializer</jclouds.test.initializer>
</properties>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-scriptbuilder</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-jsch</artifactId>

View File

@ -0,0 +1,111 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.jclouds.scriptbuilder;
import static org.jclouds.scriptbuilder.domain.Statements.call;
import static org.jclouds.scriptbuilder.domain.Statements.createRunScript;
import static org.jclouds.scriptbuilder.domain.Statements.findPid;
import static org.jclouds.scriptbuilder.domain.Statements.forget;
import static org.jclouds.scriptbuilder.domain.Statements.interpret;
import static org.jclouds.scriptbuilder.domain.Statements.kill;
import static org.jclouds.scriptbuilder.domain.Statements.newStatementList;
import static org.jclouds.scriptbuilder.domain.Statements.switchArg;
import java.util.Map;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
/**
* Creates an init script file
*
* @author Adrian Cole
*/
public class InitBuilder extends ScriptBuilder {
@SuppressWarnings("unchecked")
public InitBuilder(String instanceName, String instanceHome, String logDir,
Map<String, String> variables, String... execLines) {
super();
Map<String, String> defaultVariables = ImmutableMap.of("instanceName", instanceName,
"instanceHome", instanceHome, "logDir", logDir);
addEnvironmentVariableScope("default", defaultVariables)
.addEnvironmentVariableScope(instanceName, variables)
.addStatement(
switchArg(
1,
new ImmutableMap.Builder()
.put(
"init",
newStatementList(call("default"),
call(instanceName), createRunScript(
instanceName,// TODO: convert
// so
// that
// createRunScript
// can take from a
// variable
Iterables.concat(variables
.keySet(),
defaultVariables
.keySet()),
"{varl}INSTANCE_HOME{varr}",
execLines)))
.put(
"status",
newStatementList(
call("default"),
findPid("{varl}INSTANCE_NAME{varr}"),
interpret("echo [{varl}FOUND_PID{varr}]{lf}")))
.put(
"stop",
newStatementList(call("default"),
findPid("{varl}INSTANCE_NAME{varr}"),
kill()))
.put(
"start",
newStatementList(
call("default"),
forget(
"{varl}INSTANCE_NAME{varr}",
"{varl}INSTANCE_HOME{varr}{fs}{varl}INSTANCE_NAME{varr}.{sh}",
"{varl}LOG_DIR{varr}")))
.put(
"tail",
newStatementList(
call("default"),
interpret("tail {varl}LOG_DIR{varr}{fs}stdout.log")))
.put(
"tailerr",
newStatementList(
call("default"),
interpret("tail {varl}LOG_DIR{varr}{fs}stderr.log")))
.put(
"run",
newStatementList(
call("default"),
interpret("{varl}INSTANCE_HOME{varr}{fs}{varl}INSTANCE_NAME{varr}.{sh}")))
.build()));
}
}

View File

@ -47,15 +47,20 @@ import com.google.common.collect.Maps;
*/
public class CreateRunScript implements Statement {
final String instanceName;
final List<String> exports;
final Iterable<String> exports;
final String pwd;
final String execLine;
final String[] execLines;
public CreateRunScript(String instanceName, List<String> exports, String pwd, String execLine) {
public CreateRunScript(String instanceName, Iterable<String> exports, String pwd,
String... execLines) {// TODO: convert so
// that
// createRunScript
// can take from a
// variable
this.instanceName = checkNotNull(instanceName, "instanceName");
this.exports = checkNotNull(exports, "exports");
this.pwd = checkNotNull(pwd, "pwd").replaceAll("[/\\\\]", "{fs}");
this.execLine = checkNotNull(execLine, "execLine");
this.execLines = checkNotNull(execLines, "execLines");
}
public static class AddTitleToFile implements Statement {
@ -148,6 +153,7 @@ public class CreateRunScript implements Statement {
statements.add(appendToFile(line, runScript, family));
}
statements.add(new AddTitleToFile(instanceName, runScript));
statements.add(appendToFile(Utils.writeZeroPath(family), runScript, family));
statements.add(new AddExportToFile("instanceName", instanceName, runScript));
for (String export : exports) {
statements.add(new AddExportToFile(export, Utils.replaceTokens("{varl}"
@ -155,7 +161,9 @@ public class CreateRunScript implements Statement {
tokenMap), runScript));
}
statements.add(appendToFile("{cd} " + pwd, runScript, family));
statements.add(appendToFile(execLine, runScript, family));
for (String execLine : execLines) {
statements.add(appendToFile(execLine, runScript, family));
}
for (String line : Splitter.on(ShellToken.LF.to(family)).split(
ShellToken.END_SCRIPT.to(family))) {
if (!line.equals(""))

View File

@ -23,7 +23,6 @@
*/
package org.jclouds.scriptbuilder.domain;
import java.util.List;
import java.util.Map;
/**
@ -46,9 +45,13 @@ public class Statements {
return new Call(function, args);
}
public static Statement createRunScript(String instanceName, List<String> exports, String pwd,
String execLine) {
return new CreateRunScript(instanceName, exports, pwd, execLine);
public static Statement createRunScript(String instanceName, Iterable<String> exports,
String pwd, String... execLines) {// TODO: convert so
// that
// createRunScript
// can take from a
// variable
return new CreateRunScript(instanceName, exports, pwd, execLines);
}
/**
@ -61,6 +64,25 @@ public class Statements {
return new Call("findPid", args);
}
/**
*
* Runs the script in a way that it can be matched later with {@link findPid}
*
* @param instanceName
* - what to match the process on
* @param script
* - what to run in the background
* @param logDir
* - where to write the following logs:
* <ol>
* <li>stdout.log</li>
* <li>stderr.log</li>
* </ol>
*/
public static Statement forget(String instanceName, String script, String logDir) {
return new Call("forget", instanceName, script, logDir);
}
/**
* Kills the pid and subprocesses related to the variable {@code FOUND_PID} if set.
*

View File

@ -216,7 +216,7 @@ public class Utils {
public static final Map<OsFamily, String> OS_TO_ZERO_PATH = ImmutableMap.of(OsFamily.WINDOWS,
"set PATH=c:\\windows\\;C:\\windows\\system32;c:\\windows\\system32\\wbem\r\n",
OsFamily.UNIX, "export PATH=/usr/ucb/bin:/bin:/usr/bin:/usr/sbin\n");
OsFamily.UNIX, "export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin\n");
/**
* @return line used to zero out the path of the script such that basic commands such as unix ps

View File

@ -0,0 +1,95 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.jclouds.scriptbuilder;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.net.MalformedURLException;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.ShellToken;
import org.testng.annotations.Test;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.CharStreams;
import com.google.common.io.Resources;
/**
* Tests possible uses of InitBuilder
*
* @author Adrian Cole
*/
public class InitBuilderTest {
InitBuilder testInitBuilder = new InitBuilder("mkebsboot", "/mnt/tmp", "/mnt/tmp", ImmutableMap
.of("tmpDir", "/mnt/tmp"), "find /");
@Test
public void testBuildSimpleWindows() throws MalformedURLException, IOException {
assertEquals(testInitBuilder.build(OsFamily.WINDOWS), CharStreams.toString(Resources
.newReaderSupplier(Resources.getResource("test_init."
+ ShellToken.SH.to(OsFamily.WINDOWS)), Charsets.UTF_8)));
}
@Test
public void testBuildSimpleUNIX() throws MalformedURLException, IOException {
assertEquals(testInitBuilder.build(OsFamily.UNIX), CharStreams.toString(Resources
.newReaderSupplier(Resources.getResource("test_init."
+ ShellToken.SH.to(OsFamily.UNIX)), Charsets.UTF_8)));
}
@Test
public void testBuildEBS() throws MalformedURLException, IOException {
assertEquals(
new InitBuilder(
"mkebsboot",// name of the script
"/tmp",// working directory
"/tmp/logs",// location of stdout.log and stderr.log
ImmutableMap.of("imageDir", "/mnt/tmp", "ebsDevice", "/dev/sdh",
"ebsMountPoint", "/mnt/ebs"),// variables used inside of the script
"echo creating a filesystem and mounting the ebs volume",// what to execute
"{md} {varl}IMAGE_DIR{varr} {varl}EBS_MOUNT_POINT{varr}",
"rm -rf {varl}IMAGE_DIR{varr}/*",
"yes| mkfs -t ext3 {varl}EBS_DEVICE{varr} 2>&-",
"mount {varl}EBS_DEVICE{varr} {varl}EBS_MOUNT_POINT{varr}",
"echo making a local working copy of the boot disk",
"rsync -ax --exclude=/mnt/* --exclude=/proc/* --exclude=/tmp/* --exclude=/dev/log / {varl}IMAGE_DIR{varr}",
"echo preparing the local working copy",
"touch {varl}IMAGE_DIR{varr}/etc/init.d/ec2-init-user-data",
"echo copying the local working copy to the ebs mount",
"{cd} {varl}IMAGE_DIR{varr}",
"tar -cSf - * | tar xf - -C {varl}EBS_MOUNT_POINT{varr}",
"echo size of ebs",
"du -sk {varl}EBS_MOUNT_POINT{varr}",
"echo size of source",
"du -sk {varl}IMAGE_DIR{varr}",
"rm -rf {varl}IMAGE_DIR{varr}/*",
"umount {varl}EBS_MOUNT_POINT{varr}", "echo ----COMPLETE----")
.build(OsFamily.UNIX), CharStreams.toString(Resources.newReaderSupplier(
Resources.getResource("test_ebs." + ShellToken.SH.to(OsFamily.UNIX)),
Charsets.UTF_8)));
}
}

View File

@ -41,26 +41,29 @@ import com.google.common.io.Resources;
@Test(groups = "unit", testName = "scriptbuilder.CreateRunScriptTest")
public class CreateRunScriptTest {
Statement statement = createRunScript("yahooprod", ImmutableList.<String> of("javaHome"),
"{tmp}{fs}{uid}{fs}scripttest",
"{tmp}{fs}{uid}{fs}scripttest", "echo hello",
"echo {varl}JAVA_HOME{varr}{fs}bin{fs}java -DinstanceName={varl}INSTANCE_NAME{varr} myServer.Main");
public void testUNIX() throws IOException {
assertEquals(statement.render(OsFamily.UNIX),CharStreams.toString(Resources
assertEquals(statement.render(OsFamily.UNIX), CharStreams.toString(Resources
.newReaderSupplier(Resources.getResource("test_runrun."
+ ShellToken.SH.to(OsFamily.UNIX)), Charsets.UTF_8)));
}
public void testWINDOWS() throws IOException {
assertEquals(statement.render(OsFamily.WINDOWS),CharStreams.toString(Resources
assertEquals(statement.render(OsFamily.WINDOWS), CharStreams.toString(Resources
.newReaderSupplier(Resources.getResource("test_runrun."
+ ShellToken.SH.to(OsFamily.WINDOWS)), Charsets.UTF_8)));
}
public void testRedirectGuard(){
assertEquals(CreateRunScript.addSpaceToEnsureWeDontAccidentallyRedirectFd("foo>>"),"foo>>");
assertEquals(CreateRunScript.addSpaceToEnsureWeDontAccidentallyRedirectFd("foo0>>"),"foo0 >>");
assertEquals(CreateRunScript.addSpaceToEnsureWeDontAccidentallyRedirectFd("foo1>>"),"foo1 >>");
assertEquals(CreateRunScript.addSpaceToEnsureWeDontAccidentallyRedirectFd("foo2>>"),"foo2 >>");
public void testRedirectGuard() {
assertEquals(CreateRunScript.addSpaceToEnsureWeDontAccidentallyRedirectFd("foo>>"), "foo>>");
assertEquals(CreateRunScript.addSpaceToEnsureWeDontAccidentallyRedirectFd("foo0>>"),
"foo0 >>");
assertEquals(CreateRunScript.addSpaceToEnsureWeDontAccidentallyRedirectFd("foo1>>"),
"foo1 >>");
assertEquals(CreateRunScript.addSpaceToEnsureWeDontAccidentallyRedirectFd("foo2>>"),
"foo2 >>");
}
}

View File

@ -0,0 +1,116 @@
#!/bin/bash
set +u
shopt -s xpg_echo
shopt -s expand_aliases
unset PATH JAVA_HOME LD_LIBRARY_PATH
function abort {
echo "aborting: $@" 1>&2
exit 1
}
function default {
export INSTANCE_NAME="mkebsboot"
export INSTANCE_HOME="/mnt/tmp"
export LOG_DIR="/tmp/logs"
return 0
}
function mkebsboot {
export IMAGE_DIR="/mnt/tmp"
export EBS_DEVICE="/dev/sdh"
export EBS_MOUNT_POINT="/mnt/ebs"
return 0
}
function findPid {
unset FOUND_PID;
[ $# -eq 1 ] || {
abort "findPid requires a parameter of pattern to match"
return 1
}
local PATTERN="$1"; shift
local _FOUND=`ps auxwww|grep "$PATTERN"|grep -v " $0"|grep -v grep|awk '{print $2}'`
[ -n "$_FOUND" ] && {
export FOUND_PID=$_FOUND
return 0
} || {
return 1
}
}
function forget {
unset FOUND_PID;
[ $# -eq 3 ] || {
abort "forget requires parameters INSTANCE_NAME SCRIPT LOG_DIR"
return 1
}
local INSTANCE_NAME="$1"; shift
local SCRIPT="$1"; shift
local LOG_DIR="$1"; shift
mkdir -p $LOG_DIR
findPid $INSTANCE_NAME
[ -n "$FOUND_PID" ] && {
echo $INSTANCE_NAME already running pid [$FOUND_PID]
} || {
nohup $SCRIPT >$LOG_DIR/stdout.log 2>$LOG_DIR/stderr.log &
findPid $INSTANCE_NAME
[ -n "$FOUND_PID" ] || abort "$INSTANCE_NAME did not start"
}
return 0
}
export PATH=/usr/ucb/bin:/bin:/usr/bin:/usr/sbin
case $1 in
init)
default || exit 1
mkebsboot || exit 1
mkdir -p $INSTANCE_HOME
rm $INSTANCE_HOME/mkebsboot.sh 2>&-
echo '#!/bin/bash'>>$INSTANCE_HOME/mkebsboot.sh
echo 'set +u'>>$INSTANCE_HOME/mkebsboot.sh
echo 'shopt -s xpg_echo'>>$INSTANCE_HOME/mkebsboot.sh
echo 'shopt -s expand_aliases'>>$INSTANCE_HOME/mkebsboot.sh
echo "PROMPT_COMMAND='echo -ne \"\033]0;mkebsboot\007\"'">>$INSTANCE_HOME/mkebsboot.sh
echo "export INSTANCE_NAME='mkebsboot'">>$INSTANCE_HOME/mkebsboot.sh
echo "export IMAGE_DIR='$IMAGE_DIR'">>$INSTANCE_HOME/mkebsboot.sh
echo "export EBS_DEVICE='$EBS_DEVICE'">>$INSTANCE_HOME/mkebsboot.sh
echo "export EBS_MOUNT_POINT='$EBS_MOUNT_POINT'">>$INSTANCE_HOME/mkebsboot.sh
echo 'cd $INSTANCE_HOME'>>$INSTANCE_HOME/mkebsboot.sh
echo 'echo creating a filesystem and mounting the ebs volume'>>$INSTANCE_HOME/mkebsboot.sh
echo 'mkdir -p $EBS_MOUNT_POINT'>>$INSTANCE_HOME/mkebsboot.sh
echo 'mkfs.ext3 $EBS_DEVICE'>>$INSTANCE_HOME/mkebsboot.sh
echo 'mount $EBS_DEVICE $EBS_MOUNT_POINT'>>$INSTANCE_HOME/mkebsboot.sh
echo 'echo making a local working copy of the boot disk'>>$INSTANCE_HOME/mkebsboot.sh
echo 'rsync --stats -av --exclude /root/.bash_history --exclude /home/*/.bash_history --exclude /etc/ssh/ssh_host_* --exclude /etc/ssh/moduli --exclude /etc/udev/rules.d/*persistent-net.rules --exclude /var/lib/ec2/* --exclude=/mnt/* --exclude=/proc/* --exclude=/tmp/* / $IMAGE_DIR'>>$INSTANCE_HOME/mkebsboot.sh
echo 'echo preparing the local working copy'>>$INSTANCE_HOME/mkebsboot.sh
echo 'touch $IMAGE_DIR/etc/init.d/ec2-init-user-data'>>$INSTANCE_HOME/mkebsboot.sh
echo 'echo copying the local working copy to the ebs mount'>>$INSTANCE_HOME/mkebsboot.sh
echo 'tar -cSf - -C ./ . | tar xvf - -C $EBS_MOUNT_POINT'>>$INSTANCE_HOME/mkebsboot.sh
echo 'unmount $EBS_MOUNT_POINT'>>$INSTANCE_HOME/mkebsboot.sh
echo 'echo ----COMPLETE----'>>$INSTANCE_HOME/mkebsboot.sh
echo 'exit 0'>>$INSTANCE_HOME/mkebsboot.sh
chmod u+x $INSTANCE_HOME/mkebsboot.sh
;;
status)
default || exit 1
findPid $INSTANCE_NAME || exit 1
echo [$FOUND_PID]
;;
stop)
default || exit 1
findPid $INSTANCE_NAME || exit 1
[ -n "$FOUND_PID" ] && {
echo stopping $FOUND_PID
kill -9 $FOUND_PID
}
;;
start)
default || exit 1
forget $INSTANCE_NAME $INSTANCE_HOME/$INSTANCE_NAME.sh $LOG_DIR || exit 1
;;
tail)
default || exit 1
tail $LOG_DIR/stdout.log;;
tailerr)
default || exit 1
tail $LOG_DIR/stderr.log;;
run)
default || exit 1
$INSTANCE_HOME/$INSTANCE_NAME.sh;;
esac
exit 0

View File

@ -0,0 +1,117 @@
@echo off
set PATH=
set JAVA_HOME=
set PATH=
GOTO FUNCTION_END
:abort
echo aborting: %EXCEPTION%
exit /b 1
:default
set INSTANCE_NAME=mkebsboot
set INSTANCE_HOME=/mnt/tmp
set LOG_DIR=/mnt/tmp
exit /b 0
:mkebsboot
set TMP_DIR=/mnt/tmp
exit /b 0
:findPid
set FOUND_PID=
set _expression=%1
shift
set FIND_PROCESS=TASKLIST /FI "WINDOWTITLE eq %_expression%" /NH
FOR /F "usebackq tokens=2 delims= " %%A IN (`cmd /c "%FIND_PROCESS% 2>NUL"`) DO (
SET FOUND_PID=%%A
)
if defined FOUND_PID (
exit /b 0
) else (
set EXCEPTION=%_expression% not found
exit /b 1
)
:forget
SETLOCAL
set FOUND_PID=
set NEXT_MINUTE=
set INSTANCE_NAME=%1
shift
set SCRIPT=%1
shift
set LOG_DIR=%1
shift
CALL :findProcess %INSTANCE_NAME%
if defined FOUND_PID (
echo %INSTANCE_NAME% already running pid [%FOUND_PID%]
) else (
CALL :nextMinute
set _DATE=%DATE:~4%
set CMD=schtasks /create /sd %_DATE% /tn %INSTANCE_NAME% /ru System /tr "cmd /c title %INSTANCE_NAME%&%SCRIPT% >%LOG_DIR%\stdout.log 2>%LOG_DIR%\stderr.log" /sc:once /st %NEXT_MINUTE%
echo %INSTANCE_NAME% will start at %NEXT_MINUTE%
set SECONDS=%TIME:~6,2%
set /a SECOND=60-SECONDS
%CMD% >NUL
ping -n %SECONDS% 127.0.0.1 > NUL 2>&1
CALL :findProcess %INSTANCE_NAME%
if not defined FOUND_PID (
set EXCEPTION=%INSTANCE_NAME% did not start
abort
)
)
exit /b 0
:FUNCTION_END
set PATH=c:\windows\;C:\windows\system32;c:\windows\system32\wbem
if not "%1" == "init" if not "%1" == "status" if not "%1" == "stop" if not "%1" == "start" if not "%1" == "tail" if not "%1" == "tailerr" if not "%1" == "run" (
set EXCEPTION=bad argument: %1 not in init status stop start tail tailerr run
goto abort
)
goto CASE_%1
:CASE_init
call :default
if errorlevel 1 goto abort
call :mkebsboot
if errorlevel 1 goto abort
md %INSTANCE_HOME%
del %INSTANCE_HOME%\mkebsboot.cmd 2>NUL
echo @echo off>>%INSTANCE_HOME%\mkebsboot.cmd
echo title mkebsboot>>%INSTANCE_HOME%\mkebsboot.cmd
echo set INSTANCE_NAME=mkebsboot>>%INSTANCE_HOME%\mkebsboot.cmd
echo set TMP_DIR=%TMP_DIR%>>%INSTANCE_HOME%\mkebsboot.cmd
echo cd /d %%INSTANCE_HOME%%>>%INSTANCE_HOME%\mkebsboot.cmd
echo find />>%INSTANCE_HOME%\mkebsboot.cmd
echo exit /b 0 >>%INSTANCE_HOME%\mkebsboot.cmd
GOTO END_SWITCH
:CASE_status
call :default
if errorlevel 1 goto abort
call :findPid %INSTANCE_NAME%
if errorlevel 1 goto abort
echo [%FOUND_PID%]
GOTO END_SWITCH
:CASE_stop
call :default
if errorlevel 1 goto abort
call :findPid %INSTANCE_NAME%
if errorlevel 1 goto abort
if defined FOUND_PID (
TASKKILL /F /T /PID %FOUND_PID% >NUL
)
GOTO END_SWITCH
:CASE_start
call :default
if errorlevel 1 goto abort
call :forget %INSTANCE_NAME% %INSTANCE_HOME%\%INSTANCE_NAME%.cmd %LOG_DIR%
if errorlevel 1 goto abort
GOTO END_SWITCH
:CASE_tail
call :default
if errorlevel 1 goto abort
tail %LOG_DIR%\stdout.logGOTO END_SWITCH
:CASE_tailerr
call :default
if errorlevel 1 goto abort
tail %LOG_DIR%\stderr.logGOTO END_SWITCH
:CASE_run
call :default
if errorlevel 1 goto abort
%INSTANCE_HOME%\%INSTANCE_NAME%.cmdGOTO END_SWITCH
:END_SWITCH
exit /b 0

View File

@ -0,0 +1,104 @@
#!/bin/bash
set -u
shopt -s xpg_echo
shopt -s expand_aliases
unset PATH JAVA_HOME LD_LIBRARY_PATH
function abort {
echo "aborting: $@" 1>&2
exit 1
}
function default {
export INSTANCE_NAME="mkebsboot"
export INSTANCE_HOME="/mnt/tmp"
export LOG_DIR="/mnt/tmp"
return 0
}
function mkebsboot {
export TMP_DIR="/mnt/tmp"
return 0
}
function findPid {
unset FOUND_PID;
[ $# -eq 1 ] || {
abort "findPid requires a parameter of pattern to match"
return 1
}
local PATTERN="$1"; shift
local _FOUND=`ps auxwww|grep "$PATTERN"|grep -v " $0"|grep -v grep|awk '{print $2}'`
[ -n "$_FOUND" ] && {
export FOUND_PID=$_FOUND
return 0
} || {
return 1
}
}
function forget {
unset FOUND_PID;
[ $# -eq 3 ] || {
abort "forget requires parameters INSTANCE_NAME SCRIPT LOG_DIR"
return 1
}
local INSTANCE_NAME="$1"; shift
local SCRIPT="$1"; shift
local LOG_DIR="$1"; shift
mkdir -p $LOG_DIR
findPid $INSTANCE_NAME
[ -n "$FOUND_PID" ] && {
echo $INSTANCE_NAME already running pid [$FOUND_PID]
} || {
nohup $SCRIPT >$LOG_DIR/stdout.log 2>$LOG_DIR/stderr.log &
findPid $INSTANCE_NAME
[ -n "$FOUND_PID" ] || abort "$INSTANCE_NAME did not start"
}
return 0
}
export PATH=/usr/ucb/bin:/bin:/usr/bin:/usr/sbin
case $1 in
init)
default || exit 1
mkebsboot || exit 1
mkdir -p $INSTANCE_HOME
rm $INSTANCE_HOME/mkebsboot.sh 2>&-
echo '#!/bin/bash'>>$INSTANCE_HOME/mkebsboot.sh
echo 'set -u'>>$INSTANCE_HOME/mkebsboot.sh
echo 'shopt -s xpg_echo'>>$INSTANCE_HOME/mkebsboot.sh
echo 'shopt -s expand_aliases'>>$INSTANCE_HOME/mkebsboot.sh
echo "PROMPT_COMMAND='echo -ne \"\033]0;mkebsboot\007\"'">>$INSTANCE_HOME/mkebsboot.sh
echo "export INSTANCE_NAME='mkebsboot'">>$INSTANCE_HOME/mkebsboot.sh
echo "export TMP_DIR='$TMP_DIR'">>$INSTANCE_HOME/mkebsboot.sh
echo "export INSTANCE_NAME='$INSTANCE_NAME'">>$INSTANCE_HOME/mkebsboot.sh
echo "export INSTANCE_HOME='$INSTANCE_HOME'">>$INSTANCE_HOME/mkebsboot.sh
echo "export LOG_DIR='$LOG_DIR'">>$INSTANCE_HOME/mkebsboot.sh
echo 'cd $INSTANCE_HOME'>>$INSTANCE_HOME/mkebsboot.sh
echo 'find /'>>$INSTANCE_HOME/mkebsboot.sh
echo 'exit 0'>>$INSTANCE_HOME/mkebsboot.sh
chmod u+x $INSTANCE_HOME/mkebsboot.sh
;;
status)
default || exit 1
findPid $INSTANCE_NAME || exit 1
echo [$FOUND_PID]
;;
stop)
default || exit 1
findPid $INSTANCE_NAME || exit 1
[ -n "$FOUND_PID" ] && {
echo stopping $FOUND_PID
kill -9 $FOUND_PID
}
;;
start)
default || exit 1
forget $INSTANCE_NAME $INSTANCE_HOME/$INSTANCE_NAME.sh $LOG_DIR || exit 1
;;
tail)
default || exit 1
tail $LOG_DIR/stdout.log;;
tailerr)
default || exit 1
tail $LOG_DIR/stderr.log;;
run)
default || exit 1
$INSTANCE_HOME/$INSTANCE_NAME.sh;;
esac
exit 0

View File

@ -5,5 +5,6 @@ echo title yahooprod>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd
echo set INSTANCE_NAME=yahooprod>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd
echo set JAVA_HOME=%JAVA_HOME%>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd
echo cd /d %TEMP%\%USERNAME%\scripttest>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd
echo echo hello>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd
echo echo %%JAVA_HOME%%\bin\java -DinstanceName=%%INSTANCE_NAME%% myServer.Main>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd
echo exit /b 0 >>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd

View File

@ -8,6 +8,7 @@ echo "PROMPT_COMMAND='echo -ne \"\033]0;yahooprod\007\"'">>/tmp/$USER/scripttest
echo "export INSTANCE_NAME='yahooprod'">>/tmp/$USER/scripttest/yahooprod.sh
echo "export JAVA_HOME='$JAVA_HOME'">>/tmp/$USER/scripttest/yahooprod.sh
echo 'cd /tmp/$USER/scripttest'>>/tmp/$USER/scripttest/yahooprod.sh
echo 'echo hello'>>/tmp/$USER/scripttest/yahooprod.sh
echo 'echo $JAVA_HOME/bin/java -DinstanceName=$INSTANCE_NAME myServer.Main'>>/tmp/$USER/scripttest/yahooprod.sh
echo 'exit 0'>>/tmp/$USER/scripttest/yahooprod.sh
chmod u+x /tmp/$USER/scripttest/yahooprod.sh