From 2b28c04c0f5e9dc15b53d75a1a9ed58a64369726 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Thu, 4 Aug 2011 11:25:49 +0200 Subject: [PATCH] Issue 539:expose templatebuilder parameter to prefer s3-backed images --- .../predicates/EC2ImagePredicates.java | 52 +++++++++++++++++ .../compute/domain/TemplateBuilder.java | 6 ++ .../domain/internal/TemplateBuilderImpl.java | 21 ++++++- .../compute/predicates/ImagePredicates.java | 27 ++++++++- .../internal/TemplateBuilderImplTest.java | 2 +- .../predicates/ImagePredicatesTest.java | 56 +++++++++++++++++++ .../AWSEC2TemplateBuilderLiveTest.java | 38 ++++++++++++- 7 files changed, 196 insertions(+), 6 deletions(-) create mode 100644 apis/ec2/src/main/java/org/jclouds/ec2/compute/predicates/EC2ImagePredicates.java create mode 100644 compute/src/test/java/org/jclouds/compute/predicates/ImagePredicatesTest.java diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/compute/predicates/EC2ImagePredicates.java b/apis/ec2/src/main/java/org/jclouds/ec2/compute/predicates/EC2ImagePredicates.java new file mode 100644 index 0000000000..84436a7ea6 --- /dev/null +++ b/apis/ec2/src/main/java/org/jclouds/ec2/compute/predicates/EC2ImagePredicates.java @@ -0,0 +1,52 @@ +/** + * + * Copyright (C) 2011 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.ec2.compute.predicates; + +import static com.google.common.base.Preconditions.checkNotNull; + +import org.jclouds.compute.domain.Image; +import org.jclouds.compute.predicates.ImagePredicates; +import org.jclouds.ec2.domain.RootDeviceType; + +import com.google.common.base.Predicate; + +/** + * Container for image filters (predicates). + * + * This class has static methods that create customized predicates to use with + * {@link org.jclouds.compute.ComputeService}. + * + * @author Adrian Cole + */ +public class EC2ImagePredicates { + + /** + * evaluates true if the Image has the specified root device type + * + * @param rootDeviceType + * rootDeviceType of the images + * @return predicate + */ + public static Predicate rootDeviceType(final RootDeviceType rootDeviceType) { + checkNotNull(rootDeviceType, "rootDeviceType must be defined"); + return ImagePredicates.userMetadataContains("rootDeviceType", rootDeviceType.value()); + } + + +} diff --git a/compute/src/main/java/org/jclouds/compute/domain/TemplateBuilder.java b/compute/src/main/java/org/jclouds/compute/domain/TemplateBuilder.java index 2e67313aca..3f3aaa6084 100644 --- a/compute/src/main/java/org/jclouds/compute/domain/TemplateBuilder.java +++ b/compute/src/main/java/org/jclouds/compute/domain/TemplateBuilder.java @@ -23,6 +23,7 @@ import java.util.NoSuchElementException; import org.jclouds.compute.domain.internal.TemplateBuilderImpl; import org.jclouds.compute.options.TemplateOptions; +import com.google.common.base.Predicate; import com.google.inject.ImplementedBy; /** @@ -135,6 +136,11 @@ public interface TemplateBuilder { */ TemplateBuilder imageDescriptionMatches(String imageDescriptionRegex); + /** + * Configure this template to have an image description that matches the supplied condition + */ + TemplateBuilder imageMatches(Predicate condition); + /** * Configure this template to require the minimum cores below */ diff --git a/compute/src/main/java/org/jclouds/compute/domain/internal/TemplateBuilderImpl.java b/compute/src/main/java/org/jclouds/compute/domain/internal/TemplateBuilderImpl.java index 2e1bf6d689..ce2e54a4b6 100644 --- a/compute/src/main/java/org/jclouds/compute/domain/internal/TemplateBuilderImpl.java +++ b/compute/src/main/java/org/jclouds/compute/domain/internal/TemplateBuilderImpl.java @@ -106,6 +106,8 @@ public class TemplateBuilderImpl implements TemplateBuilder { @VisibleForTesting protected String imageDescription; @VisibleForTesting + protected Predicate imagePredicate; + @VisibleForTesting protected double minCores; @VisibleForTesting protected int minRam; @@ -719,6 +721,8 @@ public class TemplateBuilderImpl implements TemplateBuilder { predicates.add(imageNamePredicate); if (imageDescription != null) predicates.add(imageDescriptionPredicate); + if (imagePredicate != null) + predicates.add(imagePredicate); } // looks verbose, but explicit type needed for this to compile @@ -736,6 +740,7 @@ public class TemplateBuilderImpl implements TemplateBuilder { this.imageId = imageId; this.imageName = null; this.imageDescription = null; + this.imagePredicate = null; this.imageVersion = null; this.osFamily = null; this.osName = null; @@ -763,6 +768,15 @@ public class TemplateBuilderImpl implements TemplateBuilder { this.imageDescription = descriptionRegex; return this; } + + /** + * {@inheritDoc} + */ + @Override + public TemplateBuilder imageMatches(Predicate condition) { + this.imagePredicate = condition; + return this; + } /** * {@inheritDoc} @@ -849,8 +863,9 @@ public class TemplateBuilderImpl implements TemplateBuilder { @VisibleForTesting boolean nothingChangedExceptOptions() { return osFamily == null && location == null && imageId == null && hardwareId == null && osName == null - && osDescription == null && imageVersion == null && osVersion == null && osArch == null && os64Bit == null - && imageName == null && imageDescription == null && minCores == 0 && minRam == 0 && !biggest && !fastest; + && imagePredicate == null && osDescription == null && imageVersion == null && osVersion == null + && osArch == null && os64Bit == null && imageName == null && imageDescription == null && minCores == 0 + && minRam == 0 && !biggest && !fastest; } /** @@ -864,7 +879,7 @@ public class TemplateBuilderImpl implements TemplateBuilder { @Override public String toString() { return "[biggest=" + biggest + ", fastest=" + fastest + ", imageName=" + imageName + ", imageDescription=" - + imageDescription + ", imageId=" + imageId + ", imageVersion=" + imageVersion + ", location=" + location + + imageDescription + ", imageId=" + imageId + ", imagePredicate=" + imagePredicate + ", imageVersion=" + imageVersion + ", location=" + location + ", minCores=" + minCores + ", minRam=" + minRam + ", osFamily=" + osFamily + ", osName=" + osName + ", osDescription=" + osDescription + ", osVersion=" + osVersion + ", osArch=" + osArch + ", os64Bit=" + os64Bit + ", hardwareId=" + hardwareId + "]"; diff --git a/compute/src/main/java/org/jclouds/compute/predicates/ImagePredicates.java b/compute/src/main/java/org/jclouds/compute/predicates/ImagePredicates.java index b5d4d59a7f..cc068450fe 100644 --- a/compute/src/main/java/org/jclouds/compute/predicates/ImagePredicates.java +++ b/compute/src/main/java/org/jclouds/compute/predicates/ImagePredicates.java @@ -58,7 +58,7 @@ public class ImagePredicates { } /** - * evaluates true if the Image + * evaluates true if the Image id is in the supplied set * * @param ids * ids of the images @@ -79,6 +79,31 @@ public class ImagePredicates { } }; } + + /** + * evaluates true if the Image metadata contains the following values + * + * @param key + * key in Image#getUserMetadata + * @param value + * value in Image#getUserMetadata + * @return predicate + */ + public static Predicate userMetadataContains(final String key, final String value) { + checkNotNull(key, "key must be defined"); + checkNotNull(value, "value must be defined"); + return new Predicate() { + @Override + public boolean apply(Image image) { + return value.equals(image.getUserMetadata().get(key)); + } + + @Override + public String toString() { + return "metadataContains(" + key +", "+value + ")"; + } + }; + } /** * evaluates true if the Image diff --git a/compute/src/test/java/org/jclouds/compute/domain/internal/TemplateBuilderImplTest.java b/compute/src/test/java/org/jclouds/compute/domain/internal/TemplateBuilderImplTest.java index 7a7eb62366..acac93c77f 100644 --- a/compute/src/test/java/org/jclouds/compute/domain/internal/TemplateBuilderImplTest.java +++ b/compute/src/test/java/org/jclouds/compute/domain/internal/TemplateBuilderImplTest.java @@ -278,7 +278,7 @@ public class TemplateBuilderImplTest { // make sure big data is not in the exception message assertEquals( e.getMessage(), - "no hardware profiles support images matching params: [biggest=false, fastest=false, imageName=null, imageDescription=null, imageId=notImageId, imageVersion=null, location=EasyMock for interface org.jclouds.domain.Location, minCores=0.0, minRam=0, osFamily=null, osName=null, osDescription=null, osVersion=null, osArch=null, os64Bit=false, hardwareId=null]"); + "no hardware profiles support images matching params: [biggest=false, fastest=false, imageName=null, imageDescription=null, imageId=notImageId, imagePredicate=null, imageVersion=null, location=EasyMock for interface org.jclouds.domain.Location, minCores=0.0, minRam=0, osFamily=null, osName=null, osDescription=null, osVersion=null, osArch=null, os64Bit=false, hardwareId=null]"); verify(image); verify(os); verify(defaultTemplate); diff --git a/compute/src/test/java/org/jclouds/compute/predicates/ImagePredicatesTest.java b/compute/src/test/java/org/jclouds/compute/predicates/ImagePredicatesTest.java new file mode 100644 index 0000000000..bebe9de1b2 --- /dev/null +++ b/compute/src/test/java/org/jclouds/compute/predicates/ImagePredicatesTest.java @@ -0,0 +1,56 @@ +/** + * + * Copyright (C) 2011 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.predicates; + +import org.jclouds.compute.ComputeService; +import org.jclouds.compute.ComputeServiceContextFactory; +import org.jclouds.compute.domain.Image; +import org.jclouds.compute.domain.ImageBuilder; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; + +/** + * Tests possible uses of OperatingSystemPredicates + * + * @author Adrian Cole + */ +@Test +public class ImagePredicatesTest { + ComputeService computeService = new ComputeServiceContextFactory().createContext("stub", "foo", "bar") + .getComputeService(); + + public void testImageId() { + Image first = Iterables.get(computeService.listImages(), 0); + assert ImagePredicates.idEquals(first.getId()).apply(first); + Image second = Iterables.get(computeService.listImages(), 1); + assert !ImagePredicates.idEquals(first.getId()).apply(second); + } + + public void testUserMetadataContains() { + Image first = Iterables.get(computeService.listImages(), 0); + first = ImageBuilder.fromImage(first).userMetadata(ImmutableMap.of("foo", "bar")).build(); + assert ImagePredicates.userMetadataContains("foo", "bar").apply(first); + Image second = Iterables.get(computeService.listImages(), 1); + second = ImageBuilder.fromImage(second).userMetadata(ImmutableMap.of("foo", "baz")).build(); + assert !ImagePredicates.userMetadataContains("foo", "bar").apply(second); + } + +} \ No newline at end of file diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/AWSEC2TemplateBuilderLiveTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/AWSEC2TemplateBuilderLiveTest.java index 3a65e66d27..459f94a515 100644 --- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/AWSEC2TemplateBuilderLiveTest.java +++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/AWSEC2TemplateBuilderLiveTest.java @@ -34,7 +34,9 @@ import org.jclouds.compute.ComputeServiceContextFactory; import org.jclouds.compute.domain.OsFamily; import org.jclouds.compute.domain.OsFamilyVersion64Bit; import org.jclouds.compute.domain.Template; +import org.jclouds.ec2.compute.predicates.EC2ImagePredicates; import org.jclouds.ec2.domain.InstanceType; +import org.jclouds.ec2.domain.RootDeviceType; import org.jclouds.logging.log4j.config.Log4JLoggingModule; import org.testng.annotations.Test; @@ -85,7 +87,7 @@ public class AWSEC2TemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest { .build(); assert (template.getImage().getProviderId().startsWith("ami-")) : template; - assertEquals(template.getImage().getOperatingSystem().getVersion(), "10.04"); + assertEquals(template.getImage().getOperatingSystem().getVersion(), "11.10"); assertEquals(template.getImage().getOperatingSystem().is64Bit(), false); assertEquals(template.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU); assertEquals(template.getImage().getUserMetadata().get("rootDeviceType"), "instance-store"); @@ -95,6 +97,24 @@ public class AWSEC2TemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest { assertEquals(template.getImage().getOperatingSystem().getArch(), "paravirtual"); } + @Test + public void testUbuntuInstanceStoreGoesM1Small() { + + Template template = context.getComputeService().templateBuilder() + .imageMatches(EC2ImagePredicates.rootDeviceType(RootDeviceType.INSTANCE_STORE)) + .osVersionMatches("1[10].[10][04]").imageDescriptionMatches("ubuntu-images").osFamily(OsFamily.UBUNTU) + .build(); + + assert (template.getImage().getProviderId().startsWith("ami-")) : template; + assertEquals(template.getImage().getOperatingSystem().getVersion(), "11.10"); + assertEquals(template.getImage().getOperatingSystem().is64Bit(), false); + assertEquals(template.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU); + assertEquals(template.getImage().getUserMetadata().get("rootDeviceType"), "instance-store"); + assertEquals(template.getLocation().getId(), "us-east-1"); + assertEquals(getCores(template.getHardware()), 1.0d); + assertEquals(template.getHardware().getId(), InstanceType.M1_SMALL); + assertEquals(template.getImage().getOperatingSystem().getArch(), "paravirtual"); + } @Test public void testTemplateBuilderCanUseImageIdAndhardwareIdAndAZ() { @@ -129,6 +149,22 @@ public class AWSEC2TemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest { assertEquals(defaultTemplate.getImage().getOperatingSystem().getArch(), "paravirtual"); } + + @Test + public void testAmazonLinuxInstanceStore() throws IOException { + + Template defaultTemplate = context.getComputeService().templateBuilder().osFamily(OsFamily.AMZN_LINUX) + .imageMatches(EC2ImagePredicates.rootDeviceType(RootDeviceType.INSTANCE_STORE)).build(); + assert (defaultTemplate.getImage().getProviderId().startsWith("ami-")) : defaultTemplate; + assertEquals(defaultTemplate.getImage().getOperatingSystem().getVersion(), "2011.02.1"); + assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(), false); + assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.AMZN_LINUX); + assertEquals(defaultTemplate.getImage().getUserMetadata().get("rootDeviceType"), "instance-store"); + assertEquals(defaultTemplate.getLocation().getId(), "us-east-1"); + assertEquals(getCores(defaultTemplate.getHardware()), 1.0d); + assertEquals(defaultTemplate.getImage().getOperatingSystem().getArch(), "paravirtual"); + } + @Test public void testFastestTemplateBuilder() throws IOException { Template fastestTemplate = context.getComputeService().templateBuilder().fastest().osFamily(OsFamily.AMZN_LINUX)