CLOUDSTACK-4757. Deploy Virtual Machine - If datadisk templates are specified 
using parameter 'datadisktemplatetodiskofferinglist', then create virtual 
machine with additional volumes attached


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/ad8033f9
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/ad8033f9
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/ad8033f9

Branch: refs/heads/multiple-disk-ova
Commit: ad8033f9807ca06f36ee85750a697fa9b4f284c7
Parents: 5db1bca
Author: Likitha Shetty <likitha.she...@citrix.com>
Authored: Mon Mar 10 19:40:05 2014 +0530
Committer: Likitha Shetty <likitha.she...@citrix.com>
Committed: Fri May 2 17:51:52 2014 +0530

----------------------------------------------------------------------
 api/src/com/cloud/vm/DiskProfile.java           |  4 ++
 api/src/com/cloud/vm/UserVmService.java         | 22 +++++++--
 .../org/apache/cloudstack/api/ApiConstants.java |  1 +
 .../cloudstack/api/ResponseGenerator.java       |  2 +
 .../api/command/user/vm/DeployVMCmd.java        | 41 +++++++++++++++--
 .../src/com/cloud/vm/VirtualMachineManager.java |  4 +-
 .../service/VolumeOrchestrationService.java     |  5 ++-
 .../service/api/OrchestrationService.java       |  4 +-
 .../com/cloud/vm/VirtualMachineManagerImpl.java | 27 ++++++++---
 .../engine/orchestration/CloudOrchestrator.java | 19 ++++++--
 .../orchestration/VolumeOrchestrator.java       |  8 +++-
 .../resource/VmwareStorageProcessor.java        |  6 ++-
 server/src/com/cloud/api/ApiResponseHelper.java |  5 +++
 .../cloud/network/as/AutoScaleManagerImpl.java  |  6 +--
 server/src/com/cloud/vm/UserVmManagerImpl.java  | 47 +++++++++++++++-----
 15 files changed, 166 insertions(+), 35 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ad8033f9/api/src/com/cloud/vm/DiskProfile.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/vm/DiskProfile.java 
b/api/src/com/cloud/vm/DiskProfile.java
index a37f7aa..d909774 100644
--- a/api/src/com/cloud/vm/DiskProfile.java
+++ b/api/src/com/cloud/vm/DiskProfile.java
@@ -139,6 +139,10 @@ public class DiskProfile {
         return templateId;
     }
 
+    public void setTemplateId(Long templateId) {
+        this.templateId = templateId;
+    }
+
     /**
      * @return disk offering id that the disk is based on.
      */

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ad8033f9/api/src/com/cloud/vm/UserVmService.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/vm/UserVmService.java 
b/api/src/com/cloud/vm/UserVmService.java
index af4e1d3..c4bca71 100755
--- a/api/src/com/cloud/vm/UserVmService.java
+++ b/api/src/com/cloud/vm/UserVmService.java
@@ -50,6 +50,7 @@ import com.cloud.exception.VirtualMachineMigrationException;
 import com.cloud.host.Host;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.network.Network.IpAddresses;
+import com.cloud.offering.DiskOffering;
 import com.cloud.offering.ServiceOffering;
 import com.cloud.storage.StoragePool;
 import com.cloud.template.VirtualMachineTemplate;
@@ -185,6 +186,11 @@ public interface UserVmService {
      * @param memory
      * @param cpuNumber
      * @param customId
+     * @param dataDiskTemplateToDiskOfferingMap
+     *            - Datadisk template to Disk offering Map
+     *             an optional parameter that creates additional data disks 
for the virtual machine
+     *             For each of the templates in the map, a data disk will be 
created from the corresponding
+     *             disk offering obtained from the map
      * @return UserVm object if successful.
      *
      * @throws InsufficientCapacityException
@@ -199,7 +205,7 @@ public interface UserVmService {
     UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, 
ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> 
securityGroupIdList,
         Account owner, String hostName, String displayName, Long 
diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, 
HTTPMethod httpmethod,
         String userData, String sshKeyPair, Map<Long, IpAddresses> 
requestedIps, IpAddresses defaultIp, Boolean displayVm, String keyboard,
-        List<Long> affinityGroupIdList, Map<String, String> customParameter, 
String customId) throws InsufficientCapacityException,
+        List<Long> affinityGroupIdList, Map<String, String> customParameter, 
String customId, Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap) 
throws InsufficientCapacityException,
         ConcurrentOperationException, ResourceUnavailableException, 
