Issue 427: deltacloud refactor and image support

This commit is contained in:
Adrian Cole 2010-12-21 14:22:10 +01:00
parent d60df6cd6b
commit 946311f812
23 changed files with 800 additions and 140 deletions

View File

@ -89,10 +89,6 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions
RunInstancesOptions instanceOptions = asType(template.getHardware().getId());
// Eucalyptus currently doesn't support additional info
if (!"eucalyptus".equals(getProvider()))
instanceOptions.withAdditionalInfo(tag);
String keyPairName = createNewKeyPairUnlessUserSpecifiedOtherwise(region, tag, template.getOptions());
String placementGroupName = template.getHardware().getId().startsWith("cc") ? createNewPlacementGroupUnlessUserSpecifiedOtherwise(

View File

@ -41,7 +41,8 @@ import org.jclouds.encryption.internal.Base64;
*
* @author Adrian Cole
* @see <a
* href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/index.html?ApiReference-form-RunInstances.html"
* href=
* "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/index.html?ApiReference-form-RunInstances.html"
* />
*/
public class RunInstancesOptions extends BaseEC2RequestOptions {
@ -105,18 +106,6 @@ public class RunInstancesOptions extends BaseEC2RequestOptions {
return getFirstFormOrNull("Placement.GroupName");
}
/**
* Specifies additional information to make available to the instance(s).
*/
public RunInstancesOptions withAdditionalInfo(String info) {
formParameters.put("AdditionalInfo", checkNotNull(info, "info"));
return this;
}
String getAdditionalInfo() {
return getFirstFormOrNull("AdditionalInfo");
}
/**
* Unencoded data
*/
@ -245,14 +234,6 @@ public class RunInstancesOptions extends BaseEC2RequestOptions {
return options.inPlacementGroup(placementGroup);
}
/**
* @see RunInstancesOptions#withAdditionalInfo(String)
*/
public static RunInstancesOptions withAdditionalInfo(String additionalInfo) {
RunInstancesOptions options = new RunInstancesOptions();
return options.withAdditionalInfo(additionalInfo);
}
/**
* @see RunInstancesOptions#withUserData(byte [])
*/

View File

@ -89,66 +89,6 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
expect(strategy.createNewKeyPairUnlessUserSpecifiedOtherwise(region, tag, options)).andReturn(
systemGeneratedKeyPairName);
expect(strategy.getSecurityGroupsForTagAndOptions(region, tag, options)).andReturn(generatedGroups);
expect(strategy.getProvider()).andReturn("ec2");
expect(options.getSubnetId()).andReturn(null);
expect(options.getUserData()).andReturn(null);
// replay mocks
replay(options);
replay(template);
replay(strategy);
// run
RunInstancesOptions runOptions = strategy.execute(region, tag, template);
assertEquals(runOptions.buildQueryParameters(), ImmutableMultimap.<String, String> of());
assertEquals(
runOptions.buildFormParameters().entries(),
ImmutableMultimap.<String, String> of("InstanceType", size.getProviderId(), "AdditionalInfo", tag,
"SecurityGroup.1", generatedGroup, "KeyName", systemGeneratedKeyPairName).entries());
assertEquals(runOptions.buildMatrixParameters(), ImmutableMultimap.<String, String> of());
assertEquals(runOptions.buildRequestHeaders(), ImmutableMultimap.<String, String> of());
assertEquals(runOptions.buildStringPayload(), null);
// verify mocks
verify(options);
verify(template);
verify(strategy);
}
public void testEucalyptusDoesNotUseAdditionalInfo() throws SecurityException, NoSuchMethodException {
// setup constants
String region = Region.AP_SOUTHEAST_1;
String tag = "tag";
Hardware size = EC2HardwareBuilder.m1_small().build();
String systemGeneratedKeyPairName = "systemGeneratedKeyPair";
String generatedGroup = "group";
Set<String> generatedGroups = ImmutableSet.of(generatedGroup);
// create mocks
CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions strategy = createMock(
CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions.class,
new Method[] {
CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions.class
.getDeclaredMethod("getProvider"),
CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions.class.getDeclaredMethod(
"createNewKeyPairUnlessUserSpecifiedOtherwise", String.class, String.class,
TemplateOptions.class),
CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions.class.getDeclaredMethod(
"createNewPlacementGroupUnlessUserSpecifiedOtherwise", String.class, String.class,
TemplateOptions.class),
CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions.class.getDeclaredMethod(
"getSecurityGroupsForTagAndOptions", String.class, String.class, TemplateOptions.class) });
EC2TemplateOptions options = createMock(EC2TemplateOptions.class);
Template template = createMock(Template.class);
// setup expectations
expect(template.getHardware()).andReturn(size).atLeastOnce();
expect(template.getOptions()).andReturn(options).atLeastOnce();
expect(strategy.createNewKeyPairUnlessUserSpecifiedOtherwise(region, tag, options)).andReturn(
systemGeneratedKeyPairName);
expect(strategy.getSecurityGroupsForTagAndOptions(region, tag, options)).andReturn(generatedGroups);
expect(strategy.getProvider()).andReturn("eucalyptus");
expect(options.getSubnetId()).andReturn(null);
expect(options.getUserData()).andReturn(null);
@ -220,9 +160,9 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
assertEquals(runOptions.buildQueryParameters(), ImmutableMultimap.<String, String> of());
assertEquals(
runOptions.buildFormParameters().entries(),
ImmutableMultimap.<String, String> of("InstanceType", size.getProviderId(), "AdditionalInfo", tag,
"SecurityGroup.1", generatedGroup, "KeyName", systemGeneratedKeyPairName, "Placement.GroupName",
generatedGroup).entries());
ImmutableMultimap.<String, String> of("InstanceType", size.getProviderId(), "SecurityGroup.1",
generatedGroup, "KeyName", systemGeneratedKeyPairName, "Placement.GroupName", generatedGroup)
.entries());
assertEquals(runOptions.buildMatrixParameters(), ImmutableMultimap.<String, String> of());
assertEquals(runOptions.buildRequestHeaders(), ImmutableMultimap.<String, String> of());
assertEquals(runOptions.buildStringPayload(), null);
@ -279,9 +219,9 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
assertEquals(runOptions.buildQueryParameters(), ImmutableMultimap.<String, String> of());
assertEquals(
runOptions.buildFormParameters().entries(),
ImmutableMultimap.<String, String> of("InstanceType", size.getProviderId(), "AdditionalInfo", tag,
"SecurityGroup.1", generatedGroup, "KeyName", systemGeneratedKeyPairName, "Placement.GroupName",
generatedGroup).entries());
ImmutableMultimap.<String, String> of("InstanceType", size.getProviderId(), "SecurityGroup.1",
generatedGroup, "KeyName", systemGeneratedKeyPairName, "Placement.GroupName", generatedGroup)
.entries());
assertEquals(runOptions.buildMatrixParameters(), ImmutableMultimap.<String, String> of());
assertEquals(runOptions.buildRequestHeaders(), ImmutableMultimap.<String, String> of());
assertEquals(runOptions.buildStringPayload(), null);
@ -333,8 +273,8 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
assertEquals(runOptions.buildQueryParameters(), ImmutableMultimap.<String, String> of());
assertEquals(
runOptions.buildFormParameters().entries(),
ImmutableMultimap.<String, String> of("InstanceType", size.getProviderId(), "AdditionalInfo", tag,
"SubnetId", "1", "KeyName", systemGeneratedKeyPairName).entries());
ImmutableMultimap.<String, String> of("InstanceType", size.getProviderId(), "SubnetId", "1", "KeyName",
systemGeneratedKeyPairName).entries());
assertEquals(runOptions.buildMatrixParameters(), ImmutableMultimap.<String, String> of());
assertEquals(runOptions.buildRequestHeaders(), ImmutableMultimap.<String, String> of());
assertEquals(runOptions.buildStringPayload(), null);
@ -389,9 +329,8 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
assertEquals(runOptions.buildQueryParameters(), ImmutableMultimap.<String, String> of());
assertEquals(
runOptions.buildFormParameters().entries(),
ImmutableMultimap.<String, String> of("InstanceType", size.getProviderId(), "AdditionalInfo", tag,
"SecurityGroup.1", "group", "KeyName", systemGeneratedKeyPairName, "UserData",
Base64.encodeBytes("hello".getBytes())).entries());
ImmutableMultimap.<String, String> of("InstanceType", size.getProviderId(), "SecurityGroup.1", "group",
"KeyName", systemGeneratedKeyPairName, "UserData", Base64.encodeBytes("hello".getBytes())).entries());
assertEquals(runOptions.buildMatrixParameters(), ImmutableMultimap.<String, String> of());
assertEquals(runOptions.buildRequestHeaders(), ImmutableMultimap.<String, String> of());
assertEquals(runOptions.buildStringPayload(), null);

