openstack-nova: Adding Volume Types extension

This commit is contained in:
Adam Lowe 2012-05-11 15:27:33 +01:00
parent 987f2f93c6
commit 95399121bd
13 changed files with 986 additions and 10 deletions

View File

@ -173,4 +173,11 @@ public interface NovaAsyncClient {
Optional<QuotaClassAsyncClient> getQuotaClassExtensionForZone( Optional<QuotaClassAsyncClient> getQuotaClassExtensionForZone(
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone); @EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
/**
* Provides asynchronous access to Volume Type features.
*/
@Delegate
Optional<VolumeTypeAsyncClient> getVolumeTypeExtensionForZone(
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
} }

View File

@ -174,4 +174,11 @@ public interface NovaClient {
Optional<QuotaClassClient> getQuotaClassExtensionForZone( Optional<QuotaClassClient> getQuotaClassExtensionForZone(
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone); @EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
/**
* Provides synchronous access to Volume Type features.
*/
@Delegate
Optional<VolumeTypeClient> getVolumeTypeExtensionForZone(
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
} }

View File

@ -81,6 +81,7 @@ public class NovaRestClientModule extends RestClientModule<NovaClient, NovaAsync
.put(FlavorExtraSpecsClient.class, FlavorExtraSpecsAsyncClient.class) .put(FlavorExtraSpecsClient.class, FlavorExtraSpecsAsyncClient.class)
.put(QuotaClient.class, QuotaAsyncClient.class) .put(QuotaClient.class, QuotaAsyncClient.class)
.put(QuotaClassClient.class, QuotaClassAsyncClient.class) .put(QuotaClassClient.class, QuotaClassAsyncClient.class)
.put(VolumeTypeClient.class, VolumeTypeAsyncClient.class)
.build(); .build();
public NovaRestClientModule() { public NovaRestClientModule() {

View File

@ -466,9 +466,9 @@ public class Server extends Resource {
* Retrieves the extended server status fields (alias "OS-EXT-STS") * Retrieves the extended server status fields (alias "OS-EXT-STS")
* <p/> * <p/>
* NOTE: This field is only present if the Extended Status extension is installed. * NOTE: This field is only present if the Extended Status extension is installed.
* *
* @see org.jclouds.openstack.nova.v1_1.features.ExtensionClient#getExtensionByAlias * @see org.jclouds.openstack.nova.v1_1.features.ExtensionClient#getExtensionByAlias
* @see org.jclouds.openstack.nova.v1_1.extensions.ExtensionNamespaces#EXTENDED_STATUS (extended status?) * @see org.jclouds.openstack.nova.v1_1.extensions.ExtensionNamespaces#EXTENDED_STATUS
*/ */
public Optional<ServerExtendedStatus> getExtendedStatus() { public Optional<ServerExtendedStatus> getExtendedStatus() {
return this.extendedStatus; return this.extendedStatus;
@ -480,16 +480,19 @@ public class Server extends Resource {
* NOTE: This field is only present if the The Extended Server Attributes API extension is installed. * NOTE: This field is only present if the The Extended Server Attributes API extension is installed.
* *
* @see org.jclouds.openstack.nova.v1_1.features.ExtensionClient#getExtensionByAlias * @see org.jclouds.openstack.nova.v1_1.features.ExtensionClient#getExtensionByAlias
* @see org.jclouds.openstack.nova.v1_1.extensions.ExtensionNamespaces#EXTENDED_STATUS (extended status?) * @see org.jclouds.openstack.nova.v1_1.extensions.ExtensionNamespaces#EXTENDED_STATUS
*/ */
public Optional<ServerExtendedAttributes> getExtendedAttributes() { public Optional<ServerExtendedAttributes> getExtendedAttributes() {
return this.extendedAttributes; return this.extendedAttributes;
} }
/** /**
* State of task running against this instance (e.g. "suspending") * Disk config attribute from the Disk Config Extension (alias "OS-DCF")
* <p/> * <p/>
* NOTE: This field is only present if the Disk Config extension is installed. * NOTE: This field is only present if the Disk Config extension is installed
*
* @see org.jclouds.openstack.nova.v1_1.features.ExtensionClient#getExtensionByAlias
* @see org.jclouds.openstack.nova.v1_1.extensions.ExtensionNamespaces#DISK_CONFIG
*/ */
public Optional<String> getDiskConfig() { public Optional<String> getDiskConfig() {
return this.diskConfig; return this.diskConfig;
@ -501,10 +504,10 @@ public class Server extends Resource {
@Override @Override
protected ToStringHelper string() { protected ToStringHelper string() {
return super.string().add("uuid", uuid).add("tenantId", tenantId).add( return super.string().add("uuid", uuid).add("tenantId", tenantId).add(
"userId", userId).add("hostId", getHostId()).add("updated", updated).add("created", created).add( "userId", userId).add("hostId", getHostId()).add("updated", updated).add("created", created).add(
"accessIPv4", getAccessIPv4()).add("accessIPv6", getAccessIPv6()).add("status", status).add( "accessIPv4", getAccessIPv4()).add("accessIPv6", getAccessIPv6()).add("status", status).add(
"configDrive", getConfigDrive()).add("image", image).add("flavor", flavor).add("metadata", metadata) "configDrive", getConfigDrive()).add("image", image).add("flavor", flavor).add("metadata", metadata)
.add("addresses", getAddresses()).add("diskConfig", diskConfig) .add("addresses", getAddresses()).add("diskConfig", diskConfig)
.add("extendedStatus", extendedStatus).add("extendedAttributes", extendedAttributes); .add("extendedStatus", extendedStatus).add("extendedAttributes", extendedAttributes);
} }
} }

View File

@ -0,0 +1,194 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.nova.v1_1.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableMap;
import com.google.gson.annotations.SerializedName;
/**
* Volume Type used in the Volume Type Extension for Nova
*
* @see org.jclouds.openstack.nova.v1_1.extensions.VolumeTypeClient
*/
public class VolumeType {
public static Builder<?> builder() {
return new ConcreteBuilder();
}
public Builder<?> toBuilder() {
return new ConcreteBuilder().fromVolumeType(this);
}
public static abstract class Builder<T extends Builder<T>> {
protected abstract T self();
private String id;
private String name;
private Date created = new Date();
private Date updated;
private Map<String, String> extraSpecs;
/**
* @see VolumeType#getId()
*/
public T id(String id) {
this.id = id;
return self();
}
/**
* @see VolumeType#getName()
*/
public T name(String name) {
this.name = name;
return self();
}
/**
* @see VolumeType#getCreated()
*/
public T created(Date created) {
this.created = created;
return self();
}
/**
* @see VolumeType#getUpdated()
*/
public T updated(Date updated) {
this.updated = updated;
return self();
}
/**
* @see VolumeType#getExtraSpecs()
*/
public T extraSpecs(Map<String, String> extraSpecs) {
this.extraSpecs = ImmutableMap.copyOf(extraSpecs);
return self();
}
public VolumeType build() {
return new VolumeType(this);
}
public T fromVolumeType(VolumeType in) {
return this
.id(in.getId())
.name(in.getName())
.extraSpecs(in.getExtraSpecs())
.created(in.getCreated())
.updated(in.getUpdated().orNull());
}
}
private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
@Override
protected ConcreteBuilder self() {
return this;
}
}
private String id;
private String name;
@SerializedName("created_at")
private Date created;
@SerializedName("updated_at")
private final Optional<Date> updated;
@SerializedName(value = "extra_specs")
private final Map<String, String> extraSpecs;
protected VolumeType(Builder<?> builder) {
this.id = checkNotNull(builder.id, "id");
this.name = checkNotNull(builder.name, "name");
this.extraSpecs = checkNotNull(builder.extraSpecs, "extraSpecs");
this.created = checkNotNull(builder.created, "created");
this.updated = Optional.fromNullable(builder.updated);
}
protected VolumeType() {
this.updated = Optional.absent();
this.extraSpecs = ImmutableMap.of();
}
public String getId() {
return this.id;
}
public String getName() {
return this.name;
}
/** The Date the VolumeType was created */
public Date getCreated() {
return created;
}
/** The Date the VolumeType as last updated - absent if no updates have taken place */
public Optional<Date> getUpdated() {
return updated;
}
public Map<String, String> getExtraSpecs() {
return Collections.unmodifiableMap(this.extraSpecs);
}
@Override
public int hashCode() {
return Objects.hashCode(id, name, created, updated, extraSpecs);
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
VolumeType that = VolumeType.class.cast(obj);
return Objects.equal(this.id, that.id)
&& Objects.equal(this.name, that.name)
&& Objects.equal(this.created, that.created)
&& Objects.equal(this.updated, that.updated)
&& Objects.equal(this.extraSpecs, that.extraSpecs);
}
protected ToStringHelper string() {
return Objects.toStringHelper("")
.add("id", id)
.add("name", name)
.add("created", created)
.add("updated", updated)
.add("extraSpecs", extraSpecs);
}
@Override
public String toString() {
return string().toString();
}
}

View File

@ -0,0 +1,154 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.nova.v1_1.extensions;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.jclouds.concurrent.Timeout;
import org.jclouds.openstack.filters.AuthenticateRequest;
import org.jclouds.openstack.nova.v1_1.binders.BindExtraSpecsToJsonPayload;
import org.jclouds.openstack.nova.v1_1.domain.VolumeType;
import org.jclouds.openstack.nova.v1_1.options.CreateVolumeTypeOptions;
import org.jclouds.openstack.services.Extension;
import org.jclouds.openstack.services.ServiceType;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.MapBinder;
import org.jclouds.rest.annotations.Payload;
import org.jclouds.rest.annotations.PayloadParam;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.SelectJson;
import org.jclouds.rest.annotations.SkipEncoding;
import org.jclouds.rest.annotations.Unwrap;
import org.jclouds.rest.functions.ReturnEmptyMapOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import com.google.common.util.concurrent.ListenableFuture;
/**
* Provides asynchronous access to Volume Type features
*
* @author Adam Lowe
* @see VolumeTypeClient
*/
@Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.VOLUME_TYPES)
@SkipEncoding({'/', '='})
@RequestFilters(AuthenticateRequest.class)
@Path("/os-volume-types")
@Consumes(MediaType.APPLICATION_JSON)
public interface VolumeTypeAsyncClient {
/**
* @see VolumeTypeClient#listVolumeTypes
*/
@GET
@SelectJson("volume_types")
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<VolumeType>> listVolumeTypes();
/**
* @see VolumeTypeClient#getVolumeType
*/
@GET
@Path("/{id}")
@SelectJson("volume_type")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<VolumeType> getVolumeType(@PathParam("id") String id);
/**
* @see VolumeTypeClient#createVolumeType
*/
@POST
@SelectJson("volume_type")
@Produces(MediaType.APPLICATION_JSON)
@Payload("%7B\"volume_type\":%7B\"name\":\"{name}\"%7D%7D")
ListenableFuture<VolumeType> createVolumeType(@PayloadParam("name") String name, CreateVolumeTypeOptions... options);
/**
* @see VolumeTypeClient#deleteVolumeType
*/
@DELETE
@Path("/{id}")
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
ListenableFuture<Boolean> deleteVolumeType(@PathParam("id") String id);
/**
* @see VolumeTypeClient#getAllExtraSpecs(String)
*/
@GET
@SelectJson("extra_specs")
@Path("/{id}/extra_specs")
@ExceptionParser(ReturnEmptyMapOnNotFoundOr404.class)
ListenableFuture<Map<String, String>> getAllExtraSpecs(@PathParam("id") String id);
/**
* @see VolumeTypeClient#setAllExtraSpecs(String, java.util.Map)
*/
@POST
@Path("/{id}/extra_specs")
@Produces(MediaType.APPLICATION_JSON)
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
@MapBinder(BindExtraSpecsToJsonPayload.class)
ListenableFuture<Boolean> setAllExtraSpecs(@PathParam("id") String id, Map<String, String> specs);
/**
* @see VolumeTypeClient#getExtraSpec(String, String)
*/
@GET
@Path("/{id}/extra_specs/{key}")
@Unwrap
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<String> getExtraSpec(@PathParam("id") String id, @PathParam("key") String key);
/**
* @see VolumeTypeClient#setExtraSpec(String, String, String)
*/
@PUT
@Path("/{id}/extra_specs/{key}")
@Produces(MediaType.APPLICATION_JSON)
@Payload("%7B\"{key}\":\"{value}\"%7D")
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
ListenableFuture<Boolean> setExtraSpec(@PathParam("id") String id,
@PathParam("key") @PayloadParam("key") String key,
@PayloadParam("value") String value);
/**
* @see VolumeTypeClient#deleteExtraSpec(String, String)
*/
@DELETE
@Path("/{id}/extra_specs/{key}")
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
ListenableFuture<Boolean> deleteExtraSpec(@PathParam("id") String id,
@PathParam("key") String key);
}

View File

@ -0,0 +1,107 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.nova.v1_1.extensions;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.jclouds.concurrent.Timeout;
import org.jclouds.openstack.filters.AuthenticateRequest;
import org.jclouds.openstack.nova.v1_1.domain.VolumeType;
import org.jclouds.openstack.nova.v1_1.options.CreateVolumeTypeOptions;
import org.jclouds.openstack.services.Extension;
import org.jclouds.openstack.services.ServiceType;
import org.jclouds.rest.annotations.RequestFilters;
/**
* Provides synchronous access to Volume Type features
*
* @author Adam Lowe
* @see VolumeClient
* @see VolumeTypeAsyncClient
* @see <a href="http://nova.openstack.org/api/nova.api.openstack.compute.contrib.volumetypes.html"/>
* @see <a href="https://blueprints.launchpad.net/nova/+spec/volume-type"/>
*/
@Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.VOLUME_TYPES)
@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
@RequestFilters(AuthenticateRequest.class)
public interface VolumeTypeClient {
/**
* @return set of all volume types
*/
Set<VolumeType> listVolumeTypes();
/**
* @param id the id of the volume type to retrieve
* @return the requested volume type
*/
VolumeType getVolumeType(String id);
/**
* Creates a new volume type
*
* @param name the name of the new volume type
* @param options optional settings for the new volume type
* @return the new volume type
*/
VolumeType createVolumeType(String name, CreateVolumeTypeOptions... options);
/**
* Deletes a volume type
*/
Boolean deleteVolumeType(String id);
/**
* @param id the id of the volume type
* @return the set of extra metadata for the flavor
*/
Map<String, String> getAllExtraSpecs(String id);
/**
* Creates or updates the extra metadata for a given flavor
*/
Boolean setAllExtraSpecs(String id, Map<String, String> specs);
/**
* Retrieve a single extra spec value
*
* @param id the id of the volume type
* @param key the key of the extra spec item to retrieve
*/
String getExtraSpec(String id, String key);
/**
* Creates or updates a single extra spec value
*
* @param id the id of the volume type
* @param key the extra spec key (when creating ensure this does not include whitespace or other difficult characters)
* @param value the new value to store associate with the key
*/
Boolean setExtraSpec(String id, String key, String value);
/**
* Deletes an existing extra spec
*
* @param id the id of the volume type
* @param key the key of the extra spec to delete
*/
Boolean deleteExtraSpec(String id, String key);
}

View File

@ -0,0 +1,103 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.nova.v1_1.options;
import static com.google.common.base.Objects.equal;
import static com.google.common.base.Objects.toStringHelper;
import java.util.Map;
import javax.inject.Inject;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.MapBinder;
import org.jclouds.rest.binders.BindToJsonPayload;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
/**
* @author Adam Lowe
*/
public class CreateVolumeTypeOptions implements MapBinder {
public static final CreateVolumeTypeOptions NONE = new CreateVolumeTypeOptions();
@Inject
protected BindToJsonPayload jsonBinder;
protected Map<String, String> specs = ImmutableMap.of();
@Override
public <R extends HttpRequest> R bindToRequest(R request, Map<String, String> postParams) {
Map<String, Object> data = Maps.newHashMap();
data.putAll(postParams);
data.put("extra_specs", specs);
return jsonBinder.bindToRequest(request, ImmutableMap.of("volume_type", data));
}
@Override
public <R extends HttpRequest> R bindToRequest(R request, Object toBind) {
throw new IllegalStateException("CreateWithExtraSpecs are POST operations");
}
@Override
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (!(object instanceof CreateVolumeTypeOptions)) return false;
final CreateVolumeTypeOptions other = CreateVolumeTypeOptions.class.cast(object);
return equal(specs, other.specs);
}
@Override
public int hashCode() {
return Objects.hashCode(specs);
}
protected ToStringHelper string() {
return toStringHelper("").add("specs", specs);
}
@Override
public String toString() {
return string().toString();
}
public CreateVolumeTypeOptions specs(Map<String, String> specs) {
this.specs = specs;
return this;
}
public Map<String, String> getSpecs() {
return specs;
}
public static class Builder {
/**
* @see CreateVolumeTypeOptions#getSpecs()
*/
public static CreateVolumeTypeOptions specs(Map<String, String> specs) {
return new CreateVolumeTypeOptions().specs(specs);
}
}
}

View File

@ -0,0 +1,260 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.nova.v1_1.extensions;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import java.net.URI;
import java.util.Set;
import javax.ws.rs.core.MediaType;
import org.jclouds.date.DateService;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.openstack.nova.v1_1.domain.VolumeType;
import org.jclouds.openstack.nova.v1_1.internal.BaseNovaClientExpectTest;
import org.jclouds.openstack.nova.v1_1.options.CreateVolumeTypeOptions;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
/**
* Tests guice wiring and parsing of VolumeTypeClient
*
* @author Adam Lowe
*/
@Test(groups = "unit", testName = "VolumeTypeClientExpectTest")
public class VolumeTypeClientExpectTest extends BaseNovaClientExpectTest {
private DateService dateService = new SimpleDateFormatDateService();
public void testListVolumeTypes() {
URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-volume-types");
VolumeTypeClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardRequestBuilder(endpoint).build(),
standardResponseBuilder(200).payload(payloadFromResource("/volume_type_list.json")).build()
).getVolumeTypeExtensionForZone("az-1.region-a.geo-1").get();
Set<VolumeType> types = client.listVolumeTypes();
assertEquals(types, ImmutableSet.of(testVolumeType()));
}
public void testGetVolumeType() {
URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-volume-types/8");
VolumeTypeClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardRequestBuilder(endpoint).build(),
standardResponseBuilder(200).payload(payloadFromResource("/volume_type.json")).build()
).getVolumeTypeExtensionForZone("az-1.region-a.geo-1").get();
VolumeType type = client.getVolumeType("8");
assertEquals(type, testVolumeType());
}
public void testGetVolumeTypeFailNotFound() {
URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-volume-types/8");
VolumeTypeClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardRequestBuilder(endpoint).build(),
standardResponseBuilder(404).build()
).getVolumeTypeExtensionForZone("az-1.region-a.geo-1").get();
assertNull(client.getVolumeType("8"));
}
public void testCreateVolumeType() {
URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-volume-types");
VolumeTypeClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardRequestBuilder(endpoint).method("POST")
.payload(payloadFromStringWithContentType("{\"volume_type\":{\"name\":\"jclouds-test-1\"}}", MediaType.APPLICATION_JSON))
.build(),
standardResponseBuilder(200).payload(payloadFromResource("/volume_type.json")).build()
).getVolumeTypeExtensionForZone("az-1.region-a.geo-1").get();
VolumeType type = client.createVolumeType("jclouds-test-1");
assertEquals(type, testVolumeType());
}
public void testCreateVolumeTypeWithOptsNONE() {
URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-volume-types");
VolumeTypeClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardRequestBuilder(endpoint).method("POST")
.payload(payloadFromStringWithContentType("{\"volume_type\":{\"name\":\"jclouds-test-1\",\"extra_specs\":{}}}", MediaType.APPLICATION_JSON))
.build(),
standardResponseBuilder(200).payload(payloadFromResource("/volume_type.json")).build()
).getVolumeTypeExtensionForZone("az-1.region-a.geo-1").get();
VolumeType type = client.createVolumeType("jclouds-test-1", CreateVolumeTypeOptions.NONE);
assertEquals(type, testVolumeType());
}
public void testCreateVolumeTypeWithOptsSet() {
URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-volume-types");
VolumeTypeClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardRequestBuilder(endpoint).method("POST")
.payload(payloadFromStringWithContentType("{\"volume_type\":{\"name\":\"jclouds-test-1\",\"extra_specs\":{\"x\": \"y\"}}}", MediaType.APPLICATION_JSON))
.build(),
standardResponseBuilder(200).payload(payloadFromResource("/volume_type.json")).build()
).getVolumeTypeExtensionForZone("az-1.region-a.geo-1").get();
VolumeType type = client.createVolumeType("jclouds-test-1", CreateVolumeTypeOptions.Builder.specs(ImmutableMap.of("x", "y")));
assertEquals(type, testVolumeType());
}
public void testDeleteVolumeType() {
URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-volume-types/8");
VolumeTypeClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardRequestBuilder(endpoint).method("DELETE").build(),
standardResponseBuilder(200).build()
).getVolumeTypeExtensionForZone("az-1.region-a.geo-1").get();
assertTrue(client.deleteVolumeType("8"));
}
public void testDeleteVolumeTypeFailNotFound() {
URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-volume-types/8");
VolumeTypeClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardRequestBuilder(endpoint).method("DELETE").build(),
standardResponseBuilder(404).build()
).getVolumeTypeExtensionForZone("az-1.region-a.geo-1").get();
assertFalse(client.deleteVolumeType("8"));
}
public void testGetAllExtraSpecs() {
URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-volume-types/9/extra_specs");
VolumeTypeClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardRequestBuilder(endpoint).build(),
standardResponseBuilder(200).payload(payloadFromResource("/volume_type_extra_specs.json")).build()
).getVolumeTypeExtensionForZone("az-1.region-a.geo-1").get();
assertEquals(client.getAllExtraSpecs("9"), ImmutableMap.of("test", "value1"));
}
public void testGetAllExtraSpecsFailNotFound() {
URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-volume-types/9/extra_specs");
VolumeTypeClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardRequestBuilder(endpoint).build(),
standardResponseBuilder(404).build()
).getVolumeTypeExtensionForZone("az-1.region-a.geo-1").get();
assertTrue(client.getAllExtraSpecs("9").isEmpty());
}
public void testSetAllExtraSpecs() {
URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-volume-types/9/extra_specs");
VolumeTypeClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardRequestBuilder(endpoint)
.method("POST")
.payload(payloadFromStringWithContentType("{\"extra_specs\":{\"test1\":\"somevalue\"}}", MediaType.APPLICATION_JSON)).build(),
standardResponseBuilder(200).build()
).getVolumeTypeExtensionForZone("az-1.region-a.geo-1").get();
assertTrue(client.setAllExtraSpecs("9", ImmutableMap.of("test1", "somevalue")));
}
public void testSetExtraSpec() {
URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-volume-types/5/extra_specs/test1");
VolumeTypeClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardRequestBuilder(endpoint)
.method("PUT")
.payload(payloadFromStringWithContentType("{\"test1\":\"somevalue\"}", MediaType.APPLICATION_JSON)).build(),
standardResponseBuilder(200).build()
).getVolumeTypeExtensionForZone("az-1.region-a.geo-1").get();
assertTrue(client.setExtraSpec("5", "test1", "somevalue"));
}
public void testGetExtraSpec() {
URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-volume-types/5/extra_specs/test1");
VolumeTypeClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardRequestBuilder(endpoint).build(),
standardResponseBuilder(200).payload(payloadFromStringWithContentType("{\"test1\":\"another value\"}", MediaType.APPLICATION_JSON)).build()
).getVolumeTypeExtensionForZone("az-1.region-a.geo-1").get();
assertEquals(client.getExtraSpec("5", "test1"), "another value");
}
public void testGetExtraSpecFailNotFound() {
URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-volume-types/5/extra_specs/test1");
VolumeTypeClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardRequestBuilder(endpoint).build(),
standardResponseBuilder(404).build()
).getVolumeTypeExtensionForZone("az-1.region-a.geo-1").get();
assertNull(client.getExtraSpec("5", "test1"));
}
public void testDeleteExtraSpec() {
URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-volume-types/5/extra_specs/test1");
VolumeTypeClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardRequestBuilder(endpoint).method("DELETE").build(),
standardResponseBuilder(200).build()
).getVolumeTypeExtensionForZone("az-1.region-a.geo-1").get();
assertTrue(client.deleteExtraSpec("5", "test1"));
}
public void testDeleteExtraSpecFailNotFound() {
URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-volume-types/5/extra_specs/test1");
VolumeTypeClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardRequestBuilder(endpoint).method("DELETE").build(),
standardResponseBuilder(404).build()
).getVolumeTypeExtensionForZone("az-1.region-a.geo-1").get();
assertFalse(client.deleteExtraSpec("5", "test1"));
}
public VolumeType testVolumeType() {
return VolumeType.builder().id("8").name("jclouds-test-1").created(dateService.iso8601SecondsDateParse("2012-05-10 12:33:06")).extraSpecs(ImmutableMap.of("test", "value1", "test1", "wibble")).build();
}
}

