Merge pull request #1465 from aplowe/1.6.x

cloudstack: adding support for create volume from a custom disk offering
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/VolumeAsyncClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/VolumeAsyncClient.java
index e9d9bd7..56d4c1d 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/VolumeAsyncClient.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/VolumeAsyncClient.java
@@ -90,6 +90,18 @@
                                                                             @QueryParam("zoneid") String zoneId);
 
    /**
+    * @see VolumeClient#createVolumeFromCustomDiskOfferingInZone(String, String, String, int)
+    */
+   @GET
+   @QueryParams(keys = "command", values = "createVolume")
+   @Unwrap
+   @Consumes(MediaType.APPLICATION_JSON)
+   ListenableFuture<AsyncCreateResponse> createVolumeFromCustomDiskOfferingInZone(@QueryParam("name") String name,
+                                                                            @QueryParam("diskofferingid") String diskOfferingId,
+                                                                            @QueryParam("zoneid") String zoneId,
+                                                                            @QueryParam("size") int size);
+
+   /**
     * @see VolumeClient#createVolumeFromSnapshotInZone(String, String, String)
     */
    @Named("createVolume")
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/VolumeClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/VolumeClient.java
index 73d845a..744bc3c 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/VolumeClient.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/VolumeClient.java
@@ -42,6 +42,18 @@
     */
    AsyncCreateResponse createVolumeFromDiskOfferingInZone(String name, String diskOfferingId, String zoneId);
 
+
+   /**
+    * Create a volume with given name, size and diskOfferingId
+    *
+    * @param name           name of the volume
+    * @param diskOfferingId the ID of the disk offering (the offering should have the custom disk size flag set)
+    * @param zoneId         the ID of the availability zone
+    * @param size           the size of volume required (in GB)
+    * @return AsyncCreateResponse job response used to track creation
+    */
+   AsyncCreateResponse createVolumeFromCustomDiskOfferingInZone(String name, String diskOfferingId, String zoneId, int size);
+
    /**
     * Create a volume with given name and snapshotId
     *
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/VolumeClientExpectTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/VolumeClientExpectTest.java
new file mode 100644
index 0000000..e930033
--- /dev/null
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/VolumeClientExpectTest.java
@@ -0,0 +1,65 @@
+/**
+* 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.cloudstack.features;
+
+import org.jclouds.cloudstack.CloudStackApiMetadata;
+import org.jclouds.cloudstack.CloudStackContext;
+import org.jclouds.cloudstack.domain.AsyncCreateResponse;
+import org.jclouds.cloudstack.internal.BaseCloudStackExpectTest;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.testng.annotations.Test;
+
+import java.net.URI;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+
+import static org.testng.Assert.assertNotNull;
+
+/**
+* Test the CloudStack VolumeClient
+*
+* @author Adam Lowe
+*/
+@Test(groups = "unit", testName = "VolumeClientExpectTest")
+public class VolumeClientExpectTest extends BaseCloudStackExpectTest<VolumeClient> {
+
+   public void testCreateVolumeFromCustomDiskOffering() throws NoSuchAlgorithmException, CertificateException {
+      VolumeClient client = requestSendsResponse(
+              HttpRequest.builder()
+                      .method("GET")
+                      .endpoint(
+                              URI.create("http://localhost:8080/client/api?response=json&" +
+                                      "command=createVolume&name=VolumeClientExpectTest-jclouds-volume&diskofferingid=0473f5dd-bca5-4af4-a9b6-db9e8a88a2f6&zoneid=6f9a2921-b22a-4149-8b71-6ffc275a2177&size=1&apiKey=identity&signature=Y4%2BmdvhS/jlKRNSJ3nQqrjwg1CY%3D"))
+                      .addHeader("Accept", "application/json")
+                      .build(),
+              HttpResponse.builder()
+                      .statusCode(200)
+                      .payload(payloadFromResource("/queryasyncjobresultresponse-createvolume.json"))
+                      .build());
+      
+      AsyncCreateResponse response = client.createVolumeFromCustomDiskOfferingInZone("VolumeClientExpectTest-jclouds-volume", "0473f5dd-bca5-4af4-a9b6-db9e8a88a2f6", "6f9a2921-b22a-4149-8b71-6ffc275a2177", 1);
+      assertNotNull(response);
+   }
+
+   @Override
+   protected VolumeClient clientFrom(CloudStackContext context) {
+      return context.unwrap(CloudStackApiMetadata.CONTEXT_TOKEN).getApi().getVolumeClient();
+   }
+}
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/VolumeClientLiveTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/VolumeClientLiveTest.java
index 258a8d5..0620987 100644
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/VolumeClientLiveTest.java
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/VolumeClientLiveTest.java
@@ -164,6 +164,33 @@
       client.getVolumeClient().deleteVolume(volume.getId());
    }
 