StorageUnavailableException, ResourceAllocationException;
 
     /**
@@ -258,6 +264,11 @@ public interface UserVmService {
      * @param memory
      * @param cpuNumber
      * @param customId
+     * @param dataDiskTemplateToDiskOfferingMap
+     *            - Datadisk template to Disk offering Map
+     *             an optional parameter that creates additional data disks 
for the virtual machine
+     *             For each of the templates in the map, a data disk will be 
created from the corresponding
+     *             disk offering obtained from the map
      * @return UserVm object if successful.
      *
      * @throws InsufficientCapacityException
@@ -272,7 +283,7 @@ public interface UserVmService {
     UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, 
ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> 
networkIdList,
         List<Long> securityGroupIdList, Account owner, String hostName, String 
displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType 
hypervisor,
         HTTPMethod httpmethod, String userData, String sshKeyPair, Map<Long, 
IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String 
keyboard,
-        List<Long> affinityGroupIdList, Map<String, String> customParameters, 
String customId) throws InsufficientCapacityException,
+        List<Long> affinityGroupIdList, Map<String, String> customParameters, 
String customId, Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap) 
throws InsufficientCapacityException,
         ConcurrentOperationException, ResourceUnavailableException, 
StorageUnavailableException, ResourceAllocationException;
 
     /**
@@ -329,6 +340,11 @@ public interface UserVmService {
      * @param memory
      * @param cpuNumber
      * @param customId
+     * @param dataDiskTemplateToDiskOfferingMap
+     *            - Datadisk template to Disk offering Map
+     *             an optional parameter that creates additional data disks 
for the virtual machine
+     *             For each of the templates in the map, a data disk will be 
created from the corresponding
+     *             disk offering obtained from the map
      * @return UserVm object if successful.
      *
      * @throws InsufficientCapacityException
@@ -343,7 +359,7 @@ public interface UserVmService {
     UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering 
serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, 
Account owner,
         String hostName, String displayName, Long diskOfferingId, Long 
diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, 
String userData,
         String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses 
defaultIps, Boolean displayVm, String keyboard, List<Long> affinityGroupIdList,
-        Map<String, String> customParameters, String customId)
+        Map<String, String> customParameters, String customId, Map<Long, 
DiskOffering> dataDiskTemplateToDiskOfferingMap)
 
         throws InsufficientCapacityException, ConcurrentOperationException, 
ResourceUnavailableException, StorageUnavailableException, 
ResourceAllocationException;
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ad8033f9/api/src/org/apache/cloudstack/api/ApiConstants.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java 
b/api/src/org/apache/cloudstack/api/ApiConstants.java
index a3faca7..7ece5d9 100755
--- a/api/src/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/org/apache/cloudstack/api/ApiConstants.java
@@ -67,6 +67,7 @@ public class ApiConstants {
     public static final String MIN_IOPS = "miniops";
     public static final String MAX_IOPS = "maxiops";
     public static final String HYPERVISOR_SNAPSHOT_RESERVE = 
"hypervisorsnapshotreserve";
+    public static final String DATADISKTEMPLATE_TO_DISKOFFERING_LIST = 
"datadisktemplatetodiskofferinglist";
     public static final String DESCRIPTION = "description";
     public static final String DESTINATION_ZONE_ID = "destzoneid";
     public static final String DETAILS = "details";

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ad8033f9/api/src/org/apache/cloudstack/api/ResponseGenerator.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/ResponseGenerator.java 
b/api/src/org/apache/cloudstack/api/ResponseGenerator.java
index 10fb6df..3cb656d 100644
--- a/api/src/org/apache/cloudstack/api/ResponseGenerator.java
+++ b/api/src/org/apache/cloudstack/api/ResponseGenerator.java
@@ -281,6 +281,8 @@ public interface ResponseGenerator {
 
     Host findHostById(Long hostId);
 
+    DiskOffering findDiskOfferingById(Long diskOfferingId);
+
     VpnUsersResponse createVpnUserResponse(VpnUser user);
 
     RemoteAccessVpnResponse createRemoteAccessVpnResponse(RemoteAccessVpn vpn);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ad8033f9/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java 
b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java
index 0adc57b..c59cea2 100755
--- a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java
@@ -190,6 +190,10 @@ public class DeployVMCmd extends 
BaseAsyncCreateCustomIdCmd {
     @Parameter(name = ApiConstants.DEPLOYMENT_PLANNER, type = 
CommandType.STRING, description = "Deployment planner to use for vm allocation. 
Available to ROOT admin only", since = "4.4", authorized = { RoleType.Admin })
     private String deploymentPlanner;
 
+    @Parameter(name = ApiConstants.DATADISKTEMPLATE_TO_DISKOFFERING_LIST, type 
= CommandType.MAP, since = "4.4", description = "datadisk template to 
disk-offering mapping;" +
+            " an optional parameter used to create additional data disks from 
datadisk templates; can't be specified with diskOfferingId parameter")
+    private Map dataDiskTemplateToDiskOfferingList;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -393,6 +397,37 @@ public class DeployVMCmd extends 
BaseAsyncCreateCustomIdCmd {
         }
     }
 
+    public Map<Long, DiskOffering> getDataDiskTemplateToDiskOfferingMap() {
+        if (diskOfferingId != null && dataDiskTemplateToDiskOfferingList != 
null) {
+            throw new InvalidParameterValueException("diskofferingid paramter 
can't be specified along with datadisktemplatetodiskofferinglist parameter");
+        }
+        HashMap<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap = new 
HashMap<Long, DiskOffering>();
+        if (dataDiskTemplateToDiskOfferingList != null && 
!dataDiskTemplateToDiskOfferingList.isEmpty()) {
+            Collection dataDiskTemplatesCollection = 
dataDiskTemplateToDiskOfferingList.values();
+            Iterator iter = dataDiskTemplatesCollection.iterator();
+            while (iter.hasNext()) {
+                HashMap<String, String> dataDiskTemplates = (HashMap<String, 
String>)iter.next();
+                Long dataDiskTemplateId;
+                DiskOffering dataDiskOffering = null;
+                VirtualMachineTemplate dataDiskTemplate= 
_entityMgr.findByUuid(VirtualMachineTemplate.class, 
dataDiskTemplates.get("datadisktemplateid"));
+                if (dataDiskTemplate == null) {
+                    dataDiskTemplate = 
_entityMgr.findById(VirtualMachineTemplate.class, 
dataDiskTemplates.get("datadisktemplateid"));
+                    if (dataDiskTemplate == null)
+                        throw new InvalidParameterValueException("Unable to 
translate and find entity with datadisktemplateid " + 
dataDiskTemplates.get("datadisktemplateid"));
+                }
+                dataDiskTemplateId = dataDiskTemplate.getId();
+                dataDiskOffering = _entityMgr.findByUuid(DiskOffering.class, 
dataDiskTemplates.get("diskofferingid"));
+                if (dataDiskOffering == null) {
+                    dataDiskOffering = _entityMgr.findById(DiskOffering.class, 
dataDiskTemplates.get("diskofferingid"));
+                    if (dataDiskOffering == null)
+                        throw new InvalidParameterValueException("Unable to 
translate and find entity with diskofferingId " + 
dataDiskTemplates.get("diskofferingid"));
+                }
+                dataDiskTemplateToDiskOfferingMap.put(dataDiskTemplateId, 
dataDiskOffering);
+            }
+        }
+        return dataDiskTemplateToDiskOfferingMap;
+    }
+
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
@@ -585,13 +620,13 @@ public class DeployVMCmd extends 
BaseAsyncCreateCustomIdCmd {
                 } else {
                     vm = 
_userVmService.createBasicSecurityGroupVirtualMachine(zone, serviceOffering, 
template, getSecurityGroupIdList(), owner, name, displayName, diskOfferingId,
                             size, group, getHypervisor(), getHttpMethod(), 
userData, sshKeyPairName, getIpToNetworkMap(), addrs, displayVm, keyboard, 
getAffinityGroupIdList(),
-                            getDetails(), getCustomId());
+                            getDetails(), getCustomId(), 
getDataDiskTemplateToDiskOfferingMap());
                 }
             } else {
                 if (zone.isSecurityGroupEnabled())  {
                     vm = 
_userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, 
template, getNetworkIds(), getSecurityGroupIdList(), owner, name,
                             displayName, diskOfferingId, size, group, 
getHypervisor(), getHttpMethod(), userData, sshKeyPairName, 
getIpToNetworkMap(), addrs, displayVm, keyboard,
-                            getAffinityGroupIdList(), getDetails(), 
getCustomId());
+                            getAffinityGroupIdList(), getDetails(), 
getCustomId(), getDataDiskTemplateToDiskOfferingMap());
 
                 } else {
                     if (getSecurityGroupIdList() != null && 
!getSecurityGroupIdList().isEmpty()) {
@@ -599,7 +634,7 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd 
{
                     }
                     vm = _userVmService.createAdvancedVirtualMachine(zone, 
serviceOffering, template, getNetworkIds(), owner, name, displayName, 
diskOfferingId, size, group,
                             getHypervisor(), getHttpMethod(), userData, 
sshKeyPairName, getIpToNetworkMap(), addrs, displayVm, keyboard, 
getAffinityGroupIdList(), getDetails(),
-                            getCustomId());
+                            getCustomId(), 
getDataDiskTemplateToDiskOfferingMap());
                 }
             }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ad8033f9/engine/api/src/com/cloud/vm/VirtualMachineManager.java
----------------------------------------------------------------------
diff --git a/engine/api/src/com/cloud/vm/VirtualMachineManager.java 
b/engine/api/src/com/cloud/vm/VirtualMachineManager.java
index f070210..a1c3809 100644
--- a/engine/api/src/com/cloud/vm/VirtualMachineManager.java
+++ b/engine/api/src/com/cloud/vm/VirtualMachineManager.java
@@ -36,6 +36,7 @@ import com.cloud.exception.OperationTimedoutException;
 import com.cloud.exception.ResourceUnavailableException;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.network.Network;
+import com.cloud.offering.DiskOffering;
 import com.cloud.offering.DiskOfferingInfo;
 import com.cloud.offering.ServiceOffering;
 import com.cloud.storage.StoragePool;
@@ -73,11 +74,12 @@ public interface VirtualMachineManager extends Manager {
      * @param auxiliaryNetworks additional networks to attach the VMs to.
      * @param plan How to deploy the VM.
      * @param hyperType Hypervisor type
+     * @param datadiskTemplateToDiskOfferingMap data disks to be created from 
datadisk templates and attached to the VM
      * @throws InsufficientCapacityException If there are insufficient 
capacity to deploy this vm.
      */
     void allocate(String vmInstanceName, VirtualMachineTemplate template, 
ServiceOffering serviceOffering, DiskOfferingInfo rootDiskOfferingInfo,
         List<DiskOfferingInfo> dataDiskOfferings, LinkedHashMap<? extends 
Network, List<? extends NicProfile>> auxiliaryNetworks, DeploymentPlan plan,
-        HypervisorType hyperType) throws InsufficientCapacityException;
+        HypervisorType hyperType, Map<Long, DiskOffering> 
datadiskTemplateToDiskOfferingMap) throws InsufficientCapacityException;
 
     void allocate(String vmInstanceName, VirtualMachineTemplate template, 
ServiceOffering serviceOffering,
         LinkedHashMap<? extends Network, List<? extends NicProfile>> 
networkProfiles, DeploymentPlan plan, HypervisorType hyperType) throws 
InsufficientCapacityException;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ad8033f9/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java
----------------------------------------------------------------------
diff --git 
a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java
 
