Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -192,4 +192,6 @@ List<VMInstanceVO> searchRemovedByRemoveDate(final Date startDate, final Date en
int getVmCountByOfferingNotInDomain(Long serviceOfferingId, List<Long> domainIds);

List<VMInstanceVO> listByIdsIncludingRemoved(List<Long> ids);

List<VMInstanceVO> listDeleteProtectedVmsByAccountId(long accountId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -106,6 +107,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase<VMInstanceVO, Long> implem
protected SearchBuilder<VMInstanceVO> IdsPowerStateSelectSearch;
GenericSearchBuilder<VMInstanceVO, Integer> CountByOfferingId;
GenericSearchBuilder<VMInstanceVO, Integer> CountUserVmNotInDomain;
SearchBuilder<VMInstanceVO> DeleteProtectedVmSearch;

@Inject
ResourceTagDao tagsDao;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1296,4 +1304,12 @@ public List<VMInstanceVO> listByIdsIncludingRemoved(List<Long> ids) {
sc.setParameters("ids", ids.toArray());
return listIncludingRemovedBy(sc);
}

@Override
public List<VMInstanceVO> listDeleteProtectedVmsByAccountId(long accountId) {
SearchCriteria<VMInstanceVO> sc = DeleteProtectedVmSearch.create();
sc.setParameters(ApiConstants.ACCOUNT_ID, accountId);
sc.setParameters(ApiConstants.DELETE_PROTECTION, true);
return listBy(sc);
}
}
19 changes: 19 additions & 0 deletions server/src/main/java/com/cloud/user/AccountManagerImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -2097,6 +2097,7 @@ public boolean deleteUserAccount(long accountId) {
return true;
}

validateNoDeleteProtectedVms(account);
checkIfAccountManagesProjects(accountId);
verifyCallerPrivilegeForUserOrAccountOperations(account);

Expand Down Expand Up @@ -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<VMInstanceVO> deleteProtectedVms = _vmDao.listDeleteProtectedVmsByAccountId(accountId);
if (deleteProtectedVms.isEmpty()) {
return;
}

if (logger.isDebugEnabled()) {
List<String> 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) {
Expand Down
Loading