mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Logic on SolidFire side for CloudStack snapshots
This commit is contained in:
parent
06f6b00cd1
commit
6beeeff7d4
@ -271,9 +271,9 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
||||
for (SnapshotVO snapshot : lstSnapshots) {
|
||||
SnapshotDetailsVO snapshotDetails = _snapshotDetailsDao.findDetail(snapshot.getId(), SolidFireUtil.SNAPSHOT_STORAGE_POOL_ID);
|
||||
|
||||
// if this snapshot belong to the storagePool that was passed in
|
||||
// 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.SNAPSHOT_SIZE);
|
||||
snapshotDetails = _snapshotDetailsDao.findDetail(snapshot.getId(), SolidFireUtil.VOLUME_SIZE);
|
||||
|
||||
if (snapshotDetails != null && snapshotDetails.getValue() != null) {
|
||||
long snapshotSize = Long.parseLong(snapshotDetails.getValue());
|
||||
@ -493,10 +493,10 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
||||
|
||||
try {
|
||||
VolumeInfo volumeInfo = snapshotInfo.getBaseVolume();
|
||||
VolumeVO volume = _volumeDao.findById(volumeInfo.getId());
|
||||
VolumeVO volumeVO = _volumeDao.findById(volumeInfo.getId());
|
||||
|
||||
long sfVolumeId = Long.parseLong(volume.getFolder());
|
||||
long storagePoolId = volume.getPoolId();
|
||||
long sfVolumeId = Long.parseLong(volumeVO.getFolder());
|
||||
long storagePoolId = volumeVO.getPoolId();
|
||||
|
||||
SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
|
||||
|
||||
@ -505,50 +505,36 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
||||
StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId);
|
||||
|
||||
long capacityBytes = storagePool.getCapacityBytes();
|
||||
// getUsedBytes(StoragePool) will not include the bytes of the proposed snapshot because
|
||||
// updateSnapshotDetails(long, long, long, long) has not yet been called for this snapshot
|
||||
// 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
|
||||
long usedBytes = getUsedBytes(storagePool);
|
||||
long sfVolumeSize = sfVolume.getTotalSize();
|
||||
|
||||
usedBytes += sfVolumeSize;
|
||||
|
||||
// For taking a snapshot, we need to check to make sure a sufficient amount of space remains in the primary storage.
|
||||
// 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.
|
||||
// Generally snapshots take up much less space than the size of the volume, but the easiest way to track this space usage
|
||||
// is to take the full size of the volume (you can always increase the amount of bytes you give to the primary storage).
|
||||
if (usedBytes > capacityBytes) {
|
||||
throw new CloudRuntimeException("Insufficient amount of space remains in this primary storage to take a snapshot");
|
||||
}
|
||||
|
||||
storagePool.setUsedBytes(usedBytes);
|
||||
|
||||
long sfSnapshotId = SolidFireUtil.createSolidFireSnapshot(sfConnection, sfVolumeId, snapshotInfo.getUuid());
|
||||
/** @todo Mike T. fill in the CloudStackVolumeSize */
|
||||
long sfNewVolumeId = SolidFireUtil.createSolidFireVolume(sfConnection, snapshotInfo.getUuid(), sfVolume.getAccountId(), sfVolumeSize,
|
||||
sfVolume.isEnable512e(), "", sfVolume.getMinIops(), sfVolume.getMaxIops(), sfVolume.getBurstIops());
|
||||
|
||||
long sfCloneId;
|
||||
String sfCloneIqn;
|
||||
|
||||
try {
|
||||
sfCloneId = SolidFireUtil.createSolidFireClone(sfConnection, sfVolumeId, sfSnapshotId, snapshotInfo.getUuid());
|
||||
|
||||
SolidFireUtil.SolidFireVolume sfClonedVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfCloneId);
|
||||
|
||||
sfCloneIqn = sfClonedVolume.getIqn();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
SolidFireUtil.deleteSolidFireSnapshot(sfConnection, sfSnapshotId);
|
||||
|
||||
throw ex;
|
||||
}
|
||||
|
||||
// Now that we have successfully taken a snapshot (for the purpose of reverting) and a clone (for the purpose of creating a template
|
||||
// and a volume), update the space usage in the storage_pool table (even though storage_pool.used_bytes is likely no longer in use).
|
||||
// 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);
|
||||
|
||||
updateSnapshotDetails(snapshotInfo.getId(), sfSnapshotId, storagePoolId, sfVolumeSize, sfCloneId, sfCloneIqn);
|
||||
SolidFireUtil.SolidFireVolume sfNewVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfNewVolumeId);
|
||||
|
||||
updateSnapshotDetails(snapshotInfo.getId(), sfNewVolumeId, storagePoolId, sfVolumeSize, sfNewVolume.getIqn());
|
||||
|
||||
SnapshotObjectTO snapshotObjectTo = (SnapshotObjectTO)snapshotInfo.getTO();
|
||||
|
||||
snapshotObjectTo.setPath(String.valueOf(sfSnapshotId));
|
||||
snapshotObjectTo.setPath(String.valueOf(sfNewVolumeId));
|
||||
|
||||
CreateObjectAnswer createObjectAnswer = new CreateObjectAnswer(snapshotObjectTo);
|
||||
|
||||
@ -567,54 +553,52 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
||||
callback.complete(result);
|
||||
}
|
||||
|
||||
private void updateSnapshotDetails(long csSnapshotId, long sfSnapshotId, long storagePoolId, long sfSnapshotSize, long sfCloneId, String sfCloneIqn) {
|
||||
private void updateSnapshotDetails(long csSnapshotId, long sfNewVolumeId, long storagePoolId, long sfNewVolumeSize, String sfNewVolumeIqn) {
|
||||
SnapshotDetailsVO accountDetail = new SnapshotDetailsVO(csSnapshotId,
|
||||
SolidFireUtil.SNAPSHOT_ID,
|
||||
String.valueOf(sfSnapshotId),
|
||||
SolidFireUtil.VOLUME_ID,
|
||||
String.valueOf(sfNewVolumeId),
|
||||
false);
|
||||
|
||||
_snapshotDetailsDao.persist(accountDetail);
|
||||
_snapshotDetailsDao.persist(accountDetail);
|
||||
|
||||
accountDetail = new SnapshotDetailsVO(csSnapshotId,
|
||||
SolidFireUtil.SNAPSHOT_STORAGE_POOL_ID,
|
||||
String.valueOf(storagePoolId),
|
||||
false);
|
||||
accountDetail = new SnapshotDetailsVO(csSnapshotId,
|
||||
SolidFireUtil.SNAPSHOT_STORAGE_POOL_ID,
|
||||
String.valueOf(storagePoolId),
|
||||
false);
|
||||
|
||||
_snapshotDetailsDao.persist(accountDetail);
|
||||
_snapshotDetailsDao.persist(accountDetail);
|
||||
|
||||
accountDetail = new SnapshotDetailsVO(csSnapshotId,
|
||||
SolidFireUtil.SNAPSHOT_SIZE,
|
||||
String.valueOf(sfSnapshotSize),
|
||||
false);
|
||||
accountDetail = new SnapshotDetailsVO(csSnapshotId,
|
||||
SolidFireUtil.VOLUME_SIZE,
|
||||
String.valueOf(sfNewVolumeSize),
|
||||
false);
|
||||
|
||||
_snapshotDetailsDao.persist(accountDetail);
|
||||
_snapshotDetailsDao.persist(accountDetail);
|
||||
|
||||
accountDetail = new SnapshotDetailsVO(csSnapshotId,
|
||||
SolidFireUtil.CLONE_ID,
|
||||
String.valueOf(sfCloneId),
|
||||
false);
|
||||
accountDetail = new SnapshotDetailsVO(csSnapshotId,
|
||||
DataMotionStrategy.IQN,
|
||||
sfNewVolumeIqn,
|
||||
false);
|
||||
|
||||
_snapshotDetailsDao.persist(accountDetail);
|
||||
|
||||
accountDetail = new SnapshotDetailsVO(csSnapshotId,
|
||||
DataMotionStrategy.IQN,
|
||||
sfCloneIqn,
|
||||
false);
|
||||
|
||||
_snapshotDetailsDao.persist(accountDetail);
|
||||
_snapshotDetailsDao.persist(accountDetail);
|
||||
}
|
||||
|
||||
// return null for no error message
|
||||
private String deleteSnapshot(SnapshotInfo snapshotInfo, long storagePoolId) {
|
||||
String errMsg = null;
|
||||
|
||||
long snapshotId = snapshotInfo.getId();
|
||||
|
||||
try {
|
||||
SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
|
||||
|
||||
SolidFireUtil.deleteSolidFireSnapshot(sfConnection, getSolidFireSnapshotId(snapshotInfo.getId()));
|
||||
SolidFireUtil.deleteSolidFireVolume(sfConnection, getSolidFireCloneId(snapshotInfo.getId()));
|
||||
SnapshotDetailsVO snapshotDetails = _snapshotDetailsDao.findDetail(snapshotId, SolidFireUtil.VOLUME_ID);
|
||||
|
||||
_snapshotDetailsDao.removeDetails(snapshotInfo.getId());
|
||||
long volumeId = Long.parseLong(snapshotDetails.getValue());
|
||||
|
||||
SolidFireUtil.deleteSolidFireVolume(sfConnection, volumeId);
|
||||
|
||||
_snapshotDetailsDao.removeDetails(snapshotId);
|
||||
|
||||
StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId);
|
||||
|
||||
@ -626,7 +610,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
||||
_storagePoolDao.update(storagePoolId, storagePool);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
s_logger.debug(SolidFireUtil.LOG_PREFIX + "Failed to delete SolidFire snapshot: " + snapshotInfo.getId(), ex);
|
||||
s_logger.debug(SolidFireUtil.LOG_PREFIX + "Failed to delete SolidFire volume. CloudStack snapshot ID: " + snapshotId, ex);
|
||||
|
||||
errMsg = ex.getMessage();
|
||||
}
|
||||
@ -634,44 +618,9 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
||||
return errMsg;
|
||||
}
|
||||
|
||||
private long getSolidFireSnapshotId(long csSnapshotId) {
|
||||
SnapshotDetailsVO snapshotDetails = _snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.SNAPSHOT_ID);
|
||||
|
||||
return Long.parseLong(snapshotDetails.getValue());
|
||||
}
|
||||
|
||||
private long getSolidFireCloneId(long csSnapshotId) {
|
||||
SnapshotDetailsVO snapshotDetails = _snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.CLONE_ID);
|
||||
|
||||
return Long.parseLong(snapshotDetails.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void revertSnapshot(SnapshotInfo snapshotInfo, AsyncCompletionCallback<CommandResult> callback) {
|
||||
String errMsg = null;
|
||||
|
||||
try {
|
||||
VolumeInfo volumeInfo = snapshotInfo.getBaseVolume();
|
||||
|
||||
long storagePoolId = volumeInfo.getPoolId();
|
||||
long sfVolumeId = Long.parseLong(volumeInfo.getFolder());
|
||||
long sfSnapshotId = getSolidFireSnapshotId(snapshotInfo.getId());
|
||||
|
||||
SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
|
||||
|
||||
SolidFireUtil.rollBackVolumeToSnapshot(sfConnection, sfVolumeId, sfSnapshotId);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
s_logger.debug(SolidFireUtil.LOG_PREFIX + "Failed to take CloudStack snapshot: " + snapshotInfo.getId(), ex);
|
||||
|
||||
errMsg = ex.getMessage();
|
||||
}
|
||||
|
||||
CommandResult result = new CommandResult();
|
||||
|
||||
result.setResult(errMsg);
|
||||
|
||||
callback.complete(result);
|
||||
throw new UnsupportedOperationException("Reverting not supported. Create a template or volume based on the snapshot instead.");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -92,11 +92,8 @@ public class SolidFireUtil {
|
||||
|
||||
public static final String ACCOUNT_ID = "accountId";
|
||||
public static final String VOLUME_ID = "volumeId";
|
||||
public static final String SNAPSHOT_ID = "snapshotId";
|
||||
public static final String CLONE_ID = "cloneId";
|
||||
|
||||
public static final String VOLUME_SIZE = "sfVolumeSize";
|
||||
public static final String SNAPSHOT_SIZE = "sfSnapshotSize";
|
||||
|
||||
public static final String SNAPSHOT_STORAGE_POOL_ID = "sfSnapshotStoragePoolId";
|
||||
|
||||
@ -513,9 +510,14 @@ public class SolidFireUtil {
|
||||
String strVolumeIqn = getVolumeIqn(volumeGetResult, lVolumeId);
|
||||
long lAccountId = getVolumeAccountId(volumeGetResult, lVolumeId);
|
||||
String strVolumeStatus = getVolumeStatus(volumeGetResult, lVolumeId);
|
||||
boolean enable512e = getVolumeEnable512e(volumeGetResult, lVolumeId);
|
||||
long lMinIops = getVolumeMinIops(volumeGetResult, lVolumeId);
|
||||
long lMaxIops = getVolumeMaxIops(volumeGetResult, lVolumeId);
|
||||
long lBurstIops = getVolumeBurstIops(volumeGetResult, lVolumeId);
|
||||
long lTotalSize = getVolumeTotalSize(volumeGetResult, lVolumeId);
|
||||
|
||||
return new SolidFireVolume(lVolumeId, strVolumeName, strVolumeIqn, lAccountId, strVolumeStatus, lTotalSize);
|
||||
return new SolidFireVolume(lVolumeId, strVolumeName, strVolumeIqn, lAccountId, strVolumeStatus, enable512e,
|
||||
lMinIops, lMaxIops, lBurstIops, lTotalSize);
|
||||
}
|
||||
|
||||
public static List<SolidFireVolume> getSolidFireVolumesForAccountId(SolidFireConnection sfConnection, long lAccountId) {
|
||||
@ -534,7 +536,8 @@ public class SolidFireUtil {
|
||||
List<SolidFireVolume> sfVolumes = new ArrayList<SolidFireVolume>();
|
||||
|
||||
for (VolumeGetResult.Result.Volume volume : volumeGetResult.result.volumes) {
|
||||
sfVolumes.add(new SolidFireVolume(volume.volumeID, volume.name, volume.iqn, volume.accountID, volume.status, volume.totalSize));
|
||||
sfVolumes.add(new SolidFireVolume(volume.volumeID, volume.name, volume.iqn, volume.accountID, volume.status, volume.enable512e,
|
||||
volume.qos.minIOPS, volume.qos.maxIOPS, volume.qos.burstIOPS, volume.totalSize));
|
||||
}
|
||||
|
||||
return sfVolumes;
|
||||
@ -557,7 +560,8 @@ public class SolidFireUtil {
|
||||
List<SolidFireVolume> deletedVolumes = new ArrayList<SolidFireVolume> ();
|
||||
|
||||
for (VolumeGetResult.Result.Volume volume : volumeGetResult.result.volumes) {
|
||||
deletedVolumes.add(new SolidFireVolume(volume.volumeID, volume.name, volume.iqn, volume.accountID, volume.status, volume.totalSize));
|
||||
deletedVolumes.add(new SolidFireVolume(volume.volumeID, volume.name, volume.iqn, volume.accountID, volume.status, volume.enable512e,
|
||||
volume.qos.minIOPS, volume.qos.maxIOPS, volume.qos.burstIOPS, volume.totalSize));
|
||||
}
|
||||
|
||||
return deletedVolumes;
|
||||
@ -593,16 +597,25 @@ public class SolidFireUtil {
|
||||
private final String _iqn;
|
||||
private final long _accountId;
|
||||
private final String _status;
|
||||
private final boolean _enable512e;
|
||||
private final long _minIops;
|
||||
private final long _maxIops;
|
||||
private final long _burstIops;
|
||||
private final long _totalSize;
|
||||
|
||||
public SolidFireVolume(long id, String name, String iqn,
|
||||
long accountId, String status, long totalSize)
|
||||
long accountId, String status, boolean enable512e,
|
||||
long minIops, long maxIops, long burstIops, long totalSize)
|
||||
{
|
||||
_id = id;
|
||||
_name = name;
|
||||
_iqn = "/" + iqn + "/0";
|
||||
_accountId = accountId;
|
||||
_status = status;
|
||||
_enable512e = enable512e;
|
||||
_minIops = minIops;
|
||||
_maxIops = maxIops;
|
||||
_burstIops = burstIops;
|
||||
_totalSize = totalSize;
|
||||
}
|
||||
|
||||
@ -626,6 +639,22 @@ public class SolidFireUtil {
|
||||
return ACTIVE.equalsIgnoreCase(_status);
|
||||
}
|
||||
|
||||
public boolean isEnable512e() {
|
||||
return _enable512e;
|
||||
}
|
||||
|
||||
public long getMinIops() {
|
||||
return _minIops;
|
||||
}
|
||||
|
||||
public long getMaxIops() {
|
||||
return _maxIops;
|
||||
}
|
||||
|
||||
public long getBurstIops() {
|
||||
return _burstIops;
|
||||
}
|
||||
|
||||
public long getTotalSize() {
|
||||
return _totalSize;
|
||||
}
|
||||
@ -1562,7 +1591,15 @@ public class SolidFireUtil {
|
||||
private String iqn;
|
||||
private long accountID;
|
||||
private String status;
|
||||
private boolean enable512e;
|
||||
private Qos qos;
|
||||
private long totalSize;
|
||||
|
||||
private static final class Qos {
|
||||
private long minIOPS;
|
||||
private long maxIOPS;
|
||||
private long burstIOPS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1790,6 +1827,50 @@ public class SolidFireUtil {
|
||||
throw new CloudRuntimeException("Could not determine the status of the volume for volume ID of " + lVolumeId + ".");
|
||||
}
|
||||
|
||||
private static boolean getVolumeEnable512e(VolumeGetResult volumeGetResult, long lVolumeId)
|
||||
{
|
||||
if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 &&
|
||||
volumeGetResult.result.volumes[0].volumeID == lVolumeId)
|
||||
{
|
||||
return volumeGetResult.result.volumes[0].enable512e;
|
||||
}
|
||||
|
||||
throw new CloudRuntimeException("Could not determine the enable 512 emulation of the volume for volume ID of " + lVolumeId + ".");
|
||||
}
|
||||
|
||||
private static long getVolumeMinIops(VolumeGetResult volumeGetResult, long lVolumeId)
|
||||
{
|
||||
if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 &&
|
||||
volumeGetResult.result.volumes[0].volumeID == lVolumeId && volumeGetResult.result.volumes[0].qos != null)
|
||||
{
|
||||
return volumeGetResult.result.volumes[0].qos.minIOPS;
|
||||
}
|
||||
|
||||
throw new CloudRuntimeException("Could not determine the min IOPS of the volume for volume ID of " + lVolumeId + ".");
|
||||
}
|
||||
|
||||
private static long getVolumeMaxIops(VolumeGetResult volumeGetResult, long lVolumeId)
|
||||
{
|
||||
if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 &&
|
||||
volumeGetResult.result.volumes[0].volumeID == lVolumeId && volumeGetResult.result.volumes[0].qos != null)
|
||||
{
|
||||
return volumeGetResult.result.volumes[0].qos.maxIOPS;
|
||||
}
|
||||
|
||||
throw new CloudRuntimeException("Could not determine the max IOPS of the volume for volume ID of " + lVolumeId + ".");
|
||||
}
|
||||
|
||||
private static long getVolumeBurstIops(VolumeGetResult volumeGetResult, long lVolumeId)
|
||||
{
|
||||
if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 &&
|
||||
volumeGetResult.result.volumes[0].volumeID == lVolumeId && volumeGetResult.result.volumes[0].qos != null)
|
||||
{
|
||||
return volumeGetResult.result.volumes[0].qos.burstIOPS;
|
||||
}
|
||||
|
||||
throw new CloudRuntimeException("Could not determine the burst IOPS of the volume for volume ID of " + lVolumeId + ".");
|
||||
}
|
||||
|
||||
private static long getVolumeTotalSize(VolumeGetResult volumeGetResult, long lVolumeId)
|
||||
{
|
||||
if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 &&
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user