diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDao.java b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDao.java index 23541c2431e7..e130bc039b50 100755 --- a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDao.java +++ b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDao.java @@ -192,4 +192,6 @@ List searchRemovedByRemoveDate(final Date startDate, final Date en int getVmCountByOfferingNotInDomain(Long serviceOfferingId, List domainIds); List listByIdsIncludingRemoved(List ids); + + List listDeleteProtectedVmsByAccountId(long accountId); } diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java index 7ebf61366fe2..4e8508fa1ffe 100755 --- a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java @@ -30,6 +30,7 @@ import javax.annotation.PostConstruct; import javax.inject.Inject; +import org.apache.cloudstack.api.ApiConstants; import org.apache.commons.collections.CollectionUtils; import org.springframework.stereotype.Component; @@ -106,6 +107,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem protected SearchBuilder IdsPowerStateSelectSearch; GenericSearchBuilder CountByOfferingId; GenericSearchBuilder CountUserVmNotInDomain; + SearchBuilder DeleteProtectedVmSearch; @Inject ResourceTagDao tagsDao; @@ -368,6 +370,12 @@ protected void init() { CountUserVmNotInDomain.and("domainIdsNotIn", CountUserVmNotInDomain.entity().getDomainId(), Op.NIN); CountUserVmNotInDomain.done(); + DeleteProtectedVmSearch = createSearchBuilder(); + DeleteProtectedVmSearch.selectFields(DeleteProtectedVmSearch.entity().getUuid()); + DeleteProtectedVmSearch.and(ApiConstants.ACCOUNT_ID, DeleteProtectedVmSearch.entity().getAccountId(), Op.EQ); + DeleteProtectedVmSearch.and(ApiConstants.DELETE_PROTECTION, DeleteProtectedVmSearch.entity().isDeleteProtection(), Op.EQ); + DeleteProtectedVmSearch.and(ApiConstants.REMOVED, DeleteProtectedVmSearch.entity().getRemoved(), Op.NULL); + DeleteProtectedVmSearch.done(); } @Override @@ -1296,4 +1304,12 @@ public List listByIdsIncludingRemoved(List ids) { sc.setParameters("ids", ids.toArray()); return listIncludingRemovedBy(sc); } + + @Override + public List listDeleteProtectedVmsByAccountId(long accountId) { + SearchCriteria sc = DeleteProtectedVmSearch.create(); + sc.setParameters(ApiConstants.ACCOUNT_ID, accountId); + sc.setParameters(ApiConstants.DELETE_PROTECTION, true); + return listBy(sc); + } } diff --git a/server/src/main/java/com/cloud/user/AccountManagerImpl.java b/server/src/main/java/com/cloud/user/AccountManagerImpl.java index bfe6a1b0a477..966b30ad9e34 100644 --- a/server/src/main/java/com/cloud/user/AccountManagerImpl.java +++ b/server/src/main/java/com/cloud/user/AccountManagerImpl.java @@ -2097,6 +2097,7 @@ public boolean deleteUserAccount(long accountId) { return true; } + validateNoDeleteProtectedVms(account); checkIfAccountManagesProjects(accountId); verifyCallerPrivilegeForUserOrAccountOperations(account); @@ -2138,6 +2139,24 @@ protected boolean isDeleteNeeded(AccountVO account, long accountId, Account call return true; } + private void validateNoDeleteProtectedVms(Account account) { + long accountId = account.getId(); + List deleteProtectedVms = _vmDao.listDeleteProtectedVmsByAccountId(accountId); + if (deleteProtectedVms.isEmpty()) { + return; + } + + if (logger.isDebugEnabled()) { + List vmUuids = deleteProtectedVms.stream().map(VMInstanceVO::getUuid).collect(Collectors.toList()); + logger.debug("Cannot delete Account {} (id={}), delete protection enabled for Instances: {}", + account.getAccountName(), accountId, vmUuids); + } + + throw new InvalidParameterValueException( + String.format("Cannot delete Account '%s'. One or more Instances have delete protection enabled.", + account.getAccountName())); + } + @Override @ActionEvent(eventType = EventTypes.EVENT_ACCOUNT_ENABLE, eventDescription = "enabling account", async = true) public AccountVO enableAccount(String accountName, Long domainId, Long accountId) {