JCLOUDS-160: Support tags in EC2 images

Based on the work made by Brock Noland
This commit is contained in:
Ignasi Barrera 2013-07-05 00:43:47 +02:00
parent 8db0218cf7
commit bbfec4a990
6 changed files with 99 additions and 13 deletions

View File

@ -59,6 +59,7 @@ public class Image implements Comparable<Image> {
@Nullable
private final String rootDeviceName;
private final Map<String, EbsBlockDevice> ebsBlockDevices = Maps.newHashMap();
private final Map<String, String> tags = Maps.newLinkedHashMap();
private final VirtualizationType virtualizationType;
public VirtualizationType getVirtualizationType() {
@ -76,7 +77,7 @@ public class Image implements Comparable<Image> {
ImageType imageType, boolean isPublic, Iterable<String> productCodes, @Nullable String kernelId,
@Nullable String platform, @Nullable String ramdiskId, RootDeviceType rootDeviceType,
@Nullable String rootDeviceName, Map<String, EbsBlockDevice> ebsBlockDevices,
VirtualizationType virtualizationType, Hypervisor hypervisor) {
Map<String, String> tags, VirtualizationType virtualizationType, Hypervisor hypervisor) {
this.region = checkNotNull(region, "region");
this.architecture = architecture;
this.imageId = checkNotNull(imageId, "imageId");
@ -95,6 +96,7 @@ public class Image implements Comparable<Image> {
this.ramdiskId = ramdiskId;
this.rootDeviceType = checkNotNull(rootDeviceType, "rootDeviceType");
this.ebsBlockDevices.putAll(checkNotNull(ebsBlockDevices, "ebsBlockDevices"));
this.tags.putAll(checkNotNull(tags, "tags"));
this.virtualizationType = checkNotNull(virtualizationType, "virtualizationType");
this.hypervisor = checkNotNull(hypervisor, "hypervisor");
}
@ -346,6 +348,10 @@ public class Image implements Comparable<Image> {
return ebsBlockDevices;
}
public Map<String, String> getTags() {
return tags;
}
@Override
public int hashCode() {
final int prime = 31;
@ -353,6 +359,7 @@ public class Image implements Comparable<Image> {
result = prime * result + ((architecture == null) ? 0 : architecture.hashCode());
result = prime * result + ((description == null) ? 0 : description.hashCode());
result = prime * result + ((ebsBlockDevices == null) ? 0 : ebsBlockDevices.hashCode());
result = prime * result + ((tags == null) ? 0 : tags.hashCode());
result = prime * result + ((imageId == null) ? 0 : imageId.hashCode());
result = prime * result + ((imageLocation == null) ? 0 : imageLocation.hashCode());
result = prime * result + ((imageOwnerId == null) ? 0 : imageOwnerId.hashCode());
@ -395,6 +402,11 @@ public class Image implements Comparable<Image> {
return false;
} else if (!ebsBlockDevices.equals(other.ebsBlockDevices))
return false;
if (tags == null) {
if (other.tags != null)
return false;
} else if (!tags.equals(other.tags))
return false;
if (imageId == null) {
if (other.imageId != null)
return false;
@ -478,7 +490,7 @@ public class Image implements Comparable<Image> {
+ ", kernelId=" + kernelId + ", name=" + name + ", platform=" + platform + ", productCodes="
+ productCodes + ", ramdiskId=" + ramdiskId + ", region=" + region + ", rootDeviceName="
+ rootDeviceName + ", rootDeviceType=" + rootDeviceType + ", virtualizationType=" + virtualizationType
+ ", hypervisor=" + hypervisor + "]";
+ ", hypervisor=" + hypervisor + ", tags=" + tags + "]";
}
}

View File

@ -17,6 +17,7 @@
package org.jclouds.ec2.xml;
import static org.jclouds.util.SaxUtils.currentOrNull;
import static org.jclouds.util.SaxUtils.equalsOrSuffix;
import java.util.Map;
import java.util.Set;
@ -54,8 +55,9 @@ import com.google.common.collect.Sets;
public class DescribeImagesResponseHandler extends ParseSax.HandlerForGeneratedRequestWithResult<Set<Image>> {
@Inject
public DescribeImagesResponseHandler(@Region Supplier<String> defaultRegion) {
public DescribeImagesResponseHandler(@Region Supplier<String> defaultRegion, TagSetHandler tagSetHandler) {
this.defaultRegion = defaultRegion;
this.tagSetHandler = tagSetHandler;
}
@Resource
@ -64,6 +66,7 @@ public class DescribeImagesResponseHandler extends ParseSax.HandlerForGeneratedR
protected Set<Image> contents = Sets.newLinkedHashSet();
private StringBuilder currentText = new StringBuilder();
private final Supplier<String> defaultRegion;
private final TagSetHandler tagSetHandler;
private Architecture architecture;
private String name;
@ -81,8 +84,10 @@ public class DescribeImagesResponseHandler extends ParseSax.HandlerForGeneratedR
private String ramdiskId;
private boolean inProductCodes;
private boolean inBlockDeviceMapping;
private boolean inTagSet;
private RootDeviceType rootDeviceType = RootDeviceType.INSTANCE_STORE;
private Map<String, EbsBlockDevice> ebsBlockDevices = Maps.newHashMap();
private Map<String, String> tags = Maps.newLinkedHashMap();
private String deviceName;
private String snapshotId;
private VirtualizationType virtualizationType = VirtualizationType.PARAVIRTUAL;
@ -102,10 +107,21 @@ public class DescribeImagesResponseHandler extends ParseSax.HandlerForGeneratedR
inProductCodes = true;
} else if (qName.equals("blockDeviceMapping")) {
inBlockDeviceMapping = true;
} else if (equalsOrSuffix(qName, "tagSet")) {
inTagSet = true;
}
if (inTagSet) {
tagSetHandler.startElement(uri, name, qName, attrs);
}
}
public void endElement(String uri, String name, String qName) {
if (equalsOrSuffix(qName, "tagSet")) {
inTagSet = false;
tags = tagSetHandler.getResult();
} else if (inTagSet) {
tagSetHandler.endElement(uri, name, qName);
}
if (qName.equals("architecture")) {
architecture = Architecture.fromValue(currentText.toString().trim());
// Nova Diablo uses the wrong name for this field
@ -161,14 +177,14 @@ public class DescribeImagesResponseHandler extends ParseSax.HandlerForGeneratedR
this.snapshotId = null;
this.volumeSize = 0;
this.deleteOnTermination = true;
} else if (!inProductCodes) {
} else if (!inTagSet && !inProductCodes) {
try {
String region = getRequest() != null ? AWSUtils.findRegionInArgsOrNull(getRequest()) : null;
if (region == null)
region = defaultRegion.get();
contents.add(new Image(region, architecture, this.name, description, imageId, imageLocation,
imageOwnerId, imageState, rawState, imageType, isPublic, productCodes, kernelId, platform,
ramdiskId, rootDeviceType, rootDeviceName, ebsBlockDevices, virtualizationType, hypervisor));
ramdiskId, rootDeviceType, rootDeviceName, ebsBlockDevices, tags, virtualizationType, hypervisor));
} catch (NullPointerException e) {
logger.warn(e, "malformed image: %s", imageId);
}
@ -198,6 +214,10 @@ public class DescribeImagesResponseHandler extends ParseSax.HandlerForGeneratedR
}
public void characters(char ch[], int start, int length) {
currentText.append(ch, start, length);
if (inTagSet) {
tagSetHandler.characters(ch, start, length);
} else {
currentText.append(ch, start, length);
}
}
}

View File

@ -59,7 +59,7 @@ public class DescribeImagesResponseHandlerTest {
"ec2-public-images/fedora-8-i386-base-v1.04.manifest.xml", "206029621532", ImageState.AVAILABLE, "available",
ImageType.MACHINE, false, Sets.<String> newHashSet("9961934F"), "aki-4438dd2d", null, "ari-4538dd2c",
RootDeviceType.INSTANCE_STORE, null, ImmutableMap.<String, EbsBlockDevice> of(),
VirtualizationType.PARAVIRTUAL, Hypervisor.XEN));
ImmutableMap.<String, String> of(), VirtualizationType.PARAVIRTUAL, Hypervisor.XEN));
Set<Image> result = parseImages("/describe_images.xml");
@ -73,7 +73,7 @@ public class DescribeImagesResponseHandlerTest {
"aws-solutions-amis/SqlSvrStd2003r2-x86_64-Win_SFWBasic5.1-v1.0.manifest.xml", "771350841976",
ImageState.AVAILABLE, "available", ImageType.MACHINE, true, Sets.<String> newHashSet("5771E9A6"), null, "windows",
null, RootDeviceType.INSTANCE_STORE, null, ImmutableMap.<String, EbsBlockDevice> of(),
VirtualizationType.PARAVIRTUAL, Hypervisor.XEN));
ImmutableMap.<String, String> of(), VirtualizationType.PARAVIRTUAL, Hypervisor.XEN));
Set<Image> result = parseImages("/describe_images_windows.xml");
@ -89,7 +89,7 @@ public class DescribeImagesResponseHandlerTest {
ImageState.AVAILABLE, "available", ImageType.MACHINE, true, Sets.<String> newHashSet(), null, "windows", null,
RootDeviceType.EBS, "/dev/sda1", ImmutableMap.<String, EbsBlockDevice> of("/dev/sda1",
new EbsBlockDevice("snap-d01272b9", 30, true), "xvdf", new EbsBlockDevice("snap-d31272ba", 250,
false)), VirtualizationType.HVM, Hypervisor.XEN));
false)), ImmutableMap.<String, String> of(), VirtualizationType.HVM, Hypervisor.XEN));
Set<Image> result = parseImages("/describe_images_ebs.xml");
@ -98,12 +98,29 @@ public class DescribeImagesResponseHandlerTest {
assertEquals(get(result, 0).getRawState(), "available");
}
public void testTags() {
Set<Image> contents = ImmutableSet.of(new Image("us-east-1", Architecture.I386, null, null, "ami-be3adfd7",
"ec2-public-images/fedora-8-i386-base-v1.04.manifest.xml", "206029621532", ImageState.AVAILABLE, "available",
ImageType.MACHINE, false, Sets.<String> newHashSet("9961934F"), "aki-4438dd2d", null, "ari-4538dd2c",
RootDeviceType.INSTANCE_STORE, null, ImmutableMap.<String, EbsBlockDevice> of(),
ImmutableMap.<String, String> of("Name", "Some machine name", "Second", "Second value"),
VirtualizationType.PARAVIRTUAL, Hypervisor.XEN));
Set<Image> result = parseImages("/describe_images_tags.xml");
assertEquals(result.toString(), contents.toString());
assertEquals(get(result, 0).getImageState(), ImageState.AVAILABLE);
assertEquals(get(result, 0).getRawState(), "available");
assertEquals(get(result, 0).getTags().get("Name"), "Some machine name");
assertEquals(get(result, 0).getTags().get("Second"), "Second value");
}
public void testDiabloWithIncorrectDisplayNameField() {
Set<Image> contents = ImmutableSet.of(new Image("us-east-1", Architecture.X86_64, "CentOS 6.2 Server 64-bit 20120125", "", "ami-0000054e",
"local (CentOS 6.2 Server 64-bit 20120125)", "", ImageState.AVAILABLE, "available",
ImageType.MACHINE, true, Sets.<String> newHashSet(), "aki-0000054c", null, "ari-0000054d",
RootDeviceType.INSTANCE_STORE, "/dev/sda1", ImmutableMap.<String, EbsBlockDevice> of(),
VirtualizationType.PARAVIRTUAL, Hypervisor.XEN));
ImmutableMap.<String, String> of(), VirtualizationType.PARAVIRTUAL, Hypervisor.XEN));
Set<Image> result = parseImages("/describe_images_nova.xml");

