You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by na...@apache.org on 2016/01/21 01:03:31 UTC
[07/19] jclouds git commit: JCLOUDS-946: Properly scope images to the
locations where they are available
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 <na...@apache.org>
Authored: Sun Jun 28 23:51:08 2015 +0200
Committer: Ignasi Barrera <na...@apache.org>
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());
- }
-}