View File

@ -21,7 +21,6 @@ package org.jclouds.aws.ec2.options;
import static org.jclouds.aws.ec2.options.RunInstancesOptions.Builder.asType;
import static org.jclouds.aws.ec2.options.RunInstancesOptions.Builder.enableMonitoring;
import static org.jclouds.aws.ec2.options.RunInstancesOptions.Builder.withAdditionalInfo;
import static org.jclouds.aws.ec2.options.RunInstancesOptions.Builder.withDeviceName;
import static org.jclouds.aws.ec2.options.RunInstancesOptions.Builder.withKernelId;
import static org.jclouds.aws.ec2.options.RunInstancesOptions.Builder.withKeyName;
@ -99,30 +98,12 @@ public class RunInstancesOptionsTest {
withSecurityGroup(null);
}
@Test
public void testWithAdditionalInfo() {
RunInstancesOptions options = new RunInstancesOptions();
options.withAdditionalInfo("test");
assertEquals(options.buildFormParameters().get("AdditionalInfo"), Collections.singletonList("test"));
}
@Test
public void testNullWithAdditionalInfo() {
RunInstancesOptions options = new RunInstancesOptions();
assertEquals(options.buildFormParameters().get("AdditionalInfo"), Collections.EMPTY_LIST);
}
@Test
public void testWithAdditionalInfoStatic() {
RunInstancesOptions options = withAdditionalInfo("test");
assertEquals(options.buildFormParameters().get("AdditionalInfo"), Collections.singletonList("test"));
}
@Test(expectedExceptions = NullPointerException.class)
public void testWithAdditionalInfoNPE() {
withAdditionalInfo(null);
}
@Test
public void testWithUserData() {
RunInstancesOptions options = new RunInstancesOptions();

View File

@ -55,8 +55,8 @@
<jclouds.compute.blacklist-nodes>trmkrun-ccc,test.trmk-924</jclouds.compute.blacklist-nodes>
<test.deltacloud.endpoint>http://localhost:3001/api</test.deltacloud.endpoint>
<test.deltacloud.apiversion>1.0</test.deltacloud.apiversion>
<test.deltacloud.identity>FIXME</test.deltacloud.identity>
<test.deltacloud.credential>FIXME</test.deltacloud.credential>
<test.deltacloud.identity>mockuser</test.deltacloud.identity>
<test.deltacloud.credential>mockpassword</test.deltacloud.credential>
</properties>
<dependencies>
<dependency>

View File

@ -21,6 +21,7 @@ package org.jclouds.deltacloud;
import java.net.URI;
import java.util.Map;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
@ -29,12 +30,22 @@ import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import org.jclouds.deltacloud.collections.DeltacloudCollection;
import org.jclouds.deltacloud.collections.Images;
import org.jclouds.deltacloud.collections.Instances;
import org.jclouds.deltacloud.domain.Image;
import org.jclouds.deltacloud.options.CreateInstanceOptions;
import org.jclouds.deltacloud.reference.DeltacloudCollection;
import org.jclouds.deltacloud.xml.ImageHandler;
import org.jclouds.deltacloud.xml.ImagesHandler;
import org.jclouds.deltacloud.xml.LinksHandler;
import org.jclouds.http.filters.BasicAuthentication;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.EndpointParam;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.XMLResponseParser;
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import com.google.common.util.concurrent.ListenableFuture;
@ -58,12 +69,31 @@ public interface DeltacloudAsyncClient {
@XMLResponseParser(LinksHandler.class)
ListenableFuture<Map<DeltacloudCollection, URI>> getCollections();
/**
* @see DeltacloudClient#listImages
*/
@GET
@Endpoint(Images.class)
@Path("")
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
@XMLResponseParser(ImagesHandler.class)
ListenableFuture<? extends Set<Image>> listImages();
/**
* @see DeltacloudClient#getImage
*/
@GET
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
@Path("")
@XMLResponseParser(ImageHandler.class)
ListenableFuture<Image> getImage(@EndpointParam URI imageHref);
/**
* @see DeltacloudClient#createInstance
*/
@POST
@Endpoint(Instances.class)
@Path("")
ListenableFuture<String> createInstance(URI instanceCollection, @FormParam("image_id") String imageId,
CreateInstanceOptions... options);
ListenableFuture<String> createInstance(@FormParam("image_id") String imageId, CreateInstanceOptions... options);
}

View File

@ -21,11 +21,13 @@ package org.jclouds.deltacloud;
import java.net.URI;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.jclouds.concurrent.Timeout;
import org.jclouds.deltacloud.collections.DeltacloudCollection;
import org.jclouds.deltacloud.domain.Image;
import org.jclouds.deltacloud.options.CreateInstanceOptions;
import org.jclouds.deltacloud.reference.DeltacloudCollection;
/**
* Provides synchronous access to deltacloud.
@ -45,6 +47,20 @@ public interface DeltacloudClient {
*/
Map<DeltacloudCollection, URI> getCollections();
/**
* The images collection will return a set of all images available to the current user.
*
* @return images viewable to the user or empty set
*/
Set<? extends Image> listImages();
/**
*
* @param imageHref
* @return image or null, if not found
*/
Image getImage(URI imageHref);
/**
* Create a new Instance
*
@ -54,13 +70,11 @@ public interface DeltacloudClient {
* reasonable defaults. The architecture of the selected hardware profile must match the
* architecture of the specified image.
*
* @param instanceCollection
* which endpoint to create the instance in
* @param imageId
* The identifier (not URL) of the image from which to base the instance
* @param options
* includes realm, hardware profile, etc.
* @return newly-created instance including a URL to retrieve the instance in the future.
*/
String createInstance(URI instanceCollection, String imageId, CreateInstanceOptions... options);
String createInstance(String imageId, CreateInstanceOptions... options);
}

