diff --git a/engine/components-api/src/com/cloud/storage/StorageManager.java b/engine/components-api/src/com/cloud/storage/StorageManager.java index 530a7dea3cc..a532a4f41e7 100644 --- a/engine/components-api/src/com/cloud/storage/StorageManager.java +++ b/engine/components-api/src/com/cloud/storage/StorageManager.java @@ -178,6 +178,8 @@ public interface StorageManager extends StorageService { */ boolean storagePoolHasEnoughSpace(List volume, StoragePool pool, Long clusterId); + boolean storagePoolHasEnoughSpaceForResize(StoragePool pool, long currentSize, long newSiz); + boolean registerHostListener(String providerUuid, HypervisorHostListener listener); void connectHostToSharedPool(long hostId, long poolId) throws StorageUnavailableException, StorageConflictException; diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index 610789f5de2..44c8189f6e1 100644 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -1788,8 +1788,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C if (s_logger.isDebugEnabled()) { s_logger.debug("Destination pool id: " + pool.getId()); } - - StoragePoolVO poolVO = _storagePoolDao.findById(pool.getId()); + // allocated space includes templates + final StoragePoolVO poolVO = _storagePoolDao.findById(pool.getId()); long allocatedSizeWithTemplate = _capacityMgr.getAllocatedPoolCapacity(poolVO, null); long totalAskingSize = 0; @@ -1830,12 +1830,37 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } } + return checkPoolforSpace(pool, allocatedSizeWithTemplate, totalAskingSize); + } + + @Override + public boolean storagePoolHasEnoughSpaceForResize(StoragePool pool, long currentSize, long newSiz) { + if (!checkUsagedSpace(pool)) { + return false; + } + if (s_logger.isDebugEnabled()) { + s_logger.debug("Destination pool id: " + pool.getId()); + } + long totalAskingSize = newSiz - currentSize; + + if (totalAskingSize <= 0) { + return true; + } else { + final StoragePoolVO poolVO = _storagePoolDao.findById(pool.getId()); + final long allocatedSizeWithTemplate = _capacityMgr.getAllocatedPoolCapacity(poolVO, null); + return checkPoolforSpace(pool, allocatedSizeWithTemplate, totalAskingSize); + } + } + + private boolean checkPoolforSpace(StoragePool pool, long allocatedSizeWithTemplate, long totalAskingSize) { + // allocated space includes templates + StoragePoolVO poolVO = _storagePoolDao.findById(pool.getId()); + long totalOverProvCapacity; if (pool.getPoolType().supportsOverProvisioning()) { BigDecimal overProvFactor = getStorageOverProvisioningFactor(pool.getId()); totalOverProvCapacity = overProvFactor.multiply(new BigDecimal(pool.getCapacityBytes())).longValue(); - s_logger.debug("Found storage pool " + poolVO.getName() + " of type " + pool.getPoolType().toString() + " with overprovisioning factor " + overProvFactor.toString()); s_logger.debug("Total over provisioned capacity calculated is " + overProvFactor + " * " + pool.getCapacityBytes()); } else { @@ -1847,21 +1872,26 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C s_logger.debug("Total capacity of the pool " + poolVO.getName() + " with ID " + pool.getId() + " is " + totalOverProvCapacity); double storageAllocatedThreshold = CapacityManager.StorageAllocatedCapacityDisableThreshold.valueIn(pool.getDataCenterId()); - - s_logger.debug("Checking pool: " + pool.getId() + " for volume allocation " + volumes.toString() + ", maxSize : " + totalOverProvCapacity + ", totalAllocatedSize : " - + allocatedSizeWithTemplate + ", askingSize : " + totalAskingSize + ", allocated disable threshold: " + storageAllocatedThreshold); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Checking pool: " + pool.getId() + " for storage allocation , maxSize : " + totalOverProvCapacity + ", totalAllocatedSize : " + allocatedSizeWithTemplate + + ", askingSize : " + totalAskingSize + ", allocated disable threshold: " + storageAllocatedThreshold); + } double usedPercentage = (allocatedSizeWithTemplate + totalAskingSize) / (double)(totalOverProvCapacity); if (usedPercentage > storageAllocatedThreshold) { - s_logger.debug("Insufficient un-allocated capacity on: " + pool.getId() + " for volume allocation: " + volumes.toString() + " since its allocated percentage: " + usedPercentage - + " has crossed the allocated pool.storage.allocated.capacity.disablethreshold: " + storageAllocatedThreshold + ", skipping this pool"); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Insufficient un-allocated capacity on: " + pool.getId() + " for storage allocation since its allocated percentage: " + usedPercentage + + " has crossed the allocated pool.storage.allocated.capacity.disablethreshold: " + storageAllocatedThreshold + ", skipping this pool"); + } return false; } if (totalOverProvCapacity < (allocatedSizeWithTemplate + totalAskingSize)) { - s_logger.debug("Insufficient un-allocated capacity on: " + pool.getId() + " for volume allocation: " + volumes.toString() + ", not enough storage, maxSize : " + totalOverProvCapacity - + ", totalAllocatedSize : " + allocatedSizeWithTemplate + ", askingSize : " + totalAskingSize); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Insufficient un-allocated capacity on: " + pool.getId() + " for storage allocation, not enough storage, maxSize : " + totalOverProvCapacity + + ", totalAllocatedSize : " + allocatedSizeWithTemplate + ", askingSize : " + totalAskingSize); + } return false; } diff --git a/server/src/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/com/cloud/storage/VolumeApiServiceImpl.java index 5e3bf54da19..372ab3423af 100644 --- a/server/src/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/com/cloud/storage/VolumeApiServiceImpl.java @@ -19,6 +19,7 @@ package com.cloud.storage; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -1137,6 +1138,10 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic UserVmVO userVm = _userVmDao.findById(volume.getInstanceId()); StoragePoolVO storagePool = _storagePoolDao.findById(volume.getPoolId()); boolean isManaged = storagePool.isManaged(); + + if (!storageMgr.storagePoolHasEnoughSpaceForResize(storagePool, currentSize, newSize)) { + throw new CloudRuntimeException("Storage pool " + storagePool.getName() + " does not have enough space to resize volume " + volume.getName()); + } /* * get a list of hosts to send the commands to, try the system the * associated vm is running on first, then the last known place it ran. @@ -2061,6 +2066,10 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic throw new InvalidParameterValueException("Cannot migrate volume " + vol + "to the destination storage pool " + destPool.getName() + " as the storage pool is in maintenance mode."); } + if (!storageMgr.storagePoolHasEnoughSpace(Collections.singletonList(vol), destPool)) { + throw new CloudRuntimeException("Storage pool " + destPool.getName() + " does not have enough space to migrate volume " + vol.getName()); + } + if (_volumeMgr.volumeOnSharedStoragePool(vol)) { if (destPool.isLocal()) { throw new InvalidParameterValueException("Migration of volume from shared to local storage pool is not supported");