Merge branch 'master' into 1.5.x

* master:
  enum is not a sustainable way to refer to address blocks
  Issue 894:update to guava 12.0-rc2
  make FutureIterables covariant compatible + update tests
  implemented image extension
  Issue 895: Adjusting name and description of openstack-nova-ec2 maven module
  Issue 895: Correcting placement of rest client binding
  Issue 895: Filtering out non-MACHINE images from Nova-EC2 responses (note 2009-04-04 EC2 API didn't support filtering at the machine end)
  Exposing contents of DescribeImagesResponseHandler to subclasses
  Adjusting openstack-nova-ec2 to handle extended volume status fields (by discarding the extra information)
  Exposing fields of CreateVolumeResponseHandler to subclasses
This commit is contained in:
Adrian Cole 2012-04-18 11:18:27 -07:00
commit e54f33c91a
97 changed files with 2015 additions and 543 deletions

View File

@ -72,7 +72,7 @@ public class CloudLoadBalancersListLoadBalancersStrategy implements ListLoadBala
@Override @Override
public Iterable<? extends LoadBalancerMetadata> listLoadBalancers() { public Iterable<? extends LoadBalancerMetadata> listLoadBalancers() {
return transform(concat(transformParallel(regions.get(), new Function<String, Future<Set<LoadBalancer>>>() { return transform(concat(transformParallel(regions.get(), new Function<String, Future<? extends Set<LoadBalancer>>>() {
@Override @Override
public ListenableFuture<Set<LoadBalancer>> apply(String from) { public ListenableFuture<Set<LoadBalancer>> apply(String from) {

View File

@ -56,6 +56,7 @@ import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.domain.LoginCredentials; import org.jclouds.domain.LoginCredentials;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.util.Iterables2;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
@ -170,8 +171,8 @@ public class CloudSigmaComputeServiceAdapter implements
*/ */
@Override @Override
public Iterable<DriveInfo> listImages() { public Iterable<DriveInfo> listImages() {
Iterable<DriveInfo> drives = transformParallel(client.listStandardDrives(), Iterable<? extends DriveInfo> drives = transformParallel(client.listStandardDrives(),
new Function<String, Future<DriveInfo>>() { new Function<String, Future<? extends DriveInfo>>() {
@Override @Override
public Future<DriveInfo> apply(String input) { public Future<DriveInfo> apply(String input) {
@ -190,7 +191,7 @@ public class CloudSigmaComputeServiceAdapter implements
return "seedDriveCache()"; return "seedDriveCache()";
} }
}, executor, null, logger, "drives"); }, executor, null, logger, "drives");
return filter(drives, PREINSTALLED_DISK); return Iterables2.concreteCopy(filter(drives, PREINSTALLED_DISK));
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

View File

@ -25,8 +25,8 @@ import static org.jclouds.compute.config.ComputeServiceProperties.RESOURCENAME_D
import static org.jclouds.util.Preconditions2.checkNotEmpty; import static org.jclouds.util.Preconditions2.checkNotEmpty;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
@ -39,6 +39,7 @@ import org.jclouds.Constants;
import org.jclouds.aws.util.AWSUtils; import org.jclouds.aws.util.AWSUtils;
import org.jclouds.collect.Memoized; import org.jclouds.collect.Memoized;
import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.ImageExtension;
import org.jclouds.compute.callables.RunScriptOnNode; import org.jclouds.compute.callables.RunScriptOnNode;
import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
@ -69,12 +70,13 @@ import org.jclouds.scriptbuilder.functions.InitAdminAccess;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableMultimap.Builder; import com.google.common.collect.ImmutableMultimap.Builder;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Inject; import com.google.inject.Inject;
/** /**
@ -101,12 +103,13 @@ public class EC2ComputeService extends BaseComputeService {
RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess, RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
PersistNodeCredentials persistNodeCredentials, Timeouts timeouts, PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, EC2Client ec2Client, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, EC2Client ec2Client,
ConcurrentMap<RegionAndName, KeyPair> credentialsMap, @Named("SECURITY") LoadingCache<RegionAndName, String> securityGroupMap) { ConcurrentMap<RegionAndName, KeyPair> credentialsMap, @Named("SECURITY") LoadingCache<RegionAndName, String> securityGroupMap,
Optional<ImageExtension> imageExtension) {
super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy, super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy, stopNodeStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy, stopNodeStrategy,
templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated, nodeSuspended, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated, nodeSuspended,
initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials, timeouts, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials, timeouts,
executor); executor, imageExtension);
this.ec2Client = ec2Client; this.ec2Client = ec2Client;
this.credentialsMap = credentialsMap; this.credentialsMap = credentialsMap;
this.securityGroupMap = securityGroupMap; this.securityGroupMap = securityGroupMap;

View File

@ -65,7 +65,7 @@ public class DescribeImagesParallel implements
Iterable<Entry<String, DescribeImagesOptions>> queries) { Iterable<Entry<String, DescribeImagesOptions>> queries) {
return concat(transformParallel( return concat(transformParallel(
queries, queries,
new Function<Entry<String, DescribeImagesOptions>, Future<Set<? extends org.jclouds.ec2.domain.Image>>>() { new Function<Entry<String, DescribeImagesOptions>, Future<? extends Set<? extends org.jclouds.ec2.domain.Image>>>() {
@Override @Override
public Future<Set<? extends org.jclouds.ec2.domain.Image>> apply( public Future<Set<? extends org.jclouds.ec2.domain.Image>> apply(

View File

@ -92,7 +92,7 @@ public class EC2ListNodesStrategy implements ListNodesStrategy {
protected Iterable<? extends RunningInstance> pollRunningInstances() { protected Iterable<? extends RunningInstance> pollRunningInstances() {
Iterable<? extends Set<? extends Reservation<? extends RunningInstance>>> reservations = transformParallel( Iterable<? extends Set<? extends Reservation<? extends RunningInstance>>> reservations = transformParallel(
regions.get(), new Function<String, Future<Set<? extends Reservation<? extends RunningInstance>>>>() { regions.get(), new Function<String, Future<? extends Set<? extends Reservation<? extends RunningInstance>>>>() {
@Override @Override
public Future<Set<? extends Reservation<? extends RunningInstance>>> apply(String from) { public Future<Set<? extends Reservation<? extends RunningInstance>>> apply(String from) {

View File

@ -50,7 +50,7 @@ import com.google.common.collect.Sets;
* @author Adrian Cole * @author Adrian Cole
*/ */
public class CreateVolumeResponseHandler extends ParseSax.HandlerForGeneratedRequestWithResult<Volume> { public class CreateVolumeResponseHandler extends ParseSax.HandlerForGeneratedRequestWithResult<Volume> {
private StringBuilder currentText = new StringBuilder(); protected StringBuilder currentText = new StringBuilder();
@Resource @Resource
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
@ -58,7 +58,7 @@ public class CreateVolumeResponseHandler extends ParseSax.HandlerForGeneratedReq
protected DateService dateService; protected DateService dateService;
@Inject @Inject
@Region @Region
Supplier<String> defaultRegion; protected Supplier<String> defaultRegion;
@Inject @Inject
@Zone @Zone
protected Supplier<Map<String, Supplier<Set<String>>>> regionToZonesSupplier; protected Supplier<Map<String, Supplier<Set<String>>>> regionToZonesSupplier;
@ -66,23 +66,23 @@ public class CreateVolumeResponseHandler extends ParseSax.HandlerForGeneratedReq
@Zone @Zone
protected Supplier<Set<String>> zonesSupplier; protected Supplier<Set<String>> zonesSupplier;
private String id; protected String id;
private int size; protected int size;
private String snapshotId; protected String snapshotId;
private String availabilityZone; protected String availabilityZone;
private Volume.Status volumeStatus; protected Volume.Status volumeStatus;
private Date createTime; protected Date createTime;
private Set<Attachment> attachments = Sets.newLinkedHashSet(); protected Set<Attachment> attachments = Sets.newLinkedHashSet();
private String volumeId; protected String volumeId;
private String instanceId; protected String instanceId;
private String device; protected String device;
private Attachment.Status attachmentStatus; protected Attachment.Status attachmentStatus;
private Date attachTime; protected Date attachTime;
private boolean inAttachmentSet; protected boolean inAttachmentSet;
private String region; protected String region;
public Volume getResult() { public Volume getResult() {
return newVolume(); return newVolume();

View File

@ -61,7 +61,7 @@ public class DescribeImagesResponseHandler extends ParseSax.HandlerForGeneratedR
@Resource @Resource
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
private Set<Image> contents = Sets.newLinkedHashSet(); protected Set<Image> contents = Sets.newLinkedHashSet();
private StringBuilder currentText = new StringBuilder(); private StringBuilder currentText = new StringBuilder();
private final Supplier<String> defaultRegion; private final Supplier<String> defaultRegion;

View File

@ -58,6 +58,7 @@ import org.jclouds.elasticstack.domain.ServerStatus;
import org.jclouds.elasticstack.domain.WellKnownImage; import org.jclouds.elasticstack.domain.WellKnownImage;
import org.jclouds.elasticstack.reference.ElasticStackConstants; import org.jclouds.elasticstack.reference.ElasticStackConstants;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.util.Iterables2;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
@ -162,11 +163,11 @@ public class ElasticStackComputeServiceAdapter implements
*/ */
@Override @Override
public Iterable<DriveInfo> listImages() { public Iterable<DriveInfo> listImages() {
Iterable<DriveInfo> drives = transformParallel(preinstalledImages.keySet(), Iterable<? extends DriveInfo> drives = transformParallel(preinstalledImages.keySet(),
new Function<String, Future<DriveInfo>>() { new Function<String, Future<? extends DriveInfo>>() {
@Override @Override
public Future<DriveInfo> apply(String input) { public Future<? extends DriveInfo> apply(String input) {
try { try {
return Futures.immediateFuture(cache.getUnchecked(input)); return Futures.immediateFuture(cache.getUnchecked(input));
} catch (CacheLoader.InvalidCacheLoadException e) { } catch (CacheLoader.InvalidCacheLoadException e) {
@ -183,7 +184,7 @@ public class ElasticStackComputeServiceAdapter implements
} }
}, executor, null, logger, "drives"); }, executor, null, logger, "drives");
return filter(drives, notNull()); return Iterables2.concreteCopy(filter(drives, notNull()));
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

View File

@ -29,8 +29,8 @@
</parent> </parent>
<groupId>org.jclouds.api</groupId> <groupId>org.jclouds.api</groupId>
<artifactId>openstack-nova-ec2</artifactId> <artifactId>openstack-nova-ec2</artifactId>
<name>jclouds Eucalyptus api</name> <name>jclouds openstack-nova-ec2 api</name>
<description>EC2 implementation based on Eucalyptus</description> <description>EC2 interface to Openstack Nova</description>
<packaging>bundle</packaging> <packaging>bundle</packaging>
<properties> <properties>

View File

@ -22,10 +22,14 @@ import org.jclouds.ec2.EC2AsyncClient;
import org.jclouds.ec2.EC2Client; import org.jclouds.ec2.EC2Client;
import org.jclouds.ec2.config.EC2RestClientModule; import org.jclouds.ec2.config.EC2RestClientModule;
import org.jclouds.ec2.suppliers.DescribeAvailabilityZonesInRegion; import org.jclouds.ec2.suppliers.DescribeAvailabilityZonesInRegion;
import org.jclouds.ec2.xml.CreateVolumeResponseHandler;
import org.jclouds.ec2.xml.DescribeImagesResponseHandler;
import org.jclouds.location.config.LocationModule; import org.jclouds.location.config.LocationModule;
import org.jclouds.location.suppliers.RegionIdToZoneIdsSupplier; import org.jclouds.location.suppliers.RegionIdToZoneIdsSupplier;
import org.jclouds.location.suppliers.ZoneIdsSupplier; import org.jclouds.location.suppliers.ZoneIdsSupplier;
import org.jclouds.location.suppliers.derived.ZoneIdsFromRegionIdToZoneIdsValues; import org.jclouds.location.suppliers.derived.ZoneIdsFromRegionIdToZoneIdsValues;
import org.jclouds.openstack.nova.ec2.xml.NovaCreateVolumeResponseHandler;
import org.jclouds.openstack.nova.ec2.xml.NovaDescribeImagesResponseHandler;
import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.rest.ConfiguresRestClient;
import com.google.inject.Scopes; import com.google.inject.Scopes;
@ -41,6 +45,13 @@ public class NovaEC2RestClientModule extends EC2RestClientModule<EC2Client, EC2A
super(EC2Client.class, EC2AsyncClient.class, DELEGATE_MAP); super(EC2Client.class, EC2AsyncClient.class, DELEGATE_MAP);
} }
@Override
protected void configure() {
super.configure();
bind(CreateVolumeResponseHandler.class).to(NovaCreateVolumeResponseHandler.class).in(Scopes.SINGLETON);
bind(DescribeImagesResponseHandler.class).to(NovaDescribeImagesResponseHandler.class);
}
@Override @Override
protected void installLocations() { protected void installLocations() {
install(new LocationModule()); install(new LocationModule());

View File

@ -0,0 +1,48 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.nova.ec2.xml;
import org.jclouds.ec2.domain.Attachment;
import org.jclouds.ec2.domain.Volume;
import org.jclouds.ec2.xml.CreateVolumeResponseHandler;
/**
*
* @author Adam lowe
*/
public class NovaCreateVolumeResponseHandler extends CreateVolumeResponseHandler {
public void endElement(String uri, String name, String qName) {
if (qName.equals("status")) {
String statusString = currentText.toString().trim();
if (statusString.contains(" ")) {
statusString = statusString.substring(0, statusString.indexOf(' '));
}
if (inAttachmentSet) {
attachmentStatus = Attachment.Status.fromValue(statusString);
} else {
volumeStatus = Volume.Status.fromValue(statusString);
}
currentText = new StringBuilder();
} else {
super.endElement(uri, name, qName);
}
}
}

View File

@ -0,0 +1,54 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.nova.ec2.xml;
import java.util.Set;
import javax.inject.Inject;
import org.jclouds.ec2.domain.Image;
import org.jclouds.ec2.domain.Image.ImageType;
import org.jclouds.ec2.xml.DescribeImagesResponseHandler;
import org.jclouds.location.Region;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
/**
* Adjusted to filter out non-MACHINE images
*
* @author Adam Lowe
*/
public class NovaDescribeImagesResponseHandler extends DescribeImagesResponseHandler {
@Inject
public NovaDescribeImagesResponseHandler(@Region Supplier<String> defaultRegion) {
super(defaultRegion);
}
public Set<Image> getResult() {
return ImmutableSet.copyOf(Iterables.filter(contents, new Predicate<Image>() {
@Override
public boolean apply(Image image) {
return image.getImageType() == ImageType.MACHINE;
}
}));
}
}

View File

@ -0,0 +1,54 @@
package org.jclouds.openstack.nova.ec2.internal;
import java.net.URI;
import javax.inject.Named;
import javax.ws.rs.core.MediaType;
import org.jclouds.Constants;
import org.jclouds.date.DateService;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.ec2.EC2Client;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.nova.ec2.config.NovaEC2RestClientModule;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.internal.BaseRestClientExpectTest;
import com.google.common.collect.ImmutableMultimap;
import com.google.inject.Module;
import com.google.inject.Provides;
public abstract class BaseNovaEC2RestClientExpectTest extends BaseRestClientExpectTest<EC2Client> {
protected static final String CONSTANT_DATE = "2012-04-16T15:54:08.897Z";
protected DateService dateService = new SimpleDateFormatDateService();
protected URI endpoint = URI.create("http://localhost:8773/services/Cloud/");
protected HttpRequest describeAvailabilityZonesRequest = HttpRequest.builder().method("POST")
.endpoint(endpoint)
.headers(ImmutableMultimap.of("Host", "localhost:8773"))
.payload(payloadFromStringWithContentType("Action=DescribeAvailabilityZones&Signature=S3fa5fybw4KAq4o11IpKHlqwx3cVJdKfeAKw3FIJYvM%3D&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2012-04-16T15%3A54%3A08.897Z&Version=2009-04-04&AWSAccessKeyId=identity", MediaType.APPLICATION_FORM_URLENCODED))
.build();
protected HttpResponse describeAvailabilityZonesResponse = HttpResponse.builder()
.statusCode(200).payload(payloadFromResourceWithContentType("/nova_ec2_availabilityZones.xml", MediaType.APPLICATION_XML)).build();
public BaseNovaEC2RestClientExpectTest() {
provider = "openstack-nova-ec2";
}
@ConfiguresRestClient
private static final class TestNovaEC2RestClientModule extends NovaEC2RestClientModule {
@Override
@Provides
protected String provideTimeStamp(final DateService dateService,
@Named(Constants.PROPERTY_SESSION_INTERVAL) final int expiration) {
return CONSTANT_DATE;
}
}
@Override
protected Module createModule() {
return new TestNovaEC2RestClientModule();
}
}

View File

@ -0,0 +1,58 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.nova.ec2.services;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import java.util.Set;
import org.jclouds.ec2.domain.Image;
import org.jclouds.ec2.services.AMIClient;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.nova.ec2.internal.BaseNovaEC2RestClientExpectTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap;
/**
* @author Adam Lowe
*/
@Test(groups = "unit", testName = "NovaEC2ElasticBlockStoreClientTest")
public class NovaEC2AMIClientTest extends BaseNovaEC2RestClientExpectTest {
public void testDescribeImagesWithNonMachineTypes() {
AMIClient client = requestsSendResponses(
describeAvailabilityZonesRequest,
describeAvailabilityZonesResponse,
HttpRequest.builder().method("POST")
.endpoint(URI.create("http://localhost:8773/services/Cloud/"))
.headers(ImmutableMultimap.of("Host", "localhost:8773"))
.payload(payloadFromStringWithContentType("Action=DescribeImages&Signature=Z3q3jSutwlfgvbcINT0Ed3AjrjxM4WMvQloXu%2F1kd40%3D&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2012-04-16T15%3A54%3A08.897Z&Version=2009-04-04&AWSAccessKeyId=identity", "application/x-www-form-urlencoded")).build(),
HttpResponse.builder().statusCode(200).payload(payloadFromResource("/nova_ec2_images_with_ramdisk.xml")).build()
).getAMIServices();
Set<? extends Image> images = client.describeImagesInRegion("nova");
assertEquals(images.size(), 1);
}
}

View File

@ -0,0 +1,68 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.nova.ec2.services;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import java.util.Set;
import org.jclouds.ec2.domain.Attachment;
import org.jclouds.ec2.domain.Volume;
import org.jclouds.ec2.services.ElasticBlockStoreClient;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.nova.ec2.internal.BaseNovaEC2RestClientExpectTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
/**
* @author Adam Lowe
*/
@Test(groups = "unit", testName = "NovaEC2ElasticBlockStoreClientTest")
public class NovaEC2ElasticBlockStoreClientTest extends BaseNovaEC2RestClientExpectTest {
public void testDescribeVolumesWithNovaEC2Status() {
ElasticBlockStoreClient client = requestsSendResponses(
describeAvailabilityZonesRequest,
describeAvailabilityZonesResponse,
HttpRequest.builder().method("POST")
.endpoint(URI.create("http://localhost:8773/services/Cloud/"))
.headers(ImmutableMultimap.of("Host", "localhost:8773"))
.payload(payloadFromStringWithContentType("Action=DescribeVolumes&Signature=AvRznSzGExM%2Buaj2JJj66wq4v4f%2BakicyLooRDtC0t0%3D&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2012-04-16T15%3A54%3A08.897Z&Version=2009-04-04&AWSAccessKeyId=identity", "application/x-www-form-urlencoded")).build(),
HttpResponse.builder().statusCode(200).payload(payloadFromResource("/nova_ec2_describe_volumes.xml")).build()
).getElasticBlockStoreServices();
Set<Volume> expected = ImmutableSet.of(Volume
.builder()
.status(Volume.Status.AVAILABLE)
.availabilityZone("nova")
.region("nova")
.id("vol-00000007")
.size(1)
.attachments(Attachment.builder().region("nova").build())
.createTime(dateService.iso8601SecondsDateParse("2012-04-10T10:39:52Z"))
.build());
assertEquals(client.describeVolumesInRegion("nova"), expected);
}
}

View File

@ -0,0 +1,10 @@
<?xml version="1.0" ?>
<DescribeAvailabilityZonesResponse xmlns="http://ec2.amazonaws.com/doc/2009-04-04/">
<requestId>req-a6cd42f8-b5e5-4c94-a1e0-41d21ea0a032</requestId>
<availabilityZoneInfo>
<item>
<zoneState>available</zoneState>
<zoneName>nova</zoneName>
</item>
</availabilityZoneInfo>
</DescribeAvailabilityZonesResponse>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" ?>
<DescribeVolumesResponse xmlns="http://ec2.amazonaws.com/doc/2009-04-04/">
<requestId>req-9e45299b-980d-4893-a475-a574b1a94ed5</requestId>
<volumeSet>
<item>
<status>available (f06de98af01446b2ae6bd79f5fbf3b2a, att-openstack1, None, None)</status>
<availabilityZone>nova</availabilityZone>
<volumeId>vol-00000007</volumeId>
<attachmentSet>
<item/>
</attachmentSet>
<snapshotId/>
<createTime>2012-04-10T10:39:52.000Z</createTime>
<size>1</size>
</item>
</volumeSet>
</DescribeVolumesResponse>

View File

@ -0,0 +1,47 @@
<?xml version="1.0" ?>
<DescribeImagesResponse xmlns="http://ec2.amazonaws.com/doc/2009-04-04/">
<requestId>req-bfdac708-c6c4-48fb-9cba-be5bb0a05b49</requestId>
<imagesSet>
<item>
<description/>
<imageOwnerId/>
<isPublic>true</isPublic>
<imageId>aki-00000002</imageId>
<imageState>available</imageState>
<architecture/>
<imageLocation>None (cirros-0.3.0-x86_64-blank-kernel)</imageLocation>
<rootDeviceType>instance-store</rootDeviceType>
<rootDeviceName>/dev/sda1</rootDeviceName>
<imageType>kernel</imageType>
<name>cirros-0.3.0-x86_64-blank-kernel</name>
</item>
<item>
<description/>
<imageOwnerId/>
<isPublic>true</isPublic>
<imageId>ari-00000003</imageId>
<imageState>available</imageState>
<architecture/>
<imageLocation>None (cirros-0.3.0-x86_64-blank-ramdisk)</imageLocation>
<rootDeviceType>instance-store</rootDeviceType>
<rootDeviceName>/dev/sda1</rootDeviceName>
<imageType>ramdisk</imageType>
<name>cirros-0.3.0-x86_64-blank-ramdisk</name>
</item>
<item>
<name>cirros-0.3.0-x86_64-blank</name>
<imageOwnerId/>
<isPublic>true</isPublic>
<imageId>ami-00000001</imageId>
<imageState>available</imageState>
<rootDeviceType>instance-store</rootDeviceType>
<architecture/>
<imageLocation>None (cirros-0.3.0-x86_64-blank)</imageLocation>
<kernelId>aki-00000002</kernelId>
<ramdiskId>ari-00000003</ramdiskId>
<rootDeviceName>/dev/sda1</rootDeviceName>
<imageType>machine</imageType>
<description/>
</item>
</imagesSet>
</DescribeImagesResponse>

View File

@ -33,6 +33,7 @@ import javax.inject.Singleton;
import org.jclouds.Constants; import org.jclouds.Constants;
import org.jclouds.collect.Memoized; import org.jclouds.collect.Memoized;
import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.ImageExtension;
import org.jclouds.compute.callables.RunScriptOnNode; import org.jclouds.compute.callables.RunScriptOnNode;
import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
@ -103,12 +104,12 @@ public class NovaComputeService extends BaseComputeService {
LoadingCache<ZoneAndName, SecurityGroupInZone> securityGroupMap, LoadingCache<ZoneAndName, SecurityGroupInZone> securityGroupMap,
LoadingCache<ZoneAndName, KeyPair> keyPairCache, LoadingCache<ZoneAndName, KeyPair> keyPairCache,
Function<Set<? extends NodeMetadata>, Multimap<String, String>> orphanedGroupsByZoneId, Function<Set<? extends NodeMetadata>, Multimap<String, String>> orphanedGroupsByZoneId,
GroupNamingConvention.Factory namingConvention) { GroupNamingConvention.Factory namingConvention, Optional<ImageExtension> imageExtension) {
super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy, super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy, stopNodeStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy,
templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated, nodeSuspended, stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials, timeouts, nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials,
executor); timeouts, executor, imageExtension);
this.novaClient = checkNotNull(novaClient, "novaClient"); this.novaClient = checkNotNull(novaClient, "novaClient");
this.securityGroupMap = checkNotNull(securityGroupMap, "securityGroupMap"); this.securityGroupMap = checkNotNull(securityGroupMap, "securityGroupMap");
this.keyPairCache = checkNotNull(keyPairCache, "keyPairCache"); this.keyPairCache = checkNotNull(keyPairCache, "keyPairCache");
@ -134,7 +135,7 @@ public class NovaComputeService extends BaseComputeService {
if (securityGroupClient.isPresent()) { if (securityGroupClient.isPresent()) {
for (String group : groups) { for (String group : groups) {
for (SecurityGroup securityGroup : Iterables.filter(securityGroupClient.get().listSecurityGroups(), for (SecurityGroup securityGroup : Iterables.filter(securityGroupClient.get().listSecurityGroups(),
SecurityGroupPredicates.nameMatches(namingConvention.create().containsGroup(group)))) { SecurityGroupPredicates.nameMatches(namingConvention.create().containsGroup(group)))) {
ZoneAndName zoneAndName = ZoneAndName.fromZoneAndName(zoneId, securityGroup.getName()); ZoneAndName zoneAndName = ZoneAndName.fromZoneAndName(zoneId, securityGroup.getName());
logger.debug(">> deleting securityGroup(%s)", zoneAndName); logger.debug(">> deleting securityGroup(%s)", zoneAndName);
securityGroupClient.get().deleteSecurityGroup(securityGroup.getId()); securityGroupClient.get().deleteSecurityGroup(securityGroup.getId());
@ -152,7 +153,7 @@ public class NovaComputeService extends BaseComputeService {
for (String group : groups) { for (String group : groups) {
for (Map<String, KeyPair> wrapper : keyPairClient.get().listKeyPairs()) { for (Map<String, KeyPair> wrapper : keyPairClient.get().listKeyPairs()) {
for (KeyPair pair : Iterables.filter(wrapper.values(), for (KeyPair pair : Iterables.filter(wrapper.values(),
KeyPairPredicates.nameMatches(namingConvention.create().containsGroup(group)))) { KeyPairPredicates.nameMatches(namingConvention.create().containsGroup(group)))) {
ZoneAndName zoneAndName = ZoneAndName.fromZoneAndName(zoneId, pair.getName()); ZoneAndName zoneAndName = ZoneAndName.fromZoneAndName(zoneId, pair.getName());
logger.debug(">> deleting keypair(%s)", zoneAndName); logger.debug(">> deleting keypair(%s)", zoneAndName);
keyPairClient.get().deleteKeyPair(pair.getName()); keyPairClient.get().deleteKeyPair(pair.getName());
@ -162,7 +163,7 @@ public class NovaComputeService extends BaseComputeService {
} }
} }
keyPairCache.invalidate(ZoneAndName.fromZoneAndName(zoneId, keyPairCache.invalidate(ZoneAndName.fromZoneAndName(zoneId,
namingConvention.create().sharedNameForGroup(group))); namingConvention.create().sharedNameForGroup(group)));
} }
} }
} }
@ -174,5 +175,7 @@ public class NovaComputeService extends BaseComputeService {
public NovaTemplateOptions templateOptions() { public NovaTemplateOptions templateOptions() {
return NovaTemplateOptions.class.cast(super.templateOptions()); return NovaTemplateOptions.class.cast(super.templateOptions());
} }
} }

View File

@ -0,0 +1,101 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.nova.v1_1.compute;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import java.util.NoSuchElementException;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.compute.ImageExtension;
import org.jclouds.compute.domain.CloneImageTemplate;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.ImageTemplate;
import org.jclouds.compute.domain.ImageTemplateBuilder;
import org.jclouds.openstack.nova.v1_1.NovaClient;
import org.jclouds.openstack.nova.v1_1.domain.Server;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ImageInZone;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndId;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
@Singleton
public class NovaImageExtension implements ImageExtension {
private final NovaClient novaClient;
private final Function<ImageInZone, Image> imageInZoneToImage;
@Inject
public NovaImageExtension(NovaClient novaClient, Function<ImageInZone, Image> imageInZoneToImage) {
this.novaClient = checkNotNull(novaClient);
this.imageInZoneToImage = imageInZoneToImage;
}
@Override
public ImageTemplate buildImageTemplateFromNode(String name, final String id) {
ZoneAndId zoneAndId = ZoneAndId.fromSlashEncoded(id);
Server server = novaClient.getServerClientForZone(zoneAndId.getZone()).getServer(zoneAndId.getId());
if (server == null)
throw new NoSuchElementException("Cannot find server with id: " + zoneAndId);
CloneImageTemplate template = new ImageTemplateBuilder.CloneImageTemplateBuilder().nodeId(id).name(name).build();
return template;
}
@Override
public Image createImage(ImageTemplate template) {
checkState(template instanceof CloneImageTemplate,
" openstack-nova only supports creating images through cloning.");
CloneImageTemplate cloneTemplate = (CloneImageTemplate) template;
ZoneAndId zoneAndId = ZoneAndId.fromSlashEncoded(cloneTemplate.getSourceNodeId());
String newImageId = novaClient.getServerClientForZone(zoneAndId.getZone()).createImageFromServer(
cloneTemplate.getName(), zoneAndId.getId());
org.jclouds.openstack.nova.v1_1.domain.Image newImage = checkNotNull(findImage(ZoneAndId.fromZoneAndId(
zoneAndId.getZone(), newImageId)));
return imageInZoneToImage.apply(new ImageInZone(newImage, zoneAndId.getZone()));
}
@Override
public boolean deleteImage(String id) {
ZoneAndId zoneAndId = ZoneAndId.fromSlashEncoded(id);
try {
this.novaClient.getImageClientForZone(zoneAndId.getZone()).deleteImage(zoneAndId.getId());
} catch (Exception e) {
return false;
}
return true;
}
private org.jclouds.openstack.nova.v1_1.domain.Image findImage(final ZoneAndId zoneAndId) {
return Iterables.tryFind(novaClient.getImageClientForZone(zoneAndId.getZone()).listImagesInDetail(),
new Predicate<org.jclouds.openstack.nova.v1_1.domain.Image>() {
@Override
public boolean apply(org.jclouds.openstack.nova.v1_1.domain.Image input) {
return input.getId().equals(zoneAndId.getId());
}
}).orNull();
}
}

View File

@ -33,6 +33,7 @@ import javax.inject.Singleton;
import org.jclouds.collect.Memoized; import org.jclouds.collect.Memoized;
import org.jclouds.compute.ComputeService; import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceAdapter; import org.jclouds.compute.ComputeServiceAdapter;
import org.jclouds.compute.ImageExtension;
import org.jclouds.compute.config.ComputeServiceAdapterContextModule; import org.jclouds.compute.config.ComputeServiceAdapterContextModule;
import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
@ -46,6 +47,7 @@ import org.jclouds.domain.LoginCredentials;
import org.jclouds.functions.IdentityFunction; import org.jclouds.functions.IdentityFunction;
import org.jclouds.openstack.nova.v1_1.compute.NovaComputeService; import org.jclouds.openstack.nova.v1_1.compute.NovaComputeService;
import org.jclouds.openstack.nova.v1_1.compute.NovaComputeServiceAdapter; import org.jclouds.openstack.nova.v1_1.compute.NovaComputeServiceAdapter;
import org.jclouds.openstack.nova.v1_1.compute.NovaImageExtension;
import org.jclouds.openstack.nova.v1_1.compute.functions.CreateSecurityGroupIfNeeded; import org.jclouds.openstack.nova.v1_1.compute.functions.CreateSecurityGroupIfNeeded;
import org.jclouds.openstack.nova.v1_1.compute.functions.FlavorInZoneToHardware; import org.jclouds.openstack.nova.v1_1.compute.functions.FlavorInZoneToHardware;
import org.jclouds.openstack.nova.v1_1.compute.functions.ImageInZoneToImage; import org.jclouds.openstack.nova.v1_1.compute.functions.ImageInZoneToImage;
@ -69,6 +71,7 @@ import org.jclouds.openstack.nova.v1_1.predicates.FindSecurityGroupWithNameAndRe
import org.jclouds.predicates.RetryablePredicate; import org.jclouds.predicates.RetryablePredicate;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
@ -135,6 +138,9 @@ public class NovaComputeServiceContextModule extends
bind(new TypeLiteral<CacheLoader<ZoneAndName, KeyPair>>() { bind(new TypeLiteral<CacheLoader<ZoneAndName, KeyPair>>() {
}).to(CreateUniqueKeyPair.class); }).to(CreateUniqueKeyPair.class);
bind(new TypeLiteral<ImageExtension>() {
}).to(NovaImageExtension.class);
} }
@Override @Override
@ -206,4 +212,9 @@ public class NovaComputeServiceContextModule extends
}, locations); }, locations);
} }
@Override
protected Optional<ImageExtension> provideImageExtension(Injector i) {
return Optional.of(i.getInstance(ImageExtension.class));
}
} }

View File

@ -20,7 +20,6 @@ package org.jclouds.openstack.nova.v1_1.compute.functions;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Iterables.filter; import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.find; import static com.google.common.collect.Iterables.find;
import static com.google.common.collect.Iterables.transform; import static com.google.common.collect.Iterables.transform;
@ -51,9 +50,11 @@ import org.jclouds.openstack.nova.v1_1.domain.Address;
import org.jclouds.openstack.nova.v1_1.domain.Server; import org.jclouds.openstack.nova.v1_1.domain.Server;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ServerInZone; import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ServerInZone;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndId; import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndId;
import org.jclouds.util.InetAddresses2;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.net.InetAddresses; import com.google.common.net.InetAddresses;
@ -103,14 +104,20 @@ public class ServerInZoneToNodeMetadata implements Function<ServerInZone, NodeMe
builder.hardware(findHardwareForServerOrNull(serverInZone)); builder.hardware(findHardwareForServerOrNull(serverInZone));
builder.state(from.getStatus().getNodeState()); builder.state(from.getStatus().getNodeState());
builder.publicAddresses(filter( builder.publicAddresses(filter(
transform(concat(from.getPublicAddresses(), from.getInternetAddresses()), transform(filter(from.getAddresses().values(), Predicates.not(isPrivateAddress)),
AddressToStringTransformationFunction.INSTANCE), isInet4Address)); AddressToStringTransformationFunction.INSTANCE), isInet4Address));
builder.privateAddresses(filter( builder.privateAddresses(filter(
transform(from.getPrivateAddresses(), AddressToStringTransformationFunction.INSTANCE), isInet4Address)); transform(filter(from.getAddresses().values(), isPrivateAddress), AddressToStringTransformationFunction.INSTANCE), isInet4Address));
return builder.build(); return builder.build();
} }
private static final Predicate<Address> isPrivateAddress = new Predicate<Address>() {
public boolean apply(Address in) {
return InetAddresses2.IsPrivateIPAddress.INSTANCE.apply(in.getAddr());
}
};
public static final Predicate<String> isInet4Address = new Predicate<String>() { public static final Predicate<String> isInet4Address = new Predicate<String>() {
@Override @Override
public boolean apply(String input) { public boolean apply(String input) {

View File

@ -30,42 +30,7 @@ import com.google.common.base.Objects;
* @author AdrianCole * @author AdrianCole
*/ */
public class Address { public class Address {
/**
* Relations associated with resources.
*/
public static enum Type {
/**
* internet routable address
*/
INTERNET,
/**
* publically routable address
*/
PUBLIC,
/**
* address that is not publicly routable.
*/
PRIVATE,
/**
* the value returned by the OpenStack service was not recognized.
*/
UNRECOGNIZED;
public String value() {
return name().toLowerCase();
}
public static Type fromValue(String v) {
try {
return valueOf(v.toUpperCase());
} catch (IllegalArgumentException e) {
return UNRECOGNIZED;
}
}
}
public static Builder builder() { public static Builder builder() {
return new Builder(); return new Builder();
} }

View File

@ -20,7 +20,6 @@ package org.jclouds.openstack.nova.v1_1.domain;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -29,20 +28,14 @@ import org.jclouds.compute.domain.NodeState;
import org.jclouds.javax.annotation.Nullable; import org.jclouds.javax.annotation.Nullable;
import org.jclouds.openstack.domain.Link; import org.jclouds.openstack.domain.Link;
import org.jclouds.openstack.domain.Resource; import org.jclouds.openstack.domain.Resource;
import org.jclouds.openstack.nova.v1_1.domain.Address.Type;
import org.jclouds.openstack.nova.v1_1.extensions.KeyPairClient; import org.jclouds.openstack.nova.v1_1.extensions.KeyPairClient;
import org.jclouds.util.InetAddresses2;
import org.jclouds.util.Multimaps2; import org.jclouds.util.Multimaps2;
import com.google.common.base.Predicate; import com.google.common.base.Objects.ToStringHelper;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.common.base.Objects.ToStringHelper;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
@ -122,7 +115,7 @@ public class Server extends Resource {
private Resource flavor; private Resource flavor;
private Map<String, String> metadata = Maps.newHashMap(); private Map<String, String> metadata = Maps.newHashMap();
// TODO: get gson multimap ad // TODO: get gson multimap ad
private Multimap<Address.Type, Address> addresses = LinkedHashMultimap.create(); private Multimap<String, Address> addresses = LinkedHashMultimap.create();
private String adminPass; private String adminPass;
private String keyName; private String keyName;
@ -233,59 +226,11 @@ public class Server extends Resource {
/** /**
* @see Server#getAddresses() * @see Server#getAddresses()
*/ */
public Builder addresses(Multimap<Address.Type, Address> addresses) { public Builder addresses(Multimap<String, Address> addresses) {
this.addresses = ImmutableMultimap.copyOf(checkNotNull(addresses, "addresses")); this.addresses = ImmutableMultimap.copyOf(checkNotNull(addresses, "addresses"));
return this; return this;
} }
/**
* @see Server#getPrivateAddresses()
*/
public Builder privateAddresses(Address... privateAddresses) {
return privateAddresses(ImmutableSet.copyOf(checkNotNull(privateAddresses, "privateAddresses")));
}
/**
* @see Server#getPrivateAddresses()
*/
public Builder privateAddresses(Set<Address> privateAddresses) {
this.addresses.replaceValues(Address.Type.PRIVATE, ImmutableSet.copyOf(checkNotNull(privateAddresses,
"privateAddresses")));
return this;
}
/**
* @see Server#getInternetAddresses()
*/
public Builder internetAddresses(Address... internetAddresses) {
return internetAddresses(ImmutableSet.copyOf(checkNotNull(internetAddresses, "internetAddresses")));
}
/**
* @see Server#getInternetAddresses()
*/
public Builder internetAddresses(Set<Address> internetAddresses) {
this.addresses.replaceValues(Address.Type.INTERNET, ImmutableSet.copyOf(checkNotNull(internetAddresses,
"internetAddresses")));
return this;
}
/**
* @see Server#getPublicAddresses()
*/
public Builder publicAddresses(Address... publicAddresses) {
return publicAddresses(ImmutableSet.copyOf(checkNotNull(publicAddresses, "publicAddresses")));
}
/**
* @see Server#getPublicAddresses()
*/
public Builder publicAddresses(Set<Address> publicAddresses) {
this.addresses.replaceValues(Address.Type.PUBLIC, ImmutableSet.copyOf(checkNotNull(publicAddresses,
"publicAddresses")));
return this;
}
/** /**
* @see Server#getAdminPass() * @see Server#getAdminPass()
*/ */
@ -376,13 +321,13 @@ public class Server extends Resource {
@SerializedName("config_drive") @SerializedName("config_drive")
protected final String configDrive; protected final String configDrive;
// TODO: get gson multimap adapter! // TODO: get gson multimap adapter!
protected final Map<Address.Type, Set<Address>> addresses; protected final Map<String, Set<Address>> addresses;
protected final Map<String, String> metadata; protected final Map<String, String> metadata;
protected Server(String id, String name, Set<Link> links, @Nullable String uuid, String tenantId, String userId, protected Server(String id, String name, Set<Link> links, @Nullable String uuid, String tenantId, String userId,
Date updated, Date created, @Nullable String hostId, @Nullable String accessIPv4, Date updated, Date created, @Nullable String hostId, @Nullable String accessIPv4,
@Nullable String accessIPv6, Status status, @Nullable String configDrive, Resource image, Resource flavor, @Nullable String accessIPv6, Status status, @Nullable String configDrive, Resource image, Resource flavor,
String adminPass, @Nullable String keyName, Multimap<Address.Type, Address> addresses, String adminPass, @Nullable String keyName, Multimap<String, Address> addresses,
Map<String, String> metadata) { Map<String, String> metadata) {
super(id, name, links); super(id, name, links);
this.uuid = uuid; // TODO: see what version this came up in this.uuid = uuid; // TODO: see what version this came up in
@ -470,75 +415,11 @@ public class Server extends Resource {
return ImmutableMap.copyOf(Maps.filterValues(this.metadata, Predicates.notNull())); return ImmutableMap.copyOf(Maps.filterValues(this.metadata, Predicates.notNull()));
} }
/**
* @return the private ip addresses assigned to the server
*/
public Set<Address> getPrivateAddresses() {
Collection<Address> privateAddresses = getAddresses().get(Address.Type.PRIVATE);
if (privateAddresses == null) {
return ImmutableSet.<Address> of();
} else {
return ImmutableSet.copyOf(privateAddresses);
}
}
/**
* @return the internet ip addresses assigned to the server
* @since essex
*/
public Set<Address> getInternetAddresses() {
Collection<Address> internetAddrs = getAddresses().get(Address.Type.INTERNET);
if (internetAddrs == null) {
return ImmutableSet.<Address> of();
} else {
return ImmutableSet.copyOf(internetAddrs);
}
}
/**
* @return the public ip addresses assigned to the server
*/
public Set<Address> getPublicAddresses() {
Collection<Address> publicAddrs = getAddresses().get(Address.Type.PUBLIC);
if (publicAddrs == null) {
return ImmutableSet.<Address> of();
} else {
return ImmutableSet.copyOf(publicAddrs);
}
}
/** /**
* @return the ip addresses assigned to the server * @return the ip addresses assigned to the server
*/ */
public Multimap<Type, Address> getAddresses() { public Multimap<String, Address> getAddresses() {
return Multimaps2.fromOldSchool(addresses);
Set<Address> privateAddresses = addresses.get(Address.Type.PRIVATE);
if (privateAddresses != null && privateAddresses.size() > 1) {
return hackNeededForFloatingIpsFixedInEssex(privateAddresses);
} else {
return Multimaps2.fromOldSchool(addresses);
}
}
private Multimap<Type, Address> hackNeededForFloatingIpsFixedInEssex(Set<Address> privateAddresses) {
Set<Address> publicAddresses = addresses.get(Address.Type.PUBLIC);
ImmutableSetMultimap.Builder<Type, Address> returnMapBuilder = new ImmutableSetMultimap.Builder<Type, Address>();
if (publicAddresses != null) {
returnMapBuilder.putAll(Address.Type.PUBLIC, publicAddresses);
}
returnMapBuilder.putAll(Address.Type.PRIVATE, Iterables.filter(privateAddresses, IsPrivateAddress.INSTANCE));
returnMapBuilder.putAll(Address.Type.PUBLIC, Iterables.filter(privateAddresses, Predicates
.not(IsPrivateAddress.INSTANCE)));
return returnMapBuilder.build();
}
private static enum IsPrivateAddress implements Predicate<Address> {
INSTANCE;
public boolean apply(Address in) {
return InetAddresses2.IsPrivateIPAddress.INSTANCE.apply(in.getAddr());
}
} }
/** /**

View File

@ -181,7 +181,7 @@ public class FloatingIPClientLiveTest extends BaseNovaClientLiveTest {
try { try {
Server server = client.getServer(serverId); Server server = client.getServer(serverId);
boolean ipInServerAddresses = false; boolean ipInServerAddresses = false;
Multimap<Address.Type, Address> addresses = server.getAddresses(); Multimap<String, Address> addresses = server.getAddresses();
for (Address address : addresses.values()) { for (Address address : addresses.values()) {
if (address.getAddr().equals(floatingIP)) { if (address.getAddr().equals(floatingIP)) {
ipInServerAddresses = true; ipInServerAddresses = true;

View File

@ -18,22 +18,17 @@
*/ */
package org.jclouds.openstack.nova.v1_1.internal; package org.jclouds.openstack.nova.v1_1.internal;
import java.io.InputStream;
import java.net.URI; import java.net.URI;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import org.jclouds.apis.ApiMetadata; import org.jclouds.apis.ApiMetadata;
import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.io.CopyInputStreamInputSupplierMap;
import org.jclouds.openstack.nova.v1_1.NovaApiMetadata; import org.jclouds.openstack.nova.v1_1.NovaApiMetadata;
import org.jclouds.rest.config.CredentialStoreModule;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableMultimap;
import com.google.common.io.InputSupplier;
import com.google.inject.Module; import com.google.inject.Module;
/** /**
@ -91,12 +86,4 @@ public abstract class BaseNovaComputeServiceContextExpectTest<T> extends BaseNov
return new NovaApiMetadata(); return new NovaApiMetadata();
} }
// isolate tests from eachother, as default credentialStore is static
protected Module credentialStoreModule = new CredentialStoreModule(new CopyInputStreamInputSupplierMap(
new ConcurrentHashMap<String, InputSupplier<InputStream>>()));
@Override
protected Module createModule() {
return credentialStoreModule;
}
} }

View File

@ -0,0 +1,164 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.nova.v1_1.parse;
import java.net.URI;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.json.BaseSetParserTest;
import org.jclouds.json.config.GsonModule;
import org.jclouds.openstack.domain.Link;
import org.jclouds.openstack.domain.Link.Relation;
import org.jclouds.openstack.domain.Resource;
import org.jclouds.openstack.nova.v1_1.config.NovaParserModule;
import org.jclouds.openstack.nova.v1_1.domain.Address;
import org.jclouds.openstack.nova.v1_1.domain.Server;
import org.jclouds.rest.annotations.SelectJson;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "ParseServerDetailsEssexTest")
public class ParseServerDetailsEssexTest extends BaseSetParserTest<Server> {
@Override
public String resource() {
return "/server_list_details_essex.json";
}
@Override
@SelectJson("servers")
@Consumes(MediaType.APPLICATION_JSON)
public Set<Server> expected() {
return ImmutableSet.<Server>of(
Server.builder()
.addresses(ImmutableMultimap.<String, Address>builder()
.putAll("Net TenantA Front-Middle", Address.createV4("172.16.11.5"))
.putAll("Public network", Address.createV4("172.16.1.13"), Address.createV4("10.193.112.119")).build())
.links(
Link.create(
Relation.SELF,
URI.create("http://nova:8774/v1.1/8d10e6646d5d4585937395b04839a353/servers/0c80b392-db30-4736-ae02-4480090f1207")),
Link.create(
Relation.BOOKMARK,
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/servers/0c80b392-db30-4736-ae02-4480090f1207")))
.image(
Resource.builder()
.id("416af940-2d3c-4a7c-977c-a9030685ad5e")
.links(
Link.create(
Relation.BOOKMARK,
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/images/416af940-2d3c-4a7c-977c-a9030685ad5e"))).build())
.flavor(
Resource.builder()
.id("1")
.links(
Link.create(
Relation.BOOKMARK,
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/flavors/1"))).build())
.id("0c80b392-db30-4736-ae02-4480090f1207")
.userId("df13814f6c354d00a8acf66502836323")
.status(Server.Status.ACTIVE)
.updated(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-04-12T11:21:33Z"))
.hostId("03d796ebb52b1b555e5f6d9262f7dbd52b3f7c181e3aa89b34ca5408")
.name("VM proxy")
.created(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-04-12T11:21:23Z"))
.tenantId("8d10e6646d5d4585937395b04839a353").build(),
Server.builder()
.addresses(ImmutableMultimap.<String, Address>builder()
.putAll("Net TenantA Front-Middle", Address.createV4("172.16.11.4"))
.putAll("Net TenantA Middle-Back", Address.createV4("172.16.12.5")).build())
.links(
Link.create(
Relation.SELF,
URI.create("http://nova:8774/v1.1/8d10e6646d5d4585937395b04839a353/servers/b332b5cd-535e-4677-b68e-fc8badc13236")),
Link.create(
Relation.BOOKMARK,
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/servers/b332b5cd-535e-4677-b68e-fc8badc13236")))
.image(
Resource.builder()
.id("416af940-2d3c-4a7c-977c-a9030685ad5e")
.links(
Link.create(
Relation.BOOKMARK,
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/images/416af940-2d3c-4a7c-977c-a9030685ad5e"))).build())
.flavor(
Resource.builder()
.id("1")
.links(
Link.create(
Relation.BOOKMARK,
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/flavors/1"))).build())
.id("b332b5cd-535e-4677-b68e-fc8badc13236")
.userId("df13814f6c354d00a8acf66502836323")
.status(Server.Status.ACTIVE)
.updated(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-04-12T11:18:58Z"))
.hostId("e5bbff80bebacfe1db63951e787b5341427060a602d33abfefb6a1bc")
.name("VM blog")
.created(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-04-12T11:18:48Z"))
.tenantId("8d10e6646d5d4585937395b04839a353").build(),
Server.builder()
.addresses(ImmutableMultimap.<String, Address>builder()
.putAll("Net TenantA Middle-Back", Address.createV4("172.16.12.4")).build())
.links(
Link.create(
Relation.SELF,
URI.create("http://nova:8774/v1.1/8d10e6646d5d4585937395b04839a353/servers/f9d43436-4572-4c9b-9b74-5fa6890a2f21")),
Link.create(
Relation.BOOKMARK,
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/servers/f9d43436-4572-4c9b-9b74-5fa6890a2f21")))
.image(
Resource.builder()
.id("416af940-2d3c-4a7c-977c-a9030685ad5e")
.links(
Link.create(
Relation.BOOKMARK,
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/images/416af940-2d3c-4a7c-977c-a9030685ad5e"))).build())
.flavor(
Resource.builder()
.id("1")
.links(
Link.create(
Relation.BOOKMARK,
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/flavors/1"))).build())
.id("f9d43436-4572-4c9b-9b74-5fa6890a2f21")
.userId("df13814f6c354d00a8acf66502836323")
.status(Server.Status.ACTIVE)
.updated(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-04-12T11:15:09Z"))
.hostId("03d796ebb52b1b555e5f6d9262f7dbd52b3f7c181e3aa89b34ca5408")
.name("VM MySQL")
.created(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-04-12T11:14:56Z"))
.tenantId("8d10e6646d5d4585937395b04839a353").build());
}
protected Injector injector() {
return Guice.createInjector(new NovaParserModule(), new GsonModule());
}
}

View File

@ -37,6 +37,7 @@ import org.jclouds.rest.annotations.SelectJson;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.Injector; import com.google.inject.Injector;
@ -96,9 +97,11 @@ public class ParseServerTest extends BaseItemParserTest<Server> {
.metadata( .metadata(
new ImmutableMap.Builder<String, String>().put("Server Label", "Web Head 1") new ImmutableMap.Builder<String, String>().put("Server Label", "Web Head 1")
.put("Image Version", "2.1").build()) .put("Image Version", "2.1").build())
.publicAddresses(Address.createV4("67.23.10.132"), Address.createV6("::babe:67.23.10.132"), .addresses(ImmutableMultimap.<String, Address>builder()
.putAll("public", Address.createV4("67.23.10.132"), Address.createV6("::babe:67.23.10.132"),
Address.createV4("67.23.10.131"), Address.createV6("::babe:4317:0A83")) Address.createV4("67.23.10.131"), Address.createV6("::babe:4317:0A83"))
.privateAddresses(Address.createV4("10.176.42.16"), Address.createV6("::babe:10.176.42.16")).build(); .putAll("private", Address.createV4("10.176.42.16"), Address.createV6("::babe:10.176.42.16"))
.build()).build();
} }

View File

@ -36,6 +36,7 @@ import org.jclouds.openstack.nova.v1_1.domain.Server.Status;
import org.jclouds.rest.annotations.SelectJson; import org.jclouds.rest.annotations.SelectJson;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.Injector; import com.google.inject.Injector;
@ -90,7 +91,7 @@ public class ParseServerWithInternetAddressesTest extends BaseItemParserTest<Ser
Link.create( Link.create(
Relation.BOOKMARK, Relation.BOOKMARK,
URI.create("https://nova-api.trystack.org:9774/37/servers/1459"))) URI.create("https://nova-api.trystack.org:9774/37/servers/1459")))
.internetAddresses(Address.createV4("8.21.28.47")).build(); .addresses(ImmutableMultimap.of("internet", Address.createV4("8.21.28.47"))).build();
} }

View File

@ -37,6 +37,7 @@ import org.jclouds.rest.annotations.SelectJson;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.Injector; import com.google.inject.Injector;
@ -44,7 +45,7 @@ import com.google.inject.Injector;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit", testName = "ParseCreatedServerTest") @Test(groups = "unit", testName = "ParseCreatedServerTest")
public class PublicIpsInPrivateAddressBlockShouldRerouteToPublicBlockExpectTest extends BaseItemParserTest<Server> { public class PublicIpsInPrivateAddressBlockExpectTest extends BaseItemParserTest<Server> {
@Override @Override
public String resource() { public String resource() {
@ -86,8 +87,8 @@ public class PublicIpsInPrivateAddressBlockShouldRerouteToPublicBlockExpectTest
URI.create("https://az-2.region-a.geo-1.compute.hpcloudsvc.com/37936628937291/flavors/100"))) URI.create("https://az-2.region-a.geo-1.compute.hpcloudsvc.com/37936628937291/flavors/100")))
.build()) .build())
.metadata(ImmutableMap.of("Name", "hpcloud-computes")) .metadata(ImmutableMap.of("Name", "hpcloud-computes"))
.privateAddresses(Address.createV4("10.6.39.189")) .addresses(ImmutableMultimap.<String, Address>builder()
.publicAddresses(Address.createV4("15.185.181.94")) .putAll("private", Address.createV4("10.6.39.189"), Address.createV4("15.185.181.94")).build())
.links( .links(
Link.create(Relation.SELF, URI.create("https://az-2.region-a.geo-1.compute.hpcloudsvc.com/v1.1/37936628937291/servers/59662")), Link.create(Relation.SELF, URI.create("https://az-2.region-a.geo-1.compute.hpcloudsvc.com/v1.1/37936628937291/servers/59662")),
Link.create(Relation.BOOKMARK, URI.create("https://az-2.region-a.geo-1.compute.hpcloudsvc.com/37936628937291/servers/59662"))).build(); Link.create(Relation.BOOKMARK, URI.create("https://az-2.region-a.geo-1.compute.hpcloudsvc.com/37936628937291/servers/59662"))).build();

View File

@ -0,0 +1,152 @@
{
"servers": [{
"OS-EXT-STS:task_state": null,
"addresses": {
"Net TenantA Front-Middle": [{
"version": 4,
"addr": "172.16.11.5"
}],
"Public network": [{
"version": 4,
"addr": "172.16.1.13"
}, {
"version": 4,
"addr": "10.193.112.119"
}]
},
"links": [{
"href": "http://nova:8774/v1.1/8d10e6646d5d4585937395b04839a353/servers/0c80b392-db30-4736-ae02-4480090f1207",
"rel": "self"
}, {
"href": "http://nova:8774/8d10e6646d5d4585937395b04839a353/servers/0c80b392-db30-4736-ae02-4480090f1207",
"rel": "bookmark"
}],
"image": {
"id": "416af940-2d3c-4a7c-977c-a9030685ad5e",
"links": [{
"href": "http://nova:8774/8d10e6646d5d4585937395b04839a353/images/416af940-2d3c-4a7c-977c-a9030685ad5e",
"rel": "bookmark"
}]
},
"OS-EXT-STS:vm_state": "active",
"flavor": {
"id": "1",
"links": [{
"href": "http://nova:8774/8d10e6646d5d4585937395b04839a353/flavors/1",
"rel": "bookmark"
}]
},
"id": "0c80b392-db30-4736-ae02-4480090f1207",
"user_id": "df13814f6c354d00a8acf66502836323",
"OS-DCF:diskConfig": "MANUAL",
"accessIPv4": "",
"accessIPv6": "",
"progress": 0,
"OS-EXT-STS:power_state": 1,
"config_drive": "",
"status": "ACTIVE",
"updated": "2012-04-12T11:21:33Z",
"hostId": "03d796ebb52b1b555e5f6d9262f7dbd52b3f7c181e3aa89b34ca5408",
"key_name": "",
"name": "VM proxy",
"created": "2012-04-12T11:21:23Z",
"tenant_id": "8d10e6646d5d4585937395b04839a353",
"metadata": {}
}, {
"OS-EXT-STS:task_state": null,
"addresses": {
"Net TenantA Front-Middle": [{
"version": 4,
"addr": "172.16.11.4"
}],
"Net TenantA Middle-Back": [{
"version": 4,
"addr": "172.16.12.5"
}]
},
"links": [{
"href": "http://nova:8774/v1.1/8d10e6646d5d4585937395b04839a353/servers/b332b5cd-535e-4677-b68e-fc8badc13236",
"rel": "self"
}, {
"href": "http://nova:8774/8d10e6646d5d4585937395b04839a353/servers/b332b5cd-535e-4677-b68e-fc8badc13236",
"rel": "bookmark"
}],
"image": {
"id": "416af940-2d3c-4a7c-977c-a9030685ad5e",
"links": [{
"href": "http://nova:8774/8d10e6646d5d4585937395b04839a353/images/416af940-2d3c-4a7c-977c-a9030685ad5e",
"rel": "bookmark"
}]
},
"OS-EXT-STS:vm_state": "active",
"flavor": {
"id": "1",
"links": [{
"href": "http://nova:8774/8d10e6646d5d4585937395b04839a353/flavors/1",
"rel": "bookmark"
}]
},
"id": "b332b5cd-535e-4677-b68e-fc8badc13236",
"user_id": "df13814f6c354d00a8acf66502836323",
"OS-DCF:diskConfig": "MANUAL",
"accessIPv4": "",
"accessIPv6": "",
"progress": 0,
"OS-EXT-STS:power_state": 1,
"config_drive": "",
"status": "ACTIVE",
"updated": "2012-04-12T11:18:58Z",
"hostId": "e5bbff80bebacfe1db63951e787b5341427060a602d33abfefb6a1bc",
"key_name": "",
"name": "VM blog",
"created": "2012-04-12T11:18:48Z",
"tenant_id": "8d10e6646d5d4585937395b04839a353",
"metadata": {}
}, {
"OS-EXT-STS:task_state": null,
"addresses": {
"Net TenantA Middle-Back": [{
"version": 4,
"addr": "172.16.12.4"
}]
},
"links": [{
"href": "http://nova:8774/v1.1/8d10e6646d5d4585937395b04839a353/servers/f9d43436-4572-4c9b-9b74-5fa6890a2f21",
"rel": "self"
}, {
"href": "http://nova:8774/8d10e6646d5d4585937395b04839a353/servers/f9d43436-4572-4c9b-9b74-5fa6890a2f21",
"rel": "bookmark"
}],
"image": {
"id": "416af940-2d3c-4a7c-977c-a9030685ad5e",
"links": [{
"href": "http://nova:8774/8d10e6646d5d4585937395b04839a353/images/416af940-2d3c-4a7c-977c-a9030685ad5e",
"rel": "bookmark"
}]
},
"OS-EXT-STS:vm_state": "active",
"flavor": {
"id": "1",
"links": [{
"href": "http://nova:8774/8d10e6646d5d4585937395b04839a353/flavors/1",
"rel": "bookmark"
}]
},
"id": "f9d43436-4572-4c9b-9b74-5fa6890a2f21",
"user_id": "df13814f6c354d00a8acf66502836323",
"OS-DCF:diskConfig": "MANUAL",
"accessIPv4": "",
"accessIPv6": "",
"progress": 0,
"OS-EXT-STS:power_state": 1,
"config_drive": "",
"status": "ACTIVE",
"updated": "2012-04-12T11:15:09Z",
"hostId": "03d796ebb52b1b555e5f6d9262f7dbd52b3f7c181e3aa89b34ca5408",
"key_name": "",
"name": "VM MySQL",
"created": "2012-04-12T11:14:56Z",
"tenant_id": "8d10e6646d5d4585937395b04839a353",
"metadata": {}
}]
}

View File

@ -27,12 +27,12 @@ import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.getLast; import static com.google.common.collect.Iterables.getLast;
import static com.google.common.collect.Iterables.transform; import static com.google.common.collect.Iterables.transform;
import static com.google.common.collect.Maps.transformValues; import static com.google.common.collect.Maps.transformValues;
import static com.google.common.collect.Maps.uniqueIndex;
import static org.jclouds.Constants.PROPERTY_API_VERSION; import static org.jclouds.Constants.PROPERTY_API_VERSION;
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
import static org.jclouds.rest.config.BinderUtils.bindClientAndAsyncClient; import static org.jclouds.rest.config.BinderUtils.bindClientAndAsyncClient;
import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_FENCEMODE; import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_FENCEMODE;
import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_TIMEOUT_TASK_COMPLETED; import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_TIMEOUT_TASK_COMPLETED;
import static org.jclouds.util.Maps2.uniqueIndex;
import java.net.URI; import java.net.URI;
import java.util.Map; import java.util.Map;
@ -118,6 +118,7 @@ import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder; import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.Lists;
import com.google.inject.Injector; import com.google.inject.Injector;
import com.google.inject.Provides; import com.google.inject.Provides;
import com.google.inject.Scopes; import com.google.inject.Scopes;
@ -285,26 +286,27 @@ public class VCloudRestClientModule extends RestClientModule<VCloudClient, VClou
@Singleton @Singleton
public static class OrgCatalogSupplier implements public static class OrgCatalogSupplier implements
Supplier<Map<String, Map<String, org.jclouds.vcloud.domain.Catalog>>> { Supplier<Map<String, Map<String, Catalog>>> {
protected final Supplier<Map<String, Org>> orgSupplier; protected final Supplier<Map<String, Org>> orgSupplier;
protected final Function<Org, Iterable<org.jclouds.vcloud.domain.Catalog>> allCatalogsInOrg; protected final Function<Org, Iterable<Catalog>> allCatalogsInOrg;
@Inject @Inject
protected OrgCatalogSupplier(Supplier<Map<String, Org>> orgSupplier, protected OrgCatalogSupplier(Supplier<Map<String, Org>> orgSupplier,
Function<Org, Iterable<org.jclouds.vcloud.domain.Catalog>> allCatalogsInOrg) { Function<Org, Iterable<Catalog>> allCatalogsInOrg) {
this.orgSupplier = orgSupplier; this.orgSupplier = orgSupplier;
this.allCatalogsInOrg = allCatalogsInOrg; this.allCatalogsInOrg = allCatalogsInOrg;
} }
@Override @Override
public Map<String, Map<String, org.jclouds.vcloud.domain.Catalog>> get() { public Map<String, Map<String, Catalog>> get() {
return transformValues( return transformValues(
transformValues(orgSupplier.get(), allCatalogsInOrg), transformValues(orgSupplier.get(), allCatalogsInOrg),
new Function<Iterable<org.jclouds.vcloud.domain.Catalog>, Map<String, org.jclouds.vcloud.domain.Catalog>>() { new Function<Iterable<? extends Catalog>,
Map<String, Catalog>>() {
@Override @Override
public Map<String, org.jclouds.vcloud.domain.Catalog> apply( public Map<String, Catalog> apply(
Iterable<org.jclouds.vcloud.domain.Catalog> from) { Iterable<? extends Catalog> from) {
return uniqueIndex(from, name); return uniqueIndex(from, name);
} }
@ -336,37 +338,37 @@ public class VCloudRestClientModule extends RestClientModule<VCloudClient, VClou
@Provides @Provides
@Singleton @Singleton
protected Supplier<Map<URI, org.jclouds.vcloud.domain.VDC>> provideURIToVDC( protected Supplier<Map<URI, VDC>> provideURIToVDC(
@Named(PROPERTY_SESSION_INTERVAL) long seconds, AtomicReference<AuthorizationException> authException, @Named(PROPERTY_SESSION_INTERVAL) long seconds, AtomicReference<AuthorizationException> authException,
URItoVDC supplier) { URItoVDC supplier) {
return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<URI, org.jclouds.vcloud.domain.VDC>>( return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<URI, VDC>>(
authException, seconds, supplier); authException, seconds, supplier);
} }
@Singleton @Singleton
public static class URItoVDC implements Supplier<Map<URI, org.jclouds.vcloud.domain.VDC>> { public static class URItoVDC implements Supplier<Map<URI, VDC>> {
private final Supplier<Map<String, Map<String, org.jclouds.vcloud.domain.VDC>>> orgVDCMap; private final Supplier<Map<String, Map<String, VDC>>> orgVDCMap;
@Inject @Inject
URItoVDC(Supplier<Map<String, Map<String, org.jclouds.vcloud.domain.VDC>>> orgVDCMap) { URItoVDC(Supplier<Map<String, Map<String, VDC>>> orgVDCMap) {
this.orgVDCMap = orgVDCMap; this.orgVDCMap = orgVDCMap;
} }
@Override @Override
public Map<URI, org.jclouds.vcloud.domain.VDC> get() { public Map<URI, VDC> get() {
return uniqueIndex(concat(transform(orgVDCMap.get().values(), return uniqueIndex(concat(transform(orgVDCMap.get().values(),
new Function<Map<String, org.jclouds.vcloud.domain.VDC>, Iterable<org.jclouds.vcloud.domain.VDC>>() { new Function<Map<String, VDC>, Iterable<VDC>>() {
@Override @Override
public Iterable<org.jclouds.vcloud.domain.VDC> apply( public Iterable<VDC> apply(
Map<String, org.jclouds.vcloud.domain.VDC> from) { Map<String, VDC> from) {
return from.values(); return from.values();
} }
})), new Function<org.jclouds.vcloud.domain.VDC, URI>() { })), new Function<VDC, URI>() {
@Override @Override
public URI apply(org.jclouds.vcloud.domain.VDC from) { public URI apply(VDC from) {
return from.getHref(); return from.getHref();
} }
@ -445,43 +447,43 @@ public class VCloudRestClientModule extends RestClientModule<VCloudClient, VClou
@Provides @Provides
@Singleton @Singleton
protected Supplier<Map<String, Map<String, org.jclouds.vcloud.domain.Catalog>>> provideOrgCatalogItemMapSupplierCache( protected Supplier<Map<String, Map<String, Catalog>>> provideOrgCatalogItemMapSupplierCache(
@Named(PROPERTY_SESSION_INTERVAL) long seconds, AtomicReference<AuthorizationException> authException, @Named(PROPERTY_SESSION_INTERVAL) long seconds, AtomicReference<AuthorizationException> authException,
OrgCatalogSupplier supplier) { OrgCatalogSupplier supplier) {
return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<String, Map<String, org.jclouds.vcloud.domain.Catalog>>>( return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<String, Map<String, Catalog>>>(
authException, seconds, supplier); authException, seconds, supplier);
} }
@Provides @Provides
@Singleton @Singleton
protected Supplier<Map<String, Map<String, org.jclouds.vcloud.domain.VDC>>> provideOrgVDCSupplierCache( protected Supplier<Map<String, Map<String, VDC>>> provideOrgVDCSupplierCache(
@Named(PROPERTY_SESSION_INTERVAL) long seconds, AtomicReference<AuthorizationException> authException, @Named(PROPERTY_SESSION_INTERVAL) long seconds, AtomicReference<AuthorizationException> authException,
OrgVDCSupplier supplier) { OrgVDCSupplier supplier) {
return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<String, Map<String, org.jclouds.vcloud.domain.VDC>>>( return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<String, Map<String, VDC>>>(
authException, seconds, supplier); authException, seconds, supplier);
} }
@Singleton @Singleton
public static class OrgVDCSupplier implements Supplier<Map<String, Map<String, org.jclouds.vcloud.domain.VDC>>> { public static class OrgVDCSupplier implements Supplier<Map<String, Map<String, VDC>>> {
protected final Supplier<Map<String, Org>> orgSupplier; protected final Supplier<Map<String, Org>> orgSupplier;
private final Function<Org, Iterable<org.jclouds.vcloud.domain.VDC>> allVDCsInOrg; private final Function<Org, Iterable<VDC>> allVDCsInOrg;
@Inject @Inject
protected OrgVDCSupplier(Supplier<Map<String, Org>> orgSupplier, protected OrgVDCSupplier(Supplier<Map<String, Org>> orgSupplier,
Function<Org, Iterable<org.jclouds.vcloud.domain.VDC>> allVDCsInOrg) { Function<Org, Iterable<VDC>> allVDCsInOrg) {
this.orgSupplier = orgSupplier; this.orgSupplier = orgSupplier;
this.allVDCsInOrg = allVDCsInOrg; this.allVDCsInOrg = allVDCsInOrg;
} }
@Override @Override
public Map<String, Map<String, org.jclouds.vcloud.domain.VDC>> get() { public Map<String, Map<String, VDC>> get() {
return transformValues(transformValues(orgSupplier.get(), allVDCsInOrg), return transformValues(transformValues(orgSupplier.get(), allVDCsInOrg),
new Function<Iterable<org.jclouds.vcloud.domain.VDC>, Map<String, org.jclouds.vcloud.domain.VDC>>() { new Function<Iterable<? extends VDC>, Map<String, VDC>>() {
@Override @Override
public Map<String, org.jclouds.vcloud.domain.VDC> apply( public Map<String, VDC> apply(
Iterable<org.jclouds.vcloud.domain.VDC> from) { Iterable<? extends VDC> from) {
return uniqueIndex(from, name); return uniqueIndex(Lists.newArrayList(from), name);
} }
}); });
@ -490,33 +492,33 @@ public class VCloudRestClientModule extends RestClientModule<VCloudClient, VClou
@Singleton @Singleton
public static class OrgCatalogItemSupplier implements public static class OrgCatalogItemSupplier implements
Supplier<Map<String, Map<String, Map<String, org.jclouds.vcloud.domain.CatalogItem>>>> { Supplier<Map<String, Map<String, Map<String, CatalogItem>>>> {
protected final Supplier<Map<String, Map<String, org.jclouds.vcloud.domain.Catalog>>> catalogSupplier; protected final Supplier<Map<String, Map<String, Catalog>>> catalogSupplier;
protected final Function<org.jclouds.vcloud.domain.Catalog, Iterable<CatalogItem>> allCatalogItemsInCatalog; protected final Function<Catalog, Iterable<CatalogItem>> allCatalogItemsInCatalog;
@Inject @Inject
protected OrgCatalogItemSupplier( protected OrgCatalogItemSupplier(
Supplier<Map<String, Map<String, org.jclouds.vcloud.domain.Catalog>>> catalogSupplier, Supplier<Map<String, Map<String, Catalog>>> catalogSupplier,
Function<org.jclouds.vcloud.domain.Catalog, Iterable<CatalogItem>> allCatalogItemsInCatalog) { Function<Catalog, Iterable<CatalogItem>> allCatalogItemsInCatalog) {
this.catalogSupplier = catalogSupplier; this.catalogSupplier = catalogSupplier;
this.allCatalogItemsInCatalog = allCatalogItemsInCatalog; this.allCatalogItemsInCatalog = allCatalogItemsInCatalog;
} }
@Override @Override
public Map<String, Map<String, Map<String, org.jclouds.vcloud.domain.CatalogItem>>> get() { public Map<String, Map<String, Map<String, CatalogItem>>> get() {
return transformValues( return transformValues(
catalogSupplier.get(), catalogSupplier.get(),
new Function<Map<String, org.jclouds.vcloud.domain.Catalog>, Map<String, Map<String, org.jclouds.vcloud.domain.CatalogItem>>>() { new Function<Map<String, Catalog>, Map<String, Map<String, CatalogItem>>>() {
@Override @Override
public Map<String, Map<String, CatalogItem>> apply( public Map<String, Map<String, CatalogItem>> apply(
Map<String, org.jclouds.vcloud.domain.Catalog> from) { Map<String, Catalog> from) {
return transformValues( return transformValues(
from, from,
new Function<org.jclouds.vcloud.domain.Catalog, Map<String, org.jclouds.vcloud.domain.CatalogItem>>() { new Function<Catalog, Map<String, CatalogItem>>() {
@Override @Override
public Map<String, CatalogItem> apply(org.jclouds.vcloud.domain.Catalog from) { public Map<String, CatalogItem> apply(Catalog from) {
return uniqueIndex(filter(allCatalogItemsInCatalog.apply(from), notNull()), name); return uniqueIndex(filter(allCatalogItemsInCatalog.apply(from), notNull()), name);
} }
}); });
@ -528,10 +530,10 @@ public class VCloudRestClientModule extends RestClientModule<VCloudClient, VClou
@Provides @Provides
@Singleton @Singleton
protected Supplier<Map<String, Map<String, Map<String, org.jclouds.vcloud.domain.CatalogItem>>>> provideOrgCatalogItemSupplierCache( protected Supplier<Map<String, Map<String, Map<String, CatalogItem>>>> provideOrgCatalogItemSupplierCache(
@Named(PROPERTY_SESSION_INTERVAL) long seconds, AtomicReference<AuthorizationException> authException, @Named(PROPERTY_SESSION_INTERVAL) long seconds, AtomicReference<AuthorizationException> authException,
OrgCatalogItemSupplier supplier) { OrgCatalogItemSupplier supplier) {
return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<String, Map<String, Map<String, org.jclouds.vcloud.domain.CatalogItem>>>>( return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<String, Map<String, Map<String, CatalogItem>>>>(
authException, seconds, supplier); authException, seconds, supplier);
} }

View File

@ -31,6 +31,7 @@ import javax.inject.Singleton;
import org.jclouds.Constants; import org.jclouds.Constants;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.util.Iterables2;
import org.jclouds.vcloud.VCloudAsyncClient; import org.jclouds.vcloud.VCloudAsyncClient;
import org.jclouds.vcloud.VCloudMediaType; import org.jclouds.vcloud.VCloudMediaType;
import org.jclouds.vcloud.domain.Catalog; import org.jclouds.vcloud.domain.Catalog;
@ -60,14 +61,14 @@ public class AllCatalogItemsInCatalog implements Function<Catalog, Iterable<Cata
@Override @Override
public Iterable<CatalogItem> apply(Catalog from) { public Iterable<CatalogItem> apply(Catalog from) {
Iterable<CatalogItem> catalogItems = transformParallel(filter(from.values(), new Predicate<ReferenceType>() { Iterable<? extends CatalogItem> catalogItems = transformParallel(filter(from.values(), new Predicate<ReferenceType>() {
@Override @Override
public boolean apply(ReferenceType input) { public boolean apply(ReferenceType input) {
return input.getType().equals(VCloudMediaType.CATALOGITEM_XML); return input.getType().equals(VCloudMediaType.CATALOGITEM_XML);
} }
}), new Function<ReferenceType, Future<CatalogItem>>() { }), new Function<ReferenceType, Future<? extends CatalogItem>>() {
@Override @Override
public Future<CatalogItem> apply(ReferenceType from) { public Future<CatalogItem> apply(ReferenceType from) {
@ -75,7 +76,7 @@ public class AllCatalogItemsInCatalog implements Function<Catalog, Iterable<Cata
} }
}, executor, null, logger, "catalogItems in " + from.getHref()); }, executor, null, logger, "catalogItems in " + from.getHref());
return catalogItems; return Iterables2.concreteCopy(catalogItems);
} }
} }

View File

@ -48,9 +48,9 @@ public class AllCatalogItemsInOrg implements Function<Org, Iterable<CatalogItem>
@Override @Override
public Iterable<CatalogItem> apply(Org from) { public Iterable<CatalogItem> apply(Org from) {
return Iterables.concat(Iterables.transform(allCatalogsInOrg.apply(from), return Iterables.concat(Iterables.transform(allCatalogsInOrg.apply(from),
new Function<Catalog, Iterable<CatalogItem>>() { new Function<Catalog, Iterable<? extends CatalogItem>>() {
@Override @Override
public Iterable<CatalogItem> apply(Catalog from) { public Iterable<? extends CatalogItem> apply(Catalog from) {
return allCatalogItemsInCatalog.apply(from); return allCatalogItemsInCatalog.apply(from);
} }

View File

@ -30,6 +30,7 @@ import javax.inject.Singleton;
import org.jclouds.Constants; import org.jclouds.Constants;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.util.Iterables2;
import org.jclouds.vcloud.VCloudAsyncClient; import org.jclouds.vcloud.VCloudAsyncClient;
import org.jclouds.vcloud.domain.Catalog; import org.jclouds.vcloud.domain.Catalog;
import org.jclouds.vcloud.domain.Org; import org.jclouds.vcloud.domain.Org;
@ -56,14 +57,14 @@ public class AllCatalogsInOrg implements Function<Org, Iterable<Catalog>> {
@Override @Override
public Iterable<Catalog> apply(final Org org) { public Iterable<Catalog> apply(final Org org) {
Iterable<Catalog> catalogs = transformParallel(org.getCatalogs().values(), Iterable<? extends Catalog> catalogs = transformParallel(org.getCatalogs().values(),
new Function<ReferenceType, Future<Catalog>>() { new Function<ReferenceType, Future<? extends Catalog>>() {
@Override @Override
public Future<Catalog> apply(ReferenceType from) { public Future<Catalog> apply(ReferenceType from) {
return (Future<Catalog>) aclient.getCatalogClient().getCatalog(from.getHref()); return aclient.getCatalogClient().getCatalog(from.getHref());
} }
}, executor, null, logger, "catalogs in " + org.getName()); }, executor, null, logger, "catalogs in " + org.getName());
return catalogs; return Iterables2.concreteCopy(catalogs);
} }
} }

View File

@ -30,6 +30,7 @@ import javax.inject.Singleton;
import org.jclouds.Constants; import org.jclouds.Constants;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.util.Iterables2;
import org.jclouds.vcloud.VCloudAsyncClient; import org.jclouds.vcloud.VCloudAsyncClient;
import org.jclouds.vcloud.domain.Org; import org.jclouds.vcloud.domain.Org;
import org.jclouds.vcloud.domain.ReferenceType; import org.jclouds.vcloud.domain.ReferenceType;
@ -41,7 +42,7 @@ import com.google.common.base.Function;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Singleton @Singleton
public class AllVDCsInOrg implements Function<Org, Iterable<org.jclouds.vcloud.domain.VDC>> { public class AllVDCsInOrg implements Function<Org, Iterable<VDC>> {
@Resource @Resource
public Logger logger = Logger.NULL; public Logger logger = Logger.NULL;
@ -58,14 +59,14 @@ public class AllVDCsInOrg implements Function<Org, Iterable<org.jclouds.vcloud.d
public Iterable<VDC> apply(final Org org) { public Iterable<VDC> apply(final Org org) {
Iterable<VDC> catalogItems = transformParallel(org.getVDCs().values(), Iterable<VDC> catalogItems = transformParallel(org.getVDCs().values(),
new Function<ReferenceType, Future<org.jclouds.vcloud.domain.VDC>>() { new Function<ReferenceType, Future<? extends VDC>>() {
@Override @Override
public Future<VDC> apply(ReferenceType from) { public Future<? extends VDC> apply(ReferenceType from) {
return aclient.getVDCClient().getVDC(from.getHref()); return aclient.getVDCClient().getVDC(from.getHref());
} }
}, executor, null, logger, "vdcs in org " + org.getName()); }, executor, null, logger, "vdcs in org " + org.getName());
return catalogItems; return Iterables2.concreteCopy(catalogItems);
} }
} }

View File

@ -35,6 +35,7 @@ import org.jclouds.Constants;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.domain.LocationScope; import org.jclouds.domain.LocationScope;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.util.Iterables2;
import org.jclouds.vcloud.VCloudAsyncClient; import org.jclouds.vcloud.VCloudAsyncClient;
import org.jclouds.vcloud.domain.Org; import org.jclouds.vcloud.domain.Org;
@ -46,7 +47,7 @@ import com.google.common.collect.Sets;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Singleton @Singleton
public class OrgsForLocations implements Function<Iterable<Location>, Iterable< Org>> { public class OrgsForLocations implements Function<Iterable<Location>, Iterable<Org>> {
@Resource @Resource
public Logger logger = Logger.NULL; public Logger logger = Logger.NULL;
private final VCloudAsyncClient aclient; private final VCloudAsyncClient aclient;
@ -65,7 +66,7 @@ public class OrgsForLocations implements Function<Iterable<Location>, Iterable<
@Override @Override
public Iterable<Org> apply(Iterable<Location> from) { public Iterable<Org> apply(Iterable<Location> from) {
return transformParallel(Sets.newLinkedHashSet(transform(filter(from, new Predicate<Location>() { return Iterables2.concreteCopy(transformParallel(Sets.newLinkedHashSet(transform(filter(from, new Predicate<Location>() {
@Override @Override
public boolean apply(Location input) { public boolean apply(Location input) {
@ -79,14 +80,14 @@ public class OrgsForLocations implements Function<Iterable<Location>, Iterable<
return URI.create(from.getParent().getId()); return URI.create(from.getParent().getId());
} }
})), new Function<URI, Future<Org>>() { })), new Function<URI, Future<? extends Org>>() {
@Override @Override
public Future<Org> apply(URI from) { public Future<Org> apply(URI from) {
return aclient.getOrgClient().getOrg(from); return aclient.getOrgClient().getOrg(from);
} }
}, executor, null, logger, "organizations for uris"); }, executor, null, logger, "organizations for uris"));
} }
} }

View File

@ -30,6 +30,7 @@ import javax.inject.Singleton;
import org.jclouds.Constants; import org.jclouds.Constants;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.util.Iterables2;
import org.jclouds.vcloud.VCloudAsyncClient; import org.jclouds.vcloud.VCloudAsyncClient;
import org.jclouds.vcloud.domain.Org; import org.jclouds.vcloud.domain.Org;
@ -53,14 +54,14 @@ public class OrgsForNames implements Function<Iterable<String>, Iterable<Org>> {
@Override @Override
public Iterable<Org> apply(Iterable<String> from) { public Iterable<Org> apply(Iterable<String> from) {
return transformParallel(from, new Function<String, Future<Org>>() { return Iterables2.concreteCopy(transformParallel(from, new Function<String, Future<? extends Org>>() {
@Override @Override
public Future<Org> apply(String from) { public Future<Org> apply(String from) {
return aclient.getOrgClient().findOrgNamed(from); return aclient.getOrgClient().findOrgNamed(from);
} }
}, executor, null, logger, "organizations for names"); }, executor, null, logger, "organizations for names"));
} }
} }

View File

@ -36,6 +36,7 @@ import org.jclouds.concurrent.ExceptionParsingListenableFuture;
import org.jclouds.concurrent.Futures; import org.jclouds.concurrent.Futures;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.AuthorizationException;
import org.jclouds.util.Iterables2;
import org.jclouds.vcloud.VCloudAsyncClient; import org.jclouds.vcloud.VCloudAsyncClient;
import org.jclouds.vcloud.VCloudMediaType; import org.jclouds.vcloud.VCloudMediaType;
import org.jclouds.vcloud.domain.CatalogItem; import org.jclouds.vcloud.domain.CatalogItem;
@ -78,14 +79,14 @@ public class VAppTemplatesForCatalogItems implements Function<Iterable<CatalogIt
@Override @Override
public Iterable<VAppTemplate> apply(Iterable<CatalogItem> from) { public Iterable<VAppTemplate> apply(Iterable<CatalogItem> from) {
return transformParallel(filter(from, new Predicate<CatalogItem>() { return Iterables2.concreteCopy(transformParallel(filter(from, new Predicate<CatalogItem>() {
@Override @Override
public boolean apply(CatalogItem input) { public boolean apply(CatalogItem input) {
return input.getEntity().getType().equals(VCloudMediaType.VAPPTEMPLATE_XML); return input.getEntity().getType().equals(VCloudMediaType.VAPPTEMPLATE_XML);
} }
}), new Function<CatalogItem, Future<VAppTemplate>>() { }), new Function<CatalogItem, Future<? extends VAppTemplate>>() {
@Override @Override
public Future<VAppTemplate> apply(CatalogItem from) { public Future<VAppTemplate> apply(CatalogItem from) {
@ -94,7 +95,7 @@ public class VAppTemplatesForCatalogItems implements Function<Iterable<CatalogIt
returnNullOnAuthorizationException); returnNullOnAuthorizationException);
} }
}, executor, null, logger, "vappTemplates in"); }, executor, null, logger, "vappTemplates in"));
} }
} }

View File

@ -25,6 +25,7 @@ import static com.google.common.collect.Iterables.filter;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.util.Iterables2;
import org.jclouds.vcloud.domain.CatalogItem; import org.jclouds.vcloud.domain.CatalogItem;
import org.jclouds.vcloud.domain.Org; import org.jclouds.vcloud.domain.Org;
import org.jclouds.vcloud.domain.Status; import org.jclouds.vcloud.domain.Status;
@ -53,7 +54,7 @@ public class VAppTemplatesInOrg implements Function<Org, Iterable<VAppTemplate>>
@Override @Override
public Iterable<VAppTemplate> apply(Org from) { public Iterable<VAppTemplate> apply(Org from) {
Iterable<CatalogItem> catalogs = allCatalogItemsInOrg.apply(from); Iterable<CatalogItem> catalogs = allCatalogItemsInOrg.apply(from);
Iterable<VAppTemplate> vAppTemplates = vAppTemplatesForCatalogItems.apply(catalogs); Iterable<VAppTemplate> vAppTemplates = Iterables2.concreteCopy(vAppTemplatesForCatalogItems.apply(catalogs));
return filter(vAppTemplates, and(notNull(), new Predicate<VAppTemplate>(){ return filter(vAppTemplates, and(notNull(), new Predicate<VAppTemplate>(){
//TODO: test this //TODO: test this

View File

@ -69,8 +69,8 @@ public class VAppTemplatesSupplier implements Supplier<Set<VAppTemplate>> {
@Override @Override
public Set<VAppTemplate> get() { public Set<VAppTemplate> get() {
Iterable<Org> orgs = checkNotNull(orgMap.get().values(), "orgs"); Iterable<Org> orgs = checkNotNull(orgMap.get().values(), "orgs");
Iterable<Iterable<VAppTemplate>> images = transformParallel(orgs, Iterable<? extends Iterable<VAppTemplate>> images = transformParallel(orgs,
new Function<Org, Future<Iterable<VAppTemplate>>>() { new Function<Org, Future<? extends Iterable<VAppTemplate>>>() {
@Override @Override
public Future<Iterable<VAppTemplate>> apply(final Org from) { public Future<Iterable<VAppTemplate>> apply(final Org from) {

View File

@ -42,6 +42,7 @@ import org.jclouds.vcloud.VCloudMediaType;
import org.jclouds.vcloud.VCloudVersionsClient; import org.jclouds.vcloud.VCloudVersionsClient;
import org.jclouds.vcloud.config.VCloudRestClientModule; import org.jclouds.vcloud.config.VCloudRestClientModule;
import org.jclouds.vcloud.domain.AllocationModel; import org.jclouds.vcloud.domain.AllocationModel;
import org.jclouds.vcloud.domain.CatalogItem;
import org.jclouds.vcloud.domain.Org; import org.jclouds.vcloud.domain.Org;
import org.jclouds.vcloud.domain.ReferenceType; import org.jclouds.vcloud.domain.ReferenceType;
import org.jclouds.vcloud.domain.Task; import org.jclouds.vcloud.domain.Task;
@ -253,11 +254,11 @@ public abstract class BaseVCloudAsyncClientTest<T> extends BaseAsyncClientTest<T
} }
@Override @Override
public Map<String, Map<String, Map<String, org.jclouds.vcloud.domain.CatalogItem>>> get() { public Map<String, Map<String, Map<String, CatalogItem>>> get() {
return ImmutableMap.<String, Map<String, Map<String, org.jclouds.vcloud.domain.CatalogItem>>> of( return ImmutableMap.<String, Map<String, Map<String, CatalogItem>>> of(
ORG_REF.getName(), ImmutableMap ORG_REF.getName(), ImmutableMap
.<String, Map<String, org.jclouds.vcloud.domain.CatalogItem>> of(CATALOG_REF .<String, Map<String, CatalogItem>> of(CATALOG_REF
.getName(), ImmutableMap.<String, org.jclouds.vcloud.domain.CatalogItem> of( .getName(), ImmutableMap.<String, CatalogItem> of(
"template", "template",
new CatalogItemImpl("template", URI new CatalogItemImpl("template", URI
.create("https://vcenterprise.bluelock.com/api/v1.0/catalogItem/2"), "description", .create("https://vcenterprise.bluelock.com/api/v1.0/catalogItem/2"), "description",

View File

@ -42,6 +42,7 @@ import org.jclouds.logging.Logger;
import com.google.common.base.Function; import com.google.common.base.Function;
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.common.collect.Lists;
import com.google.inject.Inject; import com.google.inject.Inject;
/** /**
@ -83,21 +84,21 @@ public class FetchBlobMetadata implements Function<PageSet<? extends StorageMeta
public PageSet<? extends StorageMetadata> apply(PageSet<? extends StorageMetadata> in) { public PageSet<? extends StorageMetadata> apply(PageSet<? extends StorageMetadata> in) {
checkState(container != null, "container name should be initialized"); checkState(container != null, "container name should be initialized");
Iterable<BlobMetadata> returnv = transformParallel(Iterables.filter(in, new Predicate<StorageMetadata>() { Iterable<BlobMetadata> returnv = Lists.newArrayList(transformParallel(Iterables.filter(in, new Predicate<StorageMetadata>() {
@Override @Override
public boolean apply(StorageMetadata input) { public boolean apply(StorageMetadata input) {
return input.getType() == StorageType.BLOB; return input.getType() == StorageType.BLOB;
} }
}), new Function<StorageMetadata, Future<BlobMetadata>>() { }), new Function<StorageMetadata, Future<? extends BlobMetadata>>() {
@Override @Override
public Future<BlobMetadata> apply(StorageMetadata from) { public Future<BlobMetadata> apply(StorageMetadata from) {
return ablobstore.blobMetadata(container, from.getName()); return ablobstore.blobMetadata(container, from.getName());
} }
}, userExecutor, maxTime, logger, String.format("getting metadata from containerName: %s", container)); }, userExecutor, maxTime, logger, String.format("getting metadata from containerName: %s", container)));
return new PageSetImpl<BlobMetadata>(returnv, in.getNextMarker()); return new PageSetImpl<BlobMetadata>(returnv, in.getNextMarker());
} }

View File

@ -75,7 +75,7 @@ public class GetAllBlobsInListAndRetryOnFailure implements GetBlobsInListStrateg
public Iterable<Blob> execute(final String container, ListContainerOptions options) { public Iterable<Blob> execute(final String container, ListContainerOptions options) {
Iterable<? extends BlobMetadata> list = getAllBlobMetadata.execute(container, options); Iterable<? extends BlobMetadata> list = getAllBlobMetadata.execute(container, options);
return transformParallel(list, new Function<BlobMetadata, Future<Blob>>() { return transformParallel(list, new Function<BlobMetadata, Future<? extends Blob>>() {
@Override @Override
public Future<Blob> apply(BlobMetadata from) { public Future<Blob> apply(BlobMetadata from) {

View File

@ -31,6 +31,7 @@ import javax.inject.Singleton;
import org.jclouds.Constants; import org.jclouds.Constants;
import org.jclouds.collect.Memoized; import org.jclouds.collect.Memoized;
import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.ImageExtension;
import org.jclouds.compute.callables.RunScriptOnNode; import org.jclouds.compute.callables.RunScriptOnNode;
import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
@ -54,6 +55,7 @@ import org.jclouds.scriptbuilder.functions.InitAdminAccess;
import org.jclouds.trmk.vcloud_0_8.compute.options.TerremarkVCloudTemplateOptions; import org.jclouds.trmk.vcloud_0_8.compute.options.TerremarkVCloudTemplateOptions;
import org.jclouds.trmk.vcloud_0_8.compute.strategy.CleanupOrphanKeys; import org.jclouds.trmk.vcloud_0_8.compute.strategy.CleanupOrphanKeys;
import com.google.common.base.Optional;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
@ -78,12 +80,13 @@ public class TerremarkVCloudComputeService extends BaseComputeService {
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory,
RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess, RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
PersistNodeCredentials persistNodeCredentials, Timeouts timeouts, PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, CleanupOrphanKeys cleanupOrphanKeys) { @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, CleanupOrphanKeys cleanupOrphanKeys,
Optional<ImageExtension> imageExtension) {
super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy, super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, resumeNodeStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, resumeNodeStrategy,
suspendNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated, suspendNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials, nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials,
timeouts, executor); timeouts, executor, imageExtension);
this.cleanupOrphanKeys = cleanupOrphanKeys; this.cleanupOrphanKeys = cleanupOrphanKeys;
} }

View File

@ -69,8 +69,8 @@ public class VCloudHardwareSupplier implements Supplier<Set<? extends Hardware>>
@Override @Override
public Set<? extends Hardware> get() { public Set<? extends Hardware> get() {
Iterable<? extends Org> orgs = checkNotNull(orgMap.get().values(), "orgs"); Iterable<? extends Org> orgs = checkNotNull(orgMap.get().values(), "orgs");
Iterable<Iterable<? extends Hardware>> sizes = transformParallel(orgs, Iterable<? extends Iterable<? extends Hardware>> sizes = transformParallel(orgs,
new Function<Org, Future<Iterable<? extends Hardware>>>() { new Function<Org, Future<? extends Iterable<? extends Hardware>>>() {
@Override @Override
public Future<Iterable<? extends Hardware>> apply(final Org from) { public Future<Iterable<? extends Hardware>> apply(final Org from) {

View File

@ -69,8 +69,8 @@ public class VCloudImageSupplier implements Supplier<Set<? extends Image>> {
@Override @Override
public Set<? extends Image> get() { public Set<? extends Image> get() {
Iterable<? extends Org> orgs = checkNotNull(orgMap.get().values(), "orgs"); Iterable<? extends Org> orgs = checkNotNull(orgMap.get().values(), "orgs");
Iterable<Iterable<? extends Image>> images = transformParallel(orgs, Iterable<? extends Iterable<? extends Image>> images = transformParallel(orgs,
new Function<Org, Future<Iterable<? extends Image>>>() { new Function<Org, Future<? extends Iterable<? extends Image>>>() {
@Override @Override
public Future<Iterable<? extends Image>> apply(final Org from) { public Future<Iterable<? extends Image>> apply(final Org from) {

View File

@ -61,14 +61,14 @@ public class AllCatalogItemsInCatalog implements Function<Catalog, Iterable<? ex
@Override @Override
public Iterable<? extends CatalogItem> apply(Catalog from) { public Iterable<? extends CatalogItem> apply(Catalog from) {
Iterable<CatalogItem> catalogItems = transformParallel(filter(from.values(), new Predicate<ReferenceType>() { Iterable<? extends CatalogItem> catalogItems = transformParallel(filter(from.values(), new Predicate<ReferenceType>() {
@Override @Override
public boolean apply(ReferenceType input) { public boolean apply(ReferenceType input) {
return input.getType().equals(TerremarkVCloudMediaType.CATALOGITEM_XML); return input.getType().equals(TerremarkVCloudMediaType.CATALOGITEM_XML);
} }
}), new Function<ReferenceType, Future<CatalogItem>>() { }), new Function<ReferenceType, Future<? extends CatalogItem>>() {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override

View File

@ -56,8 +56,8 @@ public class AllCatalogsInOrg implements Function<Org, Iterable<? extends Catalo
@Override @Override
public Iterable<? extends Catalog> apply(final Org org) { public Iterable<? extends Catalog> apply(final Org org) {
Iterable<Catalog> catalogs = transformParallel(org.getCatalogs().values(), Iterable<? extends Catalog> catalogs = transformParallel(org.getCatalogs().values(),
new Function<ReferenceType, Future<Catalog>>() { new Function<ReferenceType, Future<? extends Catalog>>() {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public Future<Catalog> apply(ReferenceType from) { public Future<Catalog> apply(ReferenceType from) {

View File

@ -56,12 +56,11 @@ public class AllVDCsInOrg implements Function<Org, Iterable<? extends org.jcloud
@Override @Override
public Iterable<? extends org.jclouds.trmk.vcloud_0_8.domain.VDC> apply(final Org org) { public Iterable<? extends org.jclouds.trmk.vcloud_0_8.domain.VDC> apply(final Org org) {
Iterable<org.jclouds.trmk.vcloud_0_8.domain.VDC> catalogItems = transformParallel(org.getVDCs().values(), Iterable<? extends org.jclouds.trmk.vcloud_0_8.domain.VDC> catalogItems = transformParallel(org.getVDCs().values(),
new Function<ReferenceType, Future<org.jclouds.trmk.vcloud_0_8.domain.VDC>>() { new Function<ReferenceType, Future<? extends org.jclouds.trmk.vcloud_0_8.domain.VDC>>() {
@SuppressWarnings("unchecked")
@Override @Override
public Future<org.jclouds.trmk.vcloud_0_8.domain.VDC> apply(ReferenceType from) { public Future<? extends org.jclouds.trmk.vcloud_0_8.domain.VDC> apply(ReferenceType from) {
return (Future<org.jclouds.trmk.vcloud_0_8.domain.VDC>) aclient.getVDC(from.getHref()); return aclient.getVDC(from.getHref());
} }
}, executor, null, logger, "vdcs in org " + org.getName()); }, executor, null, logger, "vdcs in org " + org.getName());

View File

@ -79,12 +79,10 @@ public class OrgsForLocations implements Function<Iterable<? extends Location>,
return URI.create(from.getParent().getId()); return URI.create(from.getParent().getId());
} }
})), new Function<URI, Future<Org>>() { })), new Function<URI, Future<? extends Org>>() {
@SuppressWarnings("unchecked")
@Override @Override
public Future<Org> apply(URI from) { public Future<? extends Org> apply(URI from) {
return (Future<Org>) aclient.getOrg(from); return aclient.getOrg(from);
} }
}, executor, null, logger, "organizations for uris"); }, executor, null, logger, "organizations for uris");

View File

@ -53,12 +53,10 @@ public class OrgsForNames implements Function<Iterable<String>, Iterable<? exten
@Override @Override
public Iterable<? extends Org> apply(Iterable<String> from) { public Iterable<? extends Org> apply(Iterable<String> from) {
return transformParallel(from, new Function<String, Future<Org>>() { return transformParallel(from, new Function<String, Future<? extends Org>>() {
@SuppressWarnings("unchecked")
@Override @Override
public Future<Org> apply(String from) { public Future<? extends Org> apply(String from) {
return (Future<Org>) aclient.findOrgNamed(from); return aclient.findOrgNamed(from);
} }
}, executor, null, logger, "organizations for names"); }, executor, null, logger, "organizations for names");

View File

@ -68,12 +68,10 @@ public class VAppTemplatesForCatalogItems implements
return input.getEntity().getType().equals(TerremarkVCloudMediaType.VAPPTEMPLATE_XML); return input.getEntity().getType().equals(TerremarkVCloudMediaType.VAPPTEMPLATE_XML);
} }
}), new Function<CatalogItem, Future<VAppTemplate>>() { }), new Function<CatalogItem, Future<? extends VAppTemplate>>() {
@SuppressWarnings("unchecked")
@Override @Override
public Future<VAppTemplate> apply(CatalogItem from) { public Future<? extends VAppTemplate> apply(CatalogItem from) {
return (Future<VAppTemplate>) aclient.getVAppTemplate(from.getEntity().getHref()); return aclient.getVAppTemplate(from.getEntity().getHref());
} }
}, executor, null, logger, "vappTemplates in"); }, executor, null, logger, "vappTemplates in");

View File

@ -69,12 +69,10 @@ public class VAppTemplatesForResourceEntities implements
return input.getType().equals(TerremarkVCloudMediaType.VAPPTEMPLATE_XML); return input.getType().equals(TerremarkVCloudMediaType.VAPPTEMPLATE_XML);
} }
}), new Function<ReferenceType, Future<VAppTemplate>>() { }), new Function<ReferenceType, Future<? extends VAppTemplate>>() {
@SuppressWarnings("unchecked")
@Override @Override
public Future<VAppTemplate> apply(ReferenceType from) { public Future<? extends VAppTemplate> apply(ReferenceType from) {
return (Future<VAppTemplate>) aclient.getVAppTemplate(from.getHref()); return aclient.getVAppTemplate(from.getHref());
} }
}, executor, null, logger, "vappTemplates in"); }, executor, null, logger, "vappTemplates in");

View File

@ -38,6 +38,7 @@ import org.jclouds.domain.Location;
import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statement;
import com.google.common.annotations.Beta; import com.google.common.annotations.Beta;
import com.google.common.base.Optional;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.inject.ImplementedBy; import com.google.inject.ImplementedBy;
@ -345,5 +346,14 @@ public interface ComputeService {
* @see #runScriptOnNode(String, String, RunScriptOptions) * @see #runScriptOnNode(String, String, RunScriptOptions)
*/ */
ExecResponse runScriptOnNode(String id, String runScript); ExecResponse runScriptOnNode(String id, String runScript);
/**
* Returns the {@link ImageExtension} for this provider if it implements it.
*
* @return an optional of the {@link ImageExtension} or {@link Optional#absent()} if not
* implemented
*/
@Beta
Optional<ImageExtension> getImageExtension();
} }

View File

@ -0,0 +1,63 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.compute;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.ImageTemplate;
/**
* An extension to compute service to allow for the manipulation of {@link Image}s. Implementation
* is optional by providers.
*
* @author David Alves
*/
public interface ImageExtension {
/**
* Build an ImageTemplate from a running node, to use later to create a new {@link Image}.
*
* @param name
* name to give the new image
*
* @param id
* node to base the template on
* @return an image template that can be used to create a new image
*/
ImageTemplate buildImageTemplateFromNode(String name, String id);
/**
* Transform the {@link ImageTemplate} on an {@link Image} that can be used to create nodes.
*
* @param template
* template to base the new image on
* @return the image that was just built *after* it is registered on the provider
*/
Image createImage(ImageTemplate template);
/**
* Delete an {@link Image} on the provider.
*
* @param id
* the id of the image to delete
* @return
*/
boolean deleteImage(String id);
}

View File

@ -31,6 +31,7 @@ import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.collect.Memoized; import org.jclouds.collect.Memoized;
import org.jclouds.compute.ImageExtension;
import org.jclouds.compute.callables.BlockUntilInitScriptStatusIsZeroThenReturnOutput; import org.jclouds.compute.callables.BlockUntilInitScriptStatusIsZeroThenReturnOutput;
import org.jclouds.compute.callables.RunScriptOnNode; import org.jclouds.compute.callables.RunScriptOnNode;
import org.jclouds.compute.callables.RunScriptOnNodeAsInitScriptUsingSsh; import org.jclouds.compute.callables.RunScriptOnNodeAsInitScriptUsingSsh;
@ -61,6 +62,7 @@ import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.ssh.SshClient; import org.jclouds.ssh.SshClient;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
@ -299,5 +301,12 @@ public abstract class BaseComputeServiceContextModule extends AbstractModule {
} }
}; };
} }
@Provides
@Singleton
protected Optional<ImageExtension> provideImageExtension(Injector i){
return Optional.absent();
}
} }

View File

@ -0,0 +1,31 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.compute.domain;
/**
* An {@link ImageTemplate} for the purpose of cloning an existing node.
*
* @author David Alves
*/
public interface CloneImageTemplate extends ImageTemplate {
public String getSourceNodeId();
}

View File

@ -0,0 +1,35 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.compute.domain;
/**
* A template for building new {@link Image}s.
*
* @author David Alves
*
*/
public interface ImageTemplate {
/**
* @return the name of the new image
*/
public String getName();
}

View File

@ -0,0 +1,62 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.compute.domain;
import org.jclouds.compute.domain.internal.ImageTemplateImpl;
/**
* A builder for {@link ImageTemplate}s. Includes sub-builders to build specific
* {@link ImageTemplate}s for different purposes, such as cloning, creating from iso, creating from
* netboot.
*
* @author David Alves
*
*/
public abstract class ImageTemplateBuilder {
String name;
private ImageTemplateBuilder() {
}
public ImageTemplateBuilder name(String name) {
this.name = name;
return this;
}
public static class CloneImageTemplateBuilder extends ImageTemplateBuilder {
String nodeId;
@Override
public CloneImageTemplateBuilder name(String name) {
return CloneImageTemplateBuilder.class.cast(super.name(name));
}
public CloneImageTemplateBuilder nodeId(String nodeId) {
this.nodeId = nodeId;
return this;
}
public CloneImageTemplate build() {
return new ImageTemplateImpl.CloneImageTemplateImpl(name, nodeId);
}
}
}

View File

@ -0,0 +1,53 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.compute.domain.internal;
import org.jclouds.compute.domain.CloneImageTemplate;
import org.jclouds.compute.domain.ImageTemplate;
public abstract class ImageTemplateImpl implements ImageTemplate {
protected final String name;
public ImageTemplateImpl(String name) {
this.name = name;
}
@Override
public String getName() {
return this.name;
}
public static class CloneImageTemplateImpl extends ImageTemplateImpl implements CloneImageTemplate {
protected final String sourceNodeId;
public CloneImageTemplateImpl(String name, String sourceNodeId) {
super(name);
this.sourceNodeId = sourceNodeId;
}
@Override
public String getSourceNodeId() {
return this.sourceNodeId;
}
}
}

View File

@ -51,6 +51,7 @@ import org.jclouds.Constants;
import org.jclouds.collect.Memoized; import org.jclouds.collect.Memoized;
import org.jclouds.compute.ComputeService; import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.ImageExtension;
import org.jclouds.compute.RunNodesException; import org.jclouds.compute.RunNodesException;
import org.jclouds.compute.RunScriptOnNodesException; import org.jclouds.compute.RunScriptOnNodesException;
import org.jclouds.compute.callables.RunScriptOnNode; import org.jclouds.compute.callables.RunScriptOnNode;
@ -90,6 +91,7 @@ import org.jclouds.scriptbuilder.functions.InitAdminAccess;
import org.jclouds.util.Maps2; import org.jclouds.util.Maps2;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
@ -134,6 +136,7 @@ public class BaseComputeService implements ComputeService {
private final PersistNodeCredentials persistNodeCredentials; private final PersistNodeCredentials persistNodeCredentials;
private final RunScriptOnNode.Factory runScriptOnNodeFactory; private final RunScriptOnNode.Factory runScriptOnNodeFactory;
private final ExecutorService executor; private final ExecutorService executor;
private final Optional<ImageExtension> imageExtension;
@Inject @Inject
protected BaseComputeService(ComputeServiceContext context, Map<String, Credentials> credentialStore, protected BaseComputeService(ComputeServiceContext context, Map<String, Credentials> credentialStore,
@ -148,7 +151,8 @@ public class BaseComputeService implements ComputeService {
@Named("NODE_SUSPENDED") Predicate<AtomicReference<NodeMetadata>> nodeSuspended, @Named("NODE_SUSPENDED") Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess, InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess,
RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials, RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials,
Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) { Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor,
Optional<ImageExtension> imageExtension) {
this.context = checkNotNull(context, "context"); this.context = checkNotNull(context, "context");
this.credentialStore = checkNotNull(credentialStore, "credentialStore"); this.credentialStore = checkNotNull(credentialStore, "credentialStore");
this.images = checkNotNull(images, "images"); this.images = checkNotNull(images, "images");
@ -172,6 +176,7 @@ public class BaseComputeService implements ComputeService {
this.runScriptOnNodeFactory = checkNotNull(runScriptOnNodeFactory, "runScriptOnNodeFactory"); this.runScriptOnNodeFactory = checkNotNull(runScriptOnNodeFactory, "runScriptOnNodeFactory");
this.persistNodeCredentials = checkNotNull(persistNodeCredentials, "persistNodeCredentials"); this.persistNodeCredentials = checkNotNull(persistNodeCredentials, "persistNodeCredentials");
this.executor = checkNotNull(executor, "executor"); this.executor = checkNotNull(executor, "executor");
this.imageExtension = imageExtension;
} }
/** /**
@ -238,7 +243,7 @@ public class BaseComputeService implements ComputeService {
public Set<? extends NodeMetadata> destroyNodesMatching(Predicate<NodeMetadata> filter) { public Set<? extends NodeMetadata> destroyNodesMatching(Predicate<NodeMetadata> filter) {
logger.debug(">> destroying nodes matching(%s)", filter); logger.debug(">> destroying nodes matching(%s)", filter);
Set<NodeMetadata> set = newLinkedHashSet(filter(transformParallel(nodesMatchingFilterAndNotTerminated(filter), Set<NodeMetadata> set = newLinkedHashSet(filter(transformParallel(nodesMatchingFilterAndNotTerminated(filter),
new Function<NodeMetadata, Future<NodeMetadata>>() { new Function<NodeMetadata, Future<? extends NodeMetadata>>() {
// TODO make an async interface instead of re-wrapping // TODO make an async interface instead of re-wrapping
@Override @Override
@ -403,7 +408,7 @@ public class BaseComputeService implements ComputeService {
public void rebootNodesMatching(Predicate<NodeMetadata> filter) { public void rebootNodesMatching(Predicate<NodeMetadata> filter) {
logger.debug(">> rebooting nodes matching(%s)", filter); logger.debug(">> rebooting nodes matching(%s)", filter);
transformParallel(nodesMatchingFilterAndNotTerminatedExceptionIfNotFound(filter), transformParallel(nodesMatchingFilterAndNotTerminatedExceptionIfNotFound(filter),
new Function<NodeMetadata, Future<Void>>() { new Function<NodeMetadata, Future<? extends Void>>() {
// TODO use native async // TODO use native async
@Override @Override
public Future<Void> apply(NodeMetadata from) { public Future<Void> apply(NodeMetadata from) {
@ -434,7 +439,7 @@ public class BaseComputeService implements ComputeService {
public void resumeNodesMatching(Predicate<NodeMetadata> filter) { public void resumeNodesMatching(Predicate<NodeMetadata> filter) {
logger.debug(">> resuming nodes matching(%s)", filter); logger.debug(">> resuming nodes matching(%s)", filter);
transformParallel(nodesMatchingFilterAndNotTerminatedExceptionIfNotFound(filter), transformParallel(nodesMatchingFilterAndNotTerminatedExceptionIfNotFound(filter),
new Function<NodeMetadata, Future<Void>>() { new Function<NodeMetadata, Future<? extends Void>>() {
// TODO use native async // TODO use native async
@Override @Override
public Future<Void> apply(NodeMetadata from) { public Future<Void> apply(NodeMetadata from) {
@ -465,7 +470,7 @@ public class BaseComputeService implements ComputeService {
public void suspendNodesMatching(Predicate<NodeMetadata> filter) { public void suspendNodesMatching(Predicate<NodeMetadata> filter) {
logger.debug(">> suspending nodes matching(%s)", filter); logger.debug(">> suspending nodes matching(%s)", filter);
transformParallel(nodesMatchingFilterAndNotTerminatedExceptionIfNotFound(filter), transformParallel(nodesMatchingFilterAndNotTerminatedExceptionIfNotFound(filter),
new Function<NodeMetadata, Future<Void>>() { new Function<NodeMetadata, Future<? extends Void>>() {
// TODO use native async // TODO use native async
@Override @Override
public Future<Void> apply(NodeMetadata from) { public Future<Void> apply(NodeMetadata from) {
@ -649,7 +654,7 @@ public class BaseComputeService implements ComputeService {
} }
private final class TransformNodesIntoInitializedScriptRunners implements private final class TransformNodesIntoInitializedScriptRunners implements
Function<NodeMetadata, Future<RunScriptOnNode>> { Function<NodeMetadata, Future<? extends RunScriptOnNode>> {
private final Map<NodeMetadata, Exception> badNodes; private final Map<NodeMetadata, Exception> badNodes;
private final Statement script; private final Statement script;
private final RunScriptOptions options; private final RunScriptOptions options;
@ -668,5 +673,13 @@ public class BaseComputeService implements ComputeService {
} }
} }
/**
* {@inheritDoc}
*/
@Override
public Optional<ImageExtension> getImageExtension() {
return imageExtension;
}
} }

View File

@ -0,0 +1,134 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.compute.internal;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
import java.util.Set;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ImageExtension;
import org.jclouds.compute.RunNodesException;
import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.ImageTemplate;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.Template;
import org.jclouds.ssh.SshClient;
import org.testng.annotations.Test;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
/**
* Base test for {@link ImageExtension} implementations.
*
* @author David Alves
*
*/
public abstract class BaseImageExtensionLiveTest extends BaseComputeServiceContextLiveTest {
/**
* Returns the template for the base node, override to test different templates.
*
* @return
*/
public Template getNodeTemplate() {
return context.getComputeService().templateBuilder().any().build();
}
@Test(groups = { "integration", "live" }, singleThreaded = true)
public void testCreateImage() throws RunNodesException, InterruptedException {
ComputeService computeService = context.getComputeService();
Optional<ImageExtension> imageExtension = computeService.getImageExtension();
assertTrue("image extension was not present", imageExtension.isPresent());
Set<? extends Image> imagesBefore = computeService.listImages();
NodeMetadata node = Iterables.getOnlyElement(computeService.createNodesInGroup("test-create-image", 1,
getNodeTemplate()));
ImageTemplate newImageTemplate = imageExtension.get().buildImageTemplateFromNode("test-create-image",
node.getId());
Image image = imageExtension.get().createImage(newImageTemplate);
assertEquals("test-create-image", image.getName());
computeService.destroyNode(node.getId());
Set<? extends Image> imagesAfter = computeService.listImages();
assertTrue(imagesBefore.size() == imagesAfter.size() - 1);
}
@Test(groups = { "integration", "live" }, singleThreaded = true, dependsOnMethods = "testCreateImage")
public void testSpawnNodeFromImage() throws RunNodesException {
ComputeService computeService = context.getComputeService();
Template template = computeService.templateBuilder().fromImage(getImage().get()).build();
NodeMetadata node = Iterables.getOnlyElement(computeService.createNodesInGroup("test-create-image", 1, template));
SshClient client = context.utils().sshForNode().apply(node);
client.connect();
ExecResponse hello = client.exec("echo hello");
assertEquals(hello.getOutput().trim(), "hello");
context.getComputeService().destroyNode(node.getId());
}
@Test(groups = { "integration", "live" }, singleThreaded = true, dependsOnMethods = { "testCreateImage",
"testSpawnNodeFromImage" })
public void testDeleteImage() {
ComputeService computeService = context.getComputeService();
Optional<ImageExtension> imageExtension = computeService.getImageExtension();
assertTrue("image extension was not present", imageExtension.isPresent());
Optional<? extends Image> optImage = getImage();
assertTrue(optImage.isPresent());
Image image = optImage.get();
assertTrue(imageExtension.get().deleteImage(image.getId()));
}
private Optional<? extends Image> getImage() {
return Iterables.tryFind(context.getComputeService().listImages(), new Predicate<Image>() {
@Override
public boolean apply(Image input) {
return input.getId().contains("test-create-image");
}
});
}
}

View File

@ -99,7 +99,7 @@
<dependency> <dependency>
<groupId>com.google.guava</groupId> <groupId>com.google.guava</groupId>
<artifactId>guava</artifactId> <artifactId>guava</artifactId>
<version>12.0-rc1</version> <version>12.0-rc2</version>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@ -58,50 +58,51 @@ import com.google.inject.Inject;
public class FutureIterables { public class FutureIterables {
@Resource @Resource
private static Logger logger = Logger.CONSOLE; private static Logger logger = Logger.CONSOLE;
@Inject(optional = true) @Inject(optional = true)
@Named(Constants.PROPERTY_MAX_RETRIES) @Named(Constants.PROPERTY_MAX_RETRIES)
private static int maxRetries = 5; private static int maxRetries = 5;
@Inject(optional = true) @Inject(optional = true)
@Named(Constants.PROPERTY_RETRY_DELAY_START) @Named(Constants.PROPERTY_RETRY_DELAY_START)
private static long delayStart = 50L; private static long delayStart = 50L;
@Inject(optional = true) @Inject(optional = true)
private static BackoffLimitedRetryHandler retryHandler = BackoffLimitedRetryHandler.INSTANCE; private static BackoffLimitedRetryHandler retryHandler = BackoffLimitedRetryHandler.INSTANCE;
public static <F, T> Iterable<T> transformParallel(final Iterable<F> fromIterable, public static <F, T> Iterable<T> transformParallel(final Iterable<F> fromIterable,
final Function<? super F, Future<T>> function) { final Function<? super F, Future<? extends T>> function) {
return transformParallel(fromIterable, function, org.jclouds.concurrent.MoreExecutors.sameThreadExecutor(), null); return transformParallel(fromIterable, function, org.jclouds.concurrent.MoreExecutors.sameThreadExecutor(), null);
} }
public static <F, T> Iterable<T> transformParallel(final Iterable<F> fromIterable, public static <F, T> Iterable<T> transformParallel(final Iterable<F> fromIterable,
final Function<? super F, Future<T>> function, ExecutorService exec, @Nullable Long maxTime) { final Function<? super F, Future<? extends T>> function, ExecutorService exec, @Nullable Long maxTime) {
return transformParallel(fromIterable, function, exec, maxTime, logger, "transforming"); return transformParallel(fromIterable, function, exec, maxTime, logger, "transforming");
} }
public static <F, T> Iterable<T> transformParallel(final Iterable<F> fromIterable, public static <F, T> Iterable<T> transformParallel(final Iterable<F> fromIterable,
final Function<? super F, Future<T>> function, ExecutorService exec, @Nullable Long maxTime, Logger logger, final Function<? super F, Future<? extends T>> function, ExecutorService exec, @Nullable Long maxTime, Logger logger,
String logPrefix) { String logPrefix) {
return transformParallel(fromIterable, function, exec, maxTime, logger, logPrefix, retryHandler, maxRetries); return transformParallel(fromIterable, function, exec, maxTime, logger, logPrefix, retryHandler, maxRetries);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <F, T> Iterable<T> transformParallel(Iterable<F> fromIterable, public static <F, T> Iterable<T> transformParallel(Iterable<F> fromIterable,
Function<? super F, Future<T>> function, ExecutorService exec, @Nullable Long maxTime, Logger logger, Function<? super F, Future<? extends T>> function, ExecutorService exec, @Nullable Long maxTime, Logger logger,
String logPrefix, BackoffLimitedRetryHandler retryHandler, int maxRetries) { String logPrefix, BackoffLimitedRetryHandler retryHandler, int maxRetries) {
Map<F, Exception> exceptions = newHashMap(); Map<F, Exception> exceptions = newHashMap();
Map<F, Future<T>> responses = newHashMap(); Map<F, Future<? extends T>> responses = newHashMap();
for (int i = 0; i < maxRetries; i++) { for (int i = 0; i < maxRetries; i++) {
for (F from : fromIterable) { for (F from : fromIterable) {
responses.put(from, function.apply(from)); Future<? extends T> to = function.apply(from);
responses.put(from, to);
} }
exceptions = awaitCompletion(responses, exec, maxTime, logger, logPrefix); exceptions = awaitCompletion(responses, exec, maxTime, logger, logPrefix);
if (exceptions.size() > 0 && !any(exceptions.values(), containsThrowable(AuthorizationException.class))) { if (exceptions.size() > 0 && !any(exceptions.values(), containsThrowable(AuthorizationException.class))) {
fromIterable = exceptions.keySet(); fromIterable = exceptions.keySet();
retryHandler.imposeBackoffExponentialDelay(delayStart, 2, i + 1, maxRetries, retryHandler.imposeBackoffExponentialDelay(delayStart, 2, i + 1, maxRetries,
String.format("error %s: %s: %s", logPrefix, fromIterable, exceptions)); String.format("error %s: %s: %s", logPrefix, fromIterable, exceptions));
} else { } else {
break; break;
} }
@ -109,13 +110,13 @@ public class FutureIterables {
//make sure we propagate any authorization exception so that we don't lock out accounts //make sure we propagate any authorization exception so that we don't lock out accounts
if (exceptions.size() > 0) if (exceptions.size() > 0)
return propagateAuthorizationOrOriginalException(new TransformParallelException((Map) responses, exceptions, return propagateAuthorizationOrOriginalException(new TransformParallelException((Map) responses, exceptions,
logPrefix)); logPrefix));
return unwrap(responses.values()); return unwrap(responses.values());
} }
public static <T> Map<T, Exception> awaitCompletion(Map<T, ? extends Future<?>> responses, ExecutorService exec, public static <T> Map<T, Exception> awaitCompletion(Map<T, ? extends Future<?>> responses, ExecutorService exec,
@Nullable Long maxTime, final Logger logger, final String logPrefix) { @Nullable Long maxTime, final Logger logger, final String logPrefix) {
final ConcurrentMap<T, Exception> errorMap = newConcurrentMap(); final ConcurrentMap<T, Exception> errorMap = newConcurrentMap();
if (responses.size() == 0) if (responses.size() == 0)
return errorMap; return errorMap;
@ -126,7 +127,7 @@ public class FutureIterables {
final long start = System.currentTimeMillis(); final long start = System.currentTimeMillis();
for (final java.util.Map.Entry<T, ? extends Future<?>> future : responses.entrySet()) { for (final java.util.Map.Entry<T, ? extends Future<?>> future : responses.entrySet()) {
Futures.makeListenable(future.getValue(), exec).addListener(new Runnable() { Futures.makeListenable(future.getValue(), exec).addListener(new Runnable() {
@Override @Override
public void run() { public void run() {
try { try {
@ -168,11 +169,11 @@ public class FutureIterables {
} }
return errorMap; return errorMap;
} }
public static <T> Iterable<T> unwrap(Iterable<Future<T>> values) { public static <T> Iterable<T> unwrap(Iterable<Future<? extends T>> values) {
return transform(values, new Function<Future<T>, T>() { return transform(values, new Function<Future<? extends T>, T>() {
@Override @Override
public T apply(Future<T> from) { public T apply(Future<? extends T> from) {
try { try {
return from.get(); return from.get();
} catch (InterruptedException e) { } catch (InterruptedException e) {
@ -189,20 +190,20 @@ public class FutureIterables {
} }
}); });
} }
private static void logException(Logger logger, String logPrefix, int total, int complete, int errors, long start, private static void logException(Logger logger, String logPrefix, int total, int complete, int errors, long start,
Exception e) { Exception e) {
String message = message(logPrefix, total, complete, errors, start); String message = message(logPrefix, total, complete, errors, start);
logger.error(e, message); logger.error(e, message);
} }
private static String message(String prefix, int size, int complete, int errors, long start) { private static String message(String prefix, int size, int complete, int errors, long start) {
return String.format("%s, completed: %d/%d, errors: %d, rate: %dms/op", prefix, complete, size, errors, return String.format("%s, completed: %d/%d, errors: %d, rate: %dms/op", prefix, complete, size, errors,
(long) ((System.currentTimeMillis() - start) / ((double) size))); (long) ((System.currentTimeMillis() - start) / ((double) size)));
} }
protected static boolean timeOut(long start, Long maxTime) { protected static boolean timeOut(long start, Long maxTime) {
return maxTime != null ? System.currentTimeMillis() < start + maxTime : false; return maxTime != null ? System.currentTimeMillis() < start + maxTime : false;
} }
} }

View File

@ -0,0 +1,40 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.util;
import com.google.common.collect.ImmutableSortedSet;
/**
* General utilities used in jclouds code for {@link Iterable Iterables}.
*
* @author danikov
*/
public class Iterables2 {
/**
* Copies the contents of a wildcarded {@link Iterable} into a concrete {@link Iterable} of the left bound
*
* @param unboundedValues wildcarded source {@link Iterable}
* @return concrete-typed copy of the source
*/
public static <T> Iterable<T> concreteCopy(Iterable<? extends T> unboundedValues) {
return ImmutableSortedSet.copyOf(unboundedValues);
}
}

View File

@ -154,5 +154,15 @@ public class Maps2 {
} }
return result; return result;
} }
/**
* Covariant compatible version
*
* @see {@link Maps#uniqueIndex(Iterable, Function)}
*/
public static <K, V> ImmutableMap<K, V> uniqueIndex(
Iterable<? extends V> values, Function<? super V, ? extends K> keyFunction) {
return ImmutableMap.copyOf(Maps.uniqueIndex(values, keyFunction));
}
} }

View File

@ -43,7 +43,7 @@ public class FutureIterablesTest {
final AtomicInteger counter = new AtomicInteger(); final AtomicInteger counter = new AtomicInteger();
try { try {
transformParallel(ImmutableSet.of("hello", "goodbye"), new Function<String, Future<String>>() { transformParallel(ImmutableSet.of("hello", "goodbye"), new Function<String, Future<? extends String>>() {
@Override @Override
public Future<String> apply(String input) { public Future<String> apply(String input) {
@ -63,7 +63,7 @@ public class FutureIterablesTest {
final AtomicInteger counter = new AtomicInteger(); final AtomicInteger counter = new AtomicInteger();
try { try {
transformParallel(ImmutableSet.of("hello", "goodbye"), new Function<String, Future<String>>() { transformParallel(ImmutableSet.of("hello", "goodbye"), new Function<String, Future<? extends String>>() {
@Override @Override
public Future<String> apply(String input) { public Future<String> apply(String input) {

View File

@ -22,11 +22,13 @@ import static com.google.common.base.Preconditions.checkNotNull;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Properties; import java.util.Properties;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -57,11 +59,13 @@ import org.jclouds.http.handlers.DelegatingErrorHandler;
import org.jclouds.http.handlers.DelegatingRetryHandler; import org.jclouds.http.handlers.DelegatingRetryHandler;
import org.jclouds.http.internal.BaseHttpCommandExecutorService; import org.jclouds.http.internal.BaseHttpCommandExecutorService;
import org.jclouds.http.internal.HttpWire; import org.jclouds.http.internal.HttpWire;
import org.jclouds.io.CopyInputStreamInputSupplierMap;
import org.jclouds.io.Payload; import org.jclouds.io.Payload;
import org.jclouds.io.Payloads; import org.jclouds.io.Payloads;
import org.jclouds.logging.config.NullLoggingModule; import org.jclouds.logging.config.NullLoggingModule;
import org.jclouds.providers.ProviderMetadata; import org.jclouds.providers.ProviderMetadata;
import org.jclouds.rest.RestApiMetadata; import org.jclouds.rest.RestApiMetadata;
import org.jclouds.rest.config.CredentialStoreModule;
import org.jclouds.util.Strings2; import org.jclouds.util.Strings2;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import org.w3c.dom.Node; import org.w3c.dom.Node;
@ -74,6 +78,7 @@ import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.io.InputSupplier;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
@ -540,11 +545,13 @@ public abstract class BaseRestClientExpectTest<S> {
this.api = RestApiMetadata.class.cast(builder.getApiMetadata()).getApi(); this.api = RestApiMetadata.class.cast(builder.getApiMetadata()).getApi();
// isolate tests from eachother, as default credentialStore is static
return builder.credentials(identity, credential).modules( return builder.credentials(identity, credential).modules(
ImmutableSet.of(new ExpectModule(fn), new NullLoggingModule(), module)).overrides(setupProperties()) ImmutableSet.of(new ExpectModule(fn), new NullLoggingModule(), new CredentialStoreModule(new CopyInputStreamInputSupplierMap(
new ConcurrentHashMap<String, InputSupplier<InputStream>>())), module)).overrides(setupProperties())
.buildInjector(); .buildInjector();
} }
/** /**
* override this to supply context-specific parameters during tests. * override this to supply context-specific parameters during tests.
*/ */

View File

@ -74,14 +74,14 @@ public class ELBListLoadBalancersStrategy implements ListLoadBalancersStrategy {
} }
@Override @Override
public Iterable<? extends LoadBalancerMetadata> listLoadBalancers() { public Iterable<LoadBalancerMetadata> listLoadBalancers() {
Iterable<? extends LoadBalancer> loadBalancers; Iterable<? extends LoadBalancer> loadBalancers;
Set<String> regions = this.regions.get(); Set<String> regions = this.regions.get();
if (regions.size() > 0) if (regions.size() > 0)
loadBalancers = concat(transformParallel(regions, new Function<String, Future<Set<? extends LoadBalancer>>>() { loadBalancers = concat(transformParallel(regions, new Function<String, Future<? extends Set<? extends LoadBalancer>>>() {
@Override @Override
public ListenableFuture<Set<? extends LoadBalancer>> apply(String from) { public ListenableFuture<? extends Set<? extends LoadBalancer>> apply(String from) {
return aclient.describeLoadBalancersInRegion(from); return aclient.describeLoadBalancersInRegion(from);
} }

View File

@ -62,6 +62,7 @@ import org.jclouds.glesys.options.DestroyServerOptions;
import org.jclouds.location.predicates.LocationPredicates; import org.jclouds.location.predicates.LocationPredicates;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.predicates.RetryablePredicate; import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.util.Iterables2;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
@ -196,13 +197,13 @@ public class GleSYSComputeServiceAdapter implements ComputeServiceAdapter<Server
@Override @Override
public Iterable<ServerDetails> listNodes() { public Iterable<ServerDetails> listNodes() {
return transformParallel(client.getServerClient().listServers(), new Function<Server, Future<ServerDetails>>() { return Iterables2.concreteCopy(transformParallel(client.getServerClient().listServers(), new Function<Server, Future<? extends ServerDetails>>() {
@Override @Override
public Future<ServerDetails> apply(Server from) { public Future<ServerDetails> apply(Server from) {
return aclient.getServerClient().getServerDetails(from.getId()); return aclient.getServerClient().getServerDetails(from.getId());
} }
}, userThreads, null, logger, "server details"); }, userThreads, null, logger, "server details"));
} }
@Override @Override

View File

@ -39,7 +39,7 @@
<test.virtualbox.build-version>4.1.8r75467</test.virtualbox.build-version> <test.virtualbox.build-version>4.1.8r75467</test.virtualbox.build-version>
<test.virtualbox.identity>administrator</test.virtualbox.identity> <test.virtualbox.identity>administrator</test.virtualbox.identity>
<test.virtualbox.credential>12345</test.virtualbox.credential> <test.virtualbox.credential>12345</test.virtualbox.credential>
<test.virtualbox.image-id>default-ubuntu-11.04-i386</test.virtualbox.image-id> <test.virtualbox.image-id>test-ubuntu-11.10-i386</test.virtualbox.image-id>
<test.virtualbox.image.login-user>toor:password</test.virtualbox.image.login-user> <test.virtualbox.image.login-user>toor:password</test.virtualbox.image.login-user>
<test.virtualbox.image.authenticate-sudo>true</test.virtualbox.image.authenticate-sudo> <test.virtualbox.image.authenticate-sudo>true</test.virtualbox.image.authenticate-sudo>
</properties> </properties>

View File

@ -27,12 +27,15 @@ import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_PREFIX; import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_PREFIX;
import java.util.Map; import java.util.Map;
import java.util.Set;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import org.jclouds.compute.ComputeServiceAdapter; import org.jclouds.compute.ComputeServiceAdapter;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.HardwareBuilder;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
@ -58,6 +61,7 @@ import com.google.common.base.Throwables;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.google.inject.Singleton; import com.google.inject.Singleton;
/** /**
@ -67,25 +71,28 @@ import com.google.inject.Singleton;
* @author Mattias Holmqvist, Andrea Turli, David Alves * @author Mattias Holmqvist, Andrea Turli, David Alves
*/ */
@Singleton @Singleton
public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IMachine, IMachine, Image, Location> { public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IMachine, Hardware, Image, Location> {
@Resource @Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER) @Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
private final Supplier<VirtualBoxManager> manager; private final Supplier<VirtualBoxManager> manager;
private final Map<Image, YamlImage> images; private final Map<Image, YamlImage> imagesToYamlImages;
private final LoadingCache<Image, Master> mastersLoader; private final LoadingCache<Image, Master> mastersLoader;
private final Function<NodeSpec, NodeAndInitialCredentials<IMachine>> cloneCreator; private final Function<NodeSpec, NodeAndInitialCredentials<IMachine>> cloneCreator;
private final Function<IMachine, Image> imachineToImage;
@Inject @Inject
public VirtualBoxComputeServiceAdapter(Supplier<VirtualBoxManager> manager, public VirtualBoxComputeServiceAdapter(Supplier<VirtualBoxManager> manager,
Supplier<Map<Image, YamlImage>> imagesMapper, LoadingCache<Image, Master> mastersLoader, Supplier<Map<Image, YamlImage>> imagesMapper, LoadingCache<Image, Master> mastersLoader,
Function<NodeSpec, NodeAndInitialCredentials<IMachine>> cloneCreator) { Function<NodeSpec, NodeAndInitialCredentials<IMachine>> cloneCreator,
Function<IMachine, Image> imachineToImage) {
this.manager = checkNotNull(manager, "manager"); this.manager = checkNotNull(manager, "manager");
this.images = imagesMapper.get(); this.imagesToYamlImages = imagesMapper.get();
this.mastersLoader = mastersLoader; this.mastersLoader = mastersLoader;
this.cloneCreator = cloneCreator; this.cloneCreator = cloneCreator;
this.imachineToImage = imachineToImage;
} }
@Override @Override
@ -97,7 +104,7 @@ public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IM
checkState(!name.contains(VIRTUALBOX_NODE_NAME_SEPARATOR), "node names cannot contain \"" checkState(!name.contains(VIRTUALBOX_NODE_NAME_SEPARATOR), "node names cannot contain \""
+ VIRTUALBOX_NODE_NAME_SEPARATOR + "\""); + VIRTUALBOX_NODE_NAME_SEPARATOR + "\"");
Master master = mastersLoader.get(template.getImage()); Master master = mastersLoader.get(template.getImage());
checkState(master != null, "could not find a master for image: "+template.getClass()); checkState(master != null, "could not find a master for image: " + template.getImage());
NodeSpec nodeSpec = NodeSpec.builder().master(master).name(name).tag(tag).template(template).build(); NodeSpec nodeSpec = NodeSpec.builder().master(master).name(name).tag(tag).template(template).build();
return cloneCreator.apply(nodeSpec); return cloneCreator.apply(nodeSpec);
} catch (Exception e) { } catch (Exception e) {
@ -116,13 +123,39 @@ public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IM
} }
@Override @Override
public Iterable<IMachine> listHardwareProfiles() { public Iterable<Hardware> listHardwareProfiles() {
return imageMachines(); Set<Hardware> hardware = Sets.newLinkedHashSet();
hardware.add(new HardwareBuilder().ids("t1.micro").hypervisor("VirtualBox").name("t1.micro").ram(512).build());
hardware.add(new HardwareBuilder().ids("m1.small").hypervisor("VirtualBox").name("m1.small").ram(1024).build());
hardware.add(new HardwareBuilder().ids("m1.medium").hypervisor("VirtualBox").name("m1.medium").ram(3840).build());
hardware.add(new HardwareBuilder().ids("m1.large").hypervisor("VirtualBox").name("m1.large").ram(7680).build());
return hardware;
} }
@Override @Override
public Iterable<Image> listImages() { public Iterable<Image> listImages() {
return images.keySet(); // the set of image vm names that were (or could be) built from the yaml file
final Set<String> imagesFromYamlNames = Sets.newHashSet(Iterables.transform(imagesToYamlImages.keySet(),
new Function<Image, String>() {
@Override
public String apply(Image input) {
return VIRTUALBOX_IMAGE_PREFIX + input.getId();
}
}));
// IMachines that were not built from the yaml file transformed to Images
Set<Image> imagesFromCloning = Sets.newHashSet(Iterables.transform(
Iterables.filter(imageMachines(), new Predicate<IMachine>() {
@Override
public boolean apply(IMachine input) {
return !imagesFromYamlNames.contains(input.getName());
}
}), imachineToImage));
// final set of images are those from yaml and those from vbox that were not a transformation
// of the yaml ones
return Sets.union(imagesToYamlImages.keySet(), imagesFromCloning);
} }
private Iterable<IMachine> imageMachines() { private Iterable<IMachine> imageMachines() {
@ -147,7 +180,7 @@ public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IM
try { try {
return manager.get().getVBox().findMachine(vmName); return manager.get().getVBox().findMachine(vmName);
} catch (VBoxException e) { } catch (VBoxException e) {
if (e.getMessage().contains("Could not find a registered machine named")){ if (e.getMessage().contains("Could not find a registered machine named")) {
return null; return null;
} }
throw Throwables.propagate(e); throw Throwables.propagate(e);
@ -202,7 +235,7 @@ public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IM
private void powerDownMachine(IMachine machine) { private void powerDownMachine(IMachine machine) {
try { try {
if (machine.getState() == MachineState.PoweredOff){ if (machine.getState() == MachineState.PoweredOff) {
logger.debug("vm was already powered down: ", machine.getId()); logger.debug("vm was already powered down: ", machine.getId());
return; return;
} }

View File

@ -0,0 +1,162 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.virtualbox.compute;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_DEFAULT_DIR;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_WORKINGDIR;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.compute.ComputeServiceAdapter;
import org.jclouds.compute.ImageExtension;
import org.jclouds.compute.domain.CloneImageTemplate;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.ImageTemplate;
import org.jclouds.compute.domain.ImageTemplateBuilder;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.domain.Location;
import org.jclouds.logging.Logger;
import org.jclouds.virtualbox.functions.IMachineToVmSpec;
import org.jclouds.virtualbox.functions.TakeSnapshotIfNotAlreadyAttached;
import org.jclouds.virtualbox.functions.admin.UnregisterMachineIfExistsAndDeleteItsMedia;
import org.jclouds.virtualbox.util.MachineUtils;
import org.virtualbox_4_1.CloneMode;
import org.virtualbox_4_1.CloneOptions;
import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.IProgress;
import org.virtualbox_4_1.ISnapshot;
import org.virtualbox_4_1.VirtualBoxManager;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.collect.Iterables;
@Singleton
public class VirtualBoxImageExtension implements ImageExtension {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
private Logger logger = Logger.NULL;
private ComputeServiceAdapter<IMachine, Hardware, Image, Location> vboxAdapter;
private Function<IMachine, NodeMetadata> machineToNode;
private Supplier<VirtualBoxManager> manager;
private String workingDir;
private boolean isLinkedClone = true;
private Function<IMachine, Image> imachineToImage;
private MachineUtils machineUtils;
@Inject
public VirtualBoxImageExtension(ComputeServiceAdapter<IMachine, Hardware, Image, Location> vboxAdapter,
Function<IMachine, NodeMetadata> machineToNode, Supplier<VirtualBoxManager> manager,
@Named(VIRTUALBOX_WORKINGDIR) String workingDir, Function<IMachine, Image> imachineToImage,
MachineUtils machineUtils) {
this.vboxAdapter = vboxAdapter;
this.machineToNode = machineToNode;
this.manager = manager;
this.workingDir = workingDir == null ? VIRTUALBOX_DEFAULT_DIR : workingDir;
this.imachineToImage = imachineToImage;
this.machineUtils = machineUtils;
}
@Override
public ImageTemplate buildImageTemplateFromNode(String name, final String id) {
Optional<NodeMetadata> sourceNode = getNodeById(id);
checkState(sourceNode.isPresent(), " there is no node with id " + id);
String vmName = VIRTUALBOX_IMAGE_PREFIX + name;
IMachine vm = null;
try {
vm = manager.get().getVBox().findMachine(vmName);
} catch (Exception e) {
}
checkState(vm == null, " a machine exists with name: " + vmName);
return new ImageTemplateBuilder.CloneImageTemplateBuilder().name(vmName).nodeId(id).build();
}
@Override
public Image createImage(ImageTemplate template) {
checkState(template instanceof CloneImageTemplate, " vbox image extension only supports cloning for the moment.");
CloneImageTemplate cloneTemplate = CloneImageTemplate.class.cast(template);
IMachine source = manager.get().getVBox().findMachine(cloneTemplate.getSourceNodeId());
String settingsFile = manager.get().getVBox().composeMachineFilename(template.getName(), workingDir);
IMachine clonedMachine = manager.get().getVBox()
.createMachine(settingsFile, template.getName(), source.getOSTypeId(), template.getName(), true);
List<CloneOptions> options = new ArrayList<CloneOptions>();
if (isLinkedClone)
options.add(CloneOptions.Link);
// TODO snapshot name
ISnapshot currentSnapshot = new TakeSnapshotIfNotAlreadyAttached(manager, "pre-image-spawn", "before spawning "
+ template.getName(), logger).apply(source);
checkNotNull(currentSnapshot);
// clone
IProgress progress = currentSnapshot.getMachine().cloneTo(clonedMachine, CloneMode.MachineState, options);
progress.waitForCompletion(-1);
logger.debug(String.format("Machine %s is cloned correctly", clonedMachine.getName()));
// registering
manager.get().getVBox().registerMachine(clonedMachine);
return imachineToImage.apply(clonedMachine);
}
@Override
public boolean deleteImage(String id) {
try {
IMachine machine = manager.get().getVBox().findMachine(VIRTUALBOX_IMAGE_PREFIX + id);
machineUtils.applyForMachine(machine.getId(), new UnregisterMachineIfExistsAndDeleteItsMedia(
new IMachineToVmSpec().apply(machine)));
} catch (Exception e) {
logger.error(e, "Could not delete machine with id %s ", id);
return false;
}
return true;
}
private Optional<NodeMetadata> getNodeById(final String id) {
return Iterables.tryFind(Iterables.transform(vboxAdapter.listNodes(), machineToNode),
new Predicate<NodeMetadata>() {
@Override
public boolean apply(NodeMetadata input) {
return input.getId().equals(id);
}
});
}
}

View File

@ -40,8 +40,9 @@ import org.jclouds.byon.Node;
import org.jclouds.byon.functions.NodeToNodeMetadata; import org.jclouds.byon.functions.NodeToNodeMetadata;
import org.jclouds.byon.suppliers.SupplyFromProviderURIOrNodesProperty; import org.jclouds.byon.suppliers.SupplyFromProviderURIOrNodesProperty;
import org.jclouds.compute.ComputeServiceAdapter; import org.jclouds.compute.ComputeServiceAdapter;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials; import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.ImageExtension;
import org.jclouds.compute.config.ComputeServiceAdapterContextModule; import org.jclouds.compute.config.ComputeServiceAdapterContextModule;
import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.HardwareBuilder; import org.jclouds.compute.domain.HardwareBuilder;
@ -58,6 +59,7 @@ import org.jclouds.ssh.SshClient;
import org.jclouds.sshj.config.SshjSshClientModule; import org.jclouds.sshj.config.SshjSshClientModule;
import org.jclouds.virtualbox.Host; import org.jclouds.virtualbox.Host;
import org.jclouds.virtualbox.compute.VirtualBoxComputeServiceAdapter; import org.jclouds.virtualbox.compute.VirtualBoxComputeServiceAdapter;
import org.jclouds.virtualbox.compute.VirtualBoxImageExtension;
import org.jclouds.virtualbox.domain.CloneSpec; import org.jclouds.virtualbox.domain.CloneSpec;
import org.jclouds.virtualbox.domain.ExecutionType; import org.jclouds.virtualbox.domain.ExecutionType;
import org.jclouds.virtualbox.domain.IsoSpec; import org.jclouds.virtualbox.domain.IsoSpec;
@ -88,6 +90,7 @@ import org.virtualbox_4_1.VirtualBoxManager;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Functions; import com.google.common.base.Functions;
import com.google.common.base.Optional;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
@ -105,17 +108,19 @@ import com.google.inject.TypeLiteral;
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class VirtualBoxComputeServiceContextModule extends public class VirtualBoxComputeServiceContextModule extends
ComputeServiceAdapterContextModule<IMachine, IMachine, Image, Location> { ComputeServiceAdapterContextModule<IMachine, Hardware, Image, Location> {
@Override @Override
protected void configure() { protected void configure() {
super.configure(); super.configure();
bind(new TypeLiteral<ComputeServiceAdapter<IMachine, IMachine, Image, Location>>() { bind(new TypeLiteral<ComputeServiceAdapter<IMachine, Hardware, Image, Location>>() {
}).to(VirtualBoxComputeServiceAdapter.class); }).to(VirtualBoxComputeServiceAdapter.class);
bind(new TypeLiteral<Function<IMachine, NodeMetadata>>() { bind(new TypeLiteral<Function<IMachine, NodeMetadata>>() {
}).to(IMachineToNodeMetadata.class); }).to(IMachineToNodeMetadata.class);
bind(new TypeLiteral<Function<Location, Location>>() { bind(new TypeLiteral<Function<Location, Location>>() {
}).to((Class) IdentityFunction.class); }).to((Class) IdentityFunction.class);
bind(new TypeLiteral<Function<Hardware, Hardware>>() {
}).to((Class) IdentityFunction.class);
bind(new TypeLiteral<Function<Image, Image>>() { bind(new TypeLiteral<Function<Image, Image>>() {
}).to((Class) IdentityFunction.class); }).to((Class) IdentityFunction.class);
bind(new TypeLiteral<Function<IMachine, Hardware>>() { bind(new TypeLiteral<Function<IMachine, Hardware>>() {
@ -139,6 +144,10 @@ public class VirtualBoxComputeServiceContextModule extends
bind(new TypeLiteral<LoadingCache<Image, Master>>() { bind(new TypeLiteral<LoadingCache<Image, Master>>() {
}).to(MastersLoadingCache.class); }).to(MastersLoadingCache.class);
// the vbox image extension
bind(new TypeLiteral<ImageExtension>() {
}).to(VirtualBoxImageExtension.class);
// the master creating function // the master creating function
bind(new TypeLiteral<Function<MasterSpec, IMachine>>() { bind(new TypeLiteral<Function<MasterSpec, IMachine>>() {
}).to((Class) CreateAndInstallVm.class); }).to((Class) CreateAndInstallVm.class);
@ -166,10 +175,9 @@ public class VirtualBoxComputeServiceContextModule extends
@Host @Host
@Singleton @Singleton
protected ComputeServiceContext provideHostController() { protected ComputeServiceContext provideHostController() {
return ContextBuilder.newBuilder(new BYONApiMetadata()) return ContextBuilder.newBuilder(new BYONApiMetadata()).credentials("", "")
.credentials("", "") .modules(ImmutableSet.<Module> of(new SLF4JLoggingModule(), new SshjSshClientModule()))
.modules(ImmutableSet.<Module> of(new SLF4JLoggingModule(), new SshjSshClientModule())) .build(ComputeServiceContext.class);
.build(ComputeServiceContext.class);
} }
@Provides @Provides
@ -202,18 +210,6 @@ public class VirtualBoxComputeServiceContextModule extends
return new RetryablePredicate<SshClient>(sshResponds, timeouts.nodeRunning, 500l, TimeUnit.MILLISECONDS); return new RetryablePredicate<SshClient>(sshResponds, timeouts.nodeRunning, 500l, TimeUnit.MILLISECONDS);
} }
@Override
protected Supplier provideHardware(ComputeServiceAdapter<IMachine, IMachine, Image, Location> adapter,
Function<IMachine, Hardware> transformer) {
// since no vms might be available we need to list images
Iterable<Image> images = adapter.listImages();
Set<Hardware> hardware = Sets.newHashSet();
for (Image image : images) {
hardware.add(new HardwareBuilder().ids(image.getId()).hypervisor("VirtualBox").name(image.getName()).build());
}
return Suppliers.ofInstance(hardware);
}
@Override @Override
protected TemplateBuilder provideTemplate(Injector injector, TemplateBuilder template) { protected TemplateBuilder provideTemplate(Injector injector, TemplateBuilder template) {
return template.osFamily(VIRTUALBOX_DEFAULT_IMAGE_OS).osVersionMatches(VIRTUALBOX_DEFAULT_IMAGE_VERSION) return template.osFamily(VIRTUALBOX_DEFAULT_IMAGE_OS).osVersionMatches(VIRTUALBOX_DEFAULT_IMAGE_VERSION)
@ -233,6 +229,11 @@ public class VirtualBoxComputeServiceContextModule extends
}), nodes); }), nodes);
} }
@Override
protected Optional<ImageExtension> provideImageExtension(Injector i) {
return Optional.of(i.getInstance(ImageExtension.class));
}
@VisibleForTesting @VisibleForTesting
public static final Map<MachineState, NodeState> machineToNodeState = ImmutableMap public static final Map<MachineState, NodeState> machineToNodeState = ImmutableMap
.<MachineState, NodeState> builder().put(MachineState.Running, NodeState.RUNNING) .<MachineState, NodeState> builder().put(MachineState.Running, NodeState.RUNNING)

View File

@ -99,13 +99,13 @@ public class CloneAndRegisterMachineFromIMachineIfNotAlreadyExists implements Fu
.getVBox() .getVBox()
.createMachine(settingsFile, vmSpec.getVmName(), vmSpec.getOsTypeId(), vmSpec.getVmId(), .createMachine(settingsFile, vmSpec.getVmName(), vmSpec.getOsTypeId(), vmSpec.getVmId(),
vmSpec.isForceOverwrite()); vmSpec.isForceOverwrite());
List<CloneOptions> options = new ArrayList<CloneOptions>(); List<CloneOptions> options = new ArrayList<CloneOptions>();
if (isLinkedClone) if (isLinkedClone)
options.add(CloneOptions.Link); options.add(CloneOptions.Link);
// TODO snapshot name // TODO snapshot name
ISnapshot currentSnapshot = new TakeSnapshotIfNotAlreadyAttached(manager, "snapshotName", "snapshotDesc") ISnapshot currentSnapshot = new TakeSnapshotIfNotAlreadyAttached(manager, "snapshotName", "snapshotDesc", logger)
.apply(master); .apply(master);
// clone // clone
@ -114,6 +114,9 @@ public class CloneAndRegisterMachineFromIMachineIfNotAlreadyExists implements Fu
progress.waitForCompletion(-1); progress.waitForCompletion(-1);
logger.debug(String.format("Machine %s is cloned correctly", clonedMachine.getName())); logger.debug(String.format("Machine %s is cloned correctly", clonedMachine.getName()));
// memory may not be the same as the master vm
clonedMachine.setMemorySize(cloneSpec.getVmSpec().getMemory());
// registering // registering
manager.get().getVBox().registerMachine(clonedMachine); manager.get().getVBox().registerMachine(clonedMachine);

View File

@ -33,6 +33,7 @@ import org.jclouds.compute.domain.ImageBuilder;
import org.jclouds.compute.domain.OperatingSystem; import org.jclouds.compute.domain.OperatingSystem;
import org.jclouds.compute.domain.OsFamily; import org.jclouds.compute.domain.OsFamily;
import org.jclouds.javax.annotation.Nullable; import org.jclouds.javax.annotation.Nullable;
import org.jclouds.virtualbox.config.VirtualBoxConstants;
import org.virtualbox_4_1.IGuestOSType; import org.virtualbox_4_1.IGuestOSType;
import org.virtualbox_4_1.IMachine; import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.VirtualBoxManager; import org.virtualbox_4_1.VirtualBoxManager;
@ -63,7 +64,9 @@ public class IMachineToImage implements Function<IMachine, Image> {
OperatingSystem os = OperatingSystem.builder().description(guestOSType.getDescription()).family(family) OperatingSystem os = OperatingSystem.builder().description(guestOSType.getDescription()).family(family)
.version(version).is64Bit(guestOSType.getIs64Bit()).build(); .version(version).is64Bit(guestOSType.getIs64Bit()).build();
return new ImageBuilder().id("" + from.getId()).name(from.getName()).description(from.getDescription()) return new ImageBuilder()
.id(from.getName().substring(VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX.length(),
from.getName().length())).name(from.getName()).description(from.getDescription())
.operatingSystem(os).build(); .operatingSystem(os).build();
} }

View File

@ -95,8 +95,6 @@ public class IMachineToNodeMetadata implements Function<IMachine, NodeMetadata>
nodeState = NodeState.UNRECOGNIZED; nodeState = NodeState.UNRECOGNIZED;
nodeMetadataBuilder.state(nodeState); nodeMetadataBuilder.state(nodeState);
logger.debug("Setting virtualbox node to: " + nodeState + " from machine state: " + vmState);
/* /*
// nat adapter // nat adapter
INetworkAdapter natAdapter = vm.getNetworkAdapter(0l); INetworkAdapter natAdapter = vm.getNetworkAdapter(0l);
@ -139,7 +137,6 @@ public class IMachineToNodeMetadata implements Function<IMachine, NodeMetadata>
private NodeMetadataBuilder getIpAddresses(IMachine vm, NodeMetadataBuilder nodeMetadataBuilder) { private NodeMetadataBuilder getIpAddresses(IMachine vm, NodeMetadataBuilder nodeMetadataBuilder) {
List<String> publicIpAddresses = Lists.newArrayList(); List<String> publicIpAddresses = Lists.newArrayList();
List<String> privateIpAddresses = Lists.newArrayList();
for(long slot = 0; slot < 4; slot ++) { for(long slot = 0; slot < 4; slot ++) {
INetworkAdapter adapter = vm.getNetworkAdapter(slot); INetworkAdapter adapter = vm.getNetworkAdapter(slot);

View File

@ -141,14 +141,51 @@ public class MastersLoadingCache extends AbstractLoadingCache<Image, Master> {
return masters.get(key.getId()); return masters.get(key.getId());
} }
// the yaml image checkState(!key.getId().contains(VIRTUALBOX_NODE_NAME_SEPARATOR), "master image names cannot contain \""
YamlImage currentImage = imageMapping.get(key.getId());
checkNotNull(currentImage, "could not find yaml image for image: " + key);
checkState(!currentImage.id.contains(VIRTUALBOX_NODE_NAME_SEPARATOR), "master image names cannot contain \""
+ VIRTUALBOX_NODE_NAME_SEPARATOR + "\""); + VIRTUALBOX_NODE_NAME_SEPARATOR + "\"");
String vmName = VIRTUALBOX_IMAGE_PREFIX + key.getId();
IMachine masterMachine;
Master master;
// ready the preseed file server
PreseedCfgServer server = new PreseedCfgServer();
try {
// try and find a master machine in vbox
masterMachine = manager.get().getVBox().findMachine(vmName);
master = Master.builder().machine(masterMachine).build();
} catch (VBoxException e) {
if (machineNotFoundException(e)) {
// machine was not found try to build one from a yaml file
YamlImage currentImage = imageMapping.get(key.getId());
checkNotNull(currentImage);
server.start(preconfigurationUrl, currentImage.preseed_cfg);
MasterSpec masterSpec = buildMasterSpecFromYaml(currentImage, vmName);
// create the master machine if it can't be found
masterMachine = masterCreatorAndInstaller.apply(masterSpec);
// build the master
master = Master.builder().machine(masterMachine).spec(masterSpec).build();
} else {
throw e;
}
} finally {
server.stop();
}
masters.put(key.getId(), master);
return master;
}
private MasterSpec buildMasterSpecFromYaml(YamlImage currentImage, String vmName) throws ExecutionException {
String guestAdditionsFileName = String.format("VBoxGuestAdditions_%s.iso", version); String guestAdditionsFileName = String.format("VBoxGuestAdditions_%s.iso", version);
String guestAdditionsIso = String.format("%s/%s", isosDir, guestAdditionsFileName); String guestAdditionsIso = String.format("%s/%s", isosDir, guestAdditionsFileName);
String guestAdditionsUri = "http://download.virtualbox.org/virtualbox/" + version + "/" + guestAdditionsFileName; String guestAdditionsUri = "http://download.virtualbox.org/virtualbox/" + version + "/" + guestAdditionsFileName;
@ -160,8 +197,6 @@ public class MastersLoadingCache extends AbstractLoadingCache<Image, Master> {
// check if the iso is here, download if not // check if the iso is here, download if not
String localIsoUrl = getFilePathOrDownload(currentImage.iso); String localIsoUrl = getFilePathOrDownload(currentImage.iso);
String vmName = VIRTUALBOX_IMAGE_PREFIX + currentImage.id;
String adminDisk = workingDir + File.separator + vmName + ".vdi"; String adminDisk = workingDir + File.separator + vmName + ".vdi";
HardDisk hardDisk = HardDisk.builder().diskpath(adminDisk).autoDelete(true).controllerPort(0).deviceSlot(1) HardDisk hardDisk = HardDisk.builder().diskpath(adminDisk).autoDelete(true).controllerPort(0).deviceSlot(1)
@ -174,46 +209,19 @@ public class MastersLoadingCache extends AbstractLoadingCache<Image, Master> {
.controller(ideController).forceOverwrite(true).cleanUpMode(CleanupMode.Full).build(); .controller(ideController).forceOverwrite(true).cleanUpMode(CleanupMode.Full).build();
NetworkAdapter networkAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.NAT) NetworkAdapter networkAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.NAT)
.tcpRedirectRule("127.0.0.1", MASTER_PORT , "", 22).build(); .tcpRedirectRule("127.0.0.1", MASTER_PORT, "", 22).build();
NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(networkAdapter) NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(networkAdapter)
.slot(0L).build(); .slot(0L).build();
NetworkSpec networkSpec = NetworkSpec.builder().addNIC(networkInterfaceCard).build(); NetworkSpec networkSpec = NetworkSpec.builder().addNIC(networkInterfaceCard).build();
MasterSpec masterSpec = MasterSpec return MasterSpec
.builder() .builder()
.vm(vmSpecification) .vm(vmSpecification)
.iso(IsoSpec.builder().sourcePath(localIsoUrl) .iso(IsoSpec.builder().sourcePath(localIsoUrl)
.installationScript(installationKeySequence.replace("HOSTNAME", vmSpecification.getVmName())) .installationScript(installationKeySequence.replace("HOSTNAME", vmSpecification.getVmName()))
.build()).network(networkSpec).build(); .build()).network(networkSpec).build();
IMachine masterMachine;
// ready the preseed file server
PreseedCfgServer server = new PreseedCfgServer();
try {
// try and find a master machine in vbox
masterMachine = manager.get().getVBox().findMachine(vmName);
} catch (VBoxException e) {
if (machineNotFoundException(e)) {
server.start(preconfigurationUrl,currentImage.preseed_cfg);
// create the master machine if it can't be found
masterMachine = masterCreatorAndInstaller.apply(masterSpec);
} else {
throw e;
}
} finally {
server.stop();
}
Master master = Master.builder().machine(masterMachine).spec(masterSpec).build();
masters.put(key.getId(), master);
return master;
} }
@Override @Override

View File

@ -118,12 +118,18 @@ public class NodeCreator implements Function<NodeSpec, NodeAndInitialCredentials
progress.waitForCompletion(-1); progress.waitForCompletion(-1);
session.unlockMachine(); session.unlockMachine();
} }
String masterNameWithoutPrefix = master.getSpec().getVmSpec().getVmName().replace(VIRTUALBOX_IMAGE_PREFIX, ""); String masterNameWithoutPrefix = master.getMachine().getName().replace(VIRTUALBOX_IMAGE_PREFIX, "");
String cloneName = VIRTUALBOX_NODE_PREFIX + masterNameWithoutPrefix + VIRTUALBOX_NODE_NAME_SEPARATOR String cloneName = VIRTUALBOX_NODE_PREFIX + masterNameWithoutPrefix + VIRTUALBOX_NODE_NAME_SEPARATOR
+ nodeSpec.getTag() + VIRTUALBOX_NODE_NAME_SEPARATOR + nodeSpec.getName(); + nodeSpec.getTag() + VIRTUALBOX_NODE_NAME_SEPARATOR + nodeSpec.getName();
VmSpec cloneVmSpec = VmSpec.builder().id(cloneName).name(cloneName).memoryMB(512).cleanUpMode(CleanupMode.Full) int ram = 512;
if (nodeSpec.getTemplate() != null && nodeSpec.getTemplate().getHardware() != null
&& nodeSpec.getTemplate().getHardware().getRam() > 0) {
ram = nodeSpec.getTemplate().getHardware().getRam();
}
VmSpec cloneVmSpec = VmSpec.builder().id(cloneName).name(cloneName).memoryMB(ram).cleanUpMode(CleanupMode.Full)
.forceOverwrite(true).build(); .forceOverwrite(true).build();
// CASE NAT + HOST-ONLY // CASE NAT + HOST-ONLY

View File

@ -20,15 +20,13 @@
package org.jclouds.virtualbox.functions; package org.jclouds.virtualbox.functions;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.Resource;
import javax.inject.Named;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.virtualbox_4_1.IMachine; import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.IProgress; import org.virtualbox_4_1.IProgress;
import org.virtualbox_4_1.ISession; import org.virtualbox_4_1.ISession;
import org.virtualbox_4_1.ISnapshot; import org.virtualbox_4_1.ISnapshot;
import org.virtualbox_4_1.MachineState;
import org.virtualbox_4_1.VirtualBoxManager; import org.virtualbox_4_1.VirtualBoxManager;
import com.google.common.base.Function; import com.google.common.base.Function;
@ -40,55 +38,80 @@ import com.google.common.base.Throwables;
*/ */
public class TakeSnapshotIfNotAlreadyAttached implements Function<IMachine, ISnapshot> { public class TakeSnapshotIfNotAlreadyAttached implements Function<IMachine, ISnapshot> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
private Supplier<VirtualBoxManager> manager; private Supplier<VirtualBoxManager> manager;
private String snapshotName; private String snapshotName;
private String snapshotDesc; private String snapshotDesc;
private Logger logger;
public TakeSnapshotIfNotAlreadyAttached(Supplier<VirtualBoxManager> manager, String snapshotName, String snapshotDesc) { public TakeSnapshotIfNotAlreadyAttached(Supplier<VirtualBoxManager> manager, String snapshotName,
String snapshotDesc, Logger logger) {
this.manager = manager; this.manager = manager;
this.snapshotName = snapshotName; this.snapshotName = snapshotName;
this.snapshotDesc = snapshotDesc; this.snapshotDesc = snapshotDesc;
this.logger = logger;
} }
@Override @Override
public ISnapshot apply(@Nullable IMachine machine) { public ISnapshot apply(@Nullable IMachine machine) {
// Snapshot a machine // Snapshot a machine
ISession session = null; ISession session = null;
if (machine.getCurrentSnapshot() == null) { ISnapshot snap = machine.getCurrentSnapshot();
int retries = 10;
while (true) { if (snap == null) {
try { try {
session = manager.get().openMachineSession(machine); session = manager.get().openMachineSession(machine);
IProgress progress = session.getConsole().takeSnapshot(snapshotName, snapshotDesc); logger.debug("No snapshot available taking new one: %s (description: %s) taken from %s", snapshotName,
progress.waitForCompletion(-1); snapshotDesc, machine.getName());
logger.debug("Snapshot %s (description: %s) taken from %s", snapshotName, snapshotDesc, int retries = 10;
machine.getName()); while (true) {
break; try {
} catch (Exception e) {
if (e.getMessage().contains("VirtualBox error: The object is not ready")) { // running machines need to be pause before a snapshot can be taken
retries--; // due to a vbox bug see https://www.virtualbox.org/ticket/9255
if (retries == 0) { boolean paused = false;
logger.error(e, if (machine.getState() == MachineState.Running) {
"Problem creating snapshot (too many retries) %s (descripton: %s) from machine %s", session.getConsole().pause();
snapshotName, snapshotDesc, machine.getName()); paused = true;
throw Throwables.propagate(e);
} }
}
logger.error(e, "Problem creating snapshot %s (descripton: %s) from machine %s", snapshotName, IProgress progress = session.getConsole().takeSnapshot(snapshotName, snapshotDesc);
snapshotDesc, machine.getName()); progress.waitForCompletion(-1);
throw Throwables.propagate(e);
} finally { if (paused) {
if (session != null) { session.getConsole().resume();
session.unlockMachine(); }
snap = machine.getCurrentSnapshot();
logger.debug("Snapshot %s (description: %s) taken from %s", snapshotName, snapshotDesc,
machine.getName());
break;
} catch (Exception e) {
if (e.getMessage().contains("VirtualBox error: The object is not ready")
|| e.getMessage().contains("This machine does not have any snapshots")) {
retries--;
if (retries == 0) {
logger.error(e,
"Problem creating snapshot (too many retries) %s (descripton: %s) from machine %s",
snapshotName, snapshotDesc, machine.getName());
throw Throwables.propagate(e);
}
Thread.sleep(1000L);
continue;
}
logger.error(e, "Problem creating snapshot %s (descripton: %s) from machine %s", snapshotName,
snapshotDesc, machine.getName());
throw Throwables.propagate(e);
} }
} }
} catch (Exception e) {
Throwables.propagate(e);
} finally {
if (session != null) {
manager.get().closeMachineSession(session);
}
} }
}
return machine.getCurrentSnapshot();
}
}
return snap;
}
} }

View File

@ -26,7 +26,6 @@ import static org.jclouds.compute.options.RunScriptOptions.Builder.runAsRoot;
import java.net.URI; import java.net.URI;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
@ -74,10 +73,10 @@ public class StartVBoxIfNotAlreadyRunning implements Supplier<VirtualBoxManager>
this.host = checkNotNull(host, "host"); this.host = checkNotNull(host, "host");
this.providerSupplier = checkNotNull(providerSupplier, "endpoint to virtualbox websrvd is needed"); this.providerSupplier = checkNotNull(providerSupplier, "endpoint to virtualbox websrvd is needed");
this.managerForNode = checkNotNull(managerForNode, "managerForNode"); this.managerForNode = checkNotNull(managerForNode, "managerForNode");
start();
} }
@PostConstruct public synchronized void start() {
public void start() {
URI provider = providerSupplier.get(); URI provider = providerSupplier.get();
if (!socketTester.apply(new IPSocket(provider.getHost(), provider.getPort()))) { if (!socketTester.apply(new IPSocket(provider.getHost(), provider.getPort()))) {
logger.debug("disabling password access"); logger.debug("disabling password access");

View File

@ -17,7 +17,7 @@
* under the License. * under the License.
*/ */
/* /*
U * Licensed to jclouds, Inc. (jclouds) under one or more U * Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file * contributor license agreements. See the NOTICE file
* distributed with this work for additional information * distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file * regarding copyright ownership. jclouds licenses this file
@ -93,8 +93,8 @@ public class UnregisterMachineIfExistsAndDeleteItsMedia implements Function<IMac
} }
} }
List<IMedium> filteredMediaToBeDeleted = Lists.newArrayList(transform(filter(mediaToBeDeleted, List<IMedium> filteredMediaToBeDeleted = Lists.newArrayList(transform(
new AutoDeleteHardDiskPredicate(vmSpec)), new DeleteChildrenOfMedium())); filter(mediaToBeDeleted, new AutoDeleteHardDiskPredicate(vmSpec)), new DeleteChildrenOfMedium()));
if (!filteredMediaToBeDeleted.isEmpty()) { if (!filteredMediaToBeDeleted.isEmpty()) {
try { try {
@ -105,7 +105,7 @@ public class UnregisterMachineIfExistsAndDeleteItsMedia implements Function<IMac
Throwables.propagate(e); Throwables.propagate(e);
} }
} }
return null; return null;
} }

View File

@ -105,8 +105,17 @@ public class UnregisterMachineIfExistsAndForceDeleteItsMedia implements Function
checkNotNull(medium.getChildren()); checkNotNull(medium.getChildren());
if (medium.getDeviceType().equals(DeviceType.HardDisk)) { if (medium.getDeviceType().equals(DeviceType.HardDisk)) {
for (IMedium child : medium.getChildren()) { for (IMedium child : medium.getChildren()) {
IProgress deletion = child.deleteStorage(); try {
deletion.waitForCompletion(-1); IProgress deletion = child.deleteStorage();
deletion.waitForCompletion(-1);
} catch (Exception e) {
// work around media that are still attached to other vm's. this can happen when a
// running node is used to create a new image and then an attempt at deleting it
// is made
if (e.getMessage().contains("is still attached to the following")) {
logger.warn("Media could not be deleted. Ignoring... [Message %s]", e.getMessage());
}
}
} }
} }
return medium; return medium;

View File

@ -39,6 +39,7 @@ import org.jclouds.concurrent.MoreExecutors;
import org.jclouds.concurrent.config.ExecutorServiceModule; import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.config.ValueOfConfigurationKeyOrNull; import org.jclouds.config.ValueOfConfigurationKeyOrNull;
import org.jclouds.rest.annotations.BuildVersion; import org.jclouds.rest.annotations.BuildVersion;
import org.jclouds.sshj.config.SshjSshClientModule;
import org.jclouds.virtualbox.config.VirtualBoxConstants; import org.jclouds.virtualbox.config.VirtualBoxConstants;
import org.jclouds.virtualbox.domain.HardDisk; import org.jclouds.virtualbox.domain.HardDisk;
import org.jclouds.virtualbox.domain.IsoSpec; import org.jclouds.virtualbox.domain.IsoSpec;
@ -217,6 +218,11 @@ public class BaseVirtualBoxClientLiveTest extends BaseComputeServiceContextLiveT
"/default-images.yaml")).get(); "/default-images.yaml")).get();
return images.get(Iterables.getOnlyElement(Iterables.filter(images.keySet(), new DefaultImagePredicate()))); return images.get(Iterables.getOnlyElement(Iterables.filter(images.keySet(), new DefaultImagePredicate())));
} }
@Override
protected Module getSshModule() {
return new SshjSshClientModule();
}
@AfterClass(groups = "live") @AfterClass(groups = "live")
protected void tearDown() throws Exception { protected void tearDown() throws Exception {

View File

@ -27,6 +27,7 @@ import javax.inject.Inject;
import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials; import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials;
import org.jclouds.compute.domain.ExecResponse; import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.domain.LoginCredentials; import org.jclouds.domain.LoginCredentials;
@ -76,7 +77,7 @@ public class VirtualBoxComputeServiceAdapterLiveTest extends BaseVirtualBoxClien
@Test @Test
public void testListHardwareProfiles() { public void testListHardwareProfiles() {
Iterable<IMachine> profiles = adapter.listHardwareProfiles(); Iterable<Hardware> profiles = adapter.listHardwareProfiles();
assertTrue(!Iterables.isEmpty(profiles)); assertTrue(!Iterables.isEmpty(profiles));
} }

View File

@ -0,0 +1,40 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.virtualbox.compute;
import org.jclouds.compute.internal.BaseImageExtensionLiveTest;
import org.jclouds.sshj.config.SshjSshClientModule;
import org.testng.annotations.Test;
import com.google.inject.Module;
@Test(groups = "live", singleThreaded = true, testName = "VirtualBoxImageExtensionLiveTest")
public class VirtualBoxImageExtensionLiveTest extends BaseImageExtensionLiveTest {
public VirtualBoxImageExtensionLiveTest() {
provider = "virtualbox";
}
@Override
protected Module getSshModule() {
return new SshjSshClientModule();
}
}

View File

@ -20,7 +20,7 @@
package org.jclouds.virtualbox.functions; package org.jclouds.virtualbox.functions;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX; import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE; import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE;
@ -56,9 +56,7 @@ import org.virtualbox_4_1.StorageBus;
import com.google.common.base.CaseFormat; import com.google.common.base.CaseFormat;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.Injector; import com.google.inject.Injector;
@ -166,15 +164,14 @@ public class CreateAndInstallVmLiveTest extends BaseVirtualBoxClientLiveTest {
checkState(sshResponds.apply(client), "timed out waiting for guest %s to be accessible via ssh", checkState(sshResponds.apply(client), "timed out waiting for guest %s to be accessible via ssh",
machine.getName()); machine.getName());
String vboxVersion = Iterables.get( String version = machineUtils.sharedLockMachineAndApplyToSession(machine.getName(), new Function<ISession, String>() {
Splitter.on('r').split(context.getProviderSpecificContext().getBuildVersion()), 0); @Override
assertEquals(vboxVersion, public String apply(ISession session) {
machineUtils.sharedLockMachineAndApplyToSession(machine.getName(), new Function<ISession, String>() { return session.getMachine().getGuestPropertyValue("/VirtualBox/GuestAdd/Version");
@Override }
public String apply(ISession session) { });
return session.getMachine().getGuestPropertyValue("/VirtualBox/GuestAdd/Version");
} assertTrue(version != null && !version.isEmpty());
}));
} finally { } finally {
for (VmSpec spec : ImmutableSet.of(machineSpec.getVmSpec())) { for (VmSpec spec : ImmutableSet.of(machineSpec.getVmSpec())) {
machineController.ensureMachineIsShutdown(spec.getVmName()); machineController.ensureMachineIsShutdown(spec.getVmName());

View File

@ -34,6 +34,7 @@ import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.json.Json; import org.jclouds.json.Json;
import org.jclouds.json.config.GsonModule; import org.jclouds.json.config.GsonModule;
import org.jclouds.virtualbox.config.VirtualBoxConstants;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import org.virtualbox_4_1.IGuestOSType; import org.virtualbox_4_1.IGuestOSType;
import org.virtualbox_4_1.IMachine; import org.virtualbox_4_1.IMachine;
@ -48,7 +49,7 @@ public class IMachineToImageTest {
Map<OsFamily, Map<String, String>> map = new BaseComputeServiceContextModule() { Map<OsFamily, Map<String, String>> map = new BaseComputeServiceContextModule() {
}.provideOsVersionMap(new ComputeServiceConstants.ReferenceData(), Guice.createInjector(new GsonModule()) }.provideOsVersionMap(new ComputeServiceConstants.ReferenceData(), Guice.createInjector(new GsonModule())
.getInstance(Json.class)); .getInstance(Json.class));
@Test @Test
public void testConvert() throws Exception { public void testConvert() throws Exception {
@ -61,6 +62,7 @@ public class IMachineToImageTest {
expect(vbm.getVBox()).andReturn(vBox).anyTimes(); expect(vbm.getVBox()).andReturn(vBox).anyTimes();
expect(vm.getOSTypeId()).andReturn("os-type").anyTimes(); expect(vm.getOSTypeId()).andReturn("os-type").anyTimes();
expect(vm.getName()).andReturn(VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX + "my-vm-id").anyTimes();
expect(vBox.getGuestOSType(eq("os-type"))).andReturn(guestOsType); expect(vBox.getGuestOSType(eq("os-type"))).andReturn(guestOsType);
expect(vm.getDescription()).andReturn("my-ubuntu-machine").anyTimes(); expect(vm.getDescription()).andReturn("my-ubuntu-machine").anyTimes();
expect(guestOsType.getDescription()).andReturn(linuxDescription).anyTimes(); expect(guestOsType.getDescription()).andReturn(linuxDescription).anyTimes();
@ -77,6 +79,7 @@ public class IMachineToImageTest {
assertTrue(image.getOperatingSystem().is64Bit()); assertTrue(image.getOperatingSystem().is64Bit());
assertEquals(image.getOperatingSystem().getFamily(), OsFamily.UBUNTU); assertEquals(image.getOperatingSystem().getFamily(), OsFamily.UBUNTU);
assertEquals(image.getOperatingSystem().getVersion(), "10.04"); assertEquals(image.getOperatingSystem().getVersion(), "10.04");
assertEquals(image.getId(), "my-vm-id");
} }
@ -91,6 +94,7 @@ public class IMachineToImageTest {
String vmDescription = "ubuntu-11.04-server-i386"; String vmDescription = "ubuntu-11.04-server-i386";
expect(vbm.getVBox()).andReturn(vBox).anyTimes(); expect(vbm.getVBox()).andReturn(vBox).anyTimes();
expect(vm.getName()).andReturn(VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX + "my-vm-id").anyTimes();
expect(vm.getOSTypeId()).andReturn("os-type").anyTimes(); expect(vm.getOSTypeId()).andReturn("os-type").anyTimes();
expect(vBox.getGuestOSType(eq("os-type"))).andReturn(guestOsType); expect(vBox.getGuestOSType(eq("os-type"))).andReturn(guestOsType);
expect(vm.getDescription()).andReturn(vmDescription).anyTimes(); expect(vm.getDescription()).andReturn(vmDescription).anyTimes();
@ -108,6 +112,7 @@ public class IMachineToImageTest {
assertTrue(image.getOperatingSystem().is64Bit()); assertTrue(image.getOperatingSystem().is64Bit());
assertEquals(image.getOperatingSystem().getFamily(), OsFamily.UBUNTU); assertEquals(image.getOperatingSystem().getFamily(), OsFamily.UBUNTU);
assertEquals(image.getOperatingSystem().getVersion(), "11.04"); assertEquals(image.getOperatingSystem().getVersion(), "11.04");
assertEquals(image.getId(), "my-vm-id");
} }
@ -121,6 +126,7 @@ public class IMachineToImageTest {
expect(vbm.getVBox()).andReturn(vBox).anyTimes(); expect(vbm.getVBox()).andReturn(vBox).anyTimes();
expect(vm.getName()).andReturn(VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX + "my-vm-id").anyTimes();
String unknownOsDescription = "SomeOtherOs 2.04"; String unknownOsDescription = "SomeOtherOs 2.04";
expect(vm.getOSTypeId()).andReturn("os-type").anyTimes(); expect(vm.getOSTypeId()).andReturn("os-type").anyTimes();
expect(vm.getDescription()).andReturn("my-unknown-machine").anyTimes(); expect(vm.getDescription()).andReturn("my-unknown-machine").anyTimes();
@ -136,6 +142,7 @@ public class IMachineToImageTest {
assertEquals(image.getOperatingSystem().getDescription(), "SomeOtherOs 2.04"); assertEquals(image.getOperatingSystem().getDescription(), "SomeOtherOs 2.04");
assertEquals(image.getOperatingSystem().getVersion(), ""); assertEquals(image.getOperatingSystem().getVersion(), "");
assertEquals(image.getId(), "my-vm-id");
} }

View File

@ -24,6 +24,7 @@ import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify; import static org.easymock.EasyMock.verify;
import org.jclouds.logging.Logger;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import org.virtualbox_4_1.IConsole; import org.virtualbox_4_1.IConsole;
import org.virtualbox_4_1.IMachine; import org.virtualbox_4_1.IMachine;
@ -31,6 +32,7 @@ import org.virtualbox_4_1.IProgress;
import org.virtualbox_4_1.ISession; import org.virtualbox_4_1.ISession;
import org.virtualbox_4_1.ISnapshot; import org.virtualbox_4_1.ISnapshot;
import org.virtualbox_4_1.IVirtualBox; import org.virtualbox_4_1.IVirtualBox;
import org.virtualbox_4_1.MachineState;
import org.virtualbox_4_1.VirtualBoxManager; import org.virtualbox_4_1.VirtualBoxManager;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
@ -55,6 +57,7 @@ public class TakeSnapshotIfNotAlreadyAttachedTest {
IProgress progress = createNiceMock(IProgress.class); IProgress progress = createNiceMock(IProgress.class);
ISnapshot snapshot = createNiceMock(ISnapshot.class); ISnapshot snapshot = createNiceMock(ISnapshot.class);
expect(machine.getCurrentSnapshot()).andReturn(snapshot).anyTimes(); expect(machine.getCurrentSnapshot()).andReturn(snapshot).anyTimes();
expect(machine.getState()).andReturn(MachineState.PoweredOff).anyTimes();
expect(manager.openMachineSession(machine)).andReturn(session); expect(manager.openMachineSession(machine)).andReturn(session);
@ -66,7 +69,7 @@ public class TakeSnapshotIfNotAlreadyAttachedTest {
session.unlockMachine(); session.unlockMachine();
replay(manager, machine, vBox, session, console, progress); replay(manager, machine, vBox, session, console, progress);
new TakeSnapshotIfNotAlreadyAttached(Suppliers.ofInstance(manager), snapshotName, snapshotDesc) new TakeSnapshotIfNotAlreadyAttached(Suppliers.ofInstance(manager), snapshotName, snapshotDesc, Logger.CONSOLE)
.apply(machine); .apply(machine);
verify(machine); verify(machine);
@ -87,6 +90,7 @@ public class TakeSnapshotIfNotAlreadyAttachedTest {
expect(progress.getCompleted()).andReturn(true); expect(progress.getCompleted()).andReturn(true);
expect(machine.getCurrentSnapshot()).andReturn(null).anyTimes(); expect(machine.getCurrentSnapshot()).andReturn(null).anyTimes();
expect(manager.openMachineSession(machine)).andReturn(session); expect(manager.openMachineSession(machine)).andReturn(session);
expect(machine.getState()).andReturn(MachineState.PoweredOff).anyTimes();
expect(machine.getName()).andReturn("machine").anyTimes(); expect(machine.getName()).andReturn("machine").anyTimes();
expect(session.getConsole()).andReturn(console); expect(session.getConsole()).andReturn(console);
@ -96,7 +100,7 @@ public class TakeSnapshotIfNotAlreadyAttachedTest {
session.unlockMachine(); session.unlockMachine();
replay(manager, machine, vBox, session, console, progress); replay(manager, machine, vBox, session, console, progress);
new TakeSnapshotIfNotAlreadyAttached(Suppliers.ofInstance(manager), snapshotName, snapshotDesc) new TakeSnapshotIfNotAlreadyAttached(Suppliers.ofInstance(manager), snapshotName, snapshotDesc, Logger.CONSOLE)
.apply(machine); .apply(machine);
verify(machine); verify(machine);

View File

@ -21,6 +21,7 @@ package org.jclouds.virtualbox.functions.admin;
import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify; import static org.easymock.EasyMock.verify;
import static org.jclouds.compute.options.RunScriptOptions.Builder.runAsRoot; import static org.jclouds.compute.options.RunScriptOptions.Builder.runAsRoot;
@ -58,10 +59,9 @@ public class StartVBoxIfNotAlreadyRunningLiveTest {
String identity = "adminstrator"; String identity = "adminstrator";
String credential = "12345"; String credential = "12345";
expect(client.seconds(3)).andReturn(client); expect(client.seconds(3)).andReturn(client);
expect(client.apply(new IPSocket(provider.getHost(), provider.getPort()))).andReturn(true).anyTimes();
expect(client.apply(new IPSocket(provider.getHost(), provider.getPort()))).andReturn(true);
manager.connect(provider.toASCIIString(), "", ""); manager.connect(provider.toASCIIString(), "", "");
expectLastCall().anyTimes();
replay(manager, runScriptOnNodeFactory, client); replay(manager, runScriptOnNodeFactory, client);
@ -87,17 +87,18 @@ public class StartVBoxIfNotAlreadyRunningLiveTest {
String credential = "12345"; String credential = "12345";
expect(client.seconds(3)).andReturn(client); expect(client.seconds(3)).andReturn(client);
expect(client.apply(new IPSocket(provider.getHost(), provider.getPort()))).andReturn(false); expect(client.apply(new IPSocket(provider.getHost(), provider.getPort()))).andReturn(false).once().andReturn(true).once();
expect( expect(
runScriptOnNodeFactory.create(host, Statements.exec("VBoxManage setproperty websrvauthlibrary null"), runScriptOnNodeFactory.create(host, Statements.exec("VBoxManage setproperty websrvauthlibrary null"),
runAsRoot(false).wrapInInitScript(false))).andReturn(runScriptOnNode); runAsRoot(false).wrapInInitScript(false))).andReturn(runScriptOnNode);
expect(runScriptOnNode.init()).andReturn(runScriptOnNode); expect(runScriptOnNode.init()).andReturn(runScriptOnNode);
expect(runScriptOnNode.call()).andReturn(new ExecResponse("", "", 0)); expect(runScriptOnNode.call()).andReturn(new ExecResponse("", "", 0));
expect(client.apply(new IPSocket(provider.getHost(), provider.getPort()))).andReturn(true);
expect( expect(
runScriptOnNodeFactory.create(host, Statements.exec("vboxwebsrv -t 10000 -v -b"), runAsRoot(false) runScriptOnNodeFactory.create(host, Statements.exec("vboxwebsrv -t 10000 -v -b"), runAsRoot(false)
.wrapInInitScript(false).blockOnComplete(false).nameTask("vboxwebsrv"))).andReturn( .wrapInInitScript(false).blockOnComplete(false).nameTask("vboxwebsrv"))).andReturn(
runScriptOnNode); runScriptOnNode);
expect(runScriptOnNode.init()).andReturn(runScriptOnNode); expect(runScriptOnNode.init()).andReturn(runScriptOnNode);
expect(runScriptOnNode.call()).andReturn(new ExecResponse("", "", 0)); expect(runScriptOnNode.call()).andReturn(new ExecResponse("", "", 0));
@ -105,7 +106,7 @@ public class StartVBoxIfNotAlreadyRunningLiveTest {
replay(manager, runScriptOnNodeFactory, runScriptOnNode, client); replay(manager, runScriptOnNodeFactory, runScriptOnNode, client);
new StartVBoxIfNotAlreadyRunning((Function) Functions.constant(manager), runScriptOnNodeFactory, client, new StartVBoxIfNotAlreadyRunning((Function) Functions.constant(manager), runScriptOnNodeFactory, client,
Suppliers.ofInstance(host), Suppliers.ofInstance(provider), identity, credential).start(); Suppliers.ofInstance(host), Suppliers.ofInstance(provider), identity, credential);
verify(manager, runScriptOnNodeFactory, runScriptOnNode, client); verify(manager, runScriptOnNodeFactory, runScriptOnNode, client);
} }

View File

@ -39,7 +39,7 @@
</appender> </appender>
<root> <root>
<level value="debug" /> <level value="DEBUG" />
<appender-ref ref="CONSOLE" /> <appender-ref ref="CONSOLE" />
</root> </root>
@ -49,7 +49,7 @@
</logger> </logger>
<logger name="jclouds.wire"> <logger name="jclouds.wire">
<level value="INFO" /> <level value="DEBUG" />
<appender-ref ref="WIREFILE" /> <appender-ref ref="WIREFILE" />
</logger> </logger>

View File

@ -42,6 +42,7 @@ import org.jclouds.aws.ec2.domain.PlacementGroup.State;
import org.jclouds.aws.util.AWSUtils; import org.jclouds.aws.util.AWSUtils;
import org.jclouds.collect.Memoized; import org.jclouds.collect.Memoized;
import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.ImageExtension;
import org.jclouds.compute.RunNodesException; import org.jclouds.compute.RunNodesException;
import org.jclouds.compute.callables.RunScriptOnNode; import org.jclouds.compute.callables.RunScriptOnNode;
import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.Hardware;
@ -72,6 +73,7 @@ import org.jclouds.util.Preconditions2;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
@ -111,12 +113,13 @@ public class AWSEC2ComputeService extends EC2ComputeService {
@Named("SECURITY") LoadingCache<RegionAndName, String> securityGroupMap, @Named("SECURITY") LoadingCache<RegionAndName, String> securityGroupMap,
@Named("PLACEMENT") LoadingCache<RegionAndName, String> placementGroupMap, @Named("PLACEMENT") LoadingCache<RegionAndName, String> placementGroupMap,
@Named("DELETED") Predicate<PlacementGroup> placementGroupDeleted, @Named("DELETED") Predicate<PlacementGroup> placementGroupDeleted,
@Named(PROPERTY_EC2_GENERATE_INSTANCE_NAMES) boolean generateInstanceNames, AWSEC2AsyncClient aclient) { @Named(PROPERTY_EC2_GENERATE_INSTANCE_NAMES) boolean generateInstanceNames, AWSEC2AsyncClient aclient,
Optional<ImageExtension> imageExtension) {
super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy, super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy,
stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated, stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
nodeSuspended, initScriptRunnerFactory, runScriptOnNodeFactory, initAdminAccess, persistNodeCredentials, nodeSuspended, initScriptRunnerFactory, runScriptOnNodeFactory, initAdminAccess, persistNodeCredentials,
timeouts, executor, ec2Client, credentialsMap, securityGroupMap); timeouts, executor, ec2Client, credentialsMap, securityGroupMap, imageExtension);
this.ec2Client = ec2Client; this.ec2Client = ec2Client;
this.placementGroupMap = placementGroupMap; this.placementGroupMap = placementGroupMap;
this.placementGroupDeleted = placementGroupDeleted; this.placementGroupDeleted = placementGroupDeleted;

View File

@ -69,12 +69,10 @@ public class AWSEC2ListNodesStrategy extends EC2ListNodesStrategy {
@Override @Override
protected Iterable<? extends RunningInstance> pollRunningInstances() { protected Iterable<? extends RunningInstance> pollRunningInstances() {
Iterable<? extends AWSRunningInstance> spots = filter(transform(concat(transformParallel(regions.get(), Iterable<? extends AWSRunningInstance> spots = filter(transform(concat(transformParallel(regions.get(),
new Function<String, Future<Set<SpotInstanceRequest>>>() { new Function<String, Future<? extends Set<SpotInstanceRequest>>>() {
@SuppressWarnings("unchecked")
@Override @Override
public Future<Set<SpotInstanceRequest>> apply(String from) { public Future<? extends Set<SpotInstanceRequest>> apply(String from) {
return (Future<Set<SpotInstanceRequest>>) client.getSpotInstanceServices() return client.getSpotInstanceServices()
.describeSpotInstanceRequestsInRegion(from); .describeSpotInstanceRequestsInRegion(from);
} }

View File

@ -31,6 +31,7 @@ import javax.inject.Singleton;
import org.jclouds.Constants; import org.jclouds.Constants;
import org.jclouds.collect.Memoized; import org.jclouds.collect.Memoized;
import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.ImageExtension;
import org.jclouds.compute.callables.RunScriptOnNode; import org.jclouds.compute.callables.RunScriptOnNode;
import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
@ -53,6 +54,7 @@ import org.jclouds.domain.Location;
import org.jclouds.gogrid.compute.options.GoGridTemplateOptions; import org.jclouds.gogrid.compute.options.GoGridTemplateOptions;
import org.jclouds.scriptbuilder.functions.InitAdminAccess; import org.jclouds.scriptbuilder.functions.InitAdminAccess;
import com.google.common.base.Optional;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
@ -74,12 +76,12 @@ public class GoGridComputeService extends BaseComputeService {
@Named("NODE_SUSPENDED") Predicate<AtomicReference<NodeMetadata>> nodeSuspended, @Named("NODE_SUSPENDED") Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess, InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess,
RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials, Timeouts timeouts, RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) { @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, Optional<ImageExtension> imageExtension) {
super(context, credentialStore, images, hardwareProfiles, locations, listNodesStrategy, getNodeMetadataStrategy, super(context, credentialStore, images, hardwareProfiles, locations, listNodesStrategy, getNodeMetadataStrategy,
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, resumeNodeStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, resumeNodeStrategy,
suspendNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated, suspendNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials, timeouts, nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials, timeouts,
executor); executor, imageExtension);
} }
/** /**

View File

@ -0,0 +1,44 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.hpcloud.compute.compute;
import org.jclouds.compute.internal.BaseImageExtensionLiveTest;
import org.jclouds.sshj.config.SshjSshClientModule;
import org.testng.annotations.Test;
import com.google.inject.Module;
/**
*
* @author David Alves
*
*/
@Test(groups = "live", singleThreaded = true, testName = "HPCloudComputeImageExtensionLivetest")
public class HPCloudComputeImageExtensionLivetest extends BaseImageExtensionLiveTest {
public HPCloudComputeImageExtensionLivetest() {
provider = "hpcloud-compute";
}
@Override
protected Module getSshModule() {
return new SshjSshClientModule();
}
}

View File

@ -31,6 +31,7 @@ import javax.inject.Singleton;
import org.jclouds.Constants; import org.jclouds.Constants;
import org.jclouds.collect.Memoized; import org.jclouds.collect.Memoized;
import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.ImageExtension;
import org.jclouds.compute.callables.RunScriptOnNode; import org.jclouds.compute.callables.RunScriptOnNode;
import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
@ -55,6 +56,7 @@ import org.libvirt.Connect;
import org.libvirt.StorageVol; import org.libvirt.StorageVol;
import org.xml.sax.InputSource; import org.xml.sax.InputSource;
import com.google.common.base.Optional;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.base.Throwables; import com.google.common.base.Throwables;
@ -85,12 +87,13 @@ public class LibvirtComputeService extends BaseComputeService {
@Named("NODE_SUSPENDED") Predicate<NodeMetadata> nodeSuspended, @Named("NODE_SUSPENDED") Predicate<NodeMetadata> nodeSuspended,
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess, InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess,
RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials, RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials,
Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, Connect client) { Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, Connect client,
Optional<ImageExtension> imageExtension) {
super(context, credentialStore, images, hardwareProfiles, locations, listNodesStrategy, getNodeMetadataStrategy, super(context, credentialStore, images, hardwareProfiles, locations, listNodesStrategy, getNodeMetadataStrategy,
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, resumeNodeStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, resumeNodeStrategy,
suspendNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated, suspendNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials, nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials,
timeouts, executor); timeouts, executor, imageExtension);
this.client = client; this.client = client;
} }