b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java
index df0b5e8..90625f7 100644
--- 
a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java
+++ 
b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java
@@ -23,6 +23,7 @@ import java.util.Set;
 
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
+import org.apache.cloudstack.framework.config.ConfigKey;
 
 import com.cloud.agent.api.to.VirtualMachineTO;
 import com.cloud.dc.DataCenter;
@@ -45,7 +46,6 @@ import com.cloud.utils.fsm.NoTransitionException;
 import com.cloud.vm.DiskProfile;
 import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.VirtualMachineProfile;
-import org.apache.cloudstack.framework.config.ConfigKey;
 
 /**
  * VolumeOrchestrationService is a PURE orchestration service on CloudStack
@@ -87,7 +87,8 @@ public interface VolumeOrchestrationService {
 
     void destroyVolume(Volume volume);
 
-    DiskProfile allocateRawVolume(Type type, String name, DiskOffering 
offering, Long size, Long minIops, Long maxIops, VirtualMachine vm, 
VirtualMachineTemplate template, Account owner);
+    DiskProfile allocateRawVolume(Type type, String name, DiskOffering 
offering, Long size, Long minIops, Long maxIops, VirtualMachine vm, 
VirtualMachineTemplate template,
+            Account owner, Long deviceId);
 
     VolumeInfo createVolumeOnPrimaryStorage(VirtualMachine vm, VolumeInfo 
volume, HypervisorType rootDiskHyperType, StoragePool storagePool) throws 
NoTransitionException;
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ad8033f9/engine/api/src/org/apache/cloudstack/engine/service/api/OrchestrationService.java
----------------------------------------------------------------------
diff --git 
a/engine/api/src/org/apache/cloudstack/engine/service/api/OrchestrationService.java
 
b/engine/api/src/org/apache/cloudstack/engine/service/api/OrchestrationService.java
index 93f969f..b259808 100755
--- 
a/engine/api/src/org/apache/cloudstack/engine/service/api/OrchestrationService.java
+++ 
b/engine/api/src/org/apache/cloudstack/engine/service/api/OrchestrationService.java
@@ -36,6 +36,7 @@ import 
org.apache.cloudstack.engine.cloud.entity.api.VolumeEntity;
 import com.cloud.deploy.DeploymentPlan;
 import com.cloud.exception.InsufficientCapacityException;
 import com.cloud.hypervisor.Hypervisor;
+import com.cloud.offering.DiskOffering;
 import com.cloud.vm.NicProfile;
 
 @Path("orchestration")
@@ -56,6 +57,7 @@ public interface OrchestrationService {
      * @param rootDiskTags tags for the root disk
      * @param networks networks that this VM should join
      * @param rootDiskSize size the root disk in case of templates.
+     * @param dataDiskTemplateDiskOfferingMap disk offerings in case of data 
disk templates
      * @return VirtualMachineEntity
      */
     @POST
