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/06/16 20:15:57 UTC

[1/2] SolidFire (shared-access) Provider

Repository: cloudstack
Updated Branches:
  refs/heads/master 520ff0008 -> 42d00cae5


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42d00cae/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java
new file mode 100644
index 0000000..ec2a52f
--- /dev/null
+++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java
@@ -0,0 +1,548 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cloudstack.storage.datastore.lifecycle;
+
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+
+import javax.inject.Inject;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
+import org.apache.cloudstack.engine.subsystem.api.storage.HostScope;
+import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo;
+import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCycle;
+import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreParameters;
+import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
+import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
+import org.apache.cloudstack.storage.datastore.util.SolidFireUtil;
+import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper;
+
+import com.cloud.template.TemplateManager;
+import com.cloud.user.AccountDetailsDao;
+import com.cloud.user.AccountVO;
+import com.cloud.agent.AgentManager;
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.CreateStoragePoolCommand;
+import com.cloud.agent.api.DeleteStoragePoolCommand;
+import com.cloud.agent.api.StoragePoolInfo;
+import com.cloud.dc.ClusterDetailsDao;
+import com.cloud.dc.ClusterVO;
+import com.cloud.dc.dao.ClusterDao;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.host.dao.HostDao;
+import com.cloud.host.Host;
+import com.cloud.host.HostVO;
+import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.resource.ResourceManager;
+import com.cloud.storage.Storage.StoragePoolType;
+import com.cloud.storage.dao.StoragePoolHostDao;
+import com.cloud.storage.StorageManager;
+import com.cloud.storage.StoragePool;
+import com.cloud.storage.StoragePoolAutomation;
+import com.cloud.storage.StoragePoolHostVO;
+import com.cloud.storage.VMTemplateStoragePoolVO;
+import com.cloud.user.Account;
+import com.cloud.user.dao.AccountDao;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeCycle {
+    private static final Logger s_logger = Logger.getLogger(SolidFireSharedPrimaryDataStoreLifeCycle.class);
+
+    @Inject private AccountDao _accountDao;
+    @Inject private AccountDetailsDao _accountDetailsDao;
+    @Inject private AgentManager _agentMgr;
+    @Inject private ClusterDao _clusterDao;
+    @Inject private ClusterDetailsDao _clusterDetailsDao;
+    @Inject private DataCenterDao _zoneDao;
+    @Inject private HostDao _hostDao;
+    @Inject private PrimaryDataStoreDao _primaryDataStoreDao;
+    @Inject private PrimaryDataStoreHelper _primaryDataStoreHelper;
+    @Inject private ResourceManager _resourceMgr;
+    @Inject private StorageManager _storageMgr;
+    @Inject private StoragePoolAutomation _storagePoolAutomation;
+    @Inject private StoragePoolDetailsDao _storagePoolDetailsDao;
+    @Inject private StoragePoolHostDao _storagePoolHostDao;
+    @Inject protected TemplateManager _tmpltMgr;
+
+    // invoked to add primary storage that is based on the SolidFire plug-in
+    @Override
+    public DataStore initialize(Map<String, Object> dsInfos) {
+        final String CAPACITY_IOPS = "capacityIops";
+
+        String url = (String)dsInfos.get("url");
+        Long zoneId = (Long)dsInfos.get("zoneId");
+        Long podId = (Long)dsInfos.get("podId");
+        Long clusterId = (Long)dsInfos.get("clusterId");
+        String storagePoolName = (String)dsInfos.get("name");
+        String providerName = (String)dsInfos.get("providerName");
+        Long capacityBytes = (Long)dsInfos.get("capacityBytes");
+        Long capacityIops = (Long)dsInfos.get(CAPACITY_IOPS);
+        String tags = (String)dsInfos.get("tags");
+        @SuppressWarnings("unchecked")
+        Map<String, String> details = (Map<String, String>)dsInfos.get("details");
+
+        if (podId == null) {
+            throw new CloudRuntimeException("The Pod ID must be specified.");
+        }
+
+        if (clusterId == null) {
+            throw new CloudRuntimeException("The Cluster ID must be specified.");
+        }
+
+        String storageVip = SolidFireUtil.getStorageVip(url);
+        int storagePort = SolidFireUtil.getStoragePort(url);
+
+        if (capacityBytes == null || capacityBytes <= 0) {
+            throw new IllegalArgumentException("'capacityBytes' must be present and greater than 0.");
+        }
+
+        if (capacityIops == null || capacityIops <= 0) {
+            throw new IllegalArgumentException("'capacityIops' must be present and greater than 0.");
+        }
+
+        HypervisorType hypervisorType = getHypervisorTypeForCluster(clusterId);
+
+        if (!isSupportedHypervisorType(hypervisorType)) {
+            throw new CloudRuntimeException(hypervisorType + " is not a supported hypervisor type.");
+        }
+
+        String datacenter = SolidFireUtil.getValue(SolidFireUtil.DATACENTER, url, false);
+
+        if (HypervisorType.VMware.equals(hypervisorType) && datacenter == null) {
+            throw new CloudRuntimeException("'Datacenter' must be set for hypervisor type of " + HypervisorType.VMware);
+        }
+
+        PrimaryDataStoreParameters parameters = new PrimaryDataStoreParameters();
+
+        parameters.setType(getStorageType(hypervisorType));
+        parameters.setZoneId(zoneId);
+        parameters.setPodId(podId);
+        parameters.setClusterId(clusterId);
+        parameters.setName(storagePoolName);
+        parameters.setProviderName(providerName);
+        parameters.setManaged(false);
+        parameters.setCapacityBytes(capacityBytes);
+        parameters.setUsedBytes(0);
+        parameters.setCapacityIops(capacityIops);
+        parameters.setHypervisorType(hypervisorType);
+        parameters.setTags(tags);
+        parameters.setDetails(details);
+
+        String managementVip = SolidFireUtil.getManagementVip(url);
+        int managementPort = SolidFireUtil.getManagementPort(url);
+
+        details.put(SolidFireUtil.MANAGEMENT_VIP, managementVip);
+        details.put(SolidFireUtil.MANAGEMENT_PORT, String.valueOf(managementPort));
+
+        String clusterAdminUsername = SolidFireUtil.getValue(SolidFireUtil.CLUSTER_ADMIN_USERNAME, url);
+        String clusterAdminPassword = SolidFireUtil.getValue(SolidFireUtil.CLUSTER_ADMIN_PASSWORD, url);
+
+        details.put(SolidFireUtil.CLUSTER_ADMIN_USERNAME, clusterAdminUsername);
+        details.put(SolidFireUtil.CLUSTER_ADMIN_PASSWORD, clusterAdminPassword);
+
+        long lMinIops = 100;
+        long lMaxIops = 15000;
+        long lBurstIops = 15000;
+
+        try {
+            String minIops = SolidFireUtil.getValue(SolidFireUtil.MIN_IOPS, url);
+
+            if (minIops != null && minIops.trim().length() > 0) {
+                lMinIops = Long.parseLong(minIops);
+            }
+        } catch (Exception ex) {
+        }
+
+        try {
+            String maxIops = SolidFireUtil.getValue(SolidFireUtil.MAX_IOPS, url);
+
+            if (maxIops != null && maxIops.trim().length() > 0) {
+                lMaxIops = Long.parseLong(maxIops);
+            }
+        } catch (Exception ex) {
+        }
+
+        try {
+            String burstIops = SolidFireUtil.getValue(SolidFireUtil.BURST_IOPS, url);
+
+            if (burstIops != null && burstIops.trim().length() > 0) {
+                lBurstIops = Long.parseLong(burstIops);
+            }
+        } catch (Exception ex) {
+        }
+
+        if (lMinIops > lMaxIops) {
+            throw new CloudRuntimeException("The parameter '" + SolidFireUtil.MIN_IOPS + "' must be less than or equal to the parameter '" + SolidFireUtil.MAX_IOPS + "'.");
+        }
+
+        if (lMaxIops > lBurstIops) {
+            throw new CloudRuntimeException("The parameter '" + SolidFireUtil.MAX_IOPS + "' must be less than or equal to the parameter '" + SolidFireUtil.BURST_IOPS + "'.");
+        }
+
+        if (lMinIops != capacityIops) {
+            throw new CloudRuntimeException("The parameter '" + CAPACITY_IOPS + "' must be equal to the parameter '" + SolidFireUtil.MIN_IOPS + "'.");
+        }
+
+        details.put(SolidFireUtil.MIN_IOPS, String.valueOf(lMinIops));
+        details.put(SolidFireUtil.MAX_IOPS, String.valueOf(lMaxIops));
+        details.put(SolidFireUtil.BURST_IOPS, String.valueOf(lBurstIops));
+
+        SolidFireUtil.SolidFireConnection sfConnection = new SolidFireUtil.SolidFireConnection(managementVip, managementPort, clusterAdminUsername, clusterAdminPassword);
+
+        SolidFireUtil.SolidFireVolume sfVolume = createSolidFireVolume(sfConnection, storagePoolName, capacityBytes, lMinIops, lMaxIops, lBurstIops);
+
+        String iqn = sfVolume.getIqn();
+
+        details.put(SolidFireUtil.VOLUME_ID, String.valueOf(sfVolume.getId()));
+
+        parameters.setUuid(iqn);
+
+        if (HypervisorType.VMware.equals(hypervisorType)) {
+            String datastore = iqn.replace("/", "_");
+            String path = "/" + datacenter + "/" + datastore;
+
+            parameters.setHost("VMFS datastore: " + path);
+            parameters.setPort(0);
+            parameters.setPath(path);
+
+            details.put(SolidFireUtil.DATASTORE_NAME, datastore);
+            details.put(SolidFireUtil.IQN, iqn);
+            details.put(SolidFireUtil.STORAGE_VIP, storageVip);
+            details.put(SolidFireUtil.STORAGE_PORT, String.valueOf(storagePort));
+        }
+        else {
+            parameters.setHost(storageVip);
+            parameters.setPort(storagePort);
+            parameters.setPath(iqn);
+        }
+
+        // this adds a row in the cloud.storage_pool table for this SolidFire volume
+        DataStore dataStore = _primaryDataStoreHelper.createPrimaryDataStore(parameters);
+
+        // now that we have a DataStore (we need the id from the DataStore instance), we can create a Volume Access Group, if need be, and
+        // place the newly created volume in the Volume Access Group
+        try {
+            List<HostVO> hosts = _hostDao.findByClusterId(clusterId);
+
+            SolidFireUtil.placeVolumeInVolumeAccessGroup(sfConnection, sfVolume.getId(), dataStore.getId(), hosts, _clusterDetailsDao);
+        } catch (Exception ex) {
+            _primaryDataStoreDao.expunge(dataStore.getId());
+
+            throw new CloudRuntimeException(ex.getMessage());
+        }
+
+        return dataStore;
+    }
+
+    private HypervisorType getHypervisorTypeForCluster(long clusterId) {
+        ClusterVO cluster = _clusterDao.findById(clusterId);
+
+        if (cluster == null) {
+            throw new CloudRuntimeException("Cluster ID '" + clusterId + "' was not found in the database.");
+        }
+
+        return cluster.getHypervisorType();
+    }
+
+    private StoragePoolType getStorageType(HypervisorType hypervisorType) {
+        if (HypervisorType.XenServer.equals(hypervisorType)) {
+            return StoragePoolType.IscsiLUN;
+        }
+
+        if (HypervisorType.VMware.equals(hypervisorType)) {
+            return StoragePoolType.VMFS;
+        }
+
+        throw new CloudRuntimeException("The 'hypervisor' parameter must be '" + HypervisorType.XenServer + "' or '" + HypervisorType.VMware + "'.");
+    }
+
+    private SolidFireUtil.SolidFireVolume createSolidFireVolume(SolidFireUtil.SolidFireConnection sfConnection,
+            String volumeName, long volumeSize, long minIops, long maxIops, long burstIops) {
+        try {
+            Account csAccount = CallContext.current().getCallingAccount();
+            long csAccountId = csAccount.getId();
+            AccountVO accountVo = _accountDao.findById(csAccountId);
+
+            String sfAccountName = SolidFireUtil.getSolidFireAccountName(accountVo.getUuid(), csAccountId);
+
+            SolidFireUtil.SolidFireAccount sfAccount = SolidFireUtil.getSolidFireAccount(sfConnection, sfAccountName);
+
+            if (sfAccount == null) {
+                long accountNumber = SolidFireUtil.createSolidFireAccount(sfConnection, sfAccountName);
+
+                sfAccount = SolidFireUtil.getSolidFireAccountById(sfConnection, accountNumber);
+
+                SolidFireUtil.updateCsDbWithSolidFireAccountInfo(csAccountId, sfAccount, _accountDetailsDao);
+            }
+
+            long sfVolumeId = SolidFireUtil.createSolidFireVolume(sfConnection, SolidFireUtil.getSolidFireVolumeName(volumeName), sfAccount.getId(), volumeSize,
+                    true, NumberFormat.getInstance().format(volumeSize), minIops, maxIops, burstIops);
+            SolidFireUtil.SolidFireVolume sfVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfVolumeId);
+
+            return sfVolume;
+        } catch (Throwable e) {
+            throw new CloudRuntimeException("Failed to create a SolidFire volume: " + e.toString());
+        }
+    }
+
+    @Override
+    public boolean attachHost(DataStore store, HostScope scope, StoragePoolInfo existingInfo) {
+        return true;
+    }
+
+    @Override
+    public boolean attachCluster(DataStore store, ClusterScope scope) {
+        PrimaryDataStoreInfo primaryDataStoreInfo = (PrimaryDataStoreInfo)store;
+
+        // check if there is at least one host up in this cluster
+        List<HostVO> allHosts = _resourceMgr.listAllUpAndEnabledHosts(Host.Type.Routing, primaryDataStoreInfo.getClusterId(),
+                primaryDataStoreInfo.getPodId(), primaryDataStoreInfo.getDataCenterId());
+
+        if (allHosts.isEmpty()) {
+            _primaryDataStoreDao.expunge(primaryDataStoreInfo.getId());
+
+            throw new CloudRuntimeException("No host up to associate a storage pool with in cluster " + primaryDataStoreInfo.getClusterId());
+        }
+
+        boolean success = false;
+
+        for (HostVO host : allHosts) {
+            success = createStoragePool(host, primaryDataStoreInfo);
+
+            if (success) {
+                break;
+            }
+        }
+
+        if (!success) {
+            throw new CloudRuntimeException("Unable to create storage in cluster " + primaryDataStoreInfo.getClusterId());
+        }
+
+        List<HostVO> poolHosts = new ArrayList<HostVO>();
+
+        for (HostVO host : allHosts) {
+            try {
+                _storageMgr.connectHostToSharedPool(host.getId(), primaryDataStoreInfo.getId());
+
+                poolHosts.add(host);
+            } catch (Exception e) {
+                s_logger.warn("Unable to establish a connection between " + host + " and " + primaryDataStoreInfo, e);
+            }
+        }
+
+        if (poolHosts.isEmpty()) {
+            s_logger.warn("No host can access storage pool '" + primaryDataStoreInfo + "' on cluster '" + primaryDataStoreInfo.getClusterId() + "'.");
+
+            _primaryDataStoreDao.expunge(primaryDataStoreInfo.getId());
+
+            throw new CloudRuntimeException("Failed to access storage pool");
+        }
+
+        _primaryDataStoreHelper.attachCluster(store);
+
+        return true;
+    }
+
+    private boolean createStoragePool(HostVO host, StoragePool storagePool) {
+        long hostId = host.getId();
+        HypervisorType hypervisorType = host.getHypervisorType();
+        CreateStoragePoolCommand cmd = new CreateStoragePoolCommand(true, storagePool);
+
+        if (HypervisorType.VMware.equals(hypervisorType)) {
+            cmd.setCreateDatastore(true);
+
+            Map<String, String> details = new HashMap<String, String>();
+
+            StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.DATASTORE_NAME);
+
+            details.put(CreateStoragePoolCommand.DATASTORE_NAME, storagePoolDetail.getValue());
+
+            storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.IQN);
+
+            details.put(CreateStoragePoolCommand.IQN, storagePoolDetail.getValue());
+
+            storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.STORAGE_VIP);
+
+            details.put(CreateStoragePoolCommand.STORAGE_HOST, storagePoolDetail.getValue());
+
+            storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.STORAGE_PORT);
+
+            details.put(CreateStoragePoolCommand.STORAGE_PORT, storagePoolDetail.getValue());
+
+            cmd.setDetails(details);
+        }
+
+        Answer answer = _agentMgr.easySend(hostId, cmd);
+
+        if (answer != null && answer.getResult()) {
+            return true;
+        } else {
+            _primaryDataStoreDao.expunge(storagePool.getId());
+
+            String msg = "";
+
+            if (answer != null) {
+                msg = "Cannot create storage pool through host '" + hostId + "' due to the following: " + answer.getDetails();
+            } else {
+                msg = "Cannot create storage pool through host '" + hostId + "' due to CreateStoragePoolCommand returns null";
+            }
+
+            s_logger.warn(msg);
+
+            throw new CloudRuntimeException(msg);
+        }
+    }
+
+    @Override
+    public boolean attachZone(DataStore dataStore, ZoneScope scope, HypervisorType hypervisorType) {
+        return true;
+    }
+
+    @Override
+    public boolean maintain(DataStore dataStore) {
+        _storagePoolAutomation.maintain(dataStore);
+        _primaryDataStoreHelper.maintain(dataStore);
+
+        return true;
+    }
+
+    @Override
+    public boolean cancelMaintain(DataStore store) {
+        _primaryDataStoreHelper.cancelMaintain(store);
+        _storagePoolAutomation.cancelMaintain(store);
+
+        return true;
+    }
+
+    // invoked to delete primary storage that is based on the SolidFire plug-in
+    @Override
+    public boolean deleteDataStore(DataStore dataStore) {
+        List<StoragePoolHostVO> hostPoolRecords = _storagePoolHostDao.listByPoolId(dataStore.getId());
+
+        HypervisorType hypervisorType = null;
+
+        if (hostPoolRecords.size() > 0 ) {
+            hypervisorType = getHypervisorType(hostPoolRecords.get(0).getHostId());
+        }
+
+        if (!isSupportedHypervisorType(hypervisorType)) {
+            throw new CloudRuntimeException(hypervisorType + " is not a supported hypervisor type.");
+        }
+
+        StoragePool storagePool = (StoragePool)dataStore;
+        StoragePoolVO storagePoolVO = _primaryDataStoreDao.findById(storagePool.getId());
+        List<VMTemplateStoragePoolVO> unusedTemplatesInPool = _tmpltMgr.getUnusedTemplatesInPool(storagePoolVO);
+
+        for (VMTemplateStoragePoolVO templatePoolVO : unusedTemplatesInPool) {
+            _tmpltMgr.evictTemplateFromStoragePool(templatePoolVO);
+        }
+
+        for (StoragePoolHostVO host : hostPoolRecords) {
+            DeleteStoragePoolCommand deleteCmd = new DeleteStoragePoolCommand(storagePool);
+
+            if (HypervisorType.VMware.equals(hypervisorType)) {
+                deleteCmd.setRemoveDatastore(true);
+
+                Map<String, String> details = new HashMap<String, String>();
+
+                StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.DATASTORE_NAME);
+
+                details.put(DeleteStoragePoolCommand.DATASTORE_NAME, storagePoolDetail.getValue());
+
+                storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.IQN);
+
+                details.put(DeleteStoragePoolCommand.IQN, storagePoolDetail.getValue());
+
+                storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.STORAGE_VIP);
+
+                details.put(DeleteStoragePoolCommand.STORAGE_HOST, storagePoolDetail.getValue());
+
+                storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.STORAGE_PORT);
+
+                details.put(DeleteStoragePoolCommand.STORAGE_PORT, storagePoolDetail.getValue());
+
+                deleteCmd.setDetails(details);
+            }
+
+            final Answer answer = _agentMgr.easySend(host.getHostId(), deleteCmd);
+
+            if (answer != null && answer.getResult()) {
+                s_logger.info("Successfully deleted storage pool using Host ID " + host.getHostId());
+
+                break;
+            }
+            else {
+                s_logger.error("Failed to delete storage pool using Host ID " + host.getHostId() + ": " + answer.getResult());
+            }
+        }
+
+        deleteSolidFireVolume(storagePool.getId());
+
+        return _primaryDataStoreHelper.deletePrimaryDataStore(dataStore);
+    }
+
+    private void deleteSolidFireVolume(long storagePoolId) {
+        SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
+
+        long sfVolumeId = getVolumeId(storagePoolId);
+
+        SolidFireUtil.deleteSolidFireVolume(sfConnection, sfVolumeId);
+    }
+
+    private long getVolumeId(long storagePoolId) {
+        StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.VOLUME_ID);
+
+        String volumeId = storagePoolDetail.getValue();
+
+        return Long.parseLong(volumeId);
+    }
+
+    private static boolean isSupportedHypervisorType(HypervisorType hypervisorType) {
+        return HypervisorType.XenServer.equals(hypervisorType) || HypervisorType.VMware.equals(hypervisorType);
+    }
+
+    private HypervisorType getHypervisorType(long hostId) {
+        HostVO host = _hostDao.findById(hostId);
+
+        if (host != null) {
+            return host.getHypervisorType();
+        }
+
+        return HypervisorType.None;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.cloudstack.engine.subsystem.api.storage.DataStoreLifeCycle#migrateToObjectStore(org.apache.cloudstack.engine.subsystem.api.storage.DataStore)
+     */
+    @Override
+    public boolean migrateToObjectStore(DataStore store) {
+        return false;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42d00cae/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java
new file mode 100644
index 0000000..9881d1d
--- /dev/null
+++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cloudstack.storage.datastore.provider;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
+import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener;
+import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.AgentManager;
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.ModifyStoragePoolAnswer;
+import com.cloud.agent.api.ModifyStoragePoolCommand;
+import com.cloud.alert.AlertManager;
+import com.cloud.storage.DataStoreRole;
+import com.cloud.storage.StoragePool;
+import com.cloud.storage.StoragePoolHostVO;
+import com.cloud.storage.dao.StoragePoolHostDao;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+public class SolidFireSharedHostListener implements HypervisorHostListener {
+    private static final Logger s_logger = Logger.getLogger(DefaultHostListener.class);
+
+    @Inject private AgentManager agentMgr;
+    @Inject private DataStoreManager dataStoreMgr;
+    @Inject private AlertManager alertMgr;
+    @Inject private StoragePoolHostDao storagePoolHostDao;
+    @Inject private PrimaryDataStoreDao primaryStoreDao;
+
+    @Override
+    public boolean hostConnect(long hostId, long storagePoolId) {
+        StoragePoolHostVO storagePoolHost = storagePoolHostDao.findByPoolHost(storagePoolId, hostId);
+
+        if (storagePoolHost == null) {
+            storagePoolHost = new StoragePoolHostVO(storagePoolId, hostId, "");
+
+            storagePoolHostDao.persist(storagePoolHost);
+        }
+
+        StoragePool storagePool = (StoragePool)dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary);
+        ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, storagePool);
+        Answer answer = agentMgr.easySend(hostId, cmd);
+
+        if (answer == null) {
+            throw new CloudRuntimeException("Unable to get an answer to the modify storage pool command for storage pool: " + storagePool.getId());
+        }
+
+        if (!answer.getResult()) {
+            String msg = "Unable to attach storage pool " + storagePoolId + " to the host " + hostId;
+
+            alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, storagePool.getDataCenterId(), storagePool.getPodId(), msg, msg);
+
+            throw new CloudRuntimeException(msg);
+        }
+
+        assert (answer instanceof ModifyStoragePoolAnswer) : "ModifyStoragePoolAnswer not returned from ModifyStoragePoolCommand; Storage pool = " +
+            storagePool.getId() + "; Host=" + hostId;
+
+        s_logger.info("Connection established between storage pool " + storagePool + " and host + " + hostId);
+
+        return true;
+    }
+
+    @Override
+    public boolean hostDisconnected(long hostId, long storagePoolId) {
+        StoragePoolHostVO storagePoolHost = storagePoolHostDao.findByPoolHost(storagePoolId, hostId);
+
+        if (storagePoolHost != null) {
+            storagePoolHostDao.deleteStoragePoolHostDetails(hostId, storagePoolId);
+        }
+
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42d00cae/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedPrimaryDataStoreProvider.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedPrimaryDataStoreProvider.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedPrimaryDataStoreProvider.java
new file mode 100644
index 0000000..d5b82a1
--- /dev/null
+++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedPrimaryDataStoreProvider.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cloudstack.storage.datastore.provider;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.springframework.stereotype.Component;
+
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreLifeCycle;
+import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener;
+import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
+import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreProvider;
+import org.apache.cloudstack.storage.datastore.driver.SolidFireSharedPrimaryDataStoreDriver;
+import org.apache.cloudstack.storage.datastore.lifecycle.SolidFireSharedPrimaryDataStoreLifeCycle;
+import org.apache.cloudstack.storage.datastore.util.SolidFireUtil;
+
+import com.cloud.utils.component.ComponentContext;
+
+@Component
+public class SolidFireSharedPrimaryDataStoreProvider implements PrimaryDataStoreProvider {
+    private DataStoreLifeCycle lifecycle;
+    private PrimaryDataStoreDriver driver;
+    private HypervisorHostListener listener;
+
+    SolidFireSharedPrimaryDataStoreProvider() {
+    }
+
+    @Override
+    public String getName() {
+        return SolidFireUtil.SHARED_PROVIDER_NAME;
+    }
+
+    @Override
+    public DataStoreLifeCycle getDataStoreLifeCycle() {
+        return lifecycle;
+    }
+
+    @Override
+    public PrimaryDataStoreDriver getDataStoreDriver() {
+        return driver;
+    }
+
+    @Override
+    public HypervisorHostListener getHostListener() {
+        return listener;
+    }
+
+    @Override
+    public boolean configure(Map<String, Object> params) {
+        lifecycle = ComponentContext.inject(SolidFireSharedPrimaryDataStoreLifeCycle.class);
+        driver = ComponentContext.inject(SolidFireSharedPrimaryDataStoreDriver.class);
+        listener = ComponentContext.inject(SolidFireSharedHostListener.class);
+
+        return true;
+    }
+
+    @Override
+    public Set<DataStoreProviderType> getTypes() {
+        Set<DataStoreProviderType> types = new HashSet<DataStoreProviderType>();
+
+        types.add(DataStoreProviderType.PRIMARY);
+
+        return types;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42d00cae/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 3c457ba..a27917b 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
@@ -29,11 +29,16 @@ import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.StringTokenizer;
+import java.util.UUID;
 
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.X509TrustManager;
 
+import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
+import org.apache.commons.lang.StringUtils;
 import org.apache.http.HttpResponse;
 import org.apache.http.auth.AuthScope;
 import org.apache.http.auth.UsernamePasswordCredentials;
@@ -49,10 +54,17 @@ import org.apache.http.impl.conn.BasicClientConnectionManager;
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 
+import com.cloud.dc.ClusterDetailsDao;
+import com.cloud.dc.ClusterDetailsVO;
+import com.cloud.host.Host;
+import com.cloud.host.HostVO;
+import com.cloud.user.AccountDetailVO;
+import com.cloud.user.AccountDetailsDao;
 import com.cloud.utils.exception.CloudRuntimeException;
 
 public class SolidFireUtil {
     public static final String PROVIDER_NAME = "SolidFire";
+    public static final String SHARED_PROVIDER_NAME = "SolidFireShared";
 
     public static final String MANAGEMENT_VIP = "mVip";
     public static final String STORAGE_VIP = "sVip";
@@ -63,11 +75,18 @@ public class SolidFireUtil {
     public static final String CLUSTER_ADMIN_USERNAME = "clusterAdminUsername";
     public static final String CLUSTER_ADMIN_PASSWORD = "clusterAdminPassword";
 
+    // these three variables should only be used for the SolidFire plug-in with the name SolidFireUtil.PROVIDER_NAME
     public static final String CLUSTER_DEFAULT_MIN_IOPS = "clusterDefaultMinIops";
     public static final String CLUSTER_DEFAULT_MAX_IOPS = "clusterDefaultMaxIops";
     public static final String CLUSTER_DEFAULT_BURST_IOPS_PERCENT_OF_MAX_IOPS = "clusterDefaultBurstIopsPercentOfMaxIops";
 
+    // these three variables should only be used for the SolidFire plug-in with the name SolidFireUtil.SHARED_PROVIDER_NAME
+    public static final String MIN_IOPS = "minIops";
+    public static final String MAX_IOPS = "maxIops";
+    public static final String BURST_IOPS = "burstIops";
+
     public static final String ACCOUNT_ID = "accountId";
+    public static final String VOLUME_ID = "volumeId";
 
     public static final String CHAP_INITIATOR_USERNAME = "chapInitiatorUsername";
     public static final String CHAP_INITIATOR_SECRET = "chapInitiatorSecret";
@@ -75,18 +94,323 @@ public class SolidFireUtil {
     public static final String CHAP_TARGET_USERNAME = "chapTargetUsername";
     public static final String CHAP_TARGET_SECRET = "chapTargetSecret";
 
-    public static long createSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword,
-            String strSfVolumeName, long lSfAccountId, long lTotalSize, boolean bEnable512e, final String strCloudStackVolumeSize,
-            long lMinIops, long lMaxIops, long lBurstIops)
+    public static final String DATACENTER = "datacenter";
+
+    public static final String DATASTORE_NAME = "datastoreName";
+    public static final String IQN = "iqn";
+
+    private static final int DEFAULT_MANAGEMENT_PORT = 443;
+    private static final int DEFAULT_STORAGE_PORT = 3260;
+
+    public static class SolidFireConnection {
+        private final String _managementVip;
+        private final int _managementPort;
+        private final String _clusterAdminUsername;
+        private final String _clusterAdminPassword;
+
+        public SolidFireConnection(String managementVip, int managementPort, String clusterAdminUsername, String clusterAdminPassword) {
+            _managementVip = managementVip;
+            _managementPort = managementPort;
+            _clusterAdminUsername = clusterAdminUsername;
+            _clusterAdminPassword = clusterAdminPassword;
+        }
+
+        public String getManagementVip() {
+            return _managementVip;
+        }
+
+        public int getManagementPort() {
+            return _managementPort;
+        }
+
+        public String getClusterAdminUsername() {
+            return _clusterAdminUsername;
+        }
+
+        public String getClusterAdminPassword() {
+            return _clusterAdminPassword;
+        }
+    }
+
+    public static SolidFireConnection getSolidFireConnection(long storagePoolId, StoragePoolDetailsDao storagePoolDetailsDao) {
+        StoragePoolDetailVO storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.MANAGEMENT_VIP);
+
+        String mVip = storagePoolDetail.getValue();
+
+        storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.MANAGEMENT_PORT);
+
+        int mPort = Integer.parseInt(storagePoolDetail.getValue());
+
+        storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_ADMIN_USERNAME);
+
+        String clusterAdminUsername = storagePoolDetail.getValue();
+
+        storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_ADMIN_PASSWORD);
+
+        String clusterAdminPassword = storagePoolDetail.getValue();
+
+        return new SolidFireConnection(mVip, mPort, clusterAdminUsername, clusterAdminPassword);
+    }
+
+    public static String getSolidFireAccountName(String csAccountUuid, long csAccountId) {
+        return "CloudStack_" + csAccountUuid + "_" + csAccountId;
+    }
+
+    public static void updateCsDbWithSolidFireAccountInfo(long csAccountId, SolidFireUtil.SolidFireAccount sfAccount,
+            AccountDetailsDao accountDetailsDao) {
+        AccountDetailVO accountDetail = new AccountDetailVO(csAccountId,
+                SolidFireUtil.ACCOUNT_ID,
+                String.valueOf(sfAccount.getId()));
+
+        accountDetailsDao.persist(accountDetail);
+
+        accountDetail = new AccountDetailVO(csAccountId,
+                SolidFireUtil.CHAP_INITIATOR_USERNAME,
+                String.valueOf(sfAccount.getName()));
+
+        accountDetailsDao.persist(accountDetail);
+
+        accountDetail = new AccountDetailVO(csAccountId,
+                SolidFireUtil.CHAP_INITIATOR_SECRET,
+                String.valueOf(sfAccount.getInitiatorSecret()));
+
+        accountDetailsDao.persist(accountDetail);
+
+        accountDetail = new AccountDetailVO(csAccountId,
+                SolidFireUtil.CHAP_TARGET_USERNAME,
+                sfAccount.getName());
+
+        accountDetailsDao.persist(accountDetail);
+
+        accountDetail = new AccountDetailVO(csAccountId,
+                SolidFireUtil.CHAP_TARGET_SECRET,
+                sfAccount.getTargetSecret());
+
+        accountDetailsDao.persist(accountDetail);
+    }
+
+    public static SolidFireAccount getSolidFireAccount(SolidFireConnection sfConnection, String sfAccountName) {
+        try {
+            return getSolidFireAccountByName(sfConnection, sfAccountName);
+        } catch (Exception ex) {
+            return null;
+        }
+    }
+
+    public static long placeVolumeInVolumeAccessGroup(SolidFireConnection sfConnection, long sfVolumeId, long storagePoolId, List<HostVO> hosts,
+            ClusterDetailsDao clusterDetailsDao) {
+        if (hosts == null || hosts.isEmpty()) {
+            throw new CloudRuntimeException("There must be at least one host in the cluster.");
+        }
+
+        long lVagId;
+
+        try {
+            lVagId = SolidFireUtil.createSolidFireVag(sfConnection, "CloudStack-" + UUID.randomUUID().toString(),
+                SolidFireUtil.getIqnsFromHosts(hosts), new long[] { sfVolumeId });
+        }
+        catch (Exception ex) {
+            String iqnInVagAlready = "Exceeded maximum number of Volume Access Groups per initiator";
+
+            if (!ex.getMessage().contains(iqnInVagAlready)) {
+                throw new CloudRuntimeException(ex.getMessage());
+            }
+
+            // getCompatibleVag throws an exception if an existing VAG can't be located
+            SolidFireUtil.SolidFireVag sfVag = getCompatibleVag(sfConnection, hosts);
+
+            lVagId = sfVag.getId();
+
+            long[] volumeIds = getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, true);
+
+            SolidFireUtil.modifySolidFireVag(sfConnection, lVagId,
+                sfVag.getInitiators(), volumeIds);
+        }
+
+        ClusterDetailsVO clusterDetail = new ClusterDetailsVO(hosts.get(0).getClusterId(), getVagKey(storagePoolId), String.valueOf(lVagId));
+
+        clusterDetailsDao.persist(clusterDetail);
+
+        return lVagId;
+    }
+
+    public static 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;
+    }
+
+    public static String[] getNewHostIqns(String[] currentIqns, String[] newIqns) {
+        List<String> lstIqns = new ArrayList<String>();
+
+        if (currentIqns != null) {
+            for (String currentIqn : currentIqns) {
+                lstIqns.add(currentIqn);
+            }
+        }
+
+        if (newIqns != null) {
+            for (String newIqn : newIqns) {
+                if (!lstIqns.contains(newIqn)) {
+                    lstIqns.add(newIqn);
+                }
+            }
+        }
+
+        return lstIqns.toArray(new String[0]);
+    }
+
+    public static long[] getNewVolumeIds(long[] volumeIds, long volumeIdToAddOrRemove, boolean add) {
+        if (add) {
+            return getNewVolumeIdsAdd(volumeIds, volumeIdToAddOrRemove);
+        }
+
+        return getNewVolumeIdsRemove(volumeIds, volumeIdToAddOrRemove);
+    }
+
+    private static 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 static 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 static 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;
+    }
+
+    public static String getVagKey(long storagePoolId) {
+        return "sfVolumeAccessGroup_" + storagePoolId;
+    }
+
+    public static 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]);
+    }
+
+    // this method takes in a collection of hosts and tries to find an existing VAG that has all of them in it
+    // if successful, the VAG is returned; else, a CloudRuntimeException is thrown and this issue should be corrected by an admin
+    private static SolidFireUtil.SolidFireVag getCompatibleVag(SolidFireConnection sfConnection, List<HostVO> hosts) {
+        List<SolidFireUtil.SolidFireVag> sfVags = SolidFireUtil.getAllSolidFireVags(sfConnection);
+
+        if (sfVags != null) {
+            List<String> hostIqns = new ArrayList<String>();
+
+            // where the method we're in is called, hosts should not be null
+            for (HostVO host : hosts) {
+                // where the method we're in is called, host.getStorageUrl() should not be null (it actually should start with "iqn")
+                hostIqns.add(host.getStorageUrl().toLowerCase());
+            }
+
+            for (SolidFireUtil.SolidFireVag sfVag : sfVags) {
+                List<String> lstInitiators = getStringArrayAsLowerCaseStringList(sfVag.getInitiators());
+
+                // lstInitiators should not be returned from getStringArrayAsLowerCaseStringList as null
+                if (lstInitiators.containsAll(hostIqns)) {
+                    return sfVag;
+                }
+            }
+        }
+
+        throw new CloudRuntimeException("Unable to locate the appropriate SolidFire Volume Access Group");
+    }
+
+    private static List<String> getStringArrayAsLowerCaseStringList(String[] aString) {
+        List<String> lstLowerCaseString = new ArrayList<String>();
+
+        if (aString != null) {
+            for (String str : aString) {
+                if (str != null) {
+                    lstLowerCaseString.add(str.toLowerCase());
+                }
+            }
+        }
+
+        return lstLowerCaseString;
+    }
+
+    public static String getSolidFireVolumeName(String strCloudStackVolumeName) {
+        final String specialChar = "-";
+
+        StringBuilder strSolidFireVolumeName = new StringBuilder();
+
+        for (int i = 0; i < strCloudStackVolumeName.length(); i++) {
+            String strChar = strCloudStackVolumeName.substring(i, i + 1);
+
+            if (StringUtils.isAlphanumeric(strChar)) {
+                strSolidFireVolumeName.append(strChar);
+            } else {
+                strSolidFireVolumeName.append(specialChar);
+            }
+        }
+
+        return strSolidFireVolumeName.toString();
+    }
+
+    public static long createSolidFireVolume(SolidFireConnection sfConnection, String strSfVolumeName, long lSfAccountId, long lTotalSize,
+            boolean bEnable512e, final String strCloudStackVolumeSize, long lMinIops, long lMaxIops, long lBurstIops)
     {
         final Gson gson = new GsonBuilder().create();
 
-        VolumeToCreate volumeToCreate =
-            new VolumeToCreate(strSfVolumeName, lSfAccountId, lTotalSize, bEnable512e, strCloudStackVolumeSize, lMinIops, lMaxIops, lBurstIops);
+        VolumeToCreate volumeToCreate = new VolumeToCreate(strSfVolumeName, lSfAccountId, lTotalSize, bEnable512e, strCloudStackVolumeSize, lMinIops, lMaxIops, lBurstIops);
 
         String strVolumeToCreateJson = gson.toJson(volumeToCreate);
 
-        String strVolumeCreateResultJson = executeJsonRpc(strVolumeToCreateJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        String strVolumeCreateResultJson = executeJsonRpc(sfConnection, strVolumeToCreateJson);
 
         VolumeCreateResult volumeCreateResult = gson.fromJson(strVolumeCreateResultJson, VolumeCreateResult.class);
 
@@ -95,7 +419,7 @@ public class SolidFireUtil {
         return volumeCreateResult.result.volumeID;
     }
 
-    public static SolidFireVolume getSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId)
+    public static SolidFireVolume getSolidFireVolume(SolidFireConnection sfConnection, long lVolumeId)
     {
         final Gson gson = new GsonBuilder().create();
 
@@ -103,7 +427,7 @@ public class SolidFireUtil {
 
         String strVolumeToGetJson = gson.toJson(volumeToGet);
 
-        String strVolumeGetResultJson = executeJsonRpc(strVolumeToGetJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        String strVolumeGetResultJson = executeJsonRpc(sfConnection, strVolumeToGetJson);
 
         VolumeGetResult volumeGetResult = gson.fromJson(strVolumeGetResultJson, VolumeGetResult.class);
 
@@ -118,14 +442,14 @@ public class SolidFireUtil {
         return new SolidFireVolume(lVolumeId, strVolumeName, strVolumeIqn, lAccountId, strVolumeStatus, lTotalSize);
     }
 
-    public static List<SolidFireVolume> getSolidFireVolumesForAccountId(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lAccountId) {
+    public static List<SolidFireVolume> getSolidFireVolumesForAccountId(SolidFireConnection sfConnection, long lAccountId) {
         final Gson gson = new GsonBuilder().create();
 
         VolumesToGetForAccount volumesToGetForAccount = new VolumesToGetForAccount(lAccountId);
 
         String strVolumesToGetForAccountJson = gson.toJson(volumesToGetForAccount);
 
-        String strVolumesGetForAccountResultJson = executeJsonRpc(strVolumesToGetForAccountJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        String strVolumesGetForAccountResultJson = executeJsonRpc(sfConnection, strVolumesToGetForAccountJson);
 
         VolumeGetResult volumeGetResult = gson.fromJson(strVolumesGetForAccountResultJson, VolumeGetResult.class);
 
@@ -140,7 +464,7 @@ public class SolidFireUtil {
         return sfVolumes;
     }
 
-    public static List<SolidFireVolume> getDeletedVolumes(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword)
+    public static List<SolidFireVolume> getDeletedVolumes(SolidFireConnection sfConnection)
     {
         final Gson gson = new GsonBuilder().create();
 
@@ -148,8 +472,7 @@ public class SolidFireUtil {
 
         String strListDeletedVolumesJson = gson.toJson(listDeletedVolumes);
 
-        String strListDeletedVolumesResultJson = executeJsonRpc(strListDeletedVolumesJson, strSfMvip, iSfPort,
-                strSfAdmin, strSfPassword);
+        String strListDeletedVolumesResultJson = executeJsonRpc(sfConnection, strListDeletedVolumesJson);
 
         VolumeGetResult volumeGetResult = gson.fromJson(strListDeletedVolumesResultJson, VolumeGetResult.class);
 
@@ -164,9 +487,9 @@ public class SolidFireUtil {
         return deletedVolumes;
     }
 
-    public static SolidFireVolume deleteSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId)
+    public static SolidFireVolume deleteSolidFireVolume(SolidFireConnection sfConnection, long lVolumeId)
     {
-        SolidFireVolume sfVolume = getSolidFireVolume(strSfMvip, iSfPort, strSfAdmin, strSfPassword, lVolumeId);
+        SolidFireVolume sfVolume = getSolidFireVolume(sfConnection, lVolumeId);
 
         final Gson gson = new GsonBuilder().create();
 
@@ -174,12 +497,12 @@ public class SolidFireUtil {
 
         String strVolumeToDeleteJson = gson.toJson(volumeToDelete);
 
-        executeJsonRpc(strVolumeToDeleteJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        executeJsonRpc(sfConnection, strVolumeToDeleteJson);
 
         return sfVolume;
     }
 
-   public static void purgeSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId)
+   public static void purgeSolidFireVolume(SolidFireConnection sfConnection, long lVolumeId)
     {
         final Gson gson = new GsonBuilder().create();
 
@@ -187,7 +510,7 @@ public class SolidFireUtil {
 
         String strVolumeToPurgeJson = gson.toJson(volumeToPurge);
 
-        executeJsonRpc(strVolumeToPurgeJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        executeJsonRpc(sfConnection, strVolumeToPurgeJson);
     }
 
     private static final String ACTIVE = "active";
@@ -267,7 +590,7 @@ public class SolidFireUtil {
         }
     }
 
-    public static long createSolidFireAccount(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, String strAccountName)
+    public static long createSolidFireAccount(SolidFireConnection sfConnection, String strAccountName)
     {
         final Gson gson = new GsonBuilder().create();
 
@@ -275,7 +598,7 @@ public class SolidFireUtil {
 
         String strAccountAddJson = gson.toJson(accountToAdd);
 
-        String strAccountAddResultJson = executeJsonRpc(strAccountAddJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        String strAccountAddResultJson = executeJsonRpc(sfConnection, strAccountAddJson);
 
         AccountAddResult accountAddResult = gson.fromJson(strAccountAddResultJson, AccountAddResult.class);
 
@@ -284,7 +607,7 @@ public class SolidFireUtil {
         return accountAddResult.result.accountID;
     }
 
-    public static SolidFireAccount getSolidFireAccountById(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lSfAccountId)
+    public static SolidFireAccount getSolidFireAccountById(SolidFireConnection sfConnection, long lSfAccountId)
     {
         final Gson gson = new GsonBuilder().create();
 
@@ -292,7 +615,7 @@ public class SolidFireUtil {
 
         String strAccountToGetByIdJson = gson.toJson(accountToGetById);
 
-        String strAccountGetByIdResultJson = executeJsonRpc(strAccountToGetByIdJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        String strAccountGetByIdResultJson = executeJsonRpc(sfConnection, strAccountToGetByIdJson);
 
         AccountGetResult accountGetByIdResult = gson.fromJson(strAccountGetByIdResultJson, AccountGetResult.class);
 
@@ -305,7 +628,7 @@ public class SolidFireUtil {
         return new SolidFireAccount(lSfAccountId, strSfAccountName, strSfAccountInitiatorSecret, strSfAccountTargetSecret);
     }
 
-    public static SolidFireAccount getSolidFireAccountByName(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, String strSfAccountName)
+    public static SolidFireAccount getSolidFireAccountByName(SolidFireConnection sfConnection, String strSfAccountName)
     {
         final Gson gson = new GsonBuilder().create();
 
@@ -313,7 +636,7 @@ public class SolidFireUtil {
 
         String strAccountToGetByNameJson = gson.toJson(accountToGetByName);
 
-        String strAccountGetByNameResultJson = executeJsonRpc(strAccountToGetByNameJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        String strAccountGetByNameResultJson = executeJsonRpc(sfConnection, strAccountToGetByNameJson);
 
         AccountGetResult accountGetByNameResult = gson.fromJson(strAccountGetByNameResultJson, AccountGetResult.class);
 
@@ -326,7 +649,7 @@ public class SolidFireUtil {
         return new SolidFireAccount(lSfAccountId, strSfAccountName, strSfAccountInitiatorSecret, strSfAccountTargetSecret);
     }
 
-    public static void deleteSolidFireAccount(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lAccountId)
+    public static void deleteSolidFireAccount(SolidFireConnection sfConnection, long lAccountId)
     {
         final Gson gson = new GsonBuilder().create();
 
@@ -334,7 +657,7 @@ public class SolidFireUtil {
 
         String strAccountToRemoveJson = gson.toJson(accountToRemove);
 
-        executeJsonRpc(strAccountToRemoveJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        executeJsonRpc(sfConnection, strAccountToRemoveJson);
     }
 
     public static class SolidFireAccount
@@ -399,7 +722,7 @@ public class SolidFireUtil {
         }
     }
 
-    public static long createSolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, String strVagName,
+    public static long createSolidFireVag(SolidFireConnection sfConnection, String strVagName,
             String[] iqns, long[] volumeIds)
     {
         final Gson gson = new GsonBuilder().create();
@@ -408,7 +731,7 @@ public class SolidFireUtil {
 
         String strVagCreateJson = gson.toJson(vagToCreate);
 
-        String strVagCreateResultJson = executeJsonRpc(strVagCreateJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        String strVagCreateResultJson = executeJsonRpc(sfConnection, strVagCreateJson);
 
         VagCreateResult vagCreateResult = gson.fromJson(strVagCreateResultJson, VagCreateResult.class);
 
@@ -417,8 +740,7 @@ public class SolidFireUtil {
         return vagCreateResult.result.volumeAccessGroupID;
     }
 
-    public static void modifySolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVagId,
-            String[] iqns, long[] volumeIds)
+    public static void modifySolidFireVag(SolidFireConnection sfConnection, long lVagId, String[] iqns, long[] volumeIds)
     {
         final Gson gson = new GsonBuilder().create();
 
@@ -426,10 +748,10 @@ public class SolidFireUtil {
 
         String strVagModifyJson = gson.toJson(vagToModify);
 
-        executeJsonRpc(strVagModifyJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        executeJsonRpc(sfConnection, strVagModifyJson);
     }
 
-    public static SolidFireVag getSolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVagId)
+    public static SolidFireVag getSolidFireVag(SolidFireConnection sfConnection, long lVagId)
     {
         final Gson gson = new GsonBuilder().create();
 
@@ -437,7 +759,7 @@ public class SolidFireUtil {
 
         String strVagToGetJson = gson.toJson(vagToGet);
 
-        String strVagGetResultJson = executeJsonRpc(strVagToGetJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        String strVagGetResultJson = executeJsonRpc(sfConnection, strVagToGetJson);
 
         VagGetResult vagGetResult = gson.fromJson(strVagGetResultJson, VagGetResult.class);
 
@@ -449,7 +771,7 @@ public class SolidFireUtil {
         return new SolidFireVag(lVagId, vagIqns, vagVolumeIds);
     }
 
-    public static List<SolidFireVag> getAllSolidFireVags(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword)
+    public static List<SolidFireVag> getAllSolidFireVags(SolidFireConnection sfConnection)
     {
         final Gson gson = new GsonBuilder().create();
 
@@ -457,7 +779,7 @@ public class SolidFireUtil {
 
         String strAllVagsJson = gson.toJson(allVags);
 
-        String strAllVagsGetResultJson = executeJsonRpc(strAllVagsJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        String strAllVagsGetResultJson = executeJsonRpc(sfConnection, strAllVagsJson);
 
         VagGetResult allVagsGetResult = gson.fromJson(strAllVagsGetResultJson, VagGetResult.class);
 
@@ -476,7 +798,7 @@ public class SolidFireUtil {
         return lstSolidFireVags;
     }
 
-    public static void deleteSolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVagId)
+    public static void deleteSolidFireVag(SolidFireConnection sfConnection, long lVagId)
     {
         final Gson gson = new GsonBuilder().create();
 
@@ -484,7 +806,7 @@ public class SolidFireUtil {
 
         String strVagToDeleteJson = gson.toJson(vagToDelete);
 
-        executeJsonRpc(strVagToDeleteJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        executeJsonRpc(sfConnection, strVagToDeleteJson);
     }
 
     public static class SolidFireVag
@@ -996,7 +1318,7 @@ public class SolidFireUtil {
         }
     }
 
-    private static String executeJsonRpc(String strJsonToExecute, String strMvip, int iPort, String strAdmin, String strPassword) {
+    private static String executeJsonRpc(SolidFireConnection sfConnection, String strJsonToExecute) {
         DefaultHttpClient httpClient = null;
         StringBuilder sb = new StringBuilder();
 
@@ -1005,11 +1327,11 @@ public class SolidFireUtil {
 
             input.setContentType("application/json");
 
-            httpClient = getHttpClient(iPort);
+            httpClient = getHttpClient(sfConnection.getManagementPort());
 
-            URI uri = new URI("https://" + strMvip + ":" + iPort + "/json-rpc/5.0");
+            URI uri = new URI("https://" + sfConnection.getManagementVip() + ":" + sfConnection.getManagementPort() + "/json-rpc/5.0");
             AuthScope authScope = new AuthScope(uri.getHost(), uri.getPort(), AuthScope.ANY_SCHEME);
-            UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(strAdmin, strPassword);
+            UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword());
 
             httpClient.getCredentialsProvider().setCredentials(authScope, credentials);
 
@@ -1132,4 +1454,119 @@ public class SolidFireUtil {
 
         throw new CloudRuntimeException("Could not determine the volume IDs of the volume access group for volume access group ID of " + lVagId + ".");
     }
+
+    // used to parse the "url" parameter when creating primary storage that's based on the SolidFire plug-in with the
+    // name SolidFireUtil.PROVIDER_NAME (as opposed to the SolidFire plug-in with the name SolidFireUtil.SHARED_PROVIDER_NAME)
+    // return a String instance that contains at most the MVIP and SVIP info
+    public static String getModifiedUrl(String originalUrl) {
+        StringBuilder sb = new StringBuilder();
+
+        String delimiter = ";";
+
+        StringTokenizer st = new StringTokenizer(originalUrl, delimiter);
+
+        while (st.hasMoreElements()) {
+            String token = st.nextElement().toString().toUpperCase();
+
+            if (token.startsWith(SolidFireUtil.MANAGEMENT_VIP.toUpperCase()) || token.startsWith(SolidFireUtil.STORAGE_VIP.toUpperCase())) {
+                sb.append(token).append(delimiter);
+            }
+        }
+
+        String modifiedUrl = sb.toString();
+        int lastIndexOf = modifiedUrl.lastIndexOf(delimiter);
+
+        if (lastIndexOf == (modifiedUrl.length() - delimiter.length())) {
+            return modifiedUrl.substring(0, lastIndexOf);
+        }
+
+        return modifiedUrl;
+    }
+
+    public static String getManagementVip(String url) {
+        return getVip(SolidFireUtil.MANAGEMENT_VIP, url);
+    }
+
+    public static String getStorageVip(String url) {
+        return getVip(SolidFireUtil.STORAGE_VIP, url);
+    }
+
+    public static int getManagementPort(String url) {
+        return getPort(SolidFireUtil.MANAGEMENT_VIP, url, DEFAULT_MANAGEMENT_PORT);
+    }
+
+    public static int getStoragePort(String url) {
+        return getPort(SolidFireUtil.STORAGE_VIP, url, DEFAULT_STORAGE_PORT);
+    }
+
+    private static String getVip(String keyToMatch, String url) {
+        String delimiter = ":";
+
+        String storageVip = getValue(keyToMatch, url);
+
+        int index = storageVip.indexOf(delimiter);
+
+        if (index != -1) {
+            return storageVip.substring(0, index);
+        }
+
+        return storageVip;
+    }
+
+    private static int getPort(String keyToMatch, String url, int defaultPortNumber) {
+        String delimiter = ":";
+
+        String storageVip = getValue(keyToMatch, url);
+
+        int index = storageVip.indexOf(delimiter);
+
+        int portNumber = defaultPortNumber;
+
+        if (index != -1) {
+            String port = storageVip.substring(index + delimiter.length());
+
+            try {
+                portNumber = Integer.parseInt(port);
+            } catch (NumberFormatException ex) {
+                throw new IllegalArgumentException("Invalid URL format (port is not an integer)");
+            }
+        }
+
+        return portNumber;
+    }
+
+    public static String getValue(String keyToMatch, String url) {
+        return getValue(keyToMatch, url, true);
+    }
+
+    public static String getValue(String keyToMatch, String url, boolean throwExceptionIfNotFound) {
+        String delimiter1 = ";";
+        String delimiter2 = "=";
+
+        StringTokenizer st = new StringTokenizer(url, delimiter1);
+
+        while (st.hasMoreElements()) {
+            String token = st.nextElement().toString();
+
+            int index = token.indexOf(delimiter2);
+
+            if (index == -1) {
+                throw new RuntimeException("Invalid URL format");
+            }
+
+            String key = token.substring(0, index);
+
+            if (key.equalsIgnoreCase(keyToMatch)) {
+                String valueToReturn = token.substring(index + delimiter2.length());
+
+                return valueToReturn;
+            }
+        }
+
+        if (throwExceptionIfNotFound) {
+            throw new RuntimeException("Key not found in URL");
+        }
+
+        return null;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42d00cae/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 298f560..b5844e9 100755
--- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostMO.java
+++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostMO.java
@@ -699,7 +699,7 @@ public class HostMO extends BaseMO implements VmwareHypervisorHost {
                     ManagedObjectReference morDs = oc.getObj();
                     String name = (String)VmwareHelper.getPropValue(oc, "name");
 
-                    if (!name.startsWith("-iqn.")) {
+                    if (!name.startsWith("-iqn.") && !name.startsWith("_iqn.")) {
                         dsList.add(new Pair<ManagedObjectReference, String>(morDs, name));
                     }
                 }


[2/2] git commit: updated refs/heads/master to 42d00ca

Posted by mt...@apache.org.
SolidFire (shared-access) Provider


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

Branch: refs/heads/master
Commit: 42d00cae584348f012d34418cbb0b8e6f020e12c
Parents: 520ff00
Author: Mike Tutkowski <mi...@solidfire.com>
Authored: Tue May 20 10:58:28 2014 -0600
Committer: Mike Tutkowski <mi...@solidfire.com>
Committed: Mon Jun 16 12:15:29 2014 -0600

----------------------------------------------------------------------
 .../agent/api/CreateStoragePoolCommand.java     |  25 +
 .../agent/api/DeleteStoragePoolCommand.java     |  47 +-
 .../vmware/resource/VmwareResource.java         |  36 +-
 .../resource/VmwareStorageProcessor.java        |  17 +-
 .../resource/XenServerStorageProcessor.java     | 147 -----
 plugins/storage/volume/solidfire/pom.xml        |   5 +
 .../spring-storage-volume-solidfire-context.xml |   4 +-
 .../SolidFireSharedPrimaryDataStoreDriver.java  |  65 +++
 .../driver/SolidfirePrimaryDataStoreDriver.java | 514 ++---------------
 .../SolidFirePrimaryDataStoreLifeCycle.java     | 137 +----
 ...olidFireSharedPrimaryDataStoreLifeCycle.java | 548 +++++++++++++++++++
 .../provider/SolidFireSharedHostListener.java   |  92 ++++
 ...SolidFireSharedPrimaryDataStoreProvider.java |  83 +++
 .../storage/datastore/util/SolidFireUtil.java   | 519 ++++++++++++++++--
 .../com/cloud/hypervisor/vmware/mo/HostMO.java  |   2 +-
 15 files changed, 1427 insertions(+), 814 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42d00cae/core/src/com/cloud/agent/api/CreateStoragePoolCommand.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/agent/api/CreateStoragePoolCommand.java b/core/src/com/cloud/agent/api/CreateStoragePoolCommand.java
index 891ea2c..f2f742a 100644
--- a/core/src/com/cloud/agent/api/CreateStoragePoolCommand.java
+++ b/core/src/com/cloud/agent/api/CreateStoragePoolCommand.java
@@ -18,7 +18,16 @@ package com.cloud.agent.api;
 
 import com.cloud.storage.StoragePool;
 
+import java.util.Map;
+
 public class CreateStoragePoolCommand extends ModifyStoragePoolCommand {
+    public static final String DATASTORE_NAME = "datastoreName";
+    public static final String IQN = "iqn";
+    public static final String STORAGE_HOST = "storageHost";
+    public static final String STORAGE_PORT = "storagePort";
+
+    private boolean _createDatastore;
+    private Map<String, String> _details;
 
     public CreateStoragePoolCommand() {
     }
@@ -26,4 +35,20 @@ public class CreateStoragePoolCommand extends ModifyStoragePoolCommand {
     public CreateStoragePoolCommand(boolean add, StoragePool pool) {
         super(add, pool);
     }
+
+    public void setCreateDatastore(boolean createDatastore) {
+        _createDatastore = createDatastore;
+    }
+
+    public boolean getCreateDatastore() {
+        return _createDatastore;
+    }
+
+    public void setDetails(Map<String, String> details) {
+        _details = details;
+    }
+
+    public Map<String, String> getDetails() {
+        return _details;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42d00cae/core/src/com/cloud/agent/api/DeleteStoragePoolCommand.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/agent/api/DeleteStoragePoolCommand.java b/core/src/com/cloud/agent/api/DeleteStoragePoolCommand.java
index f80accb..dae5678 100644
--- a/core/src/com/cloud/agent/api/DeleteStoragePoolCommand.java
+++ b/core/src/com/cloud/agent/api/DeleteStoragePoolCommand.java
@@ -17,45 +17,68 @@
 package com.cloud.agent.api;
 
 import java.io.File;
+import java.util.Map;
 import java.util.UUID;
 
 import com.cloud.agent.api.to.StorageFilerTO;
 import com.cloud.storage.StoragePool;
 
 public class DeleteStoragePoolCommand extends Command {
+    public static final String DATASTORE_NAME = "datastoreName";
+    public static final String IQN = "iqn";
+    public static final String STORAGE_HOST = "storageHost";
+    public static final String STORAGE_PORT = "storagePort";
 
-    StorageFilerTO pool;
     public static final String LOCAL_PATH_PREFIX = "/mnt/";
-    String localPath;
+
+    private StorageFilerTO _pool;
+    private String _localPath;
+    private boolean _removeDatastore;
+    private Map<String, String> _details;
 
     public DeleteStoragePoolCommand() {
 
     }
 
     public DeleteStoragePoolCommand(StoragePool pool, String localPath) {
-        this.pool = new StorageFilerTO(pool);
-        this.localPath = localPath;
+        _pool = new StorageFilerTO(pool);
+        _localPath = localPath;
     }
 
     public DeleteStoragePoolCommand(StoragePool pool) {
         this(pool, LOCAL_PATH_PREFIX + File.separator + UUID.nameUUIDFromBytes((pool.getHostAddress() + pool.getPath()).getBytes()));
     }
 
+    public void setPool(StoragePool pool) {
+        _pool = new StorageFilerTO(pool);
+    }
+
     public StorageFilerTO getPool() {
-        return pool;
+        return _pool;
     }
 
-    public void setPool(StoragePool pool) {
-        this.pool = new StorageFilerTO(pool);
+    public String getLocalPath() {
+        return _localPath;
     }
 
-    @Override
-    public boolean executeInSequence() {
-        return false;
+    public void setRemoveDatastore(boolean removeDatastore) {
+        _removeDatastore = removeDatastore;
     }
 
-    public String getLocalPath() {
-        return localPath;
+    public boolean getRemoveDatastore() {
+        return _removeDatastore;
+    }
+
+    public void setDetails(Map<String, String> details) {
+        _details = details;
+    }
+
+    public Map<String, String> getDetails() {
+        return _details;
     }
 
+    @Override
+    public boolean executeInSequence() {
+        return false;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42d00cae/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 52421fa..8dc2784 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
@@ -3177,6 +3177,18 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
     }
 
     protected Answer execute(CreateStoragePoolCommand cmd) {
+        if (cmd.getCreateDatastore()) {
+            try {
+                VmwareContext context = getServiceContext();
+
+                _storageProcessor.prepareManagedDatastore(context, getHyperHost(context),
+                        cmd.getDetails().get(CreateStoragePoolCommand.DATASTORE_NAME), cmd.getDetails().get(CreateStoragePoolCommand.IQN),
+                        cmd.getDetails().get(CreateStoragePoolCommand.STORAGE_HOST), Integer.parseInt(cmd.getDetails().get(CreateStoragePoolCommand.STORAGE_PORT)));
+            } catch (Exception ex) {
+                return new Answer(cmd, false, "Issue creating datastore");
+            }
+        }
+
         return new Answer(cmd, true, "success");
     }
 
@@ -3223,22 +3235,32 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
             s_logger.info("Executing resource DeleteStoragePoolCommand: " + _gson.toJson(cmd));
         }
 
-        StorageFilerTO pool = cmd.getPool();
         try {
-            // We will leave datastore cleanup management to vCenter. Since for cluster VMFS datastore, it will always
-            // be mounted by vCenter.
+            if (cmd.getRemoveDatastore()) {
+                _storageProcessor.handleDatastoreAndVmdkDetach(cmd.getDetails().get(DeleteStoragePoolCommand.DATASTORE_NAME), cmd.getDetails().get(DeleteStoragePoolCommand.IQN),
+                    cmd.getDetails().get(DeleteStoragePoolCommand.STORAGE_HOST), Integer.parseInt(cmd.getDetails().get(DeleteStoragePoolCommand.STORAGE_PORT)));
 
-            // VmwareHypervisorHost hyperHost = this.getHyperHost(getServiceContext());
-            // hyperHost.unmountDatastore(pool.getUuid());
-            Answer answer = new Answer(cmd, true, "success");
-            return answer;
+                return new Answer(cmd, true, "success");
+            }
+            else {
+                // We will leave datastore cleanup management to vCenter. Since for cluster VMFS datastore, it will always
+                // be mounted by vCenter.
+
+                // VmwareHypervisorHost hyperHost = this.getHyperHost(getServiceContext());
+                // hyperHost.unmountDatastore(pool.getUuid());
+
+                return new Answer(cmd, true, "success");
+            }
         } catch (Throwable e) {
             if (e instanceof RemoteException) {
                 s_logger.warn("Encounter remote exception to vCenter, invalidate VMware session context");
+
                 invalidateServiceContext();
             }
 
+            StorageFilerTO pool = cmd.getPool();
             String msg = "DeleteStoragePoolCommand (pool: " + pool.getHost() + ", path: " + pool.getPath() + ") failed due to " + VmwareHelper.getExceptionMessage(e);
+
             return new Answer(cmd, false, msg);
         }
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42d00cae/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
index 7bc5bd3..77ee4ce 100644
--- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
@@ -1688,6 +1688,11 @@ public class VmwareStorageProcessor implements StorageProcessor {
         }
     }
 
+    public ManagedObjectReference prepareManagedDatastore(VmwareContext context, VmwareHypervisorHost hyperHost, String datastoreName,
+            String iScsiName, String storageHost, int storagePort) throws Exception {
+        return getVmfsDatastore(context, hyperHost, datastoreName, storageHost, storagePort, trimIqn(iScsiName), null, null, null, null);
+    }
+
     private ManagedObjectReference prepareManagedDatastore(VmwareContext context, VmwareHypervisorHost hyperHost, String iScsiName,
             String storageHost, int storagePort, String chapInitiatorUsername, String chapInitiatorSecret,
             String chapTargetUsername, String chapTargetSecret) throws Exception {
@@ -1800,8 +1805,8 @@ public class VmwareStorageProcessor implements StorageProcessor {
         return null;
     }
 
-    private void removeVmfsDatastore(VmwareHypervisorHost hyperHost, String volumeUuid, String storageIpAddress, int storagePortNumber, String iqn) throws Exception {
-        // hyperHost.unmountDatastore(volumeUuid);
+    private void removeVmfsDatastore(VmwareHypervisorHost hyperHost, String datastoreName, String storageIpAddress, int storagePortNumber, String iqn) throws Exception {
+        // hyperHost.unmountDatastore(datastoreName);
 
         VmwareContext context = hostService.getServiceContext(null);
         ManagedObjectReference morCluster = hyperHost.getHyperHostCluster();
@@ -1990,11 +1995,15 @@ public class VmwareStorageProcessor implements StorageProcessor {
         return morDs;
     }
 
-    private void handleDatastoreAndVmdkDetach(String iqn, String storageHost, int storagePort) throws Exception {
+    public void handleDatastoreAndVmdkDetach(String datastoreName, String iqn, String storageHost, int storagePort) throws Exception {
         VmwareContext context = hostService.getServiceContext(null);
         VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, null);
 
-        removeVmfsDatastore(hyperHost, VmwareResource.getDatastoreName(iqn), storageHost, storagePort, trimIqn(iqn));
+        removeVmfsDatastore(hyperHost, datastoreName, storageHost, storagePort, trimIqn(iqn));
+    }
+
+    private void handleDatastoreAndVmdkDetach(String iqn, String storageHost, int storagePort) throws Exception {
+        handleDatastoreAndVmdkDetach(VmwareResource.getDatastoreName(iqn), iqn, storageHost, storagePort);
     }
 
     private void removeManagedTargetsFromCluster(List<String> iqns) throws Exception {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42d00cae/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServerStorageProcessor.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServerStorageProcessor.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServerStorageProcessor.java
index 9c86fbe..e96ebf4 100644
--- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServerStorageProcessor.java
+++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServerStorageProcessor.java
@@ -53,7 +53,6 @@ import org.apache.log4j.Logger;
 import org.apache.xmlrpc.XmlRpcException;
 
 import com.cloud.agent.api.Answer;
-import com.cloud.agent.api.CreateStoragePoolCommand;
 import com.cloud.agent.api.to.DataObjectType;
 import com.cloud.agent.api.to.DataStoreTO;
 import com.cloud.agent.api.to.DataTO;
@@ -66,7 +65,6 @@ import com.cloud.exception.InternalErrorException;
 import com.cloud.hypervisor.xenserver.resource.CitrixResourceBase.SRType;
 import com.cloud.storage.DataStoreRole;
 import com.cloud.storage.Storage.ImageFormat;
-import com.cloud.storage.Storage.StoragePoolType;
 import com.cloud.storage.resource.StorageProcessor;
 import com.cloud.utils.S3Utils;
 import com.cloud.utils.exception.CloudRuntimeException;
@@ -76,7 +74,6 @@ import com.cloud.utils.storage.encoding.Decoder;
 import com.xensource.xenapi.Connection;
 import com.xensource.xenapi.Host;
 import com.xensource.xenapi.PBD;
-import com.xensource.xenapi.Pool;
 import com.xensource.xenapi.SR;
 import com.xensource.xenapi.Types;
 import com.xensource.xenapi.Types.BadServerResponse;
@@ -572,150 +569,6 @@ public class XenServerStorageProcessor implements StorageProcessor {
         }
     }
 
-    protected SR getIscsiSR(Connection conn, StorageFilerTO pool) {
-        synchronized (pool.getUuid().intern()) {
-            Map<String, String> deviceConfig = new HashMap<String, String>();
-            try {
-                String target = pool.getHost();
-                String path = pool.getPath();
-                if (path.endsWith("/")) {
-                    path = path.substring(0, path.length() - 1);
-                }
-
-                String tmp[] = path.split("/");
-                if (tmp.length != 3) {
-                    String msg = "Wrong iscsi path " + pool.getPath() + " it should be /targetIQN/LUN";
-                    s_logger.warn(msg);
-                    throw new CloudRuntimeException(msg);
-                }
-                String targetiqn = tmp[1].trim();
-                String lunid = tmp[2].trim();
-                String scsiid = "";
-
-                Set<SR> srs = SR.getByNameLabel(conn, pool.getUuid());
-                for (SR sr : srs) {
-                    if (!SRType.LVMOISCSI.equals(sr.getType(conn))) {
-                        continue;
-                    }
-                    Set<PBD> pbds = sr.getPBDs(conn);
-                    if (pbds.isEmpty()) {
-                        continue;
-                    }
-                    PBD pbd = pbds.iterator().next();
-                    Map<String, String> dc = pbd.getDeviceConfig(conn);
-                    if (dc == null) {
-                        continue;
-                    }
-                    if (dc.get("target") == null) {
-                        continue;
-                    }
-                    if (dc.get("targetIQN") == null) {
-                        continue;
-                    }
-                    if (dc.get("lunid") == null) {
-                        continue;
-                    }
-                    if (target.equals(dc.get("target")) && targetiqn.equals(dc.get("targetIQN")) && lunid.equals(dc.get("lunid"))) {
-                        throw new CloudRuntimeException("There is a SR using the same configuration target:" + dc.get("target") + ",  targetIQN:" + dc.get("targetIQN") +
-                                ", lunid:" + dc.get("lunid") + " for pool " + pool.getUuid() + "on host:" + hypervisorResource.getHost().uuid);
-                    }
-                }
-                deviceConfig.put("target", target);
-                deviceConfig.put("targetIQN", targetiqn);
-
-                Host host = Host.getByUuid(conn, hypervisorResource.getHost().uuid);
-                Map<String, String> smConfig = new HashMap<String, String>();
-                String type = SRType.LVMOISCSI.toString();
-                String poolId = Long.toString(pool.getId());
-                SR sr = null;
-                try {
-                    sr = SR.create(conn, host, deviceConfig, new Long(0), pool.getUuid(), poolId, type, "user", true, smConfig);
-                } catch (XenAPIException e) {
-                    String errmsg = e.toString();
-                    if (errmsg.contains("SR_BACKEND_FAILURE_107")) {
-                        String lun[] = errmsg.split("<LUN>");
-                        boolean found = false;
-                        for (int i = 1; i < lun.length; i++) {
-                            int blunindex = lun[i].indexOf("<LUNid>") + 7;
-                            int elunindex = lun[i].indexOf("</LUNid>");
-                            String ilun = lun[i].substring(blunindex, elunindex);
-                            ilun = ilun.trim();
-                            if (ilun.equals(lunid)) {
-                                int bscsiindex = lun[i].indexOf("<SCSIid>") + 8;
-                                int escsiindex = lun[i].indexOf("</SCSIid>");
-                                scsiid = lun[i].substring(bscsiindex, escsiindex);
-                                scsiid = scsiid.trim();
-                                found = true;
-                                break;
-                            }
-                        }
-                        if (!found) {
-                            String msg = "can not find LUN " + lunid + " in " + errmsg;
-                            s_logger.warn(msg);
-                            throw new CloudRuntimeException(msg);
-                        }
-                    } else {
-                        String msg = "Unable to create Iscsi SR  " + deviceConfig + " due to  " + e.toString();
-                        s_logger.warn(msg, e);
-                        throw new CloudRuntimeException(msg, e);
-                    }
-                }
-                deviceConfig.put("SCSIid", scsiid);
-
-                String result = SR.probe(conn, host, deviceConfig, type, smConfig);
-                String pooluuid = null;
-                if (result.indexOf("<UUID>") != -1) {
-                    pooluuid = result.substring(result.indexOf("<UUID>") + 6, result.indexOf("</UUID>")).trim();
-                }
-                if (pooluuid == null || pooluuid.length() != 36) {
-                    sr = SR.create(conn, host, deviceConfig, new Long(0), pool.getUuid(), poolId, type, "user", true, smConfig);
-                } else {
-                    sr = SR.introduce(conn, pooluuid, pool.getUuid(), poolId, type, "user", true, smConfig);
-                    Pool.Record pRec = XenServerConnectionPool.getPoolRecord(conn);
-                    PBD.Record rec = new PBD.Record();
-                    rec.deviceConfig = deviceConfig;
-                    rec.host = pRec.master;
-                    rec.SR = sr;
-                    PBD pbd = PBD.create(conn, rec);
-                    pbd.plug(conn);
-                }
-                sr.scan(conn);
-                return sr;
-            } catch (XenAPIException e) {
-                String msg = "Unable to create Iscsi SR  " + deviceConfig + " due to  " + e.toString();
-                s_logger.warn(msg, e);
-                throw new CloudRuntimeException(msg, e);
-            } catch (Exception e) {
-                String msg = "Unable to create Iscsi SR  " + deviceConfig + " due to  " + e.getMessage();
-                s_logger.warn(msg, e);
-                throw new CloudRuntimeException(msg, e);
-            }
-        }
-    }
-
-    protected Answer execute(CreateStoragePoolCommand cmd) {
-        Connection conn = hypervisorResource.getConnection();
-        StorageFilerTO pool = cmd.getPool();
-        try {
-            if (pool.getType() == StoragePoolType.NetworkFilesystem) {
-                getNfsSR(conn, pool);
-            } else if (pool.getType() == StoragePoolType.IscsiLUN) {
-                getIscsiSR(conn, pool);
-            } else if (pool.getType() == StoragePoolType.PreSetup) {
-            } else {
-                return new Answer(cmd, false, "The pool type: " + pool.getType().name() + " is not supported.");
-            }
-            return new Answer(cmd, true, "success");
-        } catch (Exception e) {
-            String msg =
-                    "Catch Exception " + e.getClass().getName() + ", create StoragePool failed due to " + e.toString() + " on host:" +
-                            hypervisorResource.getHost().uuid + " pool: " + pool.getHost() + pool.getPath();
-            s_logger.warn(msg, e);
-            return new Answer(cmd, false, msg);
-        }
-
-    }
-
     protected Answer directDownloadHttpTemplate(CopyCommand cmd, DecodedDataObject srcObj, DecodedDataObject destObj) {
         Connection conn = hypervisorResource.getConnection();
         SR poolsr = null;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42d00cae/plugins/storage/volume/solidfire/pom.xml
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/solidfire/pom.xml b/plugins/storage/volume/solidfire/pom.xml
index c3cd11f..1803925 100644
--- a/plugins/storage/volume/solidfire/pom.xml
+++ b/plugins/storage/volume/solidfire/pom.xml
@@ -22,6 +22,11 @@
   <dependencies>
     <dependency>
       <groupId>org.apache.cloudstack</groupId>
+      <artifactId>cloud-plugin-storage-volume-default</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.cloudstack</groupId>
       <artifactId>cloud-engine-storage-volume</artifactId>
       <version>${project.version}</version>
     </dependency>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42d00cae/plugins/storage/volume/solidfire/resources/META-INF/cloudstack/storage-volume-solidfire/spring-storage-volume-solidfire-context.xml
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/solidfire/resources/META-INF/cloudstack/storage-volume-solidfire/spring-storage-volume-solidfire-context.xml b/plugins/storage/volume/solidfire/resources/META-INF/cloudstack/storage-volume-solidfire/spring-storage-volume-solidfire-context.xml
index a83e3ca..df32f1e 100644
--- a/plugins/storage/volume/solidfire/resources/META-INF/cloudstack/storage-volume-solidfire/spring-storage-volume-solidfire-context.xml
+++ b/plugins/storage/volume/solidfire/resources/META-INF/cloudstack/storage-volume-solidfire/spring-storage-volume-solidfire-context.xml
@@ -29,5 +29,7 @@
 
     <bean id="solidFireDataStoreProvider"
         class="org.apache.cloudstack.storage.datastore.provider.SolidfirePrimaryDataStoreProvider" />
-    
+    <bean id="solidFireSharedDataStoreProvider"
+        class="org.apache.cloudstack.storage.datastore.provider.SolidFireSharedPrimaryDataStoreProvider" />
+
 </beans>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42d00cae/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFireSharedPrimaryDataStoreDriver.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFireSharedPrimaryDataStoreDriver.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFireSharedPrimaryDataStoreDriver.java
new file mode 100644
index 0000000..a16408e
--- /dev/null
+++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFireSharedPrimaryDataStoreDriver.java
@@ -0,0 +1,65 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.storage.datastore.driver;
+
+import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
+import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
+import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
+import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
+import org.apache.cloudstack.storage.command.CommandResult;
+
+import com.cloud.agent.api.to.DataStoreTO;
+import com.cloud.agent.api.to.DataTO;
+
+public class SolidFireSharedPrimaryDataStoreDriver extends CloudStackPrimaryDataStoreDriverImpl {
+    @Override
+    public DataTO getTO(DataObject data) {
+        return null;
+    }
+
+    @Override
+    public DataStoreTO getStoreTO(DataStore store) {
+        return null;
+    }
+
+    @Override
+    public boolean canCopy(DataObject srcData, DataObject destData) {
+        return false;
+    }
+
+    @Override
+    public void copyAsync(DataObject srcdata, DataObject destData, AsyncCompletionCallback<CopyCommandResult> callback) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void resize(DataObject data, AsyncCompletionCallback<CreateCmdResult> callback) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CreateCmdResult> callback) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void revertSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CommandResult> callback) {
+        throw new UnsupportedOperationException();
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42d00cae/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 014413d..766e1f8 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,15 +17,11 @@
 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;
 
-import org.apache.commons.lang.StringUtils;
-
 import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo;
 import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
@@ -57,23 +53,20 @@ import com.cloud.storage.StoragePool;
 import com.cloud.storage.Volume;
 import com.cloud.storage.VolumeVO;
 import com.cloud.storage.dao.VolumeDao;
-import com.cloud.storage.dao.VolumeDetailsDao;
 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 ClusterDetailsDao _clusterDetailsDao;
+    @Inject private DataCenterDao _zoneDao;
     @Inject private HostDao _hostDao;
+    @Inject private PrimaryDataStoreDao _storagePoolDao;
+    @Inject private StoragePoolDetailsDao _storagePoolDetailsDao;
+    @Inject private VolumeDao _volumeDao;
 
     @Override
     public Map<String, String> getCapabilities() {
@@ -90,131 +83,10 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
         return null;
     }
 
-    private static class SolidFireConnection {
-        private final String _managementVip;
-        private final int _managementPort;
-        private final String _clusterAdminUsername;
-        private final String _clusterAdminPassword;
-
-        public SolidFireConnection(String managementVip, int managementPort, String clusterAdminUsername, String clusterAdminPassword) {
-            _managementVip = managementVip;
-            _managementPort = managementPort;
-            _clusterAdminUsername = clusterAdminUsername;
-            _clusterAdminPassword = clusterAdminPassword;
-        }
-
-        public String getManagementVip() {
-            return _managementVip;
-        }
-
-        public int getManagementPort() {
-            return _managementPort;
-        }
-
-        public String getClusterAdminUsername() {
-            return _clusterAdminUsername;
-        }
-
-        public String getClusterAdminPassword() {
-            return _clusterAdminPassword;
-        }
-    }
-
-    private SolidFireConnection getSolidFireConnection(long storagePoolId) {
-        StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.MANAGEMENT_VIP);
-
-        String mVip = storagePoolDetail.getValue();
-
-        storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.MANAGEMENT_PORT);
-
-        int mPort = Integer.parseInt(storagePoolDetail.getValue());
-
-        storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_ADMIN_USERNAME);
-
-        String clusterAdminUsername = storagePoolDetail.getValue();
-
-        storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_ADMIN_PASSWORD);
-
-        String clusterAdminPassword = storagePoolDetail.getValue();
-
-        return new SolidFireConnection(mVip, mPort, clusterAdminUsername, clusterAdminPassword);
-    }
-
-    private SolidFireUtil.SolidFireAccount createSolidFireAccount(String sfAccountName, SolidFireConnection sfConnection) {
-        String mVip = sfConnection.getManagementVip();
-        int mPort = sfConnection.getManagementPort();
-        String clusterAdminUsername = sfConnection.getClusterAdminUsername();
-        String clusterAdminPassword = sfConnection.getClusterAdminPassword();
-
-        long accountNumber = SolidFireUtil.createSolidFireAccount(mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfAccountName);
-
-        return SolidFireUtil.getSolidFireAccountById(mVip, mPort, clusterAdminUsername, clusterAdminPassword, accountNumber);
-    }
-
-    private void updateCsDbWithAccountInfo(long csAccountId, SolidFireUtil.SolidFireAccount sfAccount) {
-        AccountDetailVO accountDetail = new AccountDetailVO(csAccountId,
-                SolidFireUtil.ACCOUNT_ID,
-                String.valueOf(sfAccount.getId()));
-
-        _accountDetailsDao.persist(accountDetail);
-
-        accountDetail = new AccountDetailVO(csAccountId,
-                SolidFireUtil.CHAP_INITIATOR_USERNAME,
-                String.valueOf(sfAccount.getName()));
-
-        _accountDetailsDao.persist(accountDetail);
-
-        accountDetail = new AccountDetailVO(csAccountId,
-                SolidFireUtil.CHAP_INITIATOR_SECRET,
-                String.valueOf(sfAccount.getInitiatorSecret()));
-
-        _accountDetailsDao.persist(accountDetail);
-
-        accountDetail = new AccountDetailVO(csAccountId,
-                SolidFireUtil.CHAP_TARGET_USERNAME,
-                sfAccount.getName());
-
-        _accountDetailsDao.persist(accountDetail);
-
-        accountDetail = new AccountDetailVO(csAccountId,
-                SolidFireUtil.CHAP_TARGET_SECRET,
-                sfAccount.getTargetSecret());
-
-        _accountDetailsDao.persist(accountDetail);
-    }
-
-    private class ChapInfoImpl implements ChapInfo {
-        private final String _initiatorUsername;
-        private final String _initiatorSecret;
-        private final String _targetUsername;
-        private final String _targetSecret;
-
-        public ChapInfoImpl(String initiatorUsername, String initiatorSecret, String targetUsername, String targetSecret) {
-            _initiatorUsername = initiatorUsername;
-            _initiatorSecret = initiatorSecret;
-            _targetUsername = targetUsername;
-            _targetSecret = targetSecret;
-        }
-
-        @Override
-        public String getInitiatorUsername() {
-            return _initiatorUsername;
-        }
-
-        @Override
-        public String getInitiatorSecret() {
-            return _initiatorSecret;
-        }
-
-        @Override
-        public String getTargetUsername() {
-            return _targetUsername;
-        }
+    private SolidFireUtil.SolidFireAccount createSolidFireAccount(SolidFireUtil.SolidFireConnection sfConnection, String sfAccountName) {
+        long accountNumber = SolidFireUtil.createSolidFireAccount(sfConnection, sfAccountName);
 
-        @Override
-        public String getTargetSecret() {
-            return _targetSecret;
-        }
+        return SolidFireUtil.getSolidFireAccountById(sfConnection, accountNumber);
     }
 
     @Override
@@ -222,38 +94,13 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
         return null;
     }
 
-    /*
-    @Override
-    public ChapInfo getChapInfo(VolumeInfo volumeInfo) {
-        long accountId = volumeInfo.getAccountId();
-
-        AccountDetailVO accountDetail = _accountDetailsDao.findDetail(accountId, SolidFireUtil.CHAP_INITIATOR_USERNAME);
-
-        String chapInitiatorUsername = accountDetail.getValue();
-
-        accountDetail = _accountDetailsDao.findDetail(accountId, SolidFireUtil.CHAP_INITIATOR_SECRET);
-
-        String chapInitiatorSecret = accountDetail.getValue();
-
-        accountDetail = _accountDetailsDao.findDetail(accountId, SolidFireUtil.CHAP_TARGET_USERNAME);
-
-        String chapTargetUsername = accountDetail.getValue();
-
-        accountDetail = _accountDetailsDao.findDetail(accountId, SolidFireUtil.CHAP_TARGET_SECRET);
-
-        String chapTargetSecret = accountDetail.getValue();
-
-        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)
+    public synchronized boolean connectVolumeToHost(VolumeInfo volumeInfo, Host host, DataStore dataStore)
     {
         if (volumeInfo == null || host == null || dataStore == null) {
             return false;
@@ -263,111 +110,38 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
         long clusterId = host.getClusterId();
         long storagePoolId = dataStore.getId();
 
-        ClusterDetailsVO clusterDetail = _clusterDetailsDao.findDetail(clusterId, getVagKey(storagePoolId));
+        ClusterDetailsVO clusterDetail = _clusterDetailsDao.findDetail(clusterId, SolidFireUtil.getVagKey(storagePoolId));
 
         String vagId = clusterDetail != null ? clusterDetail.getValue() : null;
 
         List<HostVO> hosts = _hostDao.findByClusterId(clusterId);
 
-        if (!hostsSupport_iScsi(hosts)) {
+        if (!SolidFireUtil.hostsSupport_iScsi(hosts)) {
             return false;
         }
 
-        SolidFireConnection sfConnection = getSolidFireConnection(storagePoolId);
+        SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
 
         if (vagId != null) {
-            SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(),
-                sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), Long.parseLong(vagId));
+            SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection, Long.parseLong(vagId));
 
-            String[] hostIqns = getNewHostIqns(sfVag.getInitiators(), getIqnsFromHosts(hosts));
-            long[] volumeIds = getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, true);
+            String[] hostIqns = SolidFireUtil.getNewHostIqns(sfVag.getInitiators(), SolidFireUtil.getIqnsFromHosts(hosts));
+            long[] volumeIds = SolidFireUtil.getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, true);
 
-            SolidFireUtil.modifySolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(),
-                sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), sfVag.getId(),
-                hostIqns, volumeIds);
+            SolidFireUtil.modifySolidFireVag(sfConnection, sfVag.getId(), hostIqns, volumeIds);
         }
         else {
-            long lVagId;
-
-            try {
-                lVagId = SolidFireUtil.createSolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(),
-                    sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), "CloudStack-" + UUID.randomUUID().toString(),
-                    getIqnsFromHosts(hosts), new long[] { sfVolumeId });
-            }
-            catch (Exception ex) {
-                String iqnInVagAlready = "Exceeded maximum number of Volume Access Groups per initiator";
-
-                if (!ex.getMessage().contains(iqnInVagAlready)) {
-                    throw new CloudRuntimeException(ex.getMessage());
-                }
-
-                // getCompatibleVag throws an exception if an existing VAG can't be located
-                SolidFireUtil.SolidFireVag sfVag = getCompatibleVag(hosts, sfConnection);
-
-                long[] volumeIds = getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, true);
-
-                SolidFireUtil.modifySolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(),
-                    sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), sfVag.getId(),
-                    sfVag.getInitiators(), volumeIds);
-
-                lVagId = sfVag.getId();
-            }
-
-            clusterDetail = new ClusterDetailsVO(clusterId, getVagKey(storagePoolId), String.valueOf(lVagId));
-
-            _clusterDetailsDao.persist(clusterDetail);
+            SolidFireUtil.placeVolumeInVolumeAccessGroup(sfConnection, sfVolumeId, storagePoolId, hosts, _clusterDetailsDao);
         }
 
         return true;
     }
 
-    // this method takes in a collection of hosts and tries to find an existing VAG that has all three of them in it
-    // if successful, the VAG is returned; else, a CloudRuntimeException is thrown and this issue should be corrected by an admin
-    private SolidFireUtil.SolidFireVag getCompatibleVag(List<HostVO> hosts, SolidFireConnection sfConnection) {
-        List<SolidFireUtil.SolidFireVag> sfVags = SolidFireUtil.getAllSolidFireVags(sfConnection.getManagementVip(), sfConnection.getManagementPort(),
-                sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword());
-
-        if (sfVags != null) {
-            List<String> hostIqns = new ArrayList<String>();
-
-            // where the method we're in is called, hosts should not be null
-            for (HostVO host : hosts) {
-                // where the method we're in is called, host.getStorageUrl() should not be null (it actually should start with "iqn")
-                hostIqns.add(host.getStorageUrl().toLowerCase());
-            }
-
-            for (SolidFireUtil.SolidFireVag sfVag : sfVags) {
-                List<String> lstInitiators = getStringArrayAsLowerCaseStringList(sfVag.getInitiators());
-
-                // lstInitiators should not be returned from getStringArrayAsLowerCaseStringList as null
-                if (lstInitiators.containsAll(hostIqns)) {
-                    return sfVag;
-                }
-            }
-        }
-
-        throw new CloudRuntimeException("Unable to locate the appropriate SolidFire Volume Access Group");
-    }
-
-    private List<String> getStringArrayAsLowerCaseStringList(String[] aString) {
-        List<String> lstLowerCaseString = new ArrayList<String>();
-
-        if (aString != null) {
-            for (String str : aString) {
-                if (str != null) {
-                    lstLowerCaseString.add(str.toLowerCase());
-                }
-            }
-        }
-
-        return lstLowerCaseString;
-      }
-
     // 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)
+    public synchronized void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore)
     {
         if (volumeInfo == null || host == null || dataStore == null) {
             return;
@@ -377,133 +151,22 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
         long clusterId = host.getClusterId();
         long storagePoolId = dataStore.getId();
 
-        ClusterDetailsVO clusterDetail = _clusterDetailsDao.findDetail(clusterId, getVagKey(storagePoolId));
+        ClusterDetailsVO clusterDetail = _clusterDetailsDao.findDetail(clusterId, SolidFireUtil.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));
-
-            String[] hostIqns = getNewHostIqns(sfVag.getInitiators(), getIqnsFromHosts(hosts));
-            long[] volumeIds = getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, false);
+            SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
 
-            SolidFireUtil.modifySolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(),
-                sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), sfVag.getId(),
-                hostIqns, volumeIds);
-        }
-    }
+            SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection, Long.parseLong(vagId));
 
-    private boolean hostsSupport_iScsi(List<HostVO> hosts) {
-        if (hosts == null || hosts.size() == 0) {
-            return false;
-        }
+            String[] hostIqns = SolidFireUtil.getNewHostIqns(sfVag.getInitiators(), SolidFireUtil.getIqnsFromHosts(hosts));
+            long[] volumeIds = SolidFireUtil.getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, false);
 
-        for (Host host : hosts) {
-            if (host == null || host.getStorageUrl() == null || host.getStorageUrl().trim().length() == 0 || !host.getStorageUrl().startsWith("iqn")) {
-                return false;
-            }
+            SolidFireUtil.modifySolidFireVag(sfConnection, sfVag.getId(), hostIqns, volumeIds);
         }
-
-        return true;
-    }
-
-    private String[] getNewHostIqns(String[] currentIqns, String[] newIqns) {
-        List<String> lstIqns = new ArrayList<String>();
-
-        if (currentIqns != null) {
-            for (String currentIqn : currentIqns) {
-                lstIqns.add(currentIqn);
-            }
-        }
-
-        if (newIqns != null) {
-            for (String newIqn : newIqns) {
-                if (!lstIqns.contains(newIqn)) {
-                    lstIqns.add(newIqn);
-                }
-            }
-        }
-
-        return lstIqns.toArray(new String[0]);
-    }
-
-    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) {
@@ -532,12 +195,7 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
         return (long)(maxIops * fClusterDefaultBurstIopsPercentOfMaxIops);
     }
 
-    private SolidFireUtil.SolidFireVolume createSolidFireVolume(VolumeInfo volumeInfo, SolidFireConnection sfConnection) {
-        String mVip = sfConnection.getManagementVip();
-        int mPort = sfConnection.getManagementPort();
-        String clusterAdminUsername = sfConnection.getClusterAdminUsername();
-        String clusterAdminPassword = sfConnection.getClusterAdminPassword();
-
+    private SolidFireUtil.SolidFireVolume createSolidFireVolume(SolidFireUtil.SolidFireConnection sfConnection, VolumeInfo volumeInfo) {
         AccountDetailVO accountDetail = _accountDetailsDao.findDetail(volumeInfo.getAccountId(), SolidFireUtil.ACCOUNT_ID);
         long sfAccountId = Long.parseLong(accountDetail.getValue());
 
@@ -558,12 +216,10 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
 
         long volumeSize = getVolumeSizeIncludingHypervisorSnapshotReserve(volumeInfo, _storagePoolDao.findById(storagePoolId));
 
-        long sfVolumeId = SolidFireUtil.createSolidFireVolume(mVip, mPort, clusterAdminUsername, clusterAdminPassword,
-                getSolidFireVolumeName(volumeInfo.getName()), sfAccountId, volumeSize, true,
-                NumberFormat.getInstance().format(volumeInfo.getSize()),
-                iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops());
+        long sfVolumeId = SolidFireUtil.createSolidFireVolume(sfConnection, SolidFireUtil.getSolidFireVolumeName(volumeInfo.getName()), sfAccountId, volumeSize, true,
+                NumberFormat.getInstance().format(volumeInfo.getSize()), iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops());
 
-        return SolidFireUtil.getSolidFireVolume(mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfVolumeId);
+        return SolidFireUtil.getSolidFireVolume(sfConnection, sfVolumeId);
     }
 
     @Override
@@ -582,24 +238,6 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
         return volumeSize;
     }
 
-    private String getSolidFireVolumeName(String strCloudStackVolumeName) {
-        final String specialChar = "-";
-
-        StringBuilder strSolidFireVolumeName = new StringBuilder();
-
-        for (int i = 0; i < strCloudStackVolumeName.length(); i++) {
-            String strChar = strCloudStackVolumeName.substring(i, i + 1);
-
-            if (StringUtils.isAlphanumeric(strChar)) {
-                strSolidFireVolumeName.append(strChar);
-            } else {
-                strSolidFireVolumeName.append(specialChar);
-            }
-        }
-
-        return strSolidFireVolumeName.toString();
-    }
-
     private static class Iops {
         private final long _minIops;
         private final long _maxIops;
@@ -636,7 +274,7 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
         }
     }
 
-    private SolidFireUtil.SolidFireVolume deleteSolidFireVolume(VolumeInfo volumeInfo, SolidFireConnection sfConnection)
+    private SolidFireUtil.SolidFireVolume deleteSolidFireVolume(SolidFireUtil.SolidFireConnection sfConnection, VolumeInfo volumeInfo)
     {
         Long storagePoolId = volumeInfo.getPoolId();
 
@@ -644,33 +282,9 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
             return null; // this volume was never assigned to a storage pool, so no SAN volume should exist for it
         }
 
-        String mVip = sfConnection.getManagementVip();
-        int mPort = sfConnection.getManagementPort();
-        String clusterAdminUsername = sfConnection.getClusterAdminUsername();
-        String clusterAdminPassword = sfConnection.getClusterAdminPassword();
-
         long sfVolumeId = Long.parseLong(volumeInfo.getFolder());
 
-        return SolidFireUtil.deleteSolidFireVolume(mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfVolumeId);
-    }
-
-    private String getSfAccountName(String csAccountUuid, long csAccountId) {
-        return "CloudStack_" + csAccountUuid + "_" + csAccountId;
-    }
-
-    private boolean sfAccountExists(String sfAccountName, SolidFireConnection sfConnection) {
-        String mVip = sfConnection.getManagementVip();
-        int mPort = sfConnection.getManagementPort();
-        String clusterAdminUsername = sfConnection.getClusterAdminUsername();
-        String clusterAdminPassword = sfConnection.getClusterAdminPassword();
-
-        try {
-            SolidFireUtil.getSolidFireAccountByName(mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfAccountName);
-        } catch (Exception ex) {
-            return false;
-        }
-
-        return true;
+        return SolidFireUtil.deleteSolidFireVolume(sfConnection, sfVolumeId);
     }
 
     @Override
@@ -681,18 +295,18 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
         if (dataObject.getType() == DataObjectType.VOLUME) {
             VolumeInfo volumeInfo = (VolumeInfo)dataObject;
             AccountVO account = _accountDao.findById(volumeInfo.getAccountId());
-            String sfAccountName = getSfAccountName(account.getUuid(), account.getAccountId());
+            String sfAccountName = SolidFireUtil.getSolidFireAccountName(account.getUuid(), account.getAccountId());
 
             long storagePoolId = dataStore.getId();
-            SolidFireConnection sfConnection = getSolidFireConnection(storagePoolId);
+            SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
 
-            if (!sfAccountExists(sfAccountName, sfConnection)) {
-                SolidFireUtil.SolidFireAccount sfAccount = createSolidFireAccount(sfAccountName, sfConnection);
+            if (SolidFireUtil.getSolidFireAccount(sfConnection, sfAccountName) == null) {
+                SolidFireUtil.SolidFireAccount sfAccount = createSolidFireAccount(sfConnection, sfAccountName);
 
-                updateCsDbWithAccountInfo(account.getId(), sfAccount);
+                SolidFireUtil.updateCsDbWithSolidFireAccountInfo(account.getId(), sfAccount, _accountDetailsDao);
             }
 
-            SolidFireUtil.SolidFireVolume sfVolume = createSolidFireVolume(volumeInfo, sfConnection);
+            SolidFireUtil.SolidFireVolume sfVolume = createSolidFireVolume(sfConnection, volumeInfo);
 
             iqn = sfVolume.getIqn();
 
@@ -728,74 +342,20 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
         callback.complete(result);
     }
 
-    /*
-    private void deleteSolidFireAccount(long sfAccountId, SolidFireConnection sfConnection) {
-        String mVip = sfConnection.getManagementVip();
-        int mPort = sfConnection.getManagementPort();
-        String clusterAdminUsername = sfConnection.getClusterAdminUsername();
-        String clusterAdminPassword = sfConnection.getClusterAdminPassword();
-
-        List<SolidFireUtil.SolidFireVolume> sfVolumes = SolidFireUtil.getDeletedVolumes(mVip, mPort, clusterAdminUsername, clusterAdminPassword);
-
-        // if there are volumes for this account in the trash, delete them (so the account can be deleted)
-        if (sfVolumes != null) {
-            for (SolidFireUtil.SolidFireVolume sfVolume : sfVolumes) {
-                if (sfVolume.getAccountId() == sfAccountId) {
-                    SolidFireUtil.purgeSolidFireVolume(mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfVolume.getId());
-                }
-            }
-        }
-
-        SolidFireUtil.deleteSolidFireAccount(mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfAccountId);
-    }
-
-    private boolean sfAccountHasVolume(long sfAccountId, SolidFireConnection sfConnection) {
-        String mVip = sfConnection.getManagementVip();
-        int mPort = sfConnection.getManagementPort();
-        String clusterAdminUsername = sfConnection.getClusterAdminUsername();
-        String clusterAdminPassword = sfConnection.getClusterAdminPassword();
-
-        List<SolidFireUtil.SolidFireVolume> sfVolumes =
-            SolidFireUtil.getSolidFireVolumesForAccountId(mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfAccountId);
-
-        if (sfVolumes != null) {
-            for (SolidFireUtil.SolidFireVolume sfVolume : sfVolumes) {
-                if (sfVolume.isActive()) {
-                    return true;
-                }
-            }
-        }
-
-        return false;
-    }
-    */
-
     @Override
     public void deleteAsync(DataStore dataStore, DataObject dataObject, AsyncCompletionCallback<CommandResult> callback) {
         String errMsg = null;
 
         if (dataObject.getType() == DataObjectType.VOLUME) {
             VolumeInfo volumeInfo = (VolumeInfo)dataObject;
-            // AccountVO account = _accountDao.findById(volumeInfo.getAccountId());
-            // AccountDetailVO accountDetails = _accountDetailsDao.findDetail(account.getAccountId(), SolidFireUtil.ACCOUNT_ID);
-            // long sfAccountId = Long.parseLong(accountDetails.getValue());
 
             long storagePoolId = dataStore.getId();
-            SolidFireConnection sfConnection = getSolidFireConnection(storagePoolId);
+            SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
 
-            SolidFireUtil.SolidFireVolume sfVolume = deleteSolidFireVolume(volumeInfo, sfConnection);
+            SolidFireUtil.SolidFireVolume sfVolume = deleteSolidFireVolume(sfConnection, volumeInfo);
 
             _volumeDao.deleteVolumesByInstance(volumeInfo.getId());
 
-            //  if (!sfAccountHasVolume(sfAccountId, sfConnection)) {
-            //      // delete the account from the SolidFire SAN
-            //      deleteSolidFireAccount(sfAccountId, sfConnection);
-            //
-            //      // delete the info in the account_details table
-            //      // that's related to the SolidFire account
-            //      _accountDetailsDao.deleteDetails(account.getAccountId());
-            //  }
-
             StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId);
 
             long usedBytes = storagePool.getUsedBytes();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42d00cae/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java
index d30374f..7fc3436 100644
--- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java
+++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java
@@ -21,7 +21,6 @@ package org.apache.cloudstack.storage.datastore.lifecycle;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
-import java.util.StringTokenizer;
 
 import javax.inject.Inject;
 
@@ -34,7 +33,6 @@ import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCy
 import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreParameters;
 import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
-import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
 import org.apache.cloudstack.storage.datastore.util.SolidFireUtil;
 import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper;
 
@@ -61,14 +59,9 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
     @Inject
     private ResourceManager _resourceMgr;
     @Inject
-    StorageManager _storageMgr;
+    private StorageManager _storageMgr;
     @Inject
     private StoragePoolAutomation storagePoolAutomation;
-    @Inject
-    private StoragePoolDetailsDao storagePoolDetailsDao;
-
-    private static final int DEFAULT_MANAGEMENT_PORT = 443;
-    private static final int DEFAULT_STORAGE_PORT = 3260;
 
     // invoked to add primary storage that is based on the SolidFire plug-in
     @Override
@@ -80,10 +73,11 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
         Long capacityBytes = (Long)dsInfos.get("capacityBytes");
         Long capacityIops = (Long)dsInfos.get("capacityIops");
         String tags = (String)dsInfos.get("tags");
+        @SuppressWarnings("unchecked")
         Map<String, String> details = (Map<String, String>)dsInfos.get("details");
 
-        String storageVip = getStorageVip(url);
-        int storagePort = getStoragePort(url);
+        String storageVip = SolidFireUtil.getStorageVip(url);
+        int storagePort = SolidFireUtil.getStoragePort(url);
 
         DataCenterVO zone = zoneDao.findById(zoneId);
 
@@ -101,7 +95,7 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
 
         parameters.setHost(storageVip);
         parameters.setPort(storagePort);
-        parameters.setPath(getModifiedUrl(url));
+        parameters.setPath(SolidFireUtil.getModifiedUrl(url));
         parameters.setType(StoragePoolType.Iscsi);
         parameters.setUuid(uuid);
         parameters.setZoneId(zoneId);
@@ -115,14 +109,14 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
         parameters.setTags(tags);
         parameters.setDetails(details);
 
-        String managementVip = getManagementVip(url);
-        int managementPort = getManagementPort(url);
+        String managementVip = SolidFireUtil.getManagementVip(url);
+        int managementPort = SolidFireUtil.getManagementPort(url);
 
         details.put(SolidFireUtil.MANAGEMENT_VIP, managementVip);
         details.put(SolidFireUtil.MANAGEMENT_PORT, String.valueOf(managementPort));
 
-        String clusterAdminUsername = getValue(SolidFireUtil.CLUSTER_ADMIN_USERNAME, url);
-        String clusterAdminPassword = getValue(SolidFireUtil.CLUSTER_ADMIN_PASSWORD, url);
+        String clusterAdminUsername = SolidFireUtil.getValue(SolidFireUtil.CLUSTER_ADMIN_USERNAME, url);
+        String clusterAdminPassword = SolidFireUtil.getValue(SolidFireUtil.CLUSTER_ADMIN_PASSWORD, url);
 
         details.put(SolidFireUtil.CLUSTER_ADMIN_USERNAME, clusterAdminUsername);
         details.put(SolidFireUtil.CLUSTER_ADMIN_PASSWORD, clusterAdminPassword);
@@ -132,7 +126,7 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
         float fClusterDefaultBurstIopsPercentOfMaxIops = 1.5f;
 
         try {
-            String clusterDefaultMinIops = getValue(SolidFireUtil.CLUSTER_DEFAULT_MIN_IOPS, url);
+            String clusterDefaultMinIops = SolidFireUtil.getValue(SolidFireUtil.CLUSTER_DEFAULT_MIN_IOPS, url);
 
             if (clusterDefaultMinIops != null && clusterDefaultMinIops.trim().length() > 0) {
                 lClusterDefaultMinIops = Long.parseLong(clusterDefaultMinIops);
@@ -144,7 +138,7 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
         }
 
         try {
-            String clusterDefaultMaxIops = getValue(SolidFireUtil.CLUSTER_DEFAULT_MAX_IOPS, url);
+            String clusterDefaultMaxIops = SolidFireUtil.getValue(SolidFireUtil.CLUSTER_DEFAULT_MAX_IOPS, url);
 
             if (clusterDefaultMaxIops != null && clusterDefaultMaxIops.trim().length() > 0) {
                 lClusterDefaultMaxIops = Long.parseLong(clusterDefaultMaxIops);
@@ -156,7 +150,7 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
         }
 
         try {
-            String clusterDefaultBurstIopsPercentOfMaxIops = getValue(SolidFireUtil.CLUSTER_DEFAULT_BURST_IOPS_PERCENT_OF_MAX_IOPS, url);
+            String clusterDefaultBurstIopsPercentOfMaxIops = SolidFireUtil.getValue(SolidFireUtil.CLUSTER_DEFAULT_BURST_IOPS_PERCENT_OF_MAX_IOPS, url);
 
             if (clusterDefaultBurstIopsPercentOfMaxIops != null && clusterDefaultBurstIopsPercentOfMaxIops.trim().length() > 0) {
                 fClusterDefaultBurstIopsPercentOfMaxIops = Float.parseFloat(clusterDefaultBurstIopsPercentOfMaxIops);
@@ -168,7 +162,7 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
         }
 
         if (lClusterDefaultMinIops > lClusterDefaultMaxIops) {
-            throw new CloudRuntimeException("The parameter '" + SolidFireUtil.CLUSTER_DEFAULT_MIN_IOPS + "' must be less than " + "or equal to the parameter '" +
+            throw new CloudRuntimeException("The parameter '" + SolidFireUtil.CLUSTER_DEFAULT_MIN_IOPS + "' must be less than or equal to the parameter '" +
                 SolidFireUtil.CLUSTER_DEFAULT_MAX_IOPS + "'.");
         }
 
@@ -184,111 +178,6 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
         return dataStoreHelper.createPrimaryDataStore(parameters);
     }
 
-    // remove the clusterAdmin and password key/value pairs
-    private String getModifiedUrl(String originalUrl) {
-        StringBuilder sb = new StringBuilder();
-
-        String delimiter = ";";
-
-        StringTokenizer st = new StringTokenizer(originalUrl, delimiter);
-
-        while (st.hasMoreElements()) {
-            String token = st.nextElement().toString().toUpperCase();
-
-            if (token.startsWith(SolidFireUtil.MANAGEMENT_VIP.toUpperCase()) || token.startsWith(SolidFireUtil.STORAGE_VIP.toUpperCase())) {
-                sb.append(token).append(delimiter);
-            }
-        }
-
-        String modifiedUrl = sb.toString();
-        int lastIndexOf = modifiedUrl.lastIndexOf(delimiter);
-
-        if (lastIndexOf == (modifiedUrl.length() - delimiter.length())) {
-            return modifiedUrl.substring(0, lastIndexOf);
-        }
-
-        return modifiedUrl;
-    }
-
-    private String getManagementVip(String url) {
-        return getVip(SolidFireUtil.MANAGEMENT_VIP, url);
-    }
-
-    private String getStorageVip(String url) {
-        return getVip(SolidFireUtil.STORAGE_VIP, url);
-    }
-
-    private int getManagementPort(String url) {
-        return getPort(SolidFireUtil.MANAGEMENT_VIP, url, DEFAULT_MANAGEMENT_PORT);
-    }
-
-    private int getStoragePort(String url) {
-        return getPort(SolidFireUtil.STORAGE_VIP, url, DEFAULT_STORAGE_PORT);
-    }
-
-    private String getVip(String keyToMatch, String url) {
-        String delimiter = ":";
-
-        String storageVip = getValue(keyToMatch, url);
-
-        int index = storageVip.indexOf(delimiter);
-
-        if (index != -1) {
-            return storageVip.substring(0, index);
-        }
-
-        return storageVip;
-    }
-
-    private int getPort(String keyToMatch, String url, int defaultPortNumber) {
-        String delimiter = ":";
-
-        String storageVip = getValue(keyToMatch, url);
-
-        int index = storageVip.indexOf(delimiter);
-
-        int portNumber = defaultPortNumber;
-
-        if (index != -1) {
-            String port = storageVip.substring(index + delimiter.length());
-
-            try {
-                portNumber = Integer.parseInt(port);
-            } catch (NumberFormatException ex) {
-                throw new IllegalArgumentException("Invalid URL format (port is not an integer)");
-            }
-        }
-
-        return portNumber;
-    }
-
-    private String getValue(String keyToMatch, String url) {
-        String delimiter1 = ";";
-        String delimiter2 = "=";
-
-        StringTokenizer st = new StringTokenizer(url, delimiter1);
-
-        while (st.hasMoreElements()) {
-            String token = st.nextElement().toString();
-
-            int index = token.indexOf(delimiter2);
-
-            if (index == -1) {
-                throw new RuntimeException("Invalid URL format");
-            }
-
-            String key = token.substring(0, index);
-
-            if (key.equalsIgnoreCase(keyToMatch)) {
-                String valueToReturn = token.substring(index + delimiter2.length());
-
-                return valueToReturn;
-            }
-        }
-
-        throw new RuntimeException("Key not found in URL");
-    }
-
     // do not implement this method for SolidFire's plug-in
     @Override
     public boolean attachHost(DataStore store, HostScope scope, StoragePoolInfo existingInfo) {