Repository: cloudstack Updated Branches: refs/heads/hotfix/CLOUDSTACK-7776 cf2cd5866 -> 9e89a2858
Logic on SolidFire side for CloudStack snapshots Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/6beeeff7 Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/6beeeff7 Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/6beeeff7 Branch: refs/heads/hotfix/CLOUDSTACK-7776 Commit: 6beeeff7d4d53adb10794927a4f04024fc5c69ec Parents: 06f6b00 Author: Mike Tutkowski <mike.tutkow...@solidfire.com> Authored: Fri Oct 17 15:48:01 2014 -0600 Committer: Mike Tutkowski <mike.tutkow...@solidfire.com> Committed: Tue Oct 21 16:01:13 2014 -0600 ---------------------------------------------------------------------- .../driver/SolidFirePrimaryDataStoreDriver.java | 143 ++++++------------- .../storage/datastore/util/SolidFireUtil.java | 95 +++++++++++- 2 files changed, 134 insertions(+), 104 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/6beeeff7/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 931069e..1a3085a 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 @@ -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()); - - 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; - } + /** @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()); - // 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); - - 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.SNAPSHOT_STORAGE_POOL_ID, + String.valueOf(storagePoolId), + false); - _snapshotDetailsDao.persist(accountDetail); + _snapshotDetailsDao.persist(accountDetail); - accountDetail = new SnapshotDetailsVO(csSnapshotId, - SolidFireUtil.CLONE_ID, - String.valueOf(sfCloneId), - false); + accountDetail = new SnapshotDetailsVO(csSnapshotId, + SolidFireUtil.VOLUME_SIZE, + String.valueOf(sfNewVolumeSize), + false); - _snapshotDetailsDao.persist(accountDetail); + _snapshotDetailsDao.persist(accountDetail); - accountDetail = new SnapshotDetailsVO(csSnapshotId, - DataMotionStrategy.IQN, - sfCloneIqn, - false); + accountDetail = new SnapshotDetailsVO(csSnapshotId, + DataMotionStrategy.IQN, + sfNewVolumeIqn, + 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); + + long volumeId = Long.parseLong(snapshotDetails.getValue()); - _snapshotDetailsDao.removeDetails(snapshotInfo.getId()); + 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 http://git-wip-us.apache.org/repos/asf/cloudstack/blob/6beeeff7/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java ---------------------------------------------------------------------- diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java index 6ea1f37..5ea28cb 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java @@ -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 &&