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;
+ }
}