Merge branch 'master' into 1.5.x

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,48 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.openstack.nova.ec2.xml;
import org.jclouds.ec2.domain.Attachment;
import org.jclouds.ec2.domain.Volume;
import org.jclouds.ec2.xml.CreateVolumeResponseHandler;
/**
*
* @author Adam lowe
*/
public class NovaCreateVolumeResponseHandler extends CreateVolumeResponseHandler {
public void endElement(String uri, String name, String qName) {
if (qName.equals("status")) {
String statusString = currentText.toString().trim();
if (statusString.contains(" ")) {
statusString = statusString.substring(0, statusString.indexOf(' '));
}
if (inAttachmentSet) {
attachmentStatus = Attachment.Status.fromValue(statusString);
} else {
volumeStatus = Volume.Status.fromValue(statusString);
}
currentText = new StringBuilder();
} else {
super.endElement(uri, name, qName);
}
}
}

View File

@ -0,0 +1,54 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.openstack.nova.ec2.xml;
import java.util.Set;
import javax.inject.Inject;
import org.jclouds.ec2.domain.Image;
import org.jclouds.ec2.domain.Image.ImageType;
import org.jclouds.ec2.xml.DescribeImagesResponseHandler;
import org.jclouds.location.Region;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
/**
* Adjusted to filter out non-MACHINE images
*
* @author Adam Lowe
*/
public class NovaDescribeImagesResponseHandler extends DescribeImagesResponseHandler {
@Inject
public NovaDescribeImagesResponseHandler(@Region Supplier<String> defaultRegion) {
super(defaultRegion);
}
public Set<Image> getResult() {
return ImmutableSet.copyOf(Iterables.filter(contents, new Predicate<Image>() {
@Override
public boolean apply(Image image) {
return image.getImageType() == ImageType.MACHINE;
}
}));
}
}

View File

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

View File

@ -0,0 +1,58 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.openstack.nova.ec2.services;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import java.util.Set;
import org.jclouds.ec2.domain.Image;
import org.jclouds.ec2.services.AMIClient;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.nova.ec2.internal.BaseNovaEC2RestClientExpectTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap;
/**
* @author Adam Lowe
*/
@Test(groups = "unit", testName = "NovaEC2ElasticBlockStoreClientTest")
public class NovaEC2AMIClientTest extends BaseNovaEC2RestClientExpectTest {
public void testDescribeImagesWithNonMachineTypes() {
AMIClient client = requestsSendResponses(
describeAvailabilityZonesRequest,
describeAvailabilityZonesResponse,
HttpRequest.builder().method("POST")
.endpoint(URI.create("http://localhost:8773/services/Cloud/"))
.headers(ImmutableMultimap.of("Host", "localhost:8773"))
.payload(payloadFromStringWithContentType("Action=DescribeImages&Signature=Z3q3jSutwlfgvbcINT0Ed3AjrjxM4WMvQloXu%2F1kd40%3D&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2012-04-16T15%3A54%3A08.897Z&Version=2009-04-04&AWSAccessKeyId=identity", "application/x-www-form-urlencoded")).build(),
HttpResponse.builder().statusCode(200).payload(payloadFromResource("/nova_ec2_images_with_ramdisk.xml")).build()
).getAMIServices();
Set<? extends Image> images = client.describeImagesInRegion("nova");
assertEquals(images.size(), 1);
}
}

View File

@ -0,0 +1,68 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.openstack.nova.ec2.services;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import java.util.Set;
import org.jclouds.ec2.domain.Attachment;
import org.jclouds.ec2.domain.Volume;
import org.jclouds.ec2.services.ElasticBlockStoreClient;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.nova.ec2.internal.BaseNovaEC2RestClientExpectTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
/**
* @author Adam Lowe
*/
@Test(groups = "unit", testName = "NovaEC2ElasticBlockStoreClientTest")
public class NovaEC2ElasticBlockStoreClientTest extends BaseNovaEC2RestClientExpectTest {
public void testDescribeVolumesWithNovaEC2Status() {
ElasticBlockStoreClient client = requestsSendResponses(
describeAvailabilityZonesRequest,
describeAvailabilityZonesResponse,
HttpRequest.builder().method("POST")
.endpoint(URI.create("http://localhost:8773/services/Cloud/"))
.headers(ImmutableMultimap.of("Host", "localhost:8773"))
.payload(payloadFromStringWithContentType("Action=DescribeVolumes&Signature=AvRznSzGExM%2Buaj2JJj66wq4v4f%2BakicyLooRDtC0t0%3D&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2012-04-16T15%3A54%3A08.897Z&Version=2009-04-04&AWSAccessKeyId=identity", "application/x-www-form-urlencoded")).build(),
HttpResponse.builder().statusCode(200).payload(payloadFromResource("/nova_ec2_describe_volumes.xml")).build()
).getElasticBlockStoreServices();
Set<Volume> expected = ImmutableSet.of(Volume
.builder()
.status(Volume.Status.AVAILABLE)
.availabilityZone("nova")
.region("nova")
.id("vol-00000007")
.size(1)
.attachments(Attachment.builder().region("nova").build())
.createTime(dateService.iso8601SecondsDateParse("2012-04-10T10:39:52Z"))
.build());
assertEquals(client.describeVolumesInRegion("nova"), expected);
}
}