View File

@ -1,4 +1,4 @@
package org.jclouds.deltacloud.reference;
package org.jclouds.deltacloud.collections;
import static com.google.common.base.Preconditions.checkNotNull;
@ -9,7 +9,13 @@ import com.google.common.base.CaseFormat;
* @author Adrian Cole
*/
public enum DeltacloudCollection {
HARDWARE_PROFILES, INSTANCE_STATES, REALMS, IMAGES, INSTANCES, UNRECOGNIZED;
HARDWARE_PROFILES, INSTANCE_STATES, REALMS,
@Images
IMAGES,
@Instances
INSTANCES, UNRECOGNIZED;
public String value() {
return (CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_UNDERSCORE, name()));

View File

@ -0,0 +1,40 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.deltacloud.collections;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
/**
* The images collection will return a set of all images available to the current user.
*
* @author Adrian Cole
*
*/
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = { ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Qualifier
public @interface Images {
}

View File

@ -0,0 +1,40 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.deltacloud.collections;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
/**
* The instances collection will return a set of all instances available to the current user.
*
* @author Adrian Cole
*
*/
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = { ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Qualifier
public @interface Instances {
}

View File

@ -19,16 +19,33 @@
package org.jclouds.deltacloud.config;
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
import java.net.URI;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.deltacloud.DeltacloudAsyncClient;
import org.jclouds.deltacloud.DeltacloudClient;
import org.jclouds.deltacloud.collections.DeltacloudCollection;
import org.jclouds.deltacloud.collections.Images;
import org.jclouds.deltacloud.collections.Instances;
import org.jclouds.deltacloud.handlers.DeltacloudErrorHandler;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.RequiresHttp;
import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection;
import org.jclouds.http.annotation.ServerError;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.config.RestClientModule;
import org.jclouds.rest.suppliers.RetryOnTimeOutButNotOnAuthorizationExceptionSupplier;
import com.google.common.base.Supplier;
import com.google.inject.Provides;
/**
* Configures the deltacloud connection.
@ -43,7 +60,6 @@ public class DeltacloudRestClientModule extends RestClientModule<DeltacloudClien
super(DeltacloudClient.class, DeltacloudAsyncClient.class);
}
@Override
protected void bindErrorHandlers() {
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(DeltacloudErrorHandler.class);
@ -56,4 +72,38 @@ public class DeltacloudRestClientModule extends RestClientModule<DeltacloudClien
// TODO
}
protected AtomicReference<AuthorizationException> authException = new AtomicReference<AuthorizationException>();
@Provides
@Singleton
protected Supplier<Map<DeltacloudCollection, URI>> provideCollections(
@Named(PROPERTY_SESSION_INTERVAL) long seconds, final DeltacloudClient client) {
return new RetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<DeltacloudCollection, URI>>(authException,
seconds, new Supplier<Map<DeltacloudCollection, URI>>() {
@Override
public Map<DeltacloudCollection, URI> get() {
return client.getCollections();
}
});
}
/**
* since the supplier is memoized, and there are no objects created here, this doesn't need to be
* singleton.
*/
@Provides
@Images
protected URI provideImageCollection(Supplier<Map<DeltacloudCollection, URI>> collectionSupplier) {
return collectionSupplier.get().get(DeltacloudCollection.IMAGES);
}
/**
* since the supplier is memoized, and there are no objects created here, this doesn't need to be
* singleton.
*/
@Provides
@Instances
protected URI provideInstanceCollection(Supplier<Map<DeltacloudCollection, URI>> collectionSupplier) {
return collectionSupplier.get().get(DeltacloudCollection.INSTANCES);
}
}

View File

@ -0,0 +1,29 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.deltacloud.domain;
/**
*
* @author Adrian Cole
*/
public interface Architecture {
public static final String I386 = "i386";
public static final String X86_64 = "x86_64";
}

View File

@ -0,0 +1,164 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.deltacloud.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import java.net.URI;
import javax.annotation.Nullable;
/**
* An image is a platonic form of a machine. Images are not directly executable, but are a template
* for creating actual instances of machines.
*
* @author Adrian Cole
*/
public class Image {
private final URI href;
private final String id;
private final String ownerId;
@Nullable
private final String name;
@Nullable
private final String description;
private final String architecture;
public Image(URI href, String id, String ownerId, @Nullable String name, String description, String architecture) {
this.href = checkNotNull(href, "href");
this.id = checkNotNull(id, "id");
this.ownerId = checkNotNull(ownerId, "ownerId");
this.name = name;
this.description = description;
this.architecture = checkNotNull(architecture, "architecture");
}
/**
*
* @return URL to manipulate a specific image
*/
public URI getHref() {
return href;
}
/**
*
* @return A unique identifier for the image
*/
public String getId() {
return id;
}
/**
*
* @return An opaque identifier which indicates the owner of an image
*/
public String getOwnerId() {
return ownerId;
}
/**
*
* @return An optional short label describing the image
*/
@Nullable
public String getName() {
return name;
}
/**
*
* @return An optional description describing the image more fully
*/
@Nullable
public String getDescription() {
return description;
}
/**
*
* @return A description of the machine architecture of the image which may contain values such
* as: i386, x86_64
*/
public String getArchitecture() {
return architecture;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((architecture == null) ? 0 : architecture.hashCode());
result = prime * result + ((description == null) ? 0 : description.hashCode());
result = prime * result + ((href == null) ? 0 : href.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((ownerId == null) ? 0 : ownerId.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Image other = (Image) obj;
if (architecture == null) {
if (other.architecture != null)
return false;
} else if (!architecture.equals(other.architecture))
return false;
if (description == null) {
if (other.description != null)
return false;
} else if (!description.equals(other.description))
return false;
if (href == null) {
if (other.href != null)
return false;
} else if (!href.equals(other.href))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (ownerId == null) {
if (other.ownerId != null)
return false;
} else if (!ownerId.equals(other.ownerId))
return false;
return true;
}
@Override
public String toString() {
return "[href=" + href + ", id=" + id + ", ownerId=" + ownerId + ", name=" + name + ", description="
+ description + ", architecture=" + architecture + "]";
}
}

View File

@ -0,0 +1,87 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.deltacloud.xml;
import java.net.URI;
import java.util.Map;
import org.jclouds.deltacloud.domain.Image;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.util.Utils;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
/**
* @author Adrian Cole
*/
public class ImageHandler extends ParseSax.HandlerWithResult<Image> {
private StringBuilder currentText = new StringBuilder();
private URI href;
private String id;
private String ownerId;
private String name;
private String description;
private String architecture;
private Image image;
public Image getResult() {
return image;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException {
Map<String, String> attributes = Utils.cleanseAttributes(attrs);
if (qName.equals("image")) {
String href = attributes.get("href");
if (href != null) {
this.href = URI.create(href);
}
this.id = attributes.get("id");
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName.equalsIgnoreCase("owner_id")) {
this.ownerId = currentText.toString().trim();
} else if (qName.equalsIgnoreCase("name")) {
this.name = currentText.toString().trim();
} else if (qName.equalsIgnoreCase("description")) {
this.description = currentText.toString().trim();
} else if (qName.equalsIgnoreCase("architecture")) {
this.architecture = currentText.toString().trim();
} else if (qName.equalsIgnoreCase("image")) {
this.image = new Image(href, id, ownerId, name, description, architecture);
this.href = null;
this.id = null;
this.ownerId = null;
this.name = null;
this.description = null;
this.architecture = null;
}
currentText = new StringBuilder();
}
public void characters(char ch[], int start, int length) {
currentText.append(ch, start, length);
}
}

View File

@ -0,0 +1,69 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.deltacloud.xml;
import java.util.Set;
import javax.inject.Inject;
import org.jclouds.deltacloud.domain.Image;
import org.jclouds.http.functions.ParseSax;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import com.google.common.collect.Sets;
/**
* @author Adrian Cole
*/
public class ImagesHandler extends ParseSax.HandlerWithResult<Set<? extends Image>> {
private StringBuilder currentText = new StringBuilder();
private Set<Image> images = Sets.newLinkedHashSet();
private final ImageHandler imageHandler;
@Inject
public ImagesHandler(ImageHandler locationHandler) {
this.imageHandler = locationHandler;
}
public Set<? extends Image> getResult() {
return images;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
imageHandler.startElement(uri, localName, qName, attributes);
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
imageHandler.endElement(uri, localName, qName);
if (qName.equals("image") && currentText.toString().trim().equals("")) {
this.images.add(imageHandler.getResult());
}
currentText = new StringBuilder();
}
public void characters(char ch[], int start, int length) {
imageHandler.characters(ch, start, length);
currentText.append(ch, start, length);
}
}

View File

@ -22,7 +22,7 @@ package org.jclouds.deltacloud.xml;
import java.net.URI;
import java.util.Map;
import org.jclouds.deltacloud.reference.DeltacloudCollection;
import org.jclouds.deltacloud.collections.DeltacloudCollection;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.util.Utils;
import org.xml.sax.Attributes;

View File

@ -24,22 +24,34 @@ import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.Map;
import java.util.Properties;
import org.jclouds.deltacloud.collections.DeltacloudCollection;
import org.jclouds.deltacloud.config.DeltacloudRestClientModule;
import org.jclouds.deltacloud.options.CreateInstanceOptions;
import org.jclouds.deltacloud.xml.ImageHandler;
import org.jclouds.deltacloud.xml.ImagesHandler;
import org.jclouds.deltacloud.xml.LinksHandler;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.RequiresHttp;
import org.jclouds.http.filters.BasicAuthentication;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.ReturnStringIf2xx;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.RestClientTest;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.rest.RestContextSpec;
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.testng.annotations.Test;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.Iterables;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
/**
@ -75,13 +87,42 @@ public class DeltacloudAsyncClientTest extends RestClientTest<DeltacloudAsyncCli
}
public void testCreateInstance() throws SecurityException, NoSuchMethodException, IOException {
Method method = DeltacloudAsyncClient.class.getMethod("createInstance", URI.class, String.class,
CreateInstanceOptions[].class);
GeneratedHttpRequest<DeltacloudAsyncClient> httpRequest = processor.createRequest(method,
URI.create("http://localhost:3001/api/instances"), "imageId-1");
public void testListImages() throws IOException, SecurityException, NoSuchMethodException {
Method method = DeltacloudAsyncClient.class.getMethod("listImages");
HttpRequest request = processor.createRequest(method);
assertRequestLineEquals(httpRequest, "POST http://localhost:3001/api HTTP/1.1");
assertRequestLineEquals(request, "GET http://localhost:3001/api/images HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Accept: application/xml\n");
assertPayloadEquals(request, null, null, false);
assertResponseParserClassEquals(method, request, ParseSax.class);
assertSaxResponseParserClassEquals(method, ImagesHandler.class);
assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class);
checkFilters(request);
}
public void testGetImage() throws IOException, SecurityException, NoSuchMethodException {
Method method = DeltacloudAsyncClient.class.getMethod("getImage", URI.class);
HttpRequest request = processor.createRequest(method, URI.create("https://delta/image1"));
assertRequestLineEquals(request, "GET https://delta/image1 HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Accept: application/xml\n");
assertPayloadEquals(request, null, null, false);
assertResponseParserClassEquals(method, request, ParseSax.class);
assertSaxResponseParserClassEquals(method, ImageHandler.class);
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
checkFilters(request);
}
public void testCreateInstance() throws SecurityException, NoSuchMethodException, IOException {
Method method = DeltacloudAsyncClient.class.getMethod("createInstance", String.class,
CreateInstanceOptions[].class);
GeneratedHttpRequest<DeltacloudAsyncClient> httpRequest = processor.createRequest(method, "imageId-1");
assertRequestLineEquals(httpRequest, "POST http://localhost:3001/api/instances HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/xml\n");
assertPayloadEquals(httpRequest, "image_id=imageId-1", "application/x-www-form-urlencoded", false);
@ -94,12 +135,12 @@ public class DeltacloudAsyncClientTest extends RestClientTest<DeltacloudAsyncCli
}
public void testCreateInstanceWithOptions() throws SecurityException, NoSuchMethodException, IOException {
Method method = DeltacloudAsyncClient.class.getMethod("createInstance", URI.class, String.class,
Method method = DeltacloudAsyncClient.class.getMethod("createInstance", String.class,
CreateInstanceOptions[].class);
GeneratedHttpRequest<DeltacloudAsyncClient> httpRequest = processor.createRequest(method,
URI.create("http://localhost:3001/api/instances"), "imageId-1", CreateInstanceOptions.Builder.named("foo"));
GeneratedHttpRequest<DeltacloudAsyncClient> httpRequest = processor.createRequest(method, "imageId-1",
CreateInstanceOptions.Builder.named("foo"));
assertRequestLineEquals(httpRequest, "POST http://localhost:3001/api HTTP/1.1");
assertRequestLineEquals(httpRequest, "POST http://localhost:3001/api/instances HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/xml\n");
assertPayloadEquals(httpRequest, "image_id=imageId-1&name=foo", "application/x-www-form-urlencoded", false);
@ -123,6 +164,32 @@ public class DeltacloudAsyncClientTest extends RestClientTest<DeltacloudAsyncCli
};
}
@Override
protected Module createModule() {
return new DeltacloudRestClientModuleExtension();
}
@RequiresHttp
@ConfiguresRestClient
public static class DeltacloudRestClientModuleExtension extends DeltacloudRestClientModule {
@Override
protected Supplier<Map<DeltacloudCollection, URI>> provideCollections(long seconds, DeltacloudClient client) {
return Suppliers.ofInstance(null);
}
@Override
protected URI provideImageCollection(Supplier<Map<DeltacloudCollection, URI>> collectionSupplier) {
return URI.create("http://localhost:3001/api/images");
}
@Override
protected URI provideInstanceCollection(Supplier<Map<DeltacloudCollection, URI>> collectionSupplier) {
return URI.create("http://localhost:3001/api/instances");
}
}
@Override
public RestContextSpec<DeltacloudClient, DeltacloudAsyncClient> createContextSpec() {
Properties props = new Properties();

View File

@ -20,14 +20,18 @@
package org.jclouds.deltacloud;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import java.net.URI;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.jclouds.Constants;
import org.jclouds.deltacloud.reference.DeltacloudCollection;
import org.jclouds.deltacloud.collections.DeltacloudCollection;
import org.jclouds.deltacloud.domain.Image;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.RestContextFactory;
@ -100,6 +104,17 @@ public class DeltacloudClientLiveTest {
assert (links.get(link) != null) : link;
}
public void testListAndGetImages() throws Exception {
Set<? extends Image> response = client.listImages();
assert null != response;
long imageCount = response.size();
assertTrue(imageCount >= 0);
for (Image image : response) {
Image newDetails = client.getImage(image.getHref());
assertEquals(image, newDetails);
}
}
@Test
public void testCreateInstance() throws Exception {
// TODO

View File

@ -25,7 +25,7 @@ import java.io.InputStream;
import java.net.URI;
import java.util.Map;
import org.jclouds.deltacloud.reference.DeltacloudCollection;
import org.jclouds.deltacloud.collections.DeltacloudCollection;
import org.jclouds.deltacloud.xml.LinksHandler;
import org.jclouds.http.functions.BaseHandlerTest;
import org.testng.annotations.Test;

View File

@ -0,0 +1,65 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.deltacloud.xml;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.net.URI;
import org.jclouds.deltacloud.domain.Image;
import org.jclouds.deltacloud.xml.ImageHandler;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.config.SaxParserModule;
import org.testng.annotations.Test;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
* Tests behavior of {@code ImageHandler}
*
* @author Adrian Cole
*/
@Test(groups = "unit")
public class ImageHandlerTest {
static ParseSax<Image> createParser() {
Injector injector = Guice.createInjector(new SaxParserModule());
ParseSax<Image> parser = (ParseSax<Image>) injector.getInstance(ParseSax.Factory.class).create(
injector.getInstance(ImageHandler.class));
return parser;
}
public static Image parseImage() {
return parseImage("/test_get_image.xml");
}
public static Image parseImage(String resource) {
InputStream is = ImageHandlerTest.class.getResourceAsStream(resource);
return createParser().parse(is);
}
public void test() {
Image expects = new Image(URI.create("http://fancycloudprovider.com/api/images/img1"), "img1", "fedoraproject",
"Fedora 10", "Fedora 10", "x86_64");
assertEquals(parseImage(), expects);
}
}

View File

@ -0,0 +1,60 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.deltacloud.xml;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.net.URI;
import java.util.Set;
import org.jclouds.deltacloud.domain.Image;
import org.jclouds.deltacloud.xml.ImagesHandler;
import org.jclouds.http.functions.BaseHandlerTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
/**
* Tests behavior of {@code ImagesHandler}
*
* @author Adrian Cole
*/
@Test(groups = "unit")
public class ImagesHandlerTest extends BaseHandlerTest {
@Test
public void test() {
InputStream is = getClass().getResourceAsStream("/test_list_images.xml");
Set<? extends Image> expects = ImmutableSet.of(
new Image(URI.create("http://fancycloudprovider.com/api/images/img1"), "img1", "fedoraproject", "Fedora 10",
"Fedora 10", "x86_64"), new Image(URI.create("http://fancycloudprovider.com/api/images/img2"), "img2",
"fedoraproject", "Fedora 10", "Fedora 10", "i386"),
new Image(URI.create("http://fancycloudprovider.com/api/images/img3"), "img3", "ted", "JBoss", "JBoss",
"i386"));
System.out.println(factory);
System.out.println(injector);
// not sure why this isn't always automatically called from surefire.
setUpInjector();
assertEquals(factory.create(injector.getInstance(ImagesHandler.class)).parse(is), expects);
}
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<image href="http://fancycloudprovider.com/api/images/img1" id='img1'>
<owner_id>fedoraproject</owner_id>
<name>Fedora 10</name>
<description>Fedora 10</description>
<architecture>x86_64</architecture>
</image>

View File

@ -0,0 +1,20 @@
<images>
<image href="http://fancycloudprovider.com/api/images/img1" id='img1'>
<owner_id>fedoraproject</owner_id>
<name>Fedora 10</name>
<description>Fedora 10</description>
<architecture>x86_64</architecture>
</image>
<image href="http://fancycloudprovider.com/api/images/img2" id='img2'>
<owner_id>fedoraproject</owner_id>
<name>Fedora 10</name>
<description>Fedora 10</description>
<architecture>i386</architecture>
</image>
<image href="http://fancycloudprovider.com/api/images/img3" id='img3'>
<owner_id>ted</owner_id>
<name>JBoss</name>
<description>JBoss</description>
<architecture>i386</architecture>
</image>
</images>