@@ -65,7 +67,7 @@ public interface OrchestrationService {
         @QueryParam("cpu") int cpu, @QueryParam("speed") int speed, 
@QueryParam("ram") long memory, @QueryParam("disk-size") Long diskSize,
         @QueryParam("compute-tags") List<String> computeTags, 
@QueryParam("root-disk-tags") List<String> rootDiskTags,
         @QueryParam("network-nic-map") Map<String, NicProfile> networkNicMap, 
@QueryParam("deploymentplan") DeploymentPlan plan,
-        @QueryParam("root-disk-size") Long rootDiskSize) throws 
InsufficientCapacityException;
+        @QueryParam("root-disk-size") Long rootDiskSize, 
@QueryParam("datadisktemplate-diskoffering-map") Map<Long, DiskOffering> 
datadiskTemplateToDiskOfferingMap) throws InsufficientCapacityException;
 
     @POST
     VirtualMachineEntity createVirtualMachineFromScratch(@QueryParam("id") 
String id, @QueryParam("owner") String owner, @QueryParam("iso-id") String 
isoId,

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ad8033f9/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
----------------------------------------------------------------------
diff --git 
a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java 
b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
index e15d287..0b07026 100755
--- a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
+++ b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
@@ -29,6 +29,7 @@ import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 import java.util.TimeZone;
 import java.util.UUID;
@@ -40,6 +41,8 @@ import javax.ejb.Local;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import org.apache.log4j.Logger;
+
 import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
 import org.apache.cloudstack.context.CallContext;
 import 
org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
@@ -68,7 +71,6 @@ import 
org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 import org.apache.cloudstack.storage.to.VolumeObjectTO;
 import org.apache.cloudstack.utils.identity.ManagementServerNode;
-import org.apache.log4j.Logger;
 
 import com.cloud.agent.AgentManager;
 import com.cloud.agent.Listener;
@@ -152,6 +154,7 @@ import com.cloud.network.NetworkModel;
 import com.cloud.network.dao.NetworkDao;
 import com.cloud.network.dao.NetworkVO;
 import com.cloud.network.rules.RulesManager;
+import com.cloud.offering.DiskOffering;
 import com.cloud.offering.DiskOfferingInfo;
 import com.cloud.offering.ServiceOffering;
 import com.cloud.org.Cluster;
@@ -161,6 +164,7 @@ import com.cloud.service.dao.ServiceOfferingDao;
 import com.cloud.storage.DiskOfferingVO;
 import com.cloud.storage.Storage.ImageFormat;
 import com.cloud.storage.StoragePool;
+import com.cloud.storage.VMTemplateVO;
 import com.cloud.storage.Volume;
 import com.cloud.storage.Volume.Type;
 import com.cloud.storage.VolumeVO;
@@ -374,7 +378,8 @@ public class VirtualMachineManagerImpl extends ManagerBase 
implements VirtualMac
     @DB
     public void allocate(String vmInstanceName, final VirtualMachineTemplate 
template, ServiceOffering serviceOffering,
             final DiskOfferingInfo rootDiskOfferingInfo, final 
List<DiskOfferingInfo> dataDiskOfferings,
-            final LinkedHashMap<? extends Network, List<? extends NicProfile>> 
auxiliaryNetworks, DeploymentPlan plan, HypervisorType hyperType)
+            final LinkedHashMap<? extends Network, List<? extends NicProfile>> 
auxiliaryNetworks, DeploymentPlan plan, HypervisorType hyperType,
+                    final Map<Long, DiskOffering> 
datadiskTemplateToDiskOfferingMap)
                     throws InsufficientCapacityException {
 
         VMInstanceVO vm = _vmDao.findVMByInstanceName(vmInstanceName);
@@ -412,7 +417,7 @@ public class VirtualMachineManagerImpl extends ManagerBase 
implements VirtualMac
 
                         if (template.getFormat() == ImageFormat.ISO) {
                             volumeMgr.allocateRawVolume(Type.ROOT, "ROOT-" + 
vmFinal.getId(), rootDiskOfferingInfo.getDiskOffering(), 
rootDiskOfferingInfo.getSize(),
-                                    rootDiskOfferingInfo.getMinIops(), 
rootDiskOfferingInfo.getMaxIops(), vmFinal, template, owner);
+                                    rootDiskOfferingInfo.getMinIops(), 
rootDiskOfferingInfo.getMaxIops(), vmFinal, template, owner, null);
                         } else if (template.getFormat() == 
ImageFormat.BAREMETAL) {
                             // Do nothing
                         } else {
@@ -423,7 +428,19 @@ public class VirtualMachineManagerImpl extends ManagerBase 
implements VirtualMac
                         if (dataDiskOfferings != null) {
                             for (DiskOfferingInfo dataDiskOfferingInfo : 
dataDiskOfferings) {
                                 volumeMgr.allocateRawVolume(Type.DATADISK, 
"DATA-" + vmFinal.getId(), dataDiskOfferingInfo.getDiskOffering(), 
dataDiskOfferingInfo.getSize(),
-                                        dataDiskOfferingInfo.getMinIops(), 
dataDiskOfferingInfo.getMaxIops(), vmFinal, template, owner);
+                                        dataDiskOfferingInfo.getMinIops(), 
dataDiskOfferingInfo.getMaxIops(), vmFinal, template, owner, null);
+                            }
+                        }
+
+                        if (datadiskTemplateToDiskOfferingMap != null && 
!datadiskTemplateToDiskOfferingMap.isEmpty()) {
+                            int diskNumber = 1;
+                            for (Entry<Long, DiskOffering> 
dataDiskTemplateToDiskOfferingMap : 
datadiskTemplateToDiskOfferingMap.entrySet()) {
+                                DiskOffering diskOffering = 
dataDiskTemplateToDiskOfferingMap.getValue();
+                                long diskOfferingSize = 
diskOffering.getDiskSize() / (1024 * 1024 * 1024);
+                                VMTemplateVO dataDiskTemplate = 
_templateDao.findById(dataDiskTemplateToDiskOfferingMap.getKey());
+                                volumeMgr.allocateRawVolume(Type.DATADISK, 
"DATA-" + vmFinal.getId() + "-" + String.valueOf(diskNumber), diskOffering, 
diskOfferingSize, null, null,
+                                        vmFinal, dataDiskTemplate, owner, 
Long.valueOf(diskNumber));
+                                diskNumber++;
                             }
                         }
                     }
