You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by da...@apache.org on 2016/05/24 09:49:18 UTC
[13/48] git commit: updated refs/heads/4.9-bountycastle-daan to
98bf0ca
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2bd035d1/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 5f647db..af969e1 100644
--- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java
+++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java
@@ -17,32 +17,13 @@
package org.apache.cloudstack.storage.datastore.driver;
import java.text.NumberFormat;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
-import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo;
-import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
-import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
-import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
-import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
-import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
-import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
-import org.apache.cloudstack.storage.command.CommandResult;
-import org.apache.cloudstack.storage.command.CreateObjectAnswer;
-import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
-import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
-import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
-import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
-import org.apache.cloudstack.storage.datastore.util.SolidFireUtil;
-import org.apache.cloudstack.storage.to.SnapshotObjectTO;
-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;
@@ -55,16 +36,19 @@ import com.cloud.dc.dao.ClusterDao;
import com.cloud.host.Host;
import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao;
-import com.cloud.storage.Storage.StoragePoolType;
+import com.cloud.storage.DataStoreRole;
import com.cloud.storage.ResizeVolumePayload;
+import com.cloud.storage.Snapshot.State;
+import com.cloud.storage.SnapshotVO;
import com.cloud.storage.StoragePool;
-import com.cloud.storage.Volume;
+import com.cloud.storage.VMTemplateStoragePoolVO;
import com.cloud.storage.VolumeDetailVO;
import com.cloud.storage.VolumeVO;
-import com.cloud.storage.SnapshotVO;
+import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.storage.dao.SnapshotDao;
import com.cloud.storage.dao.SnapshotDetailsDao;
import com.cloud.storage.dao.SnapshotDetailsVO;
+import com.cloud.storage.dao.VMTemplatePoolDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.storage.dao.VolumeDetailsDao;
import com.cloud.user.AccountDetailVO;
@@ -74,27 +58,64 @@ import com.cloud.user.dao.AccountDao;
import com.cloud.utils.db.GlobalLock;
import com.cloud.utils.exception.CloudRuntimeException;
+import com.google.common.base.Preconditions;
+
+import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo;
+import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
+import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
+import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
+import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
+import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
+import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
+import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
+import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
+import org.apache.cloudstack.storage.command.CommandResult;
+import org.apache.cloudstack.storage.command.CreateObjectAnswer;
+import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
+import org.apache.cloudstack.storage.datastore.util.SolidFireUtil;
+import org.apache.cloudstack.storage.to.SnapshotObjectTO;
+import org.apache.log4j.Logger;
+
public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
- private static final Logger s_logger = Logger.getLogger(SolidFirePrimaryDataStoreDriver.class);
- private static final int s_lowestHypervisorSnapshotReserve = 10;
-
- @Inject private AccountDao _accountDao;
- @Inject private AccountDetailsDao _accountDetailsDao;
- @Inject private ClusterDao _clusterDao;
- @Inject private ClusterDetailsDao _clusterDetailsDao;
- @Inject private HostDao _hostDao;
- @Inject private SnapshotDao _snapshotDao;
- @Inject private SnapshotDetailsDao _snapshotDetailsDao;
- @Inject private PrimaryDataStoreDao _storagePoolDao;
- @Inject private StoragePoolDetailsDao _storagePoolDetailsDao;
- @Inject private VolumeDao _volumeDao;
- @Inject private VolumeDetailsDao _volumeDetailsDao;
+ private static final Logger LOGGER = Logger.getLogger(SolidFirePrimaryDataStoreDriver.class);
+ private static final int LOCK_TIME_IN_SECONDS = 300;
+ private static final int LOWEST_HYPERVISOR_SNAPSHOT_RESERVE = 10;
+ private static final long MIN_IOPS_FOR_TEMPLATE_VOLUME = 100L;
+ private static final long MAX_IOPS_FOR_TEMPLATE_VOLUME = 20000L;
+ private static final long MIN_IOPS_FOR_TEMP_VOLUME = 100L;
+ private static final long MAX_IOPS_FOR_TEMP_VOLUME = 20000L;
+ private static final long MIN_IOPS_FOR_SNAPSHOT_VOLUME = 100L;
+ private static final long MAX_IOPS_FOR_SNAPSHOT_VOLUME = 20000L;
+
+ @Inject private AccountDao accountDao;
+ @Inject private AccountDetailsDao accountDetailsDao;
+ @Inject private ClusterDao clusterDao;
+ @Inject private ClusterDetailsDao clusterDetailsDao;
+ @Inject private DataStoreManager dataStoreMgr;
+ @Inject private HostDao hostDao;
+ @Inject private SnapshotDao snapshotDao;
+ @Inject private SnapshotDetailsDao snapshotDetailsDao;
+ @Inject private PrimaryDataStoreDao storagePoolDao;
+ @Inject private StoragePoolDetailsDao storagePoolDetailsDao;
+ @Inject private VMTemplatePoolDao tmpltPoolDao;
+ @Inject private VolumeDao volumeDao;
+ @Inject private VolumeDetailsDao volumeDetailsDao;
+ @Inject private VolumeDataFactory volumeFactory;
@Override
public Map<String, String> getCapabilities() {
- Map<String, String> mapCapabilities = new HashMap<String, String>();
+ Map<String, String> mapCapabilities = new HashMap<>();
mapCapabilities.put(DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT.toString(), Boolean.TRUE.toString());
+ mapCapabilities.put(DataStoreCapabilities.CAN_CREATE_VOLUME_FROM_SNAPSHOT.toString(), Boolean.TRUE.toString());
+ mapCapabilities.put(DataStoreCapabilities.CAN_CREATE_VOLUME_FROM_VOLUME.toString(), Boolean.TRUE.toString());
return mapCapabilities;
}
@@ -116,7 +137,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
}
@Override
- public ChapInfo getChapInfo(VolumeInfo volumeInfo) {
+ public ChapInfo getChapInfo(DataObject dataObject) {
return null;
}
@@ -128,38 +149,42 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
@Override
public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore)
{
- if (dataObject == null || host == null || dataStore == null) {
- return false;
- }
+ Preconditions.checkArgument(dataObject != null, "'dataObject' should not be 'null'");
+ Preconditions.checkArgument(host != null, "'host' should not be 'null'");
+ Preconditions.checkArgument(dataStore != null, "'dataStore' should not be 'null'");
long sfVolumeId = getSolidFireVolumeId(dataObject);
long clusterId = host.getClusterId();
long storagePoolId = dataStore.getId();
- ClusterVO cluster = _clusterDao.findById(clusterId);
+ ClusterVO cluster = clusterDao.findById(clusterId);
GlobalLock lock = GlobalLock.getInternLock(cluster.getUuid());
- if (!lock.lock(SolidFireUtil.s_lockTimeInSeconds)) {
+ if (!lock.lock(LOCK_TIME_IN_SECONDS)) {
String errMsg = "Couldn't lock the DB (in grantAccess) on the following string: " + cluster.getUuid();
- s_logger.debug(errMsg);
+ LOGGER.warn(errMsg);
throw new CloudRuntimeException(errMsg);
}
try {
- ClusterDetailsVO clusterDetail = _clusterDetailsDao.findDetail(clusterId, SolidFireUtil.getVagKey(storagePoolId));
+ ClusterDetailsVO clusterDetail = clusterDetailsDao.findDetail(clusterId, SolidFireUtil.getVagKey(storagePoolId));
String vagId = clusterDetail != null ? clusterDetail.getValue() : null;
- List<HostVO> hosts = _hostDao.findByClusterId(clusterId);
+ List<HostVO> hosts = hostDao.findByClusterId(clusterId);
if (!SolidFireUtil.hostsSupport_iScsi(hosts)) {
- return false;
+ String errMsg = "Not all hosts in the compute cluster support iSCSI.";
+
+ LOGGER.warn(errMsg);
+
+ throw new CloudRuntimeException(errMsg);
}
- SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
+ SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao);
if (vagId != null) {
SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection, Long.parseLong(vagId));
@@ -169,7 +194,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
SolidFireUtil.modifySolidFireVag(sfConnection, sfVag.getId(), sfVag.getInitiators(), volumeIds);
}
else {
- SolidFireUtil.placeVolumeInVolumeAccessGroup(sfConnection, sfVolumeId, storagePoolId, cluster.getUuid(), hosts, _clusterDetailsDao);
+ SolidFireUtil.placeVolumeInVolumeAccessGroup(sfConnection, sfVolumeId, storagePoolId, cluster.getUuid(), hosts, clusterDetailsDao);
}
return true;
@@ -194,25 +219,25 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
long clusterId = host.getClusterId();
long storagePoolId = dataStore.getId();
- ClusterVO cluster = _clusterDao.findById(clusterId);
+ ClusterVO cluster = clusterDao.findById(clusterId);
GlobalLock lock = GlobalLock.getInternLock(cluster.getUuid());
- if (!lock.lock(SolidFireUtil.s_lockTimeInSeconds)) {
+ if (!lock.lock(LOCK_TIME_IN_SECONDS)) {
String errMsg = "Couldn't lock the DB (in revokeAccess) on the following string: " + cluster.getUuid();
- s_logger.debug(errMsg);
+ LOGGER.debug(errMsg);
throw new CloudRuntimeException(errMsg);
}
try {
- ClusterDetailsVO clusterDetail = _clusterDetailsDao.findDetail(clusterId, SolidFireUtil.getVagKey(storagePoolId));
+ ClusterDetailsVO clusterDetail = clusterDetailsDao.findDetail(clusterId, SolidFireUtil.getVagKey(storagePoolId));
String vagId = clusterDetail != null ? clusterDetail.getValue() : null;
if (vagId != null) {
- SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
+ SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao);
SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection, Long.parseLong(vagId));
@@ -233,7 +258,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
}
if (dataObject.getType() == DataObjectType.SNAPSHOT) {
- SnapshotDetailsVO snapshotDetails = _snapshotDetailsDao.findDetail(dataObject.getId(), SolidFireUtil.VOLUME_ID);
+ SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(dataObject.getId(), SolidFireUtil.VOLUME_ID);
if (snapshotDetails == null || snapshotDetails.getValue() == null) {
throw new CloudRuntimeException("Unable to locate the volume ID associated with the following snapshot ID: " + dataObject.getId());
@@ -242,11 +267,26 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
return Long.parseLong(snapshotDetails.getValue());
}
+ if (dataObject.getType() == DataObjectType.TEMPLATE) {
+ return getVolumeIdFrom_iScsiPath(((TemplateInfo)dataObject).getInstallPath());
+ }
+
throw new CloudRuntimeException("Invalid DataObjectType (" + dataObject.getType() + ") passed to getSolidFireVolumeId(DataObject)");
}
+ private long getVolumeIdFrom_iScsiPath(String iScsiPath) {
+ String[] splits = iScsiPath.split("/");
+ String iqn = splits[1];
+
+ String sequenceToSearchFor = ".";
+ int lastIndexOf = iqn.lastIndexOf(sequenceToSearchFor);
+ String volumeIdAsString = iqn.substring(lastIndexOf + sequenceToSearchFor.length());
+
+ return Long.parseLong(volumeIdAsString);
+ }
+
private long getDefaultMinIops(long storagePoolId) {
- StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_DEFAULT_MIN_IOPS);
+ StoragePoolDetailVO storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_DEFAULT_MIN_IOPS);
String clusterDefaultMinIops = storagePoolDetail.getValue();
@@ -254,7 +294,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
}
private long getDefaultMaxIops(long storagePoolId) {
- StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_DEFAULT_MAX_IOPS);
+ StoragePoolDetailVO storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_DEFAULT_MAX_IOPS);
String clusterDefaultMaxIops = storagePoolDetail.getValue();
@@ -262,7 +302,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
}
private long getDefaultBurstIops(long storagePoolId, long maxIops) {
- StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_DEFAULT_BURST_IOPS_PERCENT_OF_MAX_IOPS);
+ StoragePoolDetailVO storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_DEFAULT_BURST_IOPS_PERCENT_OF_MAX_IOPS);
String clusterDefaultBurstIopsPercentOfMaxIops = storagePoolDetail.getValue();
@@ -271,30 +311,56 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
return (long)(maxIops * fClusterDefaultBurstIopsPercentOfMaxIops);
}
- private SolidFireUtil.SolidFireVolume createSolidFireVolume(SolidFireUtil.SolidFireConnection sfConnection, VolumeInfo volumeInfo, long sfAccountId) {
- long storagePoolId = volumeInfo.getDataStore().getId();
+ private SolidFireUtil.SolidFireVolume createSolidFireVolume(SolidFireUtil.SolidFireConnection sfConnection, DataObject dataObject, long sfAccountId) {
+ long storagePoolId = dataObject.getDataStore().getId();
+ Long minIops = null;
+ Long maxIops = null;
+ Long volumeSize = dataObject.getSize();
+ String volumeName = null;
- final Iops iops;
+ final Map<String, String> mapAttributes;
- Long minIops = volumeInfo.getMinIops();
- Long maxIops = volumeInfo.getMaxIops();
+ if (dataObject.getType() == DataObjectType.VOLUME) {
+ VolumeInfo volumeInfo = (VolumeInfo)dataObject;
- if (minIops == null || minIops <= 0 || maxIops == null || maxIops <= 0) {
- long defaultMaxIops = getDefaultMaxIops(storagePoolId);
+ minIops = volumeInfo.getMinIops();
+ maxIops = volumeInfo.getMaxIops();
+ volumeSize = getDataObjectSizeIncludingHypervisorSnapshotReserve(volumeInfo, storagePoolDao.findById(storagePoolId));
+ volumeName = volumeInfo.getName();
- iops = new Iops(getDefaultMinIops(storagePoolId), defaultMaxIops, getDefaultBurstIops(storagePoolId, defaultMaxIops));
- } else {
- iops = new Iops(volumeInfo.getMinIops(), volumeInfo.getMaxIops(), getDefaultBurstIops(storagePoolId, volumeInfo.getMaxIops()));
+ mapAttributes = getVolumeAttributes(volumeInfo);
+ } else if (dataObject.getType() == DataObjectType.TEMPLATE) {
+ TemplateInfo templateInfo = (TemplateInfo)dataObject;
+
+ minIops = MIN_IOPS_FOR_TEMPLATE_VOLUME;
+ maxIops = MAX_IOPS_FOR_TEMPLATE_VOLUME;
+ volumeSize = getDataObjectSizeIncludingHypervisorSnapshotReserve(templateInfo, storagePoolDao.findById(storagePoolId));
+ volumeName = templateInfo.getUniqueName();
+
+ mapAttributes = getTemplateAttributes(templateInfo);
+ }
+ else {
+ throw new CloudRuntimeException("Invalid type passed to createSolidFireVolume: " + dataObject.getType());
}
- long volumeSize = getVolumeSizeIncludingHypervisorSnapshotReserve(volumeInfo, _storagePoolDao.findById(storagePoolId));
+ final Iops iops = getIops(minIops, maxIops, storagePoolId);
- long sfVolumeId = SolidFireUtil.createSolidFireVolume(sfConnection, SolidFireUtil.getSolidFireVolumeName(volumeInfo.getName()), sfAccountId, volumeSize, true,
- NumberFormat.getInstance().format(volumeInfo.getSize()), iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops());
+ long sfVolumeId = SolidFireUtil.createSolidFireVolume(sfConnection, SolidFireUtil.getSolidFireVolumeName(volumeName), sfAccountId,
+ volumeSize, true, mapAttributes, iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops());
return SolidFireUtil.getSolidFireVolume(sfConnection, sfVolumeId);
}
+ private Iops getIops(Long minIops, Long maxIops, long storagePoolId) {
+ if (minIops == null || minIops <= 0 || maxIops == null || maxIops <= 0) {
+ long defaultMaxIops = getDefaultMaxIops(storagePoolId);
+
+ return new Iops(getDefaultMinIops(storagePoolId), defaultMaxIops, getDefaultBurstIops(storagePoolId, defaultMaxIops));
+ }
+
+ return new Iops(minIops, maxIops, getDefaultBurstIops(storagePoolId, maxIops));
+ }
+
@Override
public long getUsedBytes(StoragePool storagePool) {
return getUsedBytes(storagePool, Long.MIN_VALUE);
@@ -303,7 +369,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
private long getUsedBytes(StoragePool storagePool, long volumeIdToIgnore) {
long usedSpace = 0;
- List<VolumeVO> lstVolumes = _volumeDao.findByPoolId(storagePool.getId(), null);
+ List<VolumeVO> lstVolumes = volumeDao.findByPoolId(storagePool.getId(), null);
if (lstVolumes != null) {
for (VolumeVO volume : lstVolumes) {
@@ -311,7 +377,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
continue;
}
- VolumeDetailVO volumeDetail = _volumeDetailsDao.findDetail(volume.getId(), SolidFireUtil.VOLUME_SIZE);
+ VolumeDetailVO volumeDetail = volumeDetailsDao.findDetail(volume.getId(), SolidFireUtil.VOLUME_SIZE);
if (volumeDetail != null && volumeDetail.getValue() != null) {
long volumeSize = Long.parseLong(volumeDetail.getValue());
@@ -319,18 +385,22 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
usedSpace += volumeSize;
}
else {
- SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePool.getId(), _storagePoolDetailsDao);
+ SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePool.getId(), storagePoolDetailsDao);
try {
long lVolumeId = Long.parseLong(volume.getFolder());
SolidFireUtil.SolidFireVolume sfVolume = SolidFireUtil.getSolidFireVolume(sfConnection, lVolumeId);
+ long volumeSize = sfVolume.getTotalSize();
+
// SolidFireUtil.VOLUME_SIZE was introduced in 4.5.
// To be backward compatible with releases prior to 4.5, call updateVolumeDetails here.
// That way if SolidFireUtil.VOLUME_SIZE wasn't put in the volume_details table when the
// volume was initially created, it can be placed in volume_details here.
- updateVolumeDetails(volume.getId(), sfVolume.getTotalSize());
+ updateVolumeDetails(volume.getId(), volumeSize);
+
+ usedSpace += volumeSize;
}
catch (NumberFormatException ex) {
// can be ignored (the "folder" column didn't have a valid "long" in it (hasn't been placed there yet))
@@ -339,15 +409,15 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
}
}
- List<SnapshotVO> lstSnapshots = _snapshotDao.listAll();
+ List<SnapshotVO> lstSnapshots = snapshotDao.listAll();
if (lstSnapshots != null) {
for (SnapshotVO snapshot : lstSnapshots) {
- SnapshotDetailsVO snapshotDetails = _snapshotDetailsDao.findDetail(snapshot.getId(), SolidFireUtil.STORAGE_POOL_ID);
+ SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(snapshot.getId(), SolidFireUtil.STORAGE_POOL_ID);
// if this snapshot belongs to the storagePool that was passed in
if (snapshotDetails != null && snapshotDetails.getValue() != null && Long.parseLong(snapshotDetails.getValue()) == storagePool.getId()) {
- snapshotDetails = _snapshotDetailsDao.findDetail(snapshot.getId(), SolidFireUtil.VOLUME_SIZE);
+ snapshotDetails = snapshotDetailsDao.findDetail(snapshot.getId(), SolidFireUtil.VOLUME_SIZE);
if (snapshotDetails != null && snapshotDetails.getValue() != null) {
long snapshotSize = Long.parseLong(snapshotDetails.getValue());
@@ -358,6 +428,14 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
}
}
+ List<VMTemplateStoragePoolVO> lstTemplatePoolRefs = tmpltPoolDao.listByPoolId(storagePool.getId());
+
+ if (lstTemplatePoolRefs != null) {
+ for (VMTemplateStoragePoolVO templatePoolRef : lstTemplatePoolRefs) {
+ usedSpace += templatePoolRef.getTemplateSize();
+ }
+ }
+
return usedSpace;
}
@@ -365,7 +443,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
public long getUsedIops(StoragePool storagePool) {
long usedIops = 0;
- List<VolumeVO> volumes = _volumeDao.findByPoolId(storagePool.getId(), null);
+ List<VolumeVO> volumes = volumeDao.findByPoolId(storagePool.getId(), null);
if (volumes != null) {
for (VolumeVO volume : volumes) {
@@ -377,12 +455,25 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
}
@Override
- public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) {
- long volumeSize = volume.getSize();
- Integer hypervisorSnapshotReserve = volume.getHypervisorSnapshotReserve();
+ public long getDataObjectSizeIncludingHypervisorSnapshotReserve(DataObject dataObject, StoragePool pool) {
+ long volumeSize = 0;
+
+ if (dataObject.getType() == DataObjectType.VOLUME) {
+ VolumeInfo volume = (VolumeInfo)dataObject;
+
+ volumeSize = getVolumeSizeIncludingHypervisorSnapshotReserve(volume.getSize(), volume.getHypervisorSnapshotReserve());
+ } else if (dataObject.getType() == DataObjectType.TEMPLATE) {
+ TemplateInfo templateInfo = (TemplateInfo)dataObject;
+
+ volumeSize = (long)(templateInfo.getSize() + templateInfo.getSize() * (LOWEST_HYPERVISOR_SNAPSHOT_RESERVE / 100f));
+ }
+ return volumeSize;
+ }
+
+ private long getVolumeSizeIncludingHypervisorSnapshotReserve(long volumeSize, Integer hypervisorSnapshotReserve) {
if (hypervisorSnapshotReserve != null) {
- hypervisorSnapshotReserve = Math.max(hypervisorSnapshotReserve, s_lowestHypervisorSnapshotReserve);
+ hypervisorSnapshotReserve = Math.max(hypervisorSnapshotReserve, LOWEST_HYPERVISOR_SNAPSHOT_RESERVE);
volumeSize += volumeSize * (hypervisorSnapshotReserve / 100f);
}
@@ -390,6 +481,29 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
return volumeSize;
}
+ /**
+ * This method is only relevant when storagePool is being used with a compute cluster that supports UUID resigning.
+ */
+ @Override
+ public long getBytesRequiredForTemplate(TemplateInfo templateInfo, StoragePool storagePool) {
+ List<VMTemplateStoragePoolVO> lstTemplatePoolRefs = tmpltPoolDao.listByPoolId(storagePool.getId());
+
+ if (lstTemplatePoolRefs != null) {
+ for (VMTemplateStoragePoolVO templatePoolRef : lstTemplatePoolRefs) {
+ if (templatePoolRef.getTemplateId() == templateInfo.getId()) {
+ // This indicates that we already have this template stored on this primary storage, so
+ // we do not require additional space.
+ return 0;
+ }
+ }
+ }
+
+ // This indicates that we do not have a copy of this template on this primary storage, so
+ // we need to take it into consideration from a space standpoint (ex. when a new VM is spun
+ // up and wants to use this particular template for its root disk).
+ return getDataObjectSizeIncludingHypervisorSnapshotReserve(templateInfo, storagePool);
+ }
+
private static class Iops {
private final long _minIops;
private final long _maxIops;
@@ -436,7 +550,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
long sfVolumeId = Long.parseLong(volumeInfo.getFolder());
- SolidFireUtil.deleteSolidFireVolume(sfConnection, sfVolumeId);
+ deleteSolidFireVolume(sfConnection, volumeInfo.getId(), sfVolumeId);
}
@Override
@@ -444,114 +558,234 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
String iqn = null;
String errMsg = null;
- if (dataObject.getType() == DataObjectType.VOLUME) {
- VolumeInfo volumeInfo = (VolumeInfo)dataObject;
+ try {
+ if (dataObject.getType() == DataObjectType.VOLUME) {
+ iqn = createVolume((VolumeInfo)dataObject, dataStore.getId());
+ } else if (dataObject.getType() == DataObjectType.SNAPSHOT) {
+ createTempVolume((SnapshotInfo)dataObject, dataStore.getId());
+ } else if (dataObject.getType() == DataObjectType.TEMPLATE) {
+ iqn = createTemplateVolume((TemplateInfo)dataObject, dataStore.getId());
+ } else {
+ errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to createAsync";
+
+ LOGGER.error(errMsg);
+ }
+ }
+ catch (Exception ex) {
+ errMsg = ex.getMessage();
- long storagePoolId = dataStore.getId();
+ LOGGER.error(errMsg);
- SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
+ if (callback == null) {
+ throw ex;
+ }
+ }
- AccountDetailVO accountDetail = SolidFireUtil.getAccountDetail(volumeInfo.getAccountId(), storagePoolId, _accountDetailsDao);
+ if (callback != null) {
+ // path = iqn
+ // size is pulled from DataObject instance, if errMsg is null
+ CreateCmdResult result = new CreateCmdResult(iqn, new Answer(null, errMsg == null, errMsg));
- if (accountDetail == null || accountDetail.getValue() == null) {
- AccountVO account = _accountDao.findById(volumeInfo.getAccountId());
- String sfAccountName = SolidFireUtil.getSolidFireAccountName(account.getUuid(), account.getAccountId());
- SolidFireUtil.SolidFireAccount sfAccount = SolidFireUtil.getSolidFireAccount(sfConnection, sfAccountName);
+ result.setResult(errMsg);
- if (sfAccount == null) {
- sfAccount = createSolidFireAccount(sfConnection, sfAccountName);
- }
+ callback.complete(result);
+ }
+ }
+
+ private long getCreateSolidFireAccountId(SolidFireUtil.SolidFireConnection sfConnection, long csAccountId, long storagePoolId) {
+ AccountDetailVO accountDetail = SolidFireUtil.getAccountDetail(csAccountId, storagePoolId, accountDetailsDao);
- SolidFireUtil.updateCsDbWithSolidFireAccountInfo(account.getId(), sfAccount, storagePoolId, _accountDetailsDao);
+ if (accountDetail == null || accountDetail.getValue() == null) {
+ AccountVO account = accountDao.findById(csAccountId);
+ String sfAccountName = SolidFireUtil.getSolidFireAccountName(account.getUuid(), account.getAccountId());
+ SolidFireUtil.SolidFireAccount sfAccount = SolidFireUtil.getSolidFireAccount(sfConnection, sfAccountName);
- accountDetail = SolidFireUtil.getAccountDetail(volumeInfo.getAccountId(), storagePoolId, _accountDetailsDao);
+ if (sfAccount == null) {
+ sfAccount = createSolidFireAccount(sfConnection, sfAccountName);
}
- long sfAccountId = Long.parseLong(accountDetail.getValue());
+ SolidFireUtil.updateCsDbWithSolidFireAccountInfo(account.getId(), sfAccount, storagePoolId, accountDetailsDao);
- SolidFireUtil.SolidFireVolume sfVolume = createSolidFireVolume(sfConnection, volumeInfo, sfAccountId);
+ accountDetail = SolidFireUtil.getAccountDetail(csAccountId, storagePoolId, accountDetailsDao);
+ }
- iqn = sfVolume.getIqn();
+ return Long.parseLong(accountDetail.getValue());
+ }
- VolumeVO volume = _volumeDao.findById(volumeInfo.getId());
+ private void handleSnapshotDetails(long csSnapshotId, String name, String value) {
+ snapshotDetailsDao.removeDetail(csSnapshotId, name);
- volume.set_iScsiName(iqn);
- volume.setFolder(String.valueOf(sfVolume.getId()));
- volume.setPoolType(StoragePoolType.IscsiLUN);
- volume.setPoolId(storagePoolId);
+ SnapshotDetailsVO snapshotDetails = new SnapshotDetailsVO(csSnapshotId, name, value, false);
- _volumeDao.update(volume.getId(), volume);
+ snapshotDetailsDao.persist(snapshotDetails);
+ }
- updateVolumeDetails(volume.getId(), sfVolume.getTotalSize());
+ private void addTempVolumeId(long csSnapshotId, String tempVolumeId) {
+ SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.VOLUME_ID);
- StoragePoolVO storagePool = _storagePoolDao.findById(dataStore.getId());
+ if (snapshotDetails == null || snapshotDetails.getValue() == null) {
+ throw new CloudRuntimeException("'addTempVolumeId' should not be invoked unless " + SolidFireUtil.VOLUME_ID + " exists.");
+ }
- long capacityBytes = storagePool.getCapacityBytes();
- // getUsedBytes(StoragePool) will include the bytes of the newly created volume because
- // updateVolumeDetails(long, long) has already been called for this volume
- long usedBytes = getUsedBytes(storagePool);
+ String originalVolumeId = snapshotDetails.getValue();
- storagePool.setUsedBytes(usedBytes > capacityBytes ? capacityBytes : usedBytes);
+ handleSnapshotDetails(csSnapshotId, SolidFireUtil.TEMP_VOLUME_ID, originalVolumeId);
+ handleSnapshotDetails(csSnapshotId, SolidFireUtil.VOLUME_ID, tempVolumeId);
+ }
- _storagePoolDao.update(storagePoolId, storagePool);
- } else {
- errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to createAsync";
+ private void removeTempVolumeId(long csSnapshotId) {
+ SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.TEMP_VOLUME_ID);
+
+ if (snapshotDetails == null || snapshotDetails.getValue() == null) {
+ throw new CloudRuntimeException("'removeTempVolumeId' should not be invoked unless " + SolidFireUtil.TEMP_VOLUME_ID + " exists.");
}
- // path = iqn
- // size is pulled from DataObject instance, if errMsg is null
- CreateCmdResult result = new CreateCmdResult(iqn, new Answer(null, errMsg == null, errMsg));
+ String originalVolumeId = snapshotDetails.getValue();
- result.setResult(errMsg);
+ handleSnapshotDetails(csSnapshotId, SolidFireUtil.VOLUME_ID, originalVolumeId);
- callback.complete(result);
+ snapshotDetailsDao.remove(snapshotDetails.getId());
}
- private void updateVolumeDetails(long volumeId, long sfVolumeSize) {
- VolumeDetailVO volumeDetailVo = _volumeDetailsDao.findDetail(volumeId, SolidFireUtil.VOLUME_SIZE);
-
- if (volumeDetailVo == null || volumeDetailVo.getValue() == null) {
- volumeDetailVo = new VolumeDetailVO(volumeId, SolidFireUtil.VOLUME_SIZE, String.valueOf(sfVolumeSize), false);
+ private long getCsIdForCloning(long volumeId, String cloneOf) {
+ VolumeDetailVO volumeDetail = volumeDetailsDao.findDetail(volumeId, cloneOf);
- _volumeDetailsDao.persist(volumeDetailVo);
+ if (volumeDetail != null && volumeDetail.getValue() != null) {
+ return new Long(volumeDetail.getValue());
}
+
+ return Long.MIN_VALUE;
}
- @Override
- public void deleteAsync(DataStore dataStore, DataObject dataObject, AsyncCompletionCallback<CommandResult> callback) {
- String errMsg = null;
+ private boolean shouldTakeSnapshot(long snapshotId) {
+ SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(snapshotId, "takeSnapshot");
- if (dataObject.getType() == DataObjectType.VOLUME) {
- try {
- VolumeInfo volumeInfo = (VolumeInfo)dataObject;
- long volumeId = volumeInfo.getId();
+ if (snapshotDetails != null && snapshotDetails.getValue() != null) {
+ return new Boolean(snapshotDetails.getValue());
+ }
- long storagePoolId = dataStore.getId();
+ return false;
+ }
- SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
+ private SolidFireUtil.SolidFireVolume createClone(SolidFireUtil.SolidFireConnection sfConnection, long dataObjectId, VolumeInfo volumeInfo, long sfAccountId,
+ long storagePoolId, DataObjectType dataObjectType) {
+ String sfNewVolumeName = volumeInfo.getName();
- deleteSolidFireVolume(sfConnection, volumeInfo);
+ long sfVolumeId = Long.MIN_VALUE;
+ long sfSnapshotId = Long.MIN_VALUE;
- _volumeDetailsDao.removeDetails(volumeId);
+ if (dataObjectType == DataObjectType.SNAPSHOT) {
+ SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(dataObjectId, SolidFireUtil.SNAPSHOT_ID);
- StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId);
+ if (snapshotDetails != null && snapshotDetails.getValue() != null) {
+ sfSnapshotId = Long.parseLong(snapshotDetails.getValue());
+ }
- long usedBytes = getUsedBytes(storagePool, volumeId);
+ snapshotDetails = snapshotDetailsDao.findDetail(dataObjectId, SolidFireUtil.VOLUME_ID);
- storagePool.setUsedBytes(usedBytes < 0 ? 0 : usedBytes);
+ sfVolumeId = Long.parseLong(snapshotDetails.getValue());
+ } else if (dataObjectType == DataObjectType.TEMPLATE) {
+ // get the cached template on this storage
+ VMTemplateStoragePoolVO templatePoolRef = tmpltPoolDao.findByPoolTemplate(storagePoolId, dataObjectId);
- _storagePoolDao.update(storagePoolId, storagePool);
+ if (templatePoolRef != null) {
+ sfVolumeId = Long.parseLong(templatePoolRef.getLocalDownloadPath());
}
- catch (Exception ex) {
- s_logger.debug(SolidFireUtil.LOG_PREFIX + "Failed to delete SolidFire volume", ex);
+ }
+
+ if (sfVolumeId <= 0) {
+ throw new CloudRuntimeException("Unable to find SolidFire volume for the following data-object ID: " + dataObjectId +
+ " and data-object type: " + dataObjectType);
+ }
+
+ final long newSfVolumeId = SolidFireUtil.createSolidFireClone(sfConnection, sfVolumeId, sfSnapshotId, sfAccountId, sfNewVolumeName,
+ getVolumeAttributes(volumeInfo));
+
+ final Iops iops = getIops(volumeInfo.getMinIops(), volumeInfo.getMaxIops(), storagePoolId);
+
+ SolidFireUtil.modifySolidFireVolume(sfConnection, newSfVolumeId, null, null, iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops());
+
+ return SolidFireUtil.getSolidFireVolume(sfConnection, newSfVolumeId);
+ }
+
+ private Map<String, String> getVolumeAttributes(VolumeInfo volumeInfo) {
+ Map<String, String> mapAttributes = new HashMap<>();
+
+ mapAttributes.put(SolidFireUtil.CloudStackVolumeId, String.valueOf(volumeInfo.getId()));
+ mapAttributes.put(SolidFireUtil.CloudStackVolumeSize, NumberFormat.getInstance().format(volumeInfo.getSize()));
+
+ return mapAttributes;
+ }
+
+ private Map<String, String> getSnapshotAttributes(SnapshotInfo snapshotInfo) {
+ Map<String, String> mapAttributes = new HashMap<>();
+
+ mapAttributes.put(SolidFireUtil.CloudStackSnapshotId, String.valueOf(snapshotInfo.getId()));
+ mapAttributes.put(SolidFireUtil.CloudStackSnapshotSize, NumberFormat.getInstance().format(snapshotInfo.getSize()));
+
+ return mapAttributes;
+ }
+
+ private Map<String, String> getTemplateAttributes(TemplateInfo templateInfo) {
+ Map<String, String> mapAttributes = new HashMap<>();
+
+ mapAttributes.put(SolidFireUtil.CloudStackTemplateId, String.valueOf(templateInfo.getId()));
+ mapAttributes.put(SolidFireUtil.CloudStackTemplateSize, NumberFormat.getInstance().format(templateInfo.getSize()));
+
+ return mapAttributes;
+ }
+
+ private SolidFireUtil.SolidFireVolume createCloneFromSnapshot(SolidFireUtil.SolidFireConnection sfConnection, long csSnapshotId, long sfAccountId) {
+ SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.VOLUME_ID);
+
+ long sfVolumeId = Long.parseLong(snapshotDetails.getValue());
+
+ snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.SNAPSHOT_ID);
+
+ long sfSnapshotId = Long.parseLong(snapshotDetails.getValue());
+
+ SolidFireUtil.SolidFireSnapshot sfSnapshot = SolidFireUtil.getSolidFireSnapshot(sfConnection, sfVolumeId, sfSnapshotId);
+
+ long newSfVolumeId = SolidFireUtil.createSolidFireClone(sfConnection, sfVolumeId, sfSnapshotId, sfAccountId, sfSnapshot.getName(), null);
+
+ snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.STORAGE_POOL_ID);
+
+ long storagePoolId = Long.parseLong(snapshotDetails.getValue());
+
+ final Iops iops = getIops(MIN_IOPS_FOR_TEMP_VOLUME, MAX_IOPS_FOR_TEMP_VOLUME, storagePoolId);
+
+ SolidFireUtil.modifySolidFireVolume(sfConnection, newSfVolumeId, null, null, iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops());
+
+ return SolidFireUtil.getSolidFireVolume(sfConnection, newSfVolumeId);
+ }
+
+ private void updateVolumeDetails(long volumeId, long sfVolumeSize) {
+ volumeDetailsDao.removeDetail(volumeId, SolidFireUtil.VOLUME_SIZE);
- errMsg = ex.getMessage();
+ VolumeDetailVO volumeDetailVo = new VolumeDetailVO(volumeId, SolidFireUtil.VOLUME_SIZE, String.valueOf(sfVolumeSize), false);
+
+ volumeDetailsDao.persist(volumeDetailVo);
+ }
+
+ @Override
+ public void deleteAsync(DataStore dataStore, DataObject dataObject, AsyncCompletionCallback<CommandResult> callback) {
+ String errMsg = null;
+
+ try {
+ if (dataObject.getType() == DataObjectType.VOLUME) {
+ deleteVolume((VolumeInfo)dataObject, dataStore.getId());
+ } else if (dataObject.getType() == DataObjectType.SNAPSHOT) {
+ deleteSnapshot((SnapshotInfo)dataObject, dataStore.getId());
+ } else if (dataObject.getType() == DataObjectType.TEMPLATE) {
+ deleteTemplate((TemplateInfo)dataObject, dataStore.getId());
+ } else {
+ errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to deleteAsync";
}
- } else if (dataObject.getType() == DataObjectType.SNAPSHOT) {
- // should return null when no error message
- errMsg = deleteSnapshot((SnapshotInfo)dataObject, dataStore.getId());
- } else {
- errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to deleteAsync";
+ }
+ catch (Exception ex) {
+ errMsg = ex.getMessage();
+
+ LOGGER.error(errMsg);
}
CommandResult result = new CommandResult();
@@ -577,49 +811,67 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
try {
VolumeInfo volumeInfo = snapshotInfo.getBaseVolume();
- VolumeVO volumeVO = _volumeDao.findById(volumeInfo.getId());
+ VolumeVO volumeVO = volumeDao.findById(volumeInfo.getId());
long sfVolumeId = Long.parseLong(volumeVO.getFolder());
long storagePoolId = volumeVO.getPoolId();
- SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
+ SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao);
SolidFireUtil.SolidFireVolume sfVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfVolumeId);
- StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId);
+ StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId);
long capacityBytes = storagePool.getCapacityBytes();
- // getUsedBytes(StoragePool) will not include the bytes of the proposed new volume because
- // updateSnapshotDetails(long, long, long, long, String) has not yet been called for this new volume
+ // getUsedBytes(StoragePool) will not include the bytes of the proposed new volume or snapshot because
+ // updateSnapshotDetails has not yet been called for this new volume or snapshot
long usedBytes = getUsedBytes(storagePool);
long sfVolumeSize = sfVolume.getTotalSize();
usedBytes += sfVolumeSize;
- // For creating a volume, we need to check to make sure a sufficient amount of space remains in the primary storage.
- // For the purpose of "charging" these bytes against storage_pool.capacityBytes, we take the full size of the SolidFire volume.
+ // For creating a volume or a snapshot, we need to check to make sure a sufficient amount of space remains in the primary storage.
+ // For the purpose of "charging" these bytes against storage_pool.capacity_bytes, we take the full size of the SolidFire volume
+ // that is serving as the volume the snapshot is of (either a new SolidFire volume or a SolidFire snapshot).
if (usedBytes > capacityBytes) {
throw new CloudRuntimeException("Insufficient amount of space remains in this primary storage to take a snapshot");
}
storagePool.setUsedBytes(usedBytes);
- String volumeName = volumeInfo.getName() + "-" + snapshotInfo.getUuid();
+ SnapshotObjectTO snapshotObjectTo = (SnapshotObjectTO)snapshotInfo.getTO();
- long sfNewVolumeId = SolidFireUtil.createSolidFireVolume(sfConnection, volumeName, sfVolume.getAccountId(), sfVolumeSize,
- sfVolume.isEnable512e(), NumberFormat.getInstance().format(volumeInfo.getSize()), sfVolume.getMinIops(), 50000, 75000);
+ if (shouldTakeSnapshot(snapshotInfo.getId())) {
+ // We are supposed to take a SolidFire snapshot to serve as the back-end for our CloudStack volume snapshot.
- // Now that we have successfully created a volume, update the space usage in the storage_pool table
- // (even though storage_pool.used_bytes is likely no longer in use).
- _storagePoolDao.update(storagePoolId, storagePool);
+ String sfNewSnapshotName = volumeInfo.getName() + "-" + snapshotInfo.getUuid();
- SolidFireUtil.SolidFireVolume sfNewVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfNewVolumeId);
+ long sfNewSnapshotId = SolidFireUtil.createSolidFireSnapshot(sfConnection, sfVolumeId, sfNewSnapshotName, getSnapshotAttributes(snapshotInfo));
- updateSnapshotDetails(snapshotInfo.getId(), sfNewVolumeId, storagePoolId, sfVolumeSize, sfNewVolume.getIqn());
+ updateSnapshotDetails(snapshotInfo.getId(), sfVolumeId, sfNewSnapshotId, storagePoolId, sfVolumeSize);
- SnapshotObjectTO snapshotObjectTo = (SnapshotObjectTO)snapshotInfo.getTO();
+ snapshotObjectTo.setPath("SfSnapshotId=" + sfNewSnapshotId);
+ }
+ else {
+ // We are supposed to create a new SolidFire volume to serve as the back-end for our CloudStack volume snapshot.
+
+ String sfNewVolumeName = volumeInfo.getName() + "-" + snapshotInfo.getUuid();
- snapshotObjectTo.setPath(String.valueOf(sfNewVolumeId));
+ final Iops iops = getIops(MIN_IOPS_FOR_SNAPSHOT_VOLUME, MAX_IOPS_FOR_SNAPSHOT_VOLUME, storagePoolId);
+
+ long sfNewVolumeId = SolidFireUtil.createSolidFireVolume(sfConnection, sfNewVolumeName, sfVolume.getAccountId(), sfVolumeSize,
+ sfVolume.isEnable512e(), getSnapshotAttributes(snapshotInfo), iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops());
+
+ SolidFireUtil.SolidFireVolume sfNewVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfNewVolumeId);
+
+ updateSnapshotDetails(snapshotInfo.getId(), sfNewVolumeId, storagePoolId, sfVolumeSize, sfNewVolume.getIqn());
+
+ snapshotObjectTo.setPath("SfVolumeId=" + sfNewVolumeId);
+ }
+
+ // Now that we have successfully created a volume or a snapshot, update the space usage in the cloud.storage_pool table
+ // (even though cloud.storage_pool.used_bytes is likely no longer in use).
+ storagePoolDao.update(storagePoolId, storagePool);
CreateObjectAnswer createObjectAnswer = new CreateObjectAnswer(snapshotObjectTo);
@@ -628,7 +880,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
result.setResult(null);
}
catch (Exception ex) {
- s_logger.debug(SolidFireUtil.LOG_PREFIX + "Failed to take CloudStack snapshot: " + snapshotInfo.getId(), ex);
+ LOGGER.debug(SolidFireUtil.LOG_PREFIX + "Failed to take CloudStack snapshot: " + snapshotInfo.getId(), ex);
result = new CreateCmdResult(null, new CreateObjectAnswer(ex.toString()));
@@ -638,69 +890,293 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
callback.complete(result);
}
+ private void updateSnapshotDetails(long csSnapshotId, long sfVolumeId, long sfNewSnapshotId, long storagePoolId, long sfNewVolumeSize) {
+ SnapshotDetailsVO snapshotDetail = new SnapshotDetailsVO(csSnapshotId,
+ SolidFireUtil.VOLUME_ID,
+ String.valueOf(sfVolumeId),
+ false);
+
+ snapshotDetailsDao.persist(snapshotDetail);
+
+ snapshotDetail = new SnapshotDetailsVO(csSnapshotId,
+ SolidFireUtil.SNAPSHOT_ID,
+ String.valueOf(sfNewSnapshotId),
+ false);
+
+ snapshotDetailsDao.persist(snapshotDetail);
+
+ snapshotDetail = new SnapshotDetailsVO(csSnapshotId,
+ SolidFireUtil.STORAGE_POOL_ID,
+ String.valueOf(storagePoolId),
+ false);
+
+ snapshotDetailsDao.persist(snapshotDetail);
+
+ snapshotDetail = new SnapshotDetailsVO(csSnapshotId,
+ SolidFireUtil.VOLUME_SIZE,
+ String.valueOf(sfNewVolumeSize),
+ false);
+
+ snapshotDetailsDao.persist(snapshotDetail);
+ }
+
private void updateSnapshotDetails(long csSnapshotId, long sfNewVolumeId, long storagePoolId, long sfNewVolumeSize, String sfNewVolumeIqn) {
SnapshotDetailsVO snapshotDetail = new SnapshotDetailsVO(csSnapshotId,
SolidFireUtil.VOLUME_ID,
String.valueOf(sfNewVolumeId),
false);
- _snapshotDetailsDao.persist(snapshotDetail);
+ snapshotDetailsDao.persist(snapshotDetail);
snapshotDetail = new SnapshotDetailsVO(csSnapshotId,
SolidFireUtil.STORAGE_POOL_ID,
String.valueOf(storagePoolId),
false);
- _snapshotDetailsDao.persist(snapshotDetail);
+ snapshotDetailsDao.persist(snapshotDetail);
snapshotDetail = new SnapshotDetailsVO(csSnapshotId,
SolidFireUtil.VOLUME_SIZE,
String.valueOf(sfNewVolumeSize),
false);
- _snapshotDetailsDao.persist(snapshotDetail);
+ snapshotDetailsDao.persist(snapshotDetail);
snapshotDetail = new SnapshotDetailsVO(csSnapshotId,
DiskTO.IQN,
sfNewVolumeIqn,
false);
- _snapshotDetailsDao.persist(snapshotDetail);
+ snapshotDetailsDao.persist(snapshotDetail);
}
- // return null for no error message
- private String deleteSnapshot(SnapshotInfo snapshotInfo, long storagePoolId) {
- String errMsg = null;
+ private String createVolume(VolumeInfo volumeInfo, long storagePoolId) {
+ verifySufficientBytesForStoragePool(volumeInfo, storagePoolId);
+ verifySufficientIopsForStoragePool(volumeInfo.getMinIops() != null ? volumeInfo.getMinIops() : getDefaultMinIops(storagePoolId), storagePoolId);
+
+ SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao);
+
+ long sfAccountId = getCreateSolidFireAccountId(sfConnection, volumeInfo.getAccountId(), storagePoolId);
+
+ long csSnapshotId = getCsIdForCloning(volumeInfo.getId(), "cloneOfSnapshot");
+ long csTemplateId = getCsIdForCloning(volumeInfo.getId(), "cloneOfTemplate");
+
+ SolidFireUtil.SolidFireVolume sfVolume;
+
+ if (csSnapshotId > 0) {
+ // We are supposed to create a clone of the underlying volume or snapshot that supports the CloudStack snapshot.
+ sfVolume = createClone(sfConnection, csSnapshotId, volumeInfo, sfAccountId, storagePoolId, DataObjectType.SNAPSHOT);
+ } else if (csTemplateId > 0) {
+ // Clone from template.
+ sfVolume = createClone(sfConnection, csTemplateId, volumeInfo, sfAccountId, storagePoolId, DataObjectType.TEMPLATE);
+
+ long volumeSize = getDataObjectSizeIncludingHypervisorSnapshotReserve(volumeInfo, storagePoolDao.findById(storagePoolId));
+
+ if (volumeSize > sfVolume.getTotalSize()) {
+ // Expand the volume to include HSR.
+ SolidFireUtil.modifySolidFireVolume(sfConnection, sfVolume.getId(), volumeSize, getVolumeAttributes(volumeInfo),
+ sfVolume.getMinIops(), sfVolume.getMaxIops(), sfVolume.getBurstIops());
+
+ // Get the SolidFire volume from the SAN again because we just updated its size.
+ sfVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfVolume.getId());
+ }
+ }
+ else {
+ sfVolume = createSolidFireVolume(sfConnection, volumeInfo, sfAccountId);
+ }
+
+ String iqn = sfVolume.getIqn();
+
+ VolumeVO volume = 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);
+
+ updateVolumeDetails(volume.getId(), sfVolume.getTotalSize());
+
+ StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId);
+
+ long capacityBytes = storagePool.getCapacityBytes();
+ // getUsedBytes(StoragePool) will include the bytes of the newly created volume because
+ // updateVolumeDetails(long, long) has already been called for this volume
+ long usedBytes = getUsedBytes(storagePool);
+
+ storagePool.setUsedBytes(usedBytes > capacityBytes ? capacityBytes : usedBytes);
+
+ storagePoolDao.update(storagePoolId, storagePool);
+
+ return iqn;
+ }
- long snapshotId = snapshotInfo.getId();
+ private void createTempVolume(SnapshotInfo snapshotInfo, long storagePoolId) {
+ long csSnapshotId = snapshotInfo.getId();
+ SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.SNAPSHOT_ID);
+
+ if (snapshotDetails == null || snapshotDetails.getValue() == null) {
+ throw new CloudRuntimeException("'createTempVolume(SnapshotInfo, long)' should not be invoked unless " + SolidFireUtil.SNAPSHOT_ID + " exists.");
+ }
+
+ SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao);
+
+ snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, "tempVolume");
+
+ if (snapshotDetails != null && snapshotDetails.getValue() != null && snapshotDetails.getValue().equalsIgnoreCase("create")) {
+ long sfAccountId = getCreateSolidFireAccountId(sfConnection, snapshotInfo.getAccountId(), storagePoolId);
+
+ SolidFireUtil.SolidFireVolume sfVolume = createCloneFromSnapshot(sfConnection, csSnapshotId, sfAccountId);
+
+ addTempVolumeId(csSnapshotId, String.valueOf(sfVolume.getId()));
+
+ handleSnapshotDetails(csSnapshotId, DiskTO.IQN, sfVolume.getIqn());
+ }
+ else if (snapshotDetails != null && snapshotDetails.getValue() != null && snapshotDetails.getValue().equalsIgnoreCase("delete")) {
+ snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.VOLUME_ID);
+
+ SolidFireUtil.deleteSolidFireVolume(sfConnection, Long.parseLong(snapshotDetails.getValue()));
+
+ removeTempVolumeId(csSnapshotId);
+
+ snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, DiskTO.IQN);
+
+ snapshotDetailsDao.remove(snapshotDetails.getId());
+ }
+ else {
+ throw new CloudRuntimeException("Invalid state in 'createTempVolume(SnapshotInfo, long)'");
+ }
+ }
+
+ private String createTemplateVolume(TemplateInfo templateInfo, long storagePoolId) {
+ verifySufficientBytesForStoragePool(templateInfo, storagePoolId);
+
+ SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao);
+
+ long sfAccountId = getCreateSolidFireAccountId(sfConnection, templateInfo.getAccountId(), storagePoolId);
+
+ SolidFireUtil.SolidFireVolume sfVolume = createSolidFireVolume(sfConnection, templateInfo, sfAccountId);
+
+ String iqn = sfVolume.getIqn();
+
+ VMTemplateStoragePoolVO templatePoolRef = tmpltPoolDao.findByPoolTemplate(storagePoolId, templateInfo.getId());
+
+ templatePoolRef.setInstallPath(iqn);
+ templatePoolRef.setLocalDownloadPath(Long.toString(sfVolume.getId()));
+ templatePoolRef.setTemplateSize(sfVolume.getTotalSize());
+
+ tmpltPoolDao.update(templatePoolRef.getId(), templatePoolRef);
+
+ StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId);
+
+ long capacityBytes = storagePool.getCapacityBytes();
+ // getUsedBytes(StoragePool) will include the bytes of the newly created template volume because
+ // _tmpltPoolDao.update(Long, VMTemplateStoragePoolVO) has already been invoked
+ long usedBytes = getUsedBytes(storagePool);
+
+ storagePool.setUsedBytes(usedBytes > capacityBytes ? capacityBytes : usedBytes);
+
+ storagePoolDao.update(storagePoolId, storagePool);
+
+ return iqn;
+ }
+
+ private void deleteVolume(VolumeInfo volumeInfo, long storagePoolId) {
try {
- SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
+ long volumeId = volumeInfo.getId();
+
+ SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao);
- SnapshotDetailsVO snapshotDetails = _snapshotDetailsDao.findDetail(snapshotId, SolidFireUtil.VOLUME_ID);
+ deleteSolidFireVolume(sfConnection, volumeInfo);
- long volumeId = Long.parseLong(snapshotDetails.getValue());
+ volumeDetailsDao.removeDetails(volumeId);
- SolidFireUtil.deleteSolidFireVolume(sfConnection, volumeId);
+ StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId);
- _snapshotDetailsDao.removeDetails(snapshotId);
+ long usedBytes = getUsedBytes(storagePool, volumeId);
- StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId);
+ storagePool.setUsedBytes(usedBytes < 0 ? 0 : usedBytes);
+
+ storagePoolDao.update(storagePoolId, storagePool);
+ }
+ catch (Exception ex) {
+ LOGGER.debug(SolidFireUtil.LOG_PREFIX + "Failed to delete SolidFire volume. CloudStack volume ID: " + volumeInfo.getId(), ex);
+
+ throw ex;
+ }
+ }
+
+ private void deleteSnapshot(SnapshotInfo snapshotInfo, long storagePoolId) {
+ long csSnapshotId = snapshotInfo.getId();
+
+ try {
+ SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao);
+
+ SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.SNAPSHOT_ID);
+
+ if (snapshotDetails != null && snapshotDetails.getValue() != null) {
+ // A SolidFire snapshot is being used to support the CloudStack volume snapshot.
+
+ long sfSnapshotId = Long.parseLong(snapshotDetails.getValue());
+
+ deleteSolidFireSnapshot(sfConnection, csSnapshotId, sfSnapshotId);
+ }
+ else {
+ // A SolidFire volume is being used to support the CloudStack volume snapshot.
+
+ snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.VOLUME_ID);
+
+ long sfVolumeId = Long.parseLong(snapshotDetails.getValue());
+
+ SolidFireUtil.deleteSolidFireVolume(sfConnection, sfVolumeId);
+ }
+
+ snapshotDetailsDao.removeDetails(csSnapshotId);
+
+ StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId);
// getUsedBytes(StoragePool) will not include the snapshot to delete because it has already been deleted by this point
long usedBytes = getUsedBytes(storagePool);
storagePool.setUsedBytes(usedBytes < 0 ? 0 : usedBytes);
- _storagePoolDao.update(storagePoolId, storagePool);
+ storagePoolDao.update(storagePoolId, storagePool);
}
catch (Exception ex) {
- s_logger.debug(SolidFireUtil.LOG_PREFIX + "Failed to delete SolidFire volume. CloudStack snapshot ID: " + snapshotId, ex);
+ LOGGER.debug(SolidFireUtil.LOG_PREFIX + "Issue in 'deleteSnapshot(SnapshotInfo, long)'. CloudStack snapshot ID: " + csSnapshotId, ex);
- errMsg = ex.getMessage();
+ throw ex;
+ }
+ }
+
+ private void deleteTemplate(TemplateInfo template, long storagePoolId) {
+ try {
+ SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao);
+
+ long sfTemplateVolumeId = getVolumeIdFrom_iScsiPath(template.getInstallPath());
+
+ SolidFireUtil.deleteSolidFireVolume(sfConnection, sfTemplateVolumeId);
+
+ VMTemplateStoragePoolVO templatePoolRef = tmpltPoolDao.findByPoolTemplate(storagePoolId, template.getId());
+
+ tmpltPoolDao.remove(templatePoolRef.getId());
+
+ StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId);
+
+ // getUsedBytes(StoragePool) will not include the template to delete because the "template_spool_ref" table has already been updated by this point
+ long usedBytes = getUsedBytes(storagePool);
+
+ storagePool.setUsedBytes(usedBytes < 0 ? 0 : usedBytes);
+
+ storagePoolDao.update(storagePoolId, storagePool);
}
+ catch (Exception ex) {
+ LOGGER.debug(SolidFireUtil.LOG_PREFIX + "Failed to delete SolidFire template volume. CloudStack template ID: " + template.getId(), ex);
- return errMsg;
+ throw ex;
+ }
}
@Override
@@ -720,26 +1196,49 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
long sfVolumeId = Long.parseLong(volumeInfo.getFolder());
ResizeVolumePayload payload = (ResizeVolumePayload)volumeInfo.getpayload();
- SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
+ SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao);
SolidFireUtil.SolidFireVolume sfVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfVolumeId);
verifySufficientIopsForStoragePool(storagePoolId, volumeInfo.getId(), payload.newMinIops);
+ verifySufficientBytesForStoragePool(storagePoolId, volumeInfo.getId(), payload.newSize, payload.newHypervisorSnapshotReserve);
+
+ long sfNewVolumeSize = sfVolume.getTotalSize();
+
+ Integer hsr = volumeInfo.getHypervisorSnapshotReserve();
+
+ if (payload.newSize != null || payload.newHypervisorSnapshotReserve != null) {
+ if (payload.newHypervisorSnapshotReserve != null) {
+ if (hsr != null) {
+ if (payload.newHypervisorSnapshotReserve > hsr) {
+ hsr = payload.newHypervisorSnapshotReserve;
+ }
+ }
+ else {
+ hsr = payload.newHypervisorSnapshotReserve;
+ }
+ }
+
+ sfNewVolumeSize = getVolumeSizeIncludingHypervisorSnapshotReserve(payload.newSize, hsr);
+ }
+
+ Map<String, String> mapAttributes = new HashMap<>();
+
+ mapAttributes.put(SolidFireUtil.CloudStackVolumeId, String.valueOf(volumeInfo.getId()));
+ mapAttributes.put(SolidFireUtil.CloudStackVolumeSize, NumberFormat.getInstance().format(payload.newSize));
- SolidFireUtil.modifySolidFireVolume(sfConnection, sfVolumeId, sfVolume.getTotalSize(), NumberFormat.getInstance().format(payload.newSize),
+ SolidFireUtil.modifySolidFireVolume(sfConnection, sfVolumeId, sfNewVolumeSize, mapAttributes,
payload.newMinIops, payload.newMaxIops, getDefaultBurstIops(storagePoolId, payload.newMaxIops));
- VolumeVO volume = _volumeDao.findById(volumeInfo.getId());
+ VolumeVO volume = volumeDao.findById(volumeInfo.getId());
volume.setMinIops(payload.newMinIops);
volume.setMaxIops(payload.newMaxIops);
+ volume.setHypervisorSnapshotReserve(hsr);
- _volumeDao.update(volume.getId(), volume);
+ volumeDao.update(volume.getId(), volume);
// SolidFireUtil.VOLUME_SIZE was introduced in 4.5.
- // To be backward compatible with releases prior to 4.5, call updateVolumeDetails here.
- // That way if SolidFireUtil.VOLUME_SIZE wasn't put in the volume_details table when the
- // volume was initially created, it can be placed in volume_details if the volume is resized.
- updateVolumeDetails(volume.getId(), sfVolume.getTotalSize());
+ updateVolumeDetails(volume.getId(), sfNewVolumeSize);
} else {
errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to resize";
}
@@ -751,21 +1250,140 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
callback.complete(result);
}
+ private void verifySufficientBytesForStoragePool(long requestedBytes, long storagePoolId) {
+ StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId);
+
+ long capacityBytes = storagePool.getCapacityBytes();
+ long usedBytes = getUsedBytes(storagePool);
+
+ usedBytes += requestedBytes;
+
+ if (usedBytes > capacityBytes) {
+ throw new CloudRuntimeException("Insufficient amount of space remains in this primary storage");
+ }
+ }
+
+ private void verifySufficientBytesForStoragePool(DataObject dataObject, long storagePoolId) {
+ StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId);
+
+ long requestedBytes = getDataObjectSizeIncludingHypervisorSnapshotReserve(dataObject, storagePool);
+
+ verifySufficientBytesForStoragePool(requestedBytes, storagePoolId);
+ }
+
+ private void verifySufficientBytesForStoragePool(long storagePoolId, long volumeId, long newSize, Integer newHypervisorSnapshotReserve) {
+ DataStore primaryDataStore = dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary);
+ VolumeInfo volumeInfo = volumeFactory.getVolume(volumeId, primaryDataStore);
+ StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId);
+ long currentSizeWithHsr = getDataObjectSizeIncludingHypervisorSnapshotReserve(volumeInfo, storagePool);
+
+ newHypervisorSnapshotReserve = newHypervisorSnapshotReserve == null ? LOWEST_HYPERVISOR_SNAPSHOT_RESERVE :
+ Math.max(newHypervisorSnapshotReserve, LOWEST_HYPERVISOR_SNAPSHOT_RESERVE);
+
+ long newSizeWithHsr = (long)(newSize + newSize * (newHypervisorSnapshotReserve / 100f));
+
+ if (newSizeWithHsr < currentSizeWithHsr) {
+ throw new CloudRuntimeException("Storage pool " + storagePoolId + " does not support shrinking a volume.");
+ }
+
+ long availableBytes = storagePool.getCapacityBytes() - getUsedBytes(storagePool);
+
+ if ((newSizeWithHsr - currentSizeWithHsr) > availableBytes) {
+ throw new CloudRuntimeException("Storage pool " + storagePoolId + " does not have enough space to expand the volume.");
+ }
+ }
+
+ private void verifySufficientIopsForStoragePool(long requestedIops, long storagePoolId) {
+ StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId);
+
+ long usedIops = getUsedIops(storagePool);
+ long capacityIops = storagePool.getCapacityIops();
+
+ if (usedIops + requestedIops > capacityIops) {
+ throw new CloudRuntimeException("Insufficient number of IOPS available in this storage pool");
+ }
+ }
+
private void verifySufficientIopsForStoragePool(long storagePoolId, long volumeId, long newMinIops) {
- StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId);
- VolumeVO volume = _volumeDao.findById(volumeId);
+ VolumeVO volume = volumeDao.findById(volumeId);
long currentMinIops = volume.getMinIops();
long diffInMinIops = newMinIops - currentMinIops;
// if the desire is for more IOPS
if (diffInMinIops > 0) {
- long usedIops = getUsedIops(storagePool);
- long capacityIops = storagePool.getCapacityIops();
+ verifySufficientIopsForStoragePool(diffInMinIops, storagePoolId);
+ }
+ }
+
+ private void deleteSolidFireVolume(SolidFireUtil.SolidFireConnection sfConnection, long csVolumeId, long sfVolumeId) {
+ List<SnapshotVO> lstSnapshots = getNonDestroyedSnapshots(csVolumeId);
+
+ boolean deleteVolume = true;
+
+ for (SnapshotVO snapshot : lstSnapshots) {
+ SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(snapshot.getId(), SolidFireUtil.SNAPSHOT_ID);
- if (usedIops + diffInMinIops > capacityIops) {
- throw new CloudRuntimeException("Insufficient number of IOPS available in this storage pool");
+ if (snapshotDetails != null && snapshotDetails.getValue() != null) {
+ deleteVolume = false;
+
+ break;
}
}
+
+ if (deleteVolume) {
+ SolidFireUtil.deleteSolidFireVolume(sfConnection, sfVolumeId);
+ }
+ }
+
+ private void deleteSolidFireSnapshot(SolidFireUtil.SolidFireConnection sfConnection, long csSnapshotId, long sfSnapshotId) {
+ SolidFireUtil.deleteSolidFireSnapshot(sfConnection, sfSnapshotId);
+
+ SnapshotVO snapshot = snapshotDao.findById(csSnapshotId);
+ VolumeVO volume = volumeDao.findById(snapshot.getVolumeId());
+
+ if (volume == null) { // if the CloudStack volume has been deleted
+ List<SnapshotVO> lstSnapshots = getNonDestroyedSnapshots(snapshot.getVolumeId());
+
+ List<SnapshotVO> lstSnapshots2 = new ArrayList<>();
+
+ for (SnapshotVO snapshotVo : lstSnapshots) {
+ // The CloudStack volume snapshot has not yet been set to the DESTROYED state, so check to make
+ // sure snapshotVo.getId() != csSnapshotId when determining if any volume snapshots remain for the given CloudStack volume.
+ if (snapshotVo.getId() != csSnapshotId) {
+ SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(snapshotVo.getId(), SolidFireUtil.SNAPSHOT_ID);
+
+ // We are only interested here in volume snapshots that make use of SolidFire snapshots (as opposed to ones
+ // that make use of SolidFire volumes).
+ if (snapshotDetails != null && snapshotDetails.getValue() != null) {
+ lstSnapshots2.add(snapshotVo);
+ }
+ }
+ }
+
+ if (lstSnapshots2.isEmpty()) {
+ volume = volumeDao.findByIdIncludingRemoved(snapshot.getVolumeId());
+
+ SolidFireUtil.deleteSolidFireVolume(sfConnection, Long.parseLong(volume.getFolder()));
+ }
+ }
+ }
+
+ private List<SnapshotVO> getNonDestroyedSnapshots(long csVolumeId) {
+ List<SnapshotVO> lstSnapshots = snapshotDao.listByVolumeId(csVolumeId);
+
+ if (lstSnapshots == null) {
+ lstSnapshots = new ArrayList<>();
+ }
+
+ List<SnapshotVO> lstSnapshots2 = new ArrayList<>();
+
+ for (SnapshotVO snapshot : lstSnapshots) {
+ if (!State.Destroyed.equals(snapshot.getState())) {
+ lstSnapshots2.add(snapshot);
+ }
+ }
+
+ return lstSnapshots2;
}
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2bd035d1/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java
index f89c97a..c47411e 100644
--- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java
+++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java
@@ -33,6 +33,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCy
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreParameters;
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.storage.datastore.util.SolidFireUtil;
import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper;
@@ -49,23 +50,27 @@ import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.storage.dao.SnapshotDao;
import com.cloud.storage.dao.SnapshotDetailsDao;
import com.cloud.storage.dao.SnapshotDetailsVO;
+import com.cloud.storage.dao.VMTemplatePoolDao;
import com.cloud.storage.SnapshotVO;
import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePoolAutomation;
+import com.cloud.storage.VMTemplateStoragePoolVO;
import com.cloud.utils.exception.CloudRuntimeException;
public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeCycle {
private static final Logger s_logger = Logger.getLogger(SolidFirePrimaryDataStoreLifeCycle.class);
@Inject private CapacityManager _capacityMgr;
- @Inject private DataCenterDao zoneDao;
- @Inject private PrimaryDataStoreDao storagePoolDao;
- @Inject private PrimaryDataStoreHelper dataStoreHelper;
+ @Inject private DataCenterDao _zoneDao;
+ @Inject private PrimaryDataStoreDao _storagePoolDao;
+ @Inject private PrimaryDataStoreHelper _dataStoreHelper;
@Inject private ResourceManager _resourceMgr;
@Inject private SnapshotDao _snapshotDao;
@Inject private SnapshotDetailsDao _snapshotDetailsDao;
@Inject private StorageManager _storageMgr;
- @Inject private StoragePoolAutomation storagePoolAutomation;
+ @Inject private StoragePoolAutomation _storagePoolAutomation;
+ @Inject private StoragePoolDetailsDao _storagePoolDetailsDao;
+ @Inject private VMTemplatePoolDao _tmpltPoolDao;
// invoked to add primary storage that is based on the SolidFire plug-in
@Override
@@ -83,7 +88,7 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
String storageVip = SolidFireUtil.getStorageVip(url);
int storagePort = SolidFireUtil.getStoragePort(url);
- DataCenterVO zone = zoneDao.findById(zoneId);
+ DataCenterVO zone = _zoneDao.findById(zoneId);
String uuid = SolidFireUtil.PROVIDER_NAME + "_" + zone.getUuid() + "_" + storageVip;
@@ -179,7 +184,7 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
details.put(SolidFireUtil.CLUSTER_DEFAULT_BURST_IOPS_PERCENT_OF_MAX_IOPS, String.valueOf(fClusterDefaultBurstIopsPercentOfMaxIops));
// this adds a row in the cloud.storage_pool table for this SolidFire cluster
- return dataStoreHelper.createPrimaryDataStore(parameters);
+ return _dataStoreHelper.createPrimaryDataStore(parameters);
}
// do not implement this method for SolidFire's plug-in
@@ -196,7 +201,7 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
@Override
public boolean attachZone(DataStore dataStore, ZoneScope scope, HypervisorType hypervisorType) {
- dataStoreHelper.attachZone(dataStore);
+ _dataStoreHelper.attachZone(dataStore);
List<HostVO> xenServerHosts = _resourceMgr.listAllUpAndEnabledHostsInOneZoneByHypervisor(HypervisorType.XenServer, scope.getScopeId());
List<HostVO> vmWareServerHosts = _resourceMgr.listAllUpAndEnabledHostsInOneZoneByHypervisor(HypervisorType.VMware, scope.getScopeId());
@@ -220,23 +225,25 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
@Override
public boolean maintain(DataStore dataStore) {
- storagePoolAutomation.maintain(dataStore);
- dataStoreHelper.maintain(dataStore);
+ _storagePoolAutomation.maintain(dataStore);
+ _dataStoreHelper.maintain(dataStore);
return true;
}
@Override
public boolean cancelMaintain(DataStore store) {
- dataStoreHelper.cancelMaintain(store);
- storagePoolAutomation.cancelMaintain(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) {
+ public boolean deleteDataStore(DataStore dataStore) {
+ long storagePoolId = dataStore.getId();
+
List<SnapshotVO> lstSnapshots = _snapshotDao.listAll();
if (lstSnapshots != null) {
@@ -244,13 +251,39 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
SnapshotDetailsVO snapshotDetails = _snapshotDetailsDao.findDetail(snapshot.getId(), SolidFireUtil.STORAGE_POOL_ID);
// if this snapshot belongs to the storagePool that was passed in
- if (snapshotDetails != null && snapshotDetails.getValue() != null && Long.parseLong(snapshotDetails.getValue()) == store.getId()) {
+ if (snapshotDetails != null && snapshotDetails.getValue() != null && Long.parseLong(snapshotDetails.getValue()) == storagePoolId) {
throw new CloudRuntimeException("This primary storage cannot be deleted because it currently contains one or more snapshots.");
}
}
}
- return dataStoreHelper.deletePrimaryDataStore(store);
+ List<VMTemplateStoragePoolVO> lstTemplatePoolRefs = _tmpltPoolDao.listByPoolId(storagePoolId);
+
+ if (lstTemplatePoolRefs != null) {
+ for (VMTemplateStoragePoolVO templatePoolRef : lstTemplatePoolRefs) {
+ try {
+ SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
+ long sfTemplateVolumeId = Long.parseLong(templatePoolRef.getLocalDownloadPath());
+
+ SolidFireUtil.deleteSolidFireVolume(sfConnection, sfTemplateVolumeId);
+ }
+ catch (Exception ex) {
+ s_logger.error(ex.getMessage() != null ? ex.getMessage() : "Error deleting SolidFire template volume");
+ }
+
+ _tmpltPoolDao.remove(templatePoolRef.getId());
+ }
+ }
+
+ StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId);
+
+ storagePool.setUsedBytes(0);
+
+ _storagePoolDao.update(storagePoolId, storagePool);
+
+ _storagePoolDetailsDao.removeDetails(storagePoolId);
+
+ return _dataStoreHelper.deletePrimaryDataStore(dataStore);
}
/* (non-Javadoc)
@@ -263,7 +296,7 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
@Override
public void updateStoragePool(StoragePool storagePool, Map<String, String> details) {
- StoragePoolVO storagePoolVo = storagePoolDao.findById(storagePool.getId());
+ StoragePoolVO storagePoolVo = _storagePoolDao.findById(storagePool.getId());
String strCapacityBytes = details.get(PrimaryDataStoreLifeCycle.CAPACITY_BYTES);
Long capacityBytes = strCapacityBytes != null ? Long.parseLong(strCapacityBytes) : null;
@@ -290,11 +323,11 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
@Override
public void enableStoragePool(DataStore dataStore) {
- dataStoreHelper.enable(dataStore);
+ _dataStoreHelper.enable(dataStore);
}
@Override
public void disableStoragePool(DataStore dataStore) {
- dataStoreHelper.disable(dataStore);
+ _dataStoreHelper.disable(dataStore);
}
}