JCLOUDS-946: Properly scope images to the locations where they are available
Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/26210fe0 Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/26210fe0 Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/26210fe0 Branch: refs/heads/master Commit: 26210fe0981ac3bd646fb9c4bf2d7591752266e9 Parents: 057be8d Author: Ignasi Barrera <[email protected]> Authored: Sun Jun 28 23:51:08 2015 +0200 Committer: Ignasi Barrera <[email protected]> Committed: Tue Jun 30 23:08:07 2015 +0200 ---------------------------------------------------------------------- providers/digitalocean2/pom.xml | 2 +- .../digitalocean2/DigitalOcean2ApiMetadata.java | 2 +- .../DigitalOcean2ComputeServiceAdapter.java | 45 +++++++-- ...igitalOcean2ComputeServiceContextModule.java | 15 +-- .../extensions/DigitalOcean2ImageExtension.java | 8 +- .../functions/DropletToNodeMetadata.java | 25 ++--- .../compute/functions/ImageInRegionToImage.java | 92 ++++++++++++++++++ .../compute/functions/ImageToImage.java | 65 ------------- .../compute/internal/ImageInRegion.java | 54 +++++++++++ .../services/org.jclouds.apis.ApiMetadata | 18 ---- .../DigitalOcean2TemplateBuilderLiveTest.java | 2 +- .../functions/DropletToNodeMetadataTest.java | 4 +- .../functions/ImageInRegionToImageTest.java | 98 ++++++++++++++++++++ .../compute/functions/ImageToImageTest.java | 57 ------------ 14 files changed, 308 insertions(+), 179 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/jclouds/blob/26210fe0/providers/digitalocean2/pom.xml ---------------------------------------------------------------------- diff --git a/providers/digitalocean2/pom.xml b/providers/digitalocean2/pom.xml index db5139f..5b211d4 100644 --- a/providers/digitalocean2/pom.xml +++ b/providers/digitalocean2/pom.xml @@ -36,7 +36,7 @@ <test.digitalocean2.api-version>2</test.digitalocean2.api-version> <test.digitalocean2.identity>FIXME</test.digitalocean2.identity> <test.digitalocean2.credential>FIXME</test.digitalocean2.credential> - <test.digitalocean2.template>imageId=ubuntu-14-04-x64</test.digitalocean2.template> + <test.digitalocean2.template>osFamily=UBUNTU,os64Bit=true</test.digitalocean2.template> </properties> <dependencies> http://git-wip-us.apache.org/repos/asf/jclouds/blob/26210fe0/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/DigitalOcean2ApiMetadata.java ---------------------------------------------------------------------- diff --git a/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/DigitalOcean2ApiMetadata.java b/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/DigitalOcean2ApiMetadata.java index 0b20b96..7e9861d 100644 --- a/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/DigitalOcean2ApiMetadata.java +++ b/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/DigitalOcean2ApiMetadata.java @@ -65,7 +65,7 @@ public class DigitalOcean2ApiMetadata extends BaseHttpApiMetadata<DigitalOcean2A properties.put(AUDIENCE, "https://cloud.digitalocean.com/v1/oauth/token"); properties.put(CREDENTIAL_TYPE, BEARER_TOKEN_CREDENTIALS.toString()); properties.put(PROPERTY_SESSION_INTERVAL, 3600); - properties.put(TEMPLATE, "imageId=ubuntu-14-04-x64"); + properties.put(TEMPLATE, "osFamily=UBUNTU,os64Bit=true"); properties.put(POLL_INITIAL_PERIOD, 5000); properties.put(POLL_MAX_PERIOD, 20000); return properties; http://git-wip-us.apache.org/repos/asf/jclouds/blob/26210fe0/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/DigitalOcean2ComputeServiceAdapter.java ---------------------------------------------------------------------- diff --git a/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/DigitalOcean2ComputeServiceAdapter.java b/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/DigitalOcean2ComputeServiceAdapter.java index aa4f656..ec8dc11 100644 --- a/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/DigitalOcean2ComputeServiceAdapter.java +++ b/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/DigitalOcean2ComputeServiceAdapter.java @@ -17,13 +17,19 @@ package org.jclouds.digitalocean2.compute; import static com.google.common.base.Preconditions.checkState; +import static com.google.common.base.Predicates.notNull; +import static com.google.common.collect.Iterables.concat; import static com.google.common.collect.Iterables.contains; import static com.google.common.collect.Iterables.filter; import static com.google.common.collect.Iterables.getOnlyElement; +import static com.google.common.collect.Iterables.transform; +import static com.google.common.collect.Sets.newHashSet; import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING; import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED; import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED; +import java.util.Set; + import javax.annotation.Resource; import javax.inject.Inject; import javax.inject.Named; @@ -32,6 +38,7 @@ import org.jclouds.compute.ComputeServiceAdapter; import org.jclouds.compute.domain.Template; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.digitalocean2.DigitalOcean2Api; +import org.jclouds.digitalocean2.compute.internal.ImageInRegion; import org.jclouds.digitalocean2.compute.options.DigitalOcean2TemplateOptions; import org.jclouds.digitalocean2.domain.Action; import org.jclouds.digitalocean2.domain.Droplet; @@ -43,13 +50,14 @@ import org.jclouds.digitalocean2.domain.options.CreateDropletOptions; import org.jclouds.domain.LoginCredentials; import org.jclouds.logging.Logger; +import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.primitives.Ints; /** * Implementation of the Compute Service for the DigitalOcean API. */ -public class DigitalOcean2ComputeServiceAdapter implements ComputeServiceAdapter<Droplet, Size, Image, Region> { +public class DigitalOcean2ComputeServiceAdapter implements ComputeServiceAdapter<Droplet, Size, ImageInRegion, Region> { @Resource @Named(ComputeServiceConstants.COMPUTE_LOGGER) @@ -101,8 +109,30 @@ public class DigitalOcean2ComputeServiceAdapter implements ComputeServiceAdapter } @Override - public Iterable<Image> listImages() { - return api.imageApi().list().concat(); + public Iterable<ImageInRegion> listImages() { + // Images can claim to be available in a region that is currently marked as "unavailable". We shouldn't return + // the images scoped to those regions. + final Set<String> availableRegionsIds = newHashSet(transform(listLocations(), new Function<Region, String>() { + @Override + public String apply(Region input) { + return input.slug(); + } + })); + + // Public images re globally available, but non-public ones can only be available in certain regions. + // For these kind of images, return one instance of an ImageInRegion for each region where the image is + // available. This way we can properly scope global and concrete images so they can be properly looked up. + return concat(filter(api.imageApi().list().concat().transform(new Function<Image, Iterable<ImageInRegion>>() { + @Override + public Iterable<ImageInRegion> apply(final Image image) { + return transform(image.regions(), new Function<String, ImageInRegion>() { + @Override + public ImageInRegion apply(String region) { + return availableRegionsIds.contains(region) ? ImageInRegion.create(image, region) : null; + } + }); + } + }), notNull())); } @Override @@ -142,11 +172,14 @@ public class DigitalOcean2ComputeServiceAdapter implements ComputeServiceAdapter } @Override - public Image getImage(String id) { + public ImageInRegion getImage(String id) { + String region = ImageInRegion.extractRegion(id); + String imageId = ImageInRegion.extractImageId(id); // The id of the image can be an id or a slug. Use the corresponding method of the API depending on what is // provided. If it can be parsed as a number, use the method to get by ID. Otherwise, get by slug. - Integer imageId = Ints.tryParse(id); - return imageId != null ? api.imageApi().get(imageId) : api.imageApi().get(id); + Integer numericId = Ints.tryParse(imageId); + Image image = numericId == null ? api.imageApi().get(imageId) : api.imageApi().get(numericId); + return ImageInRegion.create(image, region); } @Override http://git-wip-us.apache.org/repos/asf/jclouds/blob/26210fe0/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/config/DigitalOcean2ComputeServiceContextModule.java ---------------------------------------------------------------------- diff --git a/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/config/DigitalOcean2ComputeServiceContextModule.java b/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/config/DigitalOcean2ComputeServiceContextModule.java index 7809f9d..c2ed858 100644 --- a/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/config/DigitalOcean2ComputeServiceContextModule.java +++ b/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/config/DigitalOcean2ComputeServiceContextModule.java @@ -28,6 +28,7 @@ import javax.inject.Singleton; import org.jclouds.compute.ComputeServiceAdapter; import org.jclouds.compute.config.ComputeServiceAdapterContextModule; import org.jclouds.compute.domain.Hardware; +import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata.Status; import org.jclouds.compute.extensions.ImageExtension; @@ -41,15 +42,15 @@ import org.jclouds.digitalocean2.compute.DigitalOcean2ComputeServiceAdapter; import org.jclouds.digitalocean2.compute.extensions.DigitalOcean2ImageExtension; import org.jclouds.digitalocean2.compute.functions.DropletStatusToStatus; import org.jclouds.digitalocean2.compute.functions.DropletToNodeMetadata; -import org.jclouds.digitalocean2.compute.functions.ImageToImage; +import org.jclouds.digitalocean2.compute.functions.ImageInRegionToImage; import org.jclouds.digitalocean2.compute.functions.RegionToLocation; import org.jclouds.digitalocean2.compute.functions.SizeToHardware; import org.jclouds.digitalocean2.compute.functions.TemplateOptionsToStatementWithoutPublicKey; +import org.jclouds.digitalocean2.compute.internal.ImageInRegion; import org.jclouds.digitalocean2.compute.options.DigitalOcean2TemplateOptions; import org.jclouds.digitalocean2.compute.strategy.CreateKeyPairsThenCreateNodes; import org.jclouds.digitalocean2.domain.Action; import org.jclouds.digitalocean2.domain.Droplet; -import org.jclouds.digitalocean2.domain.Image; import org.jclouds.digitalocean2.domain.Region; import org.jclouds.digitalocean2.domain.Size; import org.jclouds.domain.Location; @@ -67,19 +68,19 @@ import com.google.inject.name.Named; * Configures the compute service classes for the DigitalOcean API. */ public class DigitalOcean2ComputeServiceContextModule extends - ComputeServiceAdapterContextModule<Droplet, Size, Image, Region> { + ComputeServiceAdapterContextModule<Droplet, Size, ImageInRegion, Region> { @Override protected void configure() { super.configure(); - bind(new TypeLiteral<ComputeServiceAdapter<Droplet, Size, Image, Region>>() { + bind(new TypeLiteral<ComputeServiceAdapter<Droplet, Size, ImageInRegion, Region>>() { }).to(DigitalOcean2ComputeServiceAdapter.class); bind(new TypeLiteral<Function<Droplet, NodeMetadata>>() { }).to(DropletToNodeMetadata.class); - bind(new TypeLiteral<Function<Image, org.jclouds.compute.domain.Image>>() { - }).to(ImageToImage.class); + bind(new TypeLiteral<Function<ImageInRegion, Image>>() { + }).to(ImageInRegionToImage.class); bind(new TypeLiteral<Function<Region, Location>>() { }).to(RegionToLocation.class); bind(new TypeLiteral<Function<Size, Hardware>>() { @@ -87,7 +88,7 @@ public class DigitalOcean2ComputeServiceContextModule extends bind(new TypeLiteral<Function<Droplet.Status, Status>>() { }).to(DropletStatusToStatus.class); - install(new LocationsFromComputeServiceAdapterModule<Droplet, Size, Image, Region>() { + install(new LocationsFromComputeServiceAdapterModule<Droplet, Size, ImageInRegion, Region>() { }); bind(CreateNodesInGroupThenAddToSet.class).to(CreateKeyPairsThenCreateNodes.class); http://git-wip-us.apache.org/repos/asf/jclouds/blob/26210fe0/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/extensions/DigitalOcean2ImageExtension.java ---------------------------------------------------------------------- diff --git a/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/extensions/DigitalOcean2ImageExtension.java b/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/extensions/DigitalOcean2ImageExtension.java index 41e3270..77ccd2a 100644 --- a/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/extensions/DigitalOcean2ImageExtension.java +++ b/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/extensions/DigitalOcean2ImageExtension.java @@ -35,6 +35,7 @@ import org.jclouds.compute.domain.ImageTemplateBuilder; import org.jclouds.compute.extensions.ImageExtension; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.digitalocean2.DigitalOcean2Api; +import org.jclouds.digitalocean2.compute.internal.ImageInRegion; import org.jclouds.digitalocean2.domain.Action; import org.jclouds.digitalocean2.domain.Droplet; import org.jclouds.digitalocean2.domain.Droplet.Status; @@ -58,12 +59,12 @@ public class DigitalOcean2ImageExtension implements ImageExtension { private final DigitalOcean2Api api; private final Predicate<Integer> imageAvailablePredicate; private final Predicate<Integer> nodeStoppedPredicate; - private final Function<org.jclouds.digitalocean2.domain.Image, Image> imageTransformer; + private final Function<ImageInRegion, Image> imageTransformer; @Inject DigitalOcean2ImageExtension(DigitalOcean2Api api, @Named(TIMEOUT_IMAGE_AVAILABLE) Predicate<Integer> imageAvailablePredicate, @Named(TIMEOUT_NODE_SUSPENDED) Predicate<Integer> nodeStoppedPredicate, - Function<org.jclouds.digitalocean2.domain.Image, Image> imageTransformer) { + Function<ImageInRegion, Image> imageTransformer) { this.api = api; this.imageAvailablePredicate = imageAvailablePredicate; this.nodeStoppedPredicate = nodeStoppedPredicate; @@ -111,7 +112,8 @@ public class DigitalOcean2ImageExtension implements ImageExtension { } }).get(); - return immediateFuture(imageTransformer.apply(snapshot)); + // By default snapshots are only available in the Droplet's region + return immediateFuture(imageTransformer.apply(ImageInRegion.create(snapshot, droplet.region().slug()))); } @Override http://git-wip-us.apache.org/repos/asf/jclouds/blob/26210fe0/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/functions/DropletToNodeMetadata.java ---------------------------------------------------------------------- diff --git a/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/functions/DropletToNodeMetadata.java b/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/functions/DropletToNodeMetadata.java index eebc121..11594f8 100644 --- a/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/functions/DropletToNodeMetadata.java +++ b/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/functions/DropletToNodeMetadata.java @@ -18,10 +18,11 @@ package org.jclouds.digitalocean2.compute.functions; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.Iterables.find; -import static com.google.common.collect.Iterables.tryFind; +import static org.jclouds.digitalocean2.compute.internal.ImageInRegion.encodeId; import java.util.Map; import java.util.Set; + import javax.annotation.Resource; import javax.inject.Inject; import javax.inject.Named; @@ -35,6 +36,7 @@ import org.jclouds.compute.domain.NodeMetadata.Status; import org.jclouds.compute.domain.NodeMetadataBuilder; import org.jclouds.compute.functions.GroupNamingConvention; import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.digitalocean2.compute.internal.ImageInRegion; import org.jclouds.digitalocean2.domain.Droplet; import org.jclouds.digitalocean2.domain.Networks; import org.jclouds.digitalocean2.domain.Region; @@ -42,6 +44,7 @@ import org.jclouds.domain.Credentials; import org.jclouds.domain.Location; import org.jclouds.domain.LoginCredentials; import org.jclouds.logging.Logger; + import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.base.Predicate; @@ -91,7 +94,7 @@ public class DropletToNodeMetadata implements Function<Droplet, NodeMetadata> { builder.hardware(getHardware(input.sizeSlug())); builder.location(getLocation(input.region())); - Optional<? extends Image> image = findImage(input.image().id()); + Optional<? extends Image> image = findImage(input.image(), input.region().slug()); if (image.isPresent()) { builder.imageId(image.get().getId()); builder.operatingSystem(image.get().getOperatingSystem()); @@ -138,22 +141,8 @@ public class DropletToNodeMetadata implements Function<Droplet, NodeMetadata> { return builder.build(); } - protected Optional<? extends Image> findImage(Integer id) { - // Try to find the image by ID in the cache. The cache is indexed by slug (for public images) and by id (for - // private ones). - final String imageId = String.valueOf(id); - Optional<? extends Image> image = Optional.fromNullable(images.get().get(imageId)); - if (!image.isPresent()) { - // If it is a public image (indexed by slug) but the "int" form of the id was provided, try to find it in the - // whole list of cached images - image = tryFind(images.get().values(), new Predicate<Image>() { - @Override - public boolean apply(Image input) { - return input.getProviderId().equals(imageId); - } - }); - } - return image; + protected Optional<? extends Image> findImage(org.jclouds.digitalocean2.domain.Image image, String region) { + return Optional.fromNullable(images.get().get(encodeId(ImageInRegion.create(image, region)))); } protected Hardware getHardware(final String slug) { http://git-wip-us.apache.org/repos/asf/jclouds/blob/26210fe0/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/functions/ImageInRegionToImage.java ---------------------------------------------------------------------- diff --git a/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/functions/ImageInRegionToImage.java b/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/functions/ImageInRegionToImage.java new file mode 100644 index 0000000..08c6c71 --- /dev/null +++ b/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/functions/ImageInRegionToImage.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.digitalocean2.compute.functions; + +import static com.google.common.collect.Iterables.find; +import static org.jclouds.compute.domain.OperatingSystem.builder; +import static org.jclouds.digitalocean2.compute.internal.ImageInRegion.encodeId; + +import java.util.Set; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.collect.Memoized; +import org.jclouds.compute.domain.Image; +import org.jclouds.compute.domain.Image.Status; +import org.jclouds.compute.domain.ImageBuilder; +import org.jclouds.digitalocean2.compute.internal.ImageInRegion; +import org.jclouds.digitalocean2.domain.OperatingSystem; +import org.jclouds.domain.Location; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableMap; + +/** + * Transforms an {@link ImageInRegion} to the jclouds portable model. + */ +@Singleton +public class ImageInRegionToImage implements Function<ImageInRegion, Image> { + + private final Supplier<Set<? extends Location>> locations; + + @Inject ImageInRegionToImage(@Memoized Supplier<Set<? extends Location>> locations) { + this.locations = locations; + } + + @Override + public Image apply(final ImageInRegion input) { + String description = input.image().distribution() + " " + input.image().name(); + ImageBuilder builder = new ImageBuilder(); + // Private images don't have a slug + builder.id(encodeId(input)); + builder.providerId(String.valueOf(input.image().id())); + builder.name(input.image().name()); + builder.description(description); + builder.status(Status.AVAILABLE); + builder.location(getLocation(input.region())); + + OperatingSystem os = OperatingSystem.create(input.image().name(), input.image().distribution()); + + builder.operatingSystem(builder() + .name(os.distribution().value()) + .family(os.distribution().osFamily()) + .description(description) + .arch(os.arch()) + .version(os.version()) + .is64Bit(os.is64bit()) + .build()); + + ImmutableMap.Builder<String, String> metadata = ImmutableMap.builder(); + metadata.put("publicImage", String.valueOf(input.image().isPublic())); + builder.userMetadata(metadata.build()); + + return builder.build(); + } + + protected Location getLocation(final String region) { + return find(locations.get(), new Predicate<Location>() { + @Override + public boolean apply(Location location) { + return region.equals(location.getId()); + } + }); + } + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/26210fe0/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/functions/ImageToImage.java ---------------------------------------------------------------------- diff --git a/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/functions/ImageToImage.java b/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/functions/ImageToImage.java deleted file mode 100644 index 8f9ad92..0000000 --- a/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/functions/ImageToImage.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jclouds.digitalocean2.compute.functions; - -import static org.jclouds.compute.domain.OperatingSystem.builder; - -import javax.inject.Singleton; - -import org.jclouds.compute.domain.Image.Status; -import org.jclouds.compute.domain.ImageBuilder; -import org.jclouds.digitalocean2.domain.Image; -import org.jclouds.digitalocean2.domain.OperatingSystem; -import com.google.common.base.Function; -import com.google.common.collect.ImmutableMap; - -/** - * Transforms an {@link Image} to the jclouds portable model. - */ -@Singleton -public class ImageToImage implements Function<Image, org.jclouds.compute.domain.Image> { - - @Override - public org.jclouds.compute.domain.Image apply(final Image input) { - String description = input.distribution() + " " + input.name(); - ImageBuilder builder = new ImageBuilder(); - // Private images don't have a slug - builder.id(input.slug() != null ? input.slug() : String.valueOf(input.id())); - builder.providerId(String.valueOf(input.id())); - builder.name(input.name()); - builder.description(description); - builder.status(Status.AVAILABLE); - - OperatingSystem os = OperatingSystem.create(input.name(), input.distribution()); - - builder.operatingSystem(builder() - .name(os.distribution().value()) - .family(os.distribution().osFamily()) - .description(description) - .arch(os.arch()) - .version(os.version()) - .is64Bit(os.is64bit()) - .build()); - - ImmutableMap.Builder<String, String> metadata = ImmutableMap.builder(); - metadata.put("publicImage", String.valueOf(input.isPublic())); - builder.userMetadata(metadata.build()); - - return builder.build(); - } - -} http://git-wip-us.apache.org/repos/asf/jclouds/blob/26210fe0/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/internal/ImageInRegion.java ---------------------------------------------------------------------- diff --git a/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/internal/ImageInRegion.java b/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/internal/ImageInRegion.java new file mode 100644 index 0000000..b5beb8d --- /dev/null +++ b/providers/digitalocean2/src/main/java/org/jclouds/digitalocean2/compute/internal/ImageInRegion.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.digitalocean2.compute.internal; + +import org.jclouds.digitalocean2.domain.Image; + +import com.google.auto.value.AutoValue; + +/** + * Scopes an image to a particular region. + */ +@AutoValue +public abstract class ImageInRegion { + + public abstract Image image(); + public abstract String region(); + + public static ImageInRegion create(Image image, String region) { + return new AutoValue_ImageInRegion(image, region); + } + + public static String encodeId(ImageInRegion imageInRegion) { + // Private images don't have a slug + return String.format("%s/%s", imageInRegion.region(), slugOrId(imageInRegion.image())); + } + + public static String extractRegion(String imageId) { + return imageId.substring(0, imageId.indexOf('/')); + } + + public static String extractImageId(String imageId) { + return imageId.substring(imageId.indexOf('/') + 1); + } + + private static String slugOrId(Image image) { + return image.slug() != null ? image.slug() : String.valueOf(image.id()); + } + + ImageInRegion() { } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/26210fe0/providers/digitalocean2/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata ---------------------------------------------------------------------- diff --git a/providers/digitalocean2/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata b/providers/digitalocean2/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata deleted file mode 100644 index 0be234c..0000000 --- a/providers/digitalocean2/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.jclouds.digitalocean2.DigitalOcean2ApiMetadata http://git-wip-us.apache.org/repos/asf/jclouds/blob/26210fe0/providers/digitalocean2/src/test/java/org/jclouds/digitalocean2/compute/DigitalOcean2TemplateBuilderLiveTest.java ---------------------------------------------------------------------- diff --git a/providers/digitalocean2/src/test/java/org/jclouds/digitalocean2/compute/DigitalOcean2TemplateBuilderLiveTest.java b/providers/digitalocean2/src/test/java/org/jclouds/digitalocean2/compute/DigitalOcean2TemplateBuilderLiveTest.java index e508789..8480cc1 100644 --- a/providers/digitalocean2/src/test/java/org/jclouds/digitalocean2/compute/DigitalOcean2TemplateBuilderLiveTest.java +++ b/providers/digitalocean2/src/test/java/org/jclouds/digitalocean2/compute/DigitalOcean2TemplateBuilderLiveTest.java @@ -40,7 +40,7 @@ public class DigitalOcean2TemplateBuilderLiveTest extends BaseTemplateBuilderLiv @Override public void testDefaultTemplateBuilder() throws IOException { Template defaultTemplate = view.getComputeService().templateBuilder().build(); - assert defaultTemplate.getImage().getOperatingSystem().getVersion().equals("14.04") : defaultTemplate + assert defaultTemplate.getImage().getOperatingSystem().getVersion().equals("15.04") : defaultTemplate .getImage().getOperatingSystem().getVersion(); assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(), true); assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU); http://git-wip-us.apache.org/repos/asf/jclouds/blob/26210fe0/providers/digitalocean2/src/test/java/org/jclouds/digitalocean2/compute/functions/DropletToNodeMetadataTest.java ---------------------------------------------------------------------- diff --git a/providers/digitalocean2/src/test/java/org/jclouds/digitalocean2/compute/functions/DropletToNodeMetadataTest.java b/providers/digitalocean2/src/test/java/org/jclouds/digitalocean2/compute/functions/DropletToNodeMetadataTest.java index 27dbad9..ba6d3de 100644 --- a/providers/digitalocean2/src/test/java/org/jclouds/digitalocean2/compute/functions/DropletToNodeMetadataTest.java +++ b/providers/digitalocean2/src/test/java/org/jclouds/digitalocean2/compute/functions/DropletToNodeMetadataTest.java @@ -83,7 +83,7 @@ public class DropletToNodeMetadataTest { region = Region.create("sfo1", "San Francisco 1", ImmutableList.of("2gb"), true, ImmutableList.<String> of()); images = ImmutableSet.of(new ImageBuilder() - .id("ubuntu-1404-x86") + .id("sfo1/ubuntu-1404-x86") .providerId("1") .name("mock image") .status(AVAILABLE) @@ -132,7 +132,7 @@ public class DropletToNodeMetadataTest { ImmutableList.<Networks.Address> of()), null); NodeMetadata expected = new NodeMetadataBuilder().ids("1").hardware(getOnlyElement(hardwares)) - .imageId("ubuntu-1404-x86").status(RUNNING).location(getOnlyElement(locations)).name("mock-droplet") + .imageId("sfo1/ubuntu-1404-x86").status(RUNNING).location(getOnlyElement(locations)).name("mock-droplet") .hostname("mock-droplet").group("mock").credentials(credentials) .publicAddresses(ImmutableSet.of("84.45.69.3")).privateAddresses(ImmutableSet.of("192.168.2.5")) .providerId("1").backendStatus(ACTIVE.name()).operatingSystem(getOnlyElement(images).getOperatingSystem()) http://git-wip-us.apache.org/repos/asf/jclouds/blob/26210fe0/providers/digitalocean2/src/test/java/org/jclouds/digitalocean2/compute/functions/ImageInRegionToImageTest.java ---------------------------------------------------------------------- diff --git a/providers/digitalocean2/src/test/java/org/jclouds/digitalocean2/compute/functions/ImageInRegionToImageTest.java b/providers/digitalocean2/src/test/java/org/jclouds/digitalocean2/compute/functions/ImageInRegionToImageTest.java new file mode 100644 index 0000000..f1072d6 --- /dev/null +++ b/providers/digitalocean2/src/test/java/org/jclouds/digitalocean2/compute/functions/ImageInRegionToImageTest.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.digitalocean2.compute.functions; + +import static org.jclouds.compute.domain.Image.Status.AVAILABLE; +import static org.testng.Assert.assertEquals; + +import java.util.Date; +import java.util.Set; + +import org.jclouds.compute.domain.ImageBuilder; +import org.jclouds.compute.domain.OperatingSystem; +import org.jclouds.compute.domain.OsFamily; +import org.jclouds.digitalocean2.compute.internal.ImageInRegion; +import org.jclouds.digitalocean2.domain.Image; +import org.jclouds.domain.Location; +import org.jclouds.domain.LocationBuilder; +import org.jclouds.domain.LocationScope; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; + +@Test(groups = "unit", testName = "ImageToImageTest") +public class ImageInRegionToImageTest { + + private Set<Location> locations; + + private ImageInRegionToImage function; + + @BeforeMethod + public void setup() { + locations = ImmutableSet.of( + new LocationBuilder() + .id("sfo1") + .description("sfo1/San Francisco 1") + .scope(LocationScope.REGION) + .parent( + new LocationBuilder().id("0").description("mock parent location").scope(LocationScope.PROVIDER) + .build()).build(), + new LocationBuilder() + .id("lon1") + .description("lon1/London 1") + .scope(LocationScope.REGION) + .parent( + new LocationBuilder().id("0").description("mock parent location").scope(LocationScope.PROVIDER) + .build()).build()); + + function = new ImageInRegionToImage(new Supplier<Set<? extends Location>>() { + @Override + public Set<? extends Location> get() { + return locations; + } + }); + } + + @Test + public void testConvertImage() { + Image image = Image.create(1, "14.04 x64", "distribution", "Ubuntu", "ubuntu-1404-x86", true, + ImmutableList.of("sfo1", "lon1"), new Date()); + org.jclouds.compute.domain.Image expected = new ImageBuilder() + .id("lon1/ubuntu-1404-x86") // Location scoped images have the location encoded in the id + .providerId("1") + .name("14.04 x64") + .description("Ubuntu 14.04 x64") + .status(AVAILABLE) + .operatingSystem( + OperatingSystem.builder().name("Ubuntu").description("Ubuntu 14.04 x64").family(OsFamily.UBUNTU) + .version("14.04").arch("x64").is64Bit(true).build()) + .location(Iterables.get(locations, 1)) + .userMetadata(ImmutableMap.of("publicImage", "true")).build(); + + org.jclouds.compute.domain.Image result = function.apply(ImageInRegion.create(image, "lon1")); + assertEquals(result, expected); + assertEquals(result.getDescription(), expected.getDescription()); + assertEquals(result.getOperatingSystem(), expected.getOperatingSystem()); + assertEquals(result.getStatus(), expected.getStatus()); + assertEquals(result.getLocation(), Iterables.get(locations, 1)); + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/26210fe0/providers/digitalocean2/src/test/java/org/jclouds/digitalocean2/compute/functions/ImageToImageTest.java ---------------------------------------------------------------------- diff --git a/providers/digitalocean2/src/test/java/org/jclouds/digitalocean2/compute/functions/ImageToImageTest.java b/providers/digitalocean2/src/test/java/org/jclouds/digitalocean2/compute/functions/ImageToImageTest.java deleted file mode 100644 index 6ab020c..0000000 --- a/providers/digitalocean2/src/test/java/org/jclouds/digitalocean2/compute/functions/ImageToImageTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jclouds.digitalocean2.compute.functions; - -import static org.jclouds.compute.domain.Image.Status.AVAILABLE; -import static org.testng.Assert.assertEquals; - -import java.util.Date; - -import org.jclouds.compute.domain.ImageBuilder; -import org.jclouds.compute.domain.OperatingSystem; -import org.jclouds.compute.domain.OsFamily; -import org.jclouds.digitalocean2.domain.Image; -import org.testng.annotations.Test; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; - -@Test(groups = "unit", testName = "ImageToImageTest") -public class ImageToImageTest { - - @Test - public void testConvertImage() { - Image image = Image.create(1, "14.04 x64", "distribution", "Ubuntu", "ubuntu-1404-x86", true, - ImmutableList.of("sfo1"), new Date()); - org.jclouds.compute.domain.Image expected = new ImageBuilder() - .id("ubuntu-1404-x86") - .providerId("1") - .name("14.04 x64") - .description("Ubuntu 14.04 x64") - .status(AVAILABLE) - .operatingSystem( - OperatingSystem.builder().name("Ubuntu").description("Ubuntu 14.04 x64").family(OsFamily.UBUNTU) - .version("14.04").arch("x64").is64Bit(true).build()) - .userMetadata(ImmutableMap.of("publicImage", "true")).build(); - - org.jclouds.compute.domain.Image result = new ImageToImage().apply(image); - assertEquals(result, expected); - assertEquals(result.getDescription(), expected.getDescription()); - assertEquals(result.getOperatingSystem(), expected.getOperatingSystem()); - assertEquals(result.getStatus(), expected.getStatus()); - } -}