View File

@ -0,0 +1,129 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.nova.v1_1.extensions;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import java.util.Set;
import org.jclouds.openstack.nova.v1_1.domain.VolumeType;
import org.jclouds.openstack.nova.v1_1.internal.BaseNovaClientLiveTest;
import org.jclouds.openstack.nova.v1_1.options.CreateVolumeTypeOptions;
import org.jclouds.predicates.RetryablePredicate;
import org.testng.annotations.AfterGroups;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
/**
* Tests behavior of VolumeTypeClient
*
* @author Adam Lowe
*/
@Test(groups = "live", testName = "VolumeTypeClientLiveTest", singleThreaded = true)
public class VolumeTypeClientLiveTest extends BaseNovaClientLiveTest {
private Optional<VolumeTypeClient> volumeTypeOption;
private String zone;
private VolumeType testVolumeType;
@BeforeGroups(groups = {"integration", "live"})
@Override
public void setupContext() {
super.setupContext();
zone = Iterables.getLast(novaContext.getApi().getConfiguredZones(), "nova");
volumeTypeOption = novaContext.getApi().getVolumeTypeExtensionForZone(zone);
}
@AfterGroups(groups = "live")
@Override
protected void tearDown() {
if (volumeTypeOption.isPresent()) {
if (testVolumeType != null) {
final String id = testVolumeType.getId();
assertTrue(volumeTypeOption.get().deleteVolumeType(id));
assertTrue(new RetryablePredicate<VolumeTypeClient>(new Predicate<VolumeTypeClient>() {
@Override
public boolean apply(VolumeTypeClient volumeClient) {
return volumeClient.getVolumeType(id) == null;
}
}, 5 * 1000L).apply(volumeTypeOption.get()));
}
}
super.tearDown();
}
public void testCreateVolumeType() {
if (volumeTypeOption.isPresent()) {
testVolumeType = volumeTypeOption.get().createVolumeType(
"jclouds-test-1", CreateVolumeTypeOptions.Builder.specs(ImmutableMap.of("test", "value1")));
assertTrue(new RetryablePredicate<VolumeTypeClient>(new Predicate<VolumeTypeClient>() {
@Override
public boolean apply(VolumeTypeClient volumeTypeClient) {
return volumeTypeClient.getVolumeType(testVolumeType.getId()) != null;
}
}, 180 * 1000L).apply(volumeTypeOption.get()));
assertEquals(volumeTypeOption.get().getVolumeType(testVolumeType.getId()).getName(), "jclouds-test-1");
assertEquals(volumeTypeOption.get().getVolumeType(testVolumeType.getId()).getExtraSpecs(), ImmutableMap.of("test", "value1"));
}
}
@Test(dependsOnMethods = "testCreateVolumeType")
public void testListVolumeTypes() {
if (volumeTypeOption.isPresent()) {
Set<VolumeType> volumeTypes = volumeTypeOption.get().listVolumeTypes();
assertNotNull(volumeTypes);
boolean foundIt = false;
for (VolumeType vt : volumeTypes) {
VolumeType details = volumeTypeOption.get().getVolumeType(vt.getId());
assertNotNull(details);
if (Objects.equal(details.getId(), testVolumeType.getId())) {
foundIt = true;
}
}
assertTrue(foundIt, "Failed to find the volume type we created in listVolumeTypes() response");
}
}
@Test(dependsOnMethods = "testCreateVolumeType")
public void testExtraSpecs() {
if (volumeTypeOption.isPresent()) {
assertEquals(volumeTypeOption.get().getAllExtraSpecs(testVolumeType.getId()), ImmutableMap.of("test", "value1"));
assertEquals(volumeTypeOption.get().getExtraSpec(testVolumeType.getId(), "test"), "value1");
assertTrue(volumeTypeOption.get().setAllExtraSpecs(testVolumeType.getId(), ImmutableMap.of("test1", "wibble")));
}
}
@Test(dependsOnMethods = "testCreateVolumeType")
public void testUpdateIndividualSpec() {
if (volumeTypeOption.isPresent()) {
assertTrue(volumeTypeOption.get().setExtraSpec(testVolumeType.getId(), "test1", "freddy"));
assertEquals(volumeTypeOption.get().getExtraSpec(testVolumeType.getId(), "test1"), "freddy");
}
}
}

View File

@ -0,0 +1,9 @@
{"volume_type": {
"name": "jclouds-test-1",
"deleted": false,
"created_at": "2012-05-10 12:33:06",
"updated_at": null,
"extra_specs": {"test": "value1", "test1": "wibble"},
"deleted_at": null,
"id": 8
}}

View File

@ -0,0 +1 @@
{"extra_specs": {"test": "value1"}}

View File

@ -0,0 +1 @@
{"volume_types": [{"name": "jclouds-test-1", "deleted": false, "created_at": "2012-05-10 12:33:06", "updated_at": null, "extra_specs": {"test": "value1", "test1": "wibble"}, "deleted_at": null, "id": 8}]}