@@ -437,7 +454,7 @@ public class VirtualMachineManagerImpl extends ManagerBase 
implements VirtualMac
     @Override
     public void allocate(String vmInstanceName, VirtualMachineTemplate 
template, ServiceOffering serviceOffering,
             LinkedHashMap<? extends Network, List<? extends NicProfile>> 
networks, DeploymentPlan plan, HypervisorType hyperType) throws 
InsufficientCapacityException {
-        allocate(vmInstanceName, template, serviceOffering, new 
DiskOfferingInfo(serviceOffering), new ArrayList<DiskOfferingInfo>(), networks, 
plan, hyperType);
+        allocate(vmInstanceName, template, serviceOffering, new 
DiskOfferingInfo(serviceOffering), new ArrayList<DiskOfferingInfo>(), networks, 
plan, hyperType, null);
     }
 
     private VirtualMachineGuru getVmGuru(VirtualMachine vm) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ad8033f9/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/CloudOrchestrator.java
----------------------------------------------------------------------
diff --git 
a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/CloudOrchestrator.java
 
b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/CloudOrchestrator.java
index 2b49954..994bd92 100755
--- 
a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/CloudOrchestrator.java
+++ 
b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/CloudOrchestrator.java
@@ -24,6 +24,7 @@ import java.util.Arrays;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 
 import javax.inject.Inject;
 
@@ -45,6 +46,7 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.network.Network;
 import com.cloud.network.dao.NetworkDao;
 import com.cloud.network.dao.NetworkVO;
+import com.cloud.offering.DiskOffering;
 import com.cloud.offering.DiskOfferingInfo;
 import com.cloud.service.ServiceOfferingVO;
 import com.cloud.service.dao.ServiceOfferingDao;
