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
diff --git a/apis/cloudloadbalancers/src/main/java/org/jclouds/cloudloadbalancers/loadbalancer/strategy/CloudLoadBalancersListLoadBalancersStrategy.java b/apis/cloudloadbalancers/src/main/java/org/jclouds/cloudloadbalancers/loadbalancer/strategy/CloudLoadBalancersListLoadBalancersStrategy.java
index a720ce7..9154689 100644
--- a/apis/cloudloadbalancers/src/main/java/org/jclouds/cloudloadbalancers/loadbalancer/strategy/CloudLoadBalancersListLoadBalancersStrategy.java
+++ b/apis/cloudloadbalancers/src/main/java/org/jclouds/cloudloadbalancers/loadbalancer/strategy/CloudLoadBalancersListLoadBalancersStrategy.java
@@ -72,7 +72,7 @@
@Override
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
public ListenableFuture<Set<LoadBalancer>> apply(String from) {
diff --git a/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/CloudSigmaComputeServiceAdapter.java b/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/CloudSigmaComputeServiceAdapter.java
index 52ade29..74327d0 100644
--- a/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/CloudSigmaComputeServiceAdapter.java
+++ b/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/CloudSigmaComputeServiceAdapter.java
@@ -56,6 +56,7 @@
import org.jclouds.domain.Location;
import org.jclouds.domain.LoginCredentials;
import org.jclouds.logging.Logger;
+import org.jclouds.util.Iterables2;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
@@ -170,8 +171,8 @@
*/
@Override
public Iterable<DriveInfo> listImages() {
- Iterable<DriveInfo> drives = transformParallel(client.listStandardDrives(),
- new Function<String, Future<DriveInfo>>() {
+ Iterable<? extends DriveInfo> drives = transformParallel(client.listStandardDrives(),
+ new Function<String, Future<? extends DriveInfo>>() {
@Override
public Future<DriveInfo> apply(String input) {
@@ -190,7 +191,7 @@
return "seedDriveCache()";
}
}, executor, null, logger, "drives");
- return filter(drives, PREINSTALLED_DISK);
+ return Iterables2.concreteCopy(filter(drives, PREINSTALLED_DISK));
}
@SuppressWarnings("unchecked")
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java b/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java
index 3ea04e1..c30ec5a 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java
@@ -25,8 +25,8 @@
import static org.jclouds.util.Preconditions2.checkNotEmpty;
import java.util.Map;
-import java.util.Set;
import java.util.Map.Entry;
+import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicReference;
@@ -39,6 +39,7 @@
import org.jclouds.aws.util.AWSUtils;
import org.jclouds.collect.Memoized;
import org.jclouds.compute.ComputeServiceContext;
+import org.jclouds.compute.ImageExtension;
import org.jclouds.compute.callables.RunScriptOnNode;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image;
@@ -69,12 +70,13 @@
import com.google.common.annotations.VisibleForTesting;
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.cache.LoadingCache;
import com.google.common.collect.ImmutableMultimap;
-import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableMultimap.Builder;
+import com.google.common.collect.ImmutableSet;
import com.google.inject.Inject;
/**
@@ -101,12 +103,13 @@
RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
@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,
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy, stopNodeStrategy,
templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated, nodeSuspended,
initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials, timeouts,
- executor);
+ executor, imageExtension);
this.ec2Client = ec2Client;
this.credentialsMap = credentialsMap;
this.securityGroupMap = securityGroupMap;
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/compute/strategy/DescribeImagesParallel.java b/apis/ec2/src/main/java/org/jclouds/ec2/compute/strategy/DescribeImagesParallel.java
index 61abb02..f080408 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/compute/strategy/DescribeImagesParallel.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/compute/strategy/DescribeImagesParallel.java
@@ -65,7 +65,7 @@
Iterable<Entry<String, DescribeImagesOptions>> queries) {
return concat(transformParallel(
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
public Future<Set<? extends org.jclouds.ec2.domain.Image>> apply(
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/compute/strategy/EC2ListNodesStrategy.java b/apis/ec2/src/main/java/org/jclouds/ec2/compute/strategy/EC2ListNodesStrategy.java
index 0ac45bd..2c0d1d0 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/compute/strategy/EC2ListNodesStrategy.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/compute/strategy/EC2ListNodesStrategy.java
@@ -92,7 +92,7 @@
protected Iterable<? extends RunningInstance> pollRunningInstances() {
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
public Future<Set<? extends Reservation<? extends RunningInstance>>> apply(String from) {
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/xml/CreateVolumeResponseHandler.java b/apis/ec2/src/main/java/org/jclouds/ec2/xml/CreateVolumeResponseHandler.java
index e0c92b2..2416e5e 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/xml/CreateVolumeResponseHandler.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/xml/CreateVolumeResponseHandler.java
@@ -50,7 +50,7 @@
* @author Adrian Cole
*/
public class CreateVolumeResponseHandler extends ParseSax.HandlerForGeneratedRequestWithResult<Volume> {
- private StringBuilder currentText = new StringBuilder();
+ protected StringBuilder currentText = new StringBuilder();
@Resource
protected Logger logger = Logger.NULL;
@@ -58,7 +58,7 @@
protected DateService dateService;
@Inject
@Region
- Supplier<String> defaultRegion;
+ protected Supplier<String> defaultRegion;
@Inject
@Zone
protected Supplier<Map<String, Supplier<Set<String>>>> regionToZonesSupplier;
@@ -66,23 +66,23 @@
@Zone
protected Supplier<Set<String>> zonesSupplier;
- private String id;
- private int size;
- private String snapshotId;
- private String availabilityZone;
- private Volume.Status volumeStatus;
- private Date createTime;
- private Set<Attachment> attachments = Sets.newLinkedHashSet();
+ protected String id;
+ protected int size;
+ protected String snapshotId;
+ protected String availabilityZone;
+ protected Volume.Status volumeStatus;
+ protected Date createTime;
+ protected Set<Attachment> attachments = Sets.newLinkedHashSet();
- private String volumeId;
- private String instanceId;
- private String device;
- private Attachment.Status attachmentStatus;
- private Date attachTime;
+ protected String volumeId;
+ protected String instanceId;
+ protected String device;
+ protected Attachment.Status attachmentStatus;
+ protected Date attachTime;
- private boolean inAttachmentSet;
+ protected boolean inAttachmentSet;
- private String region;
+ protected String region;
public Volume getResult() {
return newVolume();
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/xml/DescribeImagesResponseHandler.java b/apis/ec2/src/main/java/org/jclouds/ec2/xml/DescribeImagesResponseHandler.java
index 2e92af7..9b78e7d 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/xml/DescribeImagesResponseHandler.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/xml/DescribeImagesResponseHandler.java
@@ -61,7 +61,7 @@
@Resource
protected Logger logger = Logger.NULL;
- private Set<Image> contents = Sets.newLinkedHashSet();
+ protected Set<Image> contents = Sets.newLinkedHashSet();
private StringBuilder currentText = new StringBuilder();
private final Supplier<String> defaultRegion;
diff --git a/apis/elasticstack/src/main/java/org/jclouds/elasticstack/compute/ElasticStackComputeServiceAdapter.java b/apis/elasticstack/src/main/java/org/jclouds/elasticstack/compute/ElasticStackComputeServiceAdapter.java
index 6211969..0403679 100644
--- a/apis/elasticstack/src/main/java/org/jclouds/elasticstack/compute/ElasticStackComputeServiceAdapter.java
+++ b/apis/elasticstack/src/main/java/org/jclouds/elasticstack/compute/ElasticStackComputeServiceAdapter.java
@@ -58,6 +58,7 @@
import org.jclouds.elasticstack.domain.WellKnownImage;
import org.jclouds.elasticstack.reference.ElasticStackConstants;
import org.jclouds.logging.Logger;
+import org.jclouds.util.Iterables2;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
@@ -162,11 +163,11 @@
*/
@Override
public Iterable<DriveInfo> listImages() {
- Iterable<DriveInfo> drives = transformParallel(preinstalledImages.keySet(),
- new Function<String, Future<DriveInfo>>() {
+ Iterable<? extends DriveInfo> drives = transformParallel(preinstalledImages.keySet(),
+ new Function<String, Future<? extends DriveInfo>>() {
@Override
- public Future<DriveInfo> apply(String input) {
+ public Future<? extends DriveInfo> apply(String input) {
try {
return Futures.immediateFuture(cache.getUnchecked(input));
} catch (CacheLoader.InvalidCacheLoadException e) {
@@ -183,7 +184,7 @@
}
}, executor, null, logger, "drives");
- return filter(drives, notNull());
+ return Iterables2.concreteCopy(filter(drives, notNull()));
}
@SuppressWarnings("unchecked")
diff --git a/apis/openstack-nova-ec2/pom.xml b/apis/openstack-nova-ec2/pom.xml
index 647c100..e3e6ccd 100644
--- a/apis/openstack-nova-ec2/pom.xml
+++ b/apis/openstack-nova-ec2/pom.xml
@@ -29,8 +29,8 @@
</parent>
<groupId>org.jclouds.api</groupId>
<artifactId>openstack-nova-ec2</artifactId>
- <name>jclouds Eucalyptus api</name>
- <description>EC2 implementation based on Eucalyptus</description>
+ <name>jclouds openstack-nova-ec2 api</name>
+ <description>EC2 interface to Openstack Nova</description>
<packaging>bundle</packaging>
<properties>
diff --git a/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/config/NovaEC2RestClientModule.java b/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/config/NovaEC2RestClientModule.java
index f2ff664..6ea5685 100644
--- a/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/config/NovaEC2RestClientModule.java
+++ b/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/config/NovaEC2RestClientModule.java
@@ -22,10 +22,14 @@
import org.jclouds.ec2.EC2Client;
import org.jclouds.ec2.config.EC2RestClientModule;
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.suppliers.RegionIdToZoneIdsSupplier;
import org.jclouds.location.suppliers.ZoneIdsSupplier;
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 com.google.inject.Scopes;
@@ -42,6 +46,13 @@
}
@Override
+ protected void configure() {
+ super.configure();
+ bind(CreateVolumeResponseHandler.class).to(NovaCreateVolumeResponseHandler.class).in(Scopes.SINGLETON);
+ bind(DescribeImagesResponseHandler.class).to(NovaDescribeImagesResponseHandler.class);
+ }
+
+ @Override
protected void installLocations() {
install(new LocationModule());
bind(RegionIdToZoneIdsSupplier.class).to(DescribeAvailabilityZonesInRegion.class).in(Scopes.SINGLETON);
diff --git a/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/xml/NovaCreateVolumeResponseHandler.java b/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/xml/NovaCreateVolumeResponseHandler.java
new file mode 100644
index 0000000..db6b7c4
--- /dev/null
+++ b/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/xml/NovaCreateVolumeResponseHandler.java
@@ -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);
+ }
+ }
+
+}
diff --git a/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/xml/NovaDescribeImagesResponseHandler.java b/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/xml/NovaDescribeImagesResponseHandler.java
new file mode 100644
index 0000000..6c0945d
--- /dev/null
+++ b/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/xml/NovaDescribeImagesResponseHandler.java
@@ -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;
+ }
+ }));
+ }
+}
diff --git a/apis/openstack-nova-ec2/src/test/java/org/jclouds/openstack/nova/ec2/internal/BaseNovaEC2RestClientExpectTest.java b/apis/openstack-nova-ec2/src/test/java/org/jclouds/openstack/nova/ec2/internal/BaseNovaEC2RestClientExpectTest.java
new file mode 100644
index 0000000..5f34f76
--- /dev/null
+++ b/apis/openstack-nova-ec2/src/test/java/org/jclouds/openstack/nova/ec2/internal/BaseNovaEC2RestClientExpectTest.java
@@ -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();
+ }
+}
diff --git a/apis/openstack-nova-ec2/src/test/java/org/jclouds/openstack/nova/ec2/services/NovaEC2AMIClientTest.java b/apis/openstack-nova-ec2/src/test/java/org/jclouds/openstack/nova/ec2/services/NovaEC2AMIClientTest.java
new file mode 100644
index 0000000..81b15a2
--- /dev/null
+++ b/apis/openstack-nova-ec2/src/test/java/org/jclouds/openstack/nova/ec2/services/NovaEC2AMIClientTest.java
@@ -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);
+
+ }
+
+}
diff --git a/apis/openstack-nova-ec2/src/test/java/org/jclouds/openstack/nova/ec2/services/NovaEC2ElasticBlockStoreClientTest.java b/apis/openstack-nova-ec2/src/test/java/org/jclouds/openstack/nova/ec2/services/NovaEC2ElasticBlockStoreClientTest.java
new file mode 100644
index 0000000..021ee90
--- /dev/null
+++ b/apis/openstack-nova-ec2/src/test/java/org/jclouds/openstack/nova/ec2/services/NovaEC2ElasticBlockStoreClientTest.java
@@ -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);
+ }
+
+}
diff --git a/apis/openstack-nova-ec2/src/test/resources/nova_ec2_availabilityZones.xml b/apis/openstack-nova-ec2/src/test/resources/nova_ec2_availabilityZones.xml
new file mode 100644
index 0000000..4ed5280
--- /dev/null
+++ b/apis/openstack-nova-ec2/src/test/resources/nova_ec2_availabilityZones.xml
@@ -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>
\ No newline at end of file
diff --git a/apis/openstack-nova-ec2/src/test/resources/nova_ec2_describe_volumes.xml b/apis/openstack-nova-ec2/src/test/resources/nova_ec2_describe_volumes.xml
new file mode 100644
index 0000000..06b9e48
--- /dev/null
+++ b/apis/openstack-nova-ec2/src/test/resources/nova_ec2_describe_volumes.xml
@@ -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>
\ No newline at end of file
diff --git a/apis/openstack-nova-ec2/src/test/resources/nova_ec2_images_with_ramdisk.xml b/apis/openstack-nova-ec2/src/test/resources/nova_ec2_images_with_ramdisk.xml
new file mode 100644
index 0000000..b05df97
--- /dev/null
+++ b/apis/openstack-nova-ec2/src/test/resources/nova_ec2_images_with_ramdisk.xml
@@ -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>
\ No newline at end of file
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/NovaComputeService.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/NovaComputeService.java
index bd79952..f957326 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/NovaComputeService.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/NovaComputeService.java
@@ -33,6 +33,7 @@
import org.jclouds.Constants;
import org.jclouds.collect.Memoized;
import org.jclouds.compute.ComputeServiceContext;
+import org.jclouds.compute.ImageExtension;
import org.jclouds.compute.callables.RunScriptOnNode;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image;
@@ -103,12 +104,12 @@
LoadingCache<ZoneAndName, SecurityGroupInZone> securityGroupMap,
LoadingCache<ZoneAndName, KeyPair> keyPairCache,
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,
- runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy, stopNodeStrategy,
- templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated, nodeSuspended,
- initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials, timeouts,
- executor);
+ runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy,
+ stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
+ nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials,
+ timeouts, executor, imageExtension);
this.novaClient = checkNotNull(novaClient, "novaClient");
this.securityGroupMap = checkNotNull(securityGroupMap, "securityGroupMap");
this.keyPairCache = checkNotNull(keyPairCache, "keyPairCache");
@@ -134,7 +135,7 @@
if (securityGroupClient.isPresent()) {
for (String group : groups) {
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());
logger.debug(">> deleting securityGroup(%s)", zoneAndName);
securityGroupClient.get().deleteSecurityGroup(securityGroup.getId());
@@ -152,7 +153,7 @@
for (String group : groups) {
for (Map<String, KeyPair> wrapper : keyPairClient.get().listKeyPairs()) {
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());
logger.debug(">> deleting keypair(%s)", zoneAndName);
keyPairClient.get().deleteKeyPair(pair.getName());
@@ -162,7 +163,7 @@
}
}
keyPairCache.invalidate(ZoneAndName.fromZoneAndName(zoneId,
- namingConvention.create().sharedNameForGroup(group)));
+ namingConvention.create().sharedNameForGroup(group)));
}
}
}
@@ -174,5 +175,7 @@
public NovaTemplateOptions templateOptions() {
return NovaTemplateOptions.class.cast(super.templateOptions());
}
+
+
}
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/NovaImageExtension.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/NovaImageExtension.java
new file mode 100644
index 0000000..0b92881
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/NovaImageExtension.java
@@ -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();
+
+ }
+
+}
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/config/NovaComputeServiceContextModule.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/config/NovaComputeServiceContextModule.java
index 2351ac7..2ceaa9d 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/config/NovaComputeServiceContextModule.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/config/NovaComputeServiceContextModule.java
@@ -33,6 +33,7 @@
import org.jclouds.collect.Memoized;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceAdapter;
+import org.jclouds.compute.ImageExtension;
import org.jclouds.compute.config.ComputeServiceAdapterContextModule;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image;
@@ -46,6 +47,7 @@
import org.jclouds.functions.IdentityFunction;
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.NovaImageExtension;
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.ImageInZoneToImage;
@@ -69,6 +71,7 @@
import org.jclouds.predicates.RetryablePredicate;
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.base.Suppliers;
@@ -135,6 +138,9 @@
bind(new TypeLiteral<CacheLoader<ZoneAndName, KeyPair>>() {
}).to(CreateUniqueKeyPair.class);
+
+ bind(new TypeLiteral<ImageExtension>() {
+ }).to(NovaImageExtension.class);
}
@Override
@@ -206,4 +212,9 @@
}, locations);
}
+
+ @Override
+ protected Optional<ImageExtension> provideImageExtension(Injector i) {
+ return Optional.of(i.getInstance(ImageExtension.class));
+ }
}
\ No newline at end of file
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/functions/ServerInZoneToNodeMetadata.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/functions/ServerInZoneToNodeMetadata.java
index 2157cf7..591574e 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/functions/ServerInZoneToNodeMetadata.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/functions/ServerInZoneToNodeMetadata.java
@@ -20,7 +20,6 @@
import static com.google.common.base.Preconditions.checkNotNull;
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.find;
import static com.google.common.collect.Iterables.transform;
@@ -51,9 +50,11 @@
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.ZoneAndId;
+import org.jclouds.util.InetAddresses2;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
import com.google.common.base.Supplier;
import com.google.common.net.InetAddresses;
@@ -103,14 +104,20 @@
builder.hardware(findHardwareForServerOrNull(serverInZone));
builder.state(from.getStatus().getNodeState());
builder.publicAddresses(filter(
- transform(concat(from.getPublicAddresses(), from.getInternetAddresses()),
+ transform(filter(from.getAddresses().values(), Predicates.not(isPrivateAddress)),
AddressToStringTransformationFunction.INSTANCE), isInet4Address));
builder.privateAddresses(filter(
- transform(from.getPrivateAddresses(), AddressToStringTransformationFunction.INSTANCE), isInet4Address));
+ transform(filter(from.getAddresses().values(), isPrivateAddress), AddressToStringTransformationFunction.INSTANCE), isInet4Address));
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>() {
@Override
public boolean apply(String input) {
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/Address.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/Address.java
index 3053ccf..7faa0b4 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/Address.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/Address.java
@@ -30,42 +30,7 @@
* @author AdrianCole
*/
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() {
return new Builder();
}
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/Server.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/Server.java
index 9850663..576d2a3 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/Server.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/Server.java
@@ -20,7 +20,6 @@
import static com.google.common.base.Preconditions.checkNotNull;
-import java.util.Collection;
import java.util.Date;
import java.util.Map;
import java.util.Set;
@@ -29,20 +28,14 @@
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.openstack.domain.Link;
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.util.InetAddresses2;
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.Strings;
-import com.google.common.base.Objects.ToStringHelper;
import com.google.common.collect.ImmutableMap;
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.Maps;
import com.google.common.collect.Multimap;
@@ -122,7 +115,7 @@
private Resource flavor;
private Map<String, String> metadata = Maps.newHashMap();
// 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 keyName;
@@ -233,60 +226,12 @@
/**
* @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"));
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()
*/
public Builder adminPass(String adminPass) {
@@ -376,13 +321,13 @@
@SerializedName("config_drive")
protected final String configDrive;
// 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 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,
@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) {
super(id, name, links);
this.uuid = uuid; // TODO: see what version this came up in
@@ -471,74 +416,10 @@
}
/**
- * @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
*/
- public Multimap<Type, Address> getAddresses() {
-
- 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());
- }
+ public Multimap<String, Address> getAddresses() {
+ return Multimaps2.fromOldSchool(addresses);
}
/**
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/extensions/FloatingIPClientLiveTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/extensions/FloatingIPClientLiveTest.java
index 1db2604..b3262d3 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/extensions/FloatingIPClientLiveTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/extensions/FloatingIPClientLiveTest.java
@@ -181,7 +181,7 @@
try {
Server server = client.getServer(serverId);
boolean ipInServerAddresses = false;
- Multimap<Address.Type, Address> addresses = server.getAddresses();
+ Multimap<String, Address> addresses = server.getAddresses();
for (Address address : addresses.values()) {
if (address.getAddr().equals(floatingIP)) {
ipInServerAddresses = true;
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/internal/BaseNovaComputeServiceContextExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/internal/BaseNovaComputeServiceContextExpectTest.java
index f7e3681..9105e3a 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/internal/BaseNovaComputeServiceContextExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/internal/BaseNovaComputeServiceContextExpectTest.java
@@ -18,22 +18,17 @@
*/
package org.jclouds.openstack.nova.v1_1.internal;
-import java.io.InputStream;
import java.net.URI;
import java.util.Properties;
-import java.util.concurrent.ConcurrentHashMap;
import org.jclouds.apis.ApiMetadata;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
-import org.jclouds.io.CopyInputStreamInputSupplierMap;
import org.jclouds.openstack.nova.v1_1.NovaApiMetadata;
-import org.jclouds.rest.config.CredentialStoreModule;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableMultimap;
-import com.google.common.io.InputSupplier;
import com.google.inject.Module;
/**
@@ -91,12 +86,4 @@
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;
- }
}
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseServerDetailsEssexTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseServerDetailsEssexTest.java
new file mode 100644
index 0000000..a4e7f51
--- /dev/null
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseServerDetailsEssexTest.java
@@ -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());
+ }
+}
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseServerTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseServerTest.java
index f249f3b..7e54bd0 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseServerTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseServerTest.java
@@ -37,6 +37,7 @@
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMultimap;
import com.google.inject.Guice;
import com.google.inject.Injector;
@@ -96,9 +97,11 @@
.metadata(
new ImmutableMap.Builder<String, String>().put("Server Label", "Web Head 1")
.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"))
- .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();
}
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseServerWithInternetAddressesTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseServerWithInternetAddressesTest.java
index b5272f2..15a0dae 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseServerWithInternetAddressesTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseServerWithInternetAddressesTest.java
@@ -36,6 +36,7 @@
import org.jclouds.rest.annotations.SelectJson;
import org.testng.annotations.Test;
+import com.google.common.collect.ImmutableMultimap;
import com.google.inject.Guice;
import com.google.inject.Injector;
@@ -90,7 +91,7 @@
Link.create(
Relation.BOOKMARK,
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();
}
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/PublicIpsInPrivateAddressBlockShouldRerouteToPublicBlockExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/PublicIpsInPrivateAddressBlockExpectTest.java
similarity index 92%
rename from apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/PublicIpsInPrivateAddressBlockShouldRerouteToPublicBlockExpectTest.java
rename to apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/PublicIpsInPrivateAddressBlockExpectTest.java
index 7df750e..1d25130 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/PublicIpsInPrivateAddressBlockShouldRerouteToPublicBlockExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/PublicIpsInPrivateAddressBlockExpectTest.java
@@ -37,6 +37,7 @@
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMultimap;
import com.google.inject.Guice;
import com.google.inject.Injector;
@@ -44,7 +45,7 @@
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "ParseCreatedServerTest")
-public class PublicIpsInPrivateAddressBlockShouldRerouteToPublicBlockExpectTest extends BaseItemParserTest<Server> {
+public class PublicIpsInPrivateAddressBlockExpectTest extends BaseItemParserTest<Server> {
@Override
public String resource() {
@@ -86,8 +87,8 @@
URI.create("https://az-2.region-a.geo-1.compute.hpcloudsvc.com/37936628937291/flavors/100")))
.build())
.metadata(ImmutableMap.of("Name", "hpcloud-computes"))
- .privateAddresses(Address.createV4("10.6.39.189"))
- .publicAddresses(Address.createV4("15.185.181.94"))
+ .addresses(ImmutableMultimap.<String, Address>builder()
+ .putAll("private", Address.createV4("10.6.39.189"), Address.createV4("15.185.181.94")).build())
.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.BOOKMARK, URI.create("https://az-2.region-a.geo-1.compute.hpcloudsvc.com/37936628937291/servers/59662"))).build();
diff --git a/apis/openstack-nova/src/test/resources/server_list_details_essex.json b/apis/openstack-nova/src/test/resources/server_list_details_essex.json
new file mode 100644
index 0000000..9ca9445
--- /dev/null
+++ b/apis/openstack-nova/src/test/resources/server_list_details_essex.json
@@ -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": {}
+ }]
+}
\ No newline at end of file
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/config/VCloudRestClientModule.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/config/VCloudRestClientModule.java
index 486df9b..a7131c8 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/config/VCloudRestClientModule.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/config/VCloudRestClientModule.java
@@ -27,12 +27,12 @@
import static com.google.common.collect.Iterables.getLast;
import static com.google.common.collect.Iterables.transform;
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_SESSION_INTERVAL;
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_TIMEOUT_TASK_COMPLETED;
+import static org.jclouds.util.Maps2.uniqueIndex;
import java.net.URI;
import java.util.Map;
@@ -118,6 +118,7 @@
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
+import com.google.common.collect.Lists;
import com.google.inject.Injector;
import com.google.inject.Provides;
import com.google.inject.Scopes;
@@ -285,26 +286,27 @@
@Singleton
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 Function<Org, Iterable<org.jclouds.vcloud.domain.Catalog>> allCatalogsInOrg;
+ protected final Function<Org, Iterable<Catalog>> allCatalogsInOrg;
@Inject
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.allCatalogsInOrg = allCatalogsInOrg;
}
@Override
- public Map<String, Map<String, org.jclouds.vcloud.domain.Catalog>> get() {
+ public Map<String, Map<String, Catalog>> get() {
return transformValues(
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
- public Map<String, org.jclouds.vcloud.domain.Catalog> apply(
- Iterable<org.jclouds.vcloud.domain.Catalog> from) {
+ public Map<String, Catalog> apply(
+ Iterable<? extends Catalog> from) {
return uniqueIndex(from, name);
}
@@ -336,37 +338,37 @@
@Provides
@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,
URItoVDC supplier) {
- return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<URI, org.jclouds.vcloud.domain.VDC>>(
+ return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<URI, VDC>>(
authException, seconds, supplier);
}
@Singleton
- public static class URItoVDC implements Supplier<Map<URI, org.jclouds.vcloud.domain.VDC>> {
- private final Supplier<Map<String, Map<String, org.jclouds.vcloud.domain.VDC>>> orgVDCMap;
+ public static class URItoVDC implements Supplier<Map<URI, VDC>> {
+ private final Supplier<Map<String, Map<String, VDC>>> orgVDCMap;
@Inject
- URItoVDC(Supplier<Map<String, Map<String, org.jclouds.vcloud.domain.VDC>>> orgVDCMap) {
+ URItoVDC(Supplier<Map<String, Map<String, VDC>>> orgVDCMap) {
this.orgVDCMap = orgVDCMap;
}
@Override
- public Map<URI, org.jclouds.vcloud.domain.VDC> get() {
+ public Map<URI, VDC> get() {
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
- public Iterable<org.jclouds.vcloud.domain.VDC> apply(
- Map<String, org.jclouds.vcloud.domain.VDC> from) {
+ public Iterable<VDC> apply(
+ Map<String, VDC> from) {
return from.values();
}
- })), new Function<org.jclouds.vcloud.domain.VDC, URI>() {
+ })), new Function<VDC, URI>() {
@Override
- public URI apply(org.jclouds.vcloud.domain.VDC from) {
+ public URI apply(VDC from) {
return from.getHref();
}
@@ -445,43 +447,43 @@
@Provides
@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,
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);
}
@Provides
@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,
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);
}
@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;
- private final Function<Org, Iterable<org.jclouds.vcloud.domain.VDC>> allVDCsInOrg;
+ private final Function<Org, Iterable<VDC>> allVDCsInOrg;
@Inject
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.allVDCsInOrg = allVDCsInOrg;
}
@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),
- new Function<Iterable<org.jclouds.vcloud.domain.VDC>, Map<String, org.jclouds.vcloud.domain.VDC>>() {
+ new Function<Iterable<? extends VDC>, Map<String, VDC>>() {
@Override
- public Map<String, org.jclouds.vcloud.domain.VDC> apply(
- Iterable<org.jclouds.vcloud.domain.VDC> from) {
- return uniqueIndex(from, name);
+ public Map<String, VDC> apply(
+ Iterable<? extends VDC> from) {
+ return uniqueIndex(Lists.newArrayList(from), name);
}
});
@@ -490,33 +492,33 @@
@Singleton
public static class OrgCatalogItemSupplier implements
- Supplier<Map<String, Map<String, Map<String, org.jclouds.vcloud.domain.CatalogItem>>>> {
- protected final Supplier<Map<String, Map<String, org.jclouds.vcloud.domain.Catalog>>> catalogSupplier;
- protected final Function<org.jclouds.vcloud.domain.Catalog, Iterable<CatalogItem>> allCatalogItemsInCatalog;
+ Supplier<Map<String, Map<String, Map<String, CatalogItem>>>> {
+ protected final Supplier<Map<String, Map<String, Catalog>>> catalogSupplier;
+ protected final Function<Catalog, Iterable<CatalogItem>> allCatalogItemsInCatalog;
@Inject
protected OrgCatalogItemSupplier(
- Supplier<Map<String, Map<String, org.jclouds.vcloud.domain.Catalog>>> catalogSupplier,
- Function<org.jclouds.vcloud.domain.Catalog, Iterable<CatalogItem>> allCatalogItemsInCatalog) {
+ Supplier<Map<String, Map<String, Catalog>>> catalogSupplier,
+ Function<Catalog, Iterable<CatalogItem>> allCatalogItemsInCatalog) {
this.catalogSupplier = catalogSupplier;
this.allCatalogItemsInCatalog = allCatalogItemsInCatalog;
}
@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(
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
public Map<String, Map<String, CatalogItem>> apply(
- Map<String, org.jclouds.vcloud.domain.Catalog> from) {
+ Map<String, Catalog> from) {
return transformValues(
from,
- new Function<org.jclouds.vcloud.domain.Catalog, Map<String, org.jclouds.vcloud.domain.CatalogItem>>() {
+ new Function<Catalog, Map<String, CatalogItem>>() {
@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);
}
});
@@ -528,10 +530,10 @@
@Provides
@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,
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);
}
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogItemsInCatalog.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogItemsInCatalog.java
index 5721275..0393f3b 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogItemsInCatalog.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogItemsInCatalog.java
@@ -31,6 +31,7 @@
import org.jclouds.Constants;
import org.jclouds.logging.Logger;
+import org.jclouds.util.Iterables2;
import org.jclouds.vcloud.VCloudAsyncClient;
import org.jclouds.vcloud.VCloudMediaType;
import org.jclouds.vcloud.domain.Catalog;
@@ -60,14 +61,14 @@
@Override
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
public boolean apply(ReferenceType input) {
return input.getType().equals(VCloudMediaType.CATALOGITEM_XML);
}
- }), new Function<ReferenceType, Future<CatalogItem>>() {
+ }), new Function<ReferenceType, Future<? extends CatalogItem>>() {
@Override
public Future<CatalogItem> apply(ReferenceType from) {
@@ -75,7 +76,7 @@
}
}, executor, null, logger, "catalogItems in " + from.getHref());
- return catalogItems;
+ return Iterables2.concreteCopy(catalogItems);
}
}
\ No newline at end of file
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogItemsInOrg.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogItemsInOrg.java
index fc48add..098940a6 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogItemsInOrg.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogItemsInOrg.java
@@ -48,9 +48,9 @@
@Override
public Iterable<CatalogItem> apply(Org from) {
return Iterables.concat(Iterables.transform(allCatalogsInOrg.apply(from),
- new Function<Catalog, Iterable<CatalogItem>>() {
+ new Function<Catalog, Iterable<? extends CatalogItem>>() {
@Override
- public Iterable<CatalogItem> apply(Catalog from) {
+ public Iterable<? extends CatalogItem> apply(Catalog from) {
return allCatalogItemsInCatalog.apply(from);
}
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogsInOrg.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogsInOrg.java
index 644b19a..683209f 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogsInOrg.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogsInOrg.java
@@ -30,6 +30,7 @@
import org.jclouds.Constants;
import org.jclouds.logging.Logger;
+import org.jclouds.util.Iterables2;
import org.jclouds.vcloud.VCloudAsyncClient;
import org.jclouds.vcloud.domain.Catalog;
import org.jclouds.vcloud.domain.Org;
@@ -56,14 +57,14 @@
@Override
public Iterable<Catalog> apply(final Org org) {
- Iterable<Catalog> catalogs = transformParallel(org.getCatalogs().values(),
- new Function<ReferenceType, Future<Catalog>>() {
+ Iterable<? extends Catalog> catalogs = transformParallel(org.getCatalogs().values(),
+ new Function<ReferenceType, Future<? extends Catalog>>() {
@Override
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());
- return catalogs;
+ return Iterables2.concreteCopy(catalogs);
}
}
\ No newline at end of file
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllVDCsInOrg.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllVDCsInOrg.java
index 093e951..a65d6d4 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllVDCsInOrg.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllVDCsInOrg.java
@@ -30,6 +30,7 @@
import org.jclouds.Constants;
import org.jclouds.logging.Logger;
+import org.jclouds.util.Iterables2;
import org.jclouds.vcloud.VCloudAsyncClient;
import org.jclouds.vcloud.domain.Org;
import org.jclouds.vcloud.domain.ReferenceType;
@@ -41,7 +42,7 @@
* @author Adrian Cole
*/
@Singleton
-public class AllVDCsInOrg implements Function<Org, Iterable<org.jclouds.vcloud.domain.VDC>> {
+public class AllVDCsInOrg implements Function<Org, Iterable<VDC>> {
@Resource
public Logger logger = Logger.NULL;
@@ -58,14 +59,14 @@
public Iterable<VDC> apply(final Org org) {
Iterable<VDC> catalogItems = transformParallel(org.getVDCs().values(),
- new Function<ReferenceType, Future<org.jclouds.vcloud.domain.VDC>>() {
+ new Function<ReferenceType, Future<? extends VDC>>() {
@Override
- public Future<VDC> apply(ReferenceType from) {
+ public Future<? extends VDC> apply(ReferenceType from) {
return aclient.getVDCClient().getVDC(from.getHref());
}
}, executor, null, logger, "vdcs in org " + org.getName());
- return catalogItems;
+ return Iterables2.concreteCopy(catalogItems);
}
}
\ No newline at end of file
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/OrgsForLocations.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/OrgsForLocations.java
index 2d326a7..017d1b1 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/OrgsForLocations.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/OrgsForLocations.java
@@ -35,6 +35,7 @@
import org.jclouds.domain.Location;
import org.jclouds.domain.LocationScope;
import org.jclouds.logging.Logger;
+import org.jclouds.util.Iterables2;
import org.jclouds.vcloud.VCloudAsyncClient;
import org.jclouds.vcloud.domain.Org;
@@ -46,7 +47,7 @@
* @author Adrian Cole
*/
@Singleton
-public class OrgsForLocations implements Function<Iterable<Location>, Iterable< Org>> {
+public class OrgsForLocations implements Function<Iterable<Location>, Iterable<Org>> {
@Resource
public Logger logger = Logger.NULL;
private final VCloudAsyncClient aclient;
@@ -65,7 +66,7 @@
@Override
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
public boolean apply(Location input) {
@@ -79,14 +80,14 @@
return URI.create(from.getParent().getId());
}
- })), new Function<URI, Future<Org>>() {
+ })), new Function<URI, Future<? extends Org>>() {
@Override
public Future<Org> apply(URI from) {
return aclient.getOrgClient().getOrg(from);
}
- }, executor, null, logger, "organizations for uris");
+ }, executor, null, logger, "organizations for uris"));
}
}
\ No newline at end of file
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/OrgsForNames.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/OrgsForNames.java
index 96e276e..7cf4473 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/OrgsForNames.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/OrgsForNames.java
@@ -30,6 +30,7 @@
import org.jclouds.Constants;
import org.jclouds.logging.Logger;
+import org.jclouds.util.Iterables2;
import org.jclouds.vcloud.VCloudAsyncClient;
import org.jclouds.vcloud.domain.Org;
@@ -53,14 +54,14 @@
@Override
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
public Future<Org> apply(String from) {
return aclient.getOrgClient().findOrgNamed(from);
}
- }, executor, null, logger, "organizations for names");
+ }, executor, null, logger, "organizations for names"));
}
}
\ No newline at end of file
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/VAppTemplatesForCatalogItems.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/VAppTemplatesForCatalogItems.java
index 239f27a..4abf213 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/VAppTemplatesForCatalogItems.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/VAppTemplatesForCatalogItems.java
@@ -36,6 +36,7 @@
import org.jclouds.concurrent.Futures;
import org.jclouds.logging.Logger;
import org.jclouds.rest.AuthorizationException;
+import org.jclouds.util.Iterables2;
import org.jclouds.vcloud.VCloudAsyncClient;
import org.jclouds.vcloud.VCloudMediaType;
import org.jclouds.vcloud.domain.CatalogItem;
@@ -78,14 +79,14 @@
@Override
public Iterable<VAppTemplate> apply(Iterable<CatalogItem> from) {
- return transformParallel(filter(from, new Predicate<CatalogItem>() {
+ return Iterables2.concreteCopy(transformParallel(filter(from, new Predicate<CatalogItem>() {
@Override
public boolean apply(CatalogItem input) {
return input.getEntity().getType().equals(VCloudMediaType.VAPPTEMPLATE_XML);
}
- }), new Function<CatalogItem, Future<VAppTemplate>>() {
+ }), new Function<CatalogItem, Future<? extends VAppTemplate>>() {
@Override
public Future<VAppTemplate> apply(CatalogItem from) {
@@ -94,7 +95,7 @@
returnNullOnAuthorizationException);
}
- }, executor, null, logger, "vappTemplates in");
+ }, executor, null, logger, "vappTemplates in"));
}
}
\ No newline at end of file
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/VAppTemplatesInOrg.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/VAppTemplatesInOrg.java
index b4b733d..1b26580 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/VAppTemplatesInOrg.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/VAppTemplatesInOrg.java
@@ -25,6 +25,7 @@
import javax.inject.Inject;
import javax.inject.Singleton;
+import org.jclouds.util.Iterables2;
import org.jclouds.vcloud.domain.CatalogItem;
import org.jclouds.vcloud.domain.Org;
import org.jclouds.vcloud.domain.Status;
@@ -53,7 +54,7 @@
@Override
public Iterable<VAppTemplate> apply(Org 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>(){
//TODO: test this
diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/suppliers/VAppTemplatesSupplier.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/suppliers/VAppTemplatesSupplier.java
index 05cf929..b96cbc7 100644
--- a/apis/vcloud/src/main/java/org/jclouds/vcloud/suppliers/VAppTemplatesSupplier.java
+++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/suppliers/VAppTemplatesSupplier.java
@@ -69,8 +69,8 @@
@Override
public Set<VAppTemplate> get() {
Iterable<Org> orgs = checkNotNull(orgMap.get().values(), "orgs");
- Iterable<Iterable<VAppTemplate>> images = transformParallel(orgs,
- new Function<Org, Future<Iterable<VAppTemplate>>>() {
+ Iterable<? extends Iterable<VAppTemplate>> images = transformParallel(orgs,
+ new Function<Org, Future<? extends Iterable<VAppTemplate>>>() {
@Override
public Future<Iterable<VAppTemplate>> apply(final Org from) {
diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/internal/BaseVCloudAsyncClientTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/internal/BaseVCloudAsyncClientTest.java
index 93edd14..3401069 100644
--- a/apis/vcloud/src/test/java/org/jclouds/vcloud/internal/BaseVCloudAsyncClientTest.java
+++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/internal/BaseVCloudAsyncClientTest.java
@@ -42,6 +42,7 @@
import org.jclouds.vcloud.VCloudVersionsClient;
import org.jclouds.vcloud.config.VCloudRestClientModule;
import org.jclouds.vcloud.domain.AllocationModel;
+import org.jclouds.vcloud.domain.CatalogItem;
import org.jclouds.vcloud.domain.Org;
import org.jclouds.vcloud.domain.ReferenceType;
import org.jclouds.vcloud.domain.Task;
@@ -253,11 +254,11 @@
}
@Override
- public Map<String, Map<String, Map<String, org.jclouds.vcloud.domain.CatalogItem>>> get() {
- return ImmutableMap.<String, Map<String, Map<String, org.jclouds.vcloud.domain.CatalogItem>>> of(
+ public Map<String, Map<String, Map<String, CatalogItem>>> get() {
+ return ImmutableMap.<String, Map<String, Map<String, CatalogItem>>> of(
ORG_REF.getName(), ImmutableMap
- .<String, Map<String, org.jclouds.vcloud.domain.CatalogItem>> of(CATALOG_REF
- .getName(), ImmutableMap.<String, org.jclouds.vcloud.domain.CatalogItem> of(
+ .<String, Map<String, CatalogItem>> of(CATALOG_REF
+ .getName(), ImmutableMap.<String, CatalogItem> of(
"template",
new CatalogItemImpl("template", URI
.create("https://vcenterprise.bluelock.com/api/v1.0/catalogItem/2"), "description",
diff --git a/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/FetchBlobMetadata.java b/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/FetchBlobMetadata.java
index 613ff0a..3980f89 100644
--- a/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/FetchBlobMetadata.java
+++ b/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/FetchBlobMetadata.java
@@ -42,6 +42,7 @@
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
import com.google.inject.Inject;
/**
@@ -83,21 +84,21 @@
public PageSet<? extends StorageMetadata> apply(PageSet<? extends StorageMetadata> in) {
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
public boolean apply(StorageMetadata input) {
return input.getType() == StorageType.BLOB;
}
- }), new Function<StorageMetadata, Future<BlobMetadata>>() {
+ }), new Function<StorageMetadata, Future<? extends BlobMetadata>>() {
@Override
public Future<BlobMetadata> apply(StorageMetadata from) {
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());
}
diff --git a/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/GetAllBlobsInListAndRetryOnFailure.java b/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/GetAllBlobsInListAndRetryOnFailure.java
index 00adf8e..316a522 100644
--- a/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/GetAllBlobsInListAndRetryOnFailure.java
+++ b/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/GetAllBlobsInListAndRetryOnFailure.java
@@ -75,7 +75,7 @@
public Iterable<Blob> execute(final String container, ListContainerOptions 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
public Future<Blob> apply(BlobMetadata from) {
diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/TerremarkVCloudComputeService.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/TerremarkVCloudComputeService.java
index 8710791..723e886 100644
--- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/TerremarkVCloudComputeService.java
+++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/TerremarkVCloudComputeService.java
@@ -31,6 +31,7 @@
import org.jclouds.Constants;
import org.jclouds.collect.Memoized;
import org.jclouds.compute.ComputeServiceContext;
+import org.jclouds.compute.ImageExtension;
import org.jclouds.compute.callables.RunScriptOnNode;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image;
@@ -54,6 +55,7 @@
import org.jclouds.trmk.vcloud_0_8.compute.options.TerremarkVCloudTemplateOptions;
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.Supplier;
@@ -78,12 +80,13 @@
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory,
RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
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,
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, resumeNodeStrategy,
suspendNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials,
- timeouts, executor);
+ timeouts, executor, imageExtension);
this.cleanupOrphanKeys = cleanupOrphanKeys;
}
diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/suppliers/VCloudHardwareSupplier.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/suppliers/VCloudHardwareSupplier.java
index b0bdee1..bdc97a1 100644
--- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/suppliers/VCloudHardwareSupplier.java
+++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/suppliers/VCloudHardwareSupplier.java
@@ -69,8 +69,8 @@
@Override
public Set<? extends Hardware> get() {
Iterable<? extends Org> orgs = checkNotNull(orgMap.get().values(), "orgs");
- Iterable<Iterable<? extends Hardware>> sizes = transformParallel(orgs,
- new Function<Org, Future<Iterable<? extends Hardware>>>() {
+ Iterable<? extends Iterable<? extends Hardware>> sizes = transformParallel(orgs,
+ new Function<Org, Future<? extends Iterable<? extends Hardware>>>() {
@Override
public Future<Iterable<? extends Hardware>> apply(final Org from) {
diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/suppliers/VCloudImageSupplier.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/suppliers/VCloudImageSupplier.java
index d636b15..e279a64 100644
--- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/suppliers/VCloudImageSupplier.java
+++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/suppliers/VCloudImageSupplier.java
@@ -69,8 +69,8 @@
@Override
public Set<? extends Image> get() {
Iterable<? extends Org> orgs = checkNotNull(orgMap.get().values(), "orgs");
- Iterable<Iterable<? extends Image>> images = transformParallel(orgs,
- new Function<Org, Future<Iterable<? extends Image>>>() {
+ Iterable<? extends Iterable<? extends Image>> images = transformParallel(orgs,
+ new Function<Org, Future<? extends Iterable<? extends Image>>>() {
@Override
public Future<Iterable<? extends Image>> apply(final Org from) {
diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/AllCatalogItemsInCatalog.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/AllCatalogItemsInCatalog.java
index 3740de3..effb137 100644
--- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/AllCatalogItemsInCatalog.java
+++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/AllCatalogItemsInCatalog.java
@@ -61,14 +61,14 @@
@Override
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
public boolean apply(ReferenceType input) {
return input.getType().equals(TerremarkVCloudMediaType.CATALOGITEM_XML);
}
- }), new Function<ReferenceType, Future<CatalogItem>>() {
+ }), new Function<ReferenceType, Future<? extends CatalogItem>>() {
@SuppressWarnings("unchecked")
@Override
diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/AllCatalogsInOrg.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/AllCatalogsInOrg.java
index 66e7979..a2ac27f 100644
--- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/AllCatalogsInOrg.java
+++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/AllCatalogsInOrg.java
@@ -56,8 +56,8 @@
@Override
public Iterable<? extends Catalog> apply(final Org org) {
- Iterable<Catalog> catalogs = transformParallel(org.getCatalogs().values(),
- new Function<ReferenceType, Future<Catalog>>() {
+ Iterable<? extends Catalog> catalogs = transformParallel(org.getCatalogs().values(),
+ new Function<ReferenceType, Future<? extends Catalog>>() {
@SuppressWarnings("unchecked")
@Override
public Future<Catalog> apply(ReferenceType from) {
diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/AllVDCsInOrg.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/AllVDCsInOrg.java
index 3ef54d8..28307a3 100644
--- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/AllVDCsInOrg.java
+++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/AllVDCsInOrg.java
@@ -56,12 +56,11 @@
@Override
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(),
- new Function<ReferenceType, Future<org.jclouds.trmk.vcloud_0_8.domain.VDC>>() {
- @SuppressWarnings("unchecked")
+ Iterable<? extends org.jclouds.trmk.vcloud_0_8.domain.VDC> catalogItems = transformParallel(org.getVDCs().values(),
+ new Function<ReferenceType, Future<? extends org.jclouds.trmk.vcloud_0_8.domain.VDC>>() {
@Override
- public Future<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());
+ public Future<? extends org.jclouds.trmk.vcloud_0_8.domain.VDC> apply(ReferenceType from) {
+ return aclient.getVDC(from.getHref());
}
}, executor, null, logger, "vdcs in org " + org.getName());
diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/OrgsForLocations.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/OrgsForLocations.java
index 568203e..00f79b4 100644
--- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/OrgsForLocations.java
+++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/OrgsForLocations.java
@@ -79,12 +79,10 @@
return URI.create(from.getParent().getId());
}
- })), new Function<URI, Future<Org>>() {
-
- @SuppressWarnings("unchecked")
+ })), new Function<URI, Future<? extends Org>>() {
@Override
- public Future<Org> apply(URI from) {
- return (Future<Org>) aclient.getOrg(from);
+ public Future<? extends Org> apply(URI from) {
+ return aclient.getOrg(from);
}
}, executor, null, logger, "organizations for uris");
diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/OrgsForNames.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/OrgsForNames.java
index 1c95f0e..7408430 100644
--- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/OrgsForNames.java
+++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/OrgsForNames.java
@@ -53,12 +53,10 @@
@Override
public Iterable<? extends Org> apply(Iterable<String> from) {
- return transformParallel(from, new Function<String, Future<Org>>() {
-
- @SuppressWarnings("unchecked")
+ return transformParallel(from, new Function<String, Future<? extends Org>>() {
@Override
- public Future<Org> apply(String from) {
- return (Future<Org>) aclient.findOrgNamed(from);
+ public Future<? extends Org> apply(String from) {
+ return aclient.findOrgNamed(from);
}
}, executor, null, logger, "organizations for names");
diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/VAppTemplatesForCatalogItems.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/VAppTemplatesForCatalogItems.java
index 6995b71..2fbabe4 100644
--- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/VAppTemplatesForCatalogItems.java
+++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/VAppTemplatesForCatalogItems.java
@@ -68,12 +68,10 @@
return input.getEntity().getType().equals(TerremarkVCloudMediaType.VAPPTEMPLATE_XML);
}
- }), new Function<CatalogItem, Future<VAppTemplate>>() {
-
- @SuppressWarnings("unchecked")
+ }), new Function<CatalogItem, Future<? extends VAppTemplate>>() {
@Override
- public Future<VAppTemplate> apply(CatalogItem from) {
- return (Future<VAppTemplate>) aclient.getVAppTemplate(from.getEntity().getHref());
+ public Future<? extends VAppTemplate> apply(CatalogItem from) {
+ return aclient.getVAppTemplate(from.getEntity().getHref());
}
}, executor, null, logger, "vappTemplates in");
diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/VAppTemplatesForResourceEntities.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/VAppTemplatesForResourceEntities.java
index e096c28..ee9bb1a 100644
--- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/VAppTemplatesForResourceEntities.java
+++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/functions/VAppTemplatesForResourceEntities.java
@@ -69,12 +69,10 @@
return input.getType().equals(TerremarkVCloudMediaType.VAPPTEMPLATE_XML);
}
- }), new Function<ReferenceType, Future<VAppTemplate>>() {
-
- @SuppressWarnings("unchecked")
+ }), new Function<ReferenceType, Future<? extends VAppTemplate>>() {
@Override
- public Future<VAppTemplate> apply(ReferenceType from) {
- return (Future<VAppTemplate>) aclient.getVAppTemplate(from.getHref());
+ public Future<? extends VAppTemplate> apply(ReferenceType from) {
+ return aclient.getVAppTemplate(from.getHref());
}
}, executor, null, logger, "vappTemplates in");
diff --git a/compute/src/main/java/org/jclouds/compute/ComputeService.java b/compute/src/main/java/org/jclouds/compute/ComputeService.java
index 701f8f3..3c04e8a 100644
--- a/compute/src/main/java/org/jclouds/compute/ComputeService.java
+++ b/compute/src/main/java/org/jclouds/compute/ComputeService.java
@@ -38,6 +38,7 @@
import org.jclouds.scriptbuilder.domain.Statement;
import com.google.common.annotations.Beta;
+import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.inject.ImplementedBy;
@@ -345,5 +346,14 @@
* @see #runScriptOnNode(String, String, RunScriptOptions)
*/
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();
}
diff --git a/compute/src/main/java/org/jclouds/compute/ImageExtension.java b/compute/src/main/java/org/jclouds/compute/ImageExtension.java
new file mode 100644
index 0000000..56da218
--- /dev/null
+++ b/compute/src/main/java/org/jclouds/compute/ImageExtension.java
@@ -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);
+
+}
diff --git a/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java b/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java
index ecc4774..a522f13 100644
--- a/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java
+++ b/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java
@@ -31,6 +31,7 @@
import javax.inject.Singleton;
import org.jclouds.collect.Memoized;
+import org.jclouds.compute.ImageExtension;
import org.jclouds.compute.callables.BlockUntilInitScriptStatusIsZeroThenReturnOutput;
import org.jclouds.compute.callables.RunScriptOnNode;
import org.jclouds.compute.callables.RunScriptOnNodeAsInitScriptUsingSsh;
@@ -61,6 +62,7 @@
import org.jclouds.ssh.SshClient;
import com.google.common.base.Function;
+import com.google.common.base.Optional;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableMap;
@@ -299,5 +301,12 @@
}
};
}
+
+ @Provides
+ @Singleton
+ protected Optional<ImageExtension> provideImageExtension(Injector i){
+ return Optional.absent();
+ }
+
}
\ No newline at end of file
diff --git a/compute/src/main/java/org/jclouds/compute/domain/CloneImageTemplate.java b/compute/src/main/java/org/jclouds/compute/domain/CloneImageTemplate.java
new file mode 100644
index 0000000..238fdef
--- /dev/null
+++ b/compute/src/main/java/org/jclouds/compute/domain/CloneImageTemplate.java
@@ -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();
+
+}
diff --git a/compute/src/main/java/org/jclouds/compute/domain/ImageTemplate.java b/compute/src/main/java/org/jclouds/compute/domain/ImageTemplate.java
new file mode 100644
index 0000000..651a899
--- /dev/null
+++ b/compute/src/main/java/org/jclouds/compute/domain/ImageTemplate.java
@@ -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();
+
+}
diff --git a/compute/src/main/java/org/jclouds/compute/domain/ImageTemplateBuilder.java b/compute/src/main/java/org/jclouds/compute/domain/ImageTemplateBuilder.java
new file mode 100644
index 0000000..6104cd9
--- /dev/null
+++ b/compute/src/main/java/org/jclouds/compute/domain/ImageTemplateBuilder.java
@@ -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);
+ }
+ }
+}
diff --git a/compute/src/main/java/org/jclouds/compute/domain/internal/ImageTemplateImpl.java b/compute/src/main/java/org/jclouds/compute/domain/internal/ImageTemplateImpl.java
new file mode 100644
index 0000000..2745f17
--- /dev/null
+++ b/compute/src/main/java/org/jclouds/compute/domain/internal/ImageTemplateImpl.java
@@ -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;
+ }
+ }
+
+}
diff --git a/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java b/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java
index bd4496b..90a7538 100644
--- a/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java
+++ b/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java
@@ -51,6 +51,7 @@
import org.jclouds.collect.Memoized;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceContext;
+import org.jclouds.compute.ImageExtension;
import org.jclouds.compute.RunNodesException;
import org.jclouds.compute.RunScriptOnNodesException;
import org.jclouds.compute.callables.RunScriptOnNode;
@@ -90,6 +91,7 @@
import org.jclouds.util.Maps2;
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.ImmutableMap;
@@ -134,6 +136,7 @@
private final PersistNodeCredentials persistNodeCredentials;
private final RunScriptOnNode.Factory runScriptOnNodeFactory;
private final ExecutorService executor;
+ private final Optional<ImageExtension> imageExtension;
@Inject
protected BaseComputeService(ComputeServiceContext context, Map<String, Credentials> credentialStore,
@@ -148,7 +151,8 @@
@Named("NODE_SUSPENDED") Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess,
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.credentialStore = checkNotNull(credentialStore, "credentialStore");
this.images = checkNotNull(images, "images");
@@ -172,6 +176,7 @@
this.runScriptOnNodeFactory = checkNotNull(runScriptOnNodeFactory, "runScriptOnNodeFactory");
this.persistNodeCredentials = checkNotNull(persistNodeCredentials, "persistNodeCredentials");
this.executor = checkNotNull(executor, "executor");
+ this.imageExtension = imageExtension;
}
/**
@@ -238,7 +243,7 @@
public Set<? extends NodeMetadata> destroyNodesMatching(Predicate<NodeMetadata> filter) {
logger.debug(">> destroying nodes matching(%s)", 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
@Override
@@ -403,7 +408,7 @@
public void rebootNodesMatching(Predicate<NodeMetadata> filter) {
logger.debug(">> rebooting nodes matching(%s)", filter);
transformParallel(nodesMatchingFilterAndNotTerminatedExceptionIfNotFound(filter),
- new Function<NodeMetadata, Future<Void>>() {
+ new Function<NodeMetadata, Future<? extends Void>>() {
// TODO use native async
@Override
public Future<Void> apply(NodeMetadata from) {
@@ -434,7 +439,7 @@
public void resumeNodesMatching(Predicate<NodeMetadata> filter) {
logger.debug(">> resuming nodes matching(%s)", filter);
transformParallel(nodesMatchingFilterAndNotTerminatedExceptionIfNotFound(filter),
- new Function<NodeMetadata, Future<Void>>() {
+ new Function<NodeMetadata, Future<? extends Void>>() {
// TODO use native async
@Override
public Future<Void> apply(NodeMetadata from) {
@@ -465,7 +470,7 @@
public void suspendNodesMatching(Predicate<NodeMetadata> filter) {
logger.debug(">> suspending nodes matching(%s)", filter);
transformParallel(nodesMatchingFilterAndNotTerminatedExceptionIfNotFound(filter),
- new Function<NodeMetadata, Future<Void>>() {
+ new Function<NodeMetadata, Future<? extends Void>>() {
// TODO use native async
@Override
public Future<Void> apply(NodeMetadata from) {
@@ -649,7 +654,7 @@
}
private final class TransformNodesIntoInitializedScriptRunners implements
- Function<NodeMetadata, Future<RunScriptOnNode>> {
+ Function<NodeMetadata, Future<? extends RunScriptOnNode>> {
private final Map<NodeMetadata, Exception> badNodes;
private final Statement script;
private final RunScriptOptions options;
@@ -668,5 +673,13 @@
}
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Optional<ImageExtension> getImageExtension() {
+ return imageExtension;
+ }
}
\ No newline at end of file
diff --git a/compute/src/test/java/org/jclouds/compute/internal/BaseImageExtensionLiveTest.java b/compute/src/test/java/org/jclouds/compute/internal/BaseImageExtensionLiveTest.java
new file mode 100644
index 0000000..896e1ff
--- /dev/null
+++ b/compute/src/test/java/org/jclouds/compute/internal/BaseImageExtensionLiveTest.java
@@ -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");
+ }
+ });
+ }
+
+}
diff --git a/core/pom.xml b/core/pom.xml
index 9f1b049..b63f5e9 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -99,7 +99,7 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
- <version>12.0-rc1</version>
+ <version>12.0-rc2</version>
</dependency>
</dependencies>
diff --git a/core/src/main/java/org/jclouds/concurrent/FutureIterables.java b/core/src/main/java/org/jclouds/concurrent/FutureIterables.java
index 5fe7671..2655df9 100644
--- a/core/src/main/java/org/jclouds/concurrent/FutureIterables.java
+++ b/core/src/main/java/org/jclouds/concurrent/FutureIterables.java
@@ -58,50 +58,51 @@
public class FutureIterables {
@Resource
private static Logger logger = Logger.CONSOLE;
-
+
@Inject(optional = true)
@Named(Constants.PROPERTY_MAX_RETRIES)
private static int maxRetries = 5;
-
+
@Inject(optional = true)
@Named(Constants.PROPERTY_RETRY_DELAY_START)
private static long delayStart = 50L;
-
+
@Inject(optional = true)
private static BackoffLimitedRetryHandler retryHandler = BackoffLimitedRetryHandler.INSTANCE;
-
+
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);
}
-
+
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");
}
-
+
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,
- String logPrefix) {
+ final Function<? super F, Future<? extends T>> function, ExecutorService exec, @Nullable Long maxTime, Logger logger,
+ String logPrefix) {
return transformParallel(fromIterable, function, exec, maxTime, logger, logPrefix, retryHandler, maxRetries);
}
-
+
@SuppressWarnings("unchecked")
public static <F, T> Iterable<T> transformParallel(Iterable<F> fromIterable,
- Function<? super F, Future<T>> function, ExecutorService exec, @Nullable Long maxTime, Logger logger,
- String logPrefix, BackoffLimitedRetryHandler retryHandler, int maxRetries) {
+ Function<? super F, Future<? extends T>> function, ExecutorService exec, @Nullable Long maxTime, Logger logger,
+ String logPrefix, BackoffLimitedRetryHandler retryHandler, int maxRetries) {
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 (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);
if (exceptions.size() > 0 && !any(exceptions.values(), containsThrowable(AuthorizationException.class))) {
fromIterable = exceptions.keySet();
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 {
break;
}
@@ -109,13 +110,13 @@
//make sure we propagate any authorization exception so that we don't lock out accounts
if (exceptions.size() > 0)
return propagateAuthorizationOrOriginalException(new TransformParallelException((Map) responses, exceptions,
- logPrefix));
-
+ logPrefix));
+
return unwrap(responses.values());
}
-
+
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();
if (responses.size() == 0)
return errorMap;
@@ -126,7 +127,7 @@
final long start = System.currentTimeMillis();
for (final java.util.Map.Entry<T, ? extends Future<?>> future : responses.entrySet()) {
Futures.makeListenable(future.getValue(), exec).addListener(new Runnable() {
-
+
@Override
public void run() {
try {
@@ -168,11 +169,11 @@
}
return errorMap;
}
-
- public static <T> Iterable<T> unwrap(Iterable<Future<T>> values) {
- return transform(values, new Function<Future<T>, T>() {
+
+ public static <T> Iterable<T> unwrap(Iterable<Future<? extends T>> values) {
+ return transform(values, new Function<Future<? extends T>, T>() {
@Override
- public T apply(Future<T> from) {
+ public T apply(Future<? extends T> from) {
try {
return from.get();
} catch (InterruptedException e) {
@@ -189,20 +190,20 @@
}
});
}
-
+
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);
logger.error(e, message);
}
-
+
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,
- (long) ((System.currentTimeMillis() - start) / ((double) size)));
+ (long) ((System.currentTimeMillis() - start) / ((double) size)));
}
-
+
protected static boolean timeOut(long start, Long maxTime) {
return maxTime != null ? System.currentTimeMillis() < start + maxTime : false;
}
-
+
}
\ No newline at end of file
diff --git a/core/src/main/java/org/jclouds/util/Iterables2.java b/core/src/main/java/org/jclouds/util/Iterables2.java
new file mode 100644
index 0000000..886a6d0
--- /dev/null
+++ b/core/src/main/java/org/jclouds/util/Iterables2.java
@@ -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);
+ }
+
+}
diff --git a/core/src/main/java/org/jclouds/util/Maps2.java b/core/src/main/java/org/jclouds/util/Maps2.java
index 8150d8e..324995e 100644
--- a/core/src/main/java/org/jclouds/util/Maps2.java
+++ b/core/src/main/java/org/jclouds/util/Maps2.java
@@ -154,5 +154,15 @@
}
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));
+ }
}
diff --git a/core/src/test/java/org/jclouds/concurrent/FutureIterablesTest.java b/core/src/test/java/org/jclouds/concurrent/FutureIterablesTest.java
index 0601ede..2071454 100644
--- a/core/src/test/java/org/jclouds/concurrent/FutureIterablesTest.java
+++ b/core/src/test/java/org/jclouds/concurrent/FutureIterablesTest.java
@@ -43,7 +43,7 @@
final AtomicInteger counter = new AtomicInteger();
try {
- transformParallel(ImmutableSet.of("hello", "goodbye"), new Function<String, Future<String>>() {
+ transformParallel(ImmutableSet.of("hello", "goodbye"), new Function<String, Future<? extends String>>() {
@Override
public Future<String> apply(String input) {
@@ -63,7 +63,7 @@
final AtomicInteger counter = new AtomicInteger();
try {
- transformParallel(ImmutableSet.of("hello", "goodbye"), new Function<String, Future<String>>() {
+ transformParallel(ImmutableSet.of("hello", "goodbye"), new Function<String, Future<? extends String>>() {
@Override
public Future<String> apply(String input) {
diff --git a/core/src/test/java/org/jclouds/rest/internal/BaseRestClientExpectTest.java b/core/src/test/java/org/jclouds/rest/internal/BaseRestClientExpectTest.java
index 88e6758..8e77a56 100644
--- a/core/src/test/java/org/jclouds/rest/internal/BaseRestClientExpectTest.java
+++ b/core/src/test/java/org/jclouds/rest/internal/BaseRestClientExpectTest.java
@@ -22,11 +22,13 @@
import static org.testng.Assert.assertEquals;
import java.io.IOException;
+import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
@@ -57,11 +59,13 @@
import org.jclouds.http.handlers.DelegatingRetryHandler;
import org.jclouds.http.internal.BaseHttpCommandExecutorService;
import org.jclouds.http.internal.HttpWire;
+import org.jclouds.io.CopyInputStreamInputSupplierMap;
import org.jclouds.io.Payload;
import org.jclouds.io.Payloads;
import org.jclouds.logging.config.NullLoggingModule;
import org.jclouds.providers.ProviderMetadata;
import org.jclouds.rest.RestApiMetadata;
+import org.jclouds.rest.config.CredentialStoreModule;
import org.jclouds.util.Strings2;
import org.testng.annotations.Test;
import org.w3c.dom.Node;
@@ -74,6 +78,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
+import com.google.common.io.InputSupplier;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.google.inject.AbstractModule;
@@ -540,11 +545,13 @@
this.api = RestApiMetadata.class.cast(builder.getApiMetadata()).getApi();
+ // isolate tests from eachother, as default credentialStore is static
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();
}
-
+
/**
* override this to supply context-specific parameters during tests.
*/
diff --git a/labs/elb/src/main/java/org/jclouds/elb/loadbalancer/strategy/ELBListLoadBalancersStrategy.java b/labs/elb/src/main/java/org/jclouds/elb/loadbalancer/strategy/ELBListLoadBalancersStrategy.java
index 65dc261..b23916e 100644
--- a/labs/elb/src/main/java/org/jclouds/elb/loadbalancer/strategy/ELBListLoadBalancersStrategy.java
+++ b/labs/elb/src/main/java/org/jclouds/elb/loadbalancer/strategy/ELBListLoadBalancersStrategy.java
@@ -74,14 +74,14 @@
}
@Override
- public Iterable<? extends LoadBalancerMetadata> listLoadBalancers() {
+ public Iterable<LoadBalancerMetadata> listLoadBalancers() {
Iterable<? extends LoadBalancer> loadBalancers;
Set<String> regions = this.regions.get();
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
- public ListenableFuture<Set<? extends LoadBalancer>> apply(String from) {
+ public ListenableFuture<? extends Set<? extends LoadBalancer>> apply(String from) {
return aclient.describeLoadBalancersInRegion(from);
}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/compute/GleSYSComputeServiceAdapter.java b/labs/glesys/src/main/java/org/jclouds/glesys/compute/GleSYSComputeServiceAdapter.java
index 1fc9e28..386b2c4 100644
--- a/labs/glesys/src/main/java/org/jclouds/glesys/compute/GleSYSComputeServiceAdapter.java
+++ b/labs/glesys/src/main/java/org/jclouds/glesys/compute/GleSYSComputeServiceAdapter.java
@@ -62,6 +62,7 @@
import org.jclouds.location.predicates.LocationPredicates;
import org.jclouds.logging.Logger;
import org.jclouds.predicates.RetryablePredicate;
+import org.jclouds.util.Iterables2;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
@@ -196,13 +197,13 @@
@Override
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
public Future<ServerDetails> apply(Server from) {
return aclient.getServerClient().getServerDetails(from.getId());
}
- }, userThreads, null, logger, "server details");
+ }, userThreads, null, logger, "server details"));
}
@Override
diff --git a/labs/virtualbox/pom.xml b/labs/virtualbox/pom.xml
index 1d00179..fd78a46 100644
--- a/labs/virtualbox/pom.xml
+++ b/labs/virtualbox/pom.xml
@@ -39,7 +39,7 @@
<test.virtualbox.build-version>4.1.8r75467</test.virtualbox.build-version>
<test.virtualbox.identity>administrator</test.virtualbox.identity>
<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.authenticate-sudo>true</test.virtualbox.image.authenticate-sudo>
</properties>
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapter.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapter.java
index eb0a889..e2e1d21 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapter.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapter.java
@@ -27,12 +27,15 @@
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_PREFIX;
import java.util.Map;
+import java.util.Set;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
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.Template;
import org.jclouds.compute.reference.ComputeServiceConstants;
@@ -58,6 +61,7 @@
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
import com.google.inject.Singleton;
/**
@@ -67,25 +71,28 @@
* @author Mattias Holmqvist, Andrea Turli, David Alves
*/
@Singleton
-public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IMachine, IMachine, Image, Location> {
+public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IMachine, Hardware, Image, Location> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
-
+
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 Function<NodeSpec, NodeAndInitialCredentials<IMachine>> cloneCreator;
+ private final Function<IMachine, Image> imachineToImage;
@Inject
public VirtualBoxComputeServiceAdapter(Supplier<VirtualBoxManager> manager,
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.images = imagesMapper.get();
+ this.imagesToYamlImages = imagesMapper.get();
this.mastersLoader = mastersLoader;
this.cloneCreator = cloneCreator;
+ this.imachineToImage = imachineToImage;
}
@Override
@@ -97,7 +104,7 @@
checkState(!name.contains(VIRTUALBOX_NODE_NAME_SEPARATOR), "node names cannot contain \""
+ VIRTUALBOX_NODE_NAME_SEPARATOR + "\"");
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();
return cloneCreator.apply(nodeSpec);
} catch (Exception e) {
@@ -116,13 +123,39 @@
}
@Override
- public Iterable<IMachine> listHardwareProfiles() {
- return imageMachines();
+ public Iterable<Hardware> listHardwareProfiles() {
+ 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
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() {
@@ -147,7 +180,7 @@
try {
return manager.get().getVBox().findMachine(vmName);
} 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;
}
throw Throwables.propagate(e);
@@ -202,7 +235,7 @@
private void powerDownMachine(IMachine machine) {
try {
- if (machine.getState() == MachineState.PoweredOff){
+ if (machine.getState() == MachineState.PoweredOff) {
logger.debug("vm was already powered down: ", machine.getId());
return;
}
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/compute/VirtualBoxImageExtension.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/compute/VirtualBoxImageExtension.java
new file mode 100644
index 0000000..3b85954
--- /dev/null
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/compute/VirtualBoxImageExtension.java
@@ -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);
+ }
+ });
+ }
+
+}
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxComputeServiceContextModule.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxComputeServiceContextModule.java
index 55160e8..120c862 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxComputeServiceContextModule.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxComputeServiceContextModule.java
@@ -40,8 +40,9 @@
import org.jclouds.byon.functions.NodeToNodeMetadata;
import org.jclouds.byon.suppliers.SupplyFromProviderURIOrNodesProperty;
import org.jclouds.compute.ComputeServiceAdapter;
-import org.jclouds.compute.ComputeServiceContext;
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.domain.Hardware;
import org.jclouds.compute.domain.HardwareBuilder;
@@ -58,6 +59,7 @@
import org.jclouds.sshj.config.SshjSshClientModule;
import org.jclouds.virtualbox.Host;
import org.jclouds.virtualbox.compute.VirtualBoxComputeServiceAdapter;
+import org.jclouds.virtualbox.compute.VirtualBoxImageExtension;
import org.jclouds.virtualbox.domain.CloneSpec;
import org.jclouds.virtualbox.domain.ExecutionType;
import org.jclouds.virtualbox.domain.IsoSpec;
@@ -88,6 +90,7 @@
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Functions;
+import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
@@ -105,17 +108,19 @@
*/
@SuppressWarnings("unchecked")
public class VirtualBoxComputeServiceContextModule extends
- ComputeServiceAdapterContextModule<IMachine, IMachine, Image, Location> {
+ ComputeServiceAdapterContextModule<IMachine, Hardware, Image, Location> {
@Override
protected void configure() {
super.configure();
- bind(new TypeLiteral<ComputeServiceAdapter<IMachine, IMachine, Image, Location>>() {
+ bind(new TypeLiteral<ComputeServiceAdapter<IMachine, Hardware, Image, Location>>() {
}).to(VirtualBoxComputeServiceAdapter.class);
bind(new TypeLiteral<Function<IMachine, NodeMetadata>>() {
}).to(IMachineToNodeMetadata.class);
bind(new TypeLiteral<Function<Location, Location>>() {
}).to((Class) IdentityFunction.class);
+ bind(new TypeLiteral<Function<Hardware, Hardware>>() {
+ }).to((Class) IdentityFunction.class);
bind(new TypeLiteral<Function<Image, Image>>() {
}).to((Class) IdentityFunction.class);
bind(new TypeLiteral<Function<IMachine, Hardware>>() {
@@ -139,6 +144,10 @@
bind(new TypeLiteral<LoadingCache<Image, Master>>() {
}).to(MastersLoadingCache.class);
+ // the vbox image extension
+ bind(new TypeLiteral<ImageExtension>() {
+ }).to(VirtualBoxImageExtension.class);
+
// the master creating function
bind(new TypeLiteral<Function<MasterSpec, IMachine>>() {
}).to((Class) CreateAndInstallVm.class);
@@ -166,10 +175,9 @@
@Host
@Singleton
protected ComputeServiceContext provideHostController() {
- return ContextBuilder.newBuilder(new BYONApiMetadata())
- .credentials("", "")
- .modules(ImmutableSet.<Module> of(new SLF4JLoggingModule(), new SshjSshClientModule()))
- .build(ComputeServiceContext.class);
+ return ContextBuilder.newBuilder(new BYONApiMetadata()).credentials("", "")
+ .modules(ImmutableSet.<Module> of(new SLF4JLoggingModule(), new SshjSshClientModule()))
+ .build(ComputeServiceContext.class);
}
@Provides
@@ -203,18 +211,6 @@
}
@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
protected TemplateBuilder provideTemplate(Injector injector, TemplateBuilder template) {
return template.osFamily(VIRTUALBOX_DEFAULT_IMAGE_OS).osVersionMatches(VIRTUALBOX_DEFAULT_IMAGE_VERSION)
.osArchMatches(VIRTUALBOX_DEFAULT_IMAGE_ARCH);
@@ -233,6 +229,11 @@
}), nodes);
}
+ @Override
+ protected Optional<ImageExtension> provideImageExtension(Injector i) {
+ return Optional.of(i.getInstance(ImageExtension.class));
+ }
+
@VisibleForTesting
public static final Map<MachineState, NodeState> machineToNodeState = ImmutableMap
.<MachineState, NodeState> builder().put(MachineState.Running, NodeState.RUNNING)
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIMachineIfNotAlreadyExists.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIMachineIfNotAlreadyExists.java
index 0fb2f36..46521df 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIMachineIfNotAlreadyExists.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIMachineIfNotAlreadyExists.java
@@ -99,13 +99,13 @@
.getVBox()
.createMachine(settingsFile, vmSpec.getVmName(), vmSpec.getOsTypeId(), vmSpec.getVmId(),
vmSpec.isForceOverwrite());
-
+
List<CloneOptions> options = new ArrayList<CloneOptions>();
if (isLinkedClone)
options.add(CloneOptions.Link);
// TODO snapshot name
- ISnapshot currentSnapshot = new TakeSnapshotIfNotAlreadyAttached(manager, "snapshotName", "snapshotDesc")
+ ISnapshot currentSnapshot = new TakeSnapshotIfNotAlreadyAttached(manager, "snapshotName", "snapshotDesc", logger)
.apply(master);
// clone
@@ -114,6 +114,9 @@
progress.waitForCompletion(-1);
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
manager.get().getVBox().registerMachine(clonedMachine);
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToImage.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToImage.java
index 36805d7..dab6dac 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToImage.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToImage.java
@@ -33,6 +33,7 @@
import org.jclouds.compute.domain.OperatingSystem;
import org.jclouds.compute.domain.OsFamily;
import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.virtualbox.config.VirtualBoxConstants;
import org.virtualbox_4_1.IGuestOSType;
import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.VirtualBoxManager;
@@ -63,7 +64,9 @@
OperatingSystem os = OperatingSystem.builder().description(guestOSType.getDescription()).family(family)
.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();
}
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToNodeMetadata.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToNodeMetadata.java
index 9e99d8c..5379d38 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToNodeMetadata.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToNodeMetadata.java
@@ -95,8 +95,6 @@
nodeState = NodeState.UNRECOGNIZED;
nodeMetadataBuilder.state(nodeState);
- logger.debug("Setting virtualbox node to: " + nodeState + " from machine state: " + vmState);
-
/*
// nat adapter
INetworkAdapter natAdapter = vm.getNetworkAdapter(0l);
@@ -139,7 +137,6 @@
private NodeMetadataBuilder getIpAddresses(IMachine vm, NodeMetadataBuilder nodeMetadataBuilder) {
List<String> publicIpAddresses = Lists.newArrayList();
- List<String> privateIpAddresses = Lists.newArrayList();
for(long slot = 0; slot < 4; slot ++) {
INetworkAdapter adapter = vm.getNetworkAdapter(slot);
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MastersLoadingCache.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MastersLoadingCache.java
index 5aa6682..e54c011 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MastersLoadingCache.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MastersLoadingCache.java
@@ -141,14 +141,51 @@
return masters.get(key.getId());
}
- // the yaml image
- 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 \""
+ checkState(!key.getId().contains(VIRTUALBOX_NODE_NAME_SEPARATOR), "master image names cannot contain \""
+ 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 guestAdditionsIso = String.format("%s/%s", isosDir, guestAdditionsFileName);
String guestAdditionsUri = "http://download.virtualbox.org/virtualbox/" + version + "/" + guestAdditionsFileName;
@@ -160,8 +197,6 @@
// check if the iso is here, download if not
String localIsoUrl = getFilePathOrDownload(currentImage.iso);
- String vmName = VIRTUALBOX_IMAGE_PREFIX + currentImage.id;
-
String adminDisk = workingDir + File.separator + vmName + ".vdi";
HardDisk hardDisk = HardDisk.builder().diskpath(adminDisk).autoDelete(true).controllerPort(0).deviceSlot(1)
@@ -174,46 +209,19 @@
.controller(ideController).forceOverwrite(true).cleanUpMode(CleanupMode.Full).build();
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)
.slot(0L).build();
-
+
NetworkSpec networkSpec = NetworkSpec.builder().addNIC(networkInterfaceCard).build();
- MasterSpec masterSpec = MasterSpec
+ return MasterSpec
.builder()
.vm(vmSpecification)
.iso(IsoSpec.builder().sourcePath(localIsoUrl)
.installationScript(installationKeySequence.replace("HOSTNAME", vmSpecification.getVmName()))
.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
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/NodeCreator.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/NodeCreator.java
index a7f2ff9..a70f4ef 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/NodeCreator.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/NodeCreator.java
@@ -118,12 +118,18 @@
progress.waitForCompletion(-1);
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
+ 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();
// CASE NAT + HOST-ONLY
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/TakeSnapshotIfNotAlreadyAttached.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/TakeSnapshotIfNotAlreadyAttached.java
index e496cb5..830c23e 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/TakeSnapshotIfNotAlreadyAttached.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/TakeSnapshotIfNotAlreadyAttached.java
@@ -20,15 +20,13 @@
package org.jclouds.virtualbox.functions;
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.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.IProgress;
import org.virtualbox_4_1.ISession;
import org.virtualbox_4_1.ISnapshot;
+import org.virtualbox_4_1.MachineState;
import org.virtualbox_4_1.VirtualBoxManager;
import com.google.common.base.Function;
@@ -40,55 +38,80 @@
*/
public class TakeSnapshotIfNotAlreadyAttached implements Function<IMachine, ISnapshot> {
- @Resource
- @Named(ComputeServiceConstants.COMPUTE_LOGGER)
- protected Logger logger = Logger.NULL;
-
private Supplier<VirtualBoxManager> manager;
private String snapshotName;
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.snapshotName = snapshotName;
this.snapshotDesc = snapshotDesc;
+ this.logger = logger;
}
@Override
public ISnapshot apply(@Nullable IMachine machine) {
// Snapshot a machine
ISession session = null;
- if (machine.getCurrentSnapshot() == null) {
- int retries = 10;
- while (true) {
- try {
- session = manager.get().openMachineSession(machine);
- IProgress progress = session.getConsole().takeSnapshot(snapshotName, snapshotDesc);
- progress.waitForCompletion(-1);
- 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")) {
- 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);
+ ISnapshot snap = machine.getCurrentSnapshot();
+
+ if (snap == null) {
+ try {
+ session = manager.get().openMachineSession(machine);
+ logger.debug("No snapshot available taking new one: %s (description: %s) taken from %s", snapshotName,
+ snapshotDesc, machine.getName());
+ int retries = 10;
+ while (true) {
+ try {
+
+ // running machines need to be pause before a snapshot can be taken
+ // due to a vbox bug see https://www.virtualbox.org/ticket/9255
+ boolean paused = false;
+ if (machine.getState() == MachineState.Running) {
+ session.getConsole().pause();
+ paused = true;
}
- }
- logger.error(e, "Problem creating snapshot %s (descripton: %s) from machine %s", snapshotName,
- snapshotDesc, machine.getName());
- throw Throwables.propagate(e);
- } finally {
- if (session != null) {
- session.unlockMachine();
+
+ IProgress progress = session.getConsole().takeSnapshot(snapshotName, snapshotDesc);
+ progress.waitForCompletion(-1);
+
+ if (paused) {
+ session.getConsole().resume();
+ }
+
+ 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;
+ }
}
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunning.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunning.java
index dda2cb3..8c231f1 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunning.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunning.java
@@ -26,7 +26,6 @@
import java.net.URI;
import javax.annotation.Nullable;
-import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
@@ -74,10 +73,10 @@
this.host = checkNotNull(host, "host");
this.providerSupplier = checkNotNull(providerSupplier, "endpoint to virtualbox websrvd is needed");
this.managerForNode = checkNotNull(managerForNode, "managerForNode");
+ start();
}
- @PostConstruct
- public void start() {
+ public synchronized void start() {
URI provider = providerSupplier.get();
if (!socketTester.apply(new IPSocket(provider.getHost(), provider.getPort()))) {
logger.debug("disabling password access");
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/UnregisterMachineIfExistsAndDeleteItsMedia.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/UnregisterMachineIfExistsAndDeleteItsMedia.java
index ce02937..bc3dde9 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/UnregisterMachineIfExistsAndDeleteItsMedia.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/UnregisterMachineIfExistsAndDeleteItsMedia.java
@@ -17,7 +17,7 @@
* 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
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
@@ -93,8 +93,8 @@
}
}
- List<IMedium> filteredMediaToBeDeleted = Lists.newArrayList(transform(filter(mediaToBeDeleted,
- new AutoDeleteHardDiskPredicate(vmSpec)), new DeleteChildrenOfMedium()));
+ List<IMedium> filteredMediaToBeDeleted = Lists.newArrayList(transform(
+ filter(mediaToBeDeleted, new AutoDeleteHardDiskPredicate(vmSpec)), new DeleteChildrenOfMedium()));
if (!filteredMediaToBeDeleted.isEmpty()) {
try {
@@ -105,7 +105,7 @@
Throwables.propagate(e);
}
}
-
+
return null;
}
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/UnregisterMachineIfExistsAndForceDeleteItsMedia.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/UnregisterMachineIfExistsAndForceDeleteItsMedia.java
index b4d2e7c..db2761c 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/UnregisterMachineIfExistsAndForceDeleteItsMedia.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/UnregisterMachineIfExistsAndForceDeleteItsMedia.java
@@ -105,8 +105,17 @@
checkNotNull(medium.getChildren());
if (medium.getDeviceType().equals(DeviceType.HardDisk)) {
for (IMedium child : medium.getChildren()) {
- IProgress deletion = child.deleteStorage();
- deletion.waitForCompletion(-1);
+ try {
+ 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;
diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/BaseVirtualBoxClientLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/BaseVirtualBoxClientLiveTest.java
index fe6cf54..33477e5 100644
--- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/BaseVirtualBoxClientLiveTest.java
+++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/BaseVirtualBoxClientLiveTest.java
@@ -39,6 +39,7 @@
import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.config.ValueOfConfigurationKeyOrNull;
import org.jclouds.rest.annotations.BuildVersion;
+import org.jclouds.sshj.config.SshjSshClientModule;
import org.jclouds.virtualbox.config.VirtualBoxConstants;
import org.jclouds.virtualbox.domain.HardDisk;
import org.jclouds.virtualbox.domain.IsoSpec;
@@ -217,6 +218,11 @@
"/default-images.yaml")).get();
return images.get(Iterables.getOnlyElement(Iterables.filter(images.keySet(), new DefaultImagePredicate())));
}
+
+ @Override
+ protected Module getSshModule() {
+ return new SshjSshClientModule();
+ }
@AfterClass(groups = "live")
protected void tearDown() throws Exception {
diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapterLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapterLiveTest.java
index b01067c..525331a 100644
--- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapterLiveTest.java
+++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapterLiveTest.java
@@ -27,6 +27,7 @@
import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials;
import org.jclouds.compute.domain.ExecResponse;
+import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.Template;
import org.jclouds.domain.LoginCredentials;
@@ -76,7 +77,7 @@
@Test
public void testListHardwareProfiles() {
- Iterable<IMachine> profiles = adapter.listHardwareProfiles();
+ Iterable<Hardware> profiles = adapter.listHardwareProfiles();
assertTrue(!Iterables.isEmpty(profiles));
}
diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxImageExtensionLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxImageExtensionLiveTest.java
new file mode 100644
index 0000000..c498ce9
--- /dev/null
+++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxImageExtensionLiveTest.java
@@ -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();
+ }
+
+}
diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java
index d475cd8..45bd5df 100644
--- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java
+++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java
@@ -20,7 +20,7 @@
package org.jclouds.virtualbox.functions;
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_INSTALLATION_KEY_SEQUENCE;
@@ -56,9 +56,7 @@
import com.google.common.base.CaseFormat;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
-import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
import com.google.inject.Guice;
import com.google.inject.Injector;
@@ -166,15 +164,14 @@
checkState(sshResponds.apply(client), "timed out waiting for guest %s to be accessible via ssh",
machine.getName());
- String vboxVersion = Iterables.get(
- Splitter.on('r').split(context.getProviderSpecificContext().getBuildVersion()), 0);
- assertEquals(vboxVersion,
- machineUtils.sharedLockMachineAndApplyToSession(machine.getName(), new Function<ISession, String>() {
- @Override
- public String apply(ISession session) {
- return session.getMachine().getGuestPropertyValue("/VirtualBox/GuestAdd/Version");
- }
- }));
+ String version = machineUtils.sharedLockMachineAndApplyToSession(machine.getName(), new Function<ISession, String>() {
+ @Override
+ public String apply(ISession session) {
+ return session.getMachine().getGuestPropertyValue("/VirtualBox/GuestAdd/Version");
+ }
+ });
+
+ assertTrue(version != null && !version.isEmpty());
} finally {
for (VmSpec spec : ImmutableSet.of(machineSpec.getVmSpec())) {
machineController.ensureMachineIsShutdown(spec.getVmName());
diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/IMachineToImageTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/IMachineToImageTest.java
index b47f5de..8db2dfb 100644
--- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/IMachineToImageTest.java
+++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/IMachineToImageTest.java
@@ -34,6 +34,7 @@
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.json.Json;
import org.jclouds.json.config.GsonModule;
+import org.jclouds.virtualbox.config.VirtualBoxConstants;
import org.testng.annotations.Test;
import org.virtualbox_4_1.IGuestOSType;
import org.virtualbox_4_1.IMachine;
@@ -48,7 +49,7 @@
Map<OsFamily, Map<String, String>> map = new BaseComputeServiceContextModule() {
}.provideOsVersionMap(new ComputeServiceConstants.ReferenceData(), Guice.createInjector(new GsonModule())
- .getInstance(Json.class));
+ .getInstance(Json.class));
@Test
public void testConvert() throws Exception {
@@ -61,6 +62,7 @@
expect(vbm.getVBox()).andReturn(vBox).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(vm.getDescription()).andReturn("my-ubuntu-machine").anyTimes();
expect(guestOsType.getDescription()).andReturn(linuxDescription).anyTimes();
@@ -77,6 +79,7 @@
assertTrue(image.getOperatingSystem().is64Bit());
assertEquals(image.getOperatingSystem().getFamily(), OsFamily.UBUNTU);
assertEquals(image.getOperatingSystem().getVersion(), "10.04");
+ assertEquals(image.getId(), "my-vm-id");
}
@@ -91,6 +94,7 @@
String vmDescription = "ubuntu-11.04-server-i386";
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(vBox.getGuestOSType(eq("os-type"))).andReturn(guestOsType);
expect(vm.getDescription()).andReturn(vmDescription).anyTimes();
@@ -108,6 +112,7 @@
assertTrue(image.getOperatingSystem().is64Bit());
assertEquals(image.getOperatingSystem().getFamily(), OsFamily.UBUNTU);
assertEquals(image.getOperatingSystem().getVersion(), "11.04");
+ assertEquals(image.getId(), "my-vm-id");
}
@@ -121,6 +126,7 @@
expect(vbm.getVBox()).andReturn(vBox).anyTimes();
+ expect(vm.getName()).andReturn(VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX + "my-vm-id").anyTimes();
String unknownOsDescription = "SomeOtherOs 2.04";
expect(vm.getOSTypeId()).andReturn("os-type").anyTimes();
expect(vm.getDescription()).andReturn("my-unknown-machine").anyTimes();
@@ -136,6 +142,7 @@
assertEquals(image.getOperatingSystem().getDescription(), "SomeOtherOs 2.04");
assertEquals(image.getOperatingSystem().getVersion(), "");
+ assertEquals(image.getId(), "my-vm-id");
}
diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/TakeSnapshotIfNotAlreadyAttachedTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/TakeSnapshotIfNotAlreadyAttachedTest.java
index 6b2f3a0..3e3bb58 100644
--- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/TakeSnapshotIfNotAlreadyAttachedTest.java
+++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/TakeSnapshotIfNotAlreadyAttachedTest.java
@@ -24,6 +24,7 @@
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
+import org.jclouds.logging.Logger;
import org.testng.annotations.Test;
import org.virtualbox_4_1.IConsole;
import org.virtualbox_4_1.IMachine;
@@ -31,6 +32,7 @@
import org.virtualbox_4_1.ISession;
import org.virtualbox_4_1.ISnapshot;
import org.virtualbox_4_1.IVirtualBox;
+import org.virtualbox_4_1.MachineState;
import org.virtualbox_4_1.VirtualBoxManager;
import com.google.common.base.Suppliers;
@@ -55,6 +57,7 @@
IProgress progress = createNiceMock(IProgress.class);
ISnapshot snapshot = createNiceMock(ISnapshot.class);
expect(machine.getCurrentSnapshot()).andReturn(snapshot).anyTimes();
+ expect(machine.getState()).andReturn(MachineState.PoweredOff).anyTimes();
expect(manager.openMachineSession(machine)).andReturn(session);
@@ -66,7 +69,7 @@
session.unlockMachine();
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);
verify(machine);
@@ -87,6 +90,7 @@
expect(progress.getCompleted()).andReturn(true);
expect(machine.getCurrentSnapshot()).andReturn(null).anyTimes();
expect(manager.openMachineSession(machine)).andReturn(session);
+ expect(machine.getState()).andReturn(MachineState.PoweredOff).anyTimes();
expect(machine.getName()).andReturn("machine").anyTimes();
expect(session.getConsole()).andReturn(console);
@@ -96,7 +100,7 @@
session.unlockMachine();
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);
verify(machine);
diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunningLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunningLiveTest.java
index 6be7199..be64f61 100644
--- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunningLiveTest.java
+++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunningLiveTest.java
@@ -21,6 +21,7 @@
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.jclouds.compute.options.RunScriptOptions.Builder.runAsRoot;
@@ -58,10 +59,9 @@
String identity = "adminstrator";
String credential = "12345";
expect(client.seconds(3)).andReturn(client);
-
- expect(client.apply(new IPSocket(provider.getHost(), provider.getPort()))).andReturn(true);
-
+ expect(client.apply(new IPSocket(provider.getHost(), provider.getPort()))).andReturn(true).anyTimes();
manager.connect(provider.toASCIIString(), "", "");
+ expectLastCall().anyTimes();
replay(manager, runScriptOnNodeFactory, client);
@@ -87,17 +87,18 @@
String credential = "12345";
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(
runScriptOnNodeFactory.create(host, Statements.exec("VBoxManage setproperty websrvauthlibrary null"),
runAsRoot(false).wrapInInitScript(false))).andReturn(runScriptOnNode);
expect(runScriptOnNode.init()).andReturn(runScriptOnNode);
expect(runScriptOnNode.call()).andReturn(new ExecResponse("", "", 0));
- expect(client.apply(new IPSocket(provider.getHost(), provider.getPort()))).andReturn(true);
+
expect(
runScriptOnNodeFactory.create(host, Statements.exec("vboxwebsrv -t 10000 -v -b"), runAsRoot(false)
.wrapInInitScript(false).blockOnComplete(false).nameTask("vboxwebsrv"))).andReturn(
runScriptOnNode);
+
expect(runScriptOnNode.init()).andReturn(runScriptOnNode);
expect(runScriptOnNode.call()).andReturn(new ExecResponse("", "", 0));
@@ -105,7 +106,7 @@
replay(manager, runScriptOnNodeFactory, runScriptOnNode, 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);
}
diff --git a/labs/virtualbox/src/test/resources/logback.xml b/labs/virtualbox/src/test/resources/logback.xml
index f9b64ed..3a5a73c 100644
--- a/labs/virtualbox/src/test/resources/logback.xml
+++ b/labs/virtualbox/src/test/resources/logback.xml
@@ -39,7 +39,7 @@
</appender>
<root>
- <level value="debug" />
+ <level value="DEBUG" />
<appender-ref ref="CONSOLE" />
</root>
@@ -49,7 +49,7 @@
</logger>
<logger name="jclouds.wire">
- <level value="INFO" />
+ <level value="DEBUG" />
<appender-ref ref="WIREFILE" />
</logger>
diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeService.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeService.java
index d54c7ed..eccd369 100644
--- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeService.java
+++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeService.java
@@ -42,6 +42,7 @@
import org.jclouds.aws.util.AWSUtils;
import org.jclouds.collect.Memoized;
import org.jclouds.compute.ComputeServiceContext;
+import org.jclouds.compute.ImageExtension;
import org.jclouds.compute.RunNodesException;
import org.jclouds.compute.callables.RunScriptOnNode;
import org.jclouds.compute.domain.Hardware;
@@ -72,6 +73,7 @@
import com.google.common.annotations.VisibleForTesting;
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.cache.LoadingCache;
@@ -111,12 +113,13 @@
@Named("SECURITY") LoadingCache<RegionAndName, String> securityGroupMap,
@Named("PLACEMENT") LoadingCache<RegionAndName, String> placementGroupMap,
@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,
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy,
stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
nodeSuspended, initScriptRunnerFactory, runScriptOnNodeFactory, initAdminAccess, persistNodeCredentials,
- timeouts, executor, ec2Client, credentialsMap, securityGroupMap);
+ timeouts, executor, ec2Client, credentialsMap, securityGroupMap, imageExtension);
this.ec2Client = ec2Client;
this.placementGroupMap = placementGroupMap;
this.placementGroupDeleted = placementGroupDeleted;
diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/strategy/AWSEC2ListNodesStrategy.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/strategy/AWSEC2ListNodesStrategy.java
index 8f09824..240e616 100644
--- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/strategy/AWSEC2ListNodesStrategy.java
+++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/strategy/AWSEC2ListNodesStrategy.java
@@ -69,12 +69,10 @@
@Override
protected Iterable<? extends RunningInstance> pollRunningInstances() {
Iterable<? extends AWSRunningInstance> spots = filter(transform(concat(transformParallel(regions.get(),
- new Function<String, Future<Set<SpotInstanceRequest>>>() {
-
- @SuppressWarnings("unchecked")
+ new Function<String, Future<? extends Set<SpotInstanceRequest>>>() {
@Override
- public Future<Set<SpotInstanceRequest>> apply(String from) {
- return (Future<Set<SpotInstanceRequest>>) client.getSpotInstanceServices()
+ public Future<? extends Set<SpotInstanceRequest>> apply(String from) {
+ return client.getSpotInstanceServices()
.describeSpotInstanceRequestsInRegion(from);
}
diff --git a/providers/gogrid/src/main/java/org/jclouds/gogrid/compute/GoGridComputeService.java b/providers/gogrid/src/main/java/org/jclouds/gogrid/compute/GoGridComputeService.java
index b03aadf..aaa3b6e 100644
--- a/providers/gogrid/src/main/java/org/jclouds/gogrid/compute/GoGridComputeService.java
+++ b/providers/gogrid/src/main/java/org/jclouds/gogrid/compute/GoGridComputeService.java
@@ -31,6 +31,7 @@
import org.jclouds.Constants;
import org.jclouds.collect.Memoized;
import org.jclouds.compute.ComputeServiceContext;
+import org.jclouds.compute.ImageExtension;
import org.jclouds.compute.callables.RunScriptOnNode;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image;
@@ -53,6 +54,7 @@
import org.jclouds.gogrid.compute.options.GoGridTemplateOptions;
import org.jclouds.scriptbuilder.functions.InitAdminAccess;
+import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
@@ -74,12 +76,12 @@
@Named("NODE_SUSPENDED") Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess,
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,
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, resumeNodeStrategy,
suspendNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials, timeouts,
- executor);
+ executor, imageExtension);
}
/**
diff --git a/providers/hpcloud-compute/src/test/java/org/jclouds/hpcloud/compute/compute/HPCloudComputeImageExtensionLivetest.java b/providers/hpcloud-compute/src/test/java/org/jclouds/hpcloud/compute/compute/HPCloudComputeImageExtensionLivetest.java
new file mode 100644
index 0000000..f632f51
--- /dev/null
+++ b/providers/hpcloud-compute/src/test/java/org/jclouds/hpcloud/compute/compute/HPCloudComputeImageExtensionLivetest.java
@@ -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();
+ }
+}
diff --git a/sandbox-apis/libvirt/src/main/java/org/jclouds/libvirt/compute/LibvirtComputeService.java b/sandbox-apis/libvirt/src/main/java/org/jclouds/libvirt/compute/LibvirtComputeService.java
index 93a4c97..2f83bde 100644
--- a/sandbox-apis/libvirt/src/main/java/org/jclouds/libvirt/compute/LibvirtComputeService.java
+++ b/sandbox-apis/libvirt/src/main/java/org/jclouds/libvirt/compute/LibvirtComputeService.java
@@ -31,6 +31,7 @@
import org.jclouds.Constants;
import org.jclouds.collect.Memoized;
import org.jclouds.compute.ComputeServiceContext;
+import org.jclouds.compute.ImageExtension;
import org.jclouds.compute.callables.RunScriptOnNode;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image;
@@ -55,6 +56,7 @@
import org.libvirt.StorageVol;
import org.xml.sax.InputSource;
+import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.base.Throwables;
@@ -85,12 +87,13 @@
@Named("NODE_SUSPENDED") Predicate<NodeMetadata> nodeSuspended,
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess,
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,
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, resumeNodeStrategy,
suspendNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials,
- timeouts, executor);
+ timeouts, executor, imageExtension);
this.client = client;
}