You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by mt...@apache.org on 2013/10/04 23:42:17 UTC

git commit: updated refs/heads/master to bced4c7

Updated Branches:
  refs/heads/master 66b853789 -> bced4c7e8


Add support for hypervisor snapshots to CloudStack-managed storage (for XenServer and VMware)


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

Branch: refs/heads/master
Commit: bced4c7e8ba791ebcd5a8117cf30445388233d68
Parents: 66b8537
Author: Mike Tutkowski <mi...@solidfire.com>
Authored: Wed Oct 2 00:07:48 2013 -0600
Committer: Mike Tutkowski <mi...@solidfire.com>
Committed: Fri Oct 4 15:41:20 2013 -0600

----------------------------------------------------------------------
 .../cloud/agent/api/AttachVolumeCommand.java    |  8 +-
 .../api/agent/test/AttachVolumeAnswerTest.java  |  2 +-
 .../api/agent/test/AttachVolumeCommandTest.java |  2 +-
 .../vmware/manager/VmwareHostService.java       |  6 +-
 .../vmware/resource/VmwareResource.java         | 66 +++++++-------
 .../VmwareSecondaryStorageResourceHandler.java  |  9 +-
 .../resource/VmwareStorageProcessor.java        | 43 +++++++---
 .../xen/resource/CitrixResourceBase.java        | 90 ++++++++++----------
 .../xen/resource/XenServerStorageProcessor.java | 14 ++-
 .../driver/SolidfirePrimaryDataStoreDriver.java |  4 +-
 .../storage/datastore/util/SolidFireUtil.java   | 22 +++--
 .../com/cloud/storage/VolumeApiServiceImpl.java | 13 ++-
 12 files changed, 172 insertions(+), 107 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/bced4c7e/core/src/com/cloud/agent/api/AttachVolumeCommand.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/agent/api/AttachVolumeCommand.java b/core/src/com/cloud/agent/api/AttachVolumeCommand.java
