cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mtutkow...@apache.org
Subject git commit: updated refs/heads/4.3 to 574fc3a
Date Fri, 27 Dec 2013 20:13:22 GMT
Updated Branches:
  refs/heads/4.3 8cf154d55 -> 574fc3a4f


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/574fc3a4
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/574fc3a4
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/574fc3a4

Branch: refs/heads/4.3
Commit: 574fc3a4f8fa5927b488f817f99ff33a91eccd10
Parents: 8cf154d
Author: Mike Tutkowski <mike.tutkowski@solidfire.com>
Authored: Mon Dec 23 20:28:07 2013 -0700
Committer: Mike Tutkowski <mike.tutkowski@solidfire.com>
Committed: Fri Dec 27 13:12:12 2013 -0700

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


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/574fc3a4/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 581bd47..9a20f62 100755
--- a/api/src/com/cloud/host/Host.java
+++ b/api/src/com/cloud/host/Host.java
@@ -92,6 +92,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/574fc3a4/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 031ef5c..e8090db 100644
--- a/core/test/org/apache/cloudstack/api/agent/test/CheckOnHostCommandTest.java
+++ b/core/test/org/apache/cloudstack/api/agent/test/CheckOnHostCommandTest.java
@@ -76,6 +76,10 @@ public class CheckOnHostCommandTest {
             return "10.1.1.1";
         };
 
+        public String getStorageUrl() {
+            return null;
+        }
+
         public String getStorageIpAddress() {
             return "10.1.1.2";
         };

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/574fc3a4/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 6c353d9..36091e0 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
@@ -18,14 +18,19 @@
  */
 package org.apache.cloudstack.engine.subsystem.api.storage;
 
+import java.util.List;
+
 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);
     public void revertSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CommandResult> callback);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/574fc3a4/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 7515088..bdd4a17 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
@@ -19,6 +19,7 @@
 package org.apache.cloudstack.engine.subsystem.api.storage;
 
 import java.util.Map;
+import java.util.List;
 
 import org.apache.cloudstack.engine.cloud.entity.api.VolumeEntity;
 import org.apache.cloudstack.framework.async.AsyncCallFuture;
@@ -44,6 +45,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/574fc3a4/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 72373e2..399d2d1 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
@@ -18,6 +18,8 @@
  */
 package org.apache.cloudstack.storage.test;
 
+import java.util.List;
+import java.util.Map;
 import java.util.UUID;
 
 import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo;
@@ -35,17 +37,30 @@ 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;
 
 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/574fc3a4/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 3cef23d..b9dbd92 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
@@ -159,6 +159,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/574fc3a4/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 ee802d2..45803b5 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
@@ -4808,22 +4808,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>();
 
@@ -6062,11 +6066,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/574fc3a4/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 ed32a9a..f1690fd 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
@@ -19,6 +19,7 @@
 package org.apache.cloudstack.storage.datastore.driver;
 
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
@@ -52,6 +53,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.dao.DiskOfferingDao;
 import com.cloud.storage.dao.SnapshotDao;
