From 38bfb906d1d2f5443acb93f7e89db36c5dcbdef0 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Fri, 18 May 2012 19:56:20 -0700 Subject: [PATCH] cloudservers and aws-ec2 work with tags now --- .../functions/ServerToNodeMetadata.java | 3 +- .../CloudServersComputeServiceAdapter.java | 5 +- .../compute/util/ComputeServiceUtils.java | 52 +++++++++++++++++++ .../compute/util/ComputeServiceUtilsTest.java | 28 ++++++++++ .../AWSRunningInstanceToNodeMetadata.java | 10 ++-- .../AWSEC2CreateNodesInGroupThenAddToSet.java | 7 +-- .../compute/AWSEC2ComputeServiceLiveTest.java | 2 + 7 files changed, 96 insertions(+), 11 deletions(-) diff --git a/apis/cloudservers/src/main/java/org/jclouds/cloudservers/compute/functions/ServerToNodeMetadata.java b/apis/cloudservers/src/main/java/org/jclouds/cloudservers/compute/functions/ServerToNodeMetadata.java index dc8ee59659..e63f2ab336 100644 --- a/apis/cloudservers/src/main/java/org/jclouds/cloudservers/compute/functions/ServerToNodeMetadata.java +++ b/apis/cloudservers/src/main/java/org/jclouds/cloudservers/compute/functions/ServerToNodeMetadata.java @@ -20,6 +20,7 @@ package org.jclouds.cloudservers.compute.functions; import static com.google.common.base.Preconditions.checkNotNull; import static org.jclouds.compute.util.ComputeServiceUtils.parseGroupFromName; +import static org.jclouds.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromCommaDelimitedValue; import java.util.Map; import java.util.NoSuchElementException; @@ -108,7 +109,7 @@ public class ServerToNodeMetadata implements Function { builder.hostname(from.getName()); builder.location(new LocationBuilder().scope(LocationScope.HOST).id(from.getHostId()).description( from.getHostId()).parent(location.get()).build()); - builder.userMetadata(from.getMetadata()); + addMetadataAndParseTagsFromCommaDelimitedValue(builder, from.getMetadata()); builder.group(parseGroupFromName(from.getName())); builder.imageId(from.getImageId() + ""); builder.operatingSystem(parseOperatingSystem(from)); diff --git a/apis/cloudservers/src/main/java/org/jclouds/cloudservers/compute/strategy/CloudServersComputeServiceAdapter.java b/apis/cloudservers/src/main/java/org/jclouds/cloudservers/compute/strategy/CloudServersComputeServiceAdapter.java index 4ff7c642f5..df7a956be2 100644 --- a/apis/cloudservers/src/main/java/org/jclouds/cloudservers/compute/strategy/CloudServersComputeServiceAdapter.java +++ b/apis/cloudservers/src/main/java/org/jclouds/cloudservers/compute/strategy/CloudServersComputeServiceAdapter.java @@ -21,6 +21,7 @@ package org.jclouds.cloudservers.compute.strategy; import static com.google.common.base.Preconditions.checkNotNull; import static org.jclouds.cloudservers.options.CreateServerOptions.Builder.withMetadata; import static org.jclouds.cloudservers.options.ListOptions.Builder.withDetails; +import static org.jclouds.compute.util.ComputeServiceUtils.metadataAndTagsAsCommaDelimitedValue; import javax.inject.Inject; import javax.inject.Singleton; @@ -59,11 +60,13 @@ public class CloudServersComputeServiceAdapter implements ComputeServiceAdapter< Template template) { Server server = client .createServer(name, Integer.parseInt(template.getImage().getProviderId()), Integer.parseInt(template - .getHardware().getProviderId()), withMetadata(template.getOptions().getUserMetadata())); + .getHardware().getProviderId()), withMetadata(metadataAndTagsAsCommaDelimitedValue(template.getOptions()))); return new NodeAndInitialCredentials(server, server.getId() + "", LoginCredentials.builder().password( server.getAdminPass()).build()); } + + @Override public Iterable listHardwareProfiles() { diff --git a/compute/src/main/java/org/jclouds/compute/util/ComputeServiceUtils.java b/compute/src/main/java/org/jclouds/compute/util/ComputeServiceUtils.java index b5be626e57..10d7ced23c 100644 --- a/compute/src/main/java/org/jclouds/compute/util/ComputeServiceUtils.java +++ b/compute/src/main/java/org/jclouds/compute/util/ComputeServiceUtils.java @@ -19,12 +19,15 @@ package org.jclouds.compute.util; import static com.google.common.base.Preconditions.checkState; +import static com.google.common.base.Predicates.equalTo; +import static com.google.common.base.Predicates.not; import static com.google.common.base.Throwables.getStackTraceAsString; import static com.google.common.collect.Iterables.concat; import static com.google.common.collect.Iterables.filter; import static com.google.common.collect.Iterables.find; import static com.google.common.collect.Iterables.size; import static com.google.common.collect.Iterables.transform; +import static com.google.common.collect.Maps.*; import static org.jclouds.scriptbuilder.domain.Statements.pipeHttpResponseToBash; import java.net.URI; @@ -39,10 +42,12 @@ import org.jclouds.compute.ComputeServiceContextBuilder; import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.NodeMetadataBuilder; import org.jclouds.compute.domain.OsFamily; import org.jclouds.compute.domain.Processor; import org.jclouds.compute.domain.Volume; import org.jclouds.compute.predicates.RetryIfSocketNotYetOpen; +import org.jclouds.compute.options.TemplateOptions; import org.jclouds.http.HttpRequest; import org.jclouds.net.IPSocket; import org.jclouds.rest.Providers; @@ -50,8 +55,12 @@ import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statements; import com.google.common.base.Function; +import com.google.common.base.Joiner; import com.google.common.base.Predicate; +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; +import com.google.common.collect.ImmutableMap.Builder; /** * @@ -200,6 +209,49 @@ public class ComputeServiceUtils { checkState(size(concat(node.getPublicAddresses(), node.getPrivateAddresses())) > 0, "node does not have IP addresses configured: " + node); } + + /** + * For cloud apis that have a pattern of using empty strings as tags, return a map that contains + * that. + */ + public static Map metadataAndTagsAsValuesOfEmptyString(TemplateOptions options) { + Builder builder = ImmutableMap. builder(); + builder.putAll(options.getUserMetadata()); + for (String tag : options.getTags()) + builder.put(tag, ""); + return builder.build(); + } + + /** + * @see #metadataAndTagsAsValuesOfEmptyString + */ + public static NodeMetadataBuilder addMetadataAndParseTagsFromValuesOfEmptyString(NodeMetadataBuilder builder, + Map map) { + return builder.tags(filterValues(map, equalTo("")).keySet()).userMetadata(filterValues(map, not(equalTo("")))); + } + + /** + * For cloud apis that need to namespace tags as the value of the key {@code jclouds.tags} + */ + public static Map metadataAndTagsAsCommaDelimitedValue(TemplateOptions options) { + Builder builder = ImmutableMap. builder(); + builder.putAll(options.getUserMetadata()); + if (options.getTags().size() > 0) + builder.put("jclouds.tags", Joiner.on(',').join(options.getTags())); + return builder.build(); + } + + /** + * @see #metadataAndTagsAsCommaDelimitedValue + */ + public static NodeMetadataBuilder addMetadataAndParseTagsFromCommaDelimitedValue(NodeMetadataBuilder builder, + Map map) { + String tagString = map.get("jclouds.tags"); + if (tagString != null) + builder.tags(Splitter.on(',').split(tagString)); + builder.userMetadata(filterKeys(map, not(equalTo("jclouds.tags")))); + return builder; + } public static String parseVersionOrReturnEmptyString(org.jclouds.compute.domain.OsFamily family, String in, Map> osVersionMap) { diff --git a/compute/src/test/java/org/jclouds/compute/util/ComputeServiceUtilsTest.java b/compute/src/test/java/org/jclouds/compute/util/ComputeServiceUtilsTest.java index 5007f6ccf6..7ae9763a82 100644 --- a/compute/src/test/java/org/jclouds/compute/util/ComputeServiceUtilsTest.java +++ b/compute/src/test/java/org/jclouds/compute/util/ComputeServiceUtilsTest.java @@ -20,6 +20,7 @@ package org.jclouds.compute.util; import static org.jclouds.compute.util.ComputeServiceUtils.parseGroupFromName; import static org.jclouds.compute.util.ComputeServiceUtils.parseVersionOrReturnEmptyString; +import static org.jclouds.compute.util.ComputeServiceUtils.*; import static org.testng.Assert.assertEquals; import java.net.URI; @@ -27,13 +28,16 @@ import java.util.Map; import org.jclouds.compute.config.BaseComputeServiceContextModule; import org.jclouds.compute.domain.OsFamily; +import org.jclouds.compute.options.TemplateOptions; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.http.HttpRequest; import org.jclouds.json.Json; import org.jclouds.json.config.GsonModule; import org.testng.annotations.Test; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.ImmutableSet; import com.google.inject.Guice; /** @@ -53,6 +57,30 @@ public class ComputeServiceUtilsTest { assertEquals(parseGroupFromName("gogrid--849"), "gogrid-"); } + @Test + public void testMetadataAndTagsAsValuesOfEmptyString() { + TemplateOptions options = TemplateOptions.Builder.tags(ImmutableSet.of("tag")).userMetadata(ImmutableMap.of("foo", "bar")); + assertEquals(metadataAndTagsAsValuesOfEmptyString(options), ImmutableMap.of("foo", "bar", "tag", "")); + } + + @Test + public void testMetadataAndTagsAsCommaDelimitedValue() { + TemplateOptions options = TemplateOptions.Builder.tags(ImmutableSet.of("tag")).userMetadata(ImmutableMap.of("foo", "bar")); + assertEquals(metadataAndTagsAsCommaDelimitedValue(options), ImmutableMap.of("foo", "bar", "jclouds.tags", "tag")); + } + + @Test + public void testMetadataAndTagsAsValuesOfEmptyStringNoTags() { + TemplateOptions options = TemplateOptions.Builder.userMetadata(ImmutableMap.of("foo", "bar")); + assertEquals(metadataAndTagsAsValuesOfEmptyString(options), ImmutableMap.of("foo", "bar")); + } + + @Test + public void testMetadataAndTagsAsCommaDelimitedValueNoTags() { + TemplateOptions options = TemplateOptions.Builder.userMetadata(ImmutableMap.of("foo", "bar")); + assertEquals(metadataAndTagsAsCommaDelimitedValue(options), ImmutableMap.of("foo", "bar")); + } + @Test public void testParseVersionOrReturnEmptyStringUbuntu1004() { assertEquals(parseVersionOrReturnEmptyString(OsFamily.UBUNTU, "Ubuntu 10.04", map), "10.04"); diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/functions/AWSRunningInstanceToNodeMetadata.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/functions/AWSRunningInstanceToNodeMetadata.java index 66ba9e35fc..e27322da4d 100644 --- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/functions/AWSRunningInstanceToNodeMetadata.java +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/functions/AWSRunningInstanceToNodeMetadata.java @@ -18,9 +18,7 @@ */ package org.jclouds.aws.ec2.compute.functions; -import static com.google.common.base.Predicates.equalTo; -import static com.google.common.base.Predicates.not; -import static com.google.common.collect.Maps.filterValues; +import static org.jclouds.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromValuesOfEmptyString; import java.util.Map; import java.util.Set; @@ -85,8 +83,8 @@ public class AWSRunningInstanceToNodeMetadata extends RunningInstanceToNodeMetad @Override protected NodeMetadataBuilder buildInstance(RunningInstance instance, NodeMetadataBuilder builder) { AWSRunningInstance awsInstance = AWSRunningInstance.class.cast(instance); - Map tags = awsInstance.getTags(); - return super.buildInstance(instance, builder).name(tags.get("Name")).tags( - filterValues(tags, equalTo("")).keySet()).userMetadata(filterValues(tags, not(equalTo("")))); + builder.name(awsInstance.getTags().get("Name")); + addMetadataAndParseTagsFromValuesOfEmptyString(builder, awsInstance.getTags()); + return super.buildInstance(instance, builder); } } diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/strategy/AWSEC2CreateNodesInGroupThenAddToSet.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/strategy/AWSEC2CreateNodesInGroupThenAddToSet.java index 04f83f6a19..fdfbcf8e72 100644 --- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/strategy/AWSEC2CreateNodesInGroupThenAddToSet.java +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/strategy/AWSEC2CreateNodesInGroupThenAddToSet.java @@ -21,6 +21,7 @@ package org.jclouds.aws.ec2.compute.strategy; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.Iterables.transform; import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_GENERATE_INSTANCE_NAMES; +import static org.jclouds.compute.util.ComputeServiceUtils.metadataAndTagsAsValuesOfEmptyString; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; @@ -100,6 +101,7 @@ public class AWSEC2CreateNodesInGroupThenAddToSet extends EC2CreateNodesInGroupT @Override protected Iterable createNodesInRegionAndZone(String region, String zone, String group, int count, Template template, RunInstancesOptions instanceOptions) { + Map tags = metadataAndTagsAsValuesOfEmptyString(template.getOptions()); Float spotPrice = getSpotPriceOrNull(template.getOptions()); if (spotPrice != null) { LaunchSpecification spec = AWSRunInstancesOptions.class.cast(instanceOptions).getLaunchSpecificationBuilder() @@ -108,12 +110,11 @@ public class AWSEC2CreateNodesInGroupThenAddToSet extends EC2CreateNodesInGroupT if (logger.isDebugEnabled()) logger.debug(">> requesting %d spot instances region(%s) price(%f) spec(%s) options(%s)", count, region, spotPrice, spec, options); - - return addTagsToInstancesInRegion(template.getOptions().getUserMetadata(), transform(client + return addTagsToInstancesInRegion(tags, transform(client .getSpotInstanceServices().requestSpotInstancesInRegion(region, spotPrice, count, spec, options), spotConverter), region, group); } else { - return addTagsToInstancesInRegion(template.getOptions().getUserMetadata(), super.createNodesInRegionAndZone( + return addTagsToInstancesInRegion(tags, super.createNodesInRegionAndZone( region, zone, group, count, template, instanceOptions), region, group); } diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeServiceLiveTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeServiceLiveTest.java index 20a35d7f6a..0c6112dafe 100644 --- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeServiceLiveTest.java +++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeServiceLiveTest.java @@ -106,6 +106,7 @@ public class AWSEC2ComputeServiceLiveTest extends EC2ComputeServiceLiveTest { Date before = new Date(); ImmutableMap userMetadata = ImmutableMap. of("Name", group); + ImmutableSet tags = ImmutableSet. of(group); // note that if you change the location, you must also specify image parameters Template template = client.templateBuilder().locationId(region).osFamily(AMZN_LINUX).os64Bit(true).build(); @@ -142,6 +143,7 @@ public class AWSEC2ComputeServiceLiveTest extends EC2ComputeServiceLiveTest { assertEquals(first.getName(), group); checkUserMetadataInNodeEquals(first, userMetadata); + checkTagsInNodeEquals(first, tags); assert first.getCredentials() != null : first; assert first.getCredentials().identity != null : first;