diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/Flavor.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/Flavor.java
index 35030a79fe..2be1a24562 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/Flavor.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/Flavor.java
@@ -18,6 +18,9 @@
*/
package org.jclouds.openstack.nova.v2_0.domain;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import java.beans.ConstructorProperties;
import javax.inject.Named;
@@ -34,7 +37,7 @@ import com.google.common.base.Optional;
* A flavor is an available hardware configuration for a server. Each flavor has
* a unique combination of disk space and memory capacity.
*
- * @author Jeremy Daggett
+ * @author Jeremy Daggett, Ilja Bobkevic
* @see
@@ -139,9 +142,11 @@ public class Flavor extends Resource {
@ConstructorProperties({
"id", "name", "links", "ram", "disk", "vcpus", "swap", "rxtx_factor", "OS-FLV-EXT-DATA:ephemeral"
})
- protected Flavor(String id, @Nullable String name, java.util.Set links, int ram, int disk, int vcpus,
+ protected Flavor(String id, String name, java.util.Set links, int ram, int disk, int vcpus,
@Nullable String swap, @Nullable Double rxtxFactor, @Nullable Integer ephemeral) {
- super(id, name, links);
+ super(id, checkNotNull(name, "name"), links);
+ checkArgument(ram > 0, "Value of ram has to greater than 0");
+ checkArgument(vcpus > 0, "Value of vcpus has to greater than 0");
this.ram = ram;
this.disk = disk;
this.vcpus = vcpus;
@@ -149,7 +154,7 @@ public class Flavor extends Resource {
this.rxtxFactor = Optional.fromNullable(rxtxFactor);
this.ephemeral = Optional.fromNullable(ephemeral);
}
-
+
public int getRam() {
return this.ram;
}
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/FlavorApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/FlavorApi.java
index 2043de3d6c..f6f211697e 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/FlavorApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/FlavorApi.java
@@ -32,7 +32,7 @@ import org.jclouds.openstack.v2_0.options.PaginationOptions;
* @see
- * @author Jeremy Daggett
+ * @author Jeremy Daggett, Ilja Bobkevic
*/
public interface FlavorApi {
@@ -63,4 +63,18 @@ public interface FlavorApi {
*/
Flavor get(String id);
+ /**
+ * Create flavor according to the provided object
+ *
+ * @param flavor - flavor object
+ * @return newly created flavor
+ */
+ Flavor create(Flavor flavor);
+
+ /**
+ * Delete flavor with a given id
+ *
+ * @param id - flavor id
+ */
+ void delete(String id);
}
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/FlavorAsyncApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/FlavorAsyncApi.java
index ac87968d20..7bb02f5b36 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/FlavorAsyncApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/FlavorAsyncApi.java
@@ -20,13 +20,17 @@ package org.jclouds.openstack.nova.v2_0.features;
import javax.inject.Named;
import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
+import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.jclouds.Fallbacks.EmptyPagedIterableOnNotFoundOr404;
import org.jclouds.Fallbacks.NullOnNotFoundOr404;
+import org.jclouds.Fallbacks.VoidOnNotFoundOr404;
import org.jclouds.collect.PagedIterable;
import org.jclouds.openstack.keystone.v2_0.KeystoneFallbacks.EmptyPaginatedCollectionOnNotFoundOr404;
import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
@@ -41,6 +45,8 @@ import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.ResponseParser;
import org.jclouds.rest.annotations.SelectJson;
import org.jclouds.rest.annotations.Transform;
+import org.jclouds.rest.annotations.Unwrap;
+import org.jclouds.rest.annotations.WrapWith;
import com.google.common.util.concurrent.ListenableFuture;
@@ -54,6 +60,7 @@ import com.google.common.util.concurrent.ListenableFuture;
* >docs
* @author Jeremy Daggett TODO: Need a ListFlavorOptions class minDisk=minDiskInGB&
* minRam=minRamInMB& marker=markerID&limit=int
+ * @author Ilja Bobkevic
*/
@RequestFilters(AuthenticateRequest.class)
public interface FlavorAsyncApi {
@@ -115,4 +122,25 @@ public interface FlavorAsyncApi {
@Fallback(NullOnNotFoundOr404.class)
ListenableFuture extends Flavor> get(@PathParam("id") String id);
+
+ /**
+ * @see FlavorApi#create
+ */
+ @Named("flavor:create")
+ @POST
+ @Unwrap
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/flavors")
+ ListenableFuture extends Flavor> create(@WrapWith("flavor") Flavor flavor);
+
+ /**
+ * @see FlavorApi#delete
+ */
+ @Named("flavor:delete")
+ @DELETE
+ @Consumes
+ @Path("/flavors/{id}")
+ @Fallback(VoidOnNotFoundOr404.class)
+ ListenableFuture delete(@PathParam("id") String id);
}
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/FlavorApiExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/FlavorApiExpectTest.java
index e1891e5349..e5474dc908 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/FlavorApiExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/FlavorApiExpectTest.java
@@ -22,10 +22,16 @@ import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
+import javax.ws.rs.HttpMethod;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.nova.v2_0.NovaApi;
+import org.jclouds.openstack.nova.v2_0.domain.Flavor;
import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiExpectTest;
+import org.jclouds.openstack.nova.v2_0.parse.ParseCreateFlavorTest;
import org.jclouds.openstack.nova.v2_0.parse.ParseFlavorListTest;
import org.jclouds.openstack.nova.v2_0.parse.ParseFlavorTest;
import org.testng.annotations.Test;
@@ -35,7 +41,7 @@ import com.google.common.collect.ImmutableSet;
/**
* Tests annotation parsing of {@code FlavorAsyncApi}
*
- * @author Jeremy Daggett
+ * @author Jeremy Daggett, Ilja Bobkevic
*/
@Test(groups = "unit", testName = "FlavorApiExpectTest")
public class FlavorApiExpectTest extends BaseNovaApiExpectTest {
@@ -114,5 +120,47 @@ public class FlavorApiExpectTest extends BaseNovaApiExpectTest {
assertNull(apiWhenNoFlavorsExist.getFlavorApiForZone("az-1.region-a.geo-1").get("123"));
}
+
+ public void testCreateFlavor200() throws Exception {
+ ParseCreateFlavorTest parser = new ParseCreateFlavorTest();
+ HttpRequest listFlavors = HttpRequest
+ .builder()
+ .method(HttpMethod.POST)
+ .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/flavors")
+ .addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON)
+ .addHeader("X-Auth-Token", authToken)
+ .payload(payloadFromResource(parser.resource())).build();
+
+ HttpResponse listFlavorsResponse = HttpResponse.builder().statusCode(200)
+ .payload(payloadFromResource(parser.resource())).build();
+ NovaApi api = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
+ responseWithKeystoneAccess, listFlavors, listFlavorsResponse);
+
+ assertEquals(
+ api.getFlavorApiForZone("az-1.region-a.geo-1").create(Flavor.builder()
+ .id("1cb47a44-9b84-4da4-bf81-c1976e8414ab")
+ .name("128 MB Server").ram(128).vcpus(1)
+ .disk(10).build())
+ .toString(), parser.expected().toString());
+ }
+
+ public void testDeleteFlavor202() throws Exception {
+ String flavorId = "1cb47a44-9b84-4da4-bf81-c1976e8414ab";
+
+ HttpRequest updateMetadata = HttpRequest
+ .builder()
+ .method(HttpMethod.DELETE)
+ .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/flavors/" + flavorId)
+ .addHeader(HttpHeaders.ACCEPT, MediaType.WILDCARD)
+ .addHeader("X-Auth-Token", authToken)
+ .build();
+
+ HttpResponse updateMetadataResponse = HttpResponse.builder().statusCode(204).build();
+
+ NovaApi api = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
+ responseWithKeystoneAccess, updateMetadata, updateMetadataResponse);
+
+ api.getFlavorApiForZone("az-1.region-a.geo-1").delete(flavorId);
+ }
}
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseCreateFlavorTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseCreateFlavorTest.java
new file mode 100644
index 0000000000..23f641f812
--- /dev/null
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseCreateFlavorTest.java
@@ -0,0 +1,61 @@
+/**
+ * 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.v2_0.parse;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.json.BaseItemParserTest;
+import org.jclouds.json.config.GsonModule;
+import org.jclouds.openstack.nova.v2_0.config.NovaParserModule;
+import org.jclouds.openstack.nova.v2_0.domain.Flavor;
+import org.jclouds.openstack.nova.v2_0.features.FlavorApiExpectTest;
+import org.jclouds.rest.annotations.SelectJson;
+import org.testng.annotations.Test;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+
+/**
+ * @see FlavorApiExpectTest
+ * @author Ilja Bobkevic
+ */
+@Test(groups = "unit", testName = "ParseCreateFlavorTest")
+public class ParseCreateFlavorTest extends BaseItemParserTest {
+
+ @Override
+ public String resource() {
+ return "/flavor_new.json";
+ }
+
+ @Override
+ @SelectJson("flavor")
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Flavor expected() {
+ return Flavor.builder()
+ .id("1cb47a44-9b84-4da4-bf81-c1976e8414ab")
+ .name("128 MB Server").ram(128).vcpus(1)
+ .disk(10).build();
+ }
+
+ @Override
+ protected Injector injector() {
+ return Guice.createInjector(new NovaParserModule(), new GsonModule());
+ }
+}
diff --git a/apis/openstack-nova/src/test/resources/flavor_new.json b/apis/openstack-nova/src/test/resources/flavor_new.json
new file mode 100644
index 0000000000..5356f8c824
--- /dev/null
+++ b/apis/openstack-nova/src/test/resources/flavor_new.json
@@ -0,0 +1,10 @@
+{
+ "flavor" : {
+ "id" : "1cb47a44-9b84-4da4-bf81-c1976e8414ab",
+ "name" : "128 MB Server",
+ "ram" : 128,
+ "disk" : 10,
+ "vcpus" : 1,
+ "links" : []
+ }
+}