@@ -131,6 +133,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/574fc3a4/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 67e0a71..82694e7 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
@@ -40,12 +40,14 @@ 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;
 import com.cloud.utils.exception.CloudRuntimeException;
 
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 public class SamplePrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver {
@@ -82,6 +84,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/574fc3a4/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 7534ce4..ff3e33b 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,9 +17,10 @@
 package org.apache.cloudstack.storage.datastore.driver;
 
 import java.text.NumberFormat;
-import java.util.HashMap;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.UUID;
 
 import javax.inject.Inject;
 
@@ -37,7 +38,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;
@@ -48,6 +54,7 @@ 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;
@@ -57,6 +64,8 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
     @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() {
@@ -139,35 +148,35 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
     }
 
     private void updateCsDbWithAccountInfo(long csAccountId, SolidFireUtil.SolidFireAccount sfAccount) {
-        AccountDetailVO accountDetails = new AccountDetailVO(csAccountId,
+        AccountDetailVO accountDetail = new AccountDetailVO(csAccountId,
                 SolidFireUtil.ACCOUNT_ID,
                 String.valueOf(sfAccount.getId()));
 
-        _accountDetailsDao.persist(accountDetails);
+        _accountDetailsDao.persist(accountDetail);
 
-        accountDetails = new AccountDetailVO(csAccountId,
+        accountDetail = new AccountDetailVO(csAccountId,
                 SolidFireUtil.CHAP_INITIATOR_USERNAME,
                 String.valueOf(sfAccount.getName()));
 
-        _accountDetailsDao.persist(accountDetails);
+        _accountDetailsDao.persist(accountDetail);
 
-        accountDetails = new AccountDetailVO(csAccountId,
+        accountDetail = new AccountDetailVO(csAccountId,
                 SolidFireUtil.CHAP_INITIATOR_SECRET,
                 String.valueOf(sfAccount.getInitiatorSecret()));
 
-        _accountDetailsDao.persist(accountDetails);
+        _accountDetailsDao.persist(accountDetail);
 
-        accountDetails = new AccountDetailVO(csAccountId,
+        accountDetail = new AccountDetailVO(csAccountId,
                 SolidFireUtil.CHAP_TARGET_USERNAME,
                 sfAccount.getName());
 
-        _accountDetailsDao.persist(accountDetails);
+        _accountDetailsDao.persist(accountDetail);
 
-        accountDetails = new AccountDetailVO(csAccountId,
+        accountDetail = new AccountDetailVO(csAccountId,
                 SolidFireUtil.CHAP_TARGET_SECRET,
                 sfAccount.getTargetSecret());
 
-        _accountDetailsDao.persist(accountDetails);
+        _accountDetailsDao.persist(accountDetail);
     }
 
     private class ChapInfoImpl implements ChapInfo {
@@ -225,8 +234,180 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
 
         String chapTargetSecret = accountDetail.getValue();
 
-        return new ChapInfoImpl(chapInitiatorUsername, chapInitiatorSecret,
-                chapTargetUsername, chapTargetSecret);
+        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) {
@@ -462,6 +643,7 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
         callback.complete(result);
     }
 
+    /*
     private void deleteSolidFireAccount(long sfAccountId, SolidFireConnection sfConnection) {
         String mVip = sfConnection.getManagementVip();
         int mPort = sfConnection.getManagementPort();
@@ -502,10 +684,10 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
 
         return false;
     }
+    */
 
     @Override
-    public void deleteAsync(DataStore dataStore, DataObject dataObject,
-            AsyncCompletionCallback<CommandResult> callback) {
+    public void deleteAsync(DataStore dataStore, DataObject dataObject, AsyncCompletionCallback<CommandResult> callback) {
         String errMsg = null;
 
         if (dataObject.getType() == DataObjectType.VOLUME) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/574fc3a4/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 c3e3025..a372497 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,6 @@ public class SolidFireUtil
         return volumeCreateResult.result.volumeID;
     }
 
-    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);
-    }
-
     public static SolidFireVolume getSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId)
     {
         final Gson gson = new GsonBuilder().create();
@@ -167,9 +141,59 @@ 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();
 
-	private static final String ACTIVE = "active";
+        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
     {
@@ -250,7 +274,7 @@ public class SolidFireUtil
 
             return false;
         }
-	}
+    }
 
     public static long createSolidFireAccount(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword,
             String strAccountName)
@@ -270,18 +294,6 @@ 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)
     {
@@ -326,6 +338,18 @@ public class SolidFireUtil
         return new SolidFireAccount(lSfAccountId, strSfAccountName, strSfAccountInitiatorSecret, strSfAccountTargetSecret);
     }
 
+    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;
@@ -382,56 +406,65 @@ public class SolidFireUtil
             }
 
             SolidFireAccount sfa = (SolidFireAccount)obj;
-            
+
             if (_id == sfa._id && _name.equals(sfa._name) &&
                 _initiatorSecret.equals(sfa._initiatorSecret) &&
                 _targetSecret.equals(sfa._targetSecret)) {
                 return true;
             }
-            
+
             return false;
         }
     }
 
-    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);
 