View File

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

View File

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

View File

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

View File

@ -33,6 +33,7 @@ import javax.inject.Singleton;
import org.jclouds.Constants; import org.jclouds.Constants;
import org.jclouds.collect.Memoized; import org.jclouds.collect.Memoized;
import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.ImageExtension;
import org.jclouds.compute.callables.RunScriptOnNode; import org.jclouds.compute.callables.RunScriptOnNode;
import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
@ -103,12 +104,12 @@ public class NovaComputeService extends BaseComputeService {
LoadingCache<ZoneAndName, SecurityGroupInZone> securityGroupMap, LoadingCache<ZoneAndName, SecurityGroupInZone> securityGroupMap,
LoadingCache<ZoneAndName, KeyPair> keyPairCache, LoadingCache<ZoneAndName, KeyPair> keyPairCache,
Function<Set<? extends NodeMetadata>, Multimap<String, String>> orphanedGroupsByZoneId, Function<Set<? extends NodeMetadata>, Multimap<String, String>> orphanedGroupsByZoneId,
GroupNamingConvention.Factory namingConvention) { GroupNamingConvention.Factory namingConvention, Optional<ImageExtension> imageExtension) {
super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy, super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy, stopNodeStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy,
templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated, nodeSuspended, stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials, timeouts, nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials,
executor); timeouts, executor, imageExtension);
this.novaClient = checkNotNull(novaClient, "novaClient"); this.novaClient = checkNotNull(novaClient, "novaClient");
this.securityGroupMap = checkNotNull(securityGroupMap, "securityGroupMap"); this.securityGroupMap = checkNotNull(securityGroupMap, "securityGroupMap");
this.keyPairCache = checkNotNull(keyPairCache, "keyPairCache"); this.keyPairCache = checkNotNull(keyPairCache, "keyPairCache");
@ -175,4 +176,6 @@ public class NovaComputeService extends BaseComputeService {
return NovaTemplateOptions.class.cast(super.templateOptions()); return NovaTemplateOptions.class.cast(super.templateOptions());
} }
} }

View File

