You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by mt...@apache.org on 2013/06/29 01:02:51 UTC

[3/4] SolidFire plug-in and related changes

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/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 5c51585..52f4190 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
@@ -36,6 +36,9 @@ import java.util.Map;
 import java.util.Random;
 import java.util.TimeZone;
 import java.util.UUID;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Map.Entry;
 
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
@@ -216,6 +219,8 @@ import com.cloud.hypervisor.vmware.mo.HostMO;
 import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper;
 import com.cloud.hypervisor.vmware.mo.NetworkDetails;
 import com.cloud.hypervisor.vmware.mo.VirtualEthernetCardType;
+import com.cloud.hypervisor.vmware.mo.HostDatastoreSystemMO;
+import com.cloud.hypervisor.vmware.mo.HostStorageSystemMO;
 import com.cloud.hypervisor.vmware.mo.VirtualMachineMO;
 import com.cloud.hypervisor.vmware.mo.VirtualSwitchType;
 import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost;
@@ -229,7 +234,6 @@ import com.cloud.network.HAProxyConfigurator;
 import com.cloud.network.LoadBalancerConfigurator;
 import com.cloud.network.Networks;
 import com.cloud.network.Networks.BroadcastDomainType;
-import com.cloud.network.Networks.IsolationType;
 import com.cloud.network.Networks.TrafficType;
 import com.cloud.network.VmwareTrafficLabel;
 import com.cloud.network.rules.FirewallRule;
@@ -272,8 +276,16 @@ import com.vmware.vim25.GuestInfo;
 import com.vmware.vim25.HostCapability;
 import com.vmware.vim25.HostFirewallInfo;
 import com.vmware.vim25.HostFirewallRuleset;
-import com.vmware.vim25.HostNetworkTrafficShapingPolicy;
-import com.vmware.vim25.HostPortGroupSpec;
+import com.vmware.vim25.HostHostBusAdapter;
+import com.vmware.vim25.HostInternetScsiTargetTransport;
+import com.vmware.vim25.HostScsiTopology;
+import com.vmware.vim25.HostInternetScsiHba;
+import com.vmware.vim25.HostInternetScsiHbaAuthenticationProperties;
+import com.vmware.vim25.HostInternetScsiHbaStaticTarget;
+import com.vmware.vim25.HostScsiDisk;
+import com.vmware.vim25.HostScsiTopologyInterface;
+import com.vmware.vim25.HostScsiTopologyLun;
+import com.vmware.vim25.HostScsiTopologyTarget;
 import com.vmware.vim25.ManagedObjectReference;
 import com.vmware.vim25.ObjectContent;
 import com.vmware.vim25.OptionValue;
@@ -304,10 +316,6 @@ import com.vmware.vim25.VirtualMachineRelocateSpecDiskLocator;
 import com.vmware.vim25.VirtualMachineRuntimeInfo;
 import com.vmware.vim25.VirtualSCSISharing;
 
-import java.util.HashSet;
-import java.util.Set;
-import java.util.Map.Entry;
-
 public class VmwareResource implements StoragePoolResource, ServerResource, VmwareHostService {
     private static final Logger s_logger = Logger.getLogger(VmwareResource.class);
 
@@ -593,7 +601,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
 
         try {
             VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext());
-            ManagedObjectReference morDc = hyperHost.getHyperHostDatacenter();
             // find VM through datacenter (VM is not at the target host yet)
             VirtualMachineMO vmMo = hyperHost.findVmOnPeerHyperHost(vmName);
             if (vmMo == null) {
@@ -3244,7 +3251,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
             HashMap<String, State> newStates = getVmStates();
 
             List<String> requestedVmNames = cmd.getVmNames();
-            List<String> vmNames = new ArrayList();
+            List<String> vmNames = new ArrayList<String>();
 
             if (requestedVmNames != null) {
                 for (String vmName : requestedVmNames) {
@@ -3750,8 +3757,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
             s_logger.info("Executing resource MigrateVolumeCommand: " + _gson.toJson(cmd));
         }
 
-        VmwareContext context = getServiceContext();
-        VmwareManager mgr = context.getStockObject(VmwareManager.CONTEXT_STOCK_NAME);
         final String vmName = volMgr.getVmNameFromVolumeId(cmd.getVolumeId());
 
         VirtualMachineMO vmMo = null;
@@ -3903,6 +3908,45 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
         }
     }
 
+    protected ManagedObjectReference handleDatastoreAndVmdk(AttachVolumeCommand cmd) throws Exception {
+        ManagedObjectReference morDs = null;
+
+        VmwareContext context = getServiceContext();
+        VmwareHypervisorHost hyperHost = getHyperHost(context);
+
+        String iqn = cmd.get_iScsiName();
+
+        if (cmd.getAttach()) {
+            morDs = createVmfsDatastore(hyperHost, iqn,
+                        cmd.getStorageHost(), cmd.getStoragePort(), iqn,
+                        cmd.getChapInitiatorUsername(), cmd.getChapInitiatorPassword(),
+                        cmd.getChapTargetUsername(), cmd.getChapTargetPassword());
+
+            DatastoreMO dsMo = new DatastoreMO(context, morDs);
+
+            String volumeDatastorePath = String.format("[%s] %s.vmdk", dsMo.getName(), dsMo.getName());
+
+            if (!dsMo.fileExists(volumeDatastorePath)) {
+                String dummyVmName = getWorkerName(context, cmd, 0);
+
+                VirtualMachineMO vmMo = prepareVolumeHostDummyVm(hyperHost, dsMo, dummyVmName);
+
+                if (vmMo == null) {
+                    throw new Exception("Unable to create a dummy VM for volume creation");
+                }
+
+                vmMo.createDisk(volumeDatastorePath, (int)(dsMo.getSummary().getFreeSpace() / (1024L * 1024L)),
+                		morDs, vmMo.getScsiDeviceControllerKey());
+                vmMo.detachDisk(volumeDatastorePath, false);
+        	}
+        }
+        else {
+        	deleteVmfsDatastore(hyperHost, iqn, cmd.getStorageHost(), cmd.getStoragePort(), iqn);
+        }
+
+    	return morDs;
+    }
+
     protected Answer execute(AttachVolumeCommand cmd) {
         if (s_logger.isInfoEnabled()) {
             s_logger.info("Executing resource AttachVolumeCommand: " + _gson.toJson(cmd));
@@ -3922,7 +3966,15 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
                 throw new Exception(msg);
             }
 
-            ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, cmd.getPoolUuid());
+            ManagedObjectReference morDs = null;
+
+            if (cmd.getAttach() && cmd.isManaged()) {
+            	morDs = handleDatastoreAndVmdk(cmd);
+            }
+            else {
+            	morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, cmd.getPoolUuid());
+            }
+
             if (morDs == null) {
                 String msg = "Unable to find the mounted datastore to execute AttachVolumeCommand, vmName: " + cmd.getVmName();
                 s_logger.error(msg);
@@ -3933,12 +3985,16 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
             String datastoreVolumePath = dsMo.searchFileInSubFolders(cmd.getVolumePath() + ".vmdk", true);
             assert (datastoreVolumePath != null) : "Virtual disk file must exist in specified datastore for attach/detach operations.";
 
-            AttachVolumeAnswer answer = new AttachVolumeAnswer(cmd, cmd.getDeviceId());
+            AttachVolumeAnswer answer = new AttachVolumeAnswer(cmd, cmd.getDeviceId(), datastoreVolumePath);
             if (cmd.getAttach()) {
                 vmMo.attachDisk(new String[] { datastoreVolumePath }, morDs);
             } else {
                 vmMo.removeAllSnapshots();
                 vmMo.detachDisk(datastoreVolumePath, false);
+
+                if (cmd.isManaged()) {
+                	handleDatastoreAndVmdk(cmd);
+                }
             }
 
             return answer;
@@ -3954,6 +4010,198 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
         }
     }
 