-        List<SolidFireVolume> deletedVolumes = new ArrayList<SolidFireVolume> ();
+        return vagCreateResult.result.volumeAccessGroupID;
+    }
 
-        for (VolumeGetResult.Result.Volume volume : volumeGetResult.result.volumes) {
-            deletedVolumes.add(new SolidFireVolume(volume.volumeID, volume.name, volume.iqn, volume.accountID, volume.status, volume.totalSize));
-        }
+    public static void modifySolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVagId,
+            String[] iqns, long[] volumeIds)
+    {
+        final Gson gson = new GsonBuilder().create();
 
-        return deletedVolumes;
+        VagToModify vagToModify = new VagToModify(lVagId, iqns, volumeIds);
+
+        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)
@@ -445,6 +478,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
     {
@@ -506,6 +597,57 @@ public class SolidFireUtil
     }
 
     @SuppressWarnings("unused")
+    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";
@@ -528,12 +670,6 @@ public class SolidFireUtil
     }
 
     @SuppressWarnings("unused")
-    private static final class ListDeletedVolumes
-    {
-        private final String method = "ListDeletedVolumes";
-    }
-
-    @SuppressWarnings("unused")
     private static final class VolumeToPurge
     {
         private final String method = "PurgeDeletedVolume";
@@ -556,44 +692,43 @@ public class SolidFireUtil
     }
 
     @SuppressWarnings("unused")
-    private static final class VolumeToGet
+    private static final class AccountToAdd
     {
-        private final String method = "ListActiveVolumes";
-        private final VolumeToGetParams params;
+        private final String method = "AddAccount";
+        private final AccountToAddParams params;
 
-        private VolumeToGet(final long lVolumeId)
+        private AccountToAdd(final String strAccountName)
         {
-            params = new VolumeToGetParams(lVolumeId);
+            params = new AccountToAddParams(strAccountName);
         }
 
-        private static final class VolumeToGetParams
+        private static final class AccountToAddParams
         {
-            private final long startVolumeID;
-            private final long limit = 1;
+            private final String username;
 
-            private VolumeToGetParams(final long lVolumeId)
+            private AccountToAddParams(final String strAccountName)
             {
-                startVolumeID = lVolumeId;
+                username = strAccountName;
             }
         }
     }
 
     @SuppressWarnings("unused")
-    private static final class VolumesToGetForAccount
+    private static final class AccountToGetById
     {
-        private final String method = "ListVolumesForAccount";
-        private final VolumesToGetForAccountParams params;
+        private final String method = "GetAccountByID";
+        private final AccountToGetByIdParams params;
 
-        private VolumesToGetForAccount(final long lAccountId)
+        private AccountToGetById(final long lAccountId)
         {
-            params = new VolumesToGetForAccountParams(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;
             }
@@ -601,23 +736,23 @@ public class SolidFireUtil
     }
 
     @SuppressWarnings("unused")
-    private static final class AccountToAdd
+    private static final class AccountToGetByName
     {
-        private final String method = "AddAccount";
-        private final AccountToAddParams params;
+        private final String method = "GetAccountByName";
+        private final AccountToGetByNameParams params;
 
-        private AccountToAdd(final String strAccountName)
+        private AccountToGetByName(final String strUsername)
         {
-            params = new AccountToAddParams(strAccountName);
+            params = new AccountToGetByNameParams(strUsername);
         }
 
-        private static final class AccountToAddParams
+        private static final class AccountToGetByNameParams
         {
             private final String username;
 
-            private AccountToAddParams(final String strAccountName)
+            private AccountToGetByNameParams(final String strUsername)
             {
-                username = strAccountName;
+                username = strUsername;
             }
         }
     }
@@ -645,67 +780,76 @@ public class SolidFireUtil
     }
 
     @SuppressWarnings("unused")