@ -0,0 +1,101 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.openstack.nova.v1_1.compute;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import java.util.NoSuchElementException;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.compute.ImageExtension;
import org.jclouds.compute.domain.CloneImageTemplate;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.ImageTemplate;
import org.jclouds.compute.domain.ImageTemplateBuilder;
import org.jclouds.openstack.nova.v1_1.NovaClient;
import org.jclouds.openstack.nova.v1_1.domain.Server;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ImageInZone;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndId;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
@Singleton
public class NovaImageExtension implements ImageExtension {
private final NovaClient novaClient;
private final Function<ImageInZone, Image> imageInZoneToImage;
@Inject
public NovaImageExtension(NovaClient novaClient, Function<ImageInZone, Image> imageInZoneToImage) {
this.novaClient = checkNotNull(novaClient);
this.imageInZoneToImage = imageInZoneToImage;
}
@Override
public ImageTemplate buildImageTemplateFromNode(String name, final String id) {
ZoneAndId zoneAndId = ZoneAndId.fromSlashEncoded(id);
Server server = novaClient.getServerClientForZone(zoneAndId.getZone()).getServer(zoneAndId.getId());
if (server == null)
throw new NoSuchElementException("Cannot find server with id: " + zoneAndId);
CloneImageTemplate template = new ImageTemplateBuilder.CloneImageTemplateBuilder().nodeId(id).name(name).build();
return template;
}
@Override
public Image createImage(ImageTemplate template) {
checkState(template instanceof CloneImageTemplate,
" openstack-nova only supports creating images through cloning.");
CloneImageTemplate cloneTemplate = (CloneImageTemplate) template;
ZoneAndId zoneAndId = ZoneAndId.fromSlashEncoded(cloneTemplate.getSourceNodeId());
String newImageId = novaClient.getServerClientForZone(zoneAndId.getZone()).createImageFromServer(
cloneTemplate.getName(), zoneAndId.getId());
org.jclouds.openstack.nova.v1_1.domain.Image newImage = checkNotNull(findImage(ZoneAndId.fromZoneAndId(
zoneAndId.getZone(), newImageId)));
return imageInZoneToImage.apply(new ImageInZone(newImage, zoneAndId.getZone()));
}
@Override
public boolean deleteImage(String id) {
ZoneAndId zoneAndId = ZoneAndId.fromSlashEncoded(id);
try {
this.novaClient.getImageClientForZone(zoneAndId.getZone()).deleteImage(zoneAndId.getId());
} catch (Exception e) {
return false;
}
return true;
}
private org.jclouds.openstack.nova.v1_1.domain.Image findImage(final ZoneAndId zoneAndId) {
return Iterables.tryFind(novaClient.getImageClientForZone(zoneAndId.getZone()).listImagesInDetail(),
new Predicate<org.jclouds.openstack.nova.v1_1.domain.Image>() {
@Override
public boolean apply(org.jclouds.openstack.nova.v1_1.domain.Image input) {
return input.getId().equals(zoneAndId.getId());
}
}).orNull();
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,164 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing)
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.openstack.nova.v1_1.parse;
import java.net.URI;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.json.BaseSetParserTest;
import org.jclouds.json.config.GsonModule;
import org.jclouds.openstack.domain.Link;
import org.jclouds.openstack.domain.Link.Relation;
import org.jclouds.openstack.domain.Resource;
import org.jclouds.openstack.nova.v1_1.config.NovaParserModule;
import org.jclouds.openstack.nova.v1_1.domain.Address;
import org.jclouds.openstack.nova.v1_1.domain.Server;
import org.jclouds.rest.annotations.SelectJson;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "ParseServerDetailsEssexTest")
public class ParseServerDetailsEssexTest extends BaseSetParserTest<Server> {
@Override
public String resource() {
return "/server_list_details_essex.json";
}
@Override
@SelectJson("servers")
@Consumes(MediaType.APPLICATION_JSON)
public Set<Server> expected() {
return ImmutableSet.<Server>of(
Server.builder()
.addresses(ImmutableMultimap.<String, Address>builder()
.putAll("Net TenantA Front-Middle", Address.createV4("172.16.11.5"))
.putAll("Public network", Address.createV4("172.16.1.13"), Address.createV4("10.193.112.119")).build())
.links(
Link.create(
Relation.SELF,
URI.create("http://nova:8774/v1.1/8d10e6646d5d4585937395b04839a353/servers/0c80b392-db30-4736-ae02-4480090f1207")),
Link.create(
Relation.BOOKMARK,
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/servers/0c80b392-db30-4736-ae02-4480090f1207")))
.image(
Resource.builder()
.id("416af940-2d3c-4a7c-977c-a9030685ad5e")
.links(
Link.create(
Relation.BOOKMARK,
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/images/416af940-2d3c-4a7c-977c-a9030685ad5e"))).build())
.flavor(
Resource.builder()
.id("1")
.links(
Link.create(
Relation.BOOKMARK,
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/flavors/1"))).build())
.id("0c80b392-db30-4736-ae02-4480090f1207")
.userId("df13814f6c354d00a8acf66502836323")
.status(Server.Status.ACTIVE)
.updated(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-04-12T11:21:33Z"))
.hostId("03d796ebb52b1b555e5f6d9262f7dbd52b3f7c181e3aa89b34ca5408")
.name("VM proxy")
.created(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-04-12T11:21:23Z"))
.tenantId("8d10e6646d5d4585937395b04839a353").build(),
Server.builder()
.addresses(ImmutableMultimap.<String, Address>builder()
.putAll("Net TenantA Front-Middle", Address.createV4("172.16.11.4"))
.putAll("Net TenantA Middle-Back", Address.createV4("172.16.12.5")).build())
.links(
Link.create(
Relation.SELF,
URI.create("http://nova:8774/v1.1/8d10e6646d5d4585937395b04839a353/servers/b332b5cd-535e-4677-b68e-fc8badc13236")),
Link.create(
Relation.BOOKMARK,
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/servers/b332b5cd-535e-4677-b68e-fc8badc13236")))
.image(
Resource.builder()
.id("416af940-2d3c-4a7c-977c-a9030685ad5e")
.links(
Link.create(
Relation.BOOKMARK,
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/images/416af940-2d3c-4a7c-977c-a9030685ad5e"))).build())
.flavor(
Resource.builder()
.id("1")
.links(
Link.create(
Relation.BOOKMARK,
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/flavors/1"))).build())
.id("b332b5cd-535e-4677-b68e-fc8badc13236")
.userId("df13814f6c354d00a8acf66502836323")
.status(Server.Status.ACTIVE)
.updated(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-04-12T11:18:58Z"))
.hostId("e5bbff80bebacfe1db63951e787b5341427060a602d33abfefb6a1bc")
.name("VM blog")
.created(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-04-12T11:18:48Z"))
.tenantId("8d10e6646d5d4585937395b04839a353").build(),
Server.builder()
.addresses(ImmutableMultimap.<String, Address>builder()
.putAll("Net TenantA Middle-Back", Address.createV4("172.16.12.4")).build())
.links(
Link.create(
Relation.SELF,
URI.create("http://nova:8774/v1.1/8d10e6646d5d4585937395b04839a353/servers/f9d43436-4572-4c9b-9b74-5fa6890a2f21")),
Link.create(
Relation.BOOKMARK,
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/servers/f9d43436-4572-4c9b-9b74-5fa6890a2f21")))
.image(
Resource.builder()
.id("416af940-2d3c-4a7c-977c-a9030685ad5e")
.links(
Link.create(
Relation.BOOKMARK,
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/images/416af940-2d3c-4a7c-977c-a9030685ad5e"))).build())
.flavor(
Resource.builder()
.id("1")
.links(
Link.create(
Relation.BOOKMARK,
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/flavors/1"))).build())
.id("f9d43436-4572-4c9b-9b74-5fa6890a2f21")
.userId("df13814f6c354d00a8acf66502836323")
.status(Server.Status.ACTIVE)
.updated(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-04-12T11:15:09Z"))
.hostId("03d796ebb52b1b555e5f6d9262f7dbd52b3f7c181e3aa89b34ca5408")
.name("VM MySQL")
.created(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-04-12T11:14:56Z"))
.tenantId("8d10e6646d5d4585937395b04839a353").build());
}
protected Injector injector() {
return Guice.createInjector(new NovaParserModule(), new GsonModule());
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,63 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.compute;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.ImageTemplate;
/**
* An extension to compute service to allow for the manipulation of {@link Image}s. Implementation
* is optional by providers.
*
* @author David Alves
*/
public interface ImageExtension {
/**
* Build an ImageTemplate from a running node, to use later to create a new {@link Image}.
*
* @param name
* name to give the new image
*
* @param id
* node to base the template on
* @return an image template that can be used to create a new image
*/
ImageTemplate buildImageTemplateFromNode(String name, String id);
/**
* Transform the {@link ImageTemplate} on an {@link Image} that can be used to create nodes.
*
* @param template
* template to base the new image on
* @return the image that was just built *after* it is registered on the provider
*/
Image createImage(ImageTemplate template);
/**
* Delete an {@link Image} on the provider.
*
* @param id
* the id of the image to delete
* @return
*/
boolean deleteImage(String id);
}

View File

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

View File

@ -0,0 +1,31 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.compute.domain;
/**
* An {@link ImageTemplate} for the purpose of cloning an existing node.
*
* @author David Alves
*/
public interface CloneImageTemplate extends ImageTemplate {
public String getSourceNodeId();
}

View File

@ -0,0 +1,35 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.compute.domain;
/**
* A template for building new {@link Image}s.
*
* @author David Alves
*
*/
public interface ImageTemplate {
/**
* @return the name of the new image
*/
public String getName();
}

View File

@ -0,0 +1,62 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.compute.domain;
import org.jclouds.compute.domain.internal.ImageTemplateImpl;
/**
* A builder for {@link ImageTemplate}s. Includes sub-builders to build specific
* {@link ImageTemplate}s for different purposes, such as cloning, creating from iso, creating from
* netboot.
*
* @author David Alves
*
*/
public abstract class ImageTemplateBuilder {
String name;
private ImageTemplateBuilder() {
}
public ImageTemplateBuilder name(String name) {
this.name = name;
return this;
}
public static class CloneImageTemplateBuilder extends ImageTemplateBuilder {
String nodeId;
@Override
public CloneImageTemplateBuilder name(String name) {
return CloneImageTemplateBuilder.class.cast(super.name(name));
}
public CloneImageTemplateBuilder nodeId(String nodeId) {
this.nodeId = nodeId;
return this;
}
public CloneImageTemplate build() {
return new ImageTemplateImpl.CloneImageTemplateImpl(name, nodeId);
}
}
}

View File

@ -0,0 +1,53 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.compute.domain.internal;
import org.jclouds.compute.domain.CloneImageTemplate;
import org.jclouds.compute.domain.ImageTemplate;
public abstract class ImageTemplateImpl implements ImageTemplate {
protected final String name;
public ImageTemplateImpl(String name) {
this.name = name;
}
@Override
public String getName() {
return this.name;
}
public static class CloneImageTemplateImpl extends ImageTemplateImpl implements CloneImageTemplate {
protected final String sourceNodeId;
public CloneImageTemplateImpl(String name, String sourceNodeId) {
super(name);
this.sourceNodeId = sourceNodeId;
}
@Override
public String getSourceNodeId() {
return this.sourceNodeId;
}
}
}

View File

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

View File

@ -0,0 +1,134 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.compute.internal;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
import java.util.Set;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ImageExtension;
import org.jclouds.compute.RunNodesException;
import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.ImageTemplate;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.Template;
import org.jclouds.ssh.SshClient;
import org.testng.annotations.Test;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
/**
* Base test for {@link ImageExtension} implementations.
*
* @author David Alves
*
*/
public abstract class BaseImageExtensionLiveTest extends BaseComputeServiceContextLiveTest {
/**
* Returns the template for the base node, override to test different templates.
*
* @return
*/
public Template getNodeTemplate() {
return context.getComputeService().templateBuilder().any().build();
}
@Test(groups = { "integration", "live" }, singleThreaded = true)
public void testCreateImage() throws RunNodesException, InterruptedException {
ComputeService computeService = context.getComputeService();
Optional<ImageExtension> imageExtension = computeService.getImageExtension();
assertTrue("image extension was not present", imageExtension.isPresent());
Set<? extends Image> imagesBefore = computeService.listImages();
NodeMetadata node = Iterables.getOnlyElement(computeService.createNodesInGroup("test-create-image", 1,
getNodeTemplate()));
ImageTemplate newImageTemplate = imageExtension.get().buildImageTemplateFromNode("test-create-image",
node.getId());
Image image = imageExtension.get().createImage(newImageTemplate);
assertEquals("test-create-image", image.getName());
computeService.destroyNode(node.getId());
Set<? extends Image> imagesAfter = computeService.listImages();
assertTrue(imagesBefore.size() == imagesAfter.size() - 1);
}
@Test(groups = { "integration", "live" }, singleThreaded = true, dependsOnMethods = "testCreateImage")
public void testSpawnNodeFromImage() throws RunNodesException {
ComputeService computeService = context.getComputeService();
Template template = computeService.templateBuilder().fromImage(getImage().get()).build();
NodeMetadata node = Iterables.getOnlyElement(computeService.createNodesInGroup("test-create-image", 1, template));
SshClient client = context.utils().sshForNode().apply(node);
client.connect();
ExecResponse hello = client.exec("echo hello");
assertEquals(hello.getOutput().trim(), "hello");
context.getComputeService().destroyNode(node.getId());
}
@Test(groups = { "integration", "live" }, singleThreaded = true, dependsOnMethods = { "testCreateImage",
"testSpawnNodeFromImage" })
public void testDeleteImage() {
ComputeService computeService = context.getComputeService();
Optional<ImageExtension> imageExtension = computeService.getImageExtension();
assertTrue("image extension was not present", imageExtension.isPresent());
Optional<? extends Image> optImage = getImage();
assertTrue(optImage.isPresent());
Image image = optImage.get();
assertTrue(imageExtension.get().deleteImage(image.getId()));
}
private Optional<? extends Image> getImage() {
return Iterables.tryFind(context.getComputeService().listImages(), new Predicate<Image>() {
@Override
public boolean apply(Image input) {
return input.getId().contains("test-create-image");
}
});
}
}

View File

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

View File

@ -71,31 +71,32 @@ public class FutureIterables {
private static BackoffLimitedRetryHandler retryHandler = BackoffLimitedRetryHandler.INSTANCE; private static BackoffLimitedRetryHandler retryHandler = BackoffLimitedRetryHandler.INSTANCE;
public static <F, T> Iterable<T> transformParallel(final Iterable<F> fromIterable, public static <F, T> Iterable<T> transformParallel(final Iterable<F> fromIterable,
final Function<? super F, Future<T>> function) { final Function<? super F, Future<? extends T>> function) {
return transformParallel(fromIterable, function, org.jclouds.concurrent.MoreExecutors.sameThreadExecutor(), null); return transformParallel(fromIterable, function, org.jclouds.concurrent.MoreExecutors.sameThreadExecutor(), null);
} }
public static <F, T> Iterable<T> transformParallel(final Iterable<F> fromIterable, public static <F, T> Iterable<T> transformParallel(final Iterable<F> fromIterable,
final Function<? super F, Future<T>> function, ExecutorService exec, @Nullable Long maxTime) { final Function<? super F, Future<? extends T>> function, ExecutorService exec, @Nullable Long maxTime) {
return transformParallel(fromIterable, function, exec, maxTime, logger, "transforming"); return transformParallel(fromIterable, function, exec, maxTime, logger, "transforming");
} }
public static <F, T> Iterable<T> transformParallel(final Iterable<F> fromIterable, public static <F, T> Iterable<T> transformParallel(final Iterable<F> fromIterable,
final Function<? super F, Future<T>> function, ExecutorService exec, @Nullable Long maxTime, Logger logger, final Function<? super F, Future<? extends T>> function, ExecutorService exec, @Nullable Long maxTime, Logger logger,
String logPrefix) { String logPrefix) {
return transformParallel(fromIterable, function, exec, maxTime, logger, logPrefix, retryHandler, maxRetries); return transformParallel(fromIterable, function, exec, maxTime, logger, logPrefix, retryHandler, maxRetries);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <F, T> Iterable<T> transformParallel(Iterable<F> fromIterable, public static <F, T> Iterable<T> transformParallel(Iterable<F> fromIterable,
Function<? super F, Future<T>> function, ExecutorService exec, @Nullable Long maxTime, Logger logger, Function<? super F, Future<? extends T>> function, ExecutorService exec, @Nullable Long maxTime, Logger logger,
String logPrefix, BackoffLimitedRetryHandler retryHandler, int maxRetries) { String logPrefix, BackoffLimitedRetryHandler retryHandler, int maxRetries) {
Map<F, Exception> exceptions = newHashMap(); Map<F, Exception> exceptions = newHashMap();
Map<F, Future<T>> responses = newHashMap(); Map<F, Future<? extends T>> responses = newHashMap();
for (int i = 0; i < maxRetries; i++) { for (int i = 0; i < maxRetries; i++) {
for (F from : fromIterable) { for (F from : fromIterable) {
responses.put(from, function.apply(from)); Future<? extends T> to = function.apply(from);
responses.put(from, to);
} }
exceptions = awaitCompletion(responses, exec, maxTime, logger, logPrefix); exceptions = awaitCompletion(responses, exec, maxTime, logger, logPrefix);
if (exceptions.size() > 0 && !any(exceptions.values(), containsThrowable(AuthorizationException.class))) { if (exceptions.size() > 0 && !any(exceptions.values(), containsThrowable(AuthorizationException.class))) {
@ -169,10 +170,10 @@ public class FutureIterables {
return errorMap; return errorMap;
} }
public static <T> Iterable<T> unwrap(Iterable<Future<T>> values) { public static <T> Iterable<T> unwrap(Iterable<Future<? extends T>> values) {
return transform(values, new Function<Future<T>, T>() { return transform(values, new Function<Future<? extends T>, T>() {
@Override @Override
public T apply(Future<T> from) { public T apply(Future<? extends T> from) {
try { try {
return from.get(); return from.get();
} catch (InterruptedException e) { } catch (InterruptedException e) {

View File

@ -0,0 +1,40 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.util;
import com.google.common.collect.ImmutableSortedSet;
/**
* General utilities used in jclouds code for {@link Iterable Iterables}.
*
* @author danikov
*/
public class Iterables2 {
/**
* Copies the contents of a wildcarded {@link Iterable} into a concrete {@link Iterable} of the left bound
*
* @param unboundedValues wildcarded source {@link Iterable}
* @return concrete-typed copy of the source
*/
public static <T> Iterable<T> concreteCopy(Iterable<? extends T> unboundedValues) {
return ImmutableSortedSet.copyOf(unboundedValues);
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,162 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.virtualbox.compute;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_DEFAULT_DIR;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_WORKINGDIR;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.compute.ComputeServiceAdapter;
import org.jclouds.compute.ImageExtension;
import org.jclouds.compute.domain.CloneImageTemplate;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.ImageTemplate;
import org.jclouds.compute.domain.ImageTemplateBuilder;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.domain.Location;
import org.jclouds.logging.Logger;
import org.jclouds.virtualbox.functions.IMachineToVmSpec;
import org.jclouds.virtualbox.functions.TakeSnapshotIfNotAlreadyAttached;
import org.jclouds.virtualbox.functions.admin.UnregisterMachineIfExistsAndDeleteItsMedia;
import org.jclouds.virtualbox.util.MachineUtils;
import org.virtualbox_4_1.CloneMode;
import org.virtualbox_4_1.CloneOptions;
import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.IProgress;
import org.virtualbox_4_1.ISnapshot;
import org.virtualbox_4_1.VirtualBoxManager;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.collect.Iterables;
@Singleton
public class VirtualBoxImageExtension implements ImageExtension {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
private Logger logger = Logger.NULL;
private ComputeServiceAdapter<IMachine, Hardware, Image, Location> vboxAdapter;
private Function<IMachine, NodeMetadata> machineToNode;
private Supplier<VirtualBoxManager> manager;
private String workingDir;
private boolean isLinkedClone = true;
private Function<IMachine, Image> imachineToImage;
private MachineUtils machineUtils;
@Inject
public VirtualBoxImageExtension(ComputeServiceAdapter<IMachine, Hardware, Image, Location> vboxAdapter,
Function<IMachine, NodeMetadata> machineToNode, Supplier<VirtualBoxManager> manager,
@Named(VIRTUALBOX_WORKINGDIR) String workingDir, Function<IMachine, Image> imachineToImage,
MachineUtils machineUtils) {
this.vboxAdapter = vboxAdapter;
this.machineToNode = machineToNode;
this.manager = manager;
this.workingDir = workingDir == null ? VIRTUALBOX_DEFAULT_DIR : workingDir;
this.imachineToImage = imachineToImage;
this.machineUtils = machineUtils;
}
@Override
public ImageTemplate buildImageTemplateFromNode(String name, final String id) {
Optional<NodeMetadata> sourceNode = getNodeById(id);
checkState(sourceNode.isPresent(), " there is no node with id " + id);
String vmName = VIRTUALBOX_IMAGE_PREFIX + name;
IMachine vm = null;
try {
vm = manager.get().getVBox().findMachine(vmName);
} catch (Exception e) {
}
checkState(vm == null, " a machine exists with name: " + vmName);
return new ImageTemplateBuilder.CloneImageTemplateBuilder().name(vmName).nodeId(id).build();
}
@Override
public Image createImage(ImageTemplate template) {
checkState(template instanceof CloneImageTemplate, " vbox image extension only supports cloning for the moment.");
CloneImageTemplate cloneTemplate = CloneImageTemplate.class.cast(template);
IMachine source = manager.get().getVBox().findMachine(cloneTemplate.getSourceNodeId());
String settingsFile = manager.get().getVBox().composeMachineFilename(template.getName(), workingDir);
IMachine clonedMachine = manager.get().getVBox()
.createMachine(settingsFile, template.getName(), source.getOSTypeId(), template.getName(), true);
List<CloneOptions> options = new ArrayList<CloneOptions>();
if (isLinkedClone)
options.add(CloneOptions.Link);
// TODO snapshot name
ISnapshot currentSnapshot = new TakeSnapshotIfNotAlreadyAttached(manager, "pre-image-spawn", "before spawning "
+ template.getName(), logger).apply(source);
checkNotNull(currentSnapshot);
// clone
IProgress progress = currentSnapshot.getMachine().cloneTo(clonedMachine, CloneMode.MachineState, options);
progress.waitForCompletion(-1);
logger.debug(String.format("Machine %s is cloned correctly", clonedMachine.getName()));
// registering
manager.get().getVBox().registerMachine(clonedMachine);
return imachineToImage.apply(clonedMachine);
}
@Override
public boolean deleteImage(String id) {
try {
IMachine machine = manager.get().getVBox().findMachine(VIRTUALBOX_IMAGE_PREFIX + id);
machineUtils.applyForMachine(machine.getId(), new UnregisterMachineIfExistsAndDeleteItsMedia(
new IMachineToVmSpec().apply(machine)));
} catch (Exception e) {
logger.error(e, "Could not delete machine with id %s ", id);
return false;
}
return true;
}
private Optional<NodeMetadata> getNodeById(final String id) {
return Iterables.tryFind(Iterables.transform(vboxAdapter.listNodes(), machineToNode),
new Predicate<NodeMetadata>() {
@Override
public boolean apply(NodeMetadata input) {
return input.getId().equals(id);
}
});
}
}

View File

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

View File

@ -105,7 +105,7 @@ public class CloneAndRegisterMachineFromIMachineIfNotAlreadyExists implements Fu
options.add(CloneOptions.Link); options.add(CloneOptions.Link);
// TODO snapshot name // TODO snapshot name
ISnapshot currentSnapshot = new TakeSnapshotIfNotAlreadyAttached(manager, "snapshotName", "snapshotDesc") ISnapshot currentSnapshot = new TakeSnapshotIfNotAlreadyAttached(manager, "snapshotName", "snapshotDesc", logger)
.apply(master); .apply(master);
// clone // clone
@ -114,6 +114,9 @@ public class CloneAndRegisterMachineFromIMachineIfNotAlreadyExists implements Fu
progress.waitForCompletion(-1); progress.waitForCompletion(-1);
logger.debug(String.format("Machine %s is cloned correctly", clonedMachine.getName())); logger.debug(String.format("Machine %s is cloned correctly", clonedMachine.getName()));
// memory may not be the same as the master vm
clonedMachine.setMemorySize(cloneSpec.getVmSpec().getMemory());
// registering // registering
manager.get().getVBox().registerMachine(clonedMachine); manager.get().getVBox().registerMachine(clonedMachine);

View File

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

View File

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

View File

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

View File

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

View File

@ -20,15 +20,13 @@
package org.jclouds.virtualbox.functions; package org.jclouds.virtualbox.functions;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.Resource;
import javax.inject.Named;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.virtualbox_4_1.IMachine; import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.IProgress; import org.virtualbox_4_1.IProgress;
import org.virtualbox_4_1.ISession; import org.virtualbox_4_1.ISession;
import org.virtualbox_4_1.ISnapshot; import org.virtualbox_4_1.ISnapshot;
import org.virtualbox_4_1.MachineState;
import org.virtualbox_4_1.VirtualBoxManager; import org.virtualbox_4_1.VirtualBoxManager;
import com.google.common.base.Function; import com.google.common.base.Function;
@ -40,36 +38,56 @@ import com.google.common.base.Throwables;
*/ */
public class TakeSnapshotIfNotAlreadyAttached implements Function<IMachine, ISnapshot> { public class TakeSnapshotIfNotAlreadyAttached implements Function<IMachine, ISnapshot> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
private Supplier<VirtualBoxManager> manager; private Supplier<VirtualBoxManager> manager;
private String snapshotName; private String snapshotName;
private String snapshotDesc; private String snapshotDesc;
private Logger logger;
public TakeSnapshotIfNotAlreadyAttached(Supplier<VirtualBoxManager> manager, String snapshotName, String snapshotDesc) { public TakeSnapshotIfNotAlreadyAttached(Supplier<VirtualBoxManager> manager, String snapshotName,
String snapshotDesc, Logger logger) {
this.manager = manager; this.manager = manager;
this.snapshotName = snapshotName; this.snapshotName = snapshotName;
this.snapshotDesc = snapshotDesc; this.snapshotDesc = snapshotDesc;
this.logger = logger;
} }
@Override @Override
public ISnapshot apply(@Nullable IMachine machine) { public ISnapshot apply(@Nullable IMachine machine) {
// Snapshot a machine // Snapshot a machine
ISession session = null; ISession session = null;
if (machine.getCurrentSnapshot() == null) { ISnapshot snap = machine.getCurrentSnapshot();
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; int retries = 10;
while (true) { while (true) {
try { try {
session = manager.get().openMachineSession(machine);
// 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;
}
IProgress progress = session.getConsole().takeSnapshot(snapshotName, snapshotDesc); IProgress progress = session.getConsole().takeSnapshot(snapshotName, snapshotDesc);
progress.waitForCompletion(-1); progress.waitForCompletion(-1);
if (paused) {
session.getConsole().resume();
}
snap = machine.getCurrentSnapshot();
logger.debug("Snapshot %s (description: %s) taken from %s", snapshotName, snapshotDesc, logger.debug("Snapshot %s (description: %s) taken from %s", snapshotName, snapshotDesc,
machine.getName()); machine.getName());
break; break;
} catch (Exception e) { } catch (Exception e) {
if (e.getMessage().contains("VirtualBox error: The object is not ready")) { if (e.getMessage().contains("VirtualBox error: The object is not ready")
|| e.getMessage().contains("This machine does not have any snapshots")) {
retries--; retries--;
if (retries == 0) { if (retries == 0) {
logger.error(e, logger.error(e,
@ -77,18 +95,23 @@ public class TakeSnapshotIfNotAlreadyAttached implements Function<IMachine, ISna
snapshotName, snapshotDesc, machine.getName()); snapshotName, snapshotDesc, machine.getName());
throw Throwables.propagate(e); throw Throwables.propagate(e);
} }
Thread.sleep(1000L);
continue;
} }
logger.error(e, "Problem creating snapshot %s (descripton: %s) from machine %s", snapshotName, logger.error(e, "Problem creating snapshot %s (descripton: %s) from machine %s", snapshotName,
snapshotDesc, machine.getName()); snapshotDesc, machine.getName());
throw Throwables.propagate(e); throw Throwables.propagate(e);
}
}
} catch (Exception e) {
Throwables.propagate(e);
} finally { } finally {
if (session != null) { if (session != null) {
session.unlockMachine(); manager.get().closeMachineSession(session);
} }
} }
}
}
return machine.getCurrentSnapshot();
}
}
return snap;
}
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,40 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.virtualbox.compute;
import org.jclouds.compute.internal.BaseImageExtensionLiveTest;
import org.jclouds.sshj.config.SshjSshClientModule;
import org.testng.annotations.Test;
import com.google.inject.Module;
@Test(groups = "live", singleThreaded = true, testName = "VirtualBoxImageExtensionLiveTest")
public class VirtualBoxImageExtensionLiveTest extends BaseImageExtensionLiveTest {
public VirtualBoxImageExtensionLiveTest() {
provider = "virtualbox";
}
@Override
protected Module getSshModule() {
return new SshjSshClientModule();
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,44 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.hpcloud.compute.compute;
import org.jclouds.compute.internal.BaseImageExtensionLiveTest;
import org.jclouds.sshj.config.SshjSshClientModule;
import org.testng.annotations.Test;
import com.google.inject.Module;
/**
*
* @author David Alves
*
*/
@Test(groups = "live", singleThreaded = true, testName = "HPCloudComputeImageExtensionLivetest")
public class HPCloudComputeImageExtensionLivetest extends BaseImageExtensionLiveTest {
public HPCloudComputeImageExtensionLivetest() {
provider = "hpcloud-compute";
}
@Override
protected Module getSshModule() {
return new SshjSshClientModule();
}
}

View File

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