+    private ManagedObjectReference createVmfsDatastore(VmwareHypervisorHost hyperHost, String datastoreName, String storageIpAddress,
+            int storagePortNumber, String iqn, String chapName, String chapSecret, String mutualChapName, String mutualChapSecret) throws Exception {
+        VmwareContext context = getServiceContext();
+        ManagedObjectReference morCluster = hyperHost.getHyperHostCluster();
+        ClusterMO cluster = new ClusterMO(context, morCluster);
+        List<Pair<ManagedObjectReference, String>> lstHosts = cluster.getClusterHosts();
+
+        HostInternetScsiHbaStaticTarget target = new HostInternetScsiHbaStaticTarget();
+
+        target.setAddress(storageIpAddress);
+        target.setPort(storagePortNumber);
+        target.setIScsiName(iqn);
+
+        HostInternetScsiHbaAuthenticationProperties auth = new HostInternetScsiHbaAuthenticationProperties();
+
+        String strAuthType = "chapRequired";
+
+        auth.setChapAuthEnabled(true);
+        auth.setChapInherited(false);
+        auth.setChapAuthenticationType(strAuthType);
+        auth.setChapName(chapName);
+        auth.setChapSecret(chapSecret);
+        auth.setMutualChapInherited(false);
+        auth.setMutualChapAuthenticationType(strAuthType);
+        auth.setMutualChapName(mutualChapName);
+        auth.setMutualChapSecret(mutualChapSecret);
+
+        target.setAuthenticationProperties(auth);
+
+        final List<HostInternetScsiHbaStaticTarget> lstTargets = new ArrayList<HostInternetScsiHbaStaticTarget>();
+
+        lstTargets.add(target);
+
+        HostDatastoreSystemMO hostDatastoreSystem = null;
+        HostStorageSystemMO hostStorageSystem = null;
+
+        final List<Thread> threads = new ArrayList<Thread>();
+        final List<Exception> exceptions = new ArrayList<Exception>();
+
+        for (Pair<ManagedObjectReference, String> hostPair : lstHosts) {
+            HostMO host = new HostMO(context, hostPair.first());
+            hostDatastoreSystem = host.getHostDatastoreSystemMO();
+            hostStorageSystem = host.getHostStorageSystemMO();
+
+            boolean iScsiHbaConfigured = false;
+
+            for (HostHostBusAdapter hba : hostStorageSystem.getStorageDeviceInfo().getHostBusAdapter()) {
+                if (hba instanceof HostInternetScsiHba) {
+                    // just finding an instance of HostInternetScsiHba means that we have found at least one configured iSCSI HBA
+                    // at least one iSCSI HBA must be configured before a CloudStack user can use this host for iSCSI storage
+                    iScsiHbaConfigured = true;
+
+                    final String iScsiHbaDevice = hba.getDevice();
+
+                    final HostStorageSystemMO hss = hostStorageSystem;
+
+                    threads.add(new Thread() {
+                        public void run() {
+                            try {
+                                hss.addInternetScsiStaticTargets(iScsiHbaDevice, lstTargets);
+
+                                hss.rescanHba(iScsiHbaDevice);
+                            }
+                            catch (Exception ex) {
+                                synchronized (exceptions) {
+                                    exceptions.add(ex);
+                                }
+                            }
+                        }
+                    });
+                }
+            }
+
+            if (!iScsiHbaConfigured) {
+                throw new Exception("An iSCSI HBA must be configured before a host can use iSCSI storage.");
+            }
+        }
+
+        for (Thread thread : threads) {
+            thread.start();
+        }
+
+        for (Thread thread : threads) {
+            thread.join();
+        }
+
+        if (exceptions.size() > 0) {
+            throw new Exception(exceptions.get(0).getMessage());
+        }
+
+        ManagedObjectReference morDs = hostDatastoreSystem.findDatastore(iqn);
+
+        if (morDs != null) {
+            return morDs;
+        }
+
+        List<HostScsiDisk> lstHostScsiDisks = hostDatastoreSystem.queryAvailableDisksForVmfs();
+
+        HostScsiDisk hostScsiDisk = getHostScsiDisk(hostStorageSystem.getStorageDeviceInfo().getScsiTopology(), lstHostScsiDisks, iqn);
+
+        if (hostScsiDisk == null) {
+            throw new Exception("A relevant SCSI disk could not be located to use to create a datastore.");
+        }
+
+        return hostDatastoreSystem.createVmfsDatastore(datastoreName, hostScsiDisk);
+    }
+
+    // the purpose of this method is to find the HostScsiDisk in the passed-in array that exists (if any) because
+    // we added the static iqn to an iSCSI HBA
+    private static HostScsiDisk getHostScsiDisk(HostScsiTopology hst, List<HostScsiDisk> lstHostScsiDisks, String iqn) {
+        for (HostScsiTopologyInterface adapter : hst.getAdapter()) {
+            if (adapter.getTarget() != null) {
+                for (HostScsiTopologyTarget target : adapter.getTarget()) {
+                    if (target.getTransport() instanceof HostInternetScsiTargetTransport) {
+                        String iScsiName = ((HostInternetScsiTargetTransport)target.getTransport()).getIScsiName();
+
+                        if (iqn.equals(iScsiName)) {
+                            for (HostScsiDisk hostScsiDisk : lstHostScsiDisks) {
+                                for (HostScsiTopologyLun hstl : target.getLun()) {
+                                    if (hstl.getScsiLun().contains(hostScsiDisk.getUuid())) {
+                                        return hostScsiDisk;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        return null;
+    }
+
+    private void deleteVmfsDatastore(VmwareHypervisorHost hyperHost, String volumeUuid,
+            String storageIpAddress, int storagePortNumber, String iqn) throws Exception {
+        // hyperHost.unmountDatastore(volumeUuid);
+
+        VmwareContext context = getServiceContext();
+        ManagedObjectReference morCluster = hyperHost.getHyperHostCluster();
+        ClusterMO cluster = new ClusterMO(context, morCluster);
+        List<Pair<ManagedObjectReference, String>> lstHosts = cluster.getClusterHosts();
+
+        HostInternetScsiHbaStaticTarget target = new HostInternetScsiHbaStaticTarget();
+
+        target.setAddress(storageIpAddress);
+        target.setPort(storagePortNumber);
+        target.setIScsiName(iqn);
+
+        final List<HostInternetScsiHbaStaticTarget> lstTargets = new ArrayList<HostInternetScsiHbaStaticTarget>();
+
+        lstTargets.add(target);
+
+        final List<Thread> threads = new ArrayList<Thread>();
+        final List<Exception> exceptions = new ArrayList<Exception>();
+
+        for (Pair<ManagedObjectReference, String> hostPair : lstHosts) {
+            final HostMO host = new HostMO(context, hostPair.first());
+            final HostStorageSystemMO hostStorageSystem = host.getHostStorageSystemMO();
+
+            for (HostHostBusAdapter hba : hostStorageSystem.getStorageDeviceInfo().getHostBusAdapter()) {
+                if (hba instanceof HostInternetScsiHba) {
+                    final String iScsiHbaDevice = hba.getDevice();
+
+                    Thread thread = new Thread() {
+                        public void run() {
+                            try {
+                                hostStorageSystem.removeInternetScsiStaticTargets(iScsiHbaDevice, lstTargets);
+
+                                hostStorageSystem.rescanHba(iScsiHbaDevice);
+                            }
+                            catch (Exception ex) {
+                                exceptions.add(ex);
+                            }
+                        }
+                    };
+
+                    threads.add(thread);
+
+                    thread.start();
+                }
+            }
+        }
+
+        for (Thread thread : threads) {
+            thread.join();
+        }
+
+        if (exceptions.size() > 0) {
+            throw new Exception(exceptions.get(0).getMessage());
+        }
+    }
+
     protected Answer execute(AttachIsoCommand cmd) {
         if (s_logger.isInfoEnabled()) {
             s_logger.info("Executing resource AttachIsoCommand: " + _gson.toJson(cmd));

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
index cbbec7c..d9c357d 100644
--- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
+++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
@@ -4172,11 +4172,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
                             for (VIF vif : vifs) {
                                 networks.add(vif.getNetwork(conn));
                             }
-                            List<VDI> vdis = getVdis(conn, vm);
                             vm.destroy(conn);
-                            for( VDI vdi : vdis ){
-                                umount(conn, vdi);
-                            }
                             state = State.Stopped;
                             SR sr = getISOSRbyVmName(conn, cmd.getVmName());
                             removeSR(conn, sr);
@@ -4479,7 +4475,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
         throw new CloudRuntimeException("Could not find available VIF slot in VM with name: " + vmName);
     }
 
-    protected VDI mount(Connection conn, StoragePoolType pooltype, String volumeFolder, String volumePath) {
+    protected VDI mount(Connection conn, StoragePoolType poolType, String volumeFolder, String volumePath) {
         return getVDIbyUuid(conn, volumePath);
     }
 
@@ -5549,7 +5545,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
             if (pool.getType() == StoragePoolType.NetworkFilesystem) {
                 getNfsSR(conn, pool);
             } else if (pool.getType() == StoragePoolType.IscsiLUN) {
-                getIscsiSR(conn, pool);
+                getIscsiSR(conn, pool.getUuid(), pool.getHost(), pool.getPath(), null, null, new Boolean[1]);
             } else if (pool.getType() == StoragePoolType.PreSetup) {
             } else {
                 return new Answer(cmd, false, "The pool type: " + pool.getType().name() + " is not supported.");
@@ -6229,7 +6225,6 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
 
     public Answer execute(ResizeVolumeCommand cmd) {
         Connection conn = getConnection();
-        StorageFilerTO pool = cmd.getPool();
         String volid = cmd.getPath();
         long newSize = cmd.getNewSize();
 
@@ -6367,19 +6362,18 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
         }
     }
 
-    protected SR getIscsiSR(Connection conn, StorageFilerTO pool) {
-        synchronized (pool.getUuid().intern()) {
+    protected SR getIscsiSR(Connection conn, String srNameLabel, String target, String path,
+    		String chapInitiatorUsername, String chapInitiatorPassword, Boolean[] created) {
+        synchronized (srNameLabel.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";
+                    String msg = "Wrong iscsi path " + path + " it should be /targetIQN/LUN";
                     s_logger.warn(msg);
                     throw new CloudRuntimeException(msg);
                 }
@@ -6387,7 +6381,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
                 String lunid = tmp[2].trim();
                 String scsiid = "";
 
-                Set<SR> srs = SR.getByNameLabel(conn, pool.getUuid());
+                Set<SR> srs = SR.getByNameLabel(conn, srNameLabel);
                 for (SR sr : srs) {
                     if (!SRType.LVMOISCSI.equals(sr.getType(conn))) {
                         continue;
@@ -6412,19 +6406,24 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
                     }
                     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:" + _host.uuid);
+                                + dc.get("targetIQN")  + ", lunid:" + dc.get("lunid") + " for pool " + srNameLabel + "on host:" + _host.uuid);
                     }
                 }
                 deviceConfig.put("target", target);
                 deviceConfig.put("targetIQN", targetiqn);
 
+                if (StringUtils.isNotBlank(chapInitiatorUsername) &&
+                    StringUtils.isNotBlank(chapInitiatorPassword)) {
+                    deviceConfig.put("chapuser", chapInitiatorUsername);
+                    deviceConfig.put("chappassword", chapInitiatorPassword);
+                }
+
                 Host host = Host.getByUuid(conn, _host.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,
+                    sr = SR.create(conn, host, deviceConfig, new Long(0), srNameLabel, srNameLabel, type, "user", true,
                             smConfig);
                 } catch (XenAPIException e) {
                     String errmsg = e.toString();
@@ -6463,19 +6462,30 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
                 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,
+
+                if (pooluuid == null || pooluuid.length() != 36)
+                {
+                    sr = SR.create(conn, host, deviceConfig, new Long(0), srNameLabel, srNameLabel, type, "user", true,
                             smConfig);
+
+                    created[0] = true; // note that the SR was created (as opposed to introduced)
                 } else {
-                    sr = SR.introduce(conn, pooluuid, 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 = SR.introduce(conn, pooluuid, srNameLabel, srNameLabel,
+                        type, "user", true, smConfig);
+
+                    Set<Host> setHosts = Host.getAll(conn);
+
+                    for (Host currentHost : setHosts) {
+                        PBD.Record rec = new PBD.Record();
+
+                        rec.deviceConfig = deviceConfig;
+                        rec.host = currentHost;
+                        rec.SR = sr;
+
+                        PBD pbd = PBD.create(conn, rec);
+
+                        pbd.plug(conn);
+                    }
                 }
                 sr.scan(conn);
                 return sr;
@@ -6636,6 +6646,52 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
         }
     }
 
+    // for about 1 GiB of physical size, about 4 MiB seems to be used for metadata
+    private long getMetadata(long physicalSize) {
+    	return (long)(physicalSize * 0.00390625); // 1 GiB / 4 MiB = 0.00390625
+    }
+
+    protected VDI handleSrAndVdiAttach(String iqn, String storageHostName,
+            String chapInitiatorName, String chapInitiatorPassword) throws Exception {
+        VDI vdi = null;
+
+        Connection conn = getConnection();
+
+        Boolean[] created = { false };
+
+        SR sr = getIscsiSR(conn, iqn,
+                    storageHostName, iqn,
+                    chapInitiatorName, chapInitiatorPassword, created);
+
+        // if created[0] is true, this means the SR was actually created...as opposed to introduced
+        if (created[0]) {
+            VDI.Record vdir = new VDI.Record();
+
+            vdir.nameLabel = iqn;
+            vdir.SR = sr;
+            vdir.type = Types.VdiType.USER;
+            vdir.virtualSize = sr.getPhysicalSize(conn) - sr.getPhysicalUtilisation(conn) - getMetadata(sr.getPhysicalSize(conn));
+
+            if (vdir.virtualSize < 0) {
+            	throw new Exception("VDI virtual size cannot be less than 0.");
+            }
+
+            vdi = VDI.create(conn, vdir);
+        }
+        else {
+            vdi = sr.getVDIs(conn).iterator().next();
+        }
+
+    	return vdi;
+    }
+
+    protected void handleSrAndVdiDetach(String iqn) throws Exception {
+        Connection conn = getConnection();
+
+        SR sr = getStorageRepository(conn, iqn);
+
+        removeSR(conn, sr);
+    }
 
     protected AttachVolumeAnswer execute(final AttachVolumeCommand cmd) {
         Connection conn = getConnection();
@@ -6652,7 +6708,16 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
 
         try {
             // Look up the VDI
-            VDI vdi = mount(conn, cmd.getPooltype(), cmd.getVolumeFolder(),cmd.getVolumePath());
+            VDI vdi = null;
+
+            if (cmd.getAttach() && cmd.isManaged()) {
+                vdi = handleSrAndVdiAttach(cmd.get_iScsiName(), cmd.getStorageHost(),
+                        cmd.getChapInitiatorUsername(), cmd.getChapInitiatorPassword());
+            }
+            else {
+                vdi = getVDIbyUuid(conn, cmd.getVolumePath());
+            }
+
             // Look up the VM
             VM vm = getVM(conn, vmName);
             /* For HVM guest, if no pv driver installed, no attach/detach */
@@ -6704,7 +6769,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
                 // Update the VDI's label to include the VM name
                 vdi.setNameLabel(conn, vmName + "-DATA");
 
-                return new AttachVolumeAnswer(cmd, Long.parseLong(diskNumber));
+                return new AttachVolumeAnswer(cmd, Long.parseLong(diskNumber), vdi.getUuid(conn));
             } else {
                 // Look up all VBDs for this VDI
                 Set<VBD> vbds = vdi.getVBDs(conn);
@@ -6723,7 +6788,9 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
                 // Update the VDI's label to be "detached"
                 vdi.setNameLabel(conn, "detached");
 
-                umount(conn, vdi);
+                if (cmd.isManaged()) {
+                    handleSrAndVdiDetach(cmd.get_iScsiName());
+                }
 
                 return new AttachVolumeAnswer(cmd);
             }
@@ -7606,30 +7673,30 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
         }
     }
 
-    protected SR getStorageRepository(Connection conn, String uuid) {
+    protected SR getStorageRepository(Connection conn, String srNameLabel) {
         Set<SR> srs;
         try {
-            srs = SR.getByNameLabel(conn, uuid);
+            srs = SR.getByNameLabel(conn, srNameLabel);
         } catch (XenAPIException e) {
-            throw new CloudRuntimeException("Unable to get SR " + uuid + " due to " + e.toString(), e);
+            throw new CloudRuntimeException("Unable to get SR " + srNameLabel + " due to " + e.toString(), e);
         } catch (Exception e) {
-            throw new CloudRuntimeException("Unable to get SR " + uuid + " due to " + e.getMessage(), e);
+            throw new CloudRuntimeException("Unable to get SR " + srNameLabel + " due to " + e.getMessage(), e);
         }
 
         if (srs.size() > 1) {
-            throw new CloudRuntimeException("More than one storage repository was found for pool with uuid: " + uuid);
+            throw new CloudRuntimeException("More than one storage repository was found for pool with uuid: " + srNameLabel);
         } else if (srs.size() == 1) {
             SR sr = srs.iterator().next();
             if (s_logger.isDebugEnabled()) {
-                s_logger.debug("SR retrieved for " + uuid);
+                s_logger.debug("SR retrieved for " + srNameLabel);
             }
 
             if (checkSR(conn, sr)) {
                 return sr;
             }
-            throw new CloudRuntimeException("SR check failed for storage pool: " + uuid + "on host:" + _host.uuid);
+            throw new CloudRuntimeException("SR check failed for storage pool: " + srNameLabel + "on host:" + _host.uuid);
         } else {
-            throw new CloudRuntimeException("Can not see storage pool: " + uuid + " from on host:" + _host.uuid);
+            throw new CloudRuntimeException("Can not see storage pool: " + srNameLabel + " from on host:" + _host.uuid);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java
index 399e234..e6358f2 100644
--- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java
+++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java
@@ -55,7 +55,6 @@ import org.apache.xmlrpc.XmlRpcException;
 
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.CreateStoragePoolCommand;
-import com.cloud.agent.api.CreateVolumeFromSnapshotAnswer;
 import com.cloud.agent.api.to.DataObjectType;
 import com.cloud.agent.api.to.DataStoreTO;
 import com.cloud.agent.api.to.DataTO;
@@ -171,7 +170,16 @@ public class XenServerStorageProcessor implements StorageProcessor {
         try {
             Connection conn = this.hypervisorResource.getConnection();
             // Look up the VDI
-            VDI vdi = this.hypervisorResource.mount(conn, null, null, data.getPath());
+            VDI vdi = null;
+
+            if (cmd.isManaged()) {
+                vdi = this.hypervisorResource.handleSrAndVdiAttach(cmd.get_iScsiName(), cmd.getStorageHost(),
+                        cmd.getChapInitiatorUsername(), cmd.getChapInitiatorPassword());
+            }
+            else {
+                vdi = this.hypervisorResource.mount(conn, null, null, data.getPath());
+            }
+
             // Look up the VM
             VM vm = this.hypervisorResource.getVM(conn, vmName);
             /* For HVM guest, if no pv driver installed, no attach/detach */
@@ -223,7 +231,7 @@ public class XenServerStorageProcessor implements StorageProcessor {
 
             // Update the VDI's label to include the VM name
             vdi.setNameLabel(conn, vmName + "-DATA");
-            DiskTO newDisk = new DiskTO(disk.getData(), Long.parseLong(diskNumber), disk.getType());
+            DiskTO newDisk = new DiskTO(disk.getData(), Long.parseLong(diskNumber), vdi.getUuid(conn), disk.getType());
             return new AttachAnswer(newDisk);
 
         } catch (XenAPIException e) {
@@ -350,6 +358,10 @@ public class XenServerStorageProcessor implements StorageProcessor {
 
             this.hypervisorResource.umount(conn, vdi);
 
+            if (cmd.isManaged()) {
+                this.hypervisorResource.handleSrAndVdiDetach(cmd.get_iScsiName());
+            }
+
             return new DettachAnswer(disk);
         } catch(Exception e) {
             s_logger.warn("Failed dettach volume: " + data.getPath());

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java
index 8d7c965..a233407 100644
--- a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java
+++ b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java
@@ -95,7 +95,12 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri
     }
 
     @Override
-    public void createAsync(DataObject data, AsyncCompletionCallback<CreateCmdResult> callback) {
+    public ChapInfo getChapInfo(VolumeInfo volumeInfo) {
+        return null;
+    }
+
+    @Override
+    public void createAsync(DataStore dataStore, DataObject data, AsyncCompletionCallback<CreateCmdResult> callback) {
         String errMsg = null;
         Answer answer = null;
         if (data.getType() == DataObjectType.VOLUME) {
@@ -118,7 +123,7 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri
     }
 
     @Override
-    public void deleteAsync(DataObject data, AsyncCompletionCallback<CommandResult> callback) {
+    public void deleteAsync(DataStore dataStore, DataObject data, AsyncCompletionCallback<CommandResult> callback) {
         DeleteCommand cmd = new DeleteCommand(data.getTO());
 
         CommandResult result = new CommandResult();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java b/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java
index 643c933..78f2263 100644
--- a/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java
+++ b/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java
@@ -54,6 +54,11 @@ public class SamplePrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
         return null;
     }
 
+    @Override
+    public ChapInfo getChapInfo(VolumeInfo volumeInfo) {
+        return null;
+    }
+
     private class CreateVolumeContext<T> extends AsyncRpcConext<T> {
         private final DataObject volume;
         public CreateVolumeContext(AsyncCompletionCallback<T> callback, DataObject volume) {
@@ -77,7 +82,7 @@ public class SamplePrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
     }
 
     @Override
-    public void deleteAsync(DataObject vo, AsyncCompletionCallback<CommandResult> callback) {
+    public void deleteAsync(DataStore dataStore, DataObject vo, AsyncCompletionCallback<CommandResult> callback) {
         /*
          * DeleteCommand cmd = new DeleteCommand(vo.getUri());
          * 
@@ -146,7 +151,7 @@ public class SamplePrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
      */
 
     @Override
-    public void createAsync(DataObject vol, AsyncCompletionCallback<CreateCmdResult> callback) {
+    public void createAsync(DataStore dataStore, DataObject vol, AsyncCompletionCallback<CreateCmdResult> callback) {
         EndPoint ep = selector.select(vol);
         CreateObjectCommand createCmd = new CreateObjectCommand(null);
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/plugins/storage/volume/solidfire/pom.xml
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/solidfire/pom.xml b/plugins/storage/volume/solidfire/pom.xml
index 9db0685..81af8ac 100644
--- a/plugins/storage/volume/solidfire/pom.xml
+++ b/plugins/storage/volume/solidfire/pom.xml
@@ -12,7 +12,7 @@
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <artifactId>cloud-plugin-storage-volume-solidfire</artifactId>
-  <name>Apache CloudStack Plugin - Storage Volume solidfire</name>
+  <name>Apache CloudStack Plugin - Storage Volume SolidFire Provider</name>
   <parent>
     <groupId>org.apache.cloudstack</groupId>
     <artifactId>cloudstack-plugins</artifactId>
@@ -31,6 +31,11 @@
       <version>${cs.mysql.version}</version>
       <scope>provided</scope>
     </dependency>
+    <dependency>
+      <groupId>com.google.code.gson</groupId>
+      <artifactId>gson</artifactId>
+      <version>${cs.gson.version}</version>
+    </dependency>
   </dependencies>
   <build>
     <defaultGoal>install</defaultGoal>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/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 960378c..329f27f 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
@@ -16,13 +16,46 @@
 // under the License.
 package org.apache.cloudstack.storage.datastore.driver;
 
-import com.cloud.agent.api.to.DataStoreTO;
-import com.cloud.agent.api.to.DataTO;
+import java.util.List;
+import java.util.Set;
+
+import javax.inject.Inject;
+
 import org.apache.cloudstack.engine.subsystem.api.storage.*;
 import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
 import org.apache.cloudstack.storage.command.CommandResult;
+import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
+import org.apache.cloudstack.storage.datastore.util.SolidFireUtil;
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.to.DataObjectType;
+import com.cloud.agent.api.to.DataStoreTO;
+import com.cloud.agent.api.to.DataTO;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.exception.StorageUnavailableException;
+import com.cloud.storage.Storage.StoragePoolType;
+import com.cloud.storage.VolumeVO;
+import com.cloud.storage.dao.VolumeDao;
+import com.cloud.storage.dao.VolumeDetailsDao;
+import com.cloud.user.AccountVO;
+import com.cloud.user.AccountDetailsDao;
+import com.cloud.user.AccountDetailVO;
+import com.cloud.user.dao.AccountDao;
 
 public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
+    private static final Logger s_logger = Logger.getLogger(SolidfirePrimaryDataStoreDriver.class);
+
+    @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;
 
     @Override
     public DataTO getTO(DataObject data) {
@@ -34,12 +67,450 @@ 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) {
+        try {
+            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);
+        }
+        catch (Exception ex) {
+            throw new IllegalArgumentException(ex.getMessage());
+        }
+    }
+
+    private void updateCsDbWithAccountInfo(long csAccountId, SolidFireUtil.SolidFireAccount sfAccount) {
+        AccountDetailVO accountDetails = new AccountDetailVO(csAccountId,
+                SolidFireUtil.ACCOUNT_ID,
+                String.valueOf(sfAccount.getId()));
+
+        _accountDetailsDao.persist(accountDetails);
+
+        accountDetails = new AccountDetailVO(csAccountId,
+                SolidFireUtil.CHAP_INITIATOR_USERNAME,
+                String.valueOf(sfAccount.getName()));
+
+        _accountDetailsDao.persist(accountDetails);
+
+        accountDetails = new AccountDetailVO(csAccountId,
+                SolidFireUtil.CHAP_INITIATOR_SECRET,
+                String.valueOf(sfAccount.getInitiatorSecret()));
+
+        _accountDetailsDao.persist(accountDetails);
+
+        accountDetails = new AccountDetailVO(csAccountId,
+                SolidFireUtil.CHAP_TARGET_USERNAME,
+                sfAccount.getName());
+
+        _accountDetailsDao.persist(accountDetails);
+
+        accountDetails = new AccountDetailVO(csAccountId,
+                SolidFireUtil.CHAP_TARGET_SECRET,
+                sfAccount.getTargetSecret());
+
+        _accountDetailsDao.persist(accountDetails);
+    }
+
+    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;
+        }
+
+        public String getInitiatorUsername() {
+            return _initiatorUsername;
+        }
+
+        public String getInitiatorSecret() {
+            return _initiatorSecret;
+        }
+
+        public String getTargetUsername() {
+            return _targetUsername;
+        }
+
+        public String getTargetSecret() {
+            return _targetSecret;
+        }
+    }
+
+    @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);
+    }
+
+    private SolidFireUtil.SolidFireVolume createSolidFireVolume(VolumeInfo volumeInfo, SolidFireConnection sfConnection)
+            throws StorageUnavailableException, Exception
+    {
+        String mVip = sfConnection.getManagementVip();
+        int mPort = sfConnection.getManagementPort();
+        String clusterAdminUsername = sfConnection.getClusterAdminUsername();
+        String clusterAdminPassword = sfConnection.getClusterAdminPassword();
+
+        AccountDetailVO accountDetail = _accountDetailsDao.findDetail(volumeInfo.getAccountId(), SolidFireUtil.ACCOUNT_ID);
+        long sfAccountId = Long.parseLong(accountDetail.getValue());
+
+        final Iops iops;
+
+        Long minIops = volumeInfo.getMinIops();
+        Long maxIops = volumeInfo.getMaxIops();
+
+        if (minIops == null || minIops <= 0 ||
+            maxIops == null || maxIops <= 0) {
+            iops = new Iops(100, 15000);
+        }
+        else {
+            iops = new Iops(volumeInfo.getMinIops(), volumeInfo.getMaxIops());
+        }
+
+    	long sfVolumeId = SolidFireUtil.createSolidFireVolume(mVip, mPort, clusterAdminUsername, clusterAdminPassword,
+    	        volumeInfo.getName(), sfAccountId, volumeInfo.getSize(), true,
+    	        iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops());
+
+    	return SolidFireUtil.getSolidFireVolume(mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfVolumeId);
+    }
+
+    private static class Iops
+    {
+    	private final long _minIops;
+    	private final long _maxIops;
+    	private final long _burstIops;
+
+    	public Iops(long minIops, long maxIops) throws Exception
+    	{
+    	    if (minIops <= 0 || maxIops <= 0) {
+    	        throw new Exception("The 'Min IOPS' and 'Max IOPS' values must be greater than 0.");
+    	    }
+
+            if (minIops > maxIops) {
+                throw new Exception("The 'Min IOPS' value cannot exceed the 'Max IOPS' value.");
+            }
+
+            _minIops = minIops;
+            _maxIops = maxIops;
+
+            _burstIops = getBurstIops(_maxIops);
+    	}
+
+    	public long getMinIops()
+    	{
+    		return _minIops;
+    	}
+
+    	public long getMaxIops()
+    	{
+    		return _maxIops;
+    	}
+
+    	public long getBurstIops()
+    	{
+    		return _burstIops;
+    	}
+
+        private static long getBurstIops(long maxIops)
+        {
+        	return (long)(maxIops * 1.5);
+        }
+    }
+
+    private void deleteSolidFireVolume(VolumeInfo volumeInfo, SolidFireConnection sfConnection)
+            throws StorageUnavailableException, Exception
+    {
+        Long storagePoolId = volumeInfo.getPoolId();
+
+        if (storagePoolId == null) {
+            return; // 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());
+
+        SolidFireUtil.deleteSolidFireVolume(mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfVolumeId);
+    }
+
+    private String getSfAccountName(String csAccountUuid, long csAccountId) {
+        return "CloudStack_" + csAccountUuid + "_" + getRandomNumber() + "_" + csAccountId;
+    }
+
+    private static long getRandomNumber()
+    {
+        return Math.round(Math.random() * 1000000000);
+    }
+
+    private boolean sfAccountExists(String sfAccountName, SolidFireConnection sfConnection) throws Exception {
+        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;
+    }
+
     @Override
-    public void createAsync(DataObject data, AsyncCompletionCallback<CreateCmdResult> callback) {
+    public void createAsync(DataStore dataStore, DataObject dataObject,
+            AsyncCompletionCallback<CreateCmdResult> callback) {
+        String iqn = null;
+        String errMsg = null;
+
+        if (dataObject.getType() == DataObjectType.VOLUME) {
+            try {
+                VolumeInfo volumeInfo = (VolumeInfo)dataObject;
+                AccountVO account = _accountDao.findById(volumeInfo.getAccountId());
+                String sfAccountName = getSfAccountName(account.getUuid(), account.getAccountId());
+
+                long storagePoolId = dataStore.getId();
+                SolidFireConnection sfConnection = getSolidFireConnection(storagePoolId);
+
+                if (!sfAccountExists(sfAccountName, sfConnection)) {
+                    SolidFireUtil.SolidFireAccount sfAccount = createSolidFireAccount(sfAccountName,
+                            sfConnection);
+
+                    updateCsDbWithAccountInfo(account.getId(), sfAccount);
+                }
+
+                SolidFireUtil.SolidFireVolume sfVolume = createSolidFireVolume(volumeInfo, sfConnection);
+
+                iqn = sfVolume.getIqn();
+
+                VolumeVO volume = this._volumeDao.findById(volumeInfo.getId());
+
+                volume.set_iScsiName(iqn);
+                volume.setFolder(String.valueOf(sfVolume.getId()));
+                volume.setPoolType(StoragePoolType.IscsiLUN);
+                volume.setPoolId(storagePoolId);
+
+                _volumeDao.update(volume.getId(), volume);
+
+                StoragePoolVO storagePool = _storagePoolDao.findById(dataStore.getId());
+
+                long capacityBytes = storagePool.getCapacityBytes();
+                long usedBytes = storagePool.getUsedBytes();
+
+                usedBytes += volumeInfo.getSize();
+
+                if (usedBytes > capacityBytes) {
+                    usedBytes = capacityBytes;
+                }
+
+                storagePool.setUsedBytes(usedBytes);
+
+                _storagePoolDao.update(storagePoolId, storagePool);
+            } catch (StorageUnavailableException e) {
+                s_logger.error("Failed to create volume (StorageUnavailableException)", e);
+                errMsg = e.toString();
+            } catch (Exception e) {
+                s_logger.error("Failed to create volume (Exception)", e);
+                errMsg = e.toString();
+            }
+        }
+        else {
+            errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to createAsync";
+        }
+
+        // path = iqn
+        // size is pulled from DataObject instance, if errMsg is null
+        CreateCmdResult result = new CreateCmdResult(iqn, new Answer(null, errMsg == null, errMsg));
+
+        result.setResult(errMsg);
+
+        callback.complete(result);
+    }
+
+    private void deleteSolidFireAccount(long sfAccountId, SolidFireConnection sfConnection) throws Exception {
+        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) throws Exception {
+        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(DataObject data, AsyncCompletionCallback<CommandResult> callback) {
+    public void deleteAsync(DataStore dataStore, DataObject dataObject,
+            AsyncCompletionCallback<CommandResult> callback) {
+        String errMsg = null;
+
+        if (dataObject.getType() == DataObjectType.VOLUME) {
+            try {
+                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);
+
+                deleteSolidFireVolume(volumeInfo, sfConnection);
+
+                _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();
+
+                usedBytes -= volumeInfo.getSize();
+
+                if (usedBytes < 0) {
+                    usedBytes = 0;
+                }
+
+                storagePool.setUsedBytes(usedBytes);
+
+                _storagePoolDao.update(storagePoolId, storagePool);
+            } catch (StorageUnavailableException e) {
+                s_logger.error("Failed to create volume (StorageUnavailableException)", e);
+                errMsg = e.toString();
+            } catch (Exception e) {
+                s_logger.error("Failed to create volume (Exception)", e);
+                errMsg = e.toString();
+            }
+        }
+        else {
+            errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to deleteAsync";
+        }
+
+        CommandResult result = new CommandResult();
+
+        result.setResult(errMsg);
+
+        callback.complete(result);
     }
 
     @Override
@@ -62,5 +533,4 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
     @Override
     public void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CreateCmdResult> callback) {
     }
-
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/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
new file mode 100644
index 0000000..2e25cd5
--- /dev/null
+++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java
@@ -0,0 +1,274 @@
+/*
+ * 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.util.Map;
+import java.util.StringTokenizer;
+
+import javax.inject.Inject;
+
+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.ZoneScope;
+import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCycle;
+import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreParameters;
+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;
+
+import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.agent.api.StoragePoolInfo;
+import com.cloud.storage.StoragePoolAutomation;
+import com.cloud.storage.Storage.StoragePoolType;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeCycle {
+    @Inject PrimaryDataStoreDao storagePoolDao;
+    @Inject PrimaryDataStoreHelper dataStoreHelper;
+    @Inject StoragePoolAutomation storagePoolAutomation;
+    @Inject StoragePoolDetailsDao storagePoolDetailsDao;
+    @Inject DataCenterDao zoneDao;
+    
+    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
+    public DataStore initialize(Map<String, Object> dsInfos) {
+    	String url = (String)dsInfos.get("url");
+    	Long zoneId = (Long)dsInfos.get("zoneId");
+        String storagePoolName = (String) dsInfos.get("name");
+        String providerName = (String)dsInfos.get("providerName");
+        Long capacityBytes = (Long)dsInfos.get("capacityBytes");
+        Long capacityIops = (Long)dsInfos.get("capacityIops");
+        String tags = (String)dsInfos.get("tags");
+        Map<String, String> details = (Map<String, String>)dsInfos.get("details");
+    	
+    	String storageVip = getStorageVip(url);
+    	int storagePort = getStoragePort(url);
+    	
+    	DataCenterVO zone = zoneDao.findById(zoneId);
+    	
+    	String uuid = SolidFireUtil.PROVIDER_NAME + "_" + zone.getUuid() + "_" + storageVip;
+
+        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.");
+    	}
+    	
+        PrimaryDataStoreParameters parameters = new PrimaryDataStoreParameters();
+        
+        parameters.setHost(storageVip);
+        parameters.setPort(storagePort);
+        parameters.setPath(getModifiedUrl(url));
+        parameters.setType(StoragePoolType.Iscsi);
+        parameters.setUuid(uuid);
+        parameters.setZoneId(zoneId);
+        parameters.setName(storagePoolName);
+        parameters.setProviderName(providerName);
+        parameters.setManaged(true);
+        parameters.setCapacityBytes(capacityBytes);
+        parameters.setUsedBytes(0);
+        parameters.setCapacityIops(capacityIops);
+        parameters.setHypervisorType(HypervisorType.Any);
+        parameters.setTags(tags);
+        parameters.setDetails(details);
+        
+        String managementVip = getManagementVip(url);
+        int managementPort = 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);
+        
+        details.put(SolidFireUtil.CLUSTER_ADMIN_USERNAME, clusterAdminUsername);
+        details.put(SolidFireUtil.CLUSTER_ADMIN_PASSWORD, clusterAdminPassword);
+        
+        // this adds a row in the cloud.storage_pool table for this SolidFire cluster
+    	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();
+			
+			if (!token.startsWith(SolidFireUtil.CLUSTER_ADMIN_USERNAME) &&
+				!token.startsWith(SolidFireUtil.CLUSTER_ADMIN_PASSWORD)) {
+				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) {
+        return true; // should be ignored for zone-wide-only plug-ins like SolidFire's
+    }
+    
+    // do not implement this method for SolidFire's plug-in
+    @Override
+    public boolean attachCluster(DataStore store, ClusterScope scope) {
+    	return true; // should be ignored for zone-wide-only plug-ins like SolidFire's
+    }
+    
+    @Override
+    public boolean attachZone(DataStore dataStore, ZoneScope scope, HypervisorType hypervisorType) {
+    	dataStoreHelper.attachZone(dataStore);
+    	
+        return true;
+    }
+
+    
+    @Override
+    public boolean maintain(DataStore dataStore) {
+        storagePoolAutomation.maintain(dataStore);
+        dataStoreHelper.maintain(dataStore);
+        
+        return true;
+    }
+    
+    @Override
+    public boolean cancelMaintain(DataStore store) {
+        dataStoreHelper.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 store) {
+        return dataStoreHelper.deletePrimaryDataStore(store);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99227f7b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidfirePrimaryDataStoreProvider.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidfirePrimaryDataStoreProvider.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidfirePrimaryDataStoreProvider.java
index 2965e8f..28864ea 100644
--- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidfirePrimaryDataStoreProvider.java
+++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidfirePrimaryDataStoreProvider.java
@@ -1,62 +1,91 @@
-// 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.
+/*
+ * 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.Map;
 import java.util.Set;
+import java.util.HashSet;
 
-import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver;
 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.SolidfirePrimaryDataStoreDriver;
+import org.apache.cloudstack.storage.datastore.lifecycle.SolidFirePrimaryDataStoreLifeCycle;
+import org.apache.cloudstack.storage.datastore.util.SolidFireUtil;
 import org.springframework.stereotype.Component;
 
+import com.cloud.utils.component.ComponentContext;
+
 @Component
 public class SolidfirePrimaryDataStoreProvider implements PrimaryDataStoreProvider {
-    private final String name = "Solidfire Primary Data Store Provider";
+    protected DataStoreLifeCycle lifecycle;
+    protected PrimaryDataStoreDriver driver;
+    protected HypervisorHostListener listener;
+
+    SolidfirePrimaryDataStoreProvider() {
+
+    }
 
     @Override
     public String getName() {
-        return name;
+        return SolidFireUtil.PROVIDER_NAME;
     }
 
     @Override
     public DataStoreLifeCycle getDataStoreLifeCycle() {
-        return null;
+        return lifecycle;
     }
 
     @Override
-    public DataStoreDriver getDataStoreDriver() {
-        return null;
+    public PrimaryDataStoreDriver getDataStoreDriver() {
+        return driver;
     }
 
     @Override
     public HypervisorHostListener getHostListener() {
-        return null;
+        return listener;
     }
 
     @Override
     public boolean configure(Map<String, Object> params) {
-        return false;
+        lifecycle = ComponentContext.inject(SolidFirePrimaryDataStoreLifeCycle.class);
+        driver = ComponentContext.inject(SolidfirePrimaryDataStoreDriver.class);
+        listener = ComponentContext.inject(new HypervisorHostListener() {
+            public boolean hostConnect(long hostId, long poolId) {
+                return true;
+            }
+
+            public boolean hostDisconnected(long hostId, long poolId) {
+                return true;
+            }
+        });
+
+        return true;
     }
 
     @Override
     public Set<DataStoreProviderType> getTypes() {
-        return null;
-    }
+        Set<DataStoreProviderType> types =  new HashSet<DataStoreProviderType>();
 
+        types.add(DataStoreProviderType.PRIMARY);
+
+        return types;
+    }
 }