@@ -155,7 +157,7 @@ public class CloudOrchestrator implements 
OrchestrationService {
     @Override
     public VirtualMachineEntity createVirtualMachine(String id, String owner, 
String templateId, String hostName, String displayName, String hypervisor, int 
cpu,
         int speed, long memory, Long diskSize, List<String> computeTags, 
List<String> rootDiskTags, Map<String, NicProfile> networkNicMap, 
DeploymentPlan plan,
-        Long rootDiskSize) throws InsufficientCapacityException {
+        Long rootDiskSize, Map<Long, DiskOffering> 
dataDiskTemplateToDiskOfferingMap) throws InsufficientCapacityException {
 
         // VirtualMachineEntityImpl vmEntity = new 
VirtualMachineEntityImpl(id, owner, hostName, displayName, cpu, speed, memory, 
computeTags, rootDiskTags, networks,
         // vmEntityManager);
@@ -233,8 +235,19 @@ public class CloudOrchestrator implements 
OrchestrationService {
             dataDiskOfferings.add(dataDiskOfferingInfo);
         }
 
+        if (dataDiskTemplateToDiskOfferingMap != null && 
!dataDiskTemplateToDiskOfferingMap.isEmpty()) {
+            for (Entry<Long, DiskOffering> datadiskTemplateToDiskOffering : 
dataDiskTemplateToDiskOfferingMap.entrySet()) {
+                DiskOffering diskOffering = 
datadiskTemplateToDiskOffering.getValue();
+                if (diskOffering == null) {
+                    throw new InvalidParameterValueException("Unable to find 
disk offering " + vm.getDiskOfferingId());
+                }
+                if (diskOffering.getDiskSize() == 0) { // Custom disk offering 
is not supported for volumes created from datadisk templates
+                    throw new InvalidParameterValueException("Disk offering " 
+ diskOffering + " requires size parameter.");
+                }
+            }
+        }
         _itMgr.allocate(vm.getInstanceName(), _templateDao.findById(new 
Long(templateId)), computeOffering, rootDiskOfferingInfo, dataDiskOfferings, 
networkIpMap, plan,
-            hypervisorType);
+            hypervisorType, dataDiskTemplateToDiskOfferingMap);
 
         return vmEntity;
     }
@@ -299,7 +312,7 @@ public class CloudOrchestrator implements 
OrchestrationService {
 
         HypervisorType hypervisorType = HypervisorType.valueOf(hypervisor);
 
-        _itMgr.allocate(vm.getInstanceName(), _templateDao.findById(new 
Long(isoId)), computeOffering, rootDiskOfferingInfo, new 
ArrayList<DiskOfferingInfo>(), networkIpMap, plan, hypervisorType);
+        _itMgr.allocate(vm.getInstanceName(), _templateDao.findById(new 
Long(isoId)), computeOffering, rootDiskOfferingInfo, new 
ArrayList<DiskOfferingInfo>(), networkIpMap, plan, hypervisorType, null);
 
         return vmEntity;
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ad8033f9/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
----------------------------------------------------------------------
diff --git 
a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
 
b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
index 6256e25..f453f6b 100644
--- 
a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
+++ 
b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
@@ -583,7 +583,7 @@ public class VolumeOrchestrator extends ManagerBase 
implements VolumeOrchestrati
     }
 
     @Override
-    public DiskProfile allocateRawVolume(Type type, String name, DiskOffering 
offering, Long size, Long minIops, Long maxIops, VirtualMachine vm, 
VirtualMachineTemplate template, Account owner) {
+    public DiskProfile allocateRawVolume(Type type, String name, DiskOffering 
offering, Long size, Long minIops, Long maxIops, VirtualMachine vm, 
VirtualMachineTemplate template, Account owner, Long deviceId) {
         if (size == null) {
             size = offering.getDiskSize();
         } else {
@@ -608,13 +608,17 @@ public class VolumeOrchestrator extends ManagerBase 
implements VolumeOrchestrati
             vol.setInstanceId(vm.getId());
         }
 
-        if (type.equals(Type.ROOT)) {
+        if (deviceId != null) {
+            vol.setDeviceId(deviceId);
+        } else if (type.equals(Type.ROOT)) {
             vol.setDeviceId(0l);
         } else {
             vol.setDeviceId(1l);
         }
         if (template.getFormat() == ImageFormat.ISO) {
             vol.setIsoId(template.getId());
+        } else 
if(template.getTemplateType().equals(Storage.TemplateType.DATADISK)) {
+            vol.setTemplateId(template.getId());
         }
         // display flag matters only for the User vms
         if (vm.getType() == VirtualMachine.Type.User) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ad8033f9/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
----------------------------------------------------------------------
diff --git 
a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
 
b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
index ff893b2..131fe0a 100644
--- 
a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
+++ 
b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
@@ -456,7 +456,7 @@ public class VmwareStorageProcessor implements 
StorageProcessor {
                 vmMo = new ClusterMO(context, 
morCluster).findVmOnHyperHost(vmdkName);
                 assert (vmMo != null);
 
-                vmdkFileBaseName = vmMo.getVmdkFileBaseNames().get(0); // 
TO-DO: Support for base template containing multiple disks
+                vmdkFileBaseName = vmMo.getVmdkFileBaseNames().get(0);
                 s_logger.info("Move volume out of volume-wrapper VM ");
                 String[] vmwareLayoutFilePair = 
VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, vmdkName, 
vmdkFileBaseName, VmwareStorageLayoutType.VMWARE, !_fullCloneFlag);
                 String[] legacyCloudStackLayoutFilePair = 
VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, vmdkName, 
vmdkFileBaseName, VmwareStorageLayoutType.CLOUDSTACK_LEGACY, !_fullCloneFlag);
@@ -471,7 +471,9 @@ public class VmwareStorageProcessor implements 
StorageProcessor {
                 vmMo.destroy();
 
                 String srcFile = dsMo.getDatastorePath(vmdkName, true);
-                dsMo.deleteFile(srcFile, dcMo.getMor(), true);
+                if (dsMo.folderExists(String.format("[%s]", dsMo.getName()), 
vmdkName)) {
+                    dsMo.deleteFolder(srcFile, dcMo.getMor());
+                }
             }
             // restoreVM - move the new ROOT disk into corresponding VM folder
             String vmInternalCSName = volume.getVmName();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ad8033f9/server/src/com/cloud/api/ApiResponseHelper.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/ApiResponseHelper.java 
b/server/src/com/cloud/api/ApiResponseHelper.java
index 250f5a9..6d78d62 100755
--- a/server/src/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/com/cloud/api/ApiResponseHelper.java
@@ -1259,6 +1259,11 @@ public class ApiResponseHelper implements 
ResponseGenerator {
     }
 
     @Override
+    public DiskOfferingVO findDiskOfferingById(Long diskOfferingId) {
+        return ApiDBUtils.findDiskOfferingById(diskOfferingId);
+    }
+
+    @Override
     public VpnUsersResponse createVpnUserResponse(VpnUser vpnUser) {
         VpnUsersResponse vpnResponse = new VpnUsersResponse();
         vpnResponse.setId(vpnUser.getUuid());

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ad8033f9/server/src/com/cloud/network/as/AutoScaleManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/as/AutoScaleManagerImpl.java 
b/server/src/com/cloud/network/as/AutoScaleManagerImpl.java
index 09c6694..044eee5 100644
--- a/server/src/com/cloud/network/as/AutoScaleManagerImpl.java
+++ b/server/src/com/cloud/network/as/AutoScaleManagerImpl.java
@@ -1331,18 +1331,18 @@ public class AutoScaleManagerImpl<Type> extends 
ManagerBase implements AutoScale
                 vm = 
_userVmService.createBasicSecurityGroupVirtualMachine(zone, serviceOffering, 
template, null, owner, "autoScaleVm-" + asGroup.getId() + "-" +
                     getCurrentTimeStampString(),
                     "autoScaleVm-" + asGroup.getId() + "-" + 
getCurrentTimeStampString(), null, null, null, HypervisorType.XenServer, 
HTTPMethod.GET, null, null, null,
-                    null, true, null, null, null, null);
+                    null, true, null, null, null, null, null);
             } else {
                 if (zone.isSecurityGroupEnabled()) {
                     vm = 
_userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, 
template, null, null,
                         owner, "autoScaleVm-" + asGroup.getId() + "-" + 
getCurrentTimeStampString(),
                         "autoScaleVm-" + asGroup.getId() + "-" + 
getCurrentTimeStampString(), null, null, null, HypervisorType.XenServer, 
HTTPMethod.GET, null, null,
-                        null, null, true, null, null, null, null);
+                        null, null, true, null, null, null, null, null);
 
                 } else {
                     vm = _userVmService.createAdvancedVirtualMachine(zone, 
serviceOffering, template, null, owner, "autoScaleVm-" + asGroup.getId() + "-" +
                         getCurrentTimeStampString(), "autoScaleVm-" + 
asGroup.getId() + "-" + getCurrentTimeStampString(),
-                        null, null, null, HypervisorType.XenServer, 
HTTPMethod.GET, null, null, null, addrs, true, null, null, null, null);
+                        null, null, null, HypervisorType.XenServer, 
HTTPMethod.GET, null, null, null, addrs, true, null, null, null, null, null);
 
                 }
             }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ad8033f9/server/src/com/cloud/vm/UserVmManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java 
