cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mc...@apache.org
Subject [28/50] [abbrv] git commit: updated refs/heads/object_store_migration to 5ec2a44
Date Tue, 29 Oct 2013 03:53:18 GMT
Extend support of CloudStack-managed storage to KVM


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

Branch: refs/heads/object_store_migration
Commit: 858ce766659101eb731c83c806892dd5d9baa976
Parents: 11441a3
Author: Mike Tutkowski <mike.tutkowski@solidfire.com>
Authored: Thu Sep 19 15:44:03 2013 -0600
Committer: Mike Tutkowski <mike.tutkowski@solidfire.com>
Committed: Sun Oct 27 22:30:03 2013 -0600

----------------------------------------------------------------------
 api/src/com/cloud/agent/api/to/DiskTO.java      |  36 +-
 .../src/com/cloud/agent/api/MigrateCommand.java |  11 +-
 core/src/com/cloud/agent/api/StartAnswer.java   |  11 +
 .../storage/command/AttachCommand.java          |  72 ----
 .../com/cloud/vm/VirtualMachineManagerImpl.java |  59 ++-
 .../orchestration/VolumeOrchestrator.java       |  38 +-
 .../kvm/resource/LibvirtComputingResource.java  |  63 ++--
 .../hypervisor/kvm/storage/KVMStoragePool.java  |  12 +-
 .../kvm/storage/KVMStoragePoolManager.java      | 112 +++++-
 .../kvm/storage/KVMStorageProcessor.java        |   8 +-
 .../kvm/storage/LibvirtStorageAdaptor.java      |  47 +++
 .../kvm/storage/LibvirtStoragePool.java         |  11 +
 .../hypervisor/kvm/storage/StorageAdaptor.java  |  13 +
 .../kvm/storage/iScsiAdmStorageAdaptor.java     | 373 +++++++++++++++++++
 .../kvm/storage/iScsiAdmStoragePool.java        | 167 +++++++++
 .../resource/VmwareStorageProcessor.java        |  24 +-
 .../xen/resource/CitrixResourceBase.java        | 124 +++++-
 .../xen/resource/XenServerStorageProcessor.java |  22 +-
 .../SolidFirePrimaryDataStoreLifeCycle.java     | 268 +++++++------
 .../provider/SolidFireHostListener.java         | 102 +++++
 .../SolidfirePrimaryDataStoreProvider.java      |  10 +-
 .../com/cloud/storage/VolumeApiServiceImpl.java |  43 ++-
 .../storage/listener/StoragePoolMonitor.java    |   3 +
 23 files changed, 1321 insertions(+), 308 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/858ce766/api/src/com/cloud/agent/api/to/DiskTO.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/agent/api/to/DiskTO.java b/api/src/com/cloud/agent/api/to/DiskTO.java
index 556ccd4..a577689 100644
--- a/api/src/com/cloud/agent/api/to/DiskTO.java
+++ b/api/src/com/cloud/agent/api/to/DiskTO.java
@@ -18,21 +18,35 @@
  */
 package com.cloud.agent.api.to;
 
