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 2026/04/13 08:29:10 UTC
(cloudstack) 08/25: [22.0] resource reservation on volume snapshot creation
This is an automated email from the ASF dual-hosted git repository.
dahn pushed a commit to branch 22.0.1-fixes
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
commit 3d678e726ad3336fcd6bf4d991f34fa5de0e4fb8
Author: Daniel Augusto Veronezi Salvador <gu...@apache.org>
AuthorDate: Wed Feb 18 15:16:50 2026 +0100
[22.0] resource reservation on volume snapshot creation
---
.../storage/snapshot/SnapshotManagerImpl.java | 151 ++++++++++-----------
.../storage/snapshot/SnapshotManagerTest.java | 55 ++++----
2 files changed, 101 insertions(+), 105 deletions(-)
diff --git a/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java
index 4f91a66552e..fdc661d72b6 100755
--- a/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java
+++ b/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java
@@ -16,8 +16,6 @@
// under the License.
package com.cloud.storage.snapshot;
-
-import com.cloud.storage.StoragePoolStatus;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -36,9 +34,6 @@ import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
-import com.cloud.host.dao.HostDao;
-import com.cloud.storage.Upload;
-import com.cloud.storage.dao.SnapshotDetailsDao;
import org.apache.cloudstack.acl.SecurityChecker;
import com.cloud.api.ApiDBUtils;
import org.apache.cloudstack.annotation.AnnotationService;
@@ -77,6 +72,7 @@ import org.apache.cloudstack.framework.config.Configurable;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.framework.jobs.AsyncJob;
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
+import org.apache.cloudstack.reservation.dao.ReservationDao;
import org.apache.cloudstack.resourcedetail.SnapshotPolicyDetailVO;
import org.apache.cloudstack.resourcedetail.dao.SnapshotPolicyDetailsDao;
import org.apache.cloudstack.snapshot.SnapshotHelper;
@@ -119,10 +115,12 @@ import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.exception.StorageUnavailableException;
import com.cloud.host.HostVO;
+import com.cloud.host.dao.HostDao;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.org.Grouping;
import com.cloud.projects.Project.ListProjectResourcesCriteria;
import com.cloud.resource.ResourceManager;
+import com.cloud.resourcelimit.CheckedReservation;
import com.cloud.server.ResourceTag.ResourceObjectType;
import com.cloud.server.TaggedResourceService;
import com.cloud.storage.CreateSnapshotPayload;
@@ -135,15 +133,18 @@ import com.cloud.storage.SnapshotPolicyVO;
import com.cloud.storage.SnapshotScheduleVO;
import com.cloud.storage.SnapshotVO;
import com.cloud.storage.Storage;
+import com.cloud.storage.StoragePoolStatus;
import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePool;
+import com.cloud.storage.Upload;
import com.cloud.storage.VMTemplateStorageResourceAssoc;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.Volume;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.DiskOfferingDao;
+import com.cloud.storage.dao.SnapshotDetailsDao;
import com.cloud.storage.dao.SnapshotDao;
import com.cloud.storage.dao.SnapshotPolicyDao;
import com.cloud.storage.dao.SnapshotScheduleDao;
@@ -251,7 +252,8 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
public TaggedResourceService taggedResourceService;
@Inject
private AnnotationDao annotationDao;
-
+ @Inject
+ private ReservationDao reservationDao;
@Inject
protected SnapshotHelper snapshotHelper;
@Inject
@@ -312,7 +314,7 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
hostIdsToTryFirst = new long[] {vmHostId};
}
- List<Long> hostIdsToAvoid = new ArrayList<Long>();
+ List<Long> hostIdsToAvoid = new ArrayList<>();
for (int retry = _totalRetries; retry >= 0; retry--) {
try {
Pair<Long, Answer> result = _storageMgr.sendToPool(pool, hostIdsToTryFirst, hostIdsToAvoid, cmd);
@@ -377,12 +379,12 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
if (instanceId != null) {
UserVmVO vm = _vmDao.findById(instanceId);
if (vm.getState() != State.Stopped && vm.getState() != State.Shutdown) {
- throw new InvalidParameterValueException("The VM the specified disk is attached to is not in the shutdown state.");
+ throw new InvalidParameterValueException("The Instance the specified disk is attached to is not in the shutdown state.");
}
// If target VM has associated VM snapshots then don't allow to revert from snapshot
List<VMSnapshotVO> vmSnapshots = _vmSnapshotDao.findByVm(instanceId);
if (vmSnapshots.size() > 0 && !Type.GROUP.name().equals(snapshot.getTypeDescription())) {
- throw new InvalidParameterValueException("Unable to revert snapshot for VM, please remove VM snapshots before reverting VM from snapshot");
+ throw new InvalidParameterValueException("Unable to revert Snapshot for Instance, please remove Instance Snapshots before reverting Instance from Snapshot");
}
}
@@ -412,7 +414,7 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
}
public void updateVolumeSizeAndPrimaryStorageCount(VolumeVO volume, SnapshotVO snapshot) {
- Long differenceBetweenVolumeAndSnapshotSize = new Long(volume.getSize() - snapshot.getSize());
+ Long differenceBetweenVolumeAndSnapshotSize = volume.getSize() - snapshot.getSize();
if (differenceBetweenVolumeAndSnapshotSize != 0) {
if (differenceBetweenVolumeAndSnapshotSize > 0) {
_resourceLimitMgr.decrementResourceCount(snapshot.getAccountId(), ResourceType.primary_storage, differenceBetweenVolumeAndSnapshotSize);
@@ -661,7 +663,7 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
//Double check the snapshot is removed or not
SnapshotVO parentSnap = _snapshotDao.findById(parentSnapshotDataStoreVO.getSnapshotId());
if (parentSnap != null && parentSnapshotDataStoreVO.getInstallPath() != null && parentSnapshotDataStoreVO.getInstallPath().equals(vmSnapshot.getName())) {
- throw new InvalidParameterValueException("Creating snapshot failed due to snapshot : " + parentSnap.getUuid() + " is created from the same vm snapshot");
+ throw new InvalidParameterValueException("Creating Snapshot failed due to Snapshot : " + parentSnap.getUuid() + " is created from the same Instance Snapshot");
}
}
SnapshotInfo snapshotInfo = this.snapshotFactory.getSnapshot(snapshotId, store);
@@ -675,20 +677,19 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
_snapshotDao.update(snapshot.getId(), snapshot);
snapshotInfo = this.snapshotFactory.getSnapshot(snapshotId, store);
- Long snapshotOwnerId = vm.getAccountId();
+ long snapshotOwnerId = vm.getAccountId();
try {
SnapshotStrategy snapshotStrategy = _storageStrategyFactory.getSnapshotStrategy(snapshot, SnapshotOperation.BACKUP);
if (snapshotStrategy == null) {
- throw new CloudRuntimeException(String.format("Unable to find snapshot strategy to handle snapshot [%s]", snapshot));
+ throw new CloudRuntimeException(String.format("Unable to find Snapshot strategy to handle Snapshot [%s]", snapshot));
}
snapshotInfo = snapshotStrategy.backupSnapshot(snapshotInfo);
-
} catch (Exception e) {
- logger.debug("Failed to backup snapshot from vm snapshot", e);
+ logger.debug("Failed to backup Snapshot from Instance Snapshot", e);
_resourceLimitMgr.decrementResourceCount(snapshotOwnerId, ResourceType.snapshot);
- _resourceLimitMgr.decrementResourceCount(snapshotOwnerId, ResourceType.secondary_storage, new Long(volume.getSize()));
- throw new CloudRuntimeException("Failed to backup snapshot from vm snapshot", e);
+ _resourceLimitMgr.decrementResourceCount(snapshotOwnerId, ResourceType.secondary_storage, volume.getSize());
+ throw new CloudRuntimeException("Failed to backup Snapshot from Instance Snapshot", e);
} finally {
if (snapshotOnPrimaryStore != null) {
_snapshotStoreDao.remove(snapshotOnPrimaryStore.getId());
@@ -893,53 +894,44 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
_accountMgr.checkAccess(caller, null, true, snapshotCheck);
SnapshotStrategy snapshotStrategy = _storageStrategyFactory.getSnapshotStrategy(snapshotCheck, zoneId, SnapshotOperation.DELETE);
-
if (snapshotStrategy == null) {
logger.error("Unable to find snapshot strategy to handle snapshot [{}]", snapshotCheck);
-
return false;
}
Pair<List<SnapshotDataStoreVO>, List<Long>> storeRefAndZones = getStoreRefsAndZonesForSnapshotDelete(snapshotId, zoneId);
List<SnapshotDataStoreVO> snapshotStoreRefs = storeRefAndZones.first();
List<Long> zoneIds = storeRefAndZones.second();
- boolean result = snapshotStrategy.deleteSnapshot(snapshotId, zoneId);
- if (result) {
- for (Long zId : zoneIds) {
- if (snapshotCheck.getState() == Snapshot.State.BackedUp) {
- UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_DELETE, snapshotCheck.getAccountId(), zId, snapshotId,
- snapshotCheck.getName(), null, null, 0L, snapshotCheck.getClass().getName(), snapshotCheck.getUuid());
+ try {
+ boolean result = snapshotStrategy.deleteSnapshot(snapshotId, zoneId);
+ if (result) {
+ for (Long zId : zoneIds) {
+ if (snapshotCheck.getState() == Snapshot.State.BackedUp) {
+ UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_DELETE, snapshotCheck.getAccountId(), zId, snapshotId,
+ snapshotCheck.getName(), null, null, 0L, snapshotCheck.getClass().getName(), snapshotCheck.getUuid());
+ }
}
- }
- final SnapshotVO postDeleteSnapshotEntry = _snapshotDao.findById(snapshotId);
- if (postDeleteSnapshotEntry == null || Snapshot.State.Destroyed.equals(postDeleteSnapshotEntry.getState())) {
- annotationDao.removeByEntityType(AnnotationService.EntityType.SNAPSHOT.name(), snapshotCheck.getUuid());
+ final SnapshotVO postDeleteSnapshotEntry = _snapshotDao.findById(snapshotId);
+ if (postDeleteSnapshotEntry == null || Snapshot.State.Destroyed.equals(postDeleteSnapshotEntry.getState())) {
+ annotationDao.removeByEntityType(AnnotationService.EntityType.SNAPSHOT.name(), snapshotCheck.getUuid());
- if (snapshotCheck.getState() != Snapshot.State.Error && snapshotCheck.getState() != Snapshot.State.Destroyed) {
- _resourceLimitMgr.decrementResourceCount(snapshotCheck.getAccountId(), ResourceType.snapshot);
+ if (snapshotCheck.getState() != Snapshot.State.Error && snapshotCheck.getState() != Snapshot.State.Destroyed) {
+ _resourceLimitMgr.decrementResourceCount(snapshotCheck.getAccountId(), ResourceType.snapshot);
+ }
}
- }
- for (SnapshotDataStoreVO snapshotStoreRef : snapshotStoreRefs) {
- if (ObjectInDataStoreStateMachine.State.Ready.equals(snapshotStoreRef.getState()) && !DataStoreRole.Primary.equals(snapshotStoreRef.getRole())) {
- _resourceLimitMgr.decrementResourceCount(snapshotCheck.getAccountId(), ResourceType.secondary_storage, new Long(snapshotStoreRef.getPhysicalSize()));
+ for (SnapshotDataStoreVO snapshotStoreRef : snapshotStoreRefs) {
+ if (ObjectInDataStoreStateMachine.State.Ready.equals(snapshotStoreRef.getState()) && !DataStoreRole.Primary.equals(snapshotStoreRef.getRole())) {
+ _resourceLimitMgr.decrementResourceCount(snapshotCheck.getAccountId(), ResourceType.secondary_storage, snapshotStoreRef.getPhysicalSize());
+ }
}
}
- }
- final SnapshotVO postDeleteSnapshotEntry = _snapshotDao.findById(snapshotId);
- if (postDeleteSnapshotEntry == null || Snapshot.State.Destroyed.equals(postDeleteSnapshotEntry.getState())) {
- annotationDao.removeByEntityType(AnnotationService.EntityType.SNAPSHOT.name(), snapshotCheck.getUuid());
- if (snapshotCheck.getState() != Snapshot.State.Error && snapshotCheck.getState() != Snapshot.State.Destroyed) {
- _resourceLimitMgr.decrementResourceCount(snapshotCheck.getAccountId(), ResourceType.snapshot);
- }
- }
- for (SnapshotDataStoreVO snapshotStoreRef : snapshotStoreRefs) {
- if (ObjectInDataStoreStateMachine.State.Ready.equals(snapshotStoreRef.getState()) && !DataStoreRole.Primary.equals(snapshotStoreRef.getRole())) {
- _resourceLimitMgr.decrementResourceCount(snapshotCheck.getAccountId(), ResourceType.secondary_storage, new Long(snapshotStoreRef.getPhysicalSize()));
- }
- }
+ return result;
+ } catch (Exception e) {
+ logger.debug("Failed to delete snapshot {}:{}", snapshotCheck, e.toString());
- return result;
+ throw new CloudRuntimeException("Failed to delete snapshot:" + e.toString());
+ }
}
@Override
@@ -953,7 +945,7 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
Map<String, String> tags = cmd.getTags();
Long zoneId = cmd.getZoneId();
Account caller = CallContext.current().getCallingAccount();
- List<Long> permittedAccounts = new ArrayList<Long>();
+ List<Long> permittedAccounts = new ArrayList<>();
// Verify parameters
if (volumeId != null) {
@@ -965,7 +957,7 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
List<Long> ids = getIdsListFromCmd(cmd.getId(), cmd.getIds());
- Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(cmd.getDomainId(),
+ Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<>(cmd.getDomainId(),
cmd.isRecursive(), null);
_accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false);
Long domainId = domainIdRecursiveListProject.first();
@@ -1058,7 +1050,7 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
}
Pair<List<SnapshotVO>, Integer> result = _snapshotDao.searchAndCount(sc, searchFilter);
- return new Pair<List<? extends Snapshot>, Integer>(result.first(), result.second());
+ return new Pair<>(result.first(), result.second());
}
@Override
@@ -1118,7 +1110,7 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
if (Type.MANUAL == snapshot.getRecurringType()) {
_resourceLimitMgr.decrementResourceCount(accountId, ResourceType.snapshot);
for (SnapshotDataStoreVO snapshotStoreRef : snapshotStoreRefs) {
- _resourceLimitMgr.decrementResourceCount(accountId, ResourceType.secondary_storage, new Long(snapshotStoreRef.getPhysicalSize()));
+ _resourceLimitMgr.decrementResourceCount(accountId, ResourceType.secondary_storage, snapshotStoreRef.getPhysicalSize());
}
}
@@ -1147,7 +1139,6 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
throw new InvalidParameterValueException("Backing up of snapshot is not supported by the zone of the volume. Snapshots can not be taken for multiple zones");
}
boolean isRootAdminCaller = _accountMgr.isRootAdmin(caller.getId());
-
if (hasZones) {
for (Long zoneId : zoneIds) {
getCheckedDestinationZoneForSnapshotCopy(zoneId, isRootAdminCaller);
@@ -1283,7 +1274,6 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
logger.debug("Acquired lock for creating snapshot policy [{}] for volume {}.", intervalType, volume);
-
try {
SnapshotPolicyVO policy = _snapshotPolicyDao.findOneByVolumeInterval(volumeId, intervalType);
@@ -1490,7 +1480,7 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
}
// List only future schedules, not past ones.
- List<SnapshotScheduleVO> snapshotSchedules = new ArrayList<SnapshotScheduleVO>();
+ List<SnapshotScheduleVO> snapshotSchedules = new ArrayList<>();
if (policyId == null) {
List<SnapshotPolicyVO> policyInstances = listPoliciesforVolume(volumeId);
for (SnapshotPolicyVO policyInstance : policyInstances) {
@@ -1609,7 +1599,7 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
List<VMSnapshotVO> activeVMSnapshots = _vmSnapshotDao.listByInstanceId(userVm.getId(), VMSnapshot.State.Creating, VMSnapshot.State.Reverting,
VMSnapshot.State.Expunging);
if (activeVMSnapshots.size() > 0) {
- throw new CloudRuntimeException("There is other active vm snapshot tasks on the instance to which the volume is attached, please try again later");
+ throw new CloudRuntimeException("There is other active Instance Snapshot tasks on the Instance to which the volume is attached, please try again later");
}
}
}
@@ -1624,7 +1614,6 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
Long snapshotId = payload.getSnapshotId();
Account snapshotOwner = payload.getAccount();
-
SnapshotInfo snapshot = snapshotFactory.getSnapshot(snapshotId, volume.getDataStore());
StoragePool storagePool = _storagePoolDao.findById(volume.getPoolId());
@@ -1689,7 +1678,7 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
snapshotStoreRef.getPhysicalSize(), volume.getSize(), snapshot.getClass().getName(), snapshot.getUuid());
// Correct the resource count of snapshot in case of delta snapshots.
- _resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), ResourceType.secondary_storage, new Long(volume.getSize() - snapshotStoreRef.getPhysicalSize()));
+ _resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), ResourceType.secondary_storage, volume.getSize() - snapshotStoreRef.getPhysicalSize());
if (!payload.getAsyncBackup()) {
if (backupSnapToSecondary) {
@@ -1707,14 +1696,14 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
logger.debug("Failed to create snapshot" + cre.getLocalizedMessage());
}
_resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), ResourceType.snapshot);
- _resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), ResourceType.secondary_storage, new Long(volume.getSize()));
+ _resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), ResourceType.secondary_storage, volume.getSize());
throw cre;
} catch (Exception e) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to create snapshot", e);
}
_resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), ResourceType.snapshot);
- _resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), ResourceType.secondary_storage, new Long(volume.getSize()));
+ _resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), ResourceType.secondary_storage, volume.getSize());
throw new CloudRuntimeException("Failed to create snapshot", e);
}
return snapshot;
@@ -1909,7 +1898,7 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
}
if (policyIds == null) {
- policyIds = new ArrayList<Long>();
+ policyIds = new ArrayList<>();
policyIds.add(policyId);
} else if (policyIds.size() <= 0) {
// Not even sure how this is even possible
@@ -1992,24 +1981,6 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
Type snapshotType = getSnapshotType(policyId);
Account owner = _accountMgr.getAccount(volume.getAccountId());
- ResourceType storeResourceType = ResourceType.secondary_storage;
- if (!isBackupSnapshotToSecondaryForZone(volume.getDataCenterId()) ||
- Snapshot.LocationType.PRIMARY.equals(locationType)) {
- storeResourceType = ResourceType.primary_storage;
- }
- try {
- _resourceLimitMgr.checkResourceLimit(owner, ResourceType.snapshot);
- _resourceLimitMgr.checkResourceLimit(owner, storeResourceType, volume.getSize());
- } catch (ResourceAllocationException e) {
- if (snapshotType != Type.MANUAL) {
- String msg = String.format("Snapshot resource limit exceeded for account %s. Failed to create recurring snapshots", owner);
- logger.warn(msg);
- _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_UPDATE_RESOURCE_COUNT, 0L, 0L, msg, "Snapshot resource limit exceeded for account id : " + owner.getId()
- + ". Failed to create recurring snapshots; please use updateResourceLimit to increase the limit");
- }
- throw e;
- }
-
// Determine the name for this snapshot
// Snapshot Name: VMInstancename + volumeName + timeString
String timeString = DateUtil.getDateDisplayString(DateUtil.GMT_TIMEZONE, new Date(), DateUtil.YYYYMMDD_FORMAT);
@@ -2041,6 +2012,14 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
hypervisorType = volume.getHypervisorType();
}
+ ResourceType storeResourceType = ResourceType.secondary_storage;
+ if (!isBackupSnapshotToSecondaryForZone(volume.getDataCenterId()) ||
+ Snapshot.LocationType.PRIMARY.equals(locationType)) {
+ storeResourceType = ResourceType.primary_storage;
+ }
+
+ try (CheckedReservation volumeSnapshotReservation = new CheckedReservation(owner, ResourceType.snapshot, null, null, 1L, reservationDao, _resourceLimitMgr);
+ CheckedReservation storageReservation = new CheckedReservation(owner, storeResourceType, null, null, volume.getSize(), reservationDao, _resourceLimitMgr)) {
SnapshotVO snapshotVO = new SnapshotVO(volume.getDataCenterId(), volume.getAccountId(), volume.getDomainId(), volume.getId(), volume.getDiskOfferingId(), snapshotName,
(short)snapshotType.ordinal(), snapshotType.name(), volume.getSize(), volume.getMinIops(), volume.getMaxIops(), hypervisorType, locationType);
@@ -2052,6 +2031,17 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
_resourceLimitMgr.incrementResourceCount(volume.getAccountId(), ResourceType.snapshot);
_resourceLimitMgr.incrementResourceCount(volume.getAccountId(), storeResourceType, volume.getSize());
return snapshot;
+ } catch (Exception e) {
+ if (e instanceof ResourceAllocationException) {
+ if (snapshotType != Type.MANUAL) {
+ String msg = String.format("Snapshot resource limit exceeded for account id : %s. Failed to create recurring snapshots", owner.getId());
+ logger.warn(msg);
+ _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_UPDATE_RESOURCE_COUNT, 0L, 0L, msg, msg + ". Please, use updateResourceLimit to increase the limit");
+ }
+ throw (ResourceAllocationException) e;
+ }
+ throw new CloudRuntimeException(e);
+ }
}
@Override
@@ -2211,6 +2201,7 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
}
return true;
}
+
@DB
private List<String> copySnapshotToZones(SnapshotVO snapshotVO, DataStore srcSecStore, List<DataCenterVO> dstZones) throws StorageUnavailableException, ResourceAllocationException {
AccountVO account = _accountDao.findById(snapshotVO.getAccountId());
diff --git a/server/src/test/java/com/cloud/storage/snapshot/SnapshotManagerTest.java b/server/src/test/java/com/cloud/storage/snapshot/SnapshotManagerTest.java
index 3b5d92103e7..8eee0ed6626 100755
--- a/server/src/test/java/com/cloud/storage/snapshot/SnapshotManagerTest.java
+++ b/server/src/test/java/com/cloud/storage/snapshot/SnapshotManagerTest.java
@@ -16,6 +16,27 @@
// under the License.
package com.cloud.storage.snapshot;
+import org.apache.cloudstack.api.command.user.snapshot.ExtractSnapshotCmd;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
+import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
+import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory;
+import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
+import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotService;
+import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotStrategy;
+import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotStrategy.SnapshotOperation;
+import org.apache.cloudstack.engine.subsystem.api.storage.StorageStrategyFactory;
+import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
+import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
+import org.apache.cloudstack.framework.config.ConfigKey;
+import org.apache.cloudstack.snapshot.SnapshotHelper;
+import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
+import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
+import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
+import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity;
+
import com.cloud.api.ApiDBUtils;
import com.cloud.configuration.Resource.ResourceType;
import com.cloud.dc.DataCenter;
@@ -27,6 +48,7 @@ import com.cloud.exception.ResourceAllocationException;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.resource.ResourceManager;
+import com.cloud.resourcelimit.CheckedReservation;
import com.cloud.server.ResourceTag;
import com.cloud.server.TaggedResourceService;
import com.cloud.storage.DataStoreRole;
@@ -57,27 +79,6 @@ import com.cloud.vm.snapshot.VMSnapshot;
import com.cloud.vm.snapshot.VMSnapshotVO;
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
-import org.apache.cloudstack.api.command.user.snapshot.ExtractSnapshotCmd;
-import org.apache.cloudstack.context.CallContext;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
-import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
-import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory;
-import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
-import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotService;
-import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotStrategy;
-import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotStrategy.SnapshotOperation;
-import org.apache.cloudstack.engine.subsystem.api.storage.StorageStrategyFactory;
-import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
-import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
-import org.apache.cloudstack.framework.config.ConfigKey;
-import org.apache.cloudstack.snapshot.SnapshotHelper;
-import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
-import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
-import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
-import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
-import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity;
-
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@@ -87,6 +88,7 @@ import org.junit.runner.RunWith;
import org.mockito.BDDMockito;
import org.mockito.InjectMocks;
import org.mockito.Mock;
+import org.mockito.MockedConstruction;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
@@ -237,8 +239,6 @@ public class SnapshotManagerTest {
when(_storageStrategyFactory.getSnapshotStrategy(Mockito.any(SnapshotVO.class), Mockito.eq(SnapshotOperation.BACKUP))).thenReturn(snapshotStrategy);
when(_storageStrategyFactory.getSnapshotStrategy(Mockito.any(SnapshotVO.class), Mockito.eq(SnapshotOperation.REVERT))).thenReturn(snapshotStrategy);
- doNothing().when(_resourceLimitMgr).checkResourceLimit(any(Account.class), any(ResourceType.class));
- doNothing().when(_resourceLimitMgr).checkResourceLimit(any(Account.class), any(ResourceType.class), anyLong());
doNothing().when(_resourceLimitMgr).incrementResourceCount(anyLong(), any(ResourceType.class));
doNothing().when(_resourceLimitMgr).incrementResourceCount(anyLong(), any(ResourceType.class), anyLong());
@@ -320,7 +320,12 @@ public class SnapshotManagerTest {
when(mockList2.size()).thenReturn(0);
when(_vmSnapshotDao.listByInstanceId(TEST_VM_ID, VMSnapshot.State.Creating, VMSnapshot.State.Reverting, VMSnapshot.State.Expunging)).thenReturn(mockList2);
when(_snapshotDao.persist(any(SnapshotVO.class))).thenReturn(snapshotMock);
- _snapshotMgr.allocSnapshot(TEST_VOLUME_ID, Snapshot.MANUAL_POLICY_ID, null, null);
+
+ try (MockedConstruction<CheckedReservation> mockCheckedReservation = Mockito.mockConstruction(CheckedReservation.class)) {
+ _snapshotMgr.allocSnapshot(TEST_VOLUME_ID, Snapshot.MANUAL_POLICY_ID, null, null);
+ } catch (ResourceAllocationException e) {
+ Assert.fail(String.format("Failure with exception: %s", e.getMessage()));
+ }
}
@Test(expected = InvalidParameterValueException.class)
@@ -468,7 +473,7 @@ public class SnapshotManagerTest {
public void validateCreateTagsForSnapshotPolicyWithValidTags(){
Mockito.doReturn(null).when(taggedResourceServiceMock).createTags(any(), any(), any(), any());
- Map map = new HashMap<>();
+ Map<String, String> map = new HashMap<>();
map.put("test", "test");
_snapshotMgr.createTagsForSnapshotPolicy(map, snapshotPolicyVoMock);