+   /** Test requires a custom disk offering to be available */
+   public void testCreateVolumeFromCustomDiskOffering() {
+      final int size = 1;
+      DiskOffering offering = null;
+      for (DiskOffering candidate : client.getOfferingClient().listDiskOfferings()) {
+         if (candidate.isCustomized()) {
+            offering = candidate;
+            break;
+         }
+      }
+      
+      assertNotNull("No custom disk offering found!", offering);
+      
+      AsyncCreateResponse job = client.getVolumeClient().createVolumeFromCustomDiskOfferingInZone(
+                prefix + "-jclouds-volume", offering.getId(), zoneId, size);
+      assertTrue(jobComplete.apply(job.getJobId()));
+      logger.info("created volume "+job.getId());
+      
+      Volume volume = findVolumeWithId(job.getId());
+      try {
+         checkVolume(volume);
+         assertEquals(volume.getSize(), size * 1024 * 1024 * 1024);
+      } finally {
+         client.getVolumeClient().deleteVolume(volume.getId());
+      }
+   }
+
    /** test requires that a VM exist */
    public void testCreateVolumeFromDiskofferingInZoneAndAttachVolumeToVirtualMachineAndDetachAndDelete() {
       logger.info("testCreateVolumeFromDiskofferingInZoneAndAttachVolumeToVirtualMachineAndDetachAndDelete");
diff --git a/apis/cloudstack/src/test/resources/queryasyncjobresultresponse-createvolume.json b/apis/cloudstack/src/test/resources/queryasyncjobresultresponse-createvolume.json
new file mode 100644
index 0000000..31f31d0
--- /dev/null
+++ b/apis/cloudstack/src/test/resources/queryasyncjobresultresponse-createvolume.json
@@ -0,0 +1,36 @@
+{
+   "queryasyncjobresultresponse" : 
+      {"accountid":"43e3d66f-c8a3-43b2-a3d0-3bbc2416da14",
+      "userid":"99458e63-725b-48ec-aedc-f8ccc11f5231",
+      "cmd":"com.cloud.api.commands.CreateVolumeCmd",
+      "jobstatus":1,
+      "jobprocstatus":0,
+      "jobresultcode":0,
+      "jobresulttype":"object",
+      "jobresult":{
+         "volume":{
+            "id":"f947c7b3-e079-4e7d-aacc-1509d1ae387a",
+            "name":"VolumeClientExpectTest-jclouds-volume",
+            "zoneid":"6f9a2921-b22a-4149-8b71-6ffc275a2177",
+            "zonename":"Basic1",
+            "type":"DATADISK",
+            "size":1073741824,
+            "created":"2013-02-05T13:41:14+0200",
+            "state":"Allocated",
+            "account":"admin",
+            "domainid":"99f4159b-c698-4bd9-b8c5-5ac462f101eb",
+            "domain":"ROOT",
+            "storagetype":"shared",
+            "hypervisor":"None",
+            "diskofferingid":"0473f5dd-bca5-4af4-a9b6-db9e8a88a2f6",
+            "diskofferingname":"Custom",
+            "diskofferingdisplaytext":"Custom Disk",
+            "storage":"none","destroyed":false,
+            "isextractable":true,
+            "tags":[]
+         }
+      },
+      "created":"2013-02-05T13:41:14+0200",
+      "jobid":"4ec82395-365a-4dad-8bd7-238c4f388702"
+   }
+}