-    private static final class AccountToGetById
+    private static final class VagToCreate
     {
-        private final String method = "GetAccountByID";
-        private final AccountToGetByIdParams params;
+        private final String method = "CreateVolumeAccessGroup";
+        private final VagToCreateParams params;
 
-        private AccountToGetById(final long lAccountId)
+        private VagToCreate(final String strVagName, final String[] iqns, final long[] volumeIds)
         {
-            params = new AccountToGetByIdParams(lAccountId);
+            params = new VagToCreateParams(strVagName, iqns, volumeIds);
         }
 
-        private static final class AccountToGetByIdParams
+        private static final class VagToCreateParams
         {
-            private final long accountID;
+            private final String name;
+            private final String[] initiators;
+            private final long[] volumes;
 
-            private AccountToGetByIdParams(final long lAccountId)
+            private VagToCreateParams(final String strVagName, final String[] iqns, final long[] volumeIds)
             {
-                accountID = lAccountId;
+                name = strVagName;
+                initiators = iqns;
+                volumes = volumeIds;
             }
         }
     }
 
     @SuppressWarnings("unused")
-    private static final class AccountToGetByName
+    private static final class VagToModify
     {
-        private final String method = "GetAccountByName";
-        private final AccountToGetByNameParams params;
+        private final String method = "ModifyVolumeAccessGroup";
+        private final VagToModifyParams params;
 
-        private AccountToGetByName(final String strUsername)
+        private VagToModify(final long lVagName, final String[] iqns, final long[] volumeIds)
         {
-            params = new AccountToGetByNameParams(strUsername);
+            params = new VagToModifyParams(lVagName, iqns, volumeIds);
         }
 
-        private static final class AccountToGetByNameParams
+        private static final class VagToModifyParams
         {
-            private final String username;
+            private final long volumeAccessGroupID;
+            private final String[] initiators;
+            private final long[] volumes;
 
-            private AccountToGetByNameParams(final String strUsername)
+            private VagToModifyParams(final long lVagName, final String[] iqns, final long[] volumeIds)
             {
-                username = strUsername;
+                volumeAccessGroupID = lVagName;
+                initiators = iqns;
+                volumes = volumeIds;
             }
         }
     }
 
     @SuppressWarnings("unused")
-    private static final class VagToCreate
+    private static final class VagToGet
     {
-        private final String method = "CreateVolumeAccessGroup";
-        private final VagToCreateParams params;
+        private final String method = "ListVolumeAccessGroups";
+        private final VagToGetParams params;
 
-        private VagToCreate(final String strVagName)
+        private VagToGet(final long lVagId)
         {
-            params = new VagToCreateParams(strVagName);
+            params = new VagToGetParams(lVagId);
         }
 
-        private static final class VagToCreateParams
+        private static final class VagToGetParams
         {
-            private final String name;
+            private final long startVolumeAccessGroupID;
+            private final long limit = 1;
 
-            private VagToCreateParams(final String strVagName)
+            private VagToGetParams(final long lVagId)
             {
-                name = strVagName;
+                startVolumeAccessGroupID = lVagId;
             }
         }
     }
@@ -800,6 +944,23 @@ public class SolidFireUtil
         }
     }
 
+    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;
@@ -859,7 +1020,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);
 
@@ -983,4 +1144,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/574fc3a4/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 1d1c2b1..90038e7 100644
--- a/server/src/com/cloud/storage/VolumeApiServiceImpl.java
+++ b/server/src/com/cloud/storage/VolumeApiServiceImpl.java
@@ -1439,8 +1439,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();
 
@@ -1454,10 +1454,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;
@@ -1486,10 +1487,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 {
 
@@ -1871,13 +1876,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) {
@@ -1896,6 +1902,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() &&
@@ -1910,9 +1932,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>();
 
@@ -1934,6 +1954,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());
             }
         }
@@ -1970,6 +1992,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/574fc3a4/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 c4836a8..7ef8326 100755
--- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostMO.java
+++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostMO.java
@@ -718,7 +718,10 @@ 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));
+					// "-iqn." is an identifier we use to note a CloudStack-managed datastore that should never be added to CloudStack as primary storage
+					if (!name.startsWith("-iqn.")) {
+					    dsList.add(new Pair<ManagedObjectReference, String>(morDs, name));
+					}
 				}
 			}
 		}


Mime
View raw message