index 49b2a70..e927619 100644
--- a/core/src/com/cloud/agent/api/AttachVolumeCommand.java
+++ b/core/src/com/cloud/agent/api/AttachVolumeCommand.java
@@ -25,6 +25,7 @@ public class AttachVolumeCommand extends Command {
     private StoragePoolType pooltype;
     private String volumePath;
     private String volumeName;
+    private Long volumeSize;
     private Long deviceId;
     private String chainInfo;
     private String poolUuid;
@@ -45,13 +46,14 @@ public class AttachVolumeCommand extends Command {
 
     public AttachVolumeCommand(boolean attach, boolean managed, String vmName,
             StoragePoolType pooltype, String volumePath, String volumeName,
-            Long deviceId, String chainInfo) {
+            Long volumeSize, Long deviceId, String chainInfo) {
         this.attach = attach;
         this._managed = managed;
         this.vmName = vmName;
         this.pooltype = pooltype;
         this.volumePath = volumePath;
         this.volumeName = volumeName;
+        this.volumeSize = volumeSize;
         this.deviceId = deviceId;
         this.chainInfo = chainInfo;
     }
@@ -85,6 +87,10 @@ public class AttachVolumeCommand extends Command {
 	    return volumeName;
     }
 
+    public Long getVolumeSize() {
+        return volumeSize;
+    }
+
     public Long getDeviceId() {
         return deviceId;
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/bced4c7e/core/test/org/apache/cloudstack/api/agent/test/AttachVolumeAnswerTest.java
----------------------------------------------------------------------
diff --git a/core/test/org/apache/cloudstack/api/agent/test/AttachVolumeAnswerTest.java b/core/test/org/apache/cloudstack/api/agent/test/AttachVolumeAnswerTest.java
index 0b2bb1f..5262d3b 100644
--- a/core/test/org/apache/cloudstack/api/agent/test/AttachVolumeAnswerTest.java
+++ b/core/test/org/apache/cloudstack/api/agent/test/AttachVolumeAnswerTest.java
@@ -27,7 +27,7 @@ import com.cloud.storage.Storage.StoragePoolType;
 
 public class AttachVolumeAnswerTest {
     AttachVolumeCommand avc = new AttachVolumeCommand(true, false, "vmname",
-            StoragePoolType.Filesystem, "vPath", "vName",
+            StoragePoolType.Filesystem, "vPath", "vName", 1073741824L,
             123456789L, "chainInfo");
     AttachVolumeAnswer ava1 = new AttachVolumeAnswer(avc);
     String results = "";

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/bced4c7e/core/test/org/apache/cloudstack/api/agent/test/AttachVolumeCommandTest.java
----------------------------------------------------------------------
diff --git a/core/test/org/apache/cloudstack/api/agent/test/AttachVolumeCommandTest.java b/core/test/org/apache/cloudstack/api/agent/test/AttachVolumeCommandTest.java
index 6f413c0..1c5caca 100644
--- a/core/test/org/apache/cloudstack/api/agent/test/AttachVolumeCommandTest.java
+++ b/core/test/org/apache/cloudstack/api/agent/test/AttachVolumeCommandTest.java
@@ -26,7 +26,7 @@ import com.cloud.storage.Storage.StoragePoolType;
 
 public class AttachVolumeCommandTest {
     AttachVolumeCommand avc = new AttachVolumeCommand(true, false, "vmname",
-            StoragePoolType.Filesystem, "vPath", "vName",
+            StoragePoolType.Filesystem, "vPath", "vName", 1073741824L,
             123456789L, "chainInfo");
 
     @Test

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/bced4c7e/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareHostService.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareHostService.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareHostService.java
index 2b44071..d0147d1 100644
--- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareHostService.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareHostService.java
@@ -17,6 +17,7 @@
 package com.cloud.hypervisor.vmware.manager;
 
 import com.cloud.agent.api.Command;
+import com.cloud.hypervisor.vmware.mo.DatastoreMO;
 import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost;
 import com.cloud.hypervisor.vmware.util.VmwareContext;
 import com.vmware.vim25.ManagedObjectReference;
@@ -28,7 +29,8 @@ public interface VmwareHostService {
 
     String getWorkerName(VmwareContext context, Command cmd, int workerSequence);
 
-    ManagedObjectReference handleDatastoreAndVmdkAttach(Command cmd, String iqn, String storageHost, int storagePort,
-            String initiatorUsername, String initiatorPassword, String targetUsername, String targetPassword) throws Exception;
+    ManagedObjectReference getVmfsDatastore(VmwareHypervisorHost hyperHost, String datastoreName, String storageIpAddress, int storagePortNumber,
+            String iqn, String initiatorChapName, String initiatorChapSecret, String mutualChapName, String mutualChapSecret) throws Exception;
+    void createVmdk(Command cmd, DatastoreMO dsMo, String volumeDatastorePath, Long volumeSize) throws Exception;
     void handleDatastoreAndVmdkDetach(String iqn, String storageHost, int storagePort) throws Exception;
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/bced4c7e/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
index 83dcc58..6b3731ce 100755
--- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
@@ -4439,7 +4439,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
         return str.replace('/', '-');
     }
 
-    private String trimIqn(String iqn) {
+    public static String trimIqn(String iqn) {
         String[] tmp = iqn.split("/");
 
         if (tmp.length != 3) {
@@ -4454,36 +4454,23 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
     }
 
     @Override
-    public ManagedObjectReference handleDatastoreAndVmdkAttach(Command cmd, String iqn, String storageHost, int storagePort,
-            String initiatorUsername, String initiatorPassword, String targetUsername, String targetPassword) throws Exception {
+    public void createVmdk(Command cmd, DatastoreMO dsMo, String vmdkDatastorePath, Long volumeSize) throws Exception {
         VmwareContext context = getServiceContext();
         VmwareHypervisorHost hyperHost = getHyperHost(context);
 
-        ManagedObjectReference morDs = createVmfsDatastore(hyperHost, getDatastoreName(iqn),
-                                                           storageHost, storagePort, trimIqn(iqn),
-                                                           initiatorUsername, initiatorPassword,
-                                                           targetUsername, targetPassword);
+        String dummyVmName = getWorkerName(context, cmd, 0);
 
-        DatastoreMO dsMo = new DatastoreMO(context, morDs);
+        VirtualMachineMO vmMo = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, dummyVmName);
 
-        String volumeDatastorePath = String.format("[%s] %s.vmdk", dsMo.getName(), dsMo.getName());
-
-        if (!dsMo.fileExists(volumeDatastorePath)) {
-            String dummyVmName = getWorkerName(context, cmd, 0);
-
-            VirtualMachineMO vmMo = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, dummyVmName);
-
-            if (vmMo == null) {
-                throw new Exception("Unable to create a dummy VM for volume creation");
-            }
-
-            vmMo.createDisk(volumeDatastorePath, getMBsFromBytes(dsMo.getSummary().getFreeSpace()),
-                    morDs, vmMo.getScsiDeviceControllerKey());
-            vmMo.detachDisk(volumeDatastorePath, false);
-            vmMo.destroy();
+        if (vmMo == null) {
+            throw new Exception("Unable to create a dummy VM for volume creation");
         }
 
-        return morDs;
+        Long volumeSizeToUse = volumeSize < dsMo.getSummary().getFreeSpace() ? volumeSize : dsMo.getSummary().getFreeSpace();
+
+        vmMo.createDisk(vmdkDatastorePath, getMBsFromBytes(volumeSizeToUse), dsMo.getMor(), vmMo.getScsiDeviceControllerKey());
+        vmMo.detachDisk(vmdkDatastorePath, false);
+        vmMo.destroy();
     }
 
     @Override
@@ -4516,9 +4503,16 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
             ManagedObjectReference morDs = null;
 
             if (cmd.getAttach() && cmd.isManaged()) {
-                morDs = handleDatastoreAndVmdkAttach(cmd, cmd.get_iScsiName(), cmd.getStorageHost(), cmd.getStoragePort(),
-                        cmd.getChapInitiatorUsername(), cmd.getChapInitiatorPassword(),
-                        cmd.getChapTargetUsername(), cmd.getChapTargetPassword());
+                morDs = getVmfsDatastore(hyperHost, getDatastoreName(cmd.get_iScsiName()), cmd.getStorageHost(), cmd.getStoragePort(), trimIqn(cmd.get_iScsiName()),
+                            cmd.getChapInitiatorUsername(), cmd.getChapInitiatorPassword(), cmd.getChapTargetUsername(), cmd.getChapTargetPassword());
+
+                DatastoreMO dsMo = new DatastoreMO(getServiceContext(), morDs);
+
+                String volumeDatastorePath = String.format("[%s] %s.vmdk", dsMo.getName(), dsMo.getName());
+
+                if (!dsMo.fileExists(volumeDatastorePath)) {
+                    createVmdk(cmd, dsMo, VmwareResource.getDatastoreName(cmd.get_iScsiName()), cmd.getVolumeSize());
+                }
             }
             else {
                 morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, cmd.getPoolUuid());
@@ -4531,10 +4525,18 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
             }
 
             DatastoreMO dsMo = new DatastoreMO(getServiceContext(), morDs);
-            VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dsMo.getOwnerDatacenter().first(), cmd.getVmName(), 
-            	dsMo, cmd.getVolumePath());
-            
-            String datastoreVolumePath = dsMo.searchFileInSubFolders(cmd.getVolumePath() + ".vmdk", true);
+
+            String datastoreVolumePath = null;
+
+            if (cmd.isManaged()) {
+                datastoreVolumePath = dsMo.getDatastorePath(dsMo.getName() + ".vmdk");
+            }
+            else {
+                VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dsMo.getOwnerDatacenter().first(), cmd.getVmName(), dsMo, cmd.getVolumePath());
+
+                datastoreVolumePath = dsMo.searchFileInSubFolders(cmd.getVolumePath() + ".vmdk", true);
+            }
+
             assert (datastoreVolumePath != null) : "Virtual disk file must exist in specified datastore for attach/detach operations.";
             if (datastoreVolumePath == null) {
                 throw new CloudRuntimeException("Unable to find file " + cmd.getVolumePath() + ".vmdk in datastore " + dsMo.getName());
@@ -4687,7 +4689,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
         }
     }
 
-    private ManagedObjectReference createVmfsDatastore(VmwareHypervisorHost hyperHost, String datastoreName, String storageIpAddress,
+    public ManagedObjectReference getVmfsDatastore(VmwareHypervisorHost hyperHost, String datastoreName, String storageIpAddress,
             int storagePortNumber, String iqn, String chapName, String chapSecret, String mutualChapName, String mutualChapSecret) throws Exception {
         VmwareContext context = getServiceContext();
         ManagedObjectReference morCluster = hyperHost.getHyperHostCluster();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/bced4c7e/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java
index 2c302ab..c84813f 100644
--- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java
@@ -37,6 +37,7 @@ import com.cloud.hypervisor.vmware.manager.VmwareStorageManager;
 import com.cloud.hypervisor.vmware.manager.VmwareStorageManagerImpl;
 import com.cloud.hypervisor.vmware.manager.VmwareStorageMount;
 import com.cloud.hypervisor.vmware.mo.ClusterMO;
+import com.cloud.hypervisor.vmware.mo.DatastoreMO;
 import com.cloud.hypervisor.vmware.mo.HostMO;
 import com.cloud.hypervisor.vmware.mo.VmwareHostType;
 import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost;
@@ -347,8 +348,12 @@ public class VmwareSecondaryStorageResourceHandler implements SecondaryStorageRe
         return true;
     }
 
-    public ManagedObjectReference handleDatastoreAndVmdkAttach(Command cmd, String iqn, String storageHost, int storagePort,
-            String initiatorUsername, String initiatorPassword, String targetUsername, String targetPassword) throws Exception {
+    public ManagedObjectReference getVmfsDatastore(VmwareHypervisorHost hyperHost, String datastoreName, String storageIpAddress, int storagePortNumber,
+            String iqn, String initiatorChapName, String initiatorChapSecret, String mutualChapName, String mutualChapSecret) throws Exception {
+        throw new OperationNotSupportedException();
+    }
+
+    public void createVmdk(Command cmd, DatastoreMO dsMo, String volumeDatastorePath, Long volumeSize) throws Exception {
         throw new OperationNotSupportedException();
     }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/bced4c7e/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 a14c403..34bfe18 100644
--- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
@@ -1191,8 +1191,16 @@ public class VmwareStorageProcessor implements StorageProcessor {
             ManagedObjectReference morDs = null;
 
             if (isAttach && isManaged) {
-                morDs = hostService.handleDatastoreAndVmdkAttach(cmd, iScsiName, storageHost, storagePort,
-                        initiatorUsername, initiatorPassword, targetUsername, targetPassword);
+                morDs = hostService.getVmfsDatastore(hyperHost, VmwareResource.getDatastoreName(iScsiName), storageHost, storagePort,
+                            VmwareResource.trimIqn(iScsiName), initiatorUsername, initiatorPassword, targetUsername, targetPassword);
+
+                DatastoreMO dsMo = new DatastoreMO(hostService.getServiceContext(null), morDs);
+
+                String volumeDatastorePath = String.format("[%s] %s.vmdk", dsMo.getName(), dsMo.getName());
+
+                if (!dsMo.fileExists(volumeDatastorePath)) {
+                    hostService.createVmdk(cmd, dsMo, VmwareResource.getDatastoreName(iScsiName), volumeTO.getSize());
+                }
             }
             else {
                 morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, isManaged ? VmwareResource.getDatastoreName(iScsiName) : primaryStore.getUuid());
@@ -1207,24 +1215,35 @@ public class VmwareStorageProcessor implements StorageProcessor {
             DatastoreMO dsMo = new DatastoreMO(this.hostService.getServiceContext(null), morDs);
             String datastoreVolumePath;
 
-            if(isAttach) {
-                if(!isManaged)
-                    datastoreVolumePath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dsMo.getOwnerDatacenter().first(), vmName,
-                            dsMo, volumeTO.getPath());
-                else
+            if (isAttach) {
+                if (isManaged) {
                     datastoreVolumePath = dsMo.getDatastorePath(dsMo.getName() + ".vmdk");
-            } else {
-                datastoreVolumePath = VmwareStorageLayoutHelper.getLegacyDatastorePathFromVmdkFileName(dsMo, volumeTO.getPath() + ".vmdk");
-                if(!dsMo.fileExists(datastoreVolumePath))
-                    datastoreVolumePath = VmwareStorageLayoutHelper.getVmwareDatastorePathFromVmdkFileName(dsMo, vmName, volumeTO.getPath() + ".vmdk");
+                }
+                else {
+                    datastoreVolumePath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dsMo.getOwnerDatacenter().first(), vmName, dsMo, volumeTO.getPath());
+                }
+            }
+            else {
+                if (isManaged) {
+                    datastoreVolumePath = dsMo.getDatastorePath(dsMo.getName() + ".vmdk");
+                }
+                else {
+                    datastoreVolumePath = VmwareStorageLayoutHelper.getLegacyDatastorePathFromVmdkFileName(dsMo, volumeTO.getPath() + ".vmdk");
+
+                    if (!dsMo.fileExists(datastoreVolumePath)) {
+                        datastoreVolumePath = VmwareStorageLayoutHelper.getVmwareDatastorePathFromVmdkFileName(dsMo, vmName, volumeTO.getPath() + ".vmdk");
+                    }
+                }
             }
 
             disk.setVdiUuid(datastoreVolumePath);
 
             AttachAnswer answer = new AttachAnswer(disk);
+
             if (isAttach) {
                 vmMo.attachDisk(new String[] { datastoreVolumePath }, morDs);
-            } else {
+            }
+            else {
                 vmMo.removeAllSnapshots();
                 vmMo.detachDisk(datastoreVolumePath, false);
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/bced4c7e/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
index 6b81c25..92fbab2 100644
--- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
+++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
@@ -5348,7 +5348,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
             if (pool.getType() == StoragePoolType.NetworkFilesystem) {
                 getNfsSR(conn, pool);
             } else if (pool.getType() == StoragePoolType.IscsiLUN) {
-                getIscsiSR(conn, pool.getUuid(), pool.getHost(), pool.getPath(), null, null, new Boolean[1]);
+                getIscsiSR(conn, pool.getUuid(), pool.getHost(), pool.getPath(), null, null);
             } else if (pool.getType() == StoragePoolType.PreSetup) {
             } else {
                 return new Answer(cmd, false, "The pool type: " + pool.getType().name() + " is not supported.");
@@ -6166,17 +6166,27 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
     }
 
     protected VDI getVDIbyUuid(Connection conn, String uuid) {
+        return getVDIbyUuid(conn, uuid, true);
+    }
+
+    protected VDI getVDIbyUuid(Connection conn, String uuid, boolean throwExceptionIfNotFound) {
         try {
             return VDI.getByUuid(conn, uuid);
         } catch (Exception e) {
-            String msg = "Catch Exception " + e.getClass().getName() + " :VDI getByUuid for uuid: " + uuid + " failed due to " + e.toString();
-            s_logger.debug(msg);
-            throw new CloudRuntimeException(msg, e);
+            if (throwExceptionIfNotFound) {
+                String msg = "Catch Exception " + e.getClass().getName() + " :VDI getByUuid for uuid: " + uuid + " failed due to " + e.toString();
+
+                s_logger.debug(msg);
+
+                throw new CloudRuntimeException(msg, e);
+            }
+
+            return null;
         }
     }
 
     protected SR getIscsiSR(Connection conn, String srNameLabel, String target, String path,
-            String chapInitiatorUsername, String chapInitiatorPassword, Boolean[] created) {
+            String chapInitiatorUsername, String chapInitiatorPassword) {
         synchronized (srNameLabel.intern()) {
             Map<String, String> deviceConfig = new HashMap<String, String>();
             try {
@@ -6280,8 +6290,6 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
                 {
                     sr = SR.create(conn, host, deviceConfig, new Long(0), srNameLabel, srNameLabel, type, "user", true,
                             smConfig);
-
-                    created[0] = true; // note that the SR was created (as opposed to introduced)
                 } else {
                     sr = SR.introduce(conn, pooluuid, srNameLabel, srNameLabel,
                             type, "user", true, smConfig);
@@ -6459,54 +6467,41 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
         }
     }
 
-    protected VDI handleSrAndVdiAttach(String iqn, String storageHostName,
-            String chapInitiatorName, String chapInitiatorPassword) throws Types.XenAPIException, XmlRpcException {
+    protected VDI createVdi(SR sr, String vdiNameLabel, Long volumeSize) throws Types.XenAPIException, XmlRpcException {
         VDI vdi = null;
 
         Connection conn = getConnection();
 
-        Boolean[] created = { false };
-
-        SR sr = getIscsiSR(conn, iqn,
-                storageHostName, iqn,
-                chapInitiatorName, chapInitiatorPassword, created);
-
-        // if created[0] is true, this means the SR was actually created...as opposed to introduced
-        if (created[0]) {
-            VDI.Record vdir = new VDI.Record();
-
-            vdir.nameLabel = iqn;
-            vdir.SR = sr;
-            vdir.type = Types.VdiType.USER;
+        VDI.Record vdir = new VDI.Record();
 
-            long totalSpace = sr.getPhysicalSize(conn);
-            long unavailableSpace = sr.getPhysicalUtilisation(conn);
+        vdir.nameLabel = vdiNameLabel;
+        vdir.SR = sr;
+        vdir.type = Types.VdiType.USER;
 
-            vdir.virtualSize = totalSpace - unavailableSpace;
+        long totalSrSpace = sr.getPhysicalSize(conn);
+        long unavailableSrSpace = sr.getPhysicalUtilisation(conn);
+        long availableSrSpace = totalSrSpace - unavailableSrSpace;
 
-            if (vdir.virtualSize < 0) {
-                throw new CloudRuntimeException("VDI virtual size cannot be less than 0.");
-            }
+        if (availableSrSpace < volumeSize) {
+            throw new CloudRuntimeException("Available space for SR cannot be less than " + volumeSize + ".");
+        }
 
-            long maxNumberOfTries = (totalSpace / unavailableSpace >= 1) ? (totalSpace / unavailableSpace) : 1;
-            long tryNumber = 0;
+        vdir.virtualSize = volumeSize;
 
-            while (tryNumber <= maxNumberOfTries) {
-                try {
-                    vdi = VDI.create(conn, vdir);
+        long maxNumberOfTries = (totalSrSpace / unavailableSrSpace >= 1) ? (totalSrSpace / unavailableSrSpace) : 1;
+        long tryNumber = 0;
 
-                    break;
-                }
-                catch (Exception ex) {
-                    tryNumber++;
+        while (tryNumber <= maxNumberOfTries) {
+            try {
+                vdi = VDI.create(conn, vdir);
 
-                    vdir.virtualSize -= unavailableSpace;
-                }
+                break;
             }
+            catch (Exception ex) {
+                tryNumber++;
 
-        }
-        else {
-            vdi = sr.getVDIs(conn).iterator().next();
+                vdir.virtualSize -= unavailableSrSpace;
+            }
         }
 
         return vdi;
@@ -6534,12 +6529,17 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
         }
 
         try {
-            // Look up the VDI
             VDI vdi = null;
 
             if (cmd.getAttach() && cmd.isManaged()) {
-                vdi = handleSrAndVdiAttach(cmd.get_iScsiName(), cmd.getStorageHost(),
-                        cmd.getChapInitiatorUsername(), cmd.getChapInitiatorPassword());
+                SR sr = getIscsiSR(conn, cmd.get_iScsiName(), cmd.getStorageHost(), cmd.get_iScsiName(),
+                            cmd.getChapInitiatorUsername(), cmd.getChapInitiatorPassword());
+
+                vdi = getVDIbyUuid(conn, cmd.getVolumePath(), false);
+
+                if (vdi == null) {
+                    vdi = createVdi(sr, cmd.get_iScsiName(), cmd.getVolumeSize());
+                }
             }
             else {
                 vdi = getVDIbyUuid(conn, cmd.getVolumePath());

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/bced4c7e/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java
index 5da0571..2d4c86e 100644
--- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java
+++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java
@@ -167,12 +167,20 @@ public class XenServerStorageProcessor implements StorageProcessor {
 
         try {
             Connection conn = this.hypervisorResource.getConnection();
-            // Look up the VDI
+
             VDI vdi = null;
 
             if (cmd.isManaged()) {
-                vdi = this.hypervisorResource.handleSrAndVdiAttach(cmd.get_iScsiName(), cmd.getStorageHost(),
-                        cmd.getChapInitiatorUsername(), cmd.getChapInitiatorPassword());
+                SR sr = this.hypervisorResource.getIscsiSR(conn, cmd.get_iScsiName(), cmd.getStorageHost(), cmd.get_iScsiName(),
+                            cmd.getChapInitiatorUsername(), cmd.getChapInitiatorPassword());
+
+                vdi = this.hypervisorResource.getVDIbyUuid(conn, data.getPath(), false);
+
+                if (vdi == null) {
+                    VolumeObjectTO volume = (VolumeObjectTO)data;
+
+                    vdi = this.hypervisorResource.createVdi(sr, cmd.get_iScsiName(), volume.getSize());
+                }
             }
             else {
                 vdi = this.hypervisorResource.mount(conn, null, null, data.getPath());

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/bced4c7e/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java
index c73e409..8046b6c 100644
--- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java
+++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java
@@ -277,8 +277,10 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
             iops = new Iops(volumeInfo.getMinIops(), volumeInfo.getMaxIops(), getDefaultBurstIops(storagePoolId, volumeInfo.getMaxIops()));
         }
 
+        long volumeSize = volumeInfo.getSize() * 2; // in reality, use a multiplier that's at cluster-level scope
+
         long sfVolumeId = SolidFireUtil.createSolidFireVolume(mVip, mPort, clusterAdminUsername, clusterAdminPassword,
-                getSolidFireVolumeName(volumeInfo.getName()), sfAccountId, volumeInfo.getSize(), true,
+                getSolidFireVolumeName(volumeInfo.getName()), sfAccountId, volumeSize, true, volumeInfo.getSize().toString(),
                 iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops());
 
         return SolidFireUtil.getSolidFireVolume(mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfVolumeId);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/bced4c7e/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java
index ac11272..6659f98 100644
--- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java
+++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java
@@ -78,13 +78,13 @@ public class SolidFireUtil
     public static final String USE_MUTUAL_CHAP_FOR_VMWARE = "useMutualChapForVMware";
 
     public static long createSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword,
-            String strSfVolumeName, long lSfAccountId, long lTotalSize, boolean bEnable512e,
+            String strSfVolumeName, long lSfAccountId, long lTotalSize, boolean bEnable512e, final String strCloudStackVolumeSize,
             long lMinIops, long lMaxIops, long lBurstIops)
     {
         final Gson gson = new GsonBuilder().create();
 
         VolumeToCreate volumeToCreate = new VolumeToCreate(strSfVolumeName, lSfAccountId, lTotalSize, bEnable512e,
-                lMinIops, lMaxIops, lBurstIops);
+                strCloudStackVolumeSize, lMinIops, lMaxIops, lBurstIops);
 
         String strVolumeToCreateJson = gson.toJson(volumeToCreate);
 
@@ -443,10 +443,10 @@ public class SolidFireUtil
         private final VolumeToCreateParams params;
 
         private VolumeToCreate(final String strVolumeName, final long lAccountId, final long lTotalSize,
-                final boolean bEnable512e, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS)
+                final boolean bEnable512e, final String strCloudStackVolumeSize, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS)
         {
             params = new VolumeToCreateParams(strVolumeName, lAccountId, lTotalSize, bEnable512e,
-                    lMinIOPS, lMaxIOPS, lBurstIOPS);
+                    strCloudStackVolumeSize, lMinIOPS, lMaxIOPS, lBurstIOPS);
         }
 
         private static final class VolumeToCreateParams
@@ -456,18 +456,30 @@ public class SolidFireUtil
             private final long totalSize;
             private final boolean enable512e;
             private final VolumeToCreateParamsQoS qos;
+            private final VolumeToCreateParamsAttributes attributes;
 
             private VolumeToCreateParams(final String strVolumeName, final long lAccountId, final long lTotalSize,
-                    final boolean bEnable512e, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS)
+                    final boolean bEnable512e, final String strCloudStackVolumeSize, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS)
             {
                 name = strVolumeName;
                 accountID = lAccountId;
                 totalSize = lTotalSize;
                 enable512e = bEnable512e;
 
+                attributes = new VolumeToCreateParamsAttributes(strCloudStackVolumeSize);
                 qos = new VolumeToCreateParamsQoS(lMinIOPS, lMaxIOPS, lBurstIOPS);
             }
 
+            private static final class VolumeToCreateParamsAttributes
+            {
+                private final String CloudStackVolumeSize;
+
+                private VolumeToCreateParamsAttributes(final String strCloudStackVolumeSize)
+                {
+                    CloudStackVolumeSize = strCloudStackVolumeSize;
+                }
+            }
+
             private static final class VolumeToCreateParamsQoS
             {
                 private final long minIOPS;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/bced4c7e/server/src/com/cloud/storage/VolumeApiServiceImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/com/cloud/storage/VolumeApiServiceImpl.java
index faff10f..5161ca5 100644
--- a/server/src/com/cloud/storage/VolumeApiServiceImpl.java
+++ b/server/src/com/cloud/storage/VolumeApiServiceImpl.java
@@ -1047,8 +1047,17 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
         HypervisorType rootDiskHyperType = vm.getHypervisorType();
 
         HypervisorType dataDiskHyperType = _volsDao.getHypervisorType(volume.getId());
-        if (dataDiskHyperType != HypervisorType.None && rootDiskHyperType != dataDiskHyperType) {
-            throw new InvalidParameterValueException("Can't attach a volume created by: " + dataDiskHyperType + " to a " + rootDiskHyperType + " vm");
+
+        VolumeVO dataDiskVol = _volsDao.findById(volume.getId());
+        StoragePoolVO dataDiskStoragePool = _storagePoolDao.findById(dataDiskVol.getPoolId());
+
+        // managed storage can be used for different types of hypervisors
+        // only perform this check if the volume's storage pool is not null and not managed
+        if (dataDiskStoragePool != null && !dataDiskStoragePool.isManaged()) {
+            if (dataDiskHyperType != HypervisorType.None && rootDiskHyperType != dataDiskHyperType) {
+                throw new InvalidParameterValueException("Can't attach a volume created by: " + dataDiskHyperType +
+                    " to a " + rootDiskHyperType + " vm");
+            }
         }
 
         deviceId = getDeviceId(vmId, deviceId);