+import java.util.Map;
+
 import com.cloud.storage.Volume;
 
 public class DiskTO {
+    public static final String CHAP_INITIATOR_USERNAME = "chapInitiatorUsername";
+    public static final String CHAP_INITIATOR_SECRET = "chapInitiatorSecret";
+    public static final String CHAP_TARGET_USERNAME = "chapTargetUsername";
+    public static final String CHAP_TARGET_SECRET = "chapTargetSecret";
+    public static final String MANAGED = "managed";
+    public static final String IQN = "iqn";
+    public static final String STORAGE_HOST = "storageHost";
+    public static final String STORAGE_PORT = "storagePort";
+    public static final String VOLUME_SIZE = "volumeSize";
+
     private DataTO data;
     private Long diskSeq;
-    private String vdiUuid;
+    private String path;
     private Volume.Type type;
+    private Map<String, String> _details;
+
     public DiskTO() {
         
     }
     
-    public DiskTO(DataTO data, Long diskSeq, String vdiUuid, Volume.Type type) {
+    public DiskTO(DataTO data, Long diskSeq, String path, Volume.Type type) {
         this.data = data;
         this.diskSeq = diskSeq;
-        this.vdiUuid = vdiUuid;
+        this.path = path;
         this.type = type;
     }
 
@@ -52,12 +66,12 @@ public class DiskTO {
         this.diskSeq = diskSeq;
     }
 
-    public String getVdiUuid() {
-        return vdiUuid;
+    public String getPath() {
+        return path;
     }
 
-    public void setVdiUuid(String vdiUuid) {
-        this.vdiUuid = vdiUuid;
+    public void setPath(String path) {
+        this.path = path;
     }
 
     public Volume.Type getType() {
@@ -67,4 +81,12 @@ public class DiskTO {
     public void setType(Volume.Type type) {
         this.type = type;
     }
+
+    public void setDetails(Map<String, String> details) {
+        _details = details;
+    }
+
+    public Map<String, String> getDetails() {
+        return _details;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/858ce766/core/src/com/cloud/agent/api/MigrateCommand.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/agent/api/MigrateCommand.java b/core/src/com/cloud/agent/api/MigrateCommand.java
index 5042b8c..0d8f70c 100644
--- a/core/src/com/cloud/agent/api/MigrateCommand.java
+++ b/core/src/com/cloud/agent/api/MigrateCommand.java
@@ -16,26 +16,33 @@
 // under the License.
 package com.cloud.agent.api;
 
+import com.cloud.agent.api.to.VirtualMachineTO;
+
 public class MigrateCommand extends Command {
     String vmName;
     String destIp;
     String hostGuid;
     boolean isWindows;
-
+    VirtualMachineTO vmTO;
 
     protected MigrateCommand() {
     }
 
-    public MigrateCommand(String vmName, String destIp, boolean isWindows) {
+    public MigrateCommand(String vmName, String destIp, boolean isWindows, VirtualMachineTO vmTO) {
         this.vmName = vmName;
         this.destIp = destIp;
         this.isWindows = isWindows;
+        this.vmTO = vmTO;
     }
 
     public boolean isWindows() {
         return isWindows;
     }
 
+    public VirtualMachineTO getVirtualMachine() {
+        return vmTO;
+    }
+
     public String getDestinationIp() {
         return destIp;
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/858ce766/core/src/com/cloud/agent/api/StartAnswer.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/agent/api/StartAnswer.java b/core/src/com/cloud/agent/api/StartAnswer.java
index 922d060..f3e75df 100644
--- a/core/src/com/cloud/agent/api/StartAnswer.java
+++ b/core/src/com/cloud/agent/api/StartAnswer.java
@@ -16,11 +16,14 @@
 // under the License.
 package com.cloud.agent.api;
 
+import java.util.Map;
+
 import com.cloud.agent.api.to.VirtualMachineTO;
 
 public class StartAnswer extends Answer {
     VirtualMachineTO vm;
     String host_guid;
+    Map<String, String> _iqnToPath;
 
     protected StartAnswer() {
     }
@@ -54,4 +57,12 @@ public class StartAnswer extends Answer {
     public String getHost_guid() {
         return host_guid;
     }
+
+    public void setIqnToPath(Map<String, String> iqnToPath) {
+        _iqnToPath = iqnToPath;
+    }
+
+    public Map<String, String> getIqnToPath() {
+        return _iqnToPath;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/858ce766/core/src/org/apache/cloudstack/storage/command/AttachCommand.java
----------------------------------------------------------------------
diff --git a/core/src/org/apache/cloudstack/storage/command/AttachCommand.java b/core/src/org/apache/cloudstack/storage/command/AttachCommand.java
index 44bce91..7e47ba4 100644
--- a/core/src/org/apache/cloudstack/storage/command/AttachCommand.java
+++ b/core/src/org/apache/cloudstack/storage/command/AttachCommand.java
@@ -24,14 +24,6 @@ import com.cloud.agent.api.to.DiskTO;
 public final class AttachCommand extends Command implements StorageSubSystemCommand {
     private DiskTO disk;
     private String vmName;
-    private String _storageHost;
-    private int _storagePort;
-    private boolean _managed;
-    private String _iScsiName;
-    private String _chapInitiatorUsername;
-    private String _chapInitiatorPassword;
-    private String _chapTargetUsername;
-    private String _chapTargetPassword;
 
     public AttachCommand(DiskTO disk, String vmName) {
         super();
@@ -59,68 +51,4 @@ public final class AttachCommand extends Command implements StorageSubSystemComm
     public void setVmName(String vmName) {
         this.vmName = vmName;
     }
-
-    public void setStorageHost(String storageHost) {
-        _storageHost = storageHost;
-    }
-
-    public String getStorageHost() {
-        return _storageHost;
-    }
-
-    public void setStoragePort(int storagePort) {
-        _storagePort = storagePort;
-    }
-
-    public int getStoragePort() {
-        return _storagePort;
-    }
-
-    public void setManaged(boolean managed) {
-        _managed = managed;
-    }
-
-    public boolean isManaged() {
-        return _managed;
-    }
-
-    public void set_iScsiName(String iScsiName) {
-        this._iScsiName = iScsiName;
-    }
-
-    public String get_iScsiName() {
-        return _iScsiName;
-    }
-
-    public void setChapInitiatorUsername(String chapInitiatorUsername) {
-        _chapInitiatorUsername = chapInitiatorUsername;
-    }
-
-    public String getChapInitiatorUsername() {
-        return _chapInitiatorUsername;
-    }
-
-    public void setChapInitiatorPassword(String chapInitiatorPassword) {
-        _chapInitiatorPassword = chapInitiatorPassword;
-    }
-
-    public String getChapInitiatorPassword() {
-        return _chapInitiatorPassword;
-    }
-
-    public void setChapTargetUsername(String chapTargetUsername) {
-        _chapTargetUsername = chapTargetUsername;
-    }
-
-    public String getChapTargetUsername() {
-        return _chapTargetUsername;
-    }
-
-    public void setChapTargetPassword(String chapTargetPassword) {
-        _chapTargetPassword = chapTargetPassword;
-    }
-
-    public String getChapTargetPassword() {
-        return _chapTargetPassword;
-    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/858ce766/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 0ff4446..539936f 100755
--- a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
+++ b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
@@ -51,7 +51,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;
@@ -844,6 +843,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
 
                     VirtualMachineTO vmTO = hvGuru.implement(vmProfile);
 
+                    handlePath(vmTO.getDisks(), vm.getHypervisorType());
+
                     cmds = new Commands(Command.OnError.Stop);
                     cmds.addCommand(new StartCommand(vmTO, dest.getHost(), getExecuteInSequence()));
 
@@ -862,6 +863,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
 
                     startAnswer = cmds.getAnswer(StartAnswer.class);
                     if (startAnswer != null && startAnswer.getResult()) {
+                        handlePath(vmTO.getDisks(), startAnswer.getIqnToPath());
                         String host_guid = startAnswer.getHost_guid();
                         if (host_guid != null) {
                             HostVO finalHost = _resourceMgr.findHostByGuid(host_guid);
@@ -975,14 +977,63 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
         }
     }
 
+    // for managed storage on KVM, need to make sure the path field of the volume in question is populated with the IQN
+    private void handlePath(DiskTO[] disks, HypervisorType hypervisorType) {
+        if (hypervisorType != HypervisorType.KVM) {
+            return;
+        }
+
+        if (disks != null) {
+            for (DiskTO disk : disks) {
+                Map<String, String> details = disk.getDetails();
+                boolean isManaged = details != null && Boolean.parseBoolean(details.get(DiskTO.MANAGED));
+
+                if (isManaged && disk.getPath() == null) {
+                    Long volumeId = disk.getData().getId();
+                    VolumeVO volume = _volsDao.findById(volumeId);
+
+                    disk.setPath(volume.get_iScsiName());
+                    volume.setPath(volume.get_iScsiName());
+
+                    _volsDao.update(volumeId, volume);
+                }
+            }
+        }
+    }
+
+    // for managed storage on XenServer and VMware, need to update the DB with a path if the VDI/VMDK file was newly created
+    private void handlePath(DiskTO[] disks, Map<String, String> iqnToPath) {
+        if (disks != null) {
+            for (DiskTO disk : disks) {
+                Map<String, String> details = disk.getDetails();
+                boolean isManaged = details != null && Boolean.parseBoolean(details.get(DiskTO.MANAGED));
+
+                if (isManaged && disk.getPath() == null) {
+                    Long volumeId = disk.getData().getId();
+                    VolumeVO volume = _volsDao.findById(volumeId);
+                    String iScsiName = volume.get_iScsiName();
+                    String path = iqnToPath.get(iScsiName);
+
+                    volume.setPath(path);
+
+                    _volsDao.update(volumeId, volume);
+                }
+            }
+        }
+    }
+
     private void syncDiskChainChange(StartAnswer answer) {
         VirtualMachineTO vmSpec = answer.getVirtualMachine();
 
         for(DiskTO disk : vmSpec.getDisks()) {
             if(disk.getType() != Volume.Type.ISO) {
                 VolumeObjectTO vol = (VolumeObjectTO)disk.getData();
+                VolumeVO volume = _volsDao.findById(vol.getId());
 
-                volumeMgr.updateVolumeDiskChain(vol.getId(), vol.getPath(), vol.getChainInfo());
+                // Use getPath() from VolumeVO to get a fresh copy of what's in the DB.
+                // Before doing this, in a certain situation, getPath() from VolumeObjectTO
+                // returned null instead of an actual path (because it was out of date with the DB).
+                volumeMgr.updateVolumeDiskChain(vol.getId(), volume.getPath(), vol.getChainInfo());
             }
         }
     }
@@ -1523,7 +1574,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
         boolean migrated = false;
         try {
             boolean isWindows = _guestOsCategoryDao.findById(_guestOsDao.findById(vm.getGuestOSId()).getCategoryId()).getName().equalsIgnoreCase("Windows");
-            MigrateCommand mc = new MigrateCommand(vm.getInstanceName(), dest.getHost().getPrivateIpAddress(), isWindows);
+            MigrateCommand mc = new MigrateCommand(vm.getInstanceName(), dest.getHost().getPrivateIpAddress(), isWindows, to);
             mc.setHostGuid(dest.getHost().getGuid());
 
             try {
@@ -3150,7 +3201,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
         boolean migrated = false;
         try {
             boolean isWindows = _guestOsCategoryDao.findById(_guestOsDao.findById(vm.getGuestOSId()).getCategoryId()).getName().equalsIgnoreCase("Windows");
-            MigrateCommand mc = new MigrateCommand(vm.getInstanceName(), dest.getHost().getPrivateIpAddress(), isWindows);
+            MigrateCommand mc = new MigrateCommand(vm.getInstanceName(), dest.getHost().getPrivateIpAddress(), isWindows, to);
             mc.setHostGuid(dest.getHost().getGuid());
 
             try {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/858ce766/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 7d81232..0821c81 100644
--- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
+++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
@@ -32,6 +32,7 @@ import javax.naming.ConfigurationException;
 
 import org.apache.log4j.Logger;
 import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
+import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
 import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory;
@@ -886,7 +887,12 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
 
         for (VolumeVO vol : vols) {
             DataTO volTO = volFactory.getVolume(vol.getId()).getTO();
-            DiskTO disk = new DiskTO(volTO, vol.getDeviceId(), null, vol.getVolumeType());
+            DiskTO disk = new DiskTO(volTO, vol.getDeviceId(), vol.getPath(), vol.getVolumeType());
+            VolumeInfo volumeInfo = volFactory.getVolume(vol.getId());
+            DataStore dataStore = dataStoreMgr.getDataStore(vol.getPoolId(), DataStoreRole.Primary);
+
+            disk.setDetails(getDetails(volumeInfo, dataStore));
+
             vm.addDisk(disk);
         }
 
@@ -897,6 +903,29 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
         }
     }
 
+    private Map<String, String> getDetails(VolumeInfo volumeInfo, DataStore dataStore) {
+        Map<String, String> details = new HashMap<String, String>();
+
+        StoragePoolVO storagePool = _storagePoolDao.findById(dataStore.getId());
+
+        details.put(DiskTO.MANAGED, String.valueOf(storagePool.isManaged()));
+        details.put(DiskTO.STORAGE_HOST, storagePool.getHostAddress());
+        details.put(DiskTO.STORAGE_PORT, String.valueOf(storagePool.getPort()));
+        details.put(DiskTO.VOLUME_SIZE, String.valueOf(volumeInfo.getSize()));
+        details.put(DiskTO.IQN, volumeInfo.get_iScsiName());
+
+        ChapInfo chapInfo = volService.getChapInfo(volumeInfo, dataStore);
+
+        if (chapInfo != null) {
+            details.put(DiskTO.CHAP_INITIATOR_USERNAME, chapInfo.getInitiatorUsername());
+            details.put(DiskTO.CHAP_INITIATOR_SECRET, chapInfo.getInitiatorSecret());
+            details.put(DiskTO.CHAP_TARGET_USERNAME, chapInfo.getTargetUsername());
+            details.put(DiskTO.CHAP_TARGET_SECRET, chapInfo.getTargetSecret());
+        }
+
+        return details;
+    }
+
     private static enum VolumeTaskType {
         RECREATE, NOP, MIGRATE
     }
@@ -1084,7 +1113,12 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
                 vol = result.first();
             }
             DataTO volumeTO = volFactory.getVolume(vol.getId()).getTO();
-            DiskTO disk = new DiskTO(volumeTO, vol.getDeviceId(), null, vol.getVolumeType());
+            DiskTO disk = new DiskTO(volumeTO, vol.getDeviceId(), vol.getPath(), vol.getVolumeType());
+            VolumeInfo volumeInfo = volFactory.getVolume(vol.getId());
+            DataStore dataStore = dataStoreMgr.getDataStore(vol.getPoolId(), DataStoreRole.Primary);
+
+            disk.setDetails(getDetails(volumeInfo, dataStore));
+
             vm.addDisk(disk);
         }
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/858ce766/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
index 49e3501..286d0f7 100755
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
@@ -1203,8 +1203,6 @@ ServerResource {
                 return execute((AttachIsoCommand) cmd);
             } else if (cmd instanceof AttachVolumeCommand) {
                 return execute((AttachVolumeCommand) cmd);
-            } else if (cmd instanceof StopCommand) {
-                return execute((StopCommand) cmd);
             } else if (cmd instanceof CheckConsoleProxyLoadCommand) {
                 return execute((CheckConsoleProxyLoadCommand) cmd);
             } else if (cmd instanceof WatchConsoleProxyLoadCommand) {
@@ -2905,6 +2903,8 @@ ServerResource {
              */
             destDomain = dm.migrate(dconn, (1 << 0) | (1 << 3), xmlDesc, vmName, "tcp:"
                     + cmd.getDestinationIp(), _migrateSpeed);
+
+            _storagePoolMgr.disconnectPhysicalDisksViaVmSpec(cmd.getVirtualMachine());
         } catch (LibvirtException e) {
             s_logger.debug("Can't migrate domain: " + e.getMessage());
             result = e.getMessage();
@@ -2953,6 +2953,9 @@ ServerResource {
         }
 
         NicTO[] nics = vm.getNics();
+
+        boolean success = false;
+
         try {
             Connect conn = LibvirtConnection.getConnectionByVmName(vm.getName());
             for (NicTO nic : nics) {
@@ -2967,10 +2970,14 @@ ServerResource {
                 }
             }
 
+            _storagePoolMgr.connectPhysicalDisksViaVmSpec(vm);
+
             synchronized (_vms) {
                 _vms.put(vm.getName(), State.Migrating);
             }
 
+            success = true;
+
             return new PrepareForMigrationAnswer(cmd);
         } catch (LibvirtException e) {
             return new PrepareForMigrationAnswer(cmd, e.toString());
@@ -2978,6 +2985,10 @@ ServerResource {
             return new PrepareForMigrationAnswer(cmd, e.toString());
         } catch (URISyntaxException e) {
             return new PrepareForMigrationAnswer(cmd, e.toString());
+        } finally {
+            if (!success) {
+                _storagePoolMgr.disconnectPhysicalDisksViaVmSpec(vm);
+            }
         }
     }
 
@@ -3241,10 +3252,7 @@ ServerResource {
             String result = stopVM(conn, vmName);
             if (result == null) {
                 for (DiskDef disk : disks) {
-                    if (disk.getDeviceType() == DiskDef.deviceType.CDROM
-                            && disk.getDiskPath() != null) {
-                        cleanupDisk(conn, disk);
-                    }
+                    cleanupDisk(disk);
                 }
                 for (InterfaceDef iface: ifaces) {
                     // We don't know which "traffic type" is associated with
@@ -3517,6 +3525,8 @@ ServerResource {
 
             createVbd(conn, vmSpec, vmName, vm);
 
+            _storagePoolMgr.connectPhysicalDisksViaVmSpec(vmSpec);
+
             createVifs(vmSpec, vm);
 
             s_logger.debug("starting " + vmName + ": " + vm.toString());
@@ -3597,6 +3607,9 @@ ServerResource {
                     _vms.remove(vmName);
                 }
             }
+            if (state != State.Running) {
+                _storagePoolMgr.disconnectPhysicalDisksViaVmSpec(vmSpec);
+            }
         }
     }
 
@@ -3678,7 +3691,7 @@ ServerResource {
                     disk.defNetworkBasedDisk(physicalDisk.getPath().replace("rbd:", ""), pool.getSourceHost(), pool.getSourcePort(),
                             pool.getAuthUserName(), pool.getUuid(),
                             devId, diskBusType, diskProtocol.RBD);
-                } else if (pool.getType() == StoragePoolType.CLVM) {
+                } else if (pool.getType() == StoragePoolType.CLVM || physicalDisk.getFormat() == PhysicalDiskFormat.RAW) {
                     disk.defBlockBasedDisk(physicalDisk.getPath(), devId,
                             diskBusType);
                 } else {
@@ -3762,38 +3775,20 @@ ServerResource {
         return new CheckSshAnswer(cmd);
     }
 
-    public boolean cleanupDisk(Connect conn, DiskDef disk) {
-        // need to umount secondary storage
+    public boolean cleanupDisk(DiskDef disk) {
         String path = disk.getDiskPath();
-        String poolUuid = null;
-        if (path.endsWith("systemvm.iso")) {
-            //Don't need to clean up system vm iso, as it's stored in local
-            return true;
-        }
-        if (path != null) {
-            String[] token = path.split("/");
-            if (token.length > 3) {
-                poolUuid = token[2];
-            }
-        }
 
-        if (poolUuid == null) {
-            return true;
+        if (path == null) {
+            s_logger.debug("Unable to clean up disk with null path (perhaps empty cdrom drive):" + disk);
+            return false;
         }
 
-        try {
-            // we use libvirt as storage adaptor since we passed a libvirt
-            // connection to cleanupDisk. We pass a storage type that maps
-            // to libvirt adaptor.
-            KVMStoragePool pool = _storagePoolMgr.getStoragePool(
-                                      StoragePoolType.Filesystem, poolUuid);
-            if (pool != null) {
-                _storagePoolMgr.deleteStoragePool(pool.getType(),pool.getUuid());
-            }
+        if (path.endsWith("systemvm.iso")) {
+            // don't need to clean up system vm ISO as it's stored in local
             return true;
-        } catch (CloudRuntimeException e) {
-            return false;
         }
+
+        return _storagePoolMgr.disconnectPhysicalDiskByPath(path);
     }
 
     protected synchronized String attachOrDetachISO(Connect conn,
@@ -3823,7 +3818,7 @@ ServerResource {
         if (result == null && !isAttach) {
             for (DiskDef disk : disks) {
                 if (disk.getDeviceType() == DiskDef.deviceType.CDROM) {
-                    cleanupDisk(conn, disk);
+                    cleanupDisk(disk);
                 }
             }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/858ce766/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStoragePool.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStoragePool.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStoragePool.java
index a1721e1..c704a4f 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStoragePool.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStoragePool.java
@@ -17,19 +17,23 @@
 package com.cloud.hypervisor.kvm.storage;
 
 import java.util.List;
+import java.util.Map;
 
 import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
 import com.cloud.storage.Storage.StoragePoolType;
 
 public interface KVMStoragePool {
-    public KVMPhysicalDisk createPhysicalDisk(String name,
-            PhysicalDiskFormat format, long size);
+    public KVMPhysicalDisk createPhysicalDisk(String volumeUuid, PhysicalDiskFormat format, long size);
 
-    public KVMPhysicalDisk createPhysicalDisk(String name, long size);
+    public KVMPhysicalDisk createPhysicalDisk(String volumeUuid, long size);
+
+    public boolean connectPhysicalDisk(String volumeUuid, Map<String, String> details);
 
     public KVMPhysicalDisk getPhysicalDisk(String volumeUuid);
 
-    public boolean deletePhysicalDisk(String uuid);
+    public boolean disconnectPhysicalDisk(String volumeUuid);
+
+    public boolean deletePhysicalDisk(String volumeUuid);
 
     public List<KVMPhysicalDisk> listPhysicalDisks();
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/858ce766/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java
index 945243a..9ca709c 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java
@@ -18,6 +18,8 @@ package com.cloud.hypervisor.kvm.storage;
 
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.util.List;
+import java.util.Arrays;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.HashMap;
@@ -25,14 +27,21 @@ import java.util.UUID;
 
 import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
 
+import com.cloud.agent.api.to.VirtualMachineTO;
+import com.cloud.agent.api.to.DiskTO;
+
 import com.cloud.hypervisor.kvm.resource.KVMHABase;
 import com.cloud.hypervisor.kvm.resource.KVMHABase.PoolType;
 import com.cloud.hypervisor.kvm.resource.KVMHAMonitor;
 import com.cloud.storage.Storage.StoragePoolType;
 import com.cloud.storage.StorageLayer;
+import com.cloud.storage.Volume;
 import com.cloud.utils.exception.CloudRuntimeException;
 import org.apache.log4j.Logger;
 
+import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
+import org.apache.cloudstack.storage.to.VolumeObjectTO;
+
 public class KVMStoragePoolManager {
     private static final Logger s_logger = Logger
             .getLogger(KVMStoragePoolManager.class);
@@ -62,7 +71,6 @@ public class KVMStoragePoolManager {
             this.poolType = poolType;
         }
     }
-    private StorageAdaptor _storageAdaptor;
     private KVMHAMonitor _haMonitor;
     private final Map<String, StoragePoolInformation> _storagePools = new ConcurrentHashMap<String, StoragePoolInformation>();
     private final Map<String, StorageAdaptor> _storageMapper = new HashMap<String, StorageAdaptor>();
@@ -89,11 +97,102 @@ public class KVMStoragePoolManager {
     }
 
     public KVMStoragePoolManager(StorageLayer storagelayer, KVMHAMonitor monitor) {
-        this._storageAdaptor = new LibvirtStorageAdaptor(storagelayer);
         this._haMonitor = monitor;
         this._storageMapper.put("libvirt", new LibvirtStorageAdaptor(storagelayer));
         // add other storage adaptors here
-	// this._storageMapper.put("newadaptor", new NewStorageAdaptor(storagelayer));
+        // this._storageMapper.put("newadaptor", new NewStorageAdaptor(storagelayer));
+        this._storageMapper.put(StoragePoolType.Iscsi.toString(), new iScsiAdmStorageAdaptor());
+    }
+
+    public boolean connectPhysicalDisk(StoragePoolType type, String poolUuid, String volPath, Map<String, String> details) {
+        StorageAdaptor adaptor = getStorageAdaptor(type);
+        KVMStoragePool pool = adaptor.getStoragePool(poolUuid);
+
+        return adaptor.connectPhysicalDisk(volPath, pool, details);
+    }
+
+    public boolean connectPhysicalDisksViaVmSpec(VirtualMachineTO vmSpec) {
+        boolean result = false;
+
+        final String vmName = vmSpec.getName();
+
+        List<DiskTO> disks = Arrays.asList(vmSpec.getDisks());
+
+        for (DiskTO disk : disks) {
+            if (disk.getType() != Volume.Type.ISO) {
+                VolumeObjectTO vol = (VolumeObjectTO) disk.getData();
+                PrimaryDataStoreTO store = (PrimaryDataStoreTO) vol.getDataStore();
+                KVMStoragePool pool = getStoragePool(store.getPoolType(), store.getUuid());
+
+                StorageAdaptor adaptor = getStorageAdaptor(pool.getType());
+
+                result = adaptor.connectPhysicalDisk(vol.getPath(), pool, disk.getDetails());
+
+                if (!result) {
+                    s_logger.error("Failed to connect disks via vm spec for vm: " + vmName + " volume:" + vol.toString());
+
+                    return result;
+                }
+            }
+        }
+
+        return result;
+    }
+
+    public boolean disconnectPhysicalDiskByPath(String path) {
+        for (Map.Entry<String, StorageAdaptor> set : _storageMapper.entrySet()) {
+            StorageAdaptor adaptor = set.getValue();
+
+            if (adaptor.disconnectPhysicalDiskByPath(path)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    public boolean disconnectPhysicalDisksViaVmSpec(VirtualMachineTO vmSpec) {
+        if (vmSpec == null) {
+            /* CloudStack often tries to stop VMs that shouldn't be running, to ensure a known state,
+               for example if we lose communication with the agent and the VM is brought up elsewhere.
+               We may not know about these yet. This might mean that we can't use the vmspec map, because
+               when we restart the agent we lose all of the info about running VMs. */
+
+            s_logger.debug("disconnectPhysicalDiskViaVmSpec: Attempted to stop a VM that is not yet in our hash map");
+
+            return true;
+        }
+
+        boolean result = true;
+
+        final String vmName = vmSpec.getName();
+
+        List<DiskTO> disks = Arrays.asList(vmSpec.getDisks());
+
+        for (DiskTO disk : disks) {
+            if (disk.getType() != Volume.Type.ISO) {
+                s_logger.debug("Disconnecting disk " + disk.getPath());
+
+                VolumeObjectTO vol = (VolumeObjectTO) disk.getData();
+                PrimaryDataStoreTO store = (PrimaryDataStoreTO) vol.getDataStore();
+
+                KVMStoragePool pool = getStoragePool(store.getPoolType(), store.getUuid());
+
+                StorageAdaptor adaptor = getStorageAdaptor(pool.getType());
+
+                // if a disk fails to disconnect, still try to disconnect remaining
+
+                boolean subResult = adaptor.disconnectPhysicalDisk(vol.getPath(), pool);
+
+                if (!subResult) {
+                    s_logger.error("Failed to disconnect disks via vm spec for vm: " + vmName + " volume:" + vol.toString());
+
+                    result = false;
+                }
+            }
+        }
+
+        return result;
     }
 
     public KVMStoragePool getStoragePool(StoragePoolType type, String uuid) {
@@ -197,6 +296,13 @@ public class KVMStoragePoolManager {
         return pool;
     }
 
+    public boolean disconnectPhysicalDisk(StoragePoolType type, String poolUuid, String volPath) {
+        StorageAdaptor adaptor = getStorageAdaptor(type);
+        KVMStoragePool pool = adaptor.getStoragePool(poolUuid);
+
+        return adaptor.disconnectPhysicalDisk(volPath, pool);
+    }
+
     public boolean deleteStoragePool(StoragePoolType type, String uuid) {
         StorageAdaptor adaptor = getStorageAdaptor(type);
         _haMonitor.removeStoragePool(uuid);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/858ce766/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
index 04bdd76..8b8cd9e 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
@@ -828,7 +828,7 @@ public class KVMStorageProcessor implements StorageProcessor {
         if (result == null && !isAttach) {
             for (DiskDef disk : disks) {
                 if (disk.getDeviceType() == DiskDef.deviceType.CDROM) {
-                    this.resource.cleanupDisk(conn, disk);
+                    this.resource.cleanupDisk(disk);
                 }
             }
 
@@ -972,6 +972,9 @@ public class KVMStorageProcessor implements StorageProcessor {
         String vmName = cmd.getVmName();
         try {
             Connect conn = LibvirtConnection.getConnectionByVmName(vmName);
+
+            storagePoolMgr.connectPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), vol.getPath(), disk.getDetails());
+
             KVMPhysicalDisk phyDisk = storagePoolMgr.getPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), vol.getPath());
 
             attachOrDetachDisk(conn, true, vmName, phyDisk, disk.getDiskSeq().intValue());
@@ -994,10 +997,13 @@ public class KVMStorageProcessor implements StorageProcessor {
         String vmName = cmd.getVmName();
         try {
             Connect conn = LibvirtConnection.getConnectionByVmName(vmName);
+
             KVMPhysicalDisk phyDisk = storagePoolMgr.getPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), vol.getPath());
 
             attachOrDetachDisk(conn, false, vmName, phyDisk, disk.getDiskSeq().intValue());
 
+            storagePoolMgr.disconnectPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), vol.getPath());
+
             return new DettachAnswer(disk);
         } catch (LibvirtException e) {
             s_logger.debug("Failed to attach volume: " + vol.getPath() + ", due to " + e.toString());

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/858ce766/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java
index e04297e..8ef855e 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java
@@ -707,6 +707,53 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
     }
 
     @Override
+    public boolean connectPhysicalDisk(String name, KVMStoragePool pool, Map<String, String> details) {
+        // this is for managed storage that needs to prep disks prior to use
+        return true;
+    }
+
+    @Override
+    public boolean disconnectPhysicalDisk(String uuid, KVMStoragePool pool) {
+        // this is for managed storage that needs to cleanup disks after use
+        return true;
+    }
+
+    @Override
+    public boolean disconnectPhysicalDiskByPath(String localPath) {
+        // we've only ever cleaned up ISOs that are NFS mounted
+
+        String poolUuid = null;
+
+        if (localPath != null && localPath.startsWith(_mountPoint)) {
+            String[] token = localPath.split("/");
+
+            if (token.length > 3) {
+                poolUuid = token[2];
+            }
+        } else {
+            return false;
+        }
+
+        if (poolUuid == null) {
+            return false;
+        }
+
+        try {
+            Connect conn = LibvirtConnection.getConnection();
+
+            StoragePool pool = conn.storagePoolLookupByUUIDString(poolUuid);
+
+            deleteStoragePool(poolUuid);
+
+            return true;
+        } catch (LibvirtException ex) {
+            return false;
+        } catch (CloudRuntimeException ex) {
+            return false;
+        }
+    }
+
+    @Override
     public boolean deletePhysicalDisk(String uuid, KVMStoragePool pool) {
 
         /**

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/858ce766/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStoragePool.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStoragePool.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStoragePool.java
index c0e1000..df0af5f 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStoragePool.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStoragePool.java
@@ -18,6 +18,7 @@ package com.cloud.hypervisor.kvm.storage;
 
 import java.io.File;
 import java.util.List;
+import java.util.Map;
 
 import com.cloud.utils.exception.CloudRuntimeException;
 import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
@@ -154,6 +155,16 @@ public class LibvirtStoragePool implements KVMStoragePool {
     }
 
     @Override
+    public boolean connectPhysicalDisk(String name, Map<String, String> details) {
+        return true;
+    }
+
+    @Override
+    public boolean disconnectPhysicalDisk(String uuid) {
+        return true;
+    }
+
+    @Override
     public boolean deletePhysicalDisk(String uuid) {
         return this._storageAdaptor.deletePhysicalDisk(uuid, this);
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/858ce766/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/StorageAdaptor.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/StorageAdaptor.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/StorageAdaptor.java
index 44e0691..c5ff421 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/StorageAdaptor.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/StorageAdaptor.java
@@ -17,6 +17,7 @@
 package com.cloud.hypervisor.kvm.storage;
 
 import java.util.List;
+import java.util.Map;
 
 import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
 import com.cloud.storage.Storage.StoragePoolType;
@@ -25,6 +26,8 @@ public interface StorageAdaptor {
 
     public KVMStoragePool getStoragePool(String uuid);
 
+    // given disk path (per database) and pool, create new KVMPhysicalDisk, populate
+    // it with info from local disk, and return it
     public KVMPhysicalDisk getPhysicalDisk(String volumeUuid,
             KVMStoragePool pool);
 
@@ -36,6 +39,16 @@ public interface StorageAdaptor {
     public KVMPhysicalDisk createPhysicalDisk(String name, KVMStoragePool pool,
             PhysicalDiskFormat format, long size);
 
+    // given disk path (per database) and pool, prepare disk on host
+    public boolean connectPhysicalDisk(String volumePath, KVMStoragePool pool, Map<String, String> details);
+
+    // given disk path (per database) and pool, clean up disk on host
+    public boolean disconnectPhysicalDisk(String volumePath, KVMStoragePool pool);
+
+    // given local path to file/device (per Libvirt XML), 1) check that device is
+    // handled by your adaptor, return false if not. 2) clean up device, return true
+    public boolean disconnectPhysicalDiskByPath(String localPath);
+
     public boolean deletePhysicalDisk(String uuid, KVMStoragePool pool);
 
     public KVMPhysicalDisk createDiskFromTemplate(KVMPhysicalDisk template,

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/858ce766/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/iScsiAdmStorageAdaptor.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/iScsiAdmStorageAdaptor.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/iScsiAdmStorageAdaptor.java
new file mode 100644
index 0000000..476a727
--- /dev/null
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/iScsiAdmStorageAdaptor.java
@@ -0,0 +1,373 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF 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 com.cloud.hypervisor.kvm.storage;
+
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+
+import org.apache.log4j.Logger;
+import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
+
+import com.cloud.agent.api.to.DiskTO;
+import com.cloud.storage.Storage.StoragePoolType;
+import com.cloud.utils.StringUtils;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.script.OutputInterpreter;
+import com.cloud.utils.script.Script;
+
+public class iScsiAdmStorageAdaptor implements StorageAdaptor {
+    private static final Logger s_logger = Logger.getLogger(iScsiAdmStorageAdaptor.class);
+
+    private static final Map<String, KVMStoragePool> _mapStorageUuidToStoragePool = new HashMap<String, KVMStoragePool>();
+
+    @Override
+    public KVMStoragePool createStoragePool(String uuid, String host, int port, String path, String userInfo, StoragePoolType storagePoolType) {
+        iScsiAdmStoragePool storagePool = new iScsiAdmStoragePool(uuid, host, port, storagePoolType, this);
+
+        _mapStorageUuidToStoragePool.put(uuid, storagePool);
+
+        return storagePool;
+    }
+
+    @Override
+    public KVMStoragePool getStoragePool(String uuid) {
+        return _mapStorageUuidToStoragePool.get(uuid);
+    }
+
+    @Override
+    public boolean deleteStoragePool(String uuid) {
+        return _mapStorageUuidToStoragePool.remove(uuid) != null;
+    }
+
+    @Override
+    public boolean deleteStoragePool(KVMStoragePool pool) {
+        return deleteStoragePool(pool.getUuid());
+    }
+
+    // called from LibvirtComputingResource.execute(CreateCommand)
+    // does not apply for iScsiAdmStorageAdaptor
+    @Override
+    public KVMPhysicalDisk createPhysicalDisk(String volumeUuid, KVMStoragePool pool, PhysicalDiskFormat format, long size) {
+        throw new UnsupportedOperationException("Creating a physical disk is not supported.");
+    }
+
+    @Override
+    public boolean connectPhysicalDisk(String volumeUuid, KVMStoragePool pool, Map<String, String> details) {
+        // ex. sudo iscsiadm -m node -T iqn.2012-03.com.test:volume1 -p 192.168.233.10:3260 -o new
+        Script iScsiAdmCmd = new Script(true, "iscsiadm", 0, s_logger);
+
+        iScsiAdmCmd.add("-m", "node");
+        iScsiAdmCmd.add("-T", getIqn(volumeUuid));
+        iScsiAdmCmd.add("-p", pool.getSourceHost() + ":" + pool.getSourcePort());
+        iScsiAdmCmd.add("-o", "new");
+
+        String result = iScsiAdmCmd.execute();
+
+        if (result != null) {
+            s_logger.debug("Failed to add iSCSI target " + volumeUuid);
+            System.out.println("Failed to add iSCSI target " + volumeUuid);
+
+            return false;
+        }
+        else {
+            s_logger.debug("Successfully added iSCSI target " + volumeUuid);
+            System.out.println("Successfully added to iSCSI target " + volumeUuid);
+        }
+
+        String chapInitiatorUsername = details.get(DiskTO.CHAP_INITIATOR_USERNAME);
+        String chapInitiatorSecret = details.get(DiskTO.CHAP_INITIATOR_SECRET);
+
+        if (StringUtils.isNotBlank(chapInitiatorUsername) && StringUtils.isNotBlank(chapInitiatorSecret)) {
+            try {
+                // ex. sudo iscsiadm -m node -T iqn.2012-03.com.test:volume1 -p 192.168.233.10:3260 --op update -n node.session.auth.authmethod -v CHAP
+                executeChapCommand(volumeUuid, pool, "node.session.auth.authmethod", "CHAP", null);
+
+                // ex. sudo iscsiadm -m node -T iqn.2012-03.com.test:volume1 -p 192.168.233.10:3260 --op update -n node.session.auth.username -v username
+                executeChapCommand(volumeUuid, pool, "node.session.auth.username", chapInitiatorUsername, "username");
+
+                // ex. sudo iscsiadm -m node -T iqn.2012-03.com.test:volume1 -p 192.168.233.10:3260 --op update -n node.session.auth.password -v password
+                executeChapCommand(volumeUuid, pool, "node.session.auth.password", chapInitiatorSecret, "password");
+            }
+            catch (Exception ex) {
+                return false;
+            }
+        }
+
+        // ex. sudo iscsiadm -m node -T iqn.2012-03.com.test:volume1 -p 192.168.233.10 --login
+        iScsiAdmCmd = new Script(true, "iscsiadm", 0, s_logger);
+
+        iScsiAdmCmd.add("-m", "node");
+        iScsiAdmCmd.add("-T", getIqn(volumeUuid));
+        iScsiAdmCmd.add("-p", pool.getSourceHost() + ":" + pool.getSourcePort());
+        iScsiAdmCmd.add("--login");
+
+        result = iScsiAdmCmd.execute();
+
+        if (result != null) {
+            s_logger.debug("Failed to log in to iSCSI target " + volumeUuid);
+            System.out.println("Failed to log in to iSCSI target " + volumeUuid);
+
+            return false;
+        }
+        else {
+            s_logger.debug("Successfully logged in to iSCSI target " + volumeUuid);
+            System.out.println("Successfully logged in to iSCSI target " + volumeUuid);
+        }
+
+        // There appears to be a race condition where logging in to the iSCSI volume via iscsiadm
+        // returns success before the device has been added to the OS.
+        // What happens is you get logged in and the device shows up, but the device may not
+        // show up before we invoke Libvirt to attach the device to a VM.
+        // waitForDiskToBecomeAvailable(String, KVMStoragePool) invokes blockdev
+        // via getPhysicalDisk(String, KVMStoragePool) and checks if the size came back greater
+        // than 0.
+        // After a certain number of tries and a certain waiting period in between tries,
+        // this method could still return (it should not block indefinitely) (the race condition
+        // isn't solved here, but made highly unlikely to be a problem).
+        waitForDiskToBecomeAvailable(volumeUuid, pool);
+
+        return true;
+    }
+
+    private void waitForDiskToBecomeAvailable(String volumeUuid, KVMStoragePool pool) {
+        int numberOfTries = 10;
+        int timeBetweenTries = 1000;
+
+        while (getPhysicalDisk(volumeUuid, pool).getSize() == 0 && numberOfTries > 0) {
+            numberOfTries--;
+
+            try {
+                Thread.sleep(timeBetweenTries);
+            }
+            catch (Exception ex) {
+                // don't do anything
+            }
+        }
+    }
+
+    private void executeChapCommand(String path, KVMStoragePool pool, String nParameter, String vParameter, String detail) throws Exception {
+        Script iScsiAdmCmd = new Script(true, "iscsiadm", 0, s_logger);
+
+        iScsiAdmCmd.add("-m", "node");
+        iScsiAdmCmd.add("-T", getIqn(path));
+        iScsiAdmCmd.add("-p", pool.getSourceHost() + ":" + pool.getSourcePort());
+        iScsiAdmCmd.add("--op", "update");
+        iScsiAdmCmd.add("-n", nParameter);
+        iScsiAdmCmd.add("-v", vParameter);
+
+        String result = iScsiAdmCmd.execute();
+
+        boolean useDetail = detail != null && detail.trim().length() > 0;
+
+        detail = useDetail ? detail.trim() + " " : detail;
+
+        if (result != null) {
+            s_logger.debug("Failed to execute CHAP " + (useDetail ? detail : "") + "command for iSCSI target " + path + " : message = " + result);
+            System.out.println("Failed to execute CHAP " + (useDetail ? detail : "") + "command for iSCSI target " + path + " : message = " + result);
+
+            throw new Exception("Failed to execute CHAP " + (useDetail ? detail : "") + "command for iSCSI target " + path + " : message = " + result);
+        } else {
+            s_logger.debug("CHAP " + (useDetail ? detail : "") + "command executed successfully for iSCSI target " + path);
+            System.out.println("CHAP " + (useDetail ? detail : "") + "command executed successfully for iSCSI target " + path);
+        }
+    }
+
+    // example by-path: /dev/disk/by-path/ip-192.168.233.10:3260-iscsi-iqn.2012-03.com.solidfire:storagepool2-lun-0
+    private String getByPath(String host, String path) {
+        return "/dev/disk/by-path/ip-" + host + "-iscsi-" + getIqn(path) + "-lun-" + getLun(path);
+    }
+
+    @Override
+    public KVMPhysicalDisk getPhysicalDisk(String volumeUuid, KVMStoragePool pool) {
+        String deviceByPath = getByPath(pool.getSourceHost() + ":" + pool.getSourcePort(), volumeUuid);
+        KVMPhysicalDisk physicalDisk = new KVMPhysicalDisk(deviceByPath, volumeUuid, pool);
+
+        physicalDisk.setFormat(PhysicalDiskFormat.RAW);
+
+        long deviceSize = getDeviceSize(deviceByPath);
+
+        physicalDisk.setSize(deviceSize);
+        physicalDisk.setVirtualSize(deviceSize);
+
+        return physicalDisk;
+    }
+
+    private long getDeviceSize(String deviceByPath) {
+        Script iScsiAdmCmd = new Script(true, "blockdev", 0, s_logger);
+
+        iScsiAdmCmd.add("--getsize64", deviceByPath);
+
+        OutputInterpreter.OneLineParser parser = new OutputInterpreter.OneLineParser();
+
+        String result = iScsiAdmCmd.execute(parser);
+
+        if (result != null) {
+            s_logger.warn("Unable to retrieve the size of device " + deviceByPath);
+
+            return 0;
+        }
+
+        return Long.parseLong(parser.getLine());
+    }
+
+    private static String getIqn(String path) {
+        return getComponent(path, 1);
+    }
+
+    private static String getLun(String path) {
+        return getComponent(path, 2);
+    }
+
+    private static String getComponent(String path, int index) {
+        String[] tmp = path.split("/");
+
+        if (tmp.length != 3) {
+            String msg = "Wrong format for iScsi path: " + path + ". It should be formatted as '/targetIQN/LUN'.";
+
+            s_logger.warn(msg);
+
+            throw new CloudRuntimeException(msg);
+        }
+
+        return tmp[index].trim();
+    }
+
+    public boolean disconnectPhysicalDisk(String host, int port, String iqn, String lun) {
+        // use iscsiadm to log out of the iSCSI target and un-discover it
+
+        // ex. sudo iscsiadm -m node -T iqn.2012-03.com.test:volume1 -p 192.168.233.10 --logout
+        Script iScsiAdmCmd = new Script(true, "iscsiadm", 0, s_logger);
+
+        iScsiAdmCmd.add("-m", "node");
+        iScsiAdmCmd.add("-T", iqn);
+        iScsiAdmCmd.add("-p", host + ":" + port);
+        iScsiAdmCmd.add("--logout");
+
+        String result = iScsiAdmCmd.execute();
+
+        if (result != null) {
+            s_logger.debug("Failed to log out of iSCSI target /" + iqn + "/" + lun + " : message = " + result);
+            System.out.println("Failed to log out of iSCSI target /" + iqn + "/" + lun + " : message = " + result);
+
+            return false;
+        }
+        else {
+            s_logger.debug("Successfully logged out of iSCSI target /" + iqn + "/" + lun);
+            System.out.println("Successfully logged out of iSCSI target /" + iqn + "/" + lun);
+        }
+
+        // ex. sudo iscsiadm -m node -T iqn.2012-03.com.test:volume1 -p 192.168.233.10:3260 -o delete
+        iScsiAdmCmd = new Script(true, "iscsiadm", 0, s_logger);
+
+        iScsiAdmCmd.add("-m", "node");
+        iScsiAdmCmd.add("-T", iqn);
+        iScsiAdmCmd.add("-p", host + ":" + port);
+        iScsiAdmCmd.add("-o", "delete");
+
+        result = iScsiAdmCmd.execute();
+
+        if (result != null) {
+            s_logger.debug("Failed to remove iSCSI target /" + iqn + "/" + lun + " : message = " + result);
+            System.out.println("Failed to remove iSCSI target /" + iqn + "/" + lun + " : message = " + result);
+
+            return false;
+        } else {
+            s_logger.debug("Removed iSCSI target /" + iqn + "/" + lun);
+            System.out.println("Removed iSCSI target /" + iqn + "/" + lun);
+        }
+
+        return true;
+    }
+
+    @Override
+    public boolean disconnectPhysicalDisk(String volumeUuid, KVMStoragePool pool) {
+        return disconnectPhysicalDisk(pool.getSourceHost(), pool.getSourcePort(), getIqn(volumeUuid), getLun(volumeUuid));
+    }
+
+    @Override
+    public boolean disconnectPhysicalDiskByPath(String localPath) {
+        String search1 = "/dev/disk/by-path/ip-";
+        String search2 = ":";
+        String search3 = "-iscsi-";
+        String search4 = "-lun-";
+
+        if (localPath.indexOf(search3) == -1) {
+            // this volume doesn't below to this adaptor, so just return true
+            return true;
+        }
+
+        int index = localPath.indexOf(search2);
+
+        String host = localPath.substring(search1.length(), index);
+
+        int index2 = localPath.indexOf(search3);
+
+        String port = localPath.substring(index + search2.length(), index2);
+
+        index = localPath.indexOf(search4);
+
+        String iqn = localPath.substring(index2 + search3.length(), index);
+
+        String lun = localPath.substring(index + search4.length());
+
+        return disconnectPhysicalDisk(host, Integer.parseInt(port), iqn, lun);
+    }
+
+    @Override
+    public boolean deletePhysicalDisk(String volumeUuid, KVMStoragePool pool) {
+        throw new UnsupportedOperationException("Deleting a physical disk is not supported.");
+    }
+
+    // does not apply for iScsiAdmStorageAdaptor
+    @Override
+    public List<KVMPhysicalDisk> listPhysicalDisks(String storagePoolUuid, KVMStoragePool pool) {
+        throw new UnsupportedOperationException("Listing disks is not supported for this configuration.");
+    }
+
+    @Override
+    public KVMPhysicalDisk createDiskFromTemplate(KVMPhysicalDisk template, String name, PhysicalDiskFormat format, long size,
+            KVMStoragePool destPool, int timeout) {
+        throw new UnsupportedOperationException("Creating a disk from a template is not yet supported for this configuration.");
+    }
+
+    @Override
+    public KVMPhysicalDisk createTemplateFromDisk(KVMPhysicalDisk disk, String name, PhysicalDiskFormat format,
+            long size, KVMStoragePool destPool) {
+        throw new UnsupportedOperationException("Creating a template from a disk is not yet supported for this configuration.");
+    }
+
+    @Override
+    public KVMPhysicalDisk copyPhysicalDisk(KVMPhysicalDisk disk, String name, KVMStoragePool destPool, int timeout) {
+        throw new UnsupportedOperationException("Copying a disk is not supported in this configuration.");
+    }
+
+    @Override
+    public KVMPhysicalDisk createDiskFromSnapshot(KVMPhysicalDisk snapshot, String snapshotName, String name, KVMStoragePool destPool) {
+        throw new UnsupportedOperationException("Creating a disk from a snapshot is not supported in this configuration.");
+    }
+
+    @Override
+    public boolean refresh(KVMStoragePool pool) {
+        return true;
+    }
+
+    @Override
+    public boolean createFolder(String uuid, String path) {
+        throw new UnsupportedOperationException("A folder cannot be created in this configuration.");
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/858ce766/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/iScsiAdmStoragePool.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/iScsiAdmStoragePool.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/iScsiAdmStoragePool.java
new file mode 100644
index 0000000..3808815
--- /dev/null
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/iScsiAdmStoragePool.java
@@ -0,0 +1,167 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF 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 com.cloud.hypervisor.kvm.storage;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
+
+import com.cloud.storage.Storage.StoragePoolType;
+
+public class iScsiAdmStoragePool implements KVMStoragePool {
+    private String _uuid;
+    private String _sourceHost;
+    private int _sourcePort;
+    private StoragePoolType _storagePoolType;
+    private StorageAdaptor _storageAdaptor;
+    private String _authUsername;
+    private String _authSecret;
+    private String _sourceDir;
+    private String _localPath;
+
+    public iScsiAdmStoragePool(String uuid, String host, int port, StoragePoolType storagePoolType, StorageAdaptor storageAdaptor) {
+        _uuid = uuid;
+        _sourceHost = host;
+        _sourcePort = port;
+        _storagePoolType = storagePoolType;
+        _storageAdaptor = storageAdaptor;
+    }
+
+    @Override
+    public String getUuid() {
+        return _uuid;
+    }
+
+    @Override
+    public String getSourceHost() {
+        return _sourceHost;
+    }
+
+    @Override
+    public int getSourcePort() {
+        return _sourcePort;
+    }
+
+    @Override
+    public long getCapacity() {
+        return 0;
+    }
+
+    @Override
+    public long getUsed() {
+        return 0;
+    }
+
+    @Override
+    public long getAvailable() {
+        return 0;
+    }
+
+    @Override
+    public StoragePoolType getType() {
+        return _storagePoolType;
+    }
+
+    @Override
+    public PhysicalDiskFormat getDefaultFormat() {
+        return PhysicalDiskFormat.RAW;
+    }
+
+    // called from LibvirtComputingResource.copyPhysicalDisk(KVMPhysicalDisk, String, KVMStoragePool) and
+    // from LibvirtComputingResource.createDiskFromTemplate(KVMPhysicalDisk, String, PhysicalDiskFormat, long, KVMStoragePool)
+    // does not apply for iScsiAdmStoragePool
+    @Override
+    public KVMPhysicalDisk createPhysicalDisk(String name, PhysicalDiskFormat format, long size) {
+        throw new UnsupportedOperationException("Creating a physical disk is not supported.");
+    }
+
+    // called from LibvirtComputingResource.execute(CreateCommand) and
+    // from KVMStorageProcessor.createVolume(CreateObjectCommand)
+    // does not apply for iScsiAdmStoragePool
+    @Override
+    public KVMPhysicalDisk createPhysicalDisk(String name, long size) {
+        throw new UnsupportedOperationException("Creating a physical disk is not supported.");
+    }
+
+    @Override
+    public boolean connectPhysicalDisk(String name, Map<String, String> details) {
+        return this._storageAdaptor.connectPhysicalDisk(name, this, details);
+    }
+
+    @Override
+    public KVMPhysicalDisk getPhysicalDisk(String volumeUuid) {
+        return this._storageAdaptor.getPhysicalDisk(volumeUuid, this);
+    }
+
+    @Override
+    public boolean disconnectPhysicalDisk(String volumeUuid) {
+        return this._storageAdaptor.disconnectPhysicalDisk(volumeUuid, this);
+    }
+
+    @Override
+    public boolean deletePhysicalDisk(String volumeUuid) {
+        return this._storageAdaptor.deletePhysicalDisk(volumeUuid, this);
+    }
+
+    // does not apply for iScsiAdmStoragePool
+    @Override
+    public List<KVMPhysicalDisk> listPhysicalDisks() {
+        return this._storageAdaptor.listPhysicalDisks(_uuid, this);
+    }
+
+    // does not apply for iScsiAdmStoragePool
+    @Override
+    public boolean refresh() {
+        return this._storageAdaptor.refresh(this);
+    }
+
+    @Override
+    public boolean delete() {
+        return this._storageAdaptor.deleteStoragePool(this);
+    }
+
+    @Override
+    public boolean createFolder(String path) {
+        return this._storageAdaptor.createFolder(_uuid, path);
+    }
+
+    @Override
+    public boolean isExternalSnapshot() {
+        return false;
+    }
+
+    @Override
+    public String getAuthUserName() {
+        return _authUsername;
+    }
+
+    @Override
+    public String getAuthSecret() {
+        return _authSecret;
+    }
+
+    @Override
+    public String getSourceDir() {
+        return _sourceDir;
+    }
+
+    @Override
+    public String getLocalPath() {
+        return _localPath;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/858ce766/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 34bfe18..53bd144 100644
--- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
@@ -1164,19 +1164,16 @@ public class VmwareStorageProcessor implements StorageProcessor {
 
     @Override
     public Answer attachVolume(AttachCommand cmd) {
-        return this.attachVolume(cmd, cmd.getDisk(), true, cmd.isManaged(), cmd.getVmName(), cmd.get_iScsiName(),
-                cmd.getStorageHost(), cmd.getStoragePort(), cmd.getChapInitiatorUsername(), cmd.getChapInitiatorPassword(),
-                cmd.getChapTargetUsername(), cmd.getChapTargetPassword());
-    }
+        Map<String, String> details = cmd.getDisk().getDetails();
+        boolean isManaged = Boolean.parseBoolean(details.get(DiskTO.MANAGED));
+        String iScsiName = details.get(DiskTO.IQN);
+        String storageHost = details.get(DiskTO.STORAGE_HOST);
+        int storagePort = Integer.parseInt(details.get(DiskTO.STORAGE_PORT));
 
-    private Answer attachVolume(Command cmd, DiskTO disk, boolean isAttach, boolean isManaged, String vmName, String iScsiName, String storageHost, int storagePort) {
-        return attachVolume(cmd, disk, isAttach, isManaged, vmName, iScsiName, storageHost, storagePort, null, null, null, null);
+        return this.attachVolume(cmd, cmd.getDisk(), true, isManaged, cmd.getVmName(), iScsiName, storageHost, storagePort);
     }
 
-    private Answer attachVolume(Command cmd, DiskTO disk, boolean isAttach, boolean isManaged, String vmName,
-            String iScsiName, String storageHost, int storagePort, String initiatorUsername, String initiatorPassword,
-            String targetUsername, String targetPassword) {
-
+    private Answer attachVolume(Command cmd, DiskTO disk, boolean isAttach, boolean isManaged, String vmName, String iScsiName, String storageHost, int storagePort) {
         VolumeObjectTO volumeTO = (VolumeObjectTO)disk.getData();
         PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volumeTO.getDataStore();
         try {
@@ -1191,8 +1188,11 @@ public class VmwareStorageProcessor implements StorageProcessor {
             ManagedObjectReference morDs = null;
 
             if (isAttach && isManaged) {
+                Map<String, String> details = disk.getDetails();
+
                 morDs = hostService.getVmfsDatastore(hyperHost, VmwareResource.getDatastoreName(iScsiName), storageHost, storagePort,
-                            VmwareResource.trimIqn(iScsiName), initiatorUsername, initiatorPassword, targetUsername, targetPassword);
+                            VmwareResource.trimIqn(iScsiName),  details.get(DiskTO.CHAP_INITIATOR_USERNAME), details.get(DiskTO.CHAP_INITIATOR_SECRET),
+                            details.get(DiskTO.CHAP_TARGET_USERNAME), details.get(DiskTO.CHAP_TARGET_SECRET));
 
                 DatastoreMO dsMo = new DatastoreMO(hostService.getServiceContext(null), morDs);
 
@@ -1236,7 +1236,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
                 }
             }
 
-            disk.setVdiUuid(datastoreVolumePath);
+            disk.setPath(datastoreVolumePath);
 
             AttachAnswer answer = new AttachAnswer(disk);
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/858ce766/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 3c44daa..6c1efe7 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
@@ -1199,10 +1199,13 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
         }
     }
 
-    protected VBD createVbd(Connection conn, DiskTO volume, String vmName, VM vm, BootloaderType bootLoaderType) throws XmlRpcException, XenAPIException {
+    protected VBD createVbd(Connection conn, DiskTO volume, String vmName, VM vm, BootloaderType bootLoaderType, VDI vdi) throws XmlRpcException, XenAPIException {
         Volume.Type type = volume.getType();
 
-        VDI vdi = mount(conn, vmName, volume);
+        if (vdi == null) {
+            vdi = mount(conn, vmName, volume);
+        }
+
         if ( vdi != null ) {
             Map<String, String> smConfig = vdi.getSmConfig(conn);
             for (String key : smConfig.keySet()) {
@@ -1608,6 +1611,8 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
         String vmName = vmSpec.getName();
         State state = State.Stopped;
         VM vm = null;
+        // if a VDI is created, record its UUID to send back to the CS MS
+        Map<String, String> iqnToPath = new HashMap<String, String>();
         try {
             Set<VM> vms = VM.getByNameLabel(conn, vmName);
             if ( vms != null ) {
@@ -1636,7 +1641,37 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
             vm = createVmFromTemplate(conn, vmSpec, host);
 
             for (DiskTO disk : vmSpec.getDisks()) {
-                createVbd(conn, disk, vmName, vm, vmSpec.getBootloader());
+                VDI vdi = null;
+
+                if (disk.getData() instanceof VolumeObjectTO) {
+                    Map<String, String> details = disk.getDetails();
+                    boolean isManaged = details != null && Boolean.parseBoolean(details.get(DiskTO.MANAGED));
+
+                    if (isManaged) {
+                        String iScsiName = details.get(DiskTO.IQN);
+                        String storageHost = details.get(DiskTO.STORAGE_HOST);
+                        String chapInitiatorUsername = disk.getDetails().get(DiskTO.CHAP_INITIATOR_USERNAME);
+                        String chapInitiatorSecret = disk.getDetails().get(DiskTO.CHAP_INITIATOR_SECRET);
+                        Long volumeSize = Long.parseLong(details.get(DiskTO.VOLUME_SIZE));
+                        String vdiNameLabel = vmName + "-DATA";
+
+                        SR sr = getIscsiSR(conn, iScsiName, storageHost, iScsiName,
+                                    chapInitiatorUsername, chapInitiatorSecret, true);
+
+                        vdi = getVDIbyUuid(conn, disk.getPath(), false);
+
+                        if (vdi == null) {
+                            vdi = createVdi(sr, vdiNameLabel, volumeSize);
+
+                            iqnToPath.put(iScsiName, vdi.getUuid(conn));
+                        }
+                        else {
+                            vdi.setNameLabel(conn, vdiNameLabel);
+                        }
+                    }
+                }
+
+                createVbd(conn, disk, vmName, vm, vmSpec.getBootloader(), vdi);
             }
 
             if (vmSpec.getType() != VirtualMachine.Type.User) {
@@ -1718,11 +1753,21 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
             }
 
             state = State.Running;
-            return new StartAnswer(cmd);
+
+            StartAnswer startAnswer = new StartAnswer(cmd);
+
+            startAnswer.setIqnToPath(iqnToPath);
+
+            return startAnswer;
         } catch (Exception e) {
             s_logger.warn("Catch Exception: " + e.getClass().toString() + " due to " + e.toString(), e);
             String msg = handleVmStartFailure(conn, vmName, vm, "", e);
-            return new StartAnswer(cmd, msg);
+
+            StartAnswer startAnswer = new StartAnswer(cmd, msg);
+
+            startAnswer.setIqnToPath(iqnToPath);
+
+            return startAnswer;
         } finally {
             synchronized (_cluster.intern()) {
                 if (state != State.Stopped) {
@@ -1733,6 +1778,46 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
                     s_logger.debug("The VM is in stopped state, detected problem during startup : " + vmName);
                 }
             }
+
+            if (state != State.Running) {
+                disconnectManagedVolumes(conn, vm);
+            }
+        }
+    }
+
+    private void disconnectManagedVolumes(Connection conn, VM vm) {
+        try {
+            Set<VBD> vbds = vm.getVBDs(conn);
+
+            for (VBD vbd : vbds) {
+                VDI vdi = vbd.getVDI(conn);
+                SR sr = null;
+
+                try {
+                    sr = vdi.getSR(conn);
+                }
+                catch (Exception ex) {
+                    continue;
+                }
+
+                if (sr.getNameLabel(conn).startsWith("/iqn.")) {
+                    VBD.Record vbdr = vbd.getRecord(conn);
+
+                    if (vbdr.currentlyAttached) {
+                        vbd.unplug(conn);
+                    }
+
+                    vbd.destroy(conn);
+
+                    vdi.setNameLabel(conn, "detached");
+
+                    umount(conn, vdi);
+
+                    handleSrAndVdiDetach(sr.getNameLabel(conn));
+                }
+            }
+        } catch (Exception ex) {
+            s_logger.debug(ex.getMessage());
         }
     }
 
@@ -3976,6 +4061,8 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
 
                     try {
                         if (vm.getPowerState(conn) == VmPowerState.HALTED) {
+                            disconnectManagedVolumes(conn, vm);
+
                             Map<String, String> platform = vm.getPlatform(conn);
                             Integer timeoffset = null;
                             try {
@@ -5385,7 +5472,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);
+                getIscsiSR(conn, pool.getUuid(), pool.getHost(), pool.getPath(), null, null, false);
             } else if (pool.getType() == StoragePoolType.PreSetup) {
             } else {
                 return new Answer(cmd, false, "The pool type: " + pool.getType().name() + " is not supported.");
@@ -6224,7 +6311,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
     }
 
     protected SR getIscsiSR(Connection conn, String srNameLabel, String target, String path,
-            String chapInitiatorUsername, String chapInitiatorPassword) {
+            String chapInitiatorUsername, String chapInitiatorPassword, boolean ignoreIntroduceException) {
         synchronized (srNameLabel.intern()) {
             Map<String, String> deviceConfig = new HashMap<String, String>();
             try {
@@ -6273,8 +6360,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
                 deviceConfig.put("target", target);
                 deviceConfig.put("targetIQN", targetiqn);
 
-                if (StringUtils.isNotBlank(chapInitiatorUsername) &&
-                        StringUtils.isNotBlank(chapInitiatorPassword)) {
+                if (StringUtils.isNotBlank(chapInitiatorUsername) && StringUtils.isNotBlank(chapInitiatorPassword)) {
                     deviceConfig.put("chapuser", chapInitiatorUsername);
                     deviceConfig.put("chappassword", chapInitiatorPassword);
                 }
@@ -6329,8 +6415,17 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
                     sr = SR.create(conn, host, deviceConfig, new Long(0), srNameLabel, srNameLabel, type, "user", true,
                             smConfig);
                 } else {
-                    sr = SR.introduce(conn, pooluuid, srNameLabel, srNameLabel,
-                            type, "user", true, smConfig);
+                    try {
+                        sr = SR.introduce(conn, pooluuid, srNameLabel, srNameLabel,
+                                type, "user", true, smConfig);
+                    }
+                    catch (XenAPIException ex) {
+                        if (ignoreIntroduceException) {
+                            return sr;
+                        }
+
+                        throw ex;
+                    }
 
                     Set<Host> setHosts = Host.getAll(conn);
 
@@ -6557,6 +6652,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
         Connection conn = getConnection();
         boolean attach = cmd.getAttach();
         String vmName = cmd.getVmName();
+        String vdiNameLabel = vmName + "-DATA";
         Long deviceId = cmd.getDeviceId();
 
         String errorMsg;
@@ -6571,12 +6667,12 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
 
             if (cmd.getAttach() && cmd.isManaged()) {
                 SR sr = getIscsiSR(conn, cmd.get_iScsiName(), cmd.getStorageHost(), cmd.get_iScsiName(),
-                            cmd.getChapInitiatorUsername(), cmd.getChapInitiatorPassword());
+                            cmd.getChapInitiatorUsername(), cmd.getChapInitiatorPassword(), true);
 
                 vdi = getVDIbyUuid(conn, cmd.getVolumePath(), false);
 
                 if (vdi == null) {
-                    vdi = createVdi(sr, cmd.get_iScsiName(), cmd.getVolumeSize());
+                    vdi = createVdi(sr, vdiNameLabel, cmd.getVolumeSize());
                 }
             }
             else {
@@ -6632,7 +6728,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
                 vbd.plug(conn);
 
                 // Update the VDI's label to include the VM name
-                vdi.setNameLabel(conn, vmName + "-DATA");
+                vdi.setNameLabel(conn, vdiNameLabel);
 
                 return new AttachVolumeAnswer(cmd, Long.parseLong(diskNumber), vdi.getUuid(conn));
             } else {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/858ce766/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 2d4c86e..1496108 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
@@ -162,6 +162,7 @@ public class XenServerStorageProcessor implements StorageProcessor {
     @Override
     public AttachAnswer attachVolume(AttachCommand cmd) {
         String vmName = cmd.getVmName();
+        String vdiNameLabel = vmName + "-DATA";
         DiskTO disk = cmd.getDisk();
         DataTO data = disk.getData();
 
@@ -170,16 +171,23 @@ public class XenServerStorageProcessor implements StorageProcessor {
 
             VDI vdi = null;
 
-            if (cmd.isManaged()) {
-                SR sr = this.hypervisorResource.getIscsiSR(conn, cmd.get_iScsiName(), cmd.getStorageHost(), cmd.get_iScsiName(),
-                            cmd.getChapInitiatorUsername(), cmd.getChapInitiatorPassword());
+            Map<String, String> details = cmd.getDisk().getDetails();
+            boolean isManaged = Boolean.parseBoolean(details.get(DiskTO.MANAGED));
+
+            if (isManaged) {
+                String iScsiName = details.get(DiskTO.IQN);
+                String storageHost = details.get(DiskTO.STORAGE_HOST);
+                String chapInitiatorUsername = disk.getDetails().get(DiskTO.CHAP_INITIATOR_USERNAME);
+                String chapInitiatorSecret = disk.getDetails().get(DiskTO.CHAP_INITIATOR_SECRET);
+                Long volumeSize = Long.parseLong(details.get(DiskTO.VOLUME_SIZE));
+
+                SR sr = this.hypervisorResource.getIscsiSR(conn, iScsiName, storageHost, iScsiName,
+                            chapInitiatorUsername, chapInitiatorSecret, true);
 
                 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());
+                    vdi = this.hypervisorResource.createVdi(sr, vdiNameLabel, volumeSize);
                 }
             }
             else {
@@ -236,7 +244,7 @@ public class XenServerStorageProcessor implements StorageProcessor {
             vbd.plug(conn);
 
             // Update the VDI's label to include the VM name
-            vdi.setNameLabel(conn, vmName + "-DATA");
+            vdi.setNameLabel(conn, vdiNameLabel);
             DiskTO newDisk = new DiskTO(disk.getData(), Long.parseLong(diskNumber), vdi.getUuid(conn), disk.getType());
             return new AttachAnswer(newDisk);
 


Mime
View raw message