Update to volume-resize logic
Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/3773ff06 Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/3773ff06 Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/3773ff06 Branch: refs/heads/saml2 Commit: 3773ff060e994d665b3b6d37f79df40c19a74c26 Parents: 1436ce6 Author: Mike Tutkowski <mike.tutkow...@solidfire.com> Authored: Thu Aug 21 14:47:40 2014 -0600 Committer: Mike Tutkowski <mike.tutkow...@solidfire.com> Committed: Thu Aug 21 20:18:20 2014 -0600 ---------------------------------------------------------------------- .../xenserver/resource/CitrixResourceBase.java | 3 +- .../driver/SolidFirePrimaryDataStoreDriver.java | 4 +- ...olidFireSharedPrimaryDataStoreLifeCycle.java | 2 +- .../storage/datastore/util/SolidFireUtil.java | 60 +++++++++++++++++++- .../com/cloud/storage/VolumeApiServiceImpl.java | 49 ++++++++++++---- 5 files changed, 98 insertions(+), 20 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3773ff06/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java ---------------------------------------------------------------------- diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java index e391b3e..3ba8271 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java @@ -1928,7 +1928,6 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe Long volumeSize = Long.parseLong(details.get(DiskTO.VOLUME_SIZE)); if (vdi == null) { - vdi = createVdi(sr, vdiNameLabel, volumeSize); } else { // if VDI is not null, it must have already been created, so check whether a resize of the volume was performed @@ -1939,7 +1938,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe long vdiVirtualSize = vdi.getVirtualSize(conn); if (vdiVirtualSize != volumeSize) { - s_logger.info("resizing the datadisk(vdi) from vdiVirtualsize :"+ vdiVirtualSize + "to volumeSize :" + volumeSize); + s_logger.info("resizing the data disk (vdi) from vdiVirtualsize: "+ vdiVirtualSize + " to volumeSize: " + volumeSize); try { vdi.resize(conn, volumeSize); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3773ff06/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 2228c59..6eee9fe 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 @@ -420,8 +420,8 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { verifySufficientIopsForStoragePool(storagePoolId, volumeInfo.getId(), payload.newMinIops); - SolidFireUtil.modifySolidFireVolume(sfConnection, sfVolumeId, sfVolume.getTotalSize(), payload.newMinIops, payload.newMaxIops, - getDefaultBurstIops(storagePoolId, payload.newMaxIops)); + SolidFireUtil.modifySolidFireVolume(sfConnection, sfVolumeId, sfVolume.getTotalSize(), NumberFormat.getInstance().format(payload.newSize), + payload.newMinIops, payload.newMaxIops, getDefaultBurstIops(storagePoolId, payload.newMaxIops)); VolumeVO volume = _volumeDao.findById(volumeInfo.getId()); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3773ff06/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java ---------------------------------------------------------------------- diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java index 5065822..30d6659 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java @@ -621,7 +621,7 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor } } - SolidFireUtil.modifySolidFireVolume(sfConnection, getVolumeId(storagePool.getId()), size, minIops, maxIops, burstIops); + SolidFireUtil.modifySolidFireVolume(sfConnection, getVolumeId(storagePool.getId()), size, null, minIops, maxIops, burstIops); SolidFireUtil.updateCsDbWithSolidFireIopsInfo(storagePool.getId(), _primaryDataStoreDao, _storagePoolDetailsDao, minIops, maxIops, burstIops); } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3773ff06/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 307ddbc..2aa8914 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 @@ -467,11 +467,14 @@ public class SolidFireUtil { return volumeCreateResult.result.volumeID; } - public static void modifySolidFireVolume(SolidFireConnection sfConnection, long volumeId, long totalSize, long minIops, long maxIops, long burstIops) + public static void modifySolidFireVolume(SolidFireConnection sfConnection, long volumeId, long totalSize, String strCloudStackVolumeSize, + long minIops, long maxIops, long burstIops) { final Gson gson = new GsonBuilder().create(); - VolumeToModify volumeToModify = new VolumeToModify(volumeId, totalSize, minIops, maxIops, burstIops); + Object volumeToModify = strCloudStackVolumeSize != null && strCloudStackVolumeSize.trim().length() > 0 ? + new VolumeToModifyWithCloudStackVolumeSize(volumeId, totalSize, strCloudStackVolumeSize, minIops, maxIops, burstIops) : + new VolumeToModify(volumeId, totalSize, minIops, maxIops, burstIops); String strVolumeToModifyJson = gson.toJson(volumeToModify); @@ -947,8 +950,8 @@ public class SolidFireUtil { private final long accountID; private final long totalSize; private final boolean enable512e; - private final VolumeToCreateParamsQoS qos; private final VolumeToCreateParamsAttributes attributes; + private final VolumeToCreateParamsQoS qos; private VolumeToCreateParams(final String strVolumeName, final long lAccountId, final long lTotalSize, final boolean bEnable512e, final String strCloudStackVolumeSize, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) { @@ -1025,6 +1028,57 @@ public class SolidFireUtil { } @SuppressWarnings("unused") + private static final class VolumeToModifyWithCloudStackVolumeSize + { + private final String method = "ModifyVolume"; + private final VolumeToModifyParams params; + + private VolumeToModifyWithCloudStackVolumeSize(final long lVolumeId, final long lTotalSize, final String strCloudStackVolumeSize, + final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) + { + params = new VolumeToModifyParams(lVolumeId, lTotalSize, strCloudStackVolumeSize, lMinIOPS, lMaxIOPS, lBurstIOPS); + } + + private static final class VolumeToModifyParams + { + private final long volumeID; + private final long totalSize; + private final VolumeToModifyParamsAttributes attributes; + private final VolumeToModifyParamsQoS qos; + + private VolumeToModifyParams(final long lVolumeId, final long lTotalSize, String strCloudStackVolumeSize, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) + { + volumeID = lVolumeId; + + totalSize = lTotalSize; + + attributes = new VolumeToModifyParamsAttributes(strCloudStackVolumeSize); + qos = new VolumeToModifyParamsQoS(lMinIOPS, lMaxIOPS, lBurstIOPS); + } + } + + private static final class VolumeToModifyParamsAttributes { + private final String CloudStackVolumeSize; + + private VolumeToModifyParamsAttributes(final String strCloudStackVolumeSize) { + CloudStackVolumeSize = strCloudStackVolumeSize; + } + } + + private static final class VolumeToModifyParamsQoS { + private final long minIOPS; + private final long maxIOPS; + private final long burstIOPS; + + private VolumeToModifyParamsQoS(final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) { + minIOPS = lMinIOPS; + maxIOPS = lMaxIOPS; + burstIOPS = lBurstIOPS; + } + } + } + + @SuppressWarnings("unused") private static final class VolumeToModify { private final String method = "ModifyVolume"; http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3773ff06/server/src/com/cloud/storage/VolumeApiServiceImpl.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/com/cloud/storage/VolumeApiServiceImpl.java index 0734385..0c7c6e5 100644 --- a/server/src/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/com/cloud/storage/VolumeApiServiceImpl.java @@ -851,7 +851,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic } } - // Note: The storage plug-in in question should perform validation on the IOPS to check if a sufficient number of IOPS are available to perform + // Note: The storage plug-in in question should perform validation on the IOPS to check if a sufficient number of IOPS is available to perform // the requested change /* If this volume has never been beyond allocated state, short circuit everything and simply update the database. */ @@ -970,9 +970,21 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic hosts = new long[] {userVm.getLastHostId()}; } + final String errorMsg = "The VM must be stopped or the disk detached in order to resize with the XenServer Hypervisor."; + + StoragePoolVO storagePool = _storagePoolDao.findById(volume.getPoolId()); + + if (storagePool.isManaged() && storagePool.getHypervisor() == HypervisorType.Any && hosts != null && hosts.length > 0) { + HostVO host = this._hostDao.findById(hosts[0]); + + if (currentSize != newSize && host.getHypervisorType() == HypervisorType.XenServer && !userVm.getState().equals(State.Stopped)) { + throw new InvalidParameterValueException(errorMsg); + } + } + /* Xen only works offline, SR does not support VDI.resizeOnline */ if (currentSize != newSize && _volsDao.getHypervisorType(volume.getId()) == HypervisorType.XenServer && !userVm.getState().equals(State.Stopped)) { - throw new InvalidParameterValueException("VM must be stopped or disk detached in order to resize with the Xen HV"); + throw new InvalidParameterValueException(errorMsg); } } @@ -982,8 +994,30 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic VolumeInfo vol = volFactory.getVolume(volume.getId()); vol.addPayload(payload); + StoragePoolVO storagePool = _storagePoolDao.findById(vol.getPoolId()); + + // managed storage is designed in such a way that the storage plug-in does not + // talk to the hypervisor layer; as such, if the storage is managed and the + // current and new sizes are different, then CloudStack (i.e. not a storage plug-in) + // needs to tell the hypervisor to resize the disk + if (storagePool.isManaged() && currentSize != newSize) { + if (hosts != null && hosts.length > 0) { + volService.resizeVolumeOnHypervisor(volumeId, newSize, hosts[0], instanceName); + } + + volume.setSize(newSize); + + _volsDao.update(volume.getId(), volume); + } + + // this call to resize has a different impact depending on whether the + // underlying primary storage is managed or not + // if managed, this is the chance for the plug-in to change IOPS value, if applicable + // if not managed, this is the chance for the plug-in to talk to the hypervisor layer + // to change the size of the disk AsyncCallFuture<VolumeApiResult> future = volService.resize(vol); VolumeApiResult result = future.get(); + if (result.isFailed()) { s_logger.warn("Failed to resize the volume " + volume); String details = ""; @@ -995,19 +1029,10 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic volume = _volsDao.findById(volume.getId()); - StoragePoolVO storagePool = _storagePoolDao.findById(vol.getPoolId()); - - if (currentSize != newSize && storagePool.isManaged()) { - if (hosts != null && hosts.length > 0) { - volService.resizeVolumeOnHypervisor(volumeId, newSize, hosts[0], instanceName); - } - - volume.setSize(newSize); - } - if (newDiskOfferingId != null) { volume.setDiskOfferingId(newDiskOfferingId); } + _volsDao.update(volume.getId(), volume); // Log usage event for volumes belonging user VM's only UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_RESIZE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(),