b/server/src/com/cloud/vm/UserVmManagerImpl.java
index 3d262b7..9a0d2a1 100755
--- a/server/src/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/com/cloud/vm/UserVmManagerImpl.java
@@ -183,6 +183,7 @@ import com.cloud.network.security.dao.SecurityGroupDao;
 import com.cloud.network.security.dao.SecurityGroupVMMapDao;
 import com.cloud.network.vpc.VpcManager;
 import com.cloud.network.vpc.dao.VpcDao;
+import com.cloud.offering.DiskOffering;
 import com.cloud.offering.NetworkOffering;
 import com.cloud.offering.NetworkOffering.Availability;
 import com.cloud.offering.ServiceOffering;
@@ -2274,7 +2275,7 @@ public class UserVmManagerImpl extends ManagerBase 
implements UserVmManager, Vir
     public UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, 
ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> 
securityGroupIdList,
             Account owner, String hostName, String displayName, Long 
diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, 
HTTPMethod httpmethod,
             String userData, String sshKeyPair, Map<Long, IpAddresses> 
requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, 
List<Long> affinityGroupIdList,
-            Map<String, String> customParametes, String customId) throws 
InsufficientCapacityException, ConcurrentOperationException, 
ResourceUnavailableException,
+            Map<String, String> customParametes, String customId, Map<Long, 
DiskOffering> datadiskTemplateToDiskOfferringMap) throws 
InsufficientCapacityException, ConcurrentOperationException, 
ResourceUnavailableException,
             StorageUnavailableException, ResourceAllocationException {
 
         Account caller = CallContext.current().getCallingAccount();
@@ -2318,7 +2319,7 @@ public class UserVmManagerImpl extends ManagerBase 
implements UserVmManager, Vir
         }
 
         return createVirtualMachine(zone, serviceOffering, template, hostName, 
displayName, owner, diskOfferingId, diskSize, networkList, securityGroupIdList, 
group, httpmethod,
-                userData, sshKeyPair, hypervisor, caller, requestedIps, 
defaultIps, displayVm, keyboard, affinityGroupIdList, customParametes, 
customId);
+                userData, sshKeyPair, hypervisor, caller, requestedIps, 
defaultIps, displayVm, keyboard, affinityGroupIdList, customParametes, 
customId, datadiskTemplateToDiskOfferringMap);
 
     }
 
@@ -2327,7 +2328,7 @@ public class UserVmManagerImpl extends ManagerBase 
implements UserVmManager, Vir
     public UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, 
ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> 
networkIdList,
             List<Long> securityGroupIdList, Account owner, String hostName, 
String displayName, Long diskOfferingId, Long diskSize, String group, 
HypervisorType hypervisor,
             HTTPMethod httpmethod, String userData, String sshKeyPair, 
Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, 
String keyboard,
-            List<Long> affinityGroupIdList, Map<String, String> 
customParameters, String customId) throws InsufficientCapacityException, 
ConcurrentOperationException,
+            List<Long> affinityGroupIdList, Map<String, String> 
customParameters, String customId, Map<Long, DiskOffering> 
datadiskTemplateToDiskOfferringMap) throws InsufficientCapacityException, 
ConcurrentOperationException,
             ResourceUnavailableException, StorageUnavailableException, 
ResourceAllocationException {
 
         Account caller = CallContext.current().getCallingAccount();
@@ -2425,7 +2426,7 @@ public class UserVmManagerImpl extends ManagerBase 
implements UserVmManager, Vir
         }
 
         return createVirtualMachine(zone, serviceOffering, template, hostName, 
displayName, owner, diskOfferingId, diskSize, networkList, securityGroupIdList, 
group, httpmethod,
-                userData, sshKeyPair, hypervisor, caller, requestedIps, 
defaultIps, displayVm, keyboard, affinityGroupIdList, customParameters, 
customId);
+                userData, sshKeyPair, hypervisor, caller, requestedIps, 
defaultIps, displayVm, keyboard, affinityGroupIdList, customParameters, 
customId, datadiskTemplateToDiskOfferringMap);
     }
 
     @Override
@@ -2433,7 +2434,7 @@ public class UserVmManagerImpl extends ManagerBase 
implements UserVmManager, Vir
     public UserVm createAdvancedVirtualMachine(DataCenter zone, 
ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> 
networkIdList, Account owner,
             String hostName, String displayName, Long diskOfferingId, Long 
diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, 
String userData,
             String sshKeyPair, Map<Long, IpAddresses> requestedIps, 
IpAddresses defaultIps, Boolean displayvm, String keyboard, List<Long> 
affinityGroupIdList,
-            Map<String, String> customParametrs, String customId) throws 
InsufficientCapacityException, ConcurrentOperationException, 
ResourceUnavailableException,
+            Map<String, String> customParametrs, String customId, Map<Long, 
DiskOffering> datadiskTemplateToDiskOfferringMap) throws 
InsufficientCapacityException, ConcurrentOperationException, 
ResourceUnavailableException,
             StorageUnavailableException, ResourceAllocationException {
 
         Account caller = CallContext.current().getCallingAccount();
@@ -2517,7 +2518,7 @@ public class UserVmManagerImpl extends ManagerBase 
implements UserVmManager, Vir
         }
 
         return createVirtualMachine(zone, serviceOffering, template, hostName, 
displayName, owner, diskOfferingId, diskSize, networkList, null, group, 
httpmethod, userData,
-                sshKeyPair, hypervisor, caller, requestedIps, defaultIps, 
displayvm, keyboard, affinityGroupIdList, customParametrs, customId);
+                sshKeyPair, hypervisor, caller, requestedIps, defaultIps, 
displayvm, keyboard, affinityGroupIdList, customParametrs, customId, 
datadiskTemplateToDiskOfferringMap);
     }
 
     public void checkNameForRFCCompliance(String name) {
@@ -2531,7 +2532,7 @@ public class UserVmManagerImpl extends ManagerBase 
implements UserVmManager, Vir
     protected UserVm createVirtualMachine(DataCenter zone, ServiceOffering 
serviceOffering, VirtualMachineTemplate tmplt, String hostName, String 
displayName, Account owner,
             Long diskOfferingId, Long diskSize, List<NetworkVO> networkList, 
List<Long> securityGroupIdList, String group, HTTPMethod httpmethod, String 
userData,
             String sshKeyPair, HypervisorType hypervisor, Account caller, 
Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean 
isDisplayVm, String keyboard,
-            List<Long> affinityGroupIdList, Map<String, String> 
customParameters, String customId) throws InsufficientCapacityException, 
ResourceUnavailableException,
+            List<Long> affinityGroupIdList, Map<String, String> 
customParameters, String customId, Map<Long, DiskOffering> 
dataDiskTemplateToDiskOfferringMap) throws InsufficientCapacityException, 
ResourceUnavailableException,
             ConcurrentOperationException, StorageUnavailableException, 
