mirror of https://github.com/apache/jclouds.git
Added a new live test (InstanceVolumeManagerLiveTest.java).
Changed the snapshot taking behavior: snapshot is deleted when it's no longer needed. Exposed some of the object on InstanceVolumeManager for tests
This commit is contained in:
parent
1b09ebb041
commit
14d9862853
|
@ -12,3 +12,5 @@ Pre-requisites:
|
||||||
- running EBS-backed instance at Amazon EC2
|
- running EBS-backed instance at Amazon EC2
|
||||||
- Ubuntu image
|
- Ubuntu image
|
||||||
- proper settings in place (EbsResizeMain or launcher.rb)
|
- proper settings in place (EbsResizeMain or launcher.rb)
|
||||||
|
- file system is ext3 (otherwise, change is needed in org.jclouds.tools.ebsresize.InstanceVolumeManager)
|
||||||
|
- the demo doesn't take care of freezing the database, filesystem and application data
|
|
@ -23,6 +23,8 @@ import static com.google.common.base.Preconditions.checkState;
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
|
import com.google.inject.Module;
|
||||||
|
import com.google.inject.internal.ImmutableSet;
|
||||||
import org.jclouds.aws.domain.Region;
|
import org.jclouds.aws.domain.Region;
|
||||||
import org.jclouds.aws.ec2.EC2AsyncClient;
|
import org.jclouds.aws.ec2.EC2AsyncClient;
|
||||||
import org.jclouds.aws.ec2.EC2Client;
|
import org.jclouds.aws.ec2.EC2Client;
|
||||||
|
@ -44,6 +46,7 @@ import org.jclouds.tools.ebsresize.util.SshExecutor;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,10 +74,14 @@ public class InstanceVolumeManager {
|
||||||
new RetryablePredicate<InetSocketAddress>(new SocketOpen(), 180, 5, TimeUnit.SECONDS);
|
new RetryablePredicate<InetSocketAddress>(new SocketOpen(), 180, 5, TimeUnit.SECONDS);
|
||||||
|
|
||||||
public InstanceVolumeManager(String accessKeyId, String secretKey) {
|
public InstanceVolumeManager(String accessKeyId, String secretKey) {
|
||||||
|
this(accessKeyId, secretKey, new Properties());
|
||||||
|
}
|
||||||
|
|
||||||
|
public InstanceVolumeManager(String accessKeyId, String secretKey, Properties overridesForContext) {
|
||||||
try {
|
try {
|
||||||
context = new ComputeServiceContextFactory()
|
context = new ComputeServiceContextFactory()
|
||||||
.createContext("ec2", accessKeyId, secretKey);
|
.createContext("ec2", accessKeyId, secretKey,
|
||||||
|
ImmutableSet.<Module> of(), overridesForContext);
|
||||||
} catch(IOException e) { throw new RuntimeException(e); }
|
} catch(IOException e) { throw new RuntimeException(e); }
|
||||||
|
|
||||||
ec2context = context.getProviderSpecificContext();
|
ec2context = context.getProviderSpecificContext();
|
||||||
|
@ -142,6 +149,10 @@ public class InstanceVolumeManager {
|
||||||
/*or throw*/ "Couldn't connect to instance");
|
/*or throw*/ "Couldn't connect to instance");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void closeContext() {
|
||||||
|
context.close();
|
||||||
|
}
|
||||||
|
|
||||||
public ElasticBlockStoreFacade getEbsApi() {
|
public ElasticBlockStoreFacade getEbsApi() {
|
||||||
return ebsApi;
|
return ebsApi;
|
||||||
}
|
}
|
||||||
|
@ -153,4 +164,8 @@ public class InstanceVolumeManager {
|
||||||
public EC2Client getApi() {
|
public EC2Client getApi() {
|
||||||
return api;
|
return api;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ComputeServiceContext getContext() {
|
||||||
|
return context;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,6 @@ public class ElasticBlockStoreFacade {
|
||||||
"Only storage for instances with EBS type of root device can be resized.");
|
"Only storage for instances with EBS type of root device can be resized.");
|
||||||
|
|
||||||
String rootDevice = checkNotNull(runningInstance.getRootDeviceName());
|
String rootDevice = checkNotNull(runningInstance.getRootDeviceName());
|
||||||
runningInstance.getRootDeviceType();
|
|
||||||
|
|
||||||
//get volume id
|
//get volume id
|
||||||
String volumeId = null;
|
String volumeId = null;
|
||||||
|
@ -127,6 +126,7 @@ public class ElasticBlockStoreFacade {
|
||||||
checkState(volumeAvailable.apply(newVolume),
|
checkState(volumeAvailable.apply(newVolume),
|
||||||
/*or throw*/ "Couldn't create a volume from the snapshot");
|
/*or throw*/ "Couldn't create a volume from the snapshot");
|
||||||
|
|
||||||
|
elasticBlockStoreServices.deleteSnapshotInRegion(volume.getRegion(), createdSnapshot.getId());
|
||||||
return newVolume;
|
return newVolume;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,199 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ====================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jclouds.tools.ebsresize;
|
||||||
|
|
||||||
|
import com.google.common.base.Charsets;
|
||||||
|
import com.google.common.base.Predicate;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import com.google.common.io.Files;
|
||||||
|
import org.jclouds.aws.domain.Region;
|
||||||
|
import org.jclouds.aws.ec2.domain.*;
|
||||||
|
import org.jclouds.aws.ec2.domain.Volume;
|
||||||
|
import org.jclouds.aws.ec2.predicates.InstanceStateRunning;
|
||||||
|
import org.jclouds.aws.ec2.reference.EC2Constants;
|
||||||
|
import org.jclouds.compute.ComputeService;
|
||||||
|
import org.jclouds.compute.domain.*;
|
||||||
|
import org.jclouds.domain.Credentials;
|
||||||
|
import org.jclouds.predicates.RetryablePredicate;
|
||||||
|
import org.testng.annotations.*;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.SortedSet;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
|
import static org.easymock.classextension.EasyMock.*;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the resizing of instance's root EBS device.
|
||||||
|
*
|
||||||
|
* This test creates an instance, then resizes its root volume
|
||||||
|
* (which includes stopping it) and terminates it afterwards.
|
||||||
|
*
|
||||||
|
* @author Oleksiy Yarmula
|
||||||
|
*/
|
||||||
|
@Test(groups = {"live" }, enabled = false, testName = "ec2.InstanceVolumeManagerLiveTest")
|
||||||
|
public class InstanceVolumeManagerLiveTest {
|
||||||
|
|
||||||
|
private String tag;
|
||||||
|
private String secret;
|
||||||
|
private InstanceVolumeManager manager;
|
||||||
|
private ComputeService client;
|
||||||
|
private Template template;
|
||||||
|
private Predicate<RunningInstance> instanceRunning;
|
||||||
|
private RunningInstance instanceCreated;
|
||||||
|
|
||||||
|
@BeforeTest
|
||||||
|
public void setupClient() throws IOException {
|
||||||
|
|
||||||
|
//set up the constants needed to run
|
||||||
|
String user = checkNotNull(System.getProperty("jclouds.test.user"), "jclouds.test.user");
|
||||||
|
String password = checkNotNull(System.getProperty("jclouds.test.key"), "jclouds.test.key");
|
||||||
|
|
||||||
|
String secretKeyFile = checkNotNull(System.getProperty("jclouds.test.ssh.keyfile"),
|
||||||
|
"jclouds.test.ssh.keyfile");
|
||||||
|
tag = "ec2";
|
||||||
|
|
||||||
|
//ended setting up the constants
|
||||||
|
|
||||||
|
secret = Files.toString(new File(secretKeyFile), Charsets.UTF_8);
|
||||||
|
assert secret.startsWith("-----BEGIN RSA PRIVATE KEY-----") : "invalid key:\n" + secret;
|
||||||
|
|
||||||
|
//create a new manager
|
||||||
|
Properties testOnlyProperties = new Properties();
|
||||||
|
testOnlyProperties.put(EC2Constants.PROPERTY_EC2_AMI_OWNERS, "819060954727");
|
||||||
|
manager = new InstanceVolumeManager(user, password, testOnlyProperties);
|
||||||
|
client = manager.getContext().getComputeService();
|
||||||
|
|
||||||
|
TemplateBuilder templateBuilder = client.templateBuilder();
|
||||||
|
template =
|
||||||
|
templateBuilder.imageId("ami-2675974f").
|
||||||
|
build();
|
||||||
|
template.getOptions().installPrivateKey(secret);
|
||||||
|
|
||||||
|
instanceRunning =
|
||||||
|
new RetryablePredicate<RunningInstance>(new InstanceStateRunning(manager.getApi().
|
||||||
|
getInstanceServices()),
|
||||||
|
600, 10, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testResizeVolume() {
|
||||||
|
SortedSet<NodeMetadata> nodes = Sets.newTreeSet(
|
||||||
|
client.runNodesWithTag(tag, 1, template).values()
|
||||||
|
);
|
||||||
|
assert nodes.size() == 1 : "Expected to have 1 nodes created; found: " + nodes.size();
|
||||||
|
|
||||||
|
NodeMetadata launchedNode = Iterables.getOnlyElement(nodes);
|
||||||
|
|
||||||
|
AvailabilityZone availabilityZone = AvailabilityZone.fromValue(launchedNode.getLocationId());
|
||||||
|
Region region = getRegionNameForAvailabilityZone(availabilityZone);
|
||||||
|
|
||||||
|
waitForInstanceInRunningState(launchedNode.getId(), region);
|
||||||
|
|
||||||
|
manager.resizeVolume(launchedNode.getId(), region, new Credentials("ubuntu", ""),
|
||||||
|
secret, 6);
|
||||||
|
|
||||||
|
instanceCreated =
|
||||||
|
Iterables.getOnlyElement(
|
||||||
|
Iterables.getOnlyElement(
|
||||||
|
manager.getApi().
|
||||||
|
getInstanceServices().
|
||||||
|
describeInstancesInRegion(region, launchedNode.getId()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
Volume volumeAttached = manager.getEbsApi().getRootVolumeForInstance(instanceCreated);
|
||||||
|
assert volumeAttached.getSize() == 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterTest
|
||||||
|
public void close() {
|
||||||
|
manager.getApi().getInstanceServices().terminateInstancesInRegion
|
||||||
|
(instanceCreated.getRegion(), instanceCreated.getId());
|
||||||
|
manager.closeContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns region that has the given availability zone, or null,
|
||||||
|
* when nothing is found.
|
||||||
|
* This operates under the assumption that names of availability zones are
|
||||||
|
* unique, or else it returns the first matched region.
|
||||||
|
*
|
||||||
|
* @param zone
|
||||||
|
* zone that needs to be matched with region. This can not be null.
|
||||||
|
* @return region
|
||||||
|
* that has the provided zone
|
||||||
|
*/
|
||||||
|
private Region getRegionNameForAvailabilityZone(AvailabilityZone zone) {
|
||||||
|
for (Region region : ImmutableSet.of(Region.DEFAULT, Region.EU_WEST_1, Region.US_EAST_1,
|
||||||
|
Region.US_WEST_1)) {
|
||||||
|
SortedSet<AvailabilityZoneInfo> allResults = Sets.newTreeSet(manager.getApi().
|
||||||
|
getAvailabilityZoneAndRegionServices()
|
||||||
|
.describeAvailabilityZonesInRegion(region));
|
||||||
|
for(AvailabilityZoneInfo zoneInfo : allResults) {
|
||||||
|
if(zone == zoneInfo.getZone()) return zoneInfo.getRegion();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null; /*by contract*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blocks until the instance with given id and region is
|
||||||
|
* in 'running' state.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* id of the instance being run
|
||||||
|
* @param region
|
||||||
|
* region where the instance is launched
|
||||||
|
*/
|
||||||
|
private void waitForInstanceInRunningState(String id, Region region) {
|
||||||
|
RunningInstance instanceMock =
|
||||||
|
createInstanceFromIdAndRegion(id, region);
|
||||||
|
|
||||||
|
checkState(instanceRunning.apply(instanceMock),
|
||||||
|
/*or throw*/ "Couldn't run the instance");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses EasyMock to create a mock {@link RunningInstance}.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* id of the instance
|
||||||
|
* @param region
|
||||||
|
* region where it's launched
|
||||||
|
* @return
|
||||||
|
* instance of mock {@link org.jclouds.aws.ec2.domain.RunningInstance}
|
||||||
|
*/
|
||||||
|
private RunningInstance createInstanceFromIdAndRegion(String id, Region region) {
|
||||||
|
RunningInstance instanceMock = createMock(RunningInstance.class);
|
||||||
|
expect(instanceMock.getId()).andStubReturn(id);
|
||||||
|
expect(instanceMock.getRegion()).andStubReturn(region);
|
||||||
|
replay(instanceMock);
|
||||||
|
return instanceMock;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue