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 2014/01/10 05:37:17 UTC

git commit: updated refs/heads/master to ae35782

Updated Branches:
  refs/heads/master bc1eec9f7 -> ae35782cc


Merge from 4.3: CLOUDSTACK-5662: XenServer can't discover iSCSI targets with different credentials

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

Branch: refs/heads/master
Commit: ae35782ccdc208c3b2952a1250b8164f86238f56
Parents: bc1eec9
Author: Mike Tutkowski <mi...@solidfire.com>
Authored: Thu Jan 9 21:36:34 2014 -0700
Committer: Mike Tutkowski <mi...@solidfire.com>
Committed: Thu Jan 9 21:36:34 2014 -0700

----------------------------------------------------------------------
 api/src/com/cloud/host/Host.java                |   5 +
 .../api/agent/test/CheckOnHostCommandTest.java  |   5 +-
 .../api/storage/PrimaryDataStoreDriver.java     |   5 +
 .../subsystem/api/storage/VolumeService.java    |   4 +
 .../test/FakePrimaryDataStoreDriver.java        |  14 +-
 .../storage/volume/VolumeServiceImpl.java       |  18 +
 .../vmware/resource/VmwareResource.java         |  51 ++-
 .../CloudStackPrimaryDataStoreDriverImpl.java   |   7 +
 .../SamplePrimaryDataStoreDriverImpl.java       |   7 +
 .../driver/SolidfirePrimaryDataStoreDriver.java | 236 +++++++++-
 .../storage/datastore/util/SolidFireUtil.java   | 459 ++++++++++++++-----
 .../com/cloud/storage/VolumeApiServiceImpl.java |  41 +-
 .../com/cloud/hypervisor/vmware/mo/HostMO.java  |   4 +-
 13 files changed, 691 insertions(+), 165 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ae35782c/api/src/com/cloud/host/Host.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/host/Host.java b/api/src/com/cloud/host/Host.java
index 9d81125..689ed12 100755
--- a/api/src/com/cloud/host/Host.java
+++ b/api/src/com/cloud/host/Host.java
@@ -79,6 +79,11 @@ public interface Host extends StateObject<Status>, Identity, InternalIdentity {
     String getPrivateIpAddress();
 
     /**
+     * @return the ip address of the host.
+     */
+    String getStorageUrl();
+
+    /**
      * @return the ip address of the host attached to the storage network.
      */
     String getStorageIpAddress();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ae35782c/core/test/org/apache/cloudstack/api/agent/test/CheckOnHostCommandTest.java
----------------------------------------------------------------------
diff --git a/core/test/org/apache/cloudstack/api/agent/test/CheckOnHostCommandTest.java b/core/test/org/apache/cloudstack/api/agent/test/CheckOnHostCommandTest.java
index d266eb3..9edbf10 100644
--- a/core/test/org/apache/cloudstack/api/agent/test/CheckOnHostCommandTest.java
+++ b/core/test/org/apache/cloudstack/api/agent/test/CheckOnHostCommandTest.java
@@ -81,7 +81,10 @@ public class CheckOnHostCommandTest {
             return "10.1.1.1";
         };
 
-        @Override
+        public String getStorageUrl() {
+            return null;
+        }
+
         public String getStorageIpAddress() {
             return "10.1.1.2";
         };

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ae35782c/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java
index 369ee9c..c4dfc5c 100644
--- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java
+++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java
@@ -21,12 +21,17 @@ package org.apache.cloudstack.engine.subsystem.api.storage;
 import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
 import org.apache.cloudstack.storage.command.CommandResult;
 
+import com.cloud.host.Host;
 import com.cloud.storage.StoragePool;
 import com.cloud.storage.Volume;
 
 public interface PrimaryDataStoreDriver extends DataStoreDriver {
     public ChapInfo getChapInfo(VolumeInfo volumeInfo);
 
+    public boolean connectVolumeToHost(VolumeInfo volumeInfo, Host host, DataStore dataStore);
+
+    public void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore);
+
     public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool);
 
     public void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CreateCmdResult> callback);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ae35782c/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java
index bcc4e7f..3f676ae 100644
--- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java
+++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java
@@ -44,6 +44,10 @@ public interface VolumeService {
 
     ChapInfo getChapInfo(VolumeInfo volumeInfo, DataStore dataStore);
 
+    boolean connectVolumeToHost(VolumeInfo volumeInfo, Host host, DataStore dataStore);
+
+    void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore);
+
     /**
      * Creates the volume based on the given criteria
      *

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ae35782c/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/FakePrimaryDataStoreDriver.java
----------------------------------------------------------------------
diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/FakePrimaryDataStoreDriver.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/FakePrimaryDataStoreDriver.java
index dad6408..266baa7 100644
--- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/FakePrimaryDataStoreDriver.java
+++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/FakePrimaryDataStoreDriver.java
@@ -36,6 +36,7 @@ import org.apache.cloudstack.storage.to.SnapshotObjectTO;
 
 import com.cloud.agent.api.to.DataStoreTO;
 import com.cloud.agent.api.to.DataTO;
+import com.cloud.host.Host;
 import com.cloud.storage.StoragePool;
 import com.cloud.storage.Volume;
 
@@ -43,11 +44,22 @@ public class FakePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
     boolean snapshotResult = true;
 
     @Override
+    public Map<String, String> getCapabilities() {
+        return null;
+    }
+
+    @Override
     public ChapInfo getChapInfo(VolumeInfo volumeInfo) {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+        return null; // To change body of implemented methods, use File | Settings | File Templates.
     }
 
     @Override
+    public boolean  connectVolumeToHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) { return false; }
+
+    @Override
+    public void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) {}
+
+    @Override
     public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) {
         return volume.getSize();
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ae35782c/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
index c9d7fab..ac507cf 100644
--- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
+++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
@@ -158,6 +158,24 @@ public class VolumeServiceImpl implements VolumeService {
         return null;
     }
 
+    public boolean connectVolumeToHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) {
+        DataStoreDriver dataStoreDriver = dataStore.getDriver();
+
+        if (dataStoreDriver instanceof PrimaryDataStoreDriver) {
+            return ((PrimaryDataStoreDriver)dataStoreDriver).connectVolumeToHost(volumeInfo, host, dataStore);
+        }
+
+        return false;
+    }
+
+    public void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) {
+        DataStoreDriver dataStoreDriver = dataStore.getDriver();
+
+        if (dataStoreDriver instanceof PrimaryDataStoreDriver) {
+            ((PrimaryDataStoreDriver)dataStoreDriver).disconnectVolumeFromHost(volumeInfo, host, dataStore);
+        }
+    }
+
     @Override
     public AsyncCallFuture<VolumeApiResult> createVolumeAsync(VolumeInfo volume, DataStore dataStore) {
         AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ae35782c/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 c1d8bac..4aa6f27 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
@@ -4800,22 +4800,26 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
         target.setPort(storagePortNumber);
         target.setIScsiName(iqn);
 
-        HostInternetScsiHbaAuthenticationProperties auth = new HostInternetScsiHbaAuthenticationProperties();
+        if (StringUtils.isNotBlank(chapName) && StringUtils.isNotBlank(chapSecret)) {
+            HostInternetScsiHbaAuthenticationProperties auth = new HostInternetScsiHbaAuthenticationProperties();
 
-        String strAuthType = "chapRequired";
+            String strAuthType = "chapRequired";
 
-        auth.setChapAuthEnabled(true);
-        auth.setChapInherited(false);
-        auth.setChapAuthenticationType(strAuthType);
-        auth.setChapName(chapName);
-        auth.setChapSecret(chapSecret);
+            auth.setChapAuthEnabled(true);
+            auth.setChapInherited(false);
+            auth.setChapAuthenticationType(strAuthType);
+            auth.setChapName(chapName);
+            auth.setChapSecret(chapSecret);
 
-        auth.setMutualChapInherited(false);
-        auth.setMutualChapAuthenticationType(strAuthType);
-        auth.setMutualChapName(mutualChapName);
-        auth.setMutualChapSecret(mutualChapSecret);
+            if (StringUtils.isNotBlank(mutualChapName) && StringUtils.isNotBlank(mutualChapSecret)) {
+                auth.setMutualChapInherited(false);
+                auth.setMutualChapAuthenticationType(strAuthType);
+                auth.setMutualChapName(mutualChapName);
+                auth.setMutualChapSecret(mutualChapSecret);
+            }
 
-        target.setAuthenticationProperties(auth);
+            target.setAuthenticationProperties(auth);
+        }
 
         final List<HostInternetScsiHbaStaticTarget> lstTargets = new ArrayList<HostInternetScsiHbaStaticTarget>();
 
@@ -6052,11 +6056,34 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
         cmd.setName(_url);
         cmd.setGuid(_guid);
         cmd.setDataCenter(_dcId);
+        cmd.setIqn(getIqn());
         cmd.setPod(_pod);
         cmd.setCluster(_cluster);
         cmd.setVersion(VmwareResource.class.getPackage().getImplementationVersion());
     }
 
+    private String getIqn() {
+        try {
+            VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext());
+
+            if (hyperHost instanceof HostMO) {
+                HostMO host = (HostMO)hyperHost;
+                HostStorageSystemMO hostStorageSystem = host.getHostStorageSystemMO();
+
+                for (HostHostBusAdapter hba : hostStorageSystem.getStorageDeviceInfo().getHostBusAdapter()) {
+                    if (hba instanceof HostInternetScsiHba) {
+                        return ((HostInternetScsiHba)hba).getIScsiName();
+                    }
+                }
+            }
+        }
+        catch (Exception ex) {
+            s_logger.info("Could not locate an IQN for this host.");
+        }
+
+        return null;
+    }
+
     private void fillHostHardwareInfo(VmwareContext serviceContext, StartupRoutingCommand cmd) throws RuntimeFaultFaultMsg, RemoteException, Exception {
 
         VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext());

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ae35782c/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java
index c8e2582..ae217b6 100644
--- a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java
+++ b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java
@@ -61,6 +61,7 @@ import com.cloud.agent.api.to.DataTO;
 import com.cloud.agent.api.to.StorageFilerTO;
 import com.cloud.configuration.Config;
 import com.cloud.exception.StorageUnavailableException;
+import com.cloud.host.Host;
 import com.cloud.host.dao.HostDao;
 import com.cloud.storage.CreateSnapshotPayload;
 import com.cloud.storage.DataStoreRole;
@@ -150,6 +151,12 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri
     }
 
     @Override
+    public boolean connectVolumeToHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) { return false; }
+
+    @Override
+    public void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) {}
+
+    @Override
     public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) {
         return volume.getSize();
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ae35782c/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java b/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java
index 4cfc097..1f9a128 100644
--- a/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java
+++ b/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java
@@ -42,6 +42,7 @@ import org.apache.cloudstack.storage.datastore.DataObjectManager;
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.to.DataStoreTO;
 import com.cloud.agent.api.to.DataTO;
+import com.cloud.host.Host;
 import com.cloud.storage.StoragePool;
 import com.cloud.storage.Volume;
 import com.cloud.storage.dao.StoragePoolHostDao;
@@ -81,6 +82,12 @@ public class SamplePrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
     }
 
     @Override
+    public boolean connectVolumeToHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) { return false; }
+
+    @Override
+    public void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) {}
+
+    @Override
     public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) {
         return volume.getSize();
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ae35782c/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 7959af9..1212b60 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
@@ -17,8 +17,10 @@
 package org.apache.cloudstack.storage.datastore.driver;
 
 import java.text.NumberFormat;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.UUID;
 
 import javax.inject.Inject;
 
@@ -44,7 +46,12 @@ import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.to.DataObjectType;
 import com.cloud.agent.api.to.DataStoreTO;
 import com.cloud.agent.api.to.DataTO;
+import com.cloud.dc.ClusterDetailsVO;
+import com.cloud.dc.ClusterDetailsDao;
 import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.host.Host;
+import com.cloud.host.HostVO;
+import com.cloud.host.dao.HostDao;
 import com.cloud.storage.Storage.StoragePoolType;
 import com.cloud.storage.StoragePool;
 import com.cloud.storage.Volume;
@@ -55,22 +62,18 @@ import com.cloud.user.AccountDetailVO;
 import com.cloud.user.AccountDetailsDao;
 import com.cloud.user.AccountVO;
 import com.cloud.user.dao.AccountDao;
+import com.cloud.utils.exception.CloudRuntimeException;
 
 public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
-    @Inject
-    private PrimaryDataStoreDao _storagePoolDao;
-    @Inject
-    private StoragePoolDetailsDao _storagePoolDetailsDao;
-    @Inject
-    private VolumeDao _volumeDao;
-    @Inject
-    private VolumeDetailsDao _volumeDetailsDao;
-    @Inject
-    private DataCenterDao _zoneDao;
-    @Inject
-    private AccountDao _accountDao;
-    @Inject
-    private AccountDetailsDao _accountDetailsDao;
+    @Inject private PrimaryDataStoreDao _storagePoolDao;
+    @Inject private StoragePoolDetailsDao _storagePoolDetailsDao;
+    @Inject private VolumeDao _volumeDao;
+    @Inject private VolumeDetailsDao _volumeDetailsDao;
+    @Inject private DataCenterDao _zoneDao;
+    @Inject private AccountDao _accountDao;
+    @Inject private AccountDetailsDao _accountDetailsDao;
+    @Inject private ClusterDetailsDao _clusterDetailsDao;
+    @Inject private HostDao _hostDao;
 
     @Override
     public Map<String, String> getCapabilities() {
@@ -149,25 +152,35 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
     }
 
     private void updateCsDbWithAccountInfo(long csAccountId, SolidFireUtil.SolidFireAccount sfAccount) {
-        AccountDetailVO accountDetails = new AccountDetailVO(csAccountId, SolidFireUtil.ACCOUNT_ID, String.valueOf(sfAccount.getId()));
+        AccountDetailVO accountDetail = new AccountDetailVO(csAccountId,
+                SolidFireUtil.ACCOUNT_ID,
+                String.valueOf(sfAccount.getId()));
 
-        _accountDetailsDao.persist(accountDetails);
+        _accountDetailsDao.persist(accountDetail);
 
-        accountDetails = new AccountDetailVO(csAccountId, SolidFireUtil.CHAP_INITIATOR_USERNAME, String.valueOf(sfAccount.getName()));
+        accountDetail = new AccountDetailVO(csAccountId,
+                SolidFireUtil.CHAP_INITIATOR_USERNAME,
+                String.valueOf(sfAccount.getName()));
 
-        _accountDetailsDao.persist(accountDetails);
+        _accountDetailsDao.persist(accountDetail);
 
-        accountDetails = new AccountDetailVO(csAccountId, SolidFireUtil.CHAP_INITIATOR_SECRET, String.valueOf(sfAccount.getInitiatorSecret()));
+        accountDetail = new AccountDetailVO(csAccountId,
+                SolidFireUtil.CHAP_INITIATOR_SECRET,
+                String.valueOf(sfAccount.getInitiatorSecret()));
 
-        _accountDetailsDao.persist(accountDetails);
+        _accountDetailsDao.persist(accountDetail);
 
-        accountDetails = new AccountDetailVO(csAccountId, SolidFireUtil.CHAP_TARGET_USERNAME, sfAccount.getName());
+        accountDetail = new AccountDetailVO(csAccountId,
+                SolidFireUtil.CHAP_TARGET_USERNAME,
+                sfAccount.getName());
 
-        _accountDetailsDao.persist(accountDetails);
+        _accountDetailsDao.persist(accountDetail);
 
-        accountDetails = new AccountDetailVO(csAccountId, SolidFireUtil.CHAP_TARGET_SECRET, sfAccount.getTargetSecret());
+        accountDetail = new AccountDetailVO(csAccountId,
+                SolidFireUtil.CHAP_TARGET_SECRET,
+                sfAccount.getTargetSecret());
 
-        _accountDetailsDao.persist(accountDetails);
+        _accountDetailsDao.persist(accountDetail);
     }
 
     private class ChapInfoImpl implements ChapInfo {
@@ -227,6 +240,179 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
         return new ChapInfoImpl(chapInitiatorUsername, chapInitiatorSecret, chapTargetUsername, chapTargetSecret);
     }
 
+    // get the VAG associated with volumeInfo's cluster, if any (ListVolumeAccessGroups)
+    // if the VAG exists
+    //     update the VAG to contain all IQNs of the hosts (ModifyVolumeAccessGroup)
+    //     if the ID of volumeInfo in not in the VAG, add it (ModifyVolumeAccessGroup)
+    // if the VAG doesn't exist, create it with the IQNs of the hosts and the ID of volumeInfo (CreateVolumeAccessGroup)
+    @Override
+    public boolean connectVolumeToHost(VolumeInfo volumeInfo, Host host, DataStore dataStore)
+    {
+        if (volumeInfo == null || host == null || dataStore == null) {
+            return false;
+        }
+
+        long sfVolumeId = Long.parseLong(volumeInfo.getFolder());
+        long clusterId = host.getClusterId();
+        long storagePoolId = dataStore.getId();
+
+        ClusterDetailsVO clusterDetail = _clusterDetailsDao.findDetail(clusterId, getVagKey(storagePoolId));
+
+        String vagId = clusterDetail != null ? clusterDetail.getValue() : null;
+
+        List<HostVO> hosts = _hostDao.findByClusterId(clusterId);
+
+        if (!hostsSupport_iScsi(hosts)) {
+            return false;
+        }
+
+        SolidFireConnection sfConnection = getSolidFireConnection(storagePoolId);
+
+        if (vagId != null) {
+            SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(),
+                sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), Long.parseLong(vagId));
+
+            long[] volumeIds = getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, true);
+
+            SolidFireUtil.modifySolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(),
+                sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), sfVag.getId(),
+                getIqnsFromHosts(hosts), volumeIds);
+        }
+        else {
+            long lVagId = SolidFireUtil.createSolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(),
+                sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), "CloudStack-" + UUID.randomUUID().toString(),
+                getIqnsFromHosts(hosts), new long[] { sfVolumeId });
+
+            clusterDetail = new ClusterDetailsVO(clusterId, getVagKey(storagePoolId), String.valueOf(lVagId));
+
+            _clusterDetailsDao.persist(clusterDetail);
+        }
+
+        return true;
+    }
+
+    // get the VAG associated with volumeInfo's cluster, if any (ListVolumeAccessGroups) // might not exist if using CHAP
+    // if the VAG exists
+    //     remove the ID of volumeInfo from the VAG (ModifyVolumeAccessGroup)
+    @Override
+    public void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore)
+    {
+        if (volumeInfo == null || host == null || dataStore == null) {
+            return;
+        }
+
+        long sfVolumeId = Long.parseLong(volumeInfo.getFolder());
+        long clusterId = host.getClusterId();
+        long storagePoolId = dataStore.getId();
+
+        ClusterDetailsVO clusterDetail = _clusterDetailsDao.findDetail(clusterId, getVagKey(storagePoolId));
+
+        String vagId = clusterDetail != null ? clusterDetail.getValue() : null;
+
+        if (vagId != null) {
+            List<HostVO> hosts = _hostDao.findByClusterId(clusterId);
+
+            SolidFireConnection sfConnection = getSolidFireConnection(storagePoolId);
+
+            SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(),
+                sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), Long.parseLong(vagId));
+
+            long[] volumeIds = getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, false);
+
+            SolidFireUtil.modifySolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(),
+                sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), sfVag.getId(),
+                getIqnsFromHosts(hosts), volumeIds);
+        }
+    }
+
+    private boolean hostsSupport_iScsi(List<HostVO> hosts) {
+        if (hosts == null || hosts.size() == 0) {
+            return false;
+        }
+
+        for (Host host : hosts) {
+            if (host == null || host.getStorageUrl() == null || host.getStorageUrl().trim().length() == 0 || !host.getStorageUrl().startsWith("iqn")) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    private long[] getNewVolumeIds(long[] volumeIds, long volumeIdToAddOrRemove, boolean add) {
+        if (add) {
+            return getNewVolumeIdsAdd(volumeIds, volumeIdToAddOrRemove);
+        }
+
+        return getNewVolumeIdsRemove(volumeIds, volumeIdToAddOrRemove);
+    }
+
+    private long[] getNewVolumeIdsAdd(long[] volumeIds, long volumeIdToAdd) {
+        List<Long> lstVolumeIds = new ArrayList<Long>();
+
+        if (volumeIds != null) {
+            for (long volumeId : volumeIds) {
+                lstVolumeIds.add(volumeId);
+            }
+        }
+
+        if (lstVolumeIds.contains(volumeIdToAdd)) {
+            return volumeIds;
+        }
+
+        lstVolumeIds.add(volumeIdToAdd);
+
+        return convertArray(lstVolumeIds);
+    }
+
+    private long[] getNewVolumeIdsRemove(long[] volumeIds, long volumeIdToRemove) {
+        List<Long> lstVolumeIds = new ArrayList<Long>();
+
+        if (volumeIds != null) {
+            for (long volumeId : volumeIds) {
+                lstVolumeIds.add(volumeId);
+            }
+        }
+
+        lstVolumeIds.remove(volumeIdToRemove);
+
+        return convertArray(lstVolumeIds);
+    }
+
+    private long[] convertArray(List<Long> items) {
+        if (items == null) {
+            return new long[0];
+        }
+
+        long[] outArray = new long[items.size()];
+
+        for (int i = 0; i < items.size(); i++) {
+            Long value = items.get(i);
+
+            outArray[i] = value;
+        }
+
+        return outArray;
+    }
+
+    private String getVagKey(long storagePoolId) {
+        return "sfVolumeAccessGroup_" + storagePoolId;
+    }
+
+    private String[] getIqnsFromHosts(List<? extends Host> hosts) {
+        if (hosts == null || hosts.size() == 0) {
+            throw new CloudRuntimeException("There do not appear to be any hosts in this cluster.");
+        }
+
+        List<String> lstIqns = new ArrayList<String>();
+
+        for (Host host : hosts) {
+            lstIqns.add(host.getStorageUrl());
+        }
+
+        return lstIqns.toArray(new String[0]);
+    }
+
     private long getDefaultMinIops(long storagePoolId) {
         StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_DEFAULT_MIN_IOPS);
 
@@ -449,6 +635,7 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
         callback.complete(result);
     }
 
+    /*
     private void deleteSolidFireAccount(long sfAccountId, SolidFireConnection sfConnection) {
         String mVip = sfConnection.getManagementVip();
         int mPort = sfConnection.getManagementPort();
@@ -488,6 +675,7 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
 
         return false;
     }
+    */
 
     @Override
     public void deleteAsync(DataStore dataStore, DataObject dataObject, AsyncCompletionCallback<CommandResult> callback) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ae35782c/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 3c96c09..8d023d6 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
@@ -95,32 +95,8 @@ public class SolidFireUtil {
         return volumeCreateResult.result.volumeID;
     }
 
-    public static SolidFireVolume deleteSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId)
+    public static SolidFireVolume getSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId)
     {
-        SolidFireVolume sfVolume = getSolidFireVolume(strSfMvip, iSfPort, strSfAdmin, strSfPassword, lVolumeId);
-
-        final Gson gson = new GsonBuilder().create();
-
-        VolumeToDelete volumeToDelete = new VolumeToDelete(lVolumeId);
-
-        String strVolumeToDeleteJson = gson.toJson(volumeToDelete);
-
-        executeJsonRpc(strVolumeToDeleteJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
-
-        return sfVolume;
-    }
-
-    public static void purgeSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId) {
-        final Gson gson = new GsonBuilder().create();
-
-        VolumeToPurge volumeToPurge = new VolumeToPurge(lVolumeId);
-
-        String strVolumeToPurgeJson = gson.toJson(volumeToPurge);
-
-        executeJsonRpc(strVolumeToPurgeJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
-    }
-
-    public static SolidFireVolume getSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId) {
         final Gson gson = new GsonBuilder().create();
 
         VolumeToGet volumeToGet = new VolumeToGet(lVolumeId);
@@ -164,6 +140,56 @@ public class SolidFireUtil {
         return sfVolumes;
     }
 
+    public static List<SolidFireVolume> getDeletedVolumes(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword)
+    {
+        final Gson gson = new GsonBuilder().create();
+
+        ListDeletedVolumes listDeletedVolumes = new ListDeletedVolumes();
+
+        String strListDeletedVolumesJson = gson.toJson(listDeletedVolumes);
+
+        String strListDeletedVolumesResultJson = executeJsonRpc(strListDeletedVolumesJson, strSfMvip, iSfPort,
+                strSfAdmin, strSfPassword);
+
+        VolumeGetResult volumeGetResult = gson.fromJson(strListDeletedVolumesResultJson, VolumeGetResult.class);
+
+        verifyResult(volumeGetResult.result, strListDeletedVolumesResultJson, gson);
+
+        List<SolidFireVolume> deletedVolumes = new ArrayList<SolidFireVolume> ();
+
+        for (VolumeGetResult.Result.Volume volume : volumeGetResult.result.volumes) {
+            deletedVolumes.add(new SolidFireVolume(volume.volumeID, volume.name, volume.iqn, volume.accountID, volume.status, volume.totalSize));
+        }
+
+        return deletedVolumes;
+    }
+
+    public static SolidFireVolume deleteSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId)
+    {
+        SolidFireVolume sfVolume = getSolidFireVolume(strSfMvip, iSfPort, strSfAdmin, strSfPassword, lVolumeId);
+
+        final Gson gson = new GsonBuilder().create();
+
+        VolumeToDelete volumeToDelete = new VolumeToDelete(lVolumeId);
+
+        String strVolumeToDeleteJson = gson.toJson(volumeToDelete);
+
+        executeJsonRpc(strVolumeToDeleteJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+
+        return sfVolume;
+    }
+
+   public static void purgeSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId)
+    {
+        final Gson gson = new GsonBuilder().create();
+
+        VolumeToPurge volumeToPurge = new VolumeToPurge(lVolumeId);
+
+        String strVolumeToPurgeJson = gson.toJson(volumeToPurge);
+
+        executeJsonRpc(strVolumeToPurgeJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+    }
+
     private static final String ACTIVE = "active";
 
     public static class SolidFireVolume {
@@ -257,17 +283,9 @@ public class SolidFireUtil {
         return accountAddResult.result.accountID;
     }
 
-    public static void deleteSolidFireAccount(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lAccountId) {
-        final Gson gson = new GsonBuilder().create();
-
-        AccountToRemove accountToRemove = new AccountToRemove(lAccountId);
-
-        String strAccountToRemoveJson = gson.toJson(accountToRemove);
-
-        executeJsonRpc(strAccountToRemoveJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
-    }
-
-    public static SolidFireAccount getSolidFireAccountById(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lSfAccountId) {
+    public static SolidFireAccount getSolidFireAccountById(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword,
+            long lSfAccountId)
+    {
         final Gson gson = new GsonBuilder().create();
 
         AccountToGetById accountToGetById = new AccountToGetById(lSfAccountId);
@@ -307,7 +325,20 @@ public class SolidFireUtil {
         return new SolidFireAccount(lSfAccountId, strSfAccountName, strSfAccountInitiatorSecret, strSfAccountTargetSecret);
     }
 
-    public static class SolidFireAccount {
+    public static void deleteSolidFireAccount(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword,
+            long lAccountId)
+    {
+        final Gson gson = new GsonBuilder().create();
+
+        AccountToRemove accountToRemove = new AccountToRemove(lAccountId);
+
+        String strAccountToRemoveJson = gson.toJson(accountToRemove);
+
+        executeJsonRpc(strAccountToRemoveJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+    }
+
+    public static class SolidFireAccount
+    {
         private final long _id;
         private final String _name;
         private final String _initiatorSecret;
@@ -358,7 +389,9 @@ public class SolidFireUtil {
 
             SolidFireAccount sfa = (SolidFireAccount)obj;
 
-            if (_id == sfa._id && _name.equals(sfa._name) && _initiatorSecret.equals(sfa._initiatorSecret) && _targetSecret.equals(sfa._targetSecret)) {
+            if (_id == sfa._id && _name.equals(sfa._name) &&
+                _initiatorSecret.equals(sfa._initiatorSecret) &&
+                _targetSecret.equals(sfa._targetSecret)) {
                 return true;
             }
 
@@ -366,42 +399,54 @@ public class SolidFireUtil {
         }
     }
 
-    public static List<SolidFireVolume> getDeletedVolumes(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword) {
+    public static long createSolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, String strVagName,
+            String[] iqns, long[] volumeIds)
+    {
         final Gson gson = new GsonBuilder().create();
 
-        ListDeletedVolumes listDeletedVolumes = new ListDeletedVolumes();
+        VagToCreate vagToCreate = new VagToCreate(strVagName, iqns, volumeIds);
 
-        String strListDeletedVolumesJson = gson.toJson(listDeletedVolumes);
+        String strVagCreateJson = gson.toJson(vagToCreate);
 
-        String strListDeletedVolumesResultJson = executeJsonRpc(strListDeletedVolumesJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        String strVagCreateResultJson = executeJsonRpc(strVagCreateJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
 
-        VolumeGetResult volumeGetResult = gson.fromJson(strListDeletedVolumesResultJson, VolumeGetResult.class);
+        VagCreateResult vagCreateResult = gson.fromJson(strVagCreateResultJson, VagCreateResult.class);
 
-        verifyResult(volumeGetResult.result, strListDeletedVolumesResultJson, gson);
+        verifyResult(vagCreateResult.result, strVagCreateResultJson, gson);
+
+        return vagCreateResult.result.volumeAccessGroupID;
+    }
 
-        List<SolidFireVolume> deletedVolumes = new ArrayList<SolidFireVolume>();
+    public static void modifySolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVagId,
+            String[] iqns, long[] volumeIds)
+    {
+        final Gson gson = new GsonBuilder().create();
 
-        for (VolumeGetResult.Result.Volume volume : volumeGetResult.result.volumes) {
-            deletedVolumes.add(new SolidFireVolume(volume.volumeID, volume.name, volume.iqn, volume.accountID, volume.status, volume.totalSize));
-        }
+        VagToModify vagToModify = new VagToModify(lVagId, iqns, volumeIds);
 
-        return deletedVolumes;
+        String strVagModifyJson = gson.toJson(vagToModify);
+
+        executeJsonRpc(strVagModifyJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
     }
 
-    public static long createSolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, String strVagName) {
+    public static SolidFireVag getSolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVagId)
+    {
         final Gson gson = new GsonBuilder().create();
 
-        VagToCreate vagToCreate = new VagToCreate(strVagName);
+        VagToGet vagToGet = new VagToGet(lVagId);
 
-        String strVagCreateJson = gson.toJson(vagToCreate);
+        String strVagToGetJson = gson.toJson(vagToGet);
 
-        String strVagCreateResultJson = executeJsonRpc(strVagCreateJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        String strVagGetResultJson = executeJsonRpc(strVagToGetJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
 
-        VagCreateResult vagCreateResult = gson.fromJson(strVagCreateResultJson, VagCreateResult.class);
+        VagGetResult vagGetResult = gson.fromJson(strVagGetResultJson, VagGetResult.class);
 
-        verifyResult(vagCreateResult.result, strVagCreateResultJson, gson);
+        verifyResult(vagGetResult.result, strVagGetResultJson, gson);
 
-        return vagCreateResult.result.volumeAccessGroupID;
+        String[] vagIqns = getVagIqns(vagGetResult, lVagId);
+        long[] vagVolumeIds = getVagVolumeIds(vagGetResult, lVagId);
+
+        return new SolidFireVag(lVagId, vagIqns, vagVolumeIds);
     }
 
     public static void deleteSolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVagId) {
@@ -414,6 +459,64 @@ public class SolidFireUtil {
         executeJsonRpc(strVagToDeleteJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
     }
 
+    public static class SolidFireVag
+    {
+        private final long _id;
+        private final String[] _initiators;
+        private final long[] _volumeIds;
+
+        public SolidFireVag(long id, String[] initiators, long[] volumeIds)
+        {
+            _id = id;
+            _initiators = initiators;
+            _volumeIds = volumeIds;
+        }
+
+        public long getId()
+        {
+            return _id;
+        }
+
+        public String[] getInitiators()
+        {
+            return _initiators;
+        }
+
+        public long[] getVolumeIds()
+        {
+            return _volumeIds;
+        }
+
+        @Override
+        public int hashCode() {
+            return String.valueOf(_id).hashCode();
+        }
+
+        @Override
+        public String toString() {
+            return String.valueOf(_id);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == null) {
+                return false;
+            }
+
+            if (!obj.getClass().equals(SolidFireVag.class)) {
+                return false;
+            }
+
+            SolidFireVag sfvag = (SolidFireVag)obj;
+
+            if (_id == sfvag._id) {
+                return true;
+            }
+
+            return false;
+        }
+    }
+
     @SuppressWarnings("unused")
     private static final class VolumeToCreate {
         private final String method = "CreateVolume";
@@ -466,7 +569,59 @@ public class SolidFireUtil {
     }
 
     @SuppressWarnings("unused")
-    private static final class VolumeToDelete {
+    private static final class VolumeToGet
+    {
+        private final String method = "ListActiveVolumes";
+        private final VolumeToGetParams params;
+
+        private VolumeToGet(final long lVolumeId)
+        {
+            params = new VolumeToGetParams(lVolumeId);
+        }
+
+        private static final class VolumeToGetParams
+        {
+            private final long startVolumeID;
+            private final long limit = 1;
+
+            private VolumeToGetParams(final long lVolumeId)
+            {
+                startVolumeID = lVolumeId;
+            }
+        }
+    }
+
+    @SuppressWarnings("unused")
+    private static final class VolumesToGetForAccount
+    {
+        private final String method = "ListVolumesForAccount";
+        private final VolumesToGetForAccountParams params;
+
+        private VolumesToGetForAccount(final long lAccountId)
+        {
+            params = new VolumesToGetForAccountParams(lAccountId);
+        }
+
+        private static final class VolumesToGetForAccountParams
+        {
+            private final long accountID;
+
+            private VolumesToGetForAccountParams(final long lAccountId)
+            {
+                accountID = lAccountId;
+            }
+        }
+    }
+
+    @SuppressWarnings("unused")
+    private static final class ListDeletedVolumes
+    {
+        private final String method = "ListDeletedVolumes";
+    }
+
+    @SuppressWarnings("unused")
+    private static final class VolumeToDelete
+    {
         private final String method = "DeleteVolume";
         private final VolumeToDeleteParams params;
 
@@ -484,12 +639,8 @@ public class SolidFireUtil {
     }
 
     @SuppressWarnings("unused")
-    private static final class ListDeletedVolumes {
-        private final String method = "ListDeletedVolumes";
-    }
-
-    @SuppressWarnings("unused")
-    private static final class VolumeToPurge {
+    private static final class VolumeToPurge
+    {
         private final String method = "PurgeDeletedVolume";
         private final VolumeToPurgeParams params;
 
@@ -507,56 +658,67 @@ public class SolidFireUtil {
     }
 
     @SuppressWarnings("unused")
-    private static final class VolumeToGet {
-        private final String method = "ListActiveVolumes";
-        private final VolumeToGetParams params;
+    private static final class AccountToAdd
+    {
+        private final String method = "AddAccount";
+        private final AccountToAddParams params;
 
-        private VolumeToGet(final long lVolumeId) {
-            params = new VolumeToGetParams(lVolumeId);
+        private AccountToAdd(final String strAccountName)
+        {
+            params = new AccountToAddParams(strAccountName);
         }
 
-        private static final class VolumeToGetParams {
-            private final long startVolumeID;
-            private final long limit = 1;
+        private static final class AccountToAddParams
+        {
+            private final String username;
 
-            private VolumeToGetParams(final long lVolumeId) {
-                startVolumeID = lVolumeId;
+            private AccountToAddParams(final String strAccountName)
+            {
+                username = strAccountName;
             }
         }
     }
 
     @SuppressWarnings("unused")
-    private static final class VolumesToGetForAccount {
-        private final String method = "ListVolumesForAccount";
-        private final VolumesToGetForAccountParams params;
+    private static final class AccountToGetById
+    {
+        private final String method = "GetAccountByID";
+        private final AccountToGetByIdParams params;
 
-        private VolumesToGetForAccount(final long lAccountId) {
-            params = new VolumesToGetForAccountParams(lAccountId);
+        private AccountToGetById(final long lAccountId)
+        {
+            params = new AccountToGetByIdParams(lAccountId);
         }
 
-        private static final class VolumesToGetForAccountParams {
+        private static final class AccountToGetByIdParams
+        {
             private final long accountID;
 
-            private VolumesToGetForAccountParams(final long lAccountId) {
+            private AccountToGetByIdParams(final long lAccountId)
+            {
                 accountID = lAccountId;
             }
         }
     }
 
     @SuppressWarnings("unused")
-    private static final class AccountToAdd {
-        private final String method = "AddAccount";
-        private final AccountToAddParams params;
+    private static final class AccountToGetByName
+    {
+        private final String method = "GetAccountByName";
+        private final AccountToGetByNameParams params;
 
-        private AccountToAdd(final String strAccountName) {
-            params = new AccountToAddParams(strAccountName);
+        private AccountToGetByName(final String strUsername)
+        {
+            params = new AccountToGetByNameParams(strUsername);
         }
 
-        private static final class AccountToAddParams {
+        private static final class AccountToGetByNameParams
+        {
             private final String username;
 
-            private AccountToAddParams(final String strAccountName) {
-                username = strAccountName;
+            private AccountToGetByNameParams(final String strUsername)
+            {
+                username = strUsername;
             }
         }
     }
@@ -580,55 +742,76 @@ public class SolidFireUtil {
     }
 
     @SuppressWarnings("unused")
-    private static final class AccountToGetById {
-        private final String method = "GetAccountByID";
-        private final AccountToGetByIdParams params;
+    private static final class VagToCreate
+    {
+        private final String method = "CreateVolumeAccessGroup";
+        private final VagToCreateParams params;
 
-        private AccountToGetById(final long lAccountId) {
-            params = new AccountToGetByIdParams(lAccountId);
+        private VagToCreate(final String strVagName, final String[] iqns, final long[] volumeIds)
+        {
+            params = new VagToCreateParams(strVagName, iqns, volumeIds);
         }
 
-        private static final class AccountToGetByIdParams {
-            private final long accountID;
+        private static final class VagToCreateParams
+        {
+            private final String name;
+            private final String[] initiators;
+            private final long[] volumes;
 
-            private AccountToGetByIdParams(final long lAccountId) {
-                accountID = lAccountId;
+            private VagToCreateParams(final String strVagName, final String[] iqns, final long[] volumeIds)
+            {
+                name = strVagName;
+                initiators = iqns;
+                volumes = volumeIds;
             }
         }
     }
 
     @SuppressWarnings("unused")
-    private static final class AccountToGetByName {
-        private final String method = "GetAccountByName";
-        private final AccountToGetByNameParams params;
+    private static final class VagToModify
+    {
+        private final String method = "ModifyVolumeAccessGroup";
+        private final VagToModifyParams params;
 
-        private AccountToGetByName(final String strUsername) {
-            params = new AccountToGetByNameParams(strUsername);
+        private VagToModify(final long lVagName, final String[] iqns, final long[] volumeIds)
+        {
+            params = new VagToModifyParams(lVagName, iqns, volumeIds);
         }
 
-        private static final class AccountToGetByNameParams {
-            private final String username;
-
-            private AccountToGetByNameParams(final String strUsername) {
-                username = strUsername;
+        private static final class VagToModifyParams
+        {
+            private final long volumeAccessGroupID;
+            private final String[] initiators;
+            private final long[] volumes;
+
+            private VagToModifyParams(final long lVagName, final String[] iqns, final long[] volumeIds)
+            {
+                volumeAccessGroupID = lVagName;
+                initiators = iqns;
+                volumes = volumeIds;
             }
         }
     }
 
     @SuppressWarnings("unused")
-    private static final class VagToCreate {
-        private final String method = "CreateVolumeAccessGroup";
-        private final VagToCreateParams params;
+    private static final class VagToGet
+    {
+        private final String method = "ListVolumeAccessGroups";
+        private final VagToGetParams params;
 
-        private VagToCreate(final String strVagName) {
-            params = new VagToCreateParams(strVagName);
+        private VagToGet(final long lVagId)
+        {
+            params = new VagToGetParams(lVagId);
         }
 
-        private static final class VagToCreateParams {
-            private final String name;
+        private static final class VagToGetParams
+        {
+            private final long startVolumeAccessGroupID;
+            private final long limit = 1;
 
-            private VagToCreateParams(final String strVagName) {
-                name = strVagName;
+            private VagToGetParams(final long lVagId)
+            {
+                startVolumeAccessGroupID = lVagId;
             }
         }
     }
@@ -707,7 +890,25 @@ public class SolidFireUtil {
         }
     }
 
-    private static final class JsonError {
+    private static final class VagGetResult
+    {
+        private Result result;
+
+        private static final class Result
+        {
+            private Vag[] volumeAccessGroups;
+
+            private static final class Vag
+            {
+                private long volumeAccessGroupID;
+                private String[] initiators;
+                private long[] volumes;
+            }
+        }
+    }
+
+    private static final class JsonError
+    {
         private Error error;
 
         private static final class Error {
@@ -762,7 +963,7 @@ public class SolidFireUtil {
 
             httpClient = getHttpClient(iPort);
 
-            URI uri = new URI("https://" + strMvip + ":" + iPort + "/json-rpc/1.0");
+            URI uri = new URI("https://" + strMvip + ":" + iPort + "/json-rpc/5.0");
             AuthScope authScope = new AuthScope(uri.getHost(), uri.getPort(), AuthScope.ANY_SCHEME);
             UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(strAdmin, strPassword);
 
@@ -865,4 +1066,26 @@ public class SolidFireUtil {
 
         throw new CloudRuntimeException("Could not determine the total size of the volume for volume ID of " + lVolumeId + ".");
     }
+
+    private static String[] getVagIqns(VagGetResult vagGetResult, long lVagId)
+    {
+        if (vagGetResult.result.volumeAccessGroups != null && vagGetResult.result.volumeAccessGroups.length == 1 &&
+            vagGetResult.result.volumeAccessGroups[0].volumeAccessGroupID == lVagId)
+        {
+            return vagGetResult.result.volumeAccessGroups[0].initiators;
+        }
+
+        throw new CloudRuntimeException("Could not determine the IQNs of the volume access group for volume access group ID of " + lVagId + ".");
+    }
+
+    private static long[] getVagVolumeIds(VagGetResult vagGetResult, long lVagId)
+    {
+        if (vagGetResult.result.volumeAccessGroups != null && vagGetResult.result.volumeAccessGroups.length == 1 &&
+            vagGetResult.result.volumeAccessGroups[0].volumeAccessGroupID == lVagId)
+        {
+            return vagGetResult.result.volumeAccessGroups[0].volumes;
+        }
+
+        throw new CloudRuntimeException("Could not determine the volume IDs of the volume access group for volume access group ID of " + lVagId + ".");
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ae35782c/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 5f15cac..ac0c438 100644
--- a/server/src/com/cloud/storage/VolumeApiServiceImpl.java
+++ b/server/src/com/cloud/storage/VolumeApiServiceImpl.java
@@ -1434,8 +1434,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
         Volume volume = _volumeDao.findById(volumeId);
         VMInstanceVO vm = _vmInstanceDao.findById(vmId);
 
-        String errorMsg = "Failed to detach volume: " + volume.getName() + " from VM: " + vm.getHostName();
-        boolean sendCommand = (vm.getState() == State.Running);
+        String errorMsg = "Failed to detach volume " + volume.getName() + " from VM " + vm.getHostName();
+        boolean sendCommand = vm.getState() == State.Running;
 
         Long hostId = vm.getHostId();
 
@@ -1449,10 +1449,11 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
             }
         }
 
+        HostVO host = null;
         StoragePoolVO volumePool = _storagePoolDao.findById(volume.getPoolId());
 
         if (hostId != null) {
-            HostVO host = _hostDao.findById(hostId);
+            host = _hostDao.findById(hostId);
 
             if (host != null && host.getHypervisorType() == HypervisorType.XenServer && volumePool.isManaged()) {
                 sendCommand = true;
@@ -1481,10 +1482,14 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
             }
         }
 
+        DataStore dataStore = dataStoreMgr.getDataStore(volume.getPoolId(), DataStoreRole.Primary);
+
         if (!sendCommand || (answer != null && answer.getResult())) {
             // Mark the volume as detached
             _volsDao.detachVolume(volume.getId());
 
+            volService.disconnectVolumeFromHost(volFactory.getVolume(volume.getId()), host, dataStore);
+
             return _volsDao.findById(volumeId);
         } else {
 
@@ -1924,13 +1929,14 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
     }
 
     private VolumeVO sendAttachVolumeCommand(UserVmVO vm, VolumeVO volumeToAttach, Long deviceId) {
-        String errorMsg = "Failed to attach volume: " + volumeToAttach.getName() + " to VM: " + vm.getHostName();
-        boolean sendCommand = (vm.getState() == State.Running);
+        String errorMsg = "Failed to attach volume " + volumeToAttach.getName() + " to VM " + vm.getHostName();
+        boolean sendCommand = vm.getState() == State.Running;
         AttachAnswer answer = null;
         Long hostId = vm.getHostId();
 
         if (hostId == null) {
             hostId = vm.getLastHostId();
+
             HostVO host = _hostDao.findById(hostId);
 
             if (host != null && host.getHypervisorType() == HypervisorType.VMware) {
@@ -1949,6 +1955,22 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
             }
         }
 
+        DataStore dataStore = dataStoreMgr.getDataStore(volumeToAttachStoragePool.getId(), DataStoreRole.Primary);
+
+        boolean queryForChap = true;
+
+        if (host != null) {
+            try {
+                // if connectVolumeToHost returns true, then we do not want to use CHAP because the volume is already connected to the host(s)
+                queryForChap = !volService.connectVolumeToHost(volFactory.getVolume(volumeToAttach.getId()), host, dataStore);
+            }
+            catch (Exception e) {
+                volService.disconnectVolumeFromHost(volFactory.getVolume(volumeToAttach.getId()), host, dataStore);
+
+                throw new CloudRuntimeException(e.getMessage());
+            }
+        }
+
         if (sendCommand) {
             if (host.getHypervisorType() == HypervisorType.KVM &&
                 volumeToAttachStoragePool.isManaged() &&
@@ -1963,9 +1985,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
 
             AttachCommand cmd = new AttachCommand(disk, vm.getInstanceName());
 
-            VolumeInfo volumeInfo = volFactory.getVolume(volumeToAttach.getId());
-            DataStore dataStore = dataStoreMgr.getDataStore(volumeToAttachStoragePool.getId(), DataStoreRole.Primary);
-            ChapInfo chapInfo = volService.getChapInfo(volumeInfo, dataStore);
+            ChapInfo chapInfo = queryForChap ? volService.getChapInfo(volFactory.getVolume(volumeToAttach.getId()), dataStore) : null;
 
             Map<String, String> details = new HashMap<String, String>();
 
@@ -1987,6 +2007,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
             try {
                 answer = (AttachAnswer)_agentMgr.send(hostId, cmd);
             } catch (Exception e) {
+                volService.disconnectVolumeFromHost(volFactory.getVolume(volumeToAttach.getId()), host, dataStore);
+
                 throw new CloudRuntimeException(errorMsg + " due to: " + e.getMessage());
             }
         }
@@ -2023,6 +2045,9 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
                     errorMsg += "; " + details;
                 }
             }
+
+            volService.disconnectVolumeFromHost(volFactory.getVolume(volumeToAttach.getId()), host, dataStore);
+
             throw new CloudRuntimeException(errorMsg);
         }
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ae35782c/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostMO.java
----------------------------------------------------------------------
diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostMO.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostMO.java
index 1b2a102..b306b0c 100755
--- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostMO.java
+++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostMO.java
@@ -698,7 +698,9 @@ public class HostMO extends BaseMO implements VmwareHypervisorHost {
                     ManagedObjectReference morDs = oc.getObj();
                     String name = (String)VmwareHelper.getPropValue(oc, "name");
 
-                    dsList.add(new Pair<ManagedObjectReference, String>(morDs, name));
+                    if (!name.startsWith("-iqn.")) {
+                        dsList.add(new Pair<ManagedObjectReference, String>(morDs, name));
+                    }
                 }
             }
         }