View File

@ -0,0 +1,33 @@
<DescribeImagesResponse xmlns="http://ec2.amazonaws.com/doc/2009-11-30/">
<imagesSet>
<item>
<imageId>ami-be3adfd7</imageId>
<imageLocation>ec2-public-images/fedora-8-i386-base-v1.04.manifest.xml</imageLocation>
<imageState>available</imageState>
<imageOwnerId>206029621532</imageOwnerId>
<isPublic>false</isPublic>
<productCodes>
<item>
<productCode>9961934F</productCode>
</item>
</productCodes>
<architecture>i386</architecture>
<imageType>machine</imageType>
<kernelId>aki-4438dd2d</kernelId>
<ramdiskId>ari-4538dd2c</ramdiskId>
<rootDeviceType>instance-store</rootDeviceType>
<blockDeviceMapping />
<virtualizationType>paravirtual</virtualizationType>
<tagSet>
<item>
<key>Name</key>
<value>Some machine name</value>
</item>
<item>
<key>Second</key>
<value>Second value</value>
</item>
</tagSet>
</item>
</imagesSet>
</DescribeImagesResponse>

View File

@ -23,6 +23,7 @@ import javax.inject.Inject;
import org.jclouds.ec2.domain.Image;
import org.jclouds.ec2.domain.Image.ImageType;
import org.jclouds.ec2.xml.DescribeImagesResponseHandler;
import org.jclouds.ec2.xml.TagSetHandler;
import org.jclouds.location.Region;
import com.google.common.base.Predicate;
@ -37,8 +38,8 @@ import com.google.common.collect.Iterables;
*/
public class NovaDescribeImagesResponseHandler extends DescribeImagesResponseHandler {
@Inject
public NovaDescribeImagesResponseHandler(@Region Supplier<String> defaultRegion) {
super(defaultRegion);
public NovaDescribeImagesResponseHandler(@Region Supplier<String> defaultRegion, TagSetHandler tagSetHandler) {
super(defaultRegion, tagSetHandler);
}
public Set<Image> getResult() {

View File

@ -100,9 +100,12 @@ public class AWSEC2ReviseParsedImageTest {
RootDeviceType rootDeviceType = RootDeviceType.EBS;
String rootDeviceName = "";
Map<String, Image.EbsBlockDevice> ebsBlockDevices = ImmutableMap.of();
Map<String, String> tags = ImmutableMap.of();
VirtualizationType virtualizationType = VirtualizationType.HVM;
Hypervisor hypervisor = Hypervisor.XEN;
Image from = new Image(region, architecture, imageName, description, imageId, imageOwnerId + "/" + imageName, imageOwnerId, imageState, "available", imageType, isPublic, productCodes, kernelId, platform, ramdiskId, rootDeviceType, rootDeviceName, ebsBlockDevices, virtualizationType, hypervisor);
Image from = new Image(region, architecture, imageName, description, imageId, imageOwnerId + "/" + imageName,
imageOwnerId, imageState, "available", imageType, isPublic, productCodes, kernelId, platform, ramdiskId,
rootDeviceType, rootDeviceName, ebsBlockDevices, tags, virtualizationType, hypervisor);
return from;
}
}