diff --git a/atmos/src/main/java/org/jclouds/atmosonline/saas/blobstore/AtmosAsyncBlobStore.java b/atmos/src/main/java/org/jclouds/atmosonline/saas/blobstore/AtmosAsyncBlobStore.java index 64699dc821..5599749550 100644 --- a/atmos/src/main/java/org/jclouds/atmosonline/saas/blobstore/AtmosAsyncBlobStore.java +++ b/atmos/src/main/java/org/jclouds/atmosonline/saas/blobstore/AtmosAsyncBlobStore.java @@ -22,7 +22,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.util.concurrent.Futures.compose; import java.net.URI; -import java.util.Map; +import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; @@ -80,7 +80,7 @@ public class AtmosAsyncBlobStore extends BaseAsyncBlobStore { @Inject AtmosAsyncBlobStore(BlobStoreContext context, BlobStoreUtils blobUtils, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, - Location defaultLocation, Map locations, + Location defaultLocation, Set locations, AtmosStorageAsyncClient async, AtmosStorageClient sync, ObjectToBlob object2Blob, ObjectToBlobMetadata object2BlobMd, BlobToObject blob2Object, diff --git a/atmos/src/main/java/org/jclouds/atmosonline/saas/blobstore/AtmosBlobStore.java b/atmos/src/main/java/org/jclouds/atmosonline/saas/blobstore/AtmosBlobStore.java index 2ed7b87599..f2a83422dd 100644 --- a/atmos/src/main/java/org/jclouds/atmosonline/saas/blobstore/AtmosBlobStore.java +++ b/atmos/src/main/java/org/jclouds/atmosonline/saas/blobstore/AtmosBlobStore.java @@ -20,7 +20,7 @@ package org.jclouds.atmosonline.saas.blobstore; import static com.google.common.base.Preconditions.checkNotNull; -import java.util.Map; +import java.util.Set; import javax.inject.Inject; import javax.inject.Provider; @@ -65,8 +65,8 @@ public class AtmosBlobStore extends BaseBlobStore { @Inject AtmosBlobStore(BlobStoreContext context, BlobStoreUtils blobUtils, Location defaultLocation, - Map locations, AtmosStorageClient sync, - ObjectToBlob object2Blob, ObjectToBlobMetadata object2BlobMd, BlobToObject blob2Object, + Set locations, AtmosStorageClient sync, ObjectToBlob object2Blob, + ObjectToBlobMetadata object2BlobMd, BlobToObject blob2Object, BlobStoreListOptionsToListOptions container2ContainerListOptions, DirectoryEntryListToResourceMetadataList container2ResourceList, EncryptionService encryptionService, BlobToHttpGetOptions blob2ObjectGetOptions, diff --git a/atmos/src/main/java/org/jclouds/atmosonline/saas/blobstore/config/AtmosBlobStoreContextModule.java b/atmos/src/main/java/org/jclouds/atmosonline/saas/blobstore/config/AtmosBlobStoreContextModule.java index e94bfab7cd..cccd27c489 100755 --- a/atmos/src/main/java/org/jclouds/atmosonline/saas/blobstore/config/AtmosBlobStoreContextModule.java +++ b/atmos/src/main/java/org/jclouds/atmosonline/saas/blobstore/config/AtmosBlobStoreContextModule.java @@ -18,7 +18,7 @@ */ package org.jclouds.atmosonline.saas.blobstore.config; -import java.util.Map; +import java.util.Set; import javax.inject.Singleton; @@ -39,7 +39,7 @@ import org.jclouds.domain.Location; import org.jclouds.domain.LocationScope; import org.jclouds.domain.internal.LocationImpl; -import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import com.google.inject.Provides; import com.google.inject.Scopes; import com.google.inject.TypeLiteral; @@ -78,7 +78,7 @@ public class AtmosBlobStoreContextModule extends AtmosStorageContextModule { @Provides @Singleton - Map provideLocations(Location location) { - return ImmutableMap.of(location.getId(), location); + Set provideLocations(Location location) { + return ImmutableSet.of(location); } } diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/compute/EC2ComputeService.java b/aws/core/src/main/java/org/jclouds/aws/ec2/compute/EC2ComputeService.java index 0d3e44b954..d9c0514572 100644 --- a/aws/core/src/main/java/org/jclouds/aws/ec2/compute/EC2ComputeService.java +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/compute/EC2ComputeService.java @@ -19,6 +19,7 @@ package org.jclouds.aws.ec2.compute; import java.util.Map; +import java.util.Set; import java.util.concurrent.ExecutorService; import javax.inject.Inject; @@ -64,10 +65,9 @@ public class EC2ComputeService extends BaseComputeService { @Inject protected EC2ComputeService(ComputeServiceContext context, - Provider> images, - Provider> sizes, - Provider> locations, - ListNodesStrategy listNodesStrategy, GetNodeMetadataStrategy getNodeMetadataStrategy, + Provider> images, Provider> sizes, + Provider> locations, ListNodesStrategy listNodesStrategy, + GetNodeMetadataStrategy getNodeMetadataStrategy, RunNodesAndAddToSetStrategy runNodesAndAddToSetStrategy, RebootNodeStrategy rebootNodeStrategy, DestroyNodeStrategy destroyNodeStrategy, Provider templateBuilderProvider, ComputeUtils utils, @@ -101,7 +101,7 @@ public class EC2ComputeService extends BaseComputeService { logger.debug(">> deleting keyPair(%s)", tag); ec2Client.getKeyPairServices().deleteKeyPairInRegion(region, keyPair.getKeyName()); credentialsMap.remove(new RegionTag(region, keyPair.getKeyName())); // TODO: test this - // clear happens + // clear happens logger.debug("<< deleted keyPair(%s)", keyPair.getKeyName()); } } @@ -110,7 +110,7 @@ public class EC2ComputeService extends BaseComputeService { @Override public void destroyNodesWithTag(String tag) { super.destroyNodesWithTag(tag); - Iterable nodes = Iterables.filter(getNodesWithTag(tag).values(), + Iterable nodes = Iterables.filter(listNodesWithTag(tag), new Predicate() { @Override public boolean apply(NodeMetadata input) { diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/compute/config/EC2ComputeServiceContextModule.java b/aws/core/src/main/java/org/jclouds/aws/ec2/compute/config/EC2ComputeServiceContextModule.java index 78610c2b59..0bb097f07b 100755 --- a/aws/core/src/main/java/org/jclouds/aws/ec2/compute/config/EC2ComputeServiceContextModule.java +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/compute/config/EC2ComputeServiceContextModule.java @@ -254,32 +254,37 @@ public class EC2ComputeServiceContextModule extends EC2ContextModule { @Provides @Singleton - Map provideSizes(Function indexer) { - return Maps.uniqueIndex(ImmutableSet.of(EC2Size.C1_MEDIUM, EC2Size.C1_XLARGE, - EC2Size.M1_LARGE, EC2Size.M1_SMALL, EC2Size.M1_XLARGE, EC2Size.M2_XLARGE, - EC2Size.M2_2XLARGE, EC2Size.M2_4XLARGE), indexer); + Set provideSizes() { + return ImmutableSet.of(EC2Size.C1_MEDIUM, EC2Size.C1_XLARGE, EC2Size.M1_LARGE, + EC2Size.M1_SMALL, EC2Size.M1_XLARGE, EC2Size.M2_XLARGE, EC2Size.M2_2XLARGE, + EC2Size.M2_4XLARGE); } @Provides @Singleton - Map provideLocations(Map availabilityZoneToRegionMap) { + Set provideLocations(Map availabilityZoneToRegionMap) { Location ec2 = new LocationImpl(LocationScope.PROVIDER, providerName, providerName, null); - Map locations = Maps.newLinkedHashMap(); - for (String region : availabilityZoneToRegionMap.values()) { - locations.put(region, new LocationImpl(LocationScope.REGION, region, region, ec2)); - } - + Set locations = Sets.newLinkedHashSet(); for (String zone : availabilityZoneToRegionMap.keySet()) { - locations.put(zone, new LocationImpl(LocationScope.ZONE, zone, zone, locations - .get(availabilityZoneToRegionMap.get(zone)))); + Location region = new LocationImpl(LocationScope.REGION, availabilityZoneToRegionMap + .get(zone), availabilityZoneToRegionMap.get(zone), ec2); + locations.add(region); + locations.add(new LocationImpl(LocationScope.ZONE, zone, zone, region)); } return locations; } @Provides @Singleton - Location getDefaultLocation(@EC2 String region, Map map) { - return map.get(region); + Location getDefaultLocation(@EC2 final String region, Set set) { + return Iterables.find(set, new Predicate() { + + @Override + public boolean apply(Location input) { + return input.getId().equals(region); + } + + }); } private static class LogHolder { @@ -297,7 +302,7 @@ public class EC2ComputeServiceContextModule extends EC2ContextModule { @Provides @Singleton - protected Map provideImages(final EC2Client sync, + protected Set provideImages(final EC2Client sync, @EC2 Map regionMap, LogHolder holder, Function indexer, @Named(PROPERTY_EC2_AMI_OWNERS) String[] amiOwners, ImageParser parser) @@ -316,6 +321,6 @@ public class EC2ComputeServiceContextModule extends EC2ContextModule { } } holder.logger.debug("<< images(%d)", images.size()); - return Maps.uniqueIndex(images, indexer); + return images; } } diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/compute/functions/ImageParser.java b/aws/core/src/main/java/org/jclouds/aws/ec2/compute/functions/ImageParser.java index f648ae7831..c57cbc1299 100644 --- a/aws/core/src/main/java/org/jclouds/aws/ec2/compute/functions/ImageParser.java +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/compute/functions/ImageParser.java @@ -21,6 +21,8 @@ package org.jclouds.aws.ec2.compute.functions; import static com.google.common.base.Preconditions.checkNotNull; import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -38,10 +40,14 @@ import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.strategy.PopulateDefaultLoginCredentialsForImageStrategy; import org.jclouds.domain.Credentials; import org.jclouds.domain.Location; +import org.jclouds.domain.LocationScope; +import org.jclouds.domain.internal.LocationImpl; import org.jclouds.logging.Logger; import com.google.common.base.Function; +import com.google.common.base.Predicate; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; /** * @author Adrian Cole @@ -61,18 +67,21 @@ public class ImageParser implements Function locations; + private final Set locations; + + private final Location defaultLocation; @Inject ImageParser(PopulateDefaultLoginCredentialsForImageStrategy credentialProvider, - Map locations) { + Set locations, Location defaultLocation) { this.credentialProvider = checkNotNull(credentialProvider, "credentialProvider"); this.locations = checkNotNull(locations, "locations"); + this.defaultLocation = checkNotNull(defaultLocation, "defaultLocation"); } @Override - public Image apply(org.jclouds.aws.ec2.domain.Image from) { + public Image apply(final org.jclouds.aws.ec2.domain.Image from) { if (from.getImageLocation().indexOf("test") != -1) { logger.trace("skipping test image(%s)", from.getId()); return null; @@ -102,10 +111,26 @@ public class ImageParser implements Function() { + + @Override + public boolean apply(Location input) { + return input.getId().equals(from.getRegion()); + } + + }); + } catch (NoSuchElementException e) { + System.err.printf("unknown region %s for image %s; not in %s", from.getRegion(), from + .getId(), locations); + location = new LocationImpl(LocationScope.REGION, from.getRegion(), from.getRegion(), + defaultLocation.getParent()); + } return new ImageImpl( from.getId(), name, - locations.get(from.getRegion()), + location, null, ImmutableMap. of("owner", from.getImageOwnerId()), description, @@ -114,5 +139,6 @@ public class ImageParser implements Function { + + @Resource + protected Logger logger = Logger.NULL; + + private static class FindImageForInstance implements Predicate { + private final Location location; + private final RunningInstance instance; + + private FindImageForInstance(Location location, RunningInstance instance) { + this.location = location; + this.instance = instance; + } + + @Override + public boolean apply(Image input) { + return input.getId().equals(instance.getImageId()) + && (input.getLocation() == null || input.getLocation().equals(location) || input + .getLocation().equals(location.getParent())); + } + } + private static final Map instanceToNodeState = ImmutableMap . builder().put(InstanceState.PENDING, NodeState.PENDING) .put(InstanceState.RUNNING, NodeState.RUNNING).put(InstanceState.SHUTTING_DOWN, @@ -63,14 +88,17 @@ public class RunningInstanceToNodeMetadata implements Function credentialsMap; private final PopulateDefaultLoginCredentialsForImageStrategy credentialProvider; - private final Map images; - private final Map locations; + private final Set images; + private final Set locations; private final Function> instanceToStorageMapping; @Inject - RunningInstanceToNodeMetadata(AMIClient amiClient, Map credentialsMap, + RunningInstanceToNodeMetadata( + AMIClient amiClient, + Map credentialsMap, PopulateDefaultLoginCredentialsForImageStrategy credentialProvider, - Map images, Map locations, + Set images, + Set locations, @Named("volumeMapping") Function> instanceToStorageMapping) { this.amiClient = checkNotNull(amiClient, "amiClient"); this.credentialsMap = checkNotNull(credentialsMap, "credentialsMap"); @@ -81,7 +109,7 @@ public class RunningInstanceToNodeMetadata implements Function publicAddresses = nullSafeSet(instance.getIpAddress()); Set privateAddresses = nullSafeSet(instance.getPrivateIpAddress()); - String locationId = instance.getAvailabilityZone(); + final String locationId = instance.getAvailabilityZone(); Map extra = getExtra(instance); - return new NodeMetadataImpl(id, name, locations.get(locationId), uri, userMetadata, tag, - images.get(instance.getImageId()), state, publicAddresses, privateAddresses, extra, - credentials); + final Location location = Iterables.find(locations, new Predicate() { + + @Override + public boolean apply(Location input) { + return input.getId().equals(locationId); + } + + }); + + Image image = null; + try { + image = Iterables.find(images, new FindImageForInstance(location, instance)); + } catch (NoSuchElementException e) { + logger.warn("could not find a matching image for instance %s in location %s", instance, + location); + } + return new NodeMetadataImpl(id, name, location, uri, userMetadata, tag, image, state, + publicAddresses, privateAddresses, extra, credentials); } /** diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/compute/strategy/EC2RunNodesAndAddToSetStrategy.java b/aws/core/src/main/java/org/jclouds/aws/ec2/compute/strategy/EC2RunNodesAndAddToSetStrategy.java index 4a7a497ab3..1d8c78f896 100644 --- a/aws/core/src/main/java/org/jclouds/aws/ec2/compute/strategy/EC2RunNodesAndAddToSetStrategy.java +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/compute/strategy/EC2RunNodesAndAddToSetStrategy.java @@ -114,18 +114,19 @@ public class EC2RunNodesAndAddToSetStrategy implements RunNodesAndAddToSetStrate @Override public Map> execute(final String tag, final int count, - final Template template, final Set nodes) { + final Template template, final Set nodes, + final Map badNodes) { checkArgument(template.getSize() instanceof EC2Size, "unexpected image type. should be EC2Size, was: " + template.getSize().getClass()); EC2Size ec2Size = EC2Size.class.cast(template.getSize()); // parse the availability zone of the request - String zone = template.getLocation().getScope() == LocationScope.ZONE ? template.getLocation().getId() - : null; + String zone = template.getLocation().getScope() == LocationScope.ZONE ? template + .getLocation().getId() : null; // if the location has a parent, it must be an availability zone. - String region = zone == null ? template.getLocation().getId() : - template.getLocation().getParent().getId(); + String region = zone == null ? template.getLocation().getId() : template.getLocation() + .getParent().getId(); // get or create incidental resources // TODO race condition. we were using MapMaker, but it doesn't seem to refresh properly when @@ -174,8 +175,7 @@ public class EC2RunNodesAndAddToSetStrategy implements RunNodesAndAddToSetStrate } catch (Exception e) { logger.error(e, "<< problem applying options to node(%s): ", node.getId(), Throwables.getRootCause(e).getMessage()); - if (!template.getOptions().shouldDestroyOnError()) - nodes.add(computeService.getNodeMetadata(node)); + badNodes.put(computeService.getNodeMetadata(node), e); } return null; } diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/xml/DescribeImagesResponseHandler.java b/aws/core/src/main/java/org/jclouds/aws/ec2/xml/DescribeImagesResponseHandler.java index e84d4a7064..b9b7936ed5 100755 --- a/aws/core/src/main/java/org/jclouds/aws/ec2/xml/DescribeImagesResponseHandler.java +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/xml/DescribeImagesResponseHandler.java @@ -49,13 +49,18 @@ import com.google.common.collect.Sets; * /> */ public class DescribeImagesResponseHandler extends ParseSax.HandlerWithResult> { + + @Inject + public DescribeImagesResponseHandler(@EC2 String defaultRegion) { + this.defaultRegion = defaultRegion; + } + @Resource protected Logger logger = Logger.NULL; - @Inject - @EC2 - String defaultRegion; + private Set contents = Sets.newLinkedHashSet(); private StringBuilder currentText = new StringBuilder(); + private final String defaultRegion; private Architecture architecture; private String name; @@ -149,10 +154,10 @@ public class DescribeImagesResponseHandler extends ParseSax.HandlerWithResult locations, - S3AsyncClient async, S3Client sync, BucketToResourceMetadata bucket2ResourceMd, + Location defaultLocation, Set locations, S3AsyncClient async, + S3Client sync, BucketToResourceMetadata bucket2ResourceMd, ContainerToBucketListOptions container2BucketListOptions, BucketToResourceList bucket2ResourceList, ObjectToBlob object2Blob, BlobToHttpGetOptions blob2ObjectGetOptions, BlobToObject blob2Object, diff --git a/aws/core/src/main/java/org/jclouds/aws/s3/blobstore/S3BlobStore.java b/aws/core/src/main/java/org/jclouds/aws/s3/blobstore/S3BlobStore.java index 235bb89cb3..5aed722ba6 100644 --- a/aws/core/src/main/java/org/jclouds/aws/s3/blobstore/S3BlobStore.java +++ b/aws/core/src/main/java/org/jclouds/aws/s3/blobstore/S3BlobStore.java @@ -20,7 +20,7 @@ package org.jclouds.aws.s3.blobstore; import static com.google.common.base.Preconditions.checkNotNull; -import java.util.Map; +import java.util.Set; import java.util.SortedSet; import javax.inject.Inject; @@ -75,7 +75,7 @@ public class S3BlobStore extends BaseBlobStore { @Inject S3BlobStore(BlobStoreContext context, BlobStoreUtils blobUtils, Location defaultLocation, - Map locations, S3Client sync, + Set locations, S3Client sync, BucketToResourceMetadata bucket2ResourceMd, ContainerToBucketListOptions container2BucketListOptions, BucketToResourceList bucket2ResourceList, ObjectToBlob object2Blob, diff --git a/aws/core/src/main/java/org/jclouds/aws/s3/blobstore/config/S3BlobStoreContextModule.java b/aws/core/src/main/java/org/jclouds/aws/s3/blobstore/config/S3BlobStoreContextModule.java index 36a074ccd8..baf1609ef7 100755 --- a/aws/core/src/main/java/org/jclouds/aws/s3/blobstore/config/S3BlobStoreContextModule.java +++ b/aws/core/src/main/java/org/jclouds/aws/s3/blobstore/config/S3BlobStoreContextModule.java @@ -18,7 +18,6 @@ */ package org.jclouds.aws.s3.blobstore.config; -import java.util.Map; import java.util.Set; import javax.inject.Singleton; @@ -39,8 +38,8 @@ import org.jclouds.domain.Location; import org.jclouds.domain.LocationScope; import org.jclouds.domain.internal.LocationImpl; -import com.google.common.base.Function; -import com.google.common.collect.Maps; +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; import com.google.common.collect.Sets; import com.google.inject.Provides; import com.google.inject.Scopes; @@ -72,24 +71,26 @@ public class S3BlobStoreContextModule extends S3ContextModule { @Provides @Singleton - Location getDefaultLocation(@S3 String region, Map locations) { - return locations.get(region.toString()); + Location getDefaultLocation(@S3 final String region, Set locations) { + return Iterables.find(locations, new Predicate() { + + @Override + public boolean apply(Location input) { + return input.getId().equals(region); + } + + }); } @Provides @Singleton - Map provideLocations(@S3 Set regions) { + Set provideLocations(@S3 Set regions) { Set locations = Sets.newHashSet(); Location s3 = new LocationImpl(LocationScope.PROVIDER, providerName, providerName, null); for (String zone : regions) { locations .add(new LocationImpl(LocationScope.REGION, zone.toString(), zone.toString(), s3)); } - return Maps.uniqueIndex(locations, new Function() { - @Override - public String apply(Location from) { - return from.getId(); - } - }); + return locations; } } diff --git a/aws/core/src/main/java/org/jclouds/aws/s3/blobstore/functions/BucketToResourceMetadata.java b/aws/core/src/main/java/org/jclouds/aws/s3/blobstore/functions/BucketToResourceMetadata.java index 9f19f68fca..c17eb6f535 100644 --- a/aws/core/src/main/java/org/jclouds/aws/s3/blobstore/functions/BucketToResourceMetadata.java +++ b/aws/core/src/main/java/org/jclouds/aws/s3/blobstore/functions/BucketToResourceMetadata.java @@ -18,7 +18,8 @@ */ package org.jclouds.aws.s3.blobstore.functions; -import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; import javax.annotation.Resource; import javax.inject.Inject; @@ -35,6 +36,8 @@ import org.jclouds.domain.Location; import org.jclouds.logging.Logger; import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; /** * @author Adrian Cole @@ -42,13 +45,13 @@ import com.google.common.base.Function; @Singleton public class BucketToResourceMetadata implements Function { private final S3Client client; - private final Map locations; + private final Set locations; @Resource protected Logger logger = Logger.NULL; @Inject - BucketToResourceMetadata(S3Client client, Map locations) { + BucketToResourceMetadata(S3Client client, Set locations) { this.client = client; this.locations = locations; } @@ -58,12 +61,20 @@ public class BucketToResourceMetadata implements Function() { + + @Override + public boolean apply(Location input) { + return input.getId().equals(region.toString()); + } + + })); + } catch (NoSuchElementException e) { logger.error("could not get location for region %s in %s", region, locations); - to.setLocation(location); + } } else { logger.error("could not get region for %s", from.getName()); } diff --git a/aws/core/src/test/java/org/jclouds/aws/ec2/compute/EC2ComputeServiceLiveTest.java b/aws/core/src/test/java/org/jclouds/aws/ec2/compute/EC2ComputeServiceLiveTest.java index 57676a17be..cba5eb8c63 100644 --- a/aws/core/src/test/java/org/jclouds/aws/ec2/compute/EC2ComputeServiceLiveTest.java +++ b/aws/core/src/test/java/org/jclouds/aws/ec2/compute/EC2ComputeServiceLiveTest.java @@ -44,7 +44,7 @@ public class EC2ComputeServiceLiveTest extends BaseComputeServiceLiveTest { @Test public void testTemplateBuilderCanUseImageId() { - client.templateBuilder().imageId(Iterables.get(client.getImages().keySet(), 0)).build(); + client.templateBuilder().imageId(Iterables.get(client.listImages(), 0).getId()).build(); } @Test diff --git a/aws/core/src/test/java/org/jclouds/aws/ec2/compute/EC2ComputeServiceTest.java b/aws/core/src/test/java/org/jclouds/aws/ec2/compute/EC2ComputeServiceTest.java index 1e48cc4a08..35ae9ec121 100644 --- a/aws/core/src/test/java/org/jclouds/aws/ec2/compute/EC2ComputeServiceTest.java +++ b/aws/core/src/test/java/org/jclouds/aws/ec2/compute/EC2ComputeServiceTest.java @@ -41,7 +41,6 @@ import org.jclouds.domain.internal.LocationImpl; import org.testng.annotations.Test; import com.google.common.base.Function; -import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; @@ -116,10 +115,10 @@ public class EC2ComputeServiceTest { . newHashMap(), "description", "1.0", null, "ubuntu", Architecture.X86_64, new Credentials("root", null)); - return new TemplateBuilderImpl(ImmutableMap.of("us-east-1", location), ImmutableMap.of( - "ami-image", image), Maps.uniqueIndex(ImmutableSet.of(EC2Size.C1_MEDIUM, - EC2Size.C1_XLARGE, EC2Size.M1_LARGE, EC2Size.M1_SMALL, EC2Size.M1_XLARGE, - EC2Size.M2_XLARGE, EC2Size.M2_2XLARGE, EC2Size.M2_4XLARGE), indexer()), location) { + return new TemplateBuilderImpl(ImmutableSet.of(location), ImmutableSet.of(image), + ImmutableSet.of(EC2Size.C1_MEDIUM, EC2Size.C1_XLARGE, EC2Size.M1_LARGE, + EC2Size.M1_SMALL, EC2Size.M1_XLARGE, EC2Size.M2_XLARGE, EC2Size.M2_2XLARGE, + EC2Size.M2_4XLARGE), location) { }; } diff --git a/aws/core/src/test/java/org/jclouds/aws/ec2/compute/functions/ImageParserTest.java b/aws/core/src/test/java/org/jclouds/aws/ec2/compute/functions/ImageParserTest.java index 749eea12a9..3ca4208335 100644 --- a/aws/core/src/test/java/org/jclouds/aws/ec2/compute/functions/ImageParserTest.java +++ b/aws/core/src/test/java/org/jclouds/aws/ec2/compute/functions/ImageParserTest.java @@ -32,11 +32,14 @@ import org.jclouds.aws.ec2.xml.BaseEC2HandlerTest; import org.jclouds.aws.ec2.xml.DescribeImagesResponseHandler; import org.jclouds.compute.domain.OsFamily; import org.jclouds.domain.Location; +import org.jclouds.domain.LocationScope; +import org.jclouds.domain.internal.LocationImpl; import org.jclouds.http.functions.ParseSax; import org.jclouds.rest.internal.GeneratedHttpRequest; import org.testng.annotations.Test; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; /** @@ -52,15 +55,15 @@ public class ImageParserTest extends BaseEC2HandlerTest { assertEquals(result.size(), 6); ImageParser parser = new ImageParser( - new EC2PopulateDefaultLoginCredentialsForImageStrategy(), ImmutableMap - . of()); + new EC2PopulateDefaultLoginCredentialsForImageStrategy(), ImmutableSet + . of(defaultLocation), defaultLocation); org.jclouds.compute.domain.Image ubuntuHardy = parser.apply(Iterables.get(result, 0)); assertEquals(ubuntuHardy.getArchitecture(), org.jclouds.compute.domain.Architecture.X86_32); assertEquals(ubuntuHardy.getDescription(), "ubuntu-images-us/ubuntu-hardy-8.04-i386-server-20091130.manifest.xml"); assertEquals(ubuntuHardy.getId(), "ami-7e28ca17"); - assertEquals(ubuntuHardy.getLocation(), null); + assertEquals(ubuntuHardy.getLocation(), defaultLocation); assertEquals(ubuntuHardy.getName(), "8.04"); assertEquals(ubuntuHardy.getOsDescription(), "ubuntu-images-us/ubuntu-hardy-8.04-i386-server-20091130.manifest.xml"); @@ -75,7 +78,7 @@ public class ImageParserTest extends BaseEC2HandlerTest { assertEquals(alesticKarmic.getDescription(), "alestic/ubuntu-9.10-karmic-base-20090623.manifest.xml"); assertEquals(alesticKarmic.getId(), "ami-19a34270"); - assertEquals(alesticKarmic.getLocation(), null); + assertEquals(alesticKarmic.getLocation(), defaultLocation); assertEquals(alesticKarmic.getName(), "9.10"); assertEquals(alesticKarmic.getOsDescription(), "alestic/ubuntu-9.10-karmic-base-20090623.manifest.xml"); @@ -90,7 +93,7 @@ public class ImageParserTest extends BaseEC2HandlerTest { assertEquals(ubuntuKarmic.getDescription(), "ubuntu-images-us/ubuntu-karmic-9.10-i386-server-20100121.manifest.xml"); assertEquals(ubuntuKarmic.getId(), "ami-bb709dd2"); - assertEquals(ubuntuKarmic.getLocation(), null); + assertEquals(ubuntuKarmic.getLocation(), defaultLocation); assertEquals(ubuntuKarmic.getName(), "9.10"); assertEquals(ubuntuKarmic.getOsDescription(), "ubuntu-images-us/ubuntu-karmic-9.10-i386-server-20100121.manifest.xml"); @@ -108,7 +111,7 @@ public class ImageParserTest extends BaseEC2HandlerTest { assertEquals(alesticHardy.getDescription(), "alestic/ubuntu-8.04-hardy-base-20080905.manifest.xml"); assertEquals(alesticHardy.getId(), "ami-c0fa1ea9"); - assertEquals(alesticHardy.getLocation(), null); + assertEquals(alesticHardy.getLocation(), defaultLocation); assertEquals(alesticHardy.getName(), "8.04"); assertEquals(alesticHardy.getOsDescription(), "alestic/ubuntu-8.04-hardy-base-20080905.manifest.xml"); @@ -121,14 +124,17 @@ public class ImageParserTest extends BaseEC2HandlerTest { assert parser.apply(Iterables.get(result, 5)) == null; } + private Location defaultLocation = new LocationImpl(LocationScope.REGION, "us-east-1", + "us-east-1", null); + public void testParseVostokImage() { InputStream is = getClass().getResourceAsStream("/ec2/vostok.xml"); Set result = parseImages(is); ImageParser parser = new ImageParser( - new EC2PopulateDefaultLoginCredentialsForImageStrategy(), ImmutableMap - . of()); + new EC2PopulateDefaultLoginCredentialsForImageStrategy(), ImmutableSet + . of(defaultLocation), defaultLocation); org.jclouds.compute.domain.Image image = parser.apply(Iterables.get(result, 0)); @@ -136,7 +142,7 @@ public class ImageParserTest extends BaseEC2HandlerTest { assertEquals(image.getDescription(), "vostok-builds/vostok-0.95-5622/vostok-0.95-5622.manifest.xml"); assertEquals(image.getId(), "ami-870de2ee"); - assertEquals(image.getLocation(), null); + assertEquals(image.getLocation(), defaultLocation); assertEquals(image.getName(), ""); assertEquals(image.getOsDescription(), "vostok-builds/vostok-0.95-5622/vostok-0.95-5622.manifest.xml"); diff --git a/aws/core/src/test/java/org/jclouds/aws/ec2/compute/functions/RunningInstanceToNodeMetadataTest.java b/aws/core/src/test/java/org/jclouds/aws/ec2/compute/functions/RunningInstanceToNodeMetadataTest.java index cb44e80ee2..2a4298db8d 100644 --- a/aws/core/src/test/java/org/jclouds/aws/ec2/compute/functions/RunningInstanceToNodeMetadataTest.java +++ b/aws/core/src/test/java/org/jclouds/aws/ec2/compute/functions/RunningInstanceToNodeMetadataTest.java @@ -20,7 +20,6 @@ package org.jclouds.aws.ec2.compute.functions; import static org.easymock.EasyMock.expect; import static org.easymock.classextension.EasyMock.createMock; -import static org.easymock.classextension.EasyMock.createNiceMock; import static org.easymock.classextension.EasyMock.replay; import static org.easymock.classextension.EasyMock.verify; import static org.jclouds.aws.ec2.options.DescribeImagesOptions.Builder.imageIds; @@ -29,6 +28,7 @@ import static org.testng.Assert.assertEquals; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Map; +import java.util.Set; import org.jclouds.aws.domain.Region; import org.jclouds.aws.ec2.compute.domain.RegionTag; @@ -62,19 +62,19 @@ public class RunningInstanceToNodeMetadataTest { throws UnknownHostException { AMIClient amiClient = createMock(AMIClient.class); Map credentialsMap = createMock(Map.class); - Map images = createMock(Map.class); - Map locations = createMock(Map.class); + org.jclouds.compute.domain.Image jcImage = createMock(org.jclouds.compute.domain.Image.class); + + Set images = ImmutableSet + . of(jcImage); + + Location location = new LocationImpl(LocationScope.ZONE, "us-east-1a", "description", null); + Set locations = ImmutableSet. of(location); PopulateDefaultLoginCredentialsForImageStrategy credentialProvider = createMock(PopulateDefaultLoginCredentialsForImageStrategy.class); RunningInstance instance = createMock(RunningInstance.class); expect(instance.getId()).andReturn("id").atLeastOnce(); expect(instance.getKeyName()).andReturn(null).atLeastOnce(); expect(instance.getInstanceState()).andReturn(InstanceState.RUNNING); - Location location = new LocationImpl(LocationScope.ZONE, "us-east-1a", "description", null); - expect(locations.get("us-east-1a")).andReturn(location); - - org.jclouds.compute.domain.Image jcImage = createNiceMock(org.jclouds.compute.domain.Image.class); - expect(images.get("imageId")).andReturn(jcImage); expect(instance.getIpAddress()).andReturn( InetAddress.getByAddress(new byte[] { 12, 10, 10, 1 })); @@ -84,32 +84,32 @@ public class RunningInstanceToNodeMetadataTest { expect(instance.getAvailabilityZone()).andReturn(AvailabilityZone.US_EAST_1A).atLeastOnce(); expect(instance.getImageId()).andReturn("imageId").atLeastOnce(); + expect(jcImage.getId()).andReturn("imageId").atLeastOnce(); + expect(jcImage.getLocation()).andReturn(location).atLeastOnce(); expect(instance.getInstanceType()).andReturn(InstanceType.C1_XLARGE).atLeastOnce(); + replay(jcImage); replay(amiClient); replay(credentialsMap); replay(credentialProvider); replay(instance); - replay(images); - replay(locations); RunningInstanceToNodeMetadata parser = new RunningInstanceToNodeMetadata(amiClient, credentialsMap, credentialProvider, images, locations, new RunningInstanceToStorageMappingUnix()); NodeMetadata metadata = parser.apply(instance); - assertEquals(metadata.getLocation(), location); + assertEquals(metadata.getLocation(), locations.iterator().next()); assertEquals(metadata.getImage(), jcImage); assertEquals(metadata.getTag(), "NOTAG-id"); assertEquals(metadata.getCredentials(), null); + verify(jcImage); verify(amiClient); verify(credentialsMap); verify(credentialProvider); verify(instance); - verify(images); - verify(locations); } @SuppressWarnings("unchecked") @@ -118,8 +118,6 @@ public class RunningInstanceToNodeMetadataTest { throws UnknownHostException { AMIClient amiClient = createMock(AMIClient.class); Map credentialsMap = createMock(Map.class); - Map images = createMock(Map.class); - Map locations = createMock(Map.class); PopulateDefaultLoginCredentialsForImageStrategy credentialProvider = createMock(PopulateDefaultLoginCredentialsForImageStrategy.class); RunningInstance instance = createMock(RunningInstance.class); @@ -130,10 +128,10 @@ public class RunningInstanceToNodeMetadataTest { expect(instance.getInstanceState()).andReturn(InstanceState.RUNNING); Location location = new LocationImpl(LocationScope.ZONE, "us-east-1a", "description", null); - expect(locations.get("us-east-1a")).andReturn(location); - - org.jclouds.compute.domain.Image jcImage = createNiceMock(org.jclouds.compute.domain.Image.class); - expect(images.get("imageId")).andReturn(jcImage); + Set locations = ImmutableSet. of(location); + org.jclouds.compute.domain.Image jcImage = createMock(org.jclouds.compute.domain.Image.class); + Set images = ImmutableSet + . of(jcImage); expect(instance.getIpAddress()).andReturn( InetAddress.getByAddress(new byte[] { 12, 10, 10, 1 })); @@ -143,6 +141,8 @@ public class RunningInstanceToNodeMetadataTest { expect(instance.getRegion()).andReturn(Region.US_EAST_1).atLeastOnce(); expect(instance.getImageId()).andReturn("imageId").atLeastOnce(); + expect(jcImage.getId()).andReturn("imageId").atLeastOnce(); + expect(jcImage.getLocation()).andReturn(location).atLeastOnce(); expect(amiClient.describeImagesInRegion(Region.US_EAST_1, imageIds("imageId"))).andReturn( ImmutableSet. of(image)); @@ -160,8 +160,7 @@ public class RunningInstanceToNodeMetadataTest { replay(credentialsMap); replay(credentialProvider); replay(instance); - replay(images); - replay(locations); + replay(jcImage); RunningInstanceToNodeMetadata parser = new RunningInstanceToNodeMetadata(amiClient, credentialsMap, credentialProvider, images, locations, @@ -175,12 +174,12 @@ public class RunningInstanceToNodeMetadataTest { assertEquals(metadata.getCredentials(), new Credentials("user", "pass")); + verify(jcImage); verify(amiClient); verify(credentialsMap); verify(credentialProvider); verify(instance); - verify(images); - verify(locations); + } } diff --git a/aws/demos/createlamp/src/main/java/org/jclouds/aws/ec2/demos/createlamp/MainApp.java b/aws/demos/createlamp/src/main/java/org/jclouds/aws/ec2/demos/createlamp/MainApp.java index 2e04a9d1a8..ccc820da58 100755 --- a/aws/demos/createlamp/src/main/java/org/jclouds/aws/ec2/demos/createlamp/MainApp.java +++ b/aws/demos/createlamp/src/main/java/org/jclouds/aws/ec2/demos/createlamp/MainApp.java @@ -27,7 +27,6 @@ import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import org.jclouds.aws.domain.Region; import org.jclouds.aws.ec2.EC2AsyncClient; import org.jclouds.aws.ec2.EC2Client; import org.jclouds.aws.ec2.EC2ContextFactory; diff --git a/azure/src/main/java/org/jclouds/azure/storage/blob/blobstore/AzureAsyncBlobStore.java b/azure/src/main/java/org/jclouds/azure/storage/blob/blobstore/AzureAsyncBlobStore.java index eeb3839113..671155b89d 100644 --- a/azure/src/main/java/org/jclouds/azure/storage/blob/blobstore/AzureAsyncBlobStore.java +++ b/azure/src/main/java/org/jclouds/azure/storage/blob/blobstore/AzureAsyncBlobStore.java @@ -22,7 +22,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.util.concurrent.Futures.compose; import static org.jclouds.azure.storage.options.ListOptions.Builder.includeMetadata; -import java.util.Map; +import java.util.Set; import java.util.concurrent.ExecutorService; import javax.inject.Inject; @@ -77,7 +77,7 @@ public class AzureAsyncBlobStore extends BaseAsyncBlobStore { @Inject AzureAsyncBlobStore(BlobStoreContext context, BlobStoreUtils blobUtils, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, - Location defaultLocation, Map locations, + Location defaultLocation, Set locations, AzureBlobAsyncClient async, ContainerToResourceMetadata container2ResourceMd, ListOptionsToListBlobsOptions blobStore2AzureContainerListOptions, diff --git a/azure/src/main/java/org/jclouds/azure/storage/blob/blobstore/AzureBlobStore.java b/azure/src/main/java/org/jclouds/azure/storage/blob/blobstore/AzureBlobStore.java index 90591875fe..738a160444 100644 --- a/azure/src/main/java/org/jclouds/azure/storage/blob/blobstore/AzureBlobStore.java +++ b/azure/src/main/java/org/jclouds/azure/storage/blob/blobstore/AzureBlobStore.java @@ -21,7 +21,7 @@ package org.jclouds.azure.storage.blob.blobstore; import static com.google.common.base.Preconditions.checkNotNull; import static org.jclouds.azure.storage.options.ListOptions.Builder.includeMetadata; -import java.util.Map; +import java.util.Set; import javax.inject.Inject; import javax.inject.Singleton; @@ -68,7 +68,7 @@ public class AzureBlobStore extends BaseBlobStore { @Inject AzureBlobStore(BlobStoreContext context, BlobStoreUtils blobUtils, Location defaultLocation, - Map locations, AzureBlobClient sync, + Set locations, AzureBlobClient sync, ContainerToResourceMetadata container2ResourceMd, ListOptionsToListBlobsOptions blobStore2AzureContainerListOptions, ListBlobsResponseToResourceList azure2BlobStoreResourceList, diff --git a/azure/src/main/java/org/jclouds/azure/storage/blob/blobstore/config/AzureBlobStoreContextModule.java b/azure/src/main/java/org/jclouds/azure/storage/blob/blobstore/config/AzureBlobStoreContextModule.java index 468d641c73..72d9f8f5d4 100755 --- a/azure/src/main/java/org/jclouds/azure/storage/blob/blobstore/config/AzureBlobStoreContextModule.java +++ b/azure/src/main/java/org/jclouds/azure/storage/blob/blobstore/config/AzureBlobStoreContextModule.java @@ -18,7 +18,7 @@ */ package org.jclouds.azure.storage.blob.blobstore.config; -import java.util.Map; +import java.util.Set; import javax.inject.Singleton; @@ -39,7 +39,7 @@ import org.jclouds.domain.Location; import org.jclouds.domain.LocationScope; import org.jclouds.domain.internal.LocationImpl; -import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import com.google.inject.Provides; import com.google.inject.Scopes; import com.google.inject.TypeLiteral; @@ -72,7 +72,7 @@ public class AzureBlobStoreContextModule extends AzureBlobContextModule { @Provides @Singleton - Map provideLocations(Location location) { - return ImmutableMap.of(location.getId(), location); + Set provideLocations(Location location) { + return ImmutableSet.of(location); } } diff --git a/blobstore/src/main/clojure/org/jclouds/blobstore.clj b/blobstore/src/main/clojure/org/jclouds/blobstore.clj index 15cdfef206..4ee127c445 100644 --- a/blobstore/src/main/clojure/org/jclouds/blobstore.clj +++ b/blobstore/src/main/clojure/org/jclouds/blobstore.clj @@ -135,7 +135,7 @@ Options can also be specified for extension modules "Retrieve the available container locations for the blobstore context." ([] (locations *blobstore*)) ([#^BlobStore blobstore] - (seq-from-immutable-set (.getAssignableLocations blobstore)))) + (seq (.listAssignableLocations blobstore)))) (defn create-container "Create a container." diff --git a/blobstore/src/main/java/org/jclouds/blobstore/AsyncBlobStore.java b/blobstore/src/main/java/org/jclouds/blobstore/AsyncBlobStore.java index 606241831e..7f0dc56b06 100644 --- a/blobstore/src/main/java/org/jclouds/blobstore/AsyncBlobStore.java +++ b/blobstore/src/main/java/org/jclouds/blobstore/AsyncBlobStore.java @@ -18,7 +18,7 @@ */ package org.jclouds.blobstore; -import java.util.Map; +import java.util.Set; import javax.annotation.Nullable; @@ -49,9 +49,9 @@ public interface AsyncBlobStore { Blob newBlob(String name); /** - * @see BlobStore#getAssignableLocations + * @see BlobStore#listAssignableLocations */ - ListenableFuture> getAssignableLocations(); + ListenableFuture> listAssignableLocations(); /** * @see BlobStore#list diff --git a/blobstore/src/main/java/org/jclouds/blobstore/BlobStore.java b/blobstore/src/main/java/org/jclouds/blobstore/BlobStore.java index 37bdd40cd1..1c767d6b82 100644 --- a/blobstore/src/main/java/org/jclouds/blobstore/BlobStore.java +++ b/blobstore/src/main/java/org/jclouds/blobstore/BlobStore.java @@ -18,7 +18,7 @@ */ package org.jclouds.blobstore; -import java.util.Map; +import java.util.Set; import javax.annotation.Nullable; @@ -50,12 +50,12 @@ public interface BlobStore { Blob newBlob(String name); /** - * The get locations command returns all the valid locations for containers. A location has a scope, - * which is typically region or zone. A region is a general area, like eu-west, where a zone is - * similar to a datacenter. If a location has a parent, that implies it is within that location. - * For example a location can be a rack, whose parent is likely to be a zone. + * The get locations command returns all the valid locations for containers. A location has a + * scope, which is typically region or zone. A region is a general area, like eu-west, where a + * zone is similar to a datacenter. If a location has a parent, that implies it is within that + * location. For example a location can be a rack, whose parent is likely to be a zone. */ - Map getAssignableLocations(); + Set listAssignableLocations(); /** * Lists all root-level resources available to the account. diff --git a/blobstore/src/main/java/org/jclouds/blobstore/TransientAsyncBlobStore.java b/blobstore/src/main/java/org/jclouds/blobstore/TransientAsyncBlobStore.java index eda0fdfb78..1d842d6021 100755 --- a/blobstore/src/main/java/org/jclouds/blobstore/TransientAsyncBlobStore.java +++ b/blobstore/src/main/java/org/jclouds/blobstore/TransientAsyncBlobStore.java @@ -38,6 +38,7 @@ import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import java.util.Map.Entry; @@ -112,7 +113,7 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore { IfDirectoryReturnNameStrategy ifDirectoryReturnName, Blob.Factory blobFactory, BlobStoreUtils blobUtils, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, - Location defaultLocation, Map locations) { + Location defaultLocation, Set locations) { super(context, blobUtils, service, defaultLocation, locations); this.blobFactory = blobFactory; this.dateService = dateService; diff --git a/blobstore/src/main/java/org/jclouds/blobstore/config/TransientBlobStoreModule.java b/blobstore/src/main/java/org/jclouds/blobstore/config/TransientBlobStoreModule.java index 70861548a7..49c6a36dd9 100644 --- a/blobstore/src/main/java/org/jclouds/blobstore/config/TransientBlobStoreModule.java +++ b/blobstore/src/main/java/org/jclouds/blobstore/config/TransientBlobStoreModule.java @@ -18,7 +18,7 @@ */ package org.jclouds.blobstore.config; -import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -30,7 +30,7 @@ import org.jclouds.blobstore.domain.Blob; import org.jclouds.domain.Location; import org.jclouds.util.Jsr330; -import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import com.google.inject.AbstractModule; import com.google.inject.Provides; import com.google.inject.Scopes; @@ -55,7 +55,7 @@ public class TransientBlobStoreModule extends AbstractModule { @Provides @Singleton - Map provideLocations(Location defaultLocation) { - return ImmutableMap. of(defaultLocation.getId(), defaultLocation); + Set provideLocations(Location defaultLocation) { + return ImmutableSet.of( defaultLocation); } } \ No newline at end of file diff --git a/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseAsyncBlobStore.java b/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseAsyncBlobStore.java index 23d3d56677..bc6c37714a 100644 --- a/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseAsyncBlobStore.java +++ b/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseAsyncBlobStore.java @@ -24,7 +24,7 @@ import static com.google.common.util.concurrent.Futures.immediateFuture; import static org.jclouds.blobstore.options.ListContainerOptions.Builder.recursive; import static org.jclouds.concurrent.ConcurrentUtils.makeListenable; -import java.util.Map; +import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; @@ -58,12 +58,12 @@ public abstract class BaseAsyncBlobStore implements AsyncBlobStore { protected final BlobStoreUtils blobUtils; protected final ExecutorService service; protected final Location defaultLocation; - protected final Map locations; + protected final Set locations; @Inject protected BaseAsyncBlobStore(BlobStoreContext context, BlobStoreUtils blobUtils, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, - Location defaultLocation, Map locations) { + Location defaultLocation, Set locations) { this.context = checkNotNull(context, "context"); this.blobUtils = checkNotNull(blobUtils, "blobUtils"); this.service = checkNotNull(service, "service"); @@ -271,7 +271,7 @@ public abstract class BaseAsyncBlobStore implements AsyncBlobStore { } @Override - public ListenableFuture> getAssignableLocations() { + public ListenableFuture> listAssignableLocations() { return immediateFuture(locations); } diff --git a/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseBlobStore.java b/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseBlobStore.java index 46c967ba15..2bbfa1ad04 100644 --- a/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseBlobStore.java +++ b/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseBlobStore.java @@ -21,7 +21,7 @@ package org.jclouds.blobstore.internal; import static com.google.common.base.Preconditions.checkNotNull; import static org.jclouds.blobstore.options.ListContainerOptions.Builder.recursive; -import java.util.Map; +import java.util.Set; import javax.inject.Inject; @@ -48,11 +48,11 @@ public abstract class BaseBlobStore implements BlobStore { protected final BlobStoreContext context; protected final BlobStoreUtils blobUtils; protected final Location defaultLocation; - protected final Map locations; + protected final Set locations; @Inject protected BaseBlobStore(BlobStoreContext context, BlobStoreUtils blobUtils, - Location defaultLocation, Map locations) { + Location defaultLocation, Set locations) { this.context = checkNotNull(context, "context"); this.blobUtils = checkNotNull(blobUtils, "blobUtils"); this.defaultLocation = checkNotNull(defaultLocation, "defaultLocation"); @@ -213,7 +213,7 @@ public abstract class BaseBlobStore implements BlobStore { } @Override - public Map getAssignableLocations() { + public Set listAssignableLocations() { return locations; } diff --git a/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseServiceIntegrationTest.java b/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseServiceIntegrationTest.java index d5a779339a..76128c5975 100755 --- a/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseServiceIntegrationTest.java +++ b/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseServiceIntegrationTest.java @@ -21,7 +21,6 @@ package org.jclouds.blobstore.integration.internal; import static org.testng.Assert.assertEquals; import java.util.Set; -import java.util.Map.Entry; import org.jclouds.blobstore.domain.PageSet; import org.jclouds.blobstore.domain.StorageMetadata; @@ -47,7 +46,7 @@ public class BaseServiceIntegrationTest extends BaseBlobStoreIntegrationTest { @Test(groups = { "integration", "live" }) public void testAllLocations() throws InterruptedException { - for (final Location location : context.getBlobStore().getAssignableLocations().values()) { + for (final Location location : context.getBlobStore().listAssignableLocations()) { final String containerName = getScratchContainerName(); try { System.err.printf(" >> creating container in location %s%n", location); @@ -77,32 +76,31 @@ public class BaseServiceIntegrationTest extends BaseBlobStoreIntegrationTest { @Test(groups = { "integration", "live" }) public void testGetAssignableLocations() throws Exception { - for (Entry location : context.getBlobStore() - .getAssignableLocations().entrySet()) { - System.err.printf("location %s%n", location.getValue()); - assertEquals(location.getKey(), location.getValue().getId()); - assert location.getValue().getId() != null : location; - assert location.getValue() != location.getValue().getParent() : location; - assert location.getValue().getScope() != null : location; - switch (location.getValue().getScope()) { + for (Location location : context.getBlobStore() + .listAssignableLocations()) { + System.err.printf("location %s%n", location); + assert location.getId() != null : location; + assert location != location.getParent() : location; + assert location.getScope() != null : location; + switch (location.getScope()) { case PROVIDER: - assertProvider(location.getValue()); + assertProvider(location); break; case REGION: - assertProvider(location.getValue().getParent()); + assertProvider(location.getParent()); break; case ZONE: - Location provider = location.getValue().getParent().getParent(); + Location provider = location.getParent().getParent(); // zone can be a direct descendant of provider if (provider == null) - provider = location.getValue().getParent(); + provider = location.getParent(); assertProvider(provider); break; case HOST: - Location provider2 = location.getValue().getParent().getParent().getParent(); + Location provider2 = location.getParent().getParent().getParent(); // zone can be a direct descendant of provider if (provider2 == null) - provider2 = location.getValue().getParent().getParent(); + provider2 = location.getParent().getParent(); assertProvider(provider2); break; } diff --git a/compute/src/main/clojure/org/jclouds/compute.clj b/compute/src/main/clojure/org/jclouds/compute.clj index 17b34cac2b..21bb18ed26 100644 --- a/compute/src/main/clojure/org/jclouds/compute.clj +++ b/compute/src/main/clojure/org/jclouds/compute.clj @@ -117,11 +117,11 @@ See http://code.google.com/p/jclouds for details." "Retrieve the available compute locations for the compute context." ([] (locations *compute*)) ([#^ComputeService compute] - (seq-from-immutable-set (.getAssignableLocations compute)))) + (seq (.listAssignableLocations compute)))) (defn nodes-with-tag [#^String tag #^ComputeService compute] - (seq-from-immutable-set (.getNodesWithTag compute tag))) + (seq (.listNodesWithTag compute tag))) (def #^{:private true} list-nodes-map { :with-details #(when %2 (.withDetails %1)) }) @@ -139,20 +139,20 @@ See http://code.google.com/p/jclouds for details." ((list-nodes-map k) lno v) lno) (GetNodesOptions.) options)] - (seq-from-immutable-set (.getNodes compute-or-tag list-nodes-options))) + (seq (.listNodes compute-or-tag list-nodes-options))) (nodes-with-tag compute-or-tag *compute*)))) (defn images "Retrieve the available images for the compute context." ([] (images *compute*)) ([#^ComputeService compute] - (seq-from-immutable-set (.getImages compute)))) + (seq (.listImages compute)))) (defn sizes "Retrieve the available node sizes for the compute context." ([] (sizes *compute*)) ([#^ComputeService compute] - (seq-from-immutable-set (.getSizes compute)))) + (seq (.listSizes compute)))) (defn default-template ([] (default-template *compute*)) @@ -193,7 +193,7 @@ See http://code.google.com/p/jclouds for details." tag count (default-template compute-or-template) compute-or-template) (run-nodes tag count compute-or-template *compute*))) ([tag count template #^ComputeService compute] - (seq-from-immutable-set + (seq (.runNodesWithTag compute tag count template)))) (defn run-node diff --git a/compute/src/main/java/org/jclouds/compute/ComputeService.java b/compute/src/main/java/org/jclouds/compute/ComputeService.java index 34c474b7eb..7dcdc71f6e 100755 --- a/compute/src/main/java/org/jclouds/compute/ComputeService.java +++ b/compute/src/main/java/org/jclouds/compute/ComputeService.java @@ -19,6 +19,7 @@ package org.jclouds.compute; import java.util.Map; +import java.util.Set; import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.Image; @@ -54,14 +55,14 @@ public interface ComputeService { TemplateBuilder templateBuilder(); /** - * The get sizes command shows you the options including virtual cpu count, memory, and disks. + * The list sizes command shows you the options including virtual cpu count, memory, and disks. * cpu count is not a portable quantity across clouds, as they are measured differently. However, * it is a good indicator of relative speed within a cloud. memory is measured in megabytes and * disks in gigabytes. * * @return a map of sizes by ID, conceding that in some clouds the "id" is not used. */ - Map getSizes(); + Set listSizes(); /** * Images define the operating system and metadata related to a node. In some clouds, Images are @@ -70,27 +71,27 @@ public interface ComputeService { * TemplateBuilder as opposed to choosing an image explicitly. The getImages() command returns a * map of images by id. */ - Map getImages(); + Set listImages(); /** * all nodes available to the current user by id. If possible, the returned set will include * {@link NodeMetadata} objects. */ - Map getNodes(); + Set listNodes(); - /** + /** * all nodes available to the current user by id. If possible, the returned set will include * {@link NodeMetadata} objects. */ - Map getNodes(GetNodesOptions options); + Set listNodes(GetNodesOptions options); /** - * The get locations command returns all the valid locations for nodes. A location has a scope, + * The list locations command returns all the valid locations for nodes. A location has a scope, * which is typically region or zone. A region is a general area, like eu-west, where a zone is * similar to a datacenter. If a location has a parent, that implies it is within that location. * For example a location can be a rack, whose parent is likely to be a zone. */ - Map getAssignableLocations(); + Set listAssignableLocations(); /** * @@ -122,8 +123,13 @@ public interface ComputeService { * @param template * - how to configure the nodes * @return all of the nodes the api was able to launch in a running state. + * + * @throws RunNodesException + * when there's a problem applying options to nodes. Note that successful and failed + * nodes are a part of this exception, so be sure to inspect this carefully. */ - Map runNodesWithTag(String tag, int count, Template template); + Set runNodesWithTag(String tag, int count, Template template) + throws RunNodesException; /** * destroy the node. If it is the only node in a tag set, the dependent resources will also be @@ -159,27 +165,32 @@ public interface ComputeService { * * @param tag */ - Map getNodesWithTag(String tag); - - /** - * Runs the script without any additional options - * - * @see #runScriptOnNodesWithTag(String, - * byte[], org.jclouds.compute.options.RunScriptOptions) - */ - Map runScriptOnNodesWithTag(String tag, - byte[] runScript); + Set listNodesWithTag(String tag); /** - * Run the script on all nodes with the specific tag. - * - * @param tag tag to look up the nodes - * @param runScript script to run in byte format. If the script is a string, use - * {@link String#getBytes()} to retrieve the bytes - * @param options nullable options to how to run the script - * @return map with node identifiers and corresponding responses - */ - Map runScriptOnNodesWithTag(String tag, - byte[] runScript, RunScriptOptions options); + * Runs the script without any additional options + * + * @see #runScriptOnNodesWithTag(String, byte[], org.jclouds.compute.options.RunScriptOptions) + */ + Map runScriptOnNodesWithTag(String tag, byte[] runScript) + throws RunScriptOnNodesException; + + /** + * Run the script on all nodes with the specific tag. + * + * @param tag + * tag to look up the nodes + * @param runScript + * script to run in byte format. If the script is a string, use + * {@link String#getBytes()} to retrieve the bytes + * @param options + * nullable options to how to run the script + * @return map with node identifiers and corresponding responses + * @throws RunScriptOnNodesException + * when there's a problem running the script on the nodes. Note that successful and + * failed nodes are a part of this exception, so be sure to inspect this carefully. + */ + Map runScriptOnNodesWithTag(String tag, byte[] runScript, + RunScriptOptions options) throws RunScriptOnNodesException; } diff --git a/compute/src/main/java/org/jclouds/compute/RunNodesException.java b/compute/src/main/java/org/jclouds/compute/RunNodesException.java new file mode 100644 index 0000000000..d89d8385e2 --- /dev/null +++ b/compute/src/main/java/org/jclouds/compute/RunNodesException.java @@ -0,0 +1,99 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ +package org.jclouds.compute; + +import java.util.Map; +import java.util.Set; + +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.Template; +import org.jclouds.compute.util.ComputeUtils; + +/** + * + * @author Adrian Cole + */ +public class RunNodesException extends Exception { + + /** The serialVersionUID */ + private static final long serialVersionUID = -2272965726680821281L; + private final String tag; + private final int count; + private final Template template; + private final Set successfulNodes; + private final Map failedNodes; + private final Map executionExceptions; + + public RunNodesException(String tag, int count, Template template, + Set successfulNodes, Map executionExceptions, + Map failedNodes) { + super( + String + .format( + "error running %d node%s tag(%s) location(%s) image(%s) size(%s) options(%s)%n%s%n%s", + count, count > 1 ? "s" : "", tag, template.getLocation().getId(), + template.getImage().getId(), template.getSize().getId(), template + .getOptions(), ComputeUtils + .createExecutionErrorMessage(executionExceptions), + ComputeUtils.createNodeErrorMessage(failedNodes))); + this.tag = tag; + this.count = count; + this.template = template; + this.successfulNodes = successfulNodes; + this.failedNodes = failedNodes; + this.executionExceptions = executionExceptions; + } + + /** + * + * @return Nodes that performed startup without error + */ + public Set getSuccessfulNodes() { + return successfulNodes; + } + + /** + * + * @return Nodes that performed startup without error, but incurred problems applying options + */ + public Map getExecutionErrors() { + return executionExceptions; + } + + /** + * + * @return Nodes that performed startup without error, but incurred problems applying options + */ + public Map getNodeErrors() { + return failedNodes; + } + + public String getTag() { + return tag; + } + + public int getCount() { + return count; + } + + public Template getTemplate() { + return template; + } + +} diff --git a/compute/src/main/java/org/jclouds/compute/RunScriptOnNodesException.java b/compute/src/main/java/org/jclouds/compute/RunScriptOnNodesException.java new file mode 100644 index 0000000000..f16005b32c --- /dev/null +++ b/compute/src/main/java/org/jclouds/compute/RunScriptOnNodesException.java @@ -0,0 +1,96 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ +package org.jclouds.compute; + +import java.util.Map; + +import javax.annotation.Nullable; + +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.options.RunScriptOptions; +import org.jclouds.compute.util.ComputeUtils; +import org.jclouds.ssh.ExecResponse; + +/** + * + * @author Adrian Cole + */ +public class RunScriptOnNodesException extends Exception { + + /** The serialVersionUID */ + private static final long serialVersionUID = -2272965726680821281L; + private final String tag; + private final byte[] runScript; + private final RunScriptOptions options; + private final Map successfulNodes; + private final Map failedNodes; + private final Map executionExceptions; + + public RunScriptOnNodesException(String tag, final byte[] runScript, + @Nullable final RunScriptOptions options, + Map successfulNodes, Map executionExceptions, + Map failedNodes) { + super(String.format("error runScript on node tag(%s) options(%s) exceptions: %s", tag, + options, ComputeUtils.createExecutionErrorMessage(executionExceptions), ComputeUtils + .createNodeErrorMessage(failedNodes))); + this.tag = tag; + this.runScript = runScript; + this.options = options; + this.successfulNodes = successfulNodes; + this.failedNodes = failedNodes; + this.executionExceptions = executionExceptions; + } + + /** + * + * @return Nodes that performed ssh without error + */ + public Map getSuccessfulNodes() { + return successfulNodes; + } + + /** + * + * @return Nodes that performed startup without error, but incurred problems applying options + */ + public Map getExecutionErrors() { + return executionExceptions; + } + + /** + * + * @return Nodes that performed startup without error, but incurred problems applying options + */ + public Map getNodeErrors() { + return failedNodes; + } + + public String getTag() { + return tag; + } + + public byte[] getRunScript() { + return runScript; + } + + public RunScriptOptions getOptions() { + return options; + } + +} diff --git a/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java b/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java index 440b49eeea..a1cf8fb4a2 100755 --- a/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java +++ b/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java @@ -31,7 +31,6 @@ import static org.jclouds.util.Utils.checkNotEmpty; import java.util.Map; import java.util.Set; -import java.util.Map.Entry; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; @@ -45,6 +44,8 @@ import javax.inject.Singleton; import org.jclouds.Constants; import org.jclouds.compute.ComputeService; import org.jclouds.compute.ComputeServiceContext; +import org.jclouds.compute.RunNodesException; +import org.jclouds.compute.RunScriptOnNodesException; import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.ComputeType; import org.jclouds.compute.domain.Image; @@ -62,13 +63,14 @@ import org.jclouds.compute.strategy.ListNodesStrategy; import org.jclouds.compute.strategy.RebootNodeStrategy; import org.jclouds.compute.strategy.RunNodesAndAddToSetStrategy; import org.jclouds.compute.util.ComputeUtils; +import org.jclouds.compute.util.ComputeUtils.RunScriptOnNode; import org.jclouds.domain.Location; import org.jclouds.logging.Logger; import org.jclouds.ssh.ExecResponse; +import org.jclouds.ssh.SshClient; import com.google.common.base.Function; import com.google.common.base.Predicate; -import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; import com.google.common.collect.Sets; @@ -86,9 +88,9 @@ public class BaseComputeService implements ComputeService { protected Logger logger = Logger.NULL; protected final ComputeServiceContext context; - protected final Provider> images; - protected final Provider> sizes; - protected final Provider> locations; + protected final Provider> images; + protected final Provider> sizes; + protected final Provider> locations; protected final ListNodesStrategy listNodesStrategy; protected final GetNodeMetadataStrategy getNodeMetadataStrategy; protected final RunNodesAndAddToSetStrategy runNodesAndAddToSetStrategy; @@ -112,26 +114,11 @@ public class BaseComputeService implements ComputeService { }; - public static Function METADATA_TO_ID = new Function() { - @Override - public String apply(ComputeMetadata from) { - return from.getId(); - } - }; - - public static Function METADATA_TO_NAME = new Function() { - @Override - public String apply(ComputeMetadata from) { - return from.getName(); - } - }; - @Inject protected BaseComputeService(ComputeServiceContext context, - Provider> images, - Provider> sizes, - Provider> locations, - ListNodesStrategy listNodesStrategy, GetNodeMetadataStrategy getNodeMetadataStrategy, + Provider> images, Provider> sizes, + Provider> locations, ListNodesStrategy listNodesStrategy, + GetNodeMetadataStrategy getNodeMetadataStrategy, RunNodesAndAddToSetStrategy runNodesAndAddToSetStrategy, RebootNodeStrategy rebootNodeStrategy, DestroyNodeStrategy destroyNodeStrategy, Provider templateBuilderProvider, ComputeUtils utils, @@ -159,28 +146,23 @@ public class BaseComputeService implements ComputeService { } @Override - public Map runNodesWithTag(final String tag, int count, - final Template template) { + public Set runNodesWithTag(final String tag, int count, + final Template template) throws RunNodesException { checkArgument(tag.indexOf('-') == -1, "tag cannot contain hyphens"); checkNotNull(template.getLocation(), "location"); logger.debug(">> running %d node%s tag(%s) location(%s) image(%s) size(%s) options(%s)", count, count > 1 ? "s" : "", tag, template.getLocation().getId(), template .getImage().getId(), template.getSize().getId(), template.getOptions()); final Set nodes = Sets.newHashSet(); + final Map badNodes = Maps.newLinkedHashMap(); Map> responses = runNodesAndAddToSetStrategy.execute(tag, count, - template, nodes); - Map exceptions = awaitCompletion(responses, executor, null, logger, + template, nodes, badNodes); + Map executionExceptions = awaitCompletion(responses, executor, null, logger, "starting nodes"); - if (exceptions.size() > 0 && template.getOptions().shouldDestroyOnError()) { - ImmutableMap currentNodes = Maps.uniqueIndex( - listNodesStrategy.execute(GetNodesOptions.NONE), METADATA_TO_ID); - for (Entry entry : exceptions.entrySet()) { - logger.error(entry.getValue(), "<< error applying nodes(%s) [%s] destroying ", entry - .getKey(), entry.getValue().getMessage()); - destroyNode(currentNodes.get(entry.getKey())); - } + if (executionExceptions.size() > 0 || badNodes.size() > 0) { + throw new RunNodesException(tag, count, template, nodes, executionExceptions, badNodes); } - return Maps.uniqueIndex(nodes, METADATA_TO_ID); + return nodes; } @Override @@ -196,14 +178,14 @@ public class BaseComputeService implements ComputeService { @Override public void destroyNodesWithTag(String tag) { // TODO parallel logger.debug(">> destroying nodes by tag(%s)", tag); - Iterable nodesToDestroy = Iterables.filter(doGetNodesWithTag(tag) - .values(), new Predicate() { - @Override - public boolean apply(NodeMetadata input) { - return input.getState() != NodeState.TERMINATED; + Iterable nodesToDestroy = Iterables.filter(doListNodesWithTag(tag), + new Predicate() { + @Override + public boolean apply(NodeMetadata input) { + return input.getState() != NodeState.TERMINATED; - } - }); + } + }); Map> responses = Maps.newHashMap(); for (final NodeMetadata node : nodesToDestroy) { responses.put(node, makeListenable(executor.submit(new Callable() { @@ -219,69 +201,59 @@ public class BaseComputeService implements ComputeService { } @Override - public Map getNodes() { - logger.debug(">> listing servers"); - ImmutableMap map = Maps.uniqueIndex(listNodesStrategy - .execute(GetNodesOptions.NONE), METADATA_TO_ID); - logger.debug("<< list(%d)", map.size()); - return map; + public Set listNodes() { + return listNodes(null); } + @Override - public Map getNodes(GetNodesOptions options) { + public Set listNodes(GetNodesOptions options) { logger.debug(">> listing servers"); - if(options == null){ - options = GetNodesOptions.NONE; + if (options == null) { + options = GetNodesOptions.NONE; } - ImmutableMap map = Maps.uniqueIndex(listNodesStrategy - .execute(options), METADATA_TO_ID); - logger.debug("<< list(%d)", map.size()); - return map; + Set set = Sets + .newLinkedHashSet(listNodesStrategy.execute(options)); + logger.debug("<< list(%d)", set.size()); + return set; } + /** * If the result of {@link ListNodesStrategy#execute} is a set of nodes, then return them. * Otherwise iteratively call {@link #getNodeMetadata} */ - protected Map doGetNodesWithTag(final String tag) { - Iterable nodes = Iterables.filter(Iterables.transform( - listNodesStrategy.execute(GetNodesOptions.NONE), new Function() { - - @Override - public NodeMetadata apply(ComputeMetadata from) { - return from instanceof NodeMetadata ? NodeMetadata.class.cast(from) - : getNodeMetadata(from); - } - - }), new Predicate() { + protected Set doListNodesWithTag(final String tag) { + return Sets.newHashSet(Iterables.filter(Iterables.transform(listNodesStrategy + .execute(GetNodesOptions.NONE), new Function() { @Override - public boolean apply(NodeMetadata input) { - return tag.equals(input.getTag()); + public NodeMetadata apply(ComputeMetadata from) { + return from instanceof NodeMetadata ? NodeMetadata.class.cast(from) + : getNodeMetadata(from); } - }); - return Maps.uniqueIndex(Iterables.filter(nodes, new NodeMatchesTag(tag)), METADATA_TO_ID); + }), new NodeMatchesTag(tag))); } @Override - public Map getNodesWithTag(String tag) { + public Set listNodesWithTag(String tag) { logger.debug(">> listing nodes by tag(%s)", tag); - Map nodes = doGetNodesWithTag(tag); + Set nodes = doListNodesWithTag(tag); logger.debug("<< list(%d)", nodes.size()); return nodes; } @Override - public Map getSizes() { + public Set listSizes() { return sizes.get(); } @Override - public Map getImages() { + public Set listImages() { return images.get(); } @Override - public Map getAssignableLocations() { + public Set listAssignableLocations() { return locations.get(); } @@ -310,14 +282,14 @@ public class BaseComputeService implements ComputeService { @Override public void rebootNodesWithTag(String tag) { // TODO parallel logger.debug(">> rebooting nodes by tag(%s)", tag); - Iterable nodesToReboot = Iterables.filter(doGetNodesWithTag(tag) - .values(), new Predicate() { - @Override - public boolean apply(NodeMetadata input) { - return input.getState() != NodeState.TERMINATED; + Iterable nodesToReboot = Iterables.filter(doListNodesWithTag(tag), + new Predicate() { + @Override + public boolean apply(NodeMetadata input) { + return input.getState() != NodeState.TERMINATED; - } - }); + } + }); Map> responses = Maps.newHashMap(); for (final NodeMetadata node : nodesToReboot) { responses.put(node, makeListenable(executor.submit(new Callable() { @@ -333,9 +305,11 @@ public class BaseComputeService implements ComputeService { } /** + * @throws RunScriptOnNodesException * @see #runScriptOnNodesWithTag(String, byte[], org.jclouds.compute.options.RunScriptOptions) */ - public Map runScriptOnNodesWithTag(String tag, byte[] runScript) { + public Map runScriptOnNodesWithTag(String tag, byte[] runScript) + throws RunScriptOnNodesException { return runScriptOnNodesWithTag(tag, runScript, RunScriptOptions.NONE); } @@ -350,46 +324,94 @@ public class BaseComputeService implements ComputeService { * @param options * nullable options to how to run the script, whether to override credentials * @return map with node identifiers and corresponding responses + * @throws RunScriptOnNodesException */ - @SuppressWarnings("unchecked") - public Map runScriptOnNodesWithTag(String tag, byte[] runScript, - @Nullable RunScriptOptions options) { + public Map runScriptOnNodesWithTag(String tag, + final byte[] runScript, @Nullable final RunScriptOptions options) + throws RunScriptOnNodesException { + Iterable nodes = verifyParametersAndGetNodes(tag, runScript, + (options != null) ? options : RunScriptOptions.NONE); + final Map execs = Maps.newHashMap(); + + final Map badNodes = Maps.newLinkedHashMap(); + + Map> responses = Maps.newHashMap(); + + for (final NodeMetadata node : nodes) { + + responses.put(node, makeListenable(executor.submit(new Callable() { + @Override + public Void call() throws Exception { + try { + RunScriptOnNode callable; + if (options.isRunAsRoot()) + callable = utils.runScriptOnNode(node, "computeserv", runScript); + else + callable = utils.runScriptOnNodeAsDefaultUser(node, "computeserv", runScript); + SshClient ssh = utils.createSshClientOncePortIsListeningOnNode(node); + try { + ssh.connect(); + callable.setConnection(ssh, logger); + execs.put(node, callable.call()); + } finally { + if (ssh != null) + ssh.disconnect(); + } + } catch (Exception e) { + badNodes.put(node, e); + + } + return null; + } + }), executor)); + + } + Map exceptions = awaitCompletion(responses, executor, null, logger, + "starting nodes"); + if (exceptions.size() > 0 || badNodes.size() > 0) { + throw new RunScriptOnNodesException(tag, runScript, options, execs, exceptions, badNodes); + } + return execs; + } + + private Iterable verifyParametersAndGetNodes(String tag, + byte[] runScript, final RunScriptOptions options) { checkNotEmpty(tag, "Tag must be provided"); checkNotNull(runScript, "The script (represented by bytes array - use \"script\".getBytes() must be provided"); - if (options == null) - options = RunScriptOptions.NONE; + checkNotNull(options, "options"); + Iterable nodes = Iterables.filter(listNodesWithTag(tag), + new Predicate() { - Map nodes = getNodesWithTag(tag); - Map responses = Maps.newHashMap(); + @Override + public boolean apply(NodeMetadata input) { + return input.getState() == NodeState.RUNNING; + } - for (NodeMetadata node : nodes.values()) { - if (NodeState.RUNNING != node.getState()) - continue; // make sure the node is active + }); + return Iterables.transform(nodes, new Function() { - if (options.getOverrideCredentials() != null) { - // override the credentials with provided to this method - node = ComputeUtils.installNewCredentials(node, options.getOverrideCredentials()); - } else { - // don't override - checkNotNull(node.getCredentials(), - "If the default credentials need to be used, they can't be null"); - checkNotNull(node.getCredentials().account, "Account name for ssh authentication must be " + - "specified. Try passing RunScriptOptions with new credentials"); - checkNotNull(node.getCredentials().key, "Key or password for ssh authentication must be " + - "specified. Try passing RunScriptOptions with new credentials"); + @Override + public NodeMetadata apply(NodeMetadata node) { + + checkArgument(node.getPublicAddresses().size() > 0, "no public ip addresses on node: " + + node); + if (options.getOverrideCredentials() != null) { + // override the credentials with provided to this method + node = ComputeUtils.installNewCredentials(node, options.getOverrideCredentials()); + } else { + // don't override + checkNotNull(node.getCredentials(), + "If the default credentials need to be used, they can't be null"); + checkNotNull(node.getCredentials().account, + "Account name for ssh authentication must be " + + "specified. Try passing RunScriptOptions with new credentials"); + checkNotNull(node.getCredentials().key, + "Key or password for ssh authentication must be " + + "specified. Try passing RunScriptOptions with new credentials"); + } + return node; } - - ComputeUtils.SshCallable callable; - if (options.isRunAsRoot()) - callable = utils.runScriptOnNode(node, "computeserv.sh", runScript); - else - callable = utils.runScriptOnNodeAsDefaultUser(node, "computeserv.sh", runScript); - - Map, ?> scriptRunResults = utils.runCallablesOnNode(node, Sets - .newHashSet(callable), null); - responses.put(node.getId(), (ExecResponse) scriptRunResults.get(callable)); - } - return responses; + }); } } \ No newline at end of file diff --git a/compute/src/main/java/org/jclouds/compute/internal/TemplateBuilderImpl.java b/compute/src/main/java/org/jclouds/compute/internal/TemplateBuilderImpl.java index bc6ab7aec1..4b9c881fb4 100644 --- a/compute/src/main/java/org/jclouds/compute/internal/TemplateBuilderImpl.java +++ b/compute/src/main/java/org/jclouds/compute/internal/TemplateBuilderImpl.java @@ -18,11 +18,10 @@ */ package org.jclouds.compute.internal; -import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; -import java.util.Map; import java.util.NoSuchElementException; +import java.util.Set; import javax.annotation.Resource; import javax.inject.Inject; @@ -61,9 +60,9 @@ public class TemplateBuilderImpl implements TemplateBuilder { @Named(ComputeServiceConstants.COMPUTE_LOGGER) protected Logger logger = Logger.NULL; - private final Map images; - private final Map sizes; - private final Map locations; + private final Set images; + private final Set sizes; + private final Set locations; @VisibleForTesting OsFamily os; @VisibleForTesting @@ -97,9 +96,8 @@ public class TemplateBuilderImpl implements TemplateBuilder { private TemplateOptions options = TemplateOptions.NONE; @Inject - protected TemplateBuilderImpl(Map locations, - Map images, Map sizes, - Location defaultLocation) { + protected TemplateBuilderImpl(Set locations, Set images, + Set sizes, Location defaultLocation) { this.locations = locations; this.images = images; this.sizes = sizes; @@ -363,8 +361,6 @@ public class TemplateBuilderImpl implements TemplateBuilder { */ @Override public TemplateBuilder locationId(final String locationId) { - checkArgument(locations.get(checkNotNull(locationId, "locationId")) != null, "locationId " - + locationId + " not configured in: " + locations.keySet()); this.locationId = locationId; return this; } @@ -395,7 +391,7 @@ public class TemplateBuilderImpl implements TemplateBuilder { logger.debug(">> searching params(%s)", this); Image image; try { - image = DEFAULT_IMAGE_ORDERING.max(Iterables.filter(images.values(), imagePredicate)); + image = DEFAULT_IMAGE_ORDERING.max(Iterables.filter(images, imagePredicate)); } catch (NoSuchElementException exception) { throw new NoSuchElementException("image didn't match: " + toString() + "\n" + images); } @@ -410,12 +406,19 @@ public class TemplateBuilderImpl implements TemplateBuilder { sizeOrdering = Ordering.compound(ImmutableList.of(BY_CORES_ORDERING, sizeOrdering)); Size size; try { - size = sizeOrdering.max(Iterables.filter(sizes.values(), sizePredicate)); + size = sizeOrdering.max(Iterables.filter(sizes, sizePredicate)); } catch (NoSuchElementException exception) { throw new NoSuchElementException("size didn't match: " + toString() + "\n" + sizes); } logger.debug("<< matched size(%s)", size); - Location location = locations.get(locationId); + Location location = Iterables.find(locations, new Predicate() { + + @Override + public boolean apply(Location input) { + return input.getId().equals(locationId); + } + + }); logger.debug("<< matched location(%s)", location); return new TemplateImpl(image, size, location, options); } diff --git a/compute/src/main/java/org/jclouds/compute/options/RunScriptOptions.java b/compute/src/main/java/org/jclouds/compute/options/RunScriptOptions.java index 96d8882779..f8172eb351 100644 --- a/compute/src/main/java/org/jclouds/compute/options/RunScriptOptions.java +++ b/compute/src/main/java/org/jclouds/compute/options/RunScriptOptions.java @@ -83,4 +83,10 @@ public class RunScriptOptions { } + @Override + public String toString() { + return "RunScriptOptions [overridingCredentials=" + (overridingCredentials != null) + + ", runAsRoot=" + runAsRoot + "]"; + } + } diff --git a/compute/src/main/java/org/jclouds/compute/options/TemplateOptions.java b/compute/src/main/java/org/jclouds/compute/options/TemplateOptions.java index 1d156ad1df..50c618f31a 100644 --- a/compute/src/main/java/org/jclouds/compute/options/TemplateOptions.java +++ b/compute/src/main/java/org/jclouds/compute/options/TemplateOptions.java @@ -32,8 +32,6 @@ public class TemplateOptions { private String publicKey; - private boolean destroyOnError; - private int port = -1; private int seconds = -1; @@ -64,10 +62,6 @@ public class TemplateOptions { return publicKey; } - public boolean shouldDestroyOnError() { - return destroyOnError; - } - public boolean isIncludeMetadata() { return includeMetadata; } @@ -83,14 +77,6 @@ public class TemplateOptions { return this; } - /** - * If there is an error applying options after creating the node, destroy it. - */ - public TemplateOptions destroyOnError() { - this.destroyOnError = true; - return this; - } - /** * This script will be executed as the root user upon system startup. This script gets a * prologue, so no #!/bin/bash required, path set up, etc @@ -139,13 +125,6 @@ public class TemplateOptions { } public static class Builder { - /** - * @see TemplateOptions#destroyOnError - */ - public static TemplateOptions destroyOnError() { - TemplateOptions options = new TemplateOptions(); - return options.destroyOnError(); - } /** * @see TemplateOptions#inboundPorts @@ -198,7 +177,7 @@ public class TemplateOptions { public String toString() { return "TemplateOptions [inboundPorts=" + Arrays.toString(inboundPorts) + ", privateKey=" + (privateKey != null) + ", publicKey=" + (publicKey != null) + ", runScript=" - + (script != null) + ", destroyOnError=" + destroyOnError + ", port:seconds=" + port - + ":" + seconds + ", metadata/details: " + includeMetadata + "]"; + + (script != null) + ", port:seconds=" + port + ":" + seconds + + ", metadata/details: " + includeMetadata + "]"; } } diff --git a/compute/src/main/java/org/jclouds/compute/strategy/RunNodesAndAddToSetStrategy.java b/compute/src/main/java/org/jclouds/compute/strategy/RunNodesAndAddToSetStrategy.java index 032962e4b3..1a681667b6 100644 --- a/compute/src/main/java/org/jclouds/compute/strategy/RunNodesAndAddToSetStrategy.java +++ b/compute/src/main/java/org/jclouds/compute/strategy/RunNodesAndAddToSetStrategy.java @@ -38,5 +38,5 @@ import com.google.inject.ImplementedBy; public interface RunNodesAndAddToSetStrategy { Map> execute(String tag, int count, Template template, - Set nodes); + Set nodes, Map badNodes); } \ No newline at end of file diff --git a/compute/src/main/java/org/jclouds/compute/strategy/impl/EncodeTagIntoNameRunNodesAndAddToSetStrategy.java b/compute/src/main/java/org/jclouds/compute/strategy/impl/EncodeTagIntoNameRunNodesAndAddToSetStrategy.java index 3ebdbb3c1a..494aa4b470 100755 --- a/compute/src/main/java/org/jclouds/compute/strategy/impl/EncodeTagIntoNameRunNodesAndAddToSetStrategy.java +++ b/compute/src/main/java/org/jclouds/compute/strategy/impl/EncodeTagIntoNameRunNodesAndAddToSetStrategy.java @@ -36,7 +36,6 @@ import org.jclouds.Constants; import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.Template; -import org.jclouds.compute.internal.BaseComputeService; import org.jclouds.compute.options.GetNodesOptions; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.strategy.AddNodeWithTagStrategy; @@ -45,6 +44,8 @@ import org.jclouds.compute.strategy.RunNodesAndAddToSetStrategy; import org.jclouds.compute.util.ComputeUtils; import org.jclouds.logging.Logger; +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.common.util.concurrent.ListenableFuture; @@ -83,7 +84,8 @@ public class EncodeTagIntoNameRunNodesAndAddToSetStrategy implements RunNodesAnd */ @Override public Map> execute(final String tag, final int count, - final Template template, final Set nodes) { + final Template template, final Set nodes, + final Map badNodes) { Map> responses = Maps.newHashMap(); for (final String name : getNextNames(tag, template, count)) { responses.put(name, makeListenable(executor.submit(new Callable() { @@ -100,8 +102,7 @@ public class EncodeTagIntoNameRunNodesAndAddToSetStrategy implements RunNodesAnd } catch (Exception e) { logger.error(e, "<< error applying options (%s) on node (%s)", template .getOptions(), node.getId()); - if (!template.getOptions().shouldDestroyOnError()) - nodes.add(node); + badNodes.put(node, e); } return null; } @@ -122,11 +123,20 @@ public class EncodeTagIntoNameRunNodesAndAddToSetStrategy implements RunNodesAnd */ protected Set getNextNames(final String tag, final Template template, int count) { Set names = Sets.newHashSet(); - Map currentNodes = Maps.uniqueIndex(listNodesStrategy - .execute(GetNodesOptions.NONE), BaseComputeService.METADATA_TO_NAME); - while (names.size() < count) { - String name = getNextName(tag, template); - if (!currentNodes.containsKey(name)) { + Iterable currentNodes = listNodesStrategy + .execute(GetNodesOptions.NONE); + int maxTries = 100; + int currentTries = 0; + while (names.size() < count && currentTries++ < maxTries) { + final String name = getNextName(tag, template); + if (!Iterables.any(currentNodes, new Predicate() { + + @Override + public boolean apply(ComputeMetadata input) { + return name.equals(input.getName()); + } + + })) { names.add(name); } } diff --git a/compute/src/main/java/org/jclouds/compute/util/ComputeUtils.java b/compute/src/main/java/org/jclouds/compute/util/ComputeUtils.java index b4cafc1f76..637fb4e5ef 100644 --- a/compute/src/main/java/org/jclouds/compute/util/ComputeUtils.java +++ b/compute/src/main/java/org/jclouds/compute/util/ComputeUtils.java @@ -24,15 +24,16 @@ import static org.jclouds.concurrent.ConcurrentUtils.awaitCompletion; import java.io.ByteArrayInputStream; import java.io.IOException; -import java.net.ConnectException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.Comparator; +import java.util.Formatter; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; +import java.util.Map.Entry; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; @@ -84,7 +85,28 @@ public class ComputeUtils { private final Predicate socketTester; private final ExecutorService executor; - private int sshRetries = 3; + public static String createExecutionErrorMessage(Map executionExceptions) { + Formatter fmt = new Formatter().format("Execution failures:%n%n"); + int index = 1; + for (Entry errorMessage : executionExceptions.entrySet()) { + fmt.format("%s) %s on %s:%n%s%n%n", index++, errorMessage.getValue().getClass() + .getSimpleName(), errorMessage.getKey(), Throwables + .getStackTraceAsString(errorMessage.getValue())); + } + return fmt.format("%s error[s]", executionExceptions.size()).toString(); + } + + public static String createNodeErrorMessage( + Map failedNodes) { + Formatter fmt = new Formatter().format("Node failures:%n%n"); + int index = 1; + for (Entry errorMessage : failedNodes.entrySet()) { + fmt.format("%s) %s on node %s:%n%s%n%n", index++, errorMessage.getValue().getClass() + .getSimpleName(), errorMessage.getKey().getId(), Throwables + .getStackTraceAsString(errorMessage.getValue())); + } + return fmt.format("%s error[s]", failedNodes.size()).toString(); + } @Inject public ComputeUtils(Predicate socketTester, @@ -117,7 +139,7 @@ public class ComputeUtils { public void runOptionsOnNode(NodeMetadata node, TemplateOptions options) { List> callables = Lists.newArrayList(); if (options.getRunScript() != null) { - callables.add(runScriptOnNode(node, "runscript.sh", options.getRunScript())); + callables.add(runScriptOnNode(node, "runscript", options.getRunScript())); } if (options.getPublicKey() != null) { callables.add(authorizeKeyOnNode(node, options.getPublicKey())); @@ -168,60 +190,60 @@ public class ComputeUtils { Iterable> parallel, @Nullable SshCallable last) { checkState(this.sshFactory != null, "runScript requested, but no SshModule configured"); checkNotNull(node.getCredentials().key, "credentials.key for node " + node.getId()); + SshClient ssh = createSshClientOncePortIsListeningOnNode(node); + try { + ssh.connect(); + return runTasksUsingSshClient(parallel, last, ssh); + } finally { + if (ssh != null) + ssh.disconnect(); + } + } + private Map, ?> runTasksUsingSshClient( + Iterable> parallel, SshCallable last, SshClient ssh) { + Map, Object> responses = Maps.newHashMap(); + if (Iterables.size(parallel) > 0) { + responses.putAll(runCallablesUsingSshClient(parallel, ssh)); + } + if (last != null) { + last.setConnection(ssh, logger); + try { + responses.put(last, last.call()); + } catch (Exception e) { + Throwables.propagate(e); + } + } + return responses; + } + + public SshClient createSshClientOncePortIsListeningOnNode(NodeMetadata node) { InetSocketAddress socket = new InetSocketAddress(Iterables.get(node.getPublicAddresses(), 0), 22); socketTester.apply(socket); SshClient ssh = isKeyAuth(node) ? sshFactory.create(socket, node.getCredentials().account, node.getCredentials().key.getBytes()) : sshFactory.create(socket, node .getCredentials().account, node.getCredentials().key); - for (int i = 0; i < sshRetries; i++) { - try { - ssh.connect(); - Map, ListenableFuture> responses = Maps.newHashMap(); + return ssh; + } - for (SshCallable callable : parallel) { - callable.setConnection(ssh, logger); - responses.put(callable, ConcurrentUtils.makeListenable(executor.submit(callable), - executor)); - } + private Map, Object> runCallablesUsingSshClient( + Iterable> parallel, SshClient ssh) { + Map, ListenableFuture> parallelResponses = Maps.newHashMap(); - Map, Exception> exceptions = awaitCompletion(responses, executor, null, - logger, "ssh"); - if (exceptions.size() > 0) - throw new RuntimeException(String.format("error invoking callables on host %s: %s", - socket, exceptions)); - if (last != null) { - last.setConnection(ssh, logger); - try { - last.call(); - } catch (Exception e) { - Throwables.propagate(e); - } - } - return transform(responses); - } catch (RuntimeException from) { - if (i + 1 == sshRetries) - throw Throwables.propagate(from); - if (Iterables.size(Iterables.filter(Throwables.getCausalChain(from), - ConnectException.class)) >= 1// auth fail sometimes happens in EC2 - || Throwables.getRootCause(from).getMessage().indexOf("Auth fail") != -1 - || Throwables.getRootCause(from).getMessage().indexOf("invalid privatekey") != -1) { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - throw Throwables.propagate(e); - } - continue; - } - throw Throwables.propagate(from); - } finally { - if (ssh != null) - ssh.disconnect(); - } + for (SshCallable callable : parallel) { + callable.setConnection(ssh, logger); + parallelResponses.put(callable, ConcurrentUtils.makeListenable(executor.submit(callable), + executor)); } - throw new RuntimeException(String.format("Couldn't connect to node %s and run the script", - node.getId())); + + Map, Exception> exceptions = awaitCompletion(parallelResponses, executor, + null, logger, "ssh"); + if (exceptions.size() > 0) + throw new RuntimeException(String.format("error invoking callables on nodes: %s", + exceptions)); + Map, Object> newresponses = transform(parallelResponses); + return newresponses; } @SuppressWarnings("unchecked") @@ -240,6 +262,8 @@ public class ComputeUtils { } public static interface SshCallable extends Callable { + NodeMetadata getNode(); + void setConnection(SshClient ssh, Logger logger); } @@ -254,14 +278,7 @@ public class ComputeUtils { RunScriptOnNode(@Named("NOT_RUNNING") Predicate runScriptNotRunning, NodeMetadata node, String scriptName, byte[] script) { - this.runScriptNotRunning = runScriptNotRunning; - this.node = checkNotNull(node, "node"); - this.scriptName = checkNotNull(scriptName, "scriptName"); - this.script = new InitBuilder("runscript", "/tmp", "/tmp", ImmutableMap - . of(), Iterables.toArray(Splitter.on("\n").split( - new String(checkNotNull(script, "script"))), String.class)).build(OsFamily.UNIX) - .getBytes(); - this.runAsRoot = true; + this(runScriptNotRunning, node, scriptName, script, true); } RunScriptOnNode(@Named("NOT_RUNNING") Predicate runScriptNotRunning, @@ -269,10 +286,10 @@ public class ComputeUtils { this.runScriptNotRunning = runScriptNotRunning; this.node = checkNotNull(node, "node"); this.scriptName = checkNotNull(scriptName, "scriptName"); - this.script = new InitBuilder("runscript", "/tmp", "/tmp", ImmutableMap - . of(), Iterables.toArray(Splitter.on("\n").split( - new String(checkNotNull(script, "script"))), String.class)).build(OsFamily.UNIX) - .getBytes(); + this.script = new InitBuilder(scriptName, "/tmp/" + scriptName, "/tmp/" + scriptName, + ImmutableMap. of(), Iterables.toArray(Splitter.on("\n").split( + new String(checkNotNull(script, "script"))), String.class)).build( + OsFamily.UNIX).getBytes(); this.runAsRoot = runAsRoot; } @@ -329,6 +346,11 @@ public class ComputeUtils { Iterables.get(node.getPublicAddresses(), 0).getHostAddress()); return ssh.exec(String.format("./%s", scriptName + " start")); } + + @Override + public NodeMetadata getNode() { + return node; + } } public static class InstallRSAPrivateKey implements SshCallable { @@ -358,6 +380,10 @@ public class ComputeUtils { this.ssh = checkNotNull(ssh, "ssh"); } + @Override + public NodeMetadata getNode() { + return node; + } } public static class AuthorizeRSAPublicKey implements SshCallable { @@ -390,6 +416,10 @@ public class ComputeUtils { this.ssh = checkNotNull(ssh, "ssh"); } + @Override + public NodeMetadata getNode() { + return node; + } } public static boolean isKeyAuth(NodeMetadata createdNode) { @@ -434,4 +464,5 @@ public class ComputeUtils { } return providers; } + } diff --git a/compute/src/test/java/org/jclouds/compute/BaseComputeServiceLiveTest.java b/compute/src/test/java/org/jclouds/compute/BaseComputeServiceLiveTest.java index f4088fa3b4..09a9438c09 100755 --- a/compute/src/test/java/org/jclouds/compute/BaseComputeServiceLiveTest.java +++ b/compute/src/test/java/org/jclouds/compute/BaseComputeServiceLiveTest.java @@ -31,7 +31,6 @@ import java.util.NoSuchElementException; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; -import java.util.Map.Entry; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -155,9 +154,9 @@ public abstract class BaseComputeServiceLiveTest { @Test(enabled = true, dependsOnMethods = "testCorrectAuthException") public void testImagesCache() throws Exception { - client.getImages(); + client.listImages(); long time = System.currentTimeMillis(); - client.getImages(); + client.listImages(); long duration = System.currentTimeMillis() - time; assert duration < 1000 : String.format("%dms to get images", duration); } @@ -183,7 +182,7 @@ public abstract class BaseComputeServiceLiveTest { template.getOptions().installPrivateKey(keyPair.get("private")).authorizePublicKey( keyPair.get("public")).runScript( buildScript(template.getImage().getOsFamily()).getBytes()); - nodes = Sets.newTreeSet(client.runNodesWithTag(tag, 2, template).values()); + nodes = Sets.newTreeSet(client.runNodesWithTag(tag, 2, template)); assertEquals(nodes.size(), 2); checkNodes(nodes, tag); NodeMetadata node1 = nodes.first(); @@ -210,8 +209,7 @@ public abstract class BaseComputeServiceLiveTest { @Test(enabled = true, dependsOnMethods = "testCreateTwoNodesWithRunScript") public void testCreateAnotherNodeWithANewContextToEnsureSharedMemIsntRequired() throws Exception { initializeContextAndClient(); - TreeSet nodes = Sets.newTreeSet(client.runNodesWithTag(tag, 1, template) - .values()); + TreeSet nodes = Sets.newTreeSet(client.runNodesWithTag(tag, 1, template)); checkNodes(nodes, tag); NodeMetadata node = nodes.first(); this.nodes.add(node); @@ -226,13 +224,13 @@ public abstract class BaseComputeServiceLiveTest { Template simpleTemplate = buildTemplate(client.templateBuilder()); simpleTemplate.getOptions().blockOnPort(22, 120); try { - Map nodes = client.runNodesWithTag(tag, 1, simpleTemplate); - Credentials good = nodes.values().iterator().next().getCredentials(); + Set nodes = client.runNodesWithTag(tag, 1, simpleTemplate); + Credentials good = nodes.iterator().next().getCredentials(); assert good.account != null; try { - Map responses = runScriptWithCreds(tag, simpleTemplate.getImage() - .getOsFamily(), new Credentials(good.account, "romeo")); + Map responses = runScriptWithCreds(tag, simpleTemplate + .getImage().getOsFamily(), new Credentials(good.account, "romeo")); assert false : "shouldn't pass with a bad password\n" + responses; } catch (SshException e) { assert Throwables.getRootCause(e).getMessage().contains("Auth fail") : e; @@ -240,22 +238,22 @@ public abstract class BaseComputeServiceLiveTest { runScriptWithCreds(tag, simpleTemplate.getImage().getOsFamily(), good); - checkNodes(nodes.values(), tag); + checkNodes(nodes, tag); } finally { client.destroyNodesWithTag(tag); } } - private Map runScriptWithCreds(String tag, OsFamily osFamily, - Credentials creds) { + private Map runScriptWithCreds(String tag, OsFamily osFamily, + Credentials creds) throws RunScriptOnNodesException { try { return client.runScriptOnNodesWithTag(tag, buildScript(osFamily).getBytes(), RunScriptOptions.Builder.overrideCredentialsWith(creds)); } catch (SshException e) { if (Throwables.getRootCause(e).getMessage().contains("Auth fail")) { System.err.printf("bad credentials: %s:%s for %s%n", creds.account, creds.key, client - .getNodesWithTag(tag)); + .listNodesWithTag(tag)); } throw e; } @@ -316,7 +314,7 @@ public abstract class BaseComputeServiceLiveTest { @Test(enabled = true, dependsOnMethods = "testCreateAnotherNodeWithANewContextToEnsureSharedMemIsntRequired") public void testGet() throws Exception { Set metadataSet = Sets.newHashSet(Iterables.filter(client - .getNodesWithTag(tag).values(), Predicates.not(new Predicate() { + .listNodesWithTag(tag), Predicates.not(new Predicate() { @Override public boolean apply(NodeMetadata input) { return input.getState() == NodeState.TERMINATED; @@ -352,23 +350,20 @@ public abstract class BaseComputeServiceLiveTest { } public void testListNodes() throws Exception { - for (Entry node : client.getNodes().entrySet()) { - assertEquals(node.getKey(), node.getValue().getId()); - assert node.getValue().getId() != null; - assert node.getValue().getLocation() != null; - assertEquals(node.getValue().getType(), ComputeType.NODE); + for (ComputeMetadata node : client.listNodes()) { + assert node.getId() != null; + assert node.getLocation() != null; + assertEquals(node.getType(), ComputeType.NODE); } } public void testGetNodesWithDetails() throws Exception { - for (Entry node : client.getNodes( - new GetNodesOptions().withDetails()).entrySet()) { - assertEquals(node.getKey(), node.getValue().getId()); - assert node.getValue().getId() != null : node; - assert node.getValue().getLocation() != null : node; - assertEquals(node.getValue().getType(), ComputeType.NODE); - assert node.getValue() instanceof NodeMetadata; - NodeMetadata nodeMetadata = (NodeMetadata) node.getValue(); + for (ComputeMetadata node : client.listNodes(new GetNodesOptions().withDetails())) { + assert node.getId() != null : node; + assert node.getLocation() != null : node; + assertEquals(node.getType(), ComputeType.NODE); + assert node instanceof NodeMetadata; + NodeMetadata nodeMetadata = (NodeMetadata) node; assert nodeMetadata.getId() != null : nodeMetadata; // nullable // assert nodeMetadata.getImage() != null : node; @@ -384,41 +379,39 @@ public abstract class BaseComputeServiceLiveTest { } public void testListImages() throws Exception { - for (Entry image : client.getImages().entrySet()) { - assertEquals(image.getKey(), image.getValue().getId()); - assert image.getValue().getId() != null : image; - // image.getValue().getLocationId() can be null, if it is a location-free image - assertEquals(image.getValue().getType(), ComputeType.IMAGE); + for (Image image : client.listImages()) { + assert image.getId() != null : image; + // image.getLocationId() can be null, if it is a location-free image + assertEquals(image.getType(), ComputeType.IMAGE); } } @Test(groups = { "integration", "live" }) public void testGetAssignableLocations() throws Exception { - for (Entry location : client.getAssignableLocations().entrySet()) { - System.err.printf("location %s%n", location.getValue()); - assertEquals(location.getKey(), location.getValue().getId()); - assert location.getValue().getId() != null : location; - assert location.getValue() != location.getValue().getParent() : location; - assert location.getValue().getScope() != null : location; - switch (location.getValue().getScope()) { + for (Location location : client.listAssignableLocations()) { + System.err.printf("location %s%n", location); + assert location.getId() != null : location; + assert location != location.getParent() : location; + assert location.getScope() != null : location; + switch (location.getScope()) { case PROVIDER: - assertProvider(location.getValue()); + assertProvider(location); break; case REGION: - assertProvider(location.getValue().getParent()); + assertProvider(location.getParent()); break; case ZONE: - Location provider = location.getValue().getParent().getParent(); + Location provider = location.getParent().getParent(); // zone can be a direct descendant of provider if (provider == null) - provider = location.getValue().getParent(); + provider = location.getParent(); assertProvider(provider); break; case HOST: - Location provider2 = location.getValue().getParent().getParent().getParent(); + Location provider2 = location.getParent().getParent().getParent(); // zone can be a direct descendant of provider if (provider2 == null) - provider2 = location.getValue().getParent().getParent(); + provider2 = location.getParent().getParent(); assertProvider(provider2); break; } @@ -431,14 +424,13 @@ public abstract class BaseComputeServiceLiveTest { } public void testListSizes() throws Exception { - for (Entry size : client.getSizes().entrySet()) { - assertEquals(size.getKey(), size.getValue().getId()); - assert size.getValue().getId() != null; - assert size.getValue().getCores() > 0; - assert size.getValue().getDisk() > 0; - assert size.getValue().getRam() > 0; - assert size.getValue().getSupportedArchitectures() != null; - assertEquals(size.getValue().getType(), ComputeType.SIZE); + for (Size size : client.listSizes()) { + assert size.getId() != null; + assert size.getCores() > 0; + assert size.getDisk() > 0; + assert size.getRam() > 0; + assert size.getSupportedArchitectures() != null; + assertEquals(size.getType(), ComputeType.SIZE); } } @@ -480,7 +472,7 @@ public abstract class BaseComputeServiceLiveTest { protected void cleanup() throws InterruptedException, ExecutionException, TimeoutException { if (nodes != null) { client.destroyNodesWithTag(tag); - for (NodeMetadata node : client.getNodesWithTag(tag).values()) { + for (NodeMetadata node : client.listNodesWithTag(tag)) { assert node.getState() == NodeState.TERMINATED : node; } } diff --git a/compute/src/test/java/org/jclouds/compute/internal/TemplateBuilderImplTest.java b/compute/src/test/java/org/jclouds/compute/internal/TemplateBuilderImplTest.java index 6e8a1482b3..7389dfe6d9 100644 --- a/compute/src/test/java/org/jclouds/compute/internal/TemplateBuilderImplTest.java +++ b/compute/src/test/java/org/jclouds/compute/internal/TemplateBuilderImplTest.java @@ -29,7 +29,7 @@ import org.jclouds.domain.LocationScope; import org.jclouds.domain.internal.LocationImpl; import org.testng.annotations.Test; -import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; /** * @@ -40,8 +40,8 @@ public class TemplateBuilderImplTest { @Test public void testImageIdNullsEverythingElse() { - TemplateBuilderImpl template = new TemplateBuilderImpl(ImmutableMap. of(), - ImmutableMap. of(), ImmutableMap. of(), + TemplateBuilderImpl template = new TemplateBuilderImpl(ImmutableSet. of(), + ImmutableSet. of(), ImmutableSet. of(), new LocationImpl(LocationScope.REGION, " id", "description", null)); template.architecture(Architecture.X86_32); template.imageDescriptionMatches("imageDescriptionMatches"); diff --git a/core/src/main/clojure/org/jclouds/core.clj b/core/src/main/clojure/org/jclouds/core.clj index 286156fba1..d7014cb7bd 100644 --- a/core/src/main/clojure/org/jclouds/core.clj +++ b/core/src/main/clojure/org/jclouds/core.clj @@ -57,9 +57,6 @@ Ensure the module is on the classpath. You are maybe missing a dependency on (filter (complement nil?) (map (comp instantiate module-lookup) modules))))) -(defn seq-from-immutable-set [#^ImmutableSet set] - (map #(.getValue %) set)) - (defn dashed [a] (apply str (interpose "-" (map string/lower-case (re-seq #"[A-Z][^A-Z]*" a))))) diff --git a/core/src/main/java/org/jclouds/date/internal/SimpleDateFormatDateService.java b/core/src/main/java/org/jclouds/date/internal/SimpleDateFormatDateService.java index d73e68c9a9..97c4638294 100755 --- a/core/src/main/java/org/jclouds/date/internal/SimpleDateFormatDateService.java +++ b/core/src/main/java/org/jclouds/date/internal/SimpleDateFormatDateService.java @@ -25,7 +25,10 @@ import java.util.Locale; import java.util.SimpleTimeZone; import java.util.regex.Pattern; +import javax.annotation.Resource; + import org.jclouds.date.DateService; +import org.jclouds.logging.Logger; /** * @@ -35,23 +38,26 @@ import org.jclouds.date.DateService; * @author James Murty */ public class SimpleDateFormatDateService implements DateService { + + @Resource + protected Logger logger = Logger.NULL; /* * Use default Java Date/SimpleDateFormat classes for date manipulation, but be *very* careful to * guard against the lack of thread safety. */ - //@GuardedBy("this") + // @GuardedBy("this") private static final SimpleDateFormat iso8601SecondsSimpleDateFormat = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US); - //@GuardedBy("this") + // @GuardedBy("this") private static final SimpleDateFormat iso8601SimpleDateFormat = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US); - //@GuardedBy("this") + // @GuardedBy("this") private static final SimpleDateFormat rfc822SimpleDateFormat = new SimpleDateFormat( "EEE, dd MMM yyyy HH:mm:ss z", Locale.US); - //@GuardedBy("this") + // @GuardedBy("this") private static final SimpleDateFormat cSimpleDateFormat = new SimpleDateFormat( "EEE MMM dd HH:mm:ss '+0000' yyyy", Locale.US); @@ -134,6 +140,8 @@ public class SimpleDateFormatDateService implements DateService { public static final Pattern NANOS_TO_MILLIS_PATTERN = Pattern .compile(".*[0-9][0-9][0-9][0-9][0-9][0-9]"); + public static final Pattern TZ_PATTERN = Pattern.compile(".*[+][0-9][0-9]:[0-9][0-9]"); + private String trimNanosToMillis(String toParse) { if (NANOS_TO_MILLIS_PATTERN.matcher(toParse).matches()) toParse = toParse.substring(0, toParse.length() - 3) + 'Z'; @@ -143,6 +151,10 @@ public class SimpleDateFormatDateService implements DateService { public static final Pattern SECOND_PATTERN = Pattern.compile(".*[0-2][0-9]:00"); private String trimTZ(String toParse) { + if (TZ_PATTERN.matcher(toParse).matches()) { + logger.warn("trimming tz from %s", toParse); + toParse = toParse.substring(0, toParse.length() - 6) + 'Z'; + } if (toParse.length() == 25 && SECOND_PATTERN.matcher(toParse).matches()) toParse = toParse.substring(0, toParse.length() - 6) + 'Z'; return toParse; diff --git a/core/src/main/java/org/jclouds/rest/functions/MapHttp4xxCodesToExceptions.java b/core/src/main/java/org/jclouds/rest/functions/MapHttp4xxCodesToExceptions.java index 3f26730c59..d87234e67c 100644 --- a/core/src/main/java/org/jclouds/rest/functions/MapHttp4xxCodesToExceptions.java +++ b/core/src/main/java/org/jclouds/rest/functions/MapHttp4xxCodesToExceptions.java @@ -38,6 +38,8 @@ public class MapHttp4xxCodesToExceptions implements Function switch (responseException.getResponse().getStatusCode()) { case 401: throw new AuthorizationException(from); + case 403: + throw new AuthorizationException(from); case 404: throw new ResourceNotFoundException(from); } diff --git a/core/src/test/java/org/jclouds/date/DateServiceTest.java b/core/src/test/java/org/jclouds/date/DateServiceTest.java index 56a9b4d282..e9d2cf475d 100755 --- a/core/src/test/java/org/jclouds/date/DateServiceTest.java +++ b/core/src/test/java/org/jclouds/date/DateServiceTest.java @@ -58,15 +58,18 @@ public class DateServiceTest extends PerformanceTest { protected class TestData { public final String iso8601DateString; + public final String iso8601DateStringTz; + public final String iso8601SecondsDateString; public final String rfc822DateString; public final String cDateString; public final Date date; - TestData(String iso8601, String iso8601Seconds, String rfc822, String cDateString, - Date dateTime) { + TestData(String iso8601, String iso8601DateStringTz, String iso8601Seconds, String rfc822, + String cDateString, Date dateTime) { this.iso8601DateString = iso8601; + this.iso8601DateStringTz = iso8601DateStringTz; this.iso8601SecondsDateString = iso8601Seconds; this.rfc822DateString = rfc822; this.cDateString = cDateString; @@ -77,21 +80,21 @@ public class DateServiceTest extends PerformanceTest { public DateServiceTest() { // Constant time test values, each TestData item must contain matching times! testData = new TestData[] { - new TestData("2009-03-12T02:00:07.000Z", "2009-03-12T02:00:07Z", - "Thu, 12 Mar 2009 02:00:07 GMT", "Thu Mar 12 02:00:07 +0000 2009", - new Date(1236823207000l)), - new TestData("2009-03-14T04:00:07.000Z", "2009-03-14T04:00:07Z", - "Sat, 14 Mar 2009 04:00:07 GMT", "Thu Mar 14 04:00:07 +0000 2009", - new Date(1237003207000l)), - new TestData("2009-03-16T06:00:07.000Z", "2009-03-16T06:00:07Z", - "Mon, 16 Mar 2009 06:00:07 GMT", "Thu Mar 16 06:00:07 +0000 2009", - new Date(1237183207000l)), - new TestData("2009-03-18T08:00:07.000Z", "2009-03-18T08:00:07Z", - "Wed, 18 Mar 2009 08:00:07 GMT", "Thu Mar 18 08:00:07 +0000 2009", - new Date(1237363207000l)), - new TestData("2009-03-20T10:00:07.000Z", "2009-03-20T10:00:07Z", - "Fri, 20 Mar 2009 10:00:07 GMT", "Thu Mar 20 10:00:07 +0000 2009", - new Date(1237543207000l)) }; + new TestData("2009-03-12T02:00:07.000Z", "2009-03-12T02:00:07+04:00", + "2009-03-12T02:00:07Z", "Thu, 12 Mar 2009 02:00:07 GMT", + "Thu Mar 12 02:00:07 +0000 2009", new Date(1236823207000l)), + new TestData("2009-03-14T04:00:07.000Z", "2009-03-14T04:00:07Z+04:00", + "2009-03-14T04:00:07Z", "Sat, 14 Mar 2009 04:00:07 GMT", + "Thu Mar 14 04:00:07 +0000 2009", new Date(1237003207000l)), + new TestData("2009-03-16T06:00:07.000Z", "2009-03-16T06:00:07Z+04:00", + "2009-03-16T06:00:07Z", "Mon, 16 Mar 2009 06:00:07 GMT", + "Thu Mar 16 06:00:07 +0000 2009", new Date(1237183207000l)), + new TestData("2009-03-18T08:00:07.000Z", "2009-03-18T08:00:07Z+04:00", + "2009-03-18T08:00:07Z", "Wed, 18 Mar 2009 08:00:07 GMT", + "Thu Mar 18 08:00:07 +0000 2009", new Date(1237363207000l)), + new TestData("2009-03-20T10:00:07.000Z", "2009-03-20T10:00:07Z+04:00", + "2009-03-20T10:00:07Z", "Fri, 20 Mar 2009 10:00:07 GMT", + "Thu Mar 20 10:00:07 +0000 2009", new Date(1237543207000l)) }; } @Test @@ -99,6 +102,11 @@ public class DateServiceTest extends PerformanceTest { Date dsDate = dateService.iso8601DateParse(testData[0].iso8601DateString); assertEquals(dsDate, testData[0].date); } + @Test + public void testIso8601DateParseTz() throws ExecutionException, InterruptedException { + Date dsDate = dateService.iso8601SecondsDateParse(testData[0].iso8601DateStringTz); + assertEquals(dsDate, testData[0].date); + } @Test public void testIso8601SecondsDateParse() throws ExecutionException, InterruptedException { diff --git a/extensions/ssh/jsch/src/main/java/org/jclouds/ssh/jsch/JschSshClient.java b/extensions/ssh/jsch/src/main/java/org/jclouds/ssh/jsch/JschSshClient.java index f108935d93..dfb7a7b776 100644 --- a/extensions/ssh/jsch/src/main/java/org/jclouds/ssh/jsch/JschSshClient.java +++ b/extensions/ssh/jsch/src/main/java/org/jclouds/ssh/jsch/JschSshClient.java @@ -24,6 +24,7 @@ import static com.google.common.base.Preconditions.checkState; import java.io.IOException; import java.io.InputStream; +import java.net.ConnectException; import java.net.InetAddress; import java.net.InetSocketAddress; @@ -40,6 +41,8 @@ import org.jclouds.ssh.SshClient; import org.jclouds.ssh.SshException; import org.jclouds.util.Utils; +import com.google.common.base.Throwables; +import com.google.common.collect.Iterables; import com.google.common.io.Closeables; import com.jcraft.jsch.ChannelExec; import com.jcraft.jsch.ChannelSftp; @@ -75,6 +78,7 @@ public class JschSshClient implements SshClient { private final int port; private final String username; private final String password; + private int sshRetries = 3; @Resource protected Logger logger = Logger.NULL; @@ -177,15 +181,37 @@ public class JschSshClient implements SshClient { java.util.Properties config = new java.util.Properties(); config.put("StrictHostKeyChecking", "no"); session.setConfig(config); - try { - session.connect(); - } catch (JSchException e) { - throw new SshException(String.format("%s@%s:%d: Error connecting to session.", username, - host.getHostAddress(), port), e); + RETRY_LOOP: for (int i = 0; i < sshRetries; i++) { + try { + session.connect(); + break RETRY_LOOP; + } catch (Exception from) { + String rootMessage = Throwables.getRootCause(from).getMessage(); + if (i + 1 == sshRetries) + throw propagate(from); + if (Iterables.size(Iterables.filter(Throwables.getCausalChain(from), + ConnectException.class)) >= 1 + || rootMessage.indexOf("Auth fail") != -1// auth fail sometimes happens in EC2 + || rootMessage.indexOf("invalid data") != -1 + || rootMessage.indexOf("invalid privatekey") != -1) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + throw propagate(e); + } + continue; + } + throw propagate(from); + } } logger.debug("%s@%s:%d: Session connected.", username, host.getHostAddress(), port); } + private SshException propagate(Exception e) { + throw new SshException(String.format("%s@%s:%d: Error connecting to session.", username, host + .getHostAddress(), port), e); + } + @PreDestroy public void disconnect() { if (session != null && session.isConnected()) diff --git a/gogrid/src/main/java/org/jclouds/gogrid/GoGridPropertiesBuilder.java b/gogrid/src/main/java/org/jclouds/gogrid/GoGridPropertiesBuilder.java index de4ff05c68..89711d4794 100644 --- a/gogrid/src/main/java/org/jclouds/gogrid/GoGridPropertiesBuilder.java +++ b/gogrid/src/main/java/org/jclouds/gogrid/GoGridPropertiesBuilder.java @@ -23,14 +23,18 @@ */ package org.jclouds.gogrid; -import org.jclouds.PropertiesBuilder; - import static com.google.common.base.Preconditions.checkNotNull; -import static org.jclouds.gogrid.reference.GoGridConstants.*; +import static org.jclouds.gogrid.reference.GoGridConstants.PROPERTY_GOGRID_DEFAULT_DC; +import static org.jclouds.gogrid.reference.GoGridConstants.PROPERTY_GOGRID_ENDPOINT; +import static org.jclouds.gogrid.reference.GoGridConstants.PROPERTY_GOGRID_PASSWORD; +import static org.jclouds.gogrid.reference.GoGridConstants.PROPERTY_GOGRID_SESSIONINTERVAL; +import static org.jclouds.gogrid.reference.GoGridConstants.PROPERTY_GOGRID_USER; import java.net.URI; import java.util.Properties; +import org.jclouds.PropertiesBuilder; + /** * Builds properties used in GoGrid Clients * @@ -44,7 +48,7 @@ public class GoGridPropertiesBuilder extends PropertiesBuilder { Properties properties = super.defaultProperties(); properties.setProperty(PROPERTY_GOGRID_ENDPOINT, "https://api.gogrid.com/api"); properties.setProperty(PROPERTY_GOGRID_SESSIONINTERVAL, 60 + ""); - + properties.setProperty(PROPERTY_GOGRID_DEFAULT_DC, "SANFRANCISCO"); return properties; } diff --git a/gogrid/src/main/java/org/jclouds/gogrid/compute/config/GoGridComputeServiceContextModule.java b/gogrid/src/main/java/org/jclouds/gogrid/compute/config/GoGridComputeServiceContextModule.java index d41cf3fdf1..594748434a 100755 --- a/gogrid/src/main/java/org/jclouds/gogrid/compute/config/GoGridComputeServiceContextModule.java +++ b/gogrid/src/main/java/org/jclouds/gogrid/compute/config/GoGridComputeServiceContextModule.java @@ -19,6 +19,7 @@ package org.jclouds.gogrid.compute.config; import static org.jclouds.compute.domain.OsFamily.CENTOS; +import static org.jclouds.gogrid.reference.GoGridConstants.PROPERTY_GOGRID_DEFAULT_DC; import java.net.InetAddress; import java.net.UnknownHostException; @@ -82,7 +83,6 @@ import com.google.common.base.Predicates; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; -import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.inject.Provides; import com.google.inject.TypeLiteral; @@ -279,13 +279,21 @@ public class GoGridComputeServiceContextModule extends GoGridContextModule { @Provides @Singleton - Location getDefaultLocation(Map locations) { - return locations.get("SANFRANCISCO"); + Location getDefaultLocation(@Named(PROPERTY_GOGRID_DEFAULT_DC) final String defaultDC, + Set locations) { + return Iterables.find(locations, new Predicate() { + + @Override + public boolean apply(Location input) { + return input.getId().equals(defaultDC); + } + + }); } @Provides @Singleton - Map getDefaultLocations(GoGridClient sync, LogHolder holder, + Set getDefaultLocations(GoGridClient sync, LogHolder holder, Function indexer) { final Set locations = Sets.newHashSet(); holder.logger.debug(">> providing locations"); @@ -293,13 +301,7 @@ public class GoGridComputeServiceContextModule extends GoGridContextModule { locations.add(new LocationImpl(LocationScope.ZONE, "SANFRANCISCO", "San Francisco, CA", parent)); holder.logger.debug("<< locations(%d)", locations.size()); - return Maps.uniqueIndex(locations, new Function() { - - @Override - public String apply(Location from) { - return from.getId(); - } - }); + return locations; } @Provides @@ -315,10 +317,9 @@ public class GoGridComputeServiceContextModule extends GoGridContextModule { @Provides @Singleton - protected Map provideSizes(GoGridClient sync, - Map images, LogHolder holder, - Function indexer) throws InterruptedException, - TimeoutException, ExecutionException { + protected Set provideSizes(GoGridClient sync, Set images, + LogHolder holder, Function indexer) + throws InterruptedException, TimeoutException, ExecutionException { final Set sizes = Sets.newHashSet(); holder.logger.debug(">> providing sizes"); @@ -333,7 +334,7 @@ public class GoGridComputeServiceContextModule extends GoGridContextModule { sizes.add(new SizeImpl("5", "5", null, null, ImmutableMap. of(), 6, 8192, 462, ImmutableSet. of(Architecture.X86_32, Architecture.X86_64))); holder.logger.debug("<< sizes(%d)", sizes.size()); - return Maps.uniqueIndex(sizes, indexer); + return sizes; } private static class LogHolder { @@ -346,7 +347,7 @@ public class GoGridComputeServiceContextModule extends GoGridContextModule { @Provides @Singleton - protected Map provideImages(final GoGridClient sync, LogHolder holder, + protected Set provideImages(final GoGridClient sync, LogHolder holder, Function indexer, Location location, PopulateDefaultLoginCredentialsForImageStrategy authenticator) throws InterruptedException, ExecutionException, TimeoutException { @@ -375,6 +376,6 @@ public class GoGridComputeServiceContextModule extends GoGridContextModule { osDescription, arch, defaultCredentials)); } holder.logger.debug("<< images(%d)", images.size()); - return Maps.uniqueIndex(images, indexer); + return images; } } diff --git a/gogrid/src/main/java/org/jclouds/gogrid/compute/functions/ServerToNodeMetadata.java b/gogrid/src/main/java/org/jclouds/gogrid/compute/functions/ServerToNodeMetadata.java index 1a8e511ea4..4c3f170672 100644 --- a/gogrid/src/main/java/org/jclouds/gogrid/compute/functions/ServerToNodeMetadata.java +++ b/gogrid/src/main/java/org/jclouds/gogrid/compute/functions/ServerToNodeMetadata.java @@ -22,10 +22,12 @@ import static com.google.common.base.Preconditions.checkNotNull; import java.net.InetAddress; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.annotation.Resource; import javax.inject.Inject; import javax.inject.Singleton; @@ -37,11 +39,14 @@ import org.jclouds.domain.Credentials; import org.jclouds.domain.Location; import org.jclouds.gogrid.domain.Server; import org.jclouds.gogrid.services.GridServerClient; +import org.jclouds.logging.Logger; import com.google.common.base.Function; +import com.google.common.base.Predicate; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; /** * @author Oleksiy Yarmula @@ -50,14 +55,33 @@ import com.google.common.collect.ImmutableSet; public class ServerToNodeMetadata implements Function { public static final Pattern ALL_BEFORE_HYPHEN_HEX = Pattern.compile("([^-]+)-[0-9a-f]+"); + @Resource + protected Logger logger = Logger.NULL; private final Map serverStateToNodeState; private final GridServerClient client; private final Location location; - private final Map images; + private final Set images; + + private static class FindImageForServer implements Predicate { + private final Location location; + private final Server instance; + + private FindImageForServer(Location location, Server instance) { + this.location = location; + this.instance = instance; + } + + @Override + public boolean apply(Image input) { + return input.getId().equals(instance.getImage().getId() + "") + && (input.getLocation() == null || input.getLocation().equals(location) || input + .getLocation().equals(location.getParent())); + } + } @Inject ServerToNodeMetadata(Map serverStateToNodeState, GridServerClient client, - Map images, Location location) { + Set images, Location location) { this.serverStateToNodeState = checkNotNull(serverStateToNodeState, "serverStateToNodeState"); this.client = checkNotNull(client, "client"); this.images = checkNotNull(images, "images"); @@ -71,8 +95,16 @@ public class ServerToNodeMetadata implements Function { Set ipSet = ImmutableSet.of(from.getIp().getIp()); NodeState state = serverStateToNodeState.get(from.getState().getName()); Credentials creds = client.getServerCredentialsList().get(from.getName()); + Image image = null; + try { + image = Iterables.find(images, new FindImageForServer(location, from)); + } catch (NoSuchElementException e) { + logger + .warn("could not find a matching image for server %s in location %s", from, + location); + } return new NodeMetadataImpl(from.getId() + "", from.getName(), location, null, ImmutableMap - . of(), tag, images.get(from.getImage().getId() + ""), state, ipSet, - ImmutableList. of(), ImmutableMap. of(), creds); + . of(), tag, image, state, ipSet, ImmutableList. of(), + ImmutableMap. of(), creds); } } \ No newline at end of file diff --git a/gogrid/src/main/java/org/jclouds/gogrid/reference/GoGridConstants.java b/gogrid/src/main/java/org/jclouds/gogrid/reference/GoGridConstants.java index 0e74b4ed5d..852156d59d 100644 --- a/gogrid/src/main/java/org/jclouds/gogrid/reference/GoGridConstants.java +++ b/gogrid/src/main/java/org/jclouds/gogrid/reference/GoGridConstants.java @@ -25,16 +25,17 @@ package org.jclouds.gogrid.reference; /** * Configuration properties and constants used in GoGrid connections. - * + * * @author Adrian Cole */ public interface GoGridConstants { - public static final String PROPERTY_GOGRID_ENDPOINT = "jclouds.gogrid.endpoint"; - public static final String PROPERTY_GOGRID_USER = "jclouds.gogrid.api.key"; - public static final String PROPERTY_GOGRID_PASSWORD = "jclouds.gogrid.secret"; - /** - * how long do we wait before obtaining a new timestamp for requests. - */ - public static final String PROPERTY_GOGRID_SESSIONINTERVAL = "jclouds.gogrid.sessioninterval"; + public static final String PROPERTY_GOGRID_ENDPOINT = "jclouds.gogrid.endpoint"; + public static final String PROPERTY_GOGRID_USER = "jclouds.gogrid.api.key"; + public static final String PROPERTY_GOGRID_PASSWORD = "jclouds.gogrid.secret"; + /** + * how long do we wait before obtaining a new timestamp for requests. + */ + public static final String PROPERTY_GOGRID_SESSIONINTERVAL = "jclouds.gogrid.sessioninterval"; + public static final String PROPERTY_GOGRID_DEFAULT_DC = "jclouds.gogrid.defaultdc"; } diff --git a/gogrid/src/test/java/org/jclouds/gogrid/compute/functions/ServerToNodeMetadataTest.java b/gogrid/src/test/java/org/jclouds/gogrid/compute/functions/ServerToNodeMetadataTest.java index e0bb384599..9656bf70ac 100644 --- a/gogrid/src/test/java/org/jclouds/gogrid/compute/functions/ServerToNodeMetadataTest.java +++ b/gogrid/src/test/java/org/jclouds/gogrid/compute/functions/ServerToNodeMetadataTest.java @@ -9,6 +9,7 @@ import static org.testng.Assert.assertEquals; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Map; +import java.util.Set; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeState; @@ -23,6 +24,8 @@ import org.jclouds.gogrid.domain.ServerImage; import org.jclouds.gogrid.services.GridServerClient; import org.testng.annotations.Test; +import com.google.common.collect.ImmutableSet; + /** * @author Adrian Cole */ @@ -34,7 +37,9 @@ public class ServerToNodeMetadataTest { public void testApplySetsTagFromNameAndCredentialsFromName() throws UnknownHostException { GridServerClient client = createMock(GridServerClient.class); Map serverStateToNodeState = createMock(Map.class); - Map images = createMock(Map.class); + org.jclouds.compute.domain.Image jcImage = createMock(org.jclouds.compute.domain.Image.class); + + Set images = ImmutableSet.of(jcImage); Server server = createMock(Server.class); expect(server.getId()).andReturn(1000l).atLeastOnce(); @@ -54,16 +59,15 @@ public class ServerToNodeMetadataTest { ServerImage image = createMock(ServerImage.class); expect(server.getImage()).andReturn(image).atLeastOnce(); expect(image.getId()).andReturn(2000l).atLeastOnce(); - - org.jclouds.compute.domain.Image jcImage = createMock(org.jclouds.compute.domain.Image.class); - expect(images.get("2000")).andReturn(jcImage); + expect(jcImage.getId()).andReturn("2000").atLeastOnce(); + expect(jcImage.getLocation()).andReturn(location).atLeastOnce(); replay(client); replay(serverStateToNodeState); replay(server); replay(image); + replay(jcImage); replay(credentialsMap); - replay(images); ServerToNodeMetadata parser = new ServerToNodeMetadata(serverStateToNodeState, client, images, location); @@ -79,7 +83,8 @@ public class ServerToNodeMetadataTest { verify(image); verify(credentialsMap); verify(server); - verify(images); + verify(jcImage); + } } diff --git a/rackspace/src/main/java/org/jclouds/rackspace/cloudfiles/blobstore/CloudFilesAsyncBlobStore.java b/rackspace/src/main/java/org/jclouds/rackspace/cloudfiles/blobstore/CloudFilesAsyncBlobStore.java index 4fdca1c3bd..3868a9a56a 100644 --- a/rackspace/src/main/java/org/jclouds/rackspace/cloudfiles/blobstore/CloudFilesAsyncBlobStore.java +++ b/rackspace/src/main/java/org/jclouds/rackspace/cloudfiles/blobstore/CloudFilesAsyncBlobStore.java @@ -21,7 +21,6 @@ package org.jclouds.rackspace.cloudfiles.blobstore; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.util.concurrent.Futures.compose; -import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutorService; @@ -81,7 +80,7 @@ public class CloudFilesAsyncBlobStore extends BaseAsyncBlobStore { @Inject CloudFilesAsyncBlobStore(BlobStoreContext context, BlobStoreUtils blobUtils, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, - Location defaultLocation, Map locations, + Location defaultLocation, Set locations, CloudFilesClient sync, CloudFilesAsyncClient async, ContainerToResourceMetadata container2ResourceMd, BlobStoreListContainerOptionsToListContainerOptions container2ContainerListOptions, diff --git a/rackspace/src/main/java/org/jclouds/rackspace/cloudfiles/blobstore/CloudFilesBlobStore.java b/rackspace/src/main/java/org/jclouds/rackspace/cloudfiles/blobstore/CloudFilesBlobStore.java index 14ba6ffe43..9ea106ca36 100644 --- a/rackspace/src/main/java/org/jclouds/rackspace/cloudfiles/blobstore/CloudFilesBlobStore.java +++ b/rackspace/src/main/java/org/jclouds/rackspace/cloudfiles/blobstore/CloudFilesBlobStore.java @@ -20,7 +20,6 @@ package org.jclouds.rackspace.cloudfiles.blobstore; import static com.google.common.base.Preconditions.checkNotNull; -import java.util.Map; import java.util.Set; import javax.inject.Inject; @@ -70,7 +69,7 @@ public class CloudFilesBlobStore extends BaseBlobStore { @Inject CloudFilesBlobStore(BlobStoreContext context, BlobStoreUtils blobUtils, - Location defaultLocation, Map locations, + Location defaultLocation, Set locations, CloudFilesClient sync, ContainerToResourceMetadata container2ResourceMd, BlobStoreListContainerOptionsToListContainerOptions container2ContainerListOptions, ContainerToResourceList container2ResourceList, ObjectToBlob object2Blob, diff --git a/rackspace/src/main/java/org/jclouds/rackspace/cloudservers/compute/config/CloudServersComputeServiceContextModule.java b/rackspace/src/main/java/org/jclouds/rackspace/cloudservers/compute/config/CloudServersComputeServiceContextModule.java index a991750315..cbdc47b704 100755 --- a/rackspace/src/main/java/org/jclouds/rackspace/cloudservers/compute/config/CloudServersComputeServiceContextModule.java +++ b/rackspace/src/main/java/org/jclouds/rackspace/cloudservers/compute/config/CloudServersComputeServiceContextModule.java @@ -87,7 +87,6 @@ import com.google.common.base.Predicates; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; -import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.inject.Provides; import com.google.inject.TypeLiteral; @@ -303,8 +302,8 @@ public class CloudServersComputeServiceContextModule extends CloudServersContext @Provides @Singleton - protected Map provideSizes(CloudServersClient sync, - Map images, Location location, LogHolder holder, + protected Set provideSizes(CloudServersClient sync, Set images, + Location location, LogHolder holder, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, Function indexer) throws InterruptedException, TimeoutException, ExecutionException { @@ -316,7 +315,7 @@ public class CloudServersComputeServiceContextModule extends CloudServersContext ImmutableSet. of(Architecture.X86_32, Architecture.X86_64))); } holder.logger.debug("<< sizes(%d)", sizes.size()); - return Maps.uniqueIndex(sizes, indexer); + return sizes; } private static class LogHolder { @@ -329,8 +328,8 @@ public class CloudServersComputeServiceContextModule extends CloudServersContext @Provides @Singleton - protected Map provideImages(final CloudServersClient sync, - Location location, LogHolder holder, Function indexer) + protected Set provideImages(final CloudServersClient sync, Location location, + LogHolder holder, Function indexer) throws InterruptedException, ExecutionException, TimeoutException { final Set images = Sets.newHashSet(); holder.logger.debug(">> providing images"); @@ -358,6 +357,6 @@ public class CloudServersComputeServiceContextModule extends CloudServersContext new Credentials("root", null))); } holder.logger.debug("<< images(%d)", images.size()); - return Maps.uniqueIndex(images, indexer); + return images; } } diff --git a/rackspace/src/main/java/org/jclouds/rackspace/cloudservers/compute/functions/ServerToNodeMetadata.java b/rackspace/src/main/java/org/jclouds/rackspace/cloudservers/compute/functions/ServerToNodeMetadata.java index 1e05350fb7..4e6a9e5692 100644 --- a/rackspace/src/main/java/org/jclouds/rackspace/cloudservers/compute/functions/ServerToNodeMetadata.java +++ b/rackspace/src/main/java/org/jclouds/rackspace/cloudservers/compute/functions/ServerToNodeMetadata.java @@ -21,9 +21,12 @@ package org.jclouds.rackspace.cloudservers.compute.functions; import static com.google.common.base.Preconditions.checkNotNull; import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.annotation.Resource; import javax.inject.Inject; import org.jclouds.compute.domain.Image; @@ -33,11 +36,14 @@ import org.jclouds.compute.domain.internal.NodeMetadataImpl; import org.jclouds.domain.Location; import org.jclouds.domain.LocationScope; import org.jclouds.domain.internal.LocationImpl; +import org.jclouds.logging.Logger; import org.jclouds.rackspace.cloudservers.domain.Server; import org.jclouds.rackspace.cloudservers.domain.ServerStatus; import com.google.common.base.Function; +import com.google.common.base.Predicate; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; /** * @author Adrian Cole @@ -47,11 +53,31 @@ public class ServerToNodeMetadata implements Function { .compile("[^-]+-([^-]+)-[0-9a-f]+"); private final Location location; private final Map serverToNodeState; - private final Map images; + private final Set images; + + @Resource + protected Logger logger = Logger.NULL; + + private static class FindImageForServer implements Predicate { + private final Location location; + private final Server instance; + + private FindImageForServer(Location location, Server instance) { + this.location = location; + this.instance = instance; + } + + @Override + public boolean apply(Image input) { + return input.getId().equals(instance.getImageId() + "") + && (input.getLocation() == null || input.getLocation().equals( + location.getParent())); + } + } @Inject ServerToNodeMetadata(Map serverStateToNodeState, - Map images, Location location) { + Set images, Location location) { this.serverToNodeState = checkNotNull(serverStateToNodeState, "serverStateToNodeState"); this.images = checkNotNull(images, "images"); this.location = checkNotNull(location, "location"); @@ -62,10 +88,19 @@ public class ServerToNodeMetadata implements Function { Matcher matcher = SECOND_FIELD_DELIMETED_BY_HYPHEN_ENDING_IN_HYPHEN_HEX.matcher(from .getName()); final String tag = matcher.find() ? matcher.group(1) : null; - return new NodeMetadataImpl(from.getId() + "", from.getName(), new LocationImpl( - LocationScope.HOST, from.getHostId(), from.getHostId(), location), null, from - .getMetadata(), tag, images.get(from.getImageId().toString()), serverToNodeState - .get(from.getStatus()), from.getAddresses().getPublicAddresses(), from - .getAddresses().getPrivateAddresses(), ImmutableMap. of(), null); + Location host = new LocationImpl(LocationScope.HOST, from.getHostId(), from.getHostId(), + location); + Image image = null; + try { + image = Iterables.find(images, new FindImageForServer(host, from)); + } catch (NoSuchElementException e) { + logger + .warn("could not find a matching image for server %s in location %s", from, + location); + } + return new NodeMetadataImpl(from.getId() + "", from.getName(), host, null, + from.getMetadata(), tag, image, serverToNodeState.get(from.getStatus()), from + .getAddresses().getPublicAddresses(), from.getAddresses() + .getPrivateAddresses(), ImmutableMap. of(), null); } } \ No newline at end of file diff --git a/rackspace/src/main/java/org/jclouds/rackspace/config/RackspaceLocationsModule.java b/rackspace/src/main/java/org/jclouds/rackspace/config/RackspaceLocationsModule.java index 69c26f424f..99f76667a2 100644 --- a/rackspace/src/main/java/org/jclouds/rackspace/config/RackspaceLocationsModule.java +++ b/rackspace/src/main/java/org/jclouds/rackspace/config/RackspaceLocationsModule.java @@ -18,7 +18,7 @@ */ package org.jclouds.rackspace.config; -import java.util.Map; +import java.util.Set; import javax.inject.Singleton; @@ -27,7 +27,7 @@ import org.jclouds.domain.LocationScope; import org.jclouds.domain.internal.LocationImpl; import org.jclouds.http.RequiresHttp; -import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import com.google.inject.AbstractModule; import com.google.inject.Provides; @@ -57,7 +57,7 @@ public class RackspaceLocationsModule extends AbstractModule { @Provides @Singleton - Map provideLocations(Location location) { - return ImmutableMap.of(location.getId(), location); + Set provideLocations(Location location) { + return ImmutableSet.of(location); } } \ No newline at end of file diff --git a/rackspace/src/test/java/org/jclouds/rackspace/cloudservers/compute/functions/ServerToNodeMetadataTest.java b/rackspace/src/test/java/org/jclouds/rackspace/cloudservers/compute/functions/ServerToNodeMetadataTest.java index 2b1b89c724..0689d8990d 100644 --- a/rackspace/src/test/java/org/jclouds/rackspace/cloudservers/compute/functions/ServerToNodeMetadataTest.java +++ b/rackspace/src/test/java/org/jclouds/rackspace/cloudservers/compute/functions/ServerToNodeMetadataTest.java @@ -34,7 +34,9 @@ public class ServerToNodeMetadataTest { @Test public void testApplySetsTagFromNameAndSetsMetadata() throws UnknownHostException { Map serverStateToNodeState = createMock(Map.class); - Map images = createMock(Map.class); + org.jclouds.compute.domain.Image jcImage = createMock(org.jclouds.compute.domain.Image.class); + + Set images = ImmutableSet.of(jcImage); Server server = createMock(Server.class); expect(server.getId()).andReturn(10000).atLeastOnce(); @@ -60,14 +62,13 @@ public class ServerToNodeMetadataTest { expect(addresses.getPrivateAddresses()).andReturn(privateAddresses); expect(server.getImageId()).andReturn(2000).atLeastOnce(); - - org.jclouds.compute.domain.Image jcImage = createMock(org.jclouds.compute.domain.Image.class); - expect(images.get("2000")).andReturn(jcImage); + expect(jcImage.getId()).andReturn("2000").atLeastOnce(); + expect(jcImage.getLocation()).andReturn(provider).atLeastOnce(); replay(addresses); + replay(jcImage); replay(serverStateToNodeState); replay(server); - replay(images); ServerToNodeMetadata parser = new ServerToNodeMetadata(serverStateToNodeState, images, provider); @@ -85,7 +86,7 @@ public class ServerToNodeMetadataTest { verify(addresses); verify(serverStateToNodeState); verify(server); - verify(images); + verify(jcImage); } } diff --git a/rimuhosting/src/main/java/org/jclouds/rimuhosting/miro/RimuHostingPropertiesBuilder.java b/rimuhosting/src/main/java/org/jclouds/rimuhosting/miro/RimuHostingPropertiesBuilder.java index 7861b00ef3..1d65d710aa 100644 --- a/rimuhosting/src/main/java/org/jclouds/rimuhosting/miro/RimuHostingPropertiesBuilder.java +++ b/rimuhosting/src/main/java/org/jclouds/rimuhosting/miro/RimuHostingPropertiesBuilder.java @@ -20,6 +20,7 @@ package org.jclouds.rimuhosting.miro; import static com.google.common.base.Preconditions.checkNotNull; import static org.jclouds.rimuhosting.miro.reference.RimuHostingConstants.PROPERTY_RIMUHOSTING_APIKEY; +import static org.jclouds.rimuhosting.miro.reference.RimuHostingConstants.PROPERTY_RIMUHOSTING_DEFAULT_DC; import static org.jclouds.rimuhosting.miro.reference.RimuHostingConstants.PROPERTY_RIMUHOSTING_ENDPOINT; import java.net.URI; @@ -37,6 +38,7 @@ public class RimuHostingPropertiesBuilder extends PropertiesBuilder { protected Properties defaultProperties() { Properties properties = super.defaultProperties(); properties.setProperty(PROPERTY_RIMUHOSTING_ENDPOINT, "https://rimuhosting.com/r"); + properties.setProperty(PROPERTY_RIMUHOSTING_DEFAULT_DC, "DCDALLAS"); return properties; } diff --git a/rimuhosting/src/main/java/org/jclouds/rimuhosting/miro/compute/config/RimuHostingComputeServiceContextModule.java b/rimuhosting/src/main/java/org/jclouds/rimuhosting/miro/compute/config/RimuHostingComputeServiceContextModule.java index 6710d21f95..376a767313 100755 --- a/rimuhosting/src/main/java/org/jclouds/rimuhosting/miro/compute/config/RimuHostingComputeServiceContextModule.java +++ b/rimuhosting/src/main/java/org/jclouds/rimuhosting/miro/compute/config/RimuHostingComputeServiceContextModule.java @@ -20,10 +20,12 @@ package org.jclouds.rimuhosting.miro.compute.config; import static com.google.common.base.Preconditions.checkNotNull; import static org.jclouds.compute.domain.OsFamily.UBUNTU; +import static org.jclouds.rimuhosting.miro.reference.RimuHostingConstants.PROPERTY_RIMUHOSTING_DEFAULT_DC; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; @@ -85,7 +87,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; -import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.inject.Provides; import com.google.inject.TypeLiteral; @@ -259,17 +260,37 @@ public class RimuHostingComputeServiceContextModule extends RimuHostingContextMo @Singleton private static class ServerToNodeMetadata implements Function { + + @Resource + protected Logger logger = Logger.NULL; private final Function> getPublicAddresses; private final Map runningStateToNodeState; - private final Map images; + private final Set images; @SuppressWarnings("unused") - private final Map locations; + private final Set locations; + + private static class FindImageForServer implements Predicate { + private final Location location; + private final Server instance; + + private FindImageForServer(Location location, Server instance) { + this.location = location; + this.instance = instance; + } + + @Override + public boolean apply(Image input) { + return input.getId().equals(instance.getImageId()) + && (input.getLocation() == null || input.getLocation().equals(location) || input + .getLocation().equals(location.getParent())); + } + } @SuppressWarnings("unused") @Inject ServerToNodeMetadata(Function> getPublicAddresses, - Map runningStateToNodeState, - Map images, Map locations) { + Map runningStateToNodeState, Set images, + Set locations) { this.getPublicAddresses = checkNotNull(getPublicAddresses, "serverStateToNodeState"); this.runningStateToNodeState = checkNotNull(runningStateToNodeState, "serverStateToNodeState"); @@ -284,10 +305,18 @@ public class RimuHostingComputeServiceContextModule extends RimuHostingContextMo .getLocation().getName(), null); String tag = from.getName().replaceAll("-[0-9]+", ""); Credentials creds = null; + + Image image = null; + try { + image = Iterables.find(images, new FindImageForServer(location, from)); + } catch (NoSuchElementException e) { + logger.warn("could not find a matching image for server %s in location %s", from, + location); + } NodeState state = runningStateToNodeState.get(from.getState()); return new NodeMetadataImpl(from.getId() + "", from.getName(), location, null, - ImmutableMap. of(), tag, images.get(from.getImageId()), state, - getPublicAddresses.apply(from), ImmutableList. of(), ImmutableMap + ImmutableMap. of(), tag, image, state, getPublicAddresses + .apply(from), ImmutableList. of(), ImmutableMap . of(), creds); } @@ -333,13 +362,21 @@ public class RimuHostingComputeServiceContextModule extends RimuHostingContextMo @Provides @Singleton - Location getDefaultLocation(Map locations) { - return locations.get("DCDALLAS"); + Location getDefaultLocation(@Named(PROPERTY_RIMUHOSTING_DEFAULT_DC) final String defaultDC, + Set locations) { + return Iterables.find(locations, new Predicate() { + + @Override + public boolean apply(Location input) { + return input.getId().equals(defaultDC); + } + + }); } @Provides @Singleton - Map getDefaultLocations(RimuHostingClient sync, LogHolder holder, + Set getDefaultLocations(RimuHostingClient sync, LogHolder holder, Function indexer) { final Set locations = Sets.newHashSet(); holder.logger.debug(">> providing locations"); @@ -353,13 +390,7 @@ public class RimuHostingComputeServiceContextModule extends RimuHostingContextMo } } holder.logger.debug("<< locations(%d)", locations.size()); - return Maps.uniqueIndex(locations, new Function() { - - @Override - public String apply(Location from) { - return from.getId(); - } - }); + return locations; } @Provides @@ -375,25 +406,33 @@ public class RimuHostingComputeServiceContextModule extends RimuHostingContextMo @Provides @Singleton - protected Map provideSizes(RimuHostingClient sync, - Map images, Map locations, - LogHolder holder, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService userExecutor, + protected Set provideSizes(RimuHostingClient sync, Set images, + Set locations, LogHolder holder, + @Named(Constants.PROPERTY_USER_THREADS) ExecutorService userExecutor, Function indexer) throws InterruptedException, TimeoutException, ExecutionException { final Set sizes = Sets.newHashSet(); holder.logger.debug(">> providing sizes"); for (final PricingPlan from : sync.getPricingPlanList()) { try { - sizes.add(new SizeImpl(from.getId(), from.getId(), locations.get(from.getDataCenter() - .getId()), null, ImmutableMap. of(), 1, from.getRam(), from - .getDiskSize(), ImmutableSet. of(Architecture.X86_32, - Architecture.X86_64))); + + final Location location = Iterables.find(locations, new Predicate() { + + @Override + public boolean apply(Location input) { + return input.getId().equals(from.getDataCenter().getId()); + } + + }); + sizes.add(new SizeImpl(from.getId(), from.getId(), location, null, ImmutableMap + . of(), 1, from.getRam(), from.getDiskSize(), ImmutableSet + . of(Architecture.X86_32, Architecture.X86_64))); } catch (NullPointerException e) { holder.logger.warn("datacenter not present in " + from.getId()); } } holder.logger.debug("<< sizes(%d)", sizes.size()); - return Maps.uniqueIndex(sizes, indexer); + return sizes; } private static class LogHolder { @@ -406,9 +445,9 @@ public class RimuHostingComputeServiceContextModule extends RimuHostingContextMo @Provides @Singleton - protected Map provideImages(final RimuHostingClient sync, - LogHolder holder, Function indexer) - throws InterruptedException, ExecutionException, TimeoutException { + protected Set provideImages(final RimuHostingClient sync, LogHolder holder, + Function indexer) throws InterruptedException, + ExecutionException, TimeoutException { final Set images = Sets.newHashSet(); holder.logger.debug(">> providing images"); for (final org.jclouds.rimuhosting.miro.domain.Image from : sync.getImageList()) { @@ -434,7 +473,7 @@ public class RimuHostingComputeServiceContextModule extends RimuHostingContextMo new Credentials("root", null))); } holder.logger.debug("<< images(%d)", images.size()); - return Maps.uniqueIndex(images, indexer); + return images; } } diff --git a/rimuhosting/src/main/java/org/jclouds/rimuhosting/miro/reference/RimuHostingConstants.java b/rimuhosting/src/main/java/org/jclouds/rimuhosting/miro/reference/RimuHostingConstants.java index 655943e4e3..094113516a 100644 --- a/rimuhosting/src/main/java/org/jclouds/rimuhosting/miro/reference/RimuHostingConstants.java +++ b/rimuhosting/src/main/java/org/jclouds/rimuhosting/miro/reference/RimuHostingConstants.java @@ -26,4 +26,6 @@ package org.jclouds.rimuhosting.miro.reference; public interface RimuHostingConstants { public static final String PROPERTY_RIMUHOSTING_ENDPOINT = "jclouds.rimuhosting.endpoint"; public static final String PROPERTY_RIMUHOSTING_APIKEY = "jclouds.rimuhosting.password"; + public static final String PROPERTY_RIMUHOSTING_DEFAULT_DC = "jclouds.rimuhosting.defaultdc"; + } diff --git a/tools/antcontrib/src/main/java/org/jclouds/tools/ant/taskdefs/compute/ComputeTask.java b/tools/antcontrib/src/main/java/org/jclouds/tools/ant/taskdefs/compute/ComputeTask.java index 3971315f53..6a2c02a35e 100644 --- a/tools/antcontrib/src/main/java/org/jclouds/tools/ant/taskdefs/compute/ComputeTask.java +++ b/tools/antcontrib/src/main/java/org/jclouds/tools/ant/taskdefs/compute/ComputeTask.java @@ -34,6 +34,7 @@ import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.jclouds.compute.ComputeService; import org.jclouds.compute.ComputeServiceContext; +import org.jclouds.compute.RunNodesException; import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.NodeMetadata; @@ -90,14 +91,19 @@ public class ComputeTask extends Task { for (String action : Splitter.on(',').split(actions)) { Action act = Action.valueOf(CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_UNDERSCORE, action)); - invokeActionOnService(act, context.getComputeService()); + try { + invokeActionOnService(act, context.getComputeService()); + } catch (RunNodesException e) { + throw new BuildException(e); + } } } finally { context.close(); } } - private void invokeActionOnService(Action action, ComputeService computeService) { + private void invokeActionOnService(Action action, ComputeService computeService) + throws RunNodesException { switch (action) { case CREATE: case GET: @@ -140,7 +146,7 @@ public class ComputeTask extends Task { private void listDetails(ComputeService computeService) { log("list details"); - for (ComputeMetadata node : computeService.getNodes().values()) {// TODO + for (ComputeMetadata node : computeService.listNodes()) {// TODO // parallel logDetails(computeService, node); } @@ -148,7 +154,7 @@ public class ComputeTask extends Task { private void listImages(ComputeService computeService) { log("list images"); - for (Image image : computeService.getImages().values()) {// TODO + for (Image image : computeService.listImages()) {// TODO log(String .format( " image location=%s, id=%s, name=%s, version=%s, arch=%s, osfam=%s, osdesc=%s, desc=%s", @@ -160,7 +166,7 @@ public class ComputeTask extends Task { private void listSizes(ComputeService computeService) { log("list sizes"); - for (Size size : computeService.getSizes().values()) {// TODO + for (Size size : computeService.listSizes()) {// TODO log(String.format(" size id=%s, cores=%s, ram=%s, disk=%s", size.getId(), size .getCores(), size.getRam(), size.getDisk())); } @@ -168,7 +174,7 @@ public class ComputeTask extends Task { private void listLocations(ComputeService computeService) { log("list locations"); - for (Location location : computeService.getAssignableLocations().values()) {// TODO + for (Location location : computeService.listAssignableLocations()) {// TODO log(String.format(" location id=%s, scope=%s, description=%s, parent=%s", location .getId(), location.getScope(), location.getDescription(), location.getParent())); } @@ -176,13 +182,13 @@ public class ComputeTask extends Task { private void list(ComputeService computeService) { log("list"); - for (ComputeMetadata node : computeService.getNodes().values()) { + for (ComputeMetadata node : computeService.listNodes()) { log(String.format(" location=%s, id=%s, tag=%s", node.getLocation(), node.getId(), node .getName())); } } - private void create(ComputeService computeService) { + private void create(ComputeService computeService) throws RunNodesException { String tag = nodeElement.getTag(); log(String.format("create tag: %s, count: %d, size: %s, os: %s", tag, nodeElement.getCount(), @@ -191,7 +197,7 @@ public class ComputeTask extends Task { Template template = createTemplateFromElement(nodeElement, computeService); for (NodeMetadata createdNode : computeService.runNodesWithTag(tag, nodeElement.getCount(), - template).values()) { + template)) { logDetails(computeService, createdNode); addNodeDetailsAsProjectProperties(createdNode); } @@ -218,7 +224,7 @@ public class ComputeTask extends Task { private void get(ComputeService computeService) { log(String.format("get tag: %s", nodeElement.getTag())); - for (ComputeMetadata node : computeService.getNodesWithTag(nodeElement.getTag()).values()) { + for (ComputeMetadata node : computeService.listNodesWithTag(nodeElement.getTag())) { logDetails(computeService, node); } } diff --git a/vcloud/bluelock/src/test/java/org/jclouds/vcloud/bluelock/compute/BlueLockVCloudComputeServiceLiveTest.java b/vcloud/bluelock/src/test/java/org/jclouds/vcloud/bluelock/compute/BlueLockVCloudComputeServiceLiveTest.java index 7d3bf619d6..2f1f161652 100644 --- a/vcloud/bluelock/src/test/java/org/jclouds/vcloud/bluelock/compute/BlueLockVCloudComputeServiceLiveTest.java +++ b/vcloud/bluelock/src/test/java/org/jclouds/vcloud/bluelock/compute/BlueLockVCloudComputeServiceLiveTest.java @@ -22,6 +22,7 @@ package org.jclouds.vcloud.bluelock.compute; import static org.testng.Assert.assertEquals; import java.util.Map; +import java.util.Set; import org.jclouds.compute.domain.Architecture; import org.jclouds.compute.domain.Image; @@ -54,7 +55,7 @@ public class BlueLockVCloudComputeServiceLiveTest extends VCloudComputeServiceLi @Override public void testListImages() throws Exception { super.testListImages(); - Map images = client.getImages(); + Set images = client.listImages(); assertEquals(images.size(), 5); // TODO verify parsing works } diff --git a/vcloud/core/src/main/java/org/jclouds/vcloud/compute/config/VCloudComputeServiceContextModule.java b/vcloud/core/src/main/java/org/jclouds/vcloud/compute/config/VCloudComputeServiceContextModule.java index c78cab0d8b..539c7121c2 100755 --- a/vcloud/core/src/main/java/org/jclouds/vcloud/compute/config/VCloudComputeServiceContextModule.java +++ b/vcloud/core/src/main/java/org/jclouds/vcloud/compute/config/VCloudComputeServiceContextModule.java @@ -24,6 +24,7 @@ import static org.jclouds.compute.domain.OsFamily.UBUNTU; import static org.jclouds.vcloud.options.InstantiateVAppTemplateOptions.Builder.processorCount; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; @@ -97,6 +98,7 @@ import com.google.common.base.Predicates; import com.google.common.base.Supplier; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.common.util.concurrent.ListenableFuture; @@ -145,7 +147,7 @@ public class VCloudComputeServiceContextModule extends VCloudContextModule { @Provides @Named("NAMING_CONVENTION") @Singleton - String provideNamingConvention() { + protected String provideNamingConvention() { return "%s-%s%s"; } @@ -232,8 +234,10 @@ public class VCloudComputeServiceContextModule extends VCloudContextModule { @Inject protected VCloudListNodesStrategy(VCloudClient client, VCloudComputeClient computeClient, Map vAppStatusToNodeState, GetExtra getExtra, - Map locations, Map images) { - super(client, computeClient, vAppStatusToNodeState, getExtra, locations, images); + FindLocationForResourceInVDC findLocationForResourceInVDC, + Set images) { + super(client, computeClient, vAppStatusToNodeState, getExtra, + findLocationForResourceInVDC, images); } @Override @@ -273,9 +277,10 @@ public class VCloudComputeServiceContextModule extends VCloudContextModule { @Inject protected VCloudGetNodeMetadataStrategy(VCloudClient client, VCloudComputeClient computeClient, Map vAppStatusToNodeState, - GetExtra getExtra, Map locations, - Map images) { - super(client, computeClient, vAppStatusToNodeState, getExtra, locations, images); + GetExtra getExtra, FindLocationForResourceInVDC findLocationForResourceInVDC, + Set images) { + super(client, computeClient, vAppStatusToNodeState, getExtra, + findLocationForResourceInVDC, images); } @Override @@ -311,9 +316,9 @@ public class VCloudComputeServiceContextModule extends VCloudContextModule { @Provides @Singleton - protected Map provideImages(final VCloudClient client, + protected Set provideImages(final VCloudClient client, final PopulateDefaultLoginCredentialsForImageStrategy credentialsProvider, - final Map locations, LogHolder holder, + LogHolder holder, final FindLocationForResourceInVDC findLocationForResourceInVDC, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, Function indexer) throws InterruptedException, ExecutionException, TimeoutException { @@ -339,11 +344,15 @@ public class VCloudComputeServiceContextModule extends VCloudContextModule { Architecture arch = resource.getName().indexOf("64") == -1 ? Architecture.X86_32 : Architecture.X86_64; VAppTemplate template = client.getVAppTemplate(resource.getId()); + + Location location = findLocationForResourceInVDC.apply(resource, vDC + .getId()); + images.add(new ImageImpl(resource.getId(), template.getName(), - locations.get(vDC.getId()), template.getLocation(), - ImmutableMap. of(), template - .getDescription(), "", myOs, template.getName(), - arch, new Credentials("root", null))); + location, template.getLocation(), ImmutableMap + . of(), template.getDescription(), + "", myOs, template.getName(), arch, new Credentials("root", + null))); return null; } }), executor)); @@ -353,7 +362,7 @@ public class VCloudComputeServiceContextModule extends VCloudContextModule { ConcurrentUtils.awaitCompletion(responses, executor, null, holder.logger, "vAppTemplates in " + vDC); } - return Maps.uniqueIndex(images, indexer); + return images; } @Provides @@ -369,17 +378,15 @@ public class VCloudComputeServiceContextModule extends VCloudContextModule { @Provides @Singleton - Map provideLocations(Supplier cache, - VCloudClient client) { + Set provideLocations(Supplier cache, VCloudClient client) { Location provider = new LocationImpl(LocationScope.PROVIDER, providerName, providerName, null); - Map locations = Maps.newLinkedHashMap(); + Set locations = Sets.newLinkedHashSet(); for (NamedResource org : cache.get().getOrgs().values()) { Location orgL = new LocationImpl(LocationScope.REGION, org.getId(), org.getName(), provider); for (NamedResource vdc : client.getOrganization(org.getId()).getVDCs().values()) { - locations.put(vdc.getId(), new LocationImpl(LocationScope.ZONE, vdc.getId(), vdc - .getName(), orgL)); + locations.add(new LocationImpl(LocationScope.ZONE, vdc.getId(), vdc.getName(), orgL)); } } return locations; @@ -387,14 +394,22 @@ public class VCloudComputeServiceContextModule extends VCloudContextModule { @Provides @Singleton - Location getVDC(VCloudClient client, Map locations) { - return locations.get(client.getDefaultVDC().getId()); + Location getVDC(VCloudClient client, Set locations) { + final String vdc = client.getDefaultVDC().getId(); + return Iterables.find(locations, new Predicate() { + + @Override + public boolean apply(Location input) { + return input.getId().equals(vdc); + } + + }); } @Provides @Singleton - protected Map provideSizes(Function indexer, - VCloudClient client, Map images, LogHolder holder, + protected Set provideSizes(Function indexer, + VCloudClient client, Set images, LogHolder holder, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) throws InterruptedException, TimeoutException, ExecutionException { Set sizes = Sets.newHashSet(); @@ -403,6 +418,42 @@ public class VCloudComputeServiceContextModule extends VCloudContextModule { sizes.add(new SizeImpl(String.format("cpu=%d,ram=%s,disk=%d", cpus, ram, 10), null, null, null, ImmutableMap. of(), cpus, ram, 10, ImmutableSet . of(Architecture.X86_32, Architecture.X86_64))); - return Maps.uniqueIndex(sizes, indexer); + return sizes; + } + + public static class FindLocationForResourceInVDC { + + @Resource + protected Logger logger = Logger.NULL; + + final Set locations; + final Location defaultLocation; + + @Inject + public FindLocationForResourceInVDC(Set locations, + Location defaultLocation) { + this.locations = locations; + this.defaultLocation = defaultLocation; + } + + public Location apply(final NamedResource resource, final String vdcId) { + Location location = null; + try { + location = Iterables.find(locations, new Predicate() { + + @Override + public boolean apply(Location input) { + return input.getId().equals(vdcId); + } + + }); + } catch (NoSuchElementException e) { + logger.error("unknown vdc %s for %s %s; not in %s", vdcId, resource.getType(), resource + .getId(), locations); + location = new LocationImpl(LocationScope.ZONE, vdcId, vdcId, defaultLocation + .getParent()); + } + return location; + } } } diff --git a/vcloud/core/src/main/java/org/jclouds/vcloud/compute/functions/VCloudGetNodeMetadata.java b/vcloud/core/src/main/java/org/jclouds/vcloud/compute/functions/VCloudGetNodeMetadata.java index 8a40b9f38f..8b3949f94d 100644 --- a/vcloud/core/src/main/java/org/jclouds/vcloud/compute/functions/VCloudGetNodeMetadata.java +++ b/vcloud/core/src/main/java/org/jclouds/vcloud/compute/functions/VCloudGetNodeMetadata.java @@ -21,24 +21,33 @@ package org.jclouds.vcloud.compute.functions; import static com.google.common.base.Preconditions.checkNotNull; import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.annotation.Resource; import javax.inject.Inject; +import javax.inject.Named; import javax.inject.Singleton; import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeState; import org.jclouds.compute.domain.internal.NodeMetadataImpl; +import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.domain.Location; +import org.jclouds.logging.Logger; import org.jclouds.vcloud.VCloudClient; import org.jclouds.vcloud.compute.BaseVCloudComputeClient; import org.jclouds.vcloud.compute.VCloudComputeClient; +import org.jclouds.vcloud.compute.config.VCloudComputeServiceContextModule.FindLocationForResourceInVDC; import org.jclouds.vcloud.domain.VApp; import org.jclouds.vcloud.domain.VAppStatus; +import com.google.common.base.Predicate; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; /** * Configures the {@link VCloudComputeServiceContext}; requires {@link BaseVCloudComputeClient} @@ -48,28 +57,31 @@ import com.google.common.collect.ImmutableMap; */ @Singleton public class VCloudGetNodeMetadata { - + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + public Logger logger = Logger.NULL; protected final VCloudClient client; protected final VCloudComputeClient computeClient; - protected final Map images; - protected final Map locations; + protected final Set images; + protected final FindLocationForResourceInVDC findLocationForResourceInVDC; protected final GetExtra getExtra; protected final Map vAppStatusToNodeState; // hex [][][] are templateId, last two are instanceId public static final Pattern TAG_PATTERN_WITH_TEMPLATE = Pattern - .compile("([^-]+)-([0-9a-f][0-9a-f][0-9a-f])[0-9a-f]+"); + .compile("([^-]+)-?([0-9a-f][0-9a-f][0-9a-f])[0-9a-f]+"); - public static final Pattern TAG_PATTERN_WITHOUT_TEMPLATE = Pattern.compile("([^-]+)-[0-9]+"); + public static final Pattern TAG_PATTERN_WITHOUT_TEMPLATE = Pattern.compile("([^-]+)-?[0-9]+"); @Inject protected VCloudGetNodeMetadata(VCloudClient client, VCloudComputeClient computeClient, Map vAppStatusToNodeState, GetExtra getExtra, - Map locations, Map images) { + FindLocationForResourceInVDC findLocationForResourceInVDC, Set images) { this.client = checkNotNull(client, "client"); this.images = checkNotNull(images, "images"); this.getExtra = checkNotNull(getExtra, "getExtra"); - this.locations = checkNotNull(locations, "locations"); + this.findLocationForResourceInVDC = checkNotNull(findLocationForResourceInVDC, + "findLocationForResourceInVDC"); this.computeClient = checkNotNull(computeClient, "computeClient"); this.vAppStatusToNodeState = checkNotNull(vAppStatusToNodeState, "vAppStatusToNodeState"); } @@ -80,11 +92,26 @@ public class VCloudGetNodeMetadata { String tag = null; Image image = null; Matcher matcher = TAG_PATTERN_WITH_TEMPLATE.matcher(vApp.getName()); + + final Location location = findLocationForResourceInVDC.apply(vApp, vDCId); if (matcher.find()) { tag = matcher.group(1); String templateIdInHexWithoutLeadingZeros = matcher.group(2).replaceAll("^[0]+", ""); - String templateId = Integer.parseInt(templateIdInHexWithoutLeadingZeros, 16) + ""; - image = images.get(templateId); + final String templateId = Integer.parseInt(templateIdInHexWithoutLeadingZeros, 16) + ""; + try { + image = Iterables.find(images, new Predicate() { + + @Override + public boolean apply(Image input) { + return input.getId().equals(templateId) && input.getLocation().equals(location); + } + + }); + } catch (NoSuchElementException e) { + logger.warn( + "could not find a matching image for vapp %s; vapptemplate %s in location %s", + vApp, templateId, location); + } } else { matcher = TAG_PATTERN_WITHOUT_TEMPLATE.matcher(vApp.getName()); if (matcher.find()) { @@ -93,9 +120,9 @@ public class VCloudGetNodeMetadata { tag = "NOTAG-" + vApp.getName(); } } - return new NodeMetadataImpl(vApp.getId(), vApp.getName(), locations.get(vDCId), vApp - .getLocation(), ImmutableMap. of(), tag, image, - vAppStatusToNodeState.get(vApp.getStatus()), computeClient.getPublicAddresses(id), - computeClient.getPrivateAddresses(id), getExtra.apply(vApp), null); + return new NodeMetadataImpl(vApp.getId(), vApp.getName(), location, vApp.getLocation(), + ImmutableMap. of(), tag, image, vAppStatusToNodeState.get(vApp + .getStatus()), computeClient.getPublicAddresses(id), computeClient + .getPrivateAddresses(id), getExtra.apply(vApp), null); } } \ No newline at end of file diff --git a/vcloud/core/src/main/java/org/jclouds/vcloud/compute/strategy/EncodeTemplateIdIntoNameRunNodesAndAddToSetStrategy.java b/vcloud/core/src/main/java/org/jclouds/vcloud/compute/strategy/EncodeTemplateIdIntoNameRunNodesAndAddToSetStrategy.java index 5cd6395317..797be3d21c 100644 --- a/vcloud/core/src/main/java/org/jclouds/vcloud/compute/strategy/EncodeTemplateIdIntoNameRunNodesAndAddToSetStrategy.java +++ b/vcloud/core/src/main/java/org/jclouds/vcloud/compute/strategy/EncodeTemplateIdIntoNameRunNodesAndAddToSetStrategy.java @@ -42,12 +42,15 @@ import com.google.common.base.Strings; public class EncodeTemplateIdIntoNameRunNodesAndAddToSetStrategy extends EncodeTagIntoNameRunNodesAndAddToSetStrategy { + private final SecureRandom random; + @Inject protected EncodeTemplateIdIntoNameRunNodesAndAddToSetStrategy( AddNodeWithTagStrategy addNodeWithTagStrategy, ListNodesStrategy listNodesStrategy, @Named("NAMING_CONVENTION") String nodeNamingConvention, ComputeUtils utils, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) { super(addNodeWithTagStrategy, listNodesStrategy, nodeNamingConvention, utils, executor); + this.random = new SecureRandom(); } /** @@ -59,6 +62,6 @@ public class EncodeTemplateIdIntoNameRunNodesAndAddToSetStrategy extends protected String getNextName(final String tag, final Template template) { return String.format(nodeNamingConvention, tag, Strings.padStart(Integer.toHexString(Integer .parseInt(template.getImage().getId())), 3, '0'), Strings.padStart(Integer - .toHexString(new SecureRandom().nextInt(255)), 2, '0')); + .toHexString(random.nextInt(255)), 2, '0')); } } \ No newline at end of file diff --git a/vcloud/core/src/test/java/org/jclouds/vcloud/compute/VCloudComputeServiceLiveTest.java b/vcloud/core/src/test/java/org/jclouds/vcloud/compute/VCloudComputeServiceLiveTest.java index 14f9110b1a..c651f7689b 100644 --- a/vcloud/core/src/test/java/org/jclouds/vcloud/compute/VCloudComputeServiceLiveTest.java +++ b/vcloud/core/src/test/java/org/jclouds/vcloud/compute/VCloudComputeServiceLiveTest.java @@ -3,8 +3,6 @@ package org.jclouds.vcloud.compute; import static com.google.common.base.Preconditions.checkNotNull; import static org.testng.Assert.assertEquals; -import java.util.Map.Entry; - import org.jclouds.compute.BaseComputeServiceLiveTest; import org.jclouds.compute.ComputeServiceContextFactory; import org.jclouds.compute.domain.ComputeMetadata; @@ -46,12 +44,11 @@ public class VCloudComputeServiceLiveTest extends BaseComputeServiceLiveTest { @Override public void testListNodes() throws Exception { - for (Entry node : client.getNodes().entrySet()) { - assertEquals(node.getKey(), node.getValue().getId()); - assert node.getValue().getId() != null; - assert node.getValue().getLocation() != null; - assertEquals(node.getValue().getType(), ComputeType.NODE); - NodeMetadata allData = client.getNodeMetadata(node.getValue()); + for (ComputeMetadata node : client.listNodes()) { + assert node.getId() != null; + assert node.getLocation() != null; + assertEquals(node.getType(), ComputeType.NODE); + NodeMetadata allData = client.getNodeMetadata(node); assert allData.getExtra().get("processor/count") != null; assert allData.getExtra().get("disk_drive/1/kb") != null; assert allData.getExtra().get("memory/mb") != null; diff --git a/vcloud/core/src/test/java/org/jclouds/vcloud/compute/config/VCloudComputeServiceContextModuleTest.java b/vcloud/core/src/test/java/org/jclouds/vcloud/compute/config/VCloudComputeServiceContextModuleTest.java index d0139ec0a7..3ac00af9b2 100644 --- a/vcloud/core/src/test/java/org/jclouds/vcloud/compute/config/VCloudComputeServiceContextModuleTest.java +++ b/vcloud/core/src/test/java/org/jclouds/vcloud/compute/config/VCloudComputeServiceContextModuleTest.java @@ -37,8 +37,11 @@ import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.NodeState; import org.jclouds.domain.Location; +import org.jclouds.domain.LocationScope; +import org.jclouds.domain.internal.LocationImpl; import org.jclouds.vcloud.VCloudClient; import org.jclouds.vcloud.compute.VCloudComputeClient; +import org.jclouds.vcloud.compute.config.VCloudComputeServiceContextModule.FindLocationForResourceInVDC; import org.jclouds.vcloud.compute.config.VCloudComputeServiceContextModule.VCloudListNodesStrategy; import org.jclouds.vcloud.compute.functions.GetExtra; import org.jclouds.vcloud.domain.NamedResource; @@ -52,7 +55,7 @@ import org.jclouds.vcloud.domain.internal.VAppImpl; import org.testng.annotations.Test; import com.google.common.collect.ImmutableListMultimap; -import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.ListMultimap; import com.google.common.collect.Maps; @@ -108,21 +111,25 @@ public class VCloudComputeServiceContextModuleTest { expect(computeClient.getPublicAddresses("10")).andReturn(Sets. newHashSet()); expect(computeClient.getPrivateAddresses("10")).andReturn( Sets.newHashSet(InetAddress.getLocalHost())); - + replay(client); replay(computeClient); - - Map locations = ImmutableMap.of(); - Map images= ImmutableMap.of(); + + Location vdcL = new LocationImpl(LocationScope.ZONE, "1", "1", null); + Set locations = ImmutableSet.of(vdcL); + + Set images = ImmutableSet.of(); + FindLocationForResourceInVDC findLocationForResourceInVDC = new FindLocationForResourceInVDC( + locations, null); VCloudListNodesStrategy strategy = new VCloudListNodesStrategy(client, computeClient, - vAppStatusToNodeState, getExtra, locations, images); + vAppStatusToNodeState, getExtra, findLocationForResourceInVDC, images); Set nodes = Sets.newHashSet(); NamedResource vdc = new NamedResourceImpl("1", null, null, null); NamedResource resource = new NamedResourceImpl("10", null, null, null); strategy.addVAppToSetRetryingIfNotYetPresent(nodes, vdc, resource); - + verify(client); verify(computeClient); } diff --git a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/config/TerremarkVCloudComputeServiceContextModule.java b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/config/TerremarkVCloudComputeServiceContextModule.java index 902e364d6e..c168c3c884 100755 --- a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/config/TerremarkVCloudComputeServiceContextModule.java +++ b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/config/TerremarkVCloudComputeServiceContextModule.java @@ -113,9 +113,9 @@ public class TerremarkVCloudComputeServiceContextModule extends VCloudComputeSer * query the catalog. */ @Override - protected Map provideImages(final VCloudClient client, + protected Set provideImages(final VCloudClient client, final PopulateDefaultLoginCredentialsForImageStrategy credentialsProvider, - final Map locations, LogHolder holder, + LogHolder holder, final FindLocationForResourceInVDC findLocationForResourceInVDC, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, Function indexer) throws InterruptedException, ExecutionException, TimeoutException { @@ -145,11 +145,15 @@ public class TerremarkVCloudComputeServiceContextModule extends VCloudComputeSer : Architecture.X86_64; VAppTemplate template = client.getVAppTemplate(item.getEntity() .getId()); + + Location location = findLocationForResourceInVDC.apply(resource, vDC + .getId()); + images.add(new ImageImpl(resource.getId(), template.getName(), - locations.get(vDC.getId()), template.getLocation(), - ImmutableMap. of(), template - .getDescription(), "", myOs, template.getName(), - arch, credentialsProvider.execute(template))); + location, template.getLocation(), ImmutableMap + . of(), template.getDescription(), + "", myOs, template.getName(), arch, credentialsProvider + .execute(template))); return null; } }), executor)); @@ -158,20 +162,19 @@ public class TerremarkVCloudComputeServiceContextModule extends VCloudComputeSer } ConcurrentUtils.awaitCompletion(responses, executor, null, holder.logger, "vAppTemplates in " + vDC); - return Maps.uniqueIndex(images, indexer); + return images; } @Override - protected Map provideSizes(Function indexer, - VCloudClient client, Map images, LogHolder holder, + protected Set provideSizes(Function indexer, + VCloudClient client, Set images, LogHolder holder, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) throws InterruptedException, TimeoutException, ExecutionException { - Image anyImage = Iterables.get(images.values(), 0); + Image anyImage = Iterables.get(images, 0); holder.logger.debug(">> providing sizes"); SortedSet sizes = Sets.newTreeSet(Iterables.transform(TerremarkVCloudClient.class.cast( client).getComputeOptionsOfCatalogItem(anyImage.getId()), sizeConverter)); holder.logger.debug("<< sizes(%d)", sizes.size()); - return Maps.uniqueIndex(sizes, indexer); + return sizes; } - } diff --git a/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/compute/TerremarkVCloudComputeServiceLiveTest.java b/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/compute/TerremarkVCloudComputeServiceLiveTest.java index 7af0068a51..fc8ef1db06 100644 --- a/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/compute/TerremarkVCloudComputeServiceLiveTest.java +++ b/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/compute/TerremarkVCloudComputeServiceLiveTest.java @@ -21,8 +21,6 @@ package org.jclouds.vcloud.terremark.compute; import static org.testng.Assert.assertEquals; -import java.util.Map.Entry; - import org.jclouds.compute.ComputeServiceContextFactory; import org.jclouds.compute.domain.Architecture; import org.jclouds.compute.domain.ComputeType; @@ -78,14 +76,13 @@ public class TerremarkVCloudComputeServiceLiveTest extends VCloudComputeServiceL @Override public void testListImages() throws Exception { - for (Entry image : client.getImages().entrySet()) { - assertEquals(image.getKey(), image.getValue().getId()); - assert image.getValue().getId() != null : image; - // image.getValue().getLocationId() can be null, if it is a location-free image - assertEquals(image.getValue().getType(), ComputeType.IMAGE); - assert image.getValue().getDefaultCredentials().account != null : image; - if (image.getValue().getOsFamily() != OsFamily.WINDOWS) - assert image.getValue().getDefaultCredentials().key != null : image; + for (Image image : client.listImages()) { + assert image.getId() != null : image; + // image.getLocationId() can be null, if it is a location-free image + assertEquals(image.getType(), ComputeType.IMAGE); + assert image.getDefaultCredentials().account != null : image; + if (image.getOsFamily() != OsFamily.WINDOWS) + assert image.getDefaultCredentials().key != null : image; } }