ResourceAllocationException {
 
         _accountMgr.checkAccess(caller, null, owner);
@@ -2602,6 +2603,32 @@ public class UserVmManagerImpl extends ManagerBase 
implements UserVmManager, Vir
         _resourceLimitMgr.checkResourceLimit(owner, ResourceType.volume, 
(isIso || diskOfferingId == null ? 1 : 2));
         _resourceLimitMgr.checkResourceLimit(owner, 
ResourceType.primary_storage, size);
 
+        if (dataDiskTemplateToDiskOfferringMap != null && 
!dataDiskTemplateToDiskOfferringMap.isEmpty()) {
+            for (Entry<Long, DiskOffering> datadiskTemplateToDiskOffering : 
dataDiskTemplateToDiskOfferringMap.entrySet()) {
+                VMTemplateVO dataDiskTemplate = 
_templateDao.findById(datadiskTemplateToDiskOffering.getKey());
+                DiskOffering dataDiskOffering = 
datadiskTemplateToDiskOffering.getValue();
+
+                if (dataDiskTemplate == null || 
(!dataDiskTemplate.getTemplateType().equals(TemplateType.DATADISK)) &&
+                        
(dataDiskTemplate.getState().equals(VirtualMachineTemplate.State.Active))) {
+                    throw new InvalidParameterValueException("Invalid template 
id specified for Datadisk template" + datadiskTemplateToDiskOffering.getKey());
+                }
+                if 
(!dataDiskTemplate.getParentTemplateId().equals(template.getId())) {
+                    throw new InvalidParameterValueException("Invalid Datadisk 
template. Specified Datadisk template " + 
datadiskTemplateToDiskOffering.getKey()
+                            + " doesn't belong to template " + 
template.getId());
+                }
+                if (dataDiskOffering == null) {
+                    throw new InvalidParameterValueException("Invalid disk 
offering id specified" + datadiskTemplateToDiskOffering.getValue());
+                }
+                _templateDao.loadDetails(dataDiskTemplate);
+                if (dataDiskOffering.isCustomized()) {
+                    throw new InvalidParameterValueException("Invalid disk 
offering id specified" + datadiskTemplateToDiskOffering.getValue() + ". Custom 
Disk offerings are not" +
+                            " supported for Datadisk templates");
+                }
+                _resourceLimitMgr.checkResourceLimit(owner, 
ResourceType.volume, 1);
+                _resourceLimitMgr.checkResourceLimit(owner, 
ResourceType.primary_storage, dataDiskOffering.getDiskSize());
+            }
+        }
+
         // verify security group ids
         if (securityGroupIdList != null) {
             for (Long securityGroupId : securityGroupIdList) {
@@ -2785,7 +2812,7 @@ public class UserVmManagerImpl extends ManagerBase 
implements UserVmManager, Vir
         }
 
         UserVmVO vm = commitUserVm(zone, template, hostName, displayName, 
owner, diskOfferingId, diskSize, userData, hypervisor, caller, isDisplayVm, 
keyboard, accountId,
-                offering, isIso, sshPublicKey, networkNicMap, id, 
instanceName, uuidName, hypervisorType, customParameters);
+                offering, isIso, sshPublicKey, networkNicMap, id, 
instanceName, uuidName, hypervisorType, customParameters, 
dataDiskTemplateToDiskOfferringMap);
 
         // Assign instance to the group
         try {
@@ -2845,7 +2872,7 @@ public class UserVmManagerImpl extends ManagerBase 
implements UserVmManager, Vir
             final Long diskOfferingId, final Long diskSize, final String 
userData, final HypervisorType hypervisor, final Account caller, final Boolean 
isDisplayVm,
             final String keyboard, final long accountId, final 
ServiceOfferingVO offering, final boolean isIso, final String sshPublicKey,
             final LinkedHashMap<String, NicProfile> networkNicMap, final long 
id, final String instanceName, final String uuidName, final HypervisorType 
hypervisorType,
-            final Map<String, String> customParameters) throws 
InsufficientCapacityException {
+            final Map<String, String> customParameters, final Map<Long, 
DiskOffering> dataDiskTemplateToDiskOfferingMap) throws 
InsufficientCapacityException {
         return Transaction.execute(new 
TransactionCallbackWithException<UserVmVO, InsufficientCapacityException>() {
             @Override
             public UserVmVO doInTransaction(TransactionStatus status) throws 
InsufficientCapacityException {
@@ -2954,7 +2981,7 @@ public class UserVmManagerImpl extends ManagerBase 
implements UserVmManager, Vir
                             networkNicMap, plan);
                 } else {
                     _orchSrvc.createVirtualMachine(vm.getUuid(), 
Long.toString(owner.getAccountId()), Long.toString(template.getId()), hostName, 
displayName, hypervisor.name(),
-                            offering.getCpu(), offering.getSpeed(), 
offering.getRamSize(), diskSize, computeTags, rootDiskTags, networkNicMap, 
plan, rootDiskSize);
+                            offering.getCpu(), offering.getSpeed(), 
offering.getRamSize(), diskSize, computeTags, rootDiskTags, networkNicMap, 
plan, rootDiskSize, dataDiskTemplateToDiskOfferingMap);
                 }
 
                 if (s_logger.isDebugEnabled()) {

Reply via email to