[20.3] Address limit checks for VM, CPU, memory, volume, and primary storage

This commit is contained in:
Fabricio Duarte 2026-03-06 10:17:37 -03:00 committed by Daan Hoogland
parent 360b64ce1e
commit 0a4b4c6af0
27 changed files with 595 additions and 507 deletions

View File

@ -82,7 +82,7 @@ public interface ProjectService {
Project updateProject(long id, String name, String displayText, String newOwnerName, Long userId, Role newRole) throws ResourceAllocationException;
boolean addAccountToProject(long projectId, String accountName, String email, Long projectRoleId, Role projectRoleType);
boolean addAccountToProject(long projectId, String accountName, String email, Long projectRoleId, Role projectRoleType) throws ResourceAllocationException;
boolean deleteAccountFromProject(long projectId, String accountName);
@ -100,6 +100,6 @@ public interface ProjectService {
Project findByProjectAccountIdIncludingRemoved(long projectAccountId);
boolean addUserToProject(Long projectId, String username, String email, Long projectRoleId, Role projectRole);
boolean addUserToProject(Long projectId, String username, String email, Long projectRoleId, Role projectRole) throws ResourceAllocationException;
}

View File

@ -30,6 +30,7 @@ import com.cloud.exception.ResourceAllocationException;
import com.cloud.offering.DiskOffering;
import com.cloud.offering.ServiceOffering;
import com.cloud.template.VirtualMachineTemplate;
import org.apache.cloudstack.resourcelimit.Reserver;
public interface ResourceLimitService {
@ -246,12 +247,12 @@ public interface ResourceLimitService {
List<String> getResourceLimitStorageTags(DiskOffering diskOffering);
void updateTaggedResourceLimitsAndCountsForAccounts(List<AccountResponse> responses, String tag);
void updateTaggedResourceLimitsAndCountsForDomains(List<DomainResponse> responses, String tag);
void checkVolumeResourceLimit(Account owner, Boolean display, Long size, DiskOffering diskOffering) throws ResourceAllocationException;
void checkVolumeResourceLimit(Account owner, Boolean display, Long size, DiskOffering diskOffering, List<Reserver> reservations) throws ResourceAllocationException;
List<String> getResourceLimitStorageTagsForResourceCountOperation(Boolean display, DiskOffering diskOffering);
void checkVolumeResourceLimitForDiskOfferingChange(Account owner, Boolean display, Long currentSize, Long newSize,
DiskOffering currentOffering, DiskOffering newOffering) throws ResourceAllocationException;
DiskOffering currentOffering, DiskOffering newOffering, List<Reserver> reservations) throws ResourceAllocationException;
void checkPrimaryStorageResourceLimit(Account owner, Boolean display, Long size, DiskOffering diskOffering) throws ResourceAllocationException;
void checkPrimaryStorageResourceLimit(Account owner, Boolean display, Long size, DiskOffering diskOffering, List<Reserver> reservations) throws ResourceAllocationException;
void incrementVolumeResourceCount(long accountId, Boolean display, Long size, DiskOffering diskOffering);
void decrementVolumeResourceCount(long accountId, Boolean display, Long size, DiskOffering diskOffering);
@ -268,20 +269,18 @@ public interface ResourceLimitService {
void incrementVolumePrimaryStorageResourceCount(long accountId, Boolean display, Long size, DiskOffering diskOffering);
void decrementVolumePrimaryStorageResourceCount(long accountId, Boolean display, Long size, DiskOffering diskOffering);
void checkVmResourceLimit(Account owner, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template) throws ResourceAllocationException;
void checkVmResourceLimit(Account owner, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Reserver> reservations) throws ResourceAllocationException;
void incrementVmResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template);
void decrementVmResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template);
void checkVmResourceLimitsForServiceOfferingChange(Account owner, Boolean display, Long currentCpu, Long newCpu,
Long currentMemory, Long newMemory, ServiceOffering currentOffering, ServiceOffering newOffering, VirtualMachineTemplate template) throws ResourceAllocationException;
Long currentMemory, Long newMemory, ServiceOffering currentOffering, ServiceOffering newOffering, VirtualMachineTemplate template, List<Reserver> reservations) throws ResourceAllocationException;
void checkVmResourceLimitsForTemplateChange(Account owner, Boolean display, ServiceOffering offering,
VirtualMachineTemplate currentTemplate, VirtualMachineTemplate newTemplate) throws ResourceAllocationException;
VirtualMachineTemplate currentTemplate, VirtualMachineTemplate newTemplate, List<Reserver> reservations) throws ResourceAllocationException;
void checkVmCpuResourceLimit(Account owner, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long cpu) throws ResourceAllocationException;
void incrementVmCpuResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long cpu);
void decrementVmCpuResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long cpu);
void checkVmMemoryResourceLimit(Account owner, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long memory) throws ResourceAllocationException;
void incrementVmMemoryResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long memory);
void decrementVmMemoryResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long memory);

View File

@ -18,6 +18,7 @@ package org.apache.cloudstack.api.command.user.account;
import java.util.List;
import com.cloud.exception.ResourceAllocationException;
import org.apache.cloudstack.api.ApiArgValidator;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.BaseCmd;
@ -106,7 +107,7 @@ public class AddAccountToProjectCmd extends BaseAsyncCmd {
/////////////////////////////////////////////////////
@Override
public void execute() {
public void execute() throws ResourceAllocationException {
if (accountName == null && email == null) {
throw new InvalidParameterValueException("Either accountName or email is required");
}

View File

@ -17,6 +17,7 @@
package org.apache.cloudstack.api.command.user.account;
import com.cloud.exception.ResourceAllocationException;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiArgValidator;
@ -111,7 +112,7 @@ public class AddUserToProjectCmd extends BaseAsyncCmd {
/////////////////////////////////////////////////////
@Override
public void execute() {
public void execute() throws ResourceAllocationException {
validateInput();
boolean result = _projectService.addUserToProject(getProjectId(), getUsername(), getEmail(), getProjectRoleId(), getRoleType());
if (result) {

View File

@ -15,8 +15,14 @@
// specific language governing permissions and limitations
// under the License.
package com.cloud.resourcelimit;
package org.apache.cloudstack.resourcelimit;
/**
* Interface implemented by <code>CheckedReservation</code>.
* </br></br>
* This is defined in <code>cloud-api</code> to allow methods declared in modules that do not depend on <code>cloud-server</code>
* to receive <code>CheckedReservations</code> as parameters.
*/
public interface Reserver extends AutoCloseable {
void close();

View File

@ -16,6 +16,7 @@
// under the License.
package org.apache.cloudstack.api.command.test;
import com.cloud.exception.ResourceAllocationException;
import junit.framework.Assert;
import junit.framework.TestCase;
@ -149,6 +150,8 @@ public class AddAccountToProjectCmdTest extends TestCase {
addAccountToProjectCmd.execute();
} catch (InvalidParameterValueException exception) {
Assert.assertEquals("Either accountName or email is required", exception.getLocalizedMessage());
} catch (ResourceAllocationException exception) {
Assert.fail();
}
}

View File

@ -4757,9 +4757,20 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
private void saveCustomOfferingDetails(long vmId, ServiceOffering serviceOffering) {
Map<String, String> details = userVmDetailsDao.listDetailsKeyPairs(vmId);
details.put(UsageEventVO.DynamicParameters.cpuNumber.name(), serviceOffering.getCpu().toString());
details.put(UsageEventVO.DynamicParameters.cpuSpeed.name(), serviceOffering.getSpeed().toString());
details.put(UsageEventVO.DynamicParameters.memory.name(), serviceOffering.getRamSize().toString());
// We need to restore only the customizable parameters. If we save a parameter that is not customizable and attempt
// to restore a VM snapshot, com.cloud.vm.UserVmManagerImpl.validateCustomParameters will fail.
ServiceOffering unfilledOffering = _serviceOfferingDao.findByIdIncludingRemoved(serviceOffering.getId());
if (unfilledOffering.getCpu() == null) {
details.put(UsageEventVO.DynamicParameters.cpuNumber.name(), serviceOffering.getCpu().toString());
}
if (unfilledOffering.getSpeed() == null) {
details.put(UsageEventVO.DynamicParameters.cpuSpeed.name(), serviceOffering.getSpeed().toString());
}
if (unfilledOffering.getRamSize() == null) {
details.put(UsageEventVO.DynamicParameters.memory.name(), serviceOffering.getRamSize().toString());
}
List<UserVmDetailVO> detailList = new ArrayList<>();
for (Map.Entry<String, String> entry: details.entrySet()) {
UserVmDetailVO detailVO = new UserVmDetailVO(vmId, entry.getKey(), entry.getValue(), true);

View File

@ -3097,9 +3097,6 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
CallContext.current().setEventDetails("Network Id: " + network.getId());
CallContext.current().putContextParameter(Network.class, network.getUuid());
return network;
} catch (Exception e) {
logger.error(e);
throw new RuntimeException(e);
}
}

View File

@ -39,6 +39,7 @@ import javax.inject.Inject;
import javax.naming.ConfigurationException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.resourcelimit.ReservationHelper;
import com.cloud.storage.DiskOfferingVO;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.dao.VMTemplateDao;
@ -77,6 +78,7 @@ import org.apache.cloudstack.framework.jobs.AsyncJobManager;
import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO;
import org.apache.cloudstack.resourcedetail.DiskOfferingDetailVO;
import org.apache.cloudstack.resourcedetail.dao.DiskOfferingDetailsDao;
import org.apache.cloudstack.resourcelimit.Reserver;
import org.apache.cloudstack.secret.PassphraseVO;
import org.apache.cloudstack.secret.dao.PassphraseDao;
import org.apache.cloudstack.snapshot.SnapshotHelper;
@ -1867,14 +1869,20 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
template == null ? null : template.getSize(),
vol.getPassphraseId() != null);
if (newSize != vol.getSize()) {
DiskOfferingVO diskOffering = diskOfferingDao.findByIdIncludingRemoved(vol.getDiskOfferingId());
if (newSize == vol.getSize()) {
return;
}
DiskOfferingVO diskOffering = diskOfferingDao.findByIdIncludingRemoved(vol.getDiskOfferingId());
List<Reserver> reservations = new ArrayList<>();
try {
VMInstanceVO vm = vol.getInstanceId() != null ? vmInstanceDao.findById(vol.getInstanceId()) : null;
if (vm == null || vm.getType() == VirtualMachine.Type.User) {
// Update resource count for user vm volumes when volume is attached
if (newSize > vol.getSize()) {
_resourceLimitMgr.checkPrimaryStorageResourceLimit(_accountMgr.getActiveAccountById(vol.getAccountId()),
vol.isDisplay(), newSize - vol.getSize(), diskOffering);
vol.isDisplay(), newSize - vol.getSize(), diskOffering, reservations);
_resourceLimitMgr.incrementVolumePrimaryStorageResourceCount(vol.getAccountId(), vol.isDisplay(),
newSize - vol.getSize(), diskOffering);
} else {
@ -1882,9 +1890,11 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
vol.getSize() - newSize, diskOffering);
}
}
vol.setSize(newSize);
_volsDao.persist(vol);
} finally {
ReservationHelper.closeAll(reservations);
}
vol.setSize(newSize);
_volsDao.persist(vol);
}
@Override

View File

@ -544,7 +544,7 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager, C
@Override
@ActionEvent(eventType = EventTypes.EVENT_PROJECT_USER_ADD, eventDescription = "adding user to project", async = true)
public boolean addUserToProject(Long projectId, String username, String email, Long projectRoleId, Role projectRole) {
public boolean addUserToProject(Long projectId, String username, String email, Long projectRoleId, Role projectRole) throws ResourceAllocationException {
Account caller = CallContext.current().getCallingAccount();
Project project = getProject(projectId);
@ -614,8 +614,6 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager, C
logger.warn("Failed to add user to project: {}", project);
return false;
}
} catch (ResourceAllocationException e) {
throw new RuntimeException(e);
}
}
}
@ -814,7 +812,7 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager, C
@Override
@ActionEvent(eventType = EventTypes.EVENT_PROJECT_ACCOUNT_ADD, eventDescription = "adding account to project", async = true)
public boolean addAccountToProject(long projectId, String accountName, String email, Long projectRoleId, Role projectRoleType) {
public boolean addAccountToProject(long projectId, String accountName, String email, Long projectRoleId, Role projectRoleType) throws ResourceAllocationException {
Account caller = CallContext.current().getCallingAccount();
//check that the project exists
@ -892,8 +890,6 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager, C
logger.warn("Failed to add account {} to project {}", accountName, project);
return false;
}
} catch (ResourceAllocationException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -20,13 +20,16 @@ package com.cloud.resourcelimit;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.reservation.ReservationVO;
import org.apache.cloudstack.reservation.dao.ReservationDao;
import org.apache.cloudstack.resourcelimit.Reserver;
import org.apache.cloudstack.user.ResourceReservation;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -48,12 +51,15 @@ public class CheckedReservation implements Reserver {
ReservationDao reservationDao;
ResourceLimitService resourceLimitService;
private final Account account;
private Account account;
private Long domainId;
private final ResourceType resourceType;
private Long amount;
private ResourceType resourceType;
private Long resourceId;
private Long reservationAmount;
private List<String> reservationTags;
private Long existingAmount;
private List<String> existingLimitTags;
private List<ResourceReservation> reservations;
private List<String> resourceLimitTags;
private String getContextParameterKey() {
return getResourceReservationContextParameterKey(resourceType);
@ -100,9 +106,25 @@ public class CheckedReservation implements Reserver {
this.reservations.add(reservation);
}
public CheckedReservation(Account account, ResourceType resourceType, List<String> resourceLimitTags, Long amount,
ReservationDao reservationDao, ResourceLimitService resourceLimitService) throws ResourceAllocationException {
this(account, resourceType, null, resourceLimitTags, amount, reservationDao, resourceLimitService);
// TODO: refactor these into a Builder to avoid having so many constructors
public CheckedReservation(Account account, ResourceType resourceType, List<String> resourceLimitTags, Long reservationAmount,
ReservationDao reservationDao, ResourceLimitService resourceLimitService) throws ResourceAllocationException {
this(account, resourceType, null, resourceLimitTags, null, reservationAmount, null, reservationDao, resourceLimitService);
}
public CheckedReservation(Account account, ResourceType resourceType, Long resourceId, List<String> reservedTags,
List<String> existingTags, Long reservationAmount, Long existingAmount, ReservationDao reservationDao,
ResourceLimitService resourceLimitService) throws ResourceAllocationException {
this(account, null, resourceType, resourceId, reservedTags, existingTags, reservationAmount, existingAmount, reservationDao, resourceLimitService);
}
public CheckedReservation(Account account, Long domainId, ResourceType resourceType, Long resourceId, List<String> reservedTags,
Long reservationAmount, ReservationDao reservationDao, ResourceLimitService resourceLimitService) throws ResourceAllocationException {
this(account, domainId, resourceType, resourceId, reservedTags, null, reservationAmount, null, reservationDao, resourceLimitService);
}
public CheckedReservation(Account account, ResourceType resourceType, Long resourceId, List<String> reservedTags, Long reservationAmount, ReservationDao reservationDao, ResourceLimitService resourceLimitService) throws ResourceAllocationException {
this(account, null, resourceType, resourceId, reservedTags, null, reservationAmount, null, reservationDao, resourceLimitService);
}
/**
@ -110,36 +132,43 @@ public class CheckedReservation implements Reserver {
* - create DB entry for reservation
* - hold the id of this record as a ticket for implementation
*
* @param amount positive number of the resource type to reserve
* @param reservationAmount positive number of the resource type to reserve
* @throws ResourceAllocationException
*/
public CheckedReservation(Account account, ResourceType resourceType, Long resourceId, List<String> resourceLimitTags, Long amount,
ReservationDao reservationDao, ResourceLimitService resourceLimitService) throws ResourceAllocationException {
this(account, account.getDomainId(), resourceType, resourceId, resourceLimitTags, amount, reservationDao, resourceLimitService);
}
public CheckedReservation(Account account, Long domainId, ResourceType resourceType, Long resourceId, List<String> reservedTags,
List<String> existingTags, Long reservationAmount, Long existingAmount, ReservationDao reservationDao,
ResourceLimitService resourceLimitService) throws ResourceAllocationException {
if (ObjectUtils.allNull(account, domainId)) {
logger.debug("Not reserving any {} resources, as no account/domain was provided.", resourceType);
return;
}
public CheckedReservation(Account account, Long domainId, ResourceType resourceType, Long resourceId, List<String> resourceLimitTags, Long amount,
ReservationDao reservationDao, ResourceLimitService resourceLimitService) throws ResourceAllocationException {
this.reservationDao = reservationDao;
this.resourceLimitService = resourceLimitService;
this.account = account;
this.domainId = domainId;
if (domainId == null) {
this.domainId = account.getDomainId();
domainId = account.getDomainId();
}
this.domainId = domainId;
this.resourceType = resourceType;
this.amount = amount;
this.reservationAmount = reservationAmount;
this.existingAmount = existingAmount;
this.reservations = new ArrayList<>();
this.resourceLimitTags = resourceLimitTags;
if (this.amount != null && this.amount != 0) {
if (amount > 0) {
this.reservationTags = getTagsWithoutNull(reservedTags);
this.existingLimitTags = getTagsWithoutNull(existingTags);
// TODO: refactor me
if (this.reservationAmount != null && this.reservationAmount != 0) {
if (reservationAmount > 0) {
setGlobalLock();
if (quotaLimitLock.lock(TRY_TO_GET_LOCK_TIME)) {
try {
checkLimitAndPersistReservations(account, this.domainId, resourceType, resourceId, resourceLimitTags, amount);
adjustCountToNotConsiderExistingAmount();
checkLimitAndPersistReservations(account, this.domainId, resourceType, resourceId, reservationTags, reservationAmount);
CallContext.current().putContextParameter(getContextParameterKey(), getIds());
} catch (NullPointerException npe) {
throw new CloudRuntimeException("not enough means to check limits", npe);
@ -150,7 +179,7 @@ public class CheckedReservation implements Reserver {
throw new ResourceAllocationException(String.format("unable to acquire resource reservation \"%s\"", quotaLimitLock.getName()), resourceType);
}
} else {
checkLimitAndPersistReservations(account, this.domainId, resourceType, resourceId, resourceLimitTags, amount);
checkLimitAndPersistReservations(account, this.domainId, resourceType, resourceId, reservationTags, reservationAmount);
}
} else {
logger.debug("not reserving any amount of resources for {} in domain {}, type: {}, tag: {}",
@ -158,6 +187,20 @@ public class CheckedReservation implements Reserver {
}
}
protected List<String> getTagsWithoutNull(List<String> tags) {
if (tags == null) {
return null;
}
return tags.stream().filter(Objects::nonNull).collect(Collectors.toList());
}
protected void adjustCountToNotConsiderExistingAmount() throws ResourceAllocationException {
if (existingAmount == null || existingAmount == 0) {
return;
}
checkLimitAndPersistReservations(account, domainId, resourceType, resourceId, existingLimitTags, -1 * existingAmount);
}
public CheckedReservation(Account account, ResourceType resourceType, Long amount, ReservationDao reservationDao,
ResourceLimitService resourceLimitService) throws ResourceAllocationException {
this(account, resourceType, null, amount, reservationDao, resourceLimitService);
@ -183,11 +226,11 @@ public class CheckedReservation implements Reserver {
}
public String getResourceLimitTagsAsString() {
return CollectionUtils.isNotEmpty(resourceLimitTags) ? StringUtils.join(resourceLimitTags) : null;
return CollectionUtils.isNotEmpty(reservationTags) ? StringUtils.join(reservationTags) : null;
}
public Long getReservedAmount() {
return amount;
return reservationAmount;
}
public List<ResourceReservation> getReservations() {

View File

@ -0,0 +1,35 @@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
package com.cloud.resourcelimit;
import com.cloud.utils.exception.CloudRuntimeException;
import org.apache.cloudstack.resourcelimit.Reserver;
import java.util.List;
public class ReservationHelper {
public static void closeAll(List<Reserver> reservations) throws CloudRuntimeException {
for (Reserver reservation : reservations) {
reservation.close();
}
}
}

View File

@ -52,6 +52,7 @@ import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
import org.apache.cloudstack.reservation.ReservationVO;
import org.apache.cloudstack.reservation.dao.ReservationDao;
import org.apache.cloudstack.resourcelimit.Reserver;
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
@ -168,6 +169,8 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
@Inject
private ReservationDao reservationDao;
@Inject
private ResourceLimitService resourceLimitService;
@Inject
protected SnapshotDao _snapshotDao;
@Inject
private SnapshotDataStoreDao _snapshotDataStoreDao;
@ -1662,54 +1665,53 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
}
@Override
public void checkVolumeResourceLimit(Account owner, Boolean display, Long size, DiskOffering diskOffering) throws ResourceAllocationException {
public void checkVolumeResourceLimit(Account owner, Boolean display, Long size, DiskOffering diskOffering, List<Reserver> reservations) throws ResourceAllocationException {
List<String> tags = getResourceLimitStorageTagsForResourceCountOperation(display, diskOffering);
if (CollectionUtils.isEmpty(tags)) {
return;
}
for (String tag : tags) {
checkResourceLimitWithTag(owner, ResourceType.volume, tag);
if (size != null) {
checkResourceLimitWithTag(owner, ResourceType.primary_storage, tag, size);
}
CheckedReservation volumeReservation = new CheckedReservation(owner, ResourceType.volume, tags, 1L, reservationDao, resourceLimitService);
reservations.add(volumeReservation);
if (size != null) {
CheckedReservation primaryStorageReservation = new CheckedReservation(owner, ResourceType.primary_storage, tags, size, reservationDao, resourceLimitService);
reservations.add(primaryStorageReservation);
}
}
@Override
public void checkPrimaryStorageResourceLimit(Account owner, Boolean display, Long size, DiskOffering diskOffering) throws ResourceAllocationException {
public void checkPrimaryStorageResourceLimit(Account owner, Boolean display, Long size, DiskOffering diskOffering, List<Reserver> reservations) throws ResourceAllocationException {
List<String> tags = getResourceLimitStorageTagsForResourceCountOperation(display, diskOffering);
if (CollectionUtils.isEmpty(tags)) {
return;
}
if (size != null) {
for (String tag : tags) {
checkResourceLimitWithTag(owner, ResourceType.primary_storage, tag, size);
}
}
CheckedReservation primaryStorageReservation = new CheckedReservation(owner, ResourceType.primary_storage, tags, size, reservationDao, resourceLimitService);
reservations.add(primaryStorageReservation);
}
@Override
public void checkVolumeResourceLimitForDiskOfferingChange(Account owner, Boolean display, Long currentSize, Long newSize,
DiskOffering currentOffering, DiskOffering newOffering
DiskOffering currentOffering, DiskOffering newOffering, List<Reserver> reservations
) throws ResourceAllocationException {
Ternary<Set<String>, Set<String>, Set<String>> updatedResourceLimitStorageTags = getResourceLimitStorageTagsForDiskOfferingChange(display, currentOffering, newOffering);
if (updatedResourceLimitStorageTags == null) {
return;
}
Set<String> sameTags = updatedResourceLimitStorageTags.first();
Set<String> newTags = updatedResourceLimitStorageTags.second();
if (newSize > currentSize) {
for (String tag : sameTags) {
checkResourceLimitWithTag(owner, ResourceType.primary_storage, tag, newSize - currentSize);
}
List<String> currentTags = getResourceLimitStorageTagsForResourceCountOperation(true, currentOffering);
List<String> tagsAfterUpdate = getResourceLimitStorageTagsForResourceCountOperation(true, newOffering);
if (currentTags.isEmpty() && tagsAfterUpdate.isEmpty()) {
return;
}
for (String tag : newTags) {
checkResourceLimitWithTag(owner, ResourceType.volume, tag, 1L);
checkResourceLimitWithTag(owner, ResourceType.primary_storage, tag, newSize);
}
CheckedReservation volumeReservation = new CheckedReservation(owner, ResourceType.volume, null, tagsAfterUpdate,
currentTags, 1L, 1L, reservationDao, resourceLimitService);
reservations.add(volumeReservation);
CheckedReservation primaryStorageReservation = new CheckedReservation(owner, ResourceType.primary_storage, null,
tagsAfterUpdate, currentTags, newSize, currentSize, reservationDao, resourceLimitService);
reservations.add(primaryStorageReservation);
}
@DB
@ -1932,18 +1934,23 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
}
@Override
public void checkVmResourceLimit(Account owner, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template) throws ResourceAllocationException {
public void checkVmResourceLimit(Account owner, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Reserver> reservations) throws ResourceAllocationException {
List<String> tags = getResourceLimitHostTagsForResourceCountOperation(display, serviceOffering, template);
if (CollectionUtils.isEmpty(tags)) {
return;
}
CheckedReservation vmReservation = new CheckedReservation(owner, ResourceType.user_vm, tags, 1L, reservationDao, resourceLimitService);
reservations.add(vmReservation);
Long cpu = serviceOffering.getCpu() != null ? Long.valueOf(serviceOffering.getCpu()) : 0L;
CheckedReservation cpuReservation = new CheckedReservation(owner, ResourceType.cpu, tags, cpu, reservationDao, resourceLimitService);
reservations.add(cpuReservation);
Long ram = serviceOffering.getRamSize() != null ? Long.valueOf(serviceOffering.getRamSize()) : 0L;
for (String tag : tags) {
checkResourceLimitWithTag(owner, ResourceType.user_vm, tag);
checkResourceLimitWithTag(owner, ResourceType.cpu, tag, cpu);
checkResourceLimitWithTag(owner, ResourceType.memory, tag, ram);
}
CheckedReservation memReservation = new CheckedReservation(owner, ResourceType.memory, tags, ram, reservationDao, resourceLimitService);
reservations.add(memReservation);
}
@Override
@ -1989,76 +1996,53 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
@Override
public void checkVmResourceLimitsForTemplateChange(Account owner, Boolean display, ServiceOffering offering,
VirtualMachineTemplate currentTemplate, VirtualMachineTemplate newTemplate) throws ResourceAllocationException {
VirtualMachineTemplate currentTemplate, VirtualMachineTemplate newTemplate, List<Reserver> reservations) throws ResourceAllocationException {
checkVmResourceLimitsForServiceOfferingAndTemplateChange(owner, display, null, null,
null, null, offering, offering, currentTemplate, newTemplate);
null, null, offering, offering, currentTemplate, newTemplate, reservations);
}
@Override
public void checkVmResourceLimitsForServiceOfferingChange(Account owner, Boolean display, Long currentCpu, Long newCpu,
Long currentMemory, Long newMemory,
ServiceOffering currentOffering, ServiceOffering newOffering, VirtualMachineTemplate template
ServiceOffering currentOffering, ServiceOffering newOffering, VirtualMachineTemplate template, List<Reserver> reservations
) throws ResourceAllocationException {
checkVmResourceLimitsForServiceOfferingAndTemplateChange(owner, display, currentCpu, newCpu, currentMemory, newMemory, currentOffering,
newOffering != null ? newOffering : currentOffering, template, template);
newOffering != null ? newOffering : currentOffering, template, template, reservations);
}
private void checkVmResourceLimitsForServiceOfferingAndTemplateChange(Account owner, Boolean display, Long currentCpu, Long newCpu,
Long currentMemory, Long newMemory, ServiceOffering currentOffering, ServiceOffering newOffering,
VirtualMachineTemplate currentTemplate, VirtualMachineTemplate newTemplate
VirtualMachineTemplate currentTemplate, VirtualMachineTemplate newTemplate, List<Reserver> reservations
) throws ResourceAllocationException {
Ternary<Set<String>, Set<String>, Set<String>> updatedResourceLimitHostTags = getResourceLimitHostTagsForVmServiceOfferingAndTemplateChange(display, currentOffering, newOffering, currentTemplate, newTemplate);
if (updatedResourceLimitHostTags == null) {
List<String> currentTags = getResourceLimitHostTagsForResourceCountOperation(true, currentOffering, currentTemplate);
List<String> tagsAfterUpdate = getResourceLimitHostTagsForResourceCountOperation(true, newOffering, newTemplate);
if (currentTags.isEmpty() && tagsAfterUpdate.isEmpty()) {
return;
}
CheckedReservation vmReservation = new CheckedReservation(owner, ResourceType.user_vm, null, tagsAfterUpdate,
currentTags, 1L, 1L, reservationDao, resourceLimitService);
reservations.add(vmReservation);
if (currentCpu == null) {
currentCpu = currentOffering.getCpu() != null ? Long.valueOf(currentOffering.getCpu()) : 0L;
}
if (newCpu == null) {
newCpu = newOffering.getCpu() != null ? Long.valueOf(newOffering.getCpu()) : 0L;
}
CheckedReservation cpuReservation = new CheckedReservation(owner, ResourceType.cpu, null, tagsAfterUpdate,
currentTags, newCpu, currentCpu, reservationDao, resourceLimitService);
reservations.add(cpuReservation);
if (currentMemory == null) {
currentMemory = currentOffering.getRamSize() != null ? Long.valueOf(currentOffering.getRamSize()) : 0L;
}
if (newMemory == null) {
newMemory = newOffering.getRamSize() != null ? Long.valueOf(newOffering.getRamSize()) : 0L;
}
Set<String> sameTags = updatedResourceLimitHostTags.first();
Set<String> newTags = updatedResourceLimitHostTags.second();
if (newCpu - currentCpu > 0 || newMemory - currentMemory > 0) {
for (String tag : sameTags) {
if (newCpu - currentCpu > 0) {
checkResourceLimitWithTag(owner, ResourceType.cpu, tag, newCpu - currentCpu);
}
if (newMemory - currentMemory > 0) {
checkResourceLimitWithTag(owner, ResourceType.memory, tag, newMemory - currentMemory);
}
}
}
for (String tag : newTags) {
checkResourceLimitWithTag(owner, ResourceType.user_vm, tag, 1L);
checkResourceLimitWithTag(owner, ResourceType.cpu, tag, newCpu);
checkResourceLimitWithTag(owner, ResourceType.memory, tag, newMemory);
}
}
@Override
public void checkVmCpuResourceLimit(Account owner, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long cpu) throws ResourceAllocationException {
List<String> tags = getResourceLimitHostTagsForResourceCountOperation(display, serviceOffering, template);
if (CollectionUtils.isEmpty(tags)) {
return;
}
if (cpu == null) {
cpu = serviceOffering.getCpu() != null ? Long.valueOf(serviceOffering.getCpu()) : 0L;
}
for (String tag : tags) {
checkResourceLimitWithTag(owner, ResourceType.cpu, tag, cpu);
}
CheckedReservation memReservation = new CheckedReservation(owner, ResourceType.memory, null, tagsAfterUpdate,
currentTags, newMemory, currentMemory, reservationDao, resourceLimitService);
reservations.add(memReservation);
}
@Override
@ -2089,20 +2073,6 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
}
}
@Override
public void checkVmMemoryResourceLimit(Account owner, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long memory) throws ResourceAllocationException {
List<String> tags = getResourceLimitHostTagsForResourceCountOperation(display, serviceOffering, template);
if (CollectionUtils.isEmpty(tags)) {
return;
}
if (memory == null) {
memory = serviceOffering.getRamSize() != null ? Long.valueOf(serviceOffering.getRamSize()) : 0L;
}
for (String tag : tags) {
checkResourceLimitWithTag(owner, ResourceType.memory, tag, memory);
}
}
@Override
public void incrementVmMemoryResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long memory) {
List<String> tags = getResourceLimitHostTagsForResourceCountOperation(display, serviceOffering, template);

View File

@ -36,6 +36,7 @@ import java.util.stream.Collectors;
import javax.inject.Inject;
import com.cloud.resourcelimit.CheckedReservation;
import com.cloud.resourcelimit.ReservationHelper;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.InternalIdentity;
@ -93,6 +94,7 @@ import org.apache.cloudstack.resourcedetail.DiskOfferingDetailVO;
import org.apache.cloudstack.resourcedetail.SnapshotPolicyDetailVO;
import org.apache.cloudstack.resourcedetail.dao.DiskOfferingDetailsDao;
import org.apache.cloudstack.resourcedetail.dao.SnapshotPolicyDetailsDao;
import org.apache.cloudstack.resourcelimit.Reserver;
import org.apache.cloudstack.snapshot.SnapshotHelper;
import org.apache.cloudstack.storage.command.AttachAnswer;
import org.apache.cloudstack.storage.command.AttachCommand;
@ -425,9 +427,17 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
Long diskOfferingId = cmd.getDiskOfferingId();
String imageStoreUuid = cmd.getImageStoreUuid();
validateVolume(caller, ownerId, zoneId, volumeName, url, format, diskOfferingId);
VolumeVO volume;
VolumeVO volume = persistVolume(owner, zoneId, volumeName, url, format, diskOfferingId, Volume.State.Allocated);
List<Reserver> reservations = new ArrayList<>();
try {
validateVolume(caller, ownerId, zoneId, volumeName, url, format, diskOfferingId, reservations);
volume = persistVolume(owner, zoneId, volumeName, url, format, diskOfferingId, Volume.State.Allocated);
} finally {
ReservationHelper.closeAll(reservations);
}
VolumeInfo vol = volFactory.getVolume(volume.getId());
@ -467,7 +477,9 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
final Long diskOfferingId = cmd.getDiskOfferingId();
String imageStoreUuid = cmd.getImageStoreUuid();
validateVolume(caller, ownerId, zoneId, volumeName, null, format, diskOfferingId);
List<Reserver> reservations = new ArrayList<>();
try {
validateVolume(caller, ownerId, zoneId, volumeName, null, format, diskOfferingId, reservations);
return Transaction.execute(new TransactionCallbackWithException<GetUploadParamsResponse, MalformedURLException>() {
@Override
@ -535,9 +547,13 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
return response;
}
});
} finally {
ReservationHelper.closeAll(reservations);
}
}
private boolean validateVolume(Account caller, long ownerId, Long zoneId, String volumeName, String url, String format, Long diskOfferingId) throws ResourceAllocationException {
private boolean validateVolume(Account caller, long ownerId, Long zoneId, String volumeName, String url, String format, Long diskOfferingId, List<Reserver> reservations) throws ResourceAllocationException {
// permission check
Account volumeOwner = _accountMgr.getActiveAccountById(ownerId);
@ -548,7 +564,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
_accountMgr.checkAccess(caller, null, true, volumeOwner);
// Check that the resource limit for volumes won't be exceeded
_resourceLimitMgr.checkVolumeResourceLimit(volumeOwner, true, null, diskOffering);
_resourceLimitMgr.checkVolumeResourceLimit(volumeOwner, true, null, diskOffering, reservations);
// Verify that zone exists
DataCenterVO zone = _dcDao.findById(zoneId);
@ -926,8 +942,10 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
if (tags.size() == 1 && tags.get(0) == null) {
tags = new ArrayList<>();
}
try (CheckedReservation volumeReservation = new CheckedReservation(owner, ResourceType.volume, null, tags, 1L, reservationDao, _resourceLimitMgr);
CheckedReservation primaryStorageReservation = new CheckedReservation(owner, ResourceType.primary_storage, null, tags, size, reservationDao, _resourceLimitMgr)) {
List<Reserver> reservations = new ArrayList<>();
try {
_resourceLimitMgr.checkVolumeResourceLimit(owner, displayVolume, size, diskOffering, reservations);
// Verify that zone exists
DataCenterVO zone = _dcDao.findById(zoneId);
@ -950,9 +968,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
return commitVolume(cmd, caller, owner, displayVolume, zoneId, diskOfferingId, provisioningType, size, minIops, maxIops, parentVolume, userSpecifiedName,
_uuidMgr.generateUuid(Volume.class, cmd.getCustomId()), details);
} catch (Exception e) {
logger.error(e);
throw new RuntimeException(e);
} finally {
ReservationHelper.closeAll(reservations);
}
}
@ -1278,7 +1295,10 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
if (dataStore != null && dataStore.getDriver() instanceof PrimaryDataStoreDriver) {
newSize = ((PrimaryDataStoreDriver) dataStore.getDriver()).getVolumeSizeRequiredOnPool(newSize, null, isEncryptionRequired);
}
validateVolumeResizeWithSize(volume, currentSize, newSize, shrinkOk, diskOffering, newDiskOffering);
List<Reserver> reservations = new ArrayList<>();
try {
validateVolumeResizeWithSize(volume, currentSize, newSize, shrinkOk, diskOffering, newDiskOffering, reservations);
// 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
@ -1406,6 +1426,10 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
return orchestrateResizeVolume(volume.getId(), currentSize, newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve, newDiskOffering != null ? cmd.getNewDiskOfferingId() : null,
shrinkOk);
} finally {
ReservationHelper.closeAll(reservations);
}
}
/**
@ -1839,12 +1863,11 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
throw new InvalidParameterValueException("Please specify a volume in Destroy state.");
}
DiskOffering diskOffering = _diskOfferingDao.findById(volume.getDiskOfferingId());
List<Reserver> reservations = new ArrayList<>();
try {
_resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(volume.getAccountId()), ResourceType.primary_storage, volume.isDisplayVolume(), volume.getSize());
} catch (ResourceAllocationException e) {
logger.error("primary storage resource limit check failed", e);
throw new InvalidParameterValueException(e.getMessage());
}
_resourceLimitMgr.checkVolumeResourceLimit(_accountMgr.getAccount(volume.getAccountId()), volume.isDisplayVolume(), volume.getSize(), diskOffering, reservations);
try {
_volsDao.detachVolume(volume.getId());
@ -1856,6 +1879,12 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
_resourceLimitMgr.incrementVolumeResourceCount(volume.getAccountId(), volume.isDisplay(),
volume.getSize(), _diskOfferingDao.findById(volume.getDiskOfferingId()));
} catch (ResourceAllocationException e) {
logger.error("primary storage resource limit check failed", e);
throw new InvalidParameterValueException(e.getMessage());
} finally {
ReservationHelper.closeAll(reservations);
}
publishVolumeCreationUsageEvent(volume);
@ -2085,7 +2114,9 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
newSize = ((PrimaryDataStoreDriver) dataStore.getDriver()).getVolumeSizeRequiredOnPool(newSize, null, newDiskOffering.getEncrypt());
}
validateVolumeResizeWithSize(volume, currentSize, newSize, shrinkOk, existingDiskOffering, newDiskOffering);
List<Reserver> reservations = new ArrayList<>();
try {
validateVolumeResizeWithSize(volume, currentSize, newSize, shrinkOk, existingDiskOffering, newDiskOffering, reservations);
/* If this volume has never been beyond allocated state, short circuit everything and simply update the database. */
// We need to publish this event to usage_volume table
@ -2175,6 +2206,10 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
}
return volume;
} finally {
ReservationHelper.closeAll(reservations);
}
}
private void updateStorageWithTheNewDiskOffering(VolumeVO volume, DiskOfferingVO newDiskOffering) {
@ -2380,7 +2415,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
}
private void validateVolumeResizeWithSize(VolumeVO volume, long currentSize, Long newSize, boolean shrinkOk,
DiskOfferingVO existingDiskOffering, DiskOfferingVO newDiskOffering) throws ResourceAllocationException {
DiskOfferingVO existingDiskOffering, DiskOfferingVO newDiskOffering, List<Reserver> reservations) throws ResourceAllocationException {
// if the caller is looking to change the size of the volume
if (newSize != null && currentSize != newSize) {
@ -2450,7 +2485,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
/* Check resource limit for this account */
_resourceLimitMgr.checkVolumeResourceLimitForDiskOfferingChange(_accountMgr.getAccount(volume.getAccountId()),
volume.isDisplayVolume(), currentSize, newSize != null ? newSize : currentSize,
existingDiskOffering, newDiskOffering);
existingDiskOffering, newDiskOffering, reservations);
}
@Override
@ -2622,7 +2657,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
checkForBackups(vm, true);
checkRightsToAttach(caller, volumeToAttach, vm);
_accountMgr.checkAccess(caller, null, true, volumeToAttach, vm);
HypervisorType rootDiskHyperType = vm.getHypervisorType();
HypervisorType volumeToAttachHyperType = _volsDao.getHypervisorType(volumeToAttach.getId());
@ -2649,6 +2684,12 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
throw new InvalidParameterValueException("Volume's disk offering has encryption enabled, but volume encryption is not supported for hypervisor type " + rootDiskHyperType);
}
Account owner = _accountDao.findById(volumeToAttach.getAccountId());
List<String> resourceLimitStorageTags = _resourceLimitMgr.getResourceLimitStorageTagsForResourceCountOperation(true, diskOffering);
Long requiredPrimaryStorageSpace = getRequiredPrimaryStorageSizeForVolumeAttach(resourceLimitStorageTags, volumeToAttach);
try (CheckedReservation primaryStorageReservation = new CheckedReservation(owner, ResourceType.primary_storage, resourceLimitStorageTags, requiredPrimaryStorageSpace, reservationDao, _resourceLimitMgr)) {
_jobMgr.updateAsyncJobAttachment(job.getId(), "Volume", volumeId);
if (asyncExecutionContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) {
@ -2656,9 +2697,21 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
} else {
return getVolumeAttachJobResult(vmId, volumeId, deviceId);
}
} catch (ResourceAllocationException e) {
logger.error("primary storage resource limit check failed", e);
throw new InvalidParameterValueException(e.getMessage());
}
}
@Nullable private Volume getVolumeAttachJobResult(Long vmId, Long volumeId, Long deviceId) {
protected Long getRequiredPrimaryStorageSizeForVolumeAttach(List<String> resourceLimitStorageTags, VolumeInfo volumeToAttach) {
if (CollectionUtils.isEmpty(resourceLimitStorageTags) || Arrays.asList(Volume.State.Allocated, Volume.State.Ready).contains(volumeToAttach.getState())) {
return 0L;
}
return volumeToAttach.getSize();
}
@Nullable protected Volume getVolumeAttachJobResult(Long vmId, Long volumeId, Long deviceId) {
Outcome<Volume> outcome = attachVolumeToVmThroughJobQueue(vmId, volumeId, deviceId);
Volume vol = null;
@ -2707,21 +2760,6 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
}
}
private void checkRightsToAttach(Account caller, VolumeInfo volumeToAttach, UserVmVO vm) {
_accountMgr.checkAccess(caller, null, true, volumeToAttach, vm);
Account owner = _accountDao.findById(volumeToAttach.getAccountId());
if (!Arrays.asList(Volume.State.Allocated, Volume.State.Ready).contains(volumeToAttach.getState())) {
try {
_resourceLimitMgr.checkResourceLimit(owner, ResourceType.primary_storage, volumeToAttach.getSize());
} catch (ResourceAllocationException e) {
logger.error("primary storage resource limit check failed", e);
throw new InvalidParameterValueException(e.getMessage());
}
}
}
private void checkForVMSnapshots(Long vmId, UserVmVO vm) {
// if target VM has associated VM snapshots
List<VMSnapshotVO> vmSnapshots = _vmSnapshotDao.findByVm(vmId);
@ -4207,7 +4245,9 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
_accountMgr.checkAccess(caller, null, true, oldAccount);
_accountMgr.checkAccess(caller, null, true, newAccount);
_resourceLimitMgr.checkVolumeResourceLimit(newAccount, true, volume.getSize(), _diskOfferingDao.findById(volume.getDiskOfferingId()));
List<Reserver> reservations = new ArrayList<>();
try {
_resourceLimitMgr.checkVolumeResourceLimit(newAccount, true, volume.getSize(), _diskOfferingDao.findById(volume.getDiskOfferingId()), reservations);
Transaction.execute(new TransactionCallbackNoReturn() {
@Override
@ -4217,6 +4257,10 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
});
return volume;
} finally {
ReservationHelper.closeAll(reservations);
}
}
protected void updateVolumeAccount(Account oldAccount, VolumeVO volume, Account newAccount) {

View File

@ -1759,16 +1759,13 @@ 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;
} catch (ResourceAllocationException e) {
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 new CloudRuntimeException(e);
throw e;
}
}

View File

@ -357,6 +357,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
// Secondary storage resource count is not incremented for BareMetalTemplateAdapter
// Note: checking the file size before registering will require the Management Server host to have access to the Internet and a DNS server
// If it does not, UriUtils.getRemoteSize will return 0L.
long secondaryStorageUsage = adapter instanceof HypervisorTemplateAdapter && !cmd.isDirectDownload() ?
UriUtils.getRemoteSize(cmd.getUrl(), StorageManager.DataStoreDownloadFollowRedirects.value()) : 0L;
@ -365,7 +366,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
TemplateProfile profile = adapter.prepare(cmd);
VMTemplateVO template = adapter.create(profile);
// Secondary storage resource usage will be recalculated in com.cloud.template.HypervisorTemplateAdapter.createTemplateAsyncCallBack
// Secondary storage resource usage will be incremented in com.cloud.template.HypervisorTemplateAdapter.createTemplateAsyncCallBack
_resourceLimitMgr.incrementResourceCount(profile.getAccountId(), ResourceType.template);
if (secondaryStorageUsage > 0) {
_resourceLimitMgr.incrementResourceCount(profile.getAccountId(), ResourceType.secondary_storage, secondaryStorageUsage);
@ -405,7 +406,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
TemplateProfile profile = adapter.prepare(cmd);
VMTemplateVO template = adapter.create(profile);
// Secondary storage resource usage will be recalculated in com.cloud.template.HypervisorTemplateAdapter.createTemplateAsyncCallBack
// Secondary storage resource usage will be incremented in com.cloud.template.HypervisorTemplateAdapter.createTemplateAsyncCallBack
// for HypervisorTemplateAdapter
_resourceLimitMgr.incrementResourceCount(profile.getAccountId(), ResourceType.template);
if (secondaryStorageUsage > 0) {

View File

@ -54,6 +54,7 @@ import javax.naming.ConfigurationException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
import com.cloud.resourcelimit.ReservationHelper;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
@ -122,6 +123,7 @@ import org.apache.cloudstack.framework.messagebus.PublishScope;
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
import org.apache.cloudstack.query.QueryService;
import org.apache.cloudstack.reservation.dao.ReservationDao;
import org.apache.cloudstack.resourcelimit.Reserver;
import org.apache.cloudstack.snapshot.SnapshotHelper;
import org.apache.cloudstack.storage.command.DeleteCommand;
import org.apache.cloudstack.storage.command.DettachCommand;
@ -1351,9 +1353,12 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
Account owner = _accountMgr.getActiveAccountById(vmInstance.getAccountId());
VMTemplateVO template = _templateDao.findByIdIncludingRemoved(vmInstance.getTemplateId());
List<Reserver> reservations = new ArrayList<>();
try {
if (!VirtualMachineManager.ResourceCountRunningVMsonly.value()) {
_resourceLimitMgr.checkVmResourceLimitsForServiceOfferingChange(owner, vmInstance.isDisplay(), (long) currentCpu, (long) newCpu,
(long) currentMemory, (long) newMemory, currentServiceOffering, newServiceOffering, template);
(long) currentMemory, (long) newMemory, currentServiceOffering, newServiceOffering, template, reservations);
}
// Check that the specified service offering ID is valid
@ -1376,6 +1381,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
return _vmDao.findById(vmInstance.getId());
} finally {
ReservationHelper.closeAll(reservations);
}
}
/**
@ -2063,9 +2071,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
VMTemplateVO template = _templateDao.findByIdIncludingRemoved(vmInstance.getTemplateId());
List<Reserver> reservations = new ArrayList<>();
try {
// Check resource limits
_resourceLimitMgr.checkVmResourceLimitsForServiceOfferingChange(owner, vmInstance.isDisplay(), (long) currentCpu, (long) newCpu,
(long) currentMemory, (long) newMemory, currentServiceOffering, newServiceOffering, template);
(long) currentMemory, (long) newMemory, currentServiceOffering, newServiceOffering, template, reservations);
// Dynamically upgrade the running vms
boolean success = false;
@ -2137,6 +2147,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
}
}
return success;
} finally {
ReservationHelper.closeAll(reservations);
}
}
protected void validateDiskOfferingChecks(ServiceOfferingVO currentServiceOffering, ServiceOfferingVO newServiceOffering) {
@ -2322,10 +2336,12 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
ServiceOfferingVO serviceOffering = serviceOfferingDao.findById(vm.getId(), vm.getServiceOfferingId());
VMTemplateVO template = _templateDao.findByIdIncludingRemoved(vm.getTemplateId());
List<Reserver> reservations = new ArrayList<>();
try {
// First check that the maximum number of UserVMs, CPU and Memory limit for the given
// accountId will not be exceeded
if (!VirtualMachineManager.ResourceCountRunningVMsonly.value()) {
resourceLimitService.checkVmResourceLimit(account, vm.isDisplayVm(), serviceOffering, template);
resourceLimitService.checkVmResourceLimit(account, vm.isDisplayVm(), serviceOffering, template, reservations);
}
_haMgr.cancelDestroy(vm, vm.getHostId());
@ -2350,6 +2366,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
//Update Resource Count for the given account
resourceCountIncrement(account.getId(), vm.isDisplayVm(), serviceOffering, template);
} finally {
ReservationHelper.closeAll(reservations);
}
}
});
@ -2776,27 +2796,25 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
long currentCpu = currentServiceOffering.getCpu();
long currentMemory = currentServiceOffering.getRamSize();
VMTemplateVO template = _templateDao.findByIdIncludingRemoved(vmInstance.getTemplateId());
List<Reserver> reservations = new ArrayList<>();
try {
_resourceLimitMgr.checkVmResourceLimitsForServiceOfferingChange(owner, vmInstance.isDisplay(), currentCpu, newCpu,
currentMemory, newMemory, currentServiceOffering, svcOffering, template, reservations);
if (newCpu > currentCpu) {
_resourceLimitMgr.checkVmCpuResourceLimit(owner, vmInstance.isDisplay(), svcOffering, template, newCpu - currentCpu);
_resourceLimitMgr.incrementVmCpuResourceCount(owner.getAccountId(), vmInstance.isDisplay(), svcOffering, template, newCpu - currentCpu);
} else if (newCpu > 0 && currentCpu > newCpu){
_resourceLimitMgr.decrementVmCpuResourceCount(owner.getAccountId(), vmInstance.isDisplay(), svcOffering, template, currentCpu - newCpu);
}
if (newMemory > currentMemory) {
_resourceLimitMgr.checkVmMemoryResourceLimit(owner, vmInstance.isDisplay(), svcOffering, template, newMemory - currentMemory);
_resourceLimitMgr.incrementVmMemoryResourceCount(owner.getAccountId(), vmInstance.isDisplay(), svcOffering, template, newMemory - currentMemory);
} else if (newMemory > 0 && currentMemory > newMemory){
_resourceLimitMgr.decrementVmMemoryResourceCount(owner.getAccountId(), vmInstance.isDisplay(), svcOffering, template, currentMemory - newMemory);
}
} catch (ResourceAllocationException e) {
logger.error(String.format("Failed to updated VM due to: %s", e.getLocalizedMessage()));
throw new InvalidParameterValueException(e.getLocalizedMessage());
}
if (newCpu > currentCpu) {
_resourceLimitMgr.incrementVmCpuResourceCount(owner.getAccountId(), vmInstance.isDisplay(), svcOffering, template, newCpu - currentCpu);
} else if (newCpu > 0 && currentCpu > newCpu){
_resourceLimitMgr.decrementVmCpuResourceCount(owner.getAccountId(), vmInstance.isDisplay(), svcOffering, template, currentCpu - newCpu);
}
if (newMemory > currentMemory) {
_resourceLimitMgr.incrementVmMemoryResourceCount(owner.getAccountId(), vmInstance.isDisplay(), svcOffering, template, newMemory - currentMemory);
} else if (newMemory > 0 && currentMemory > newMemory){
_resourceLimitMgr.decrementVmMemoryResourceCount(owner.getAccountId(), vmInstance.isDisplay(), svcOffering, template, currentMemory - newMemory);
} finally {
ReservationHelper.closeAll(reservations);
}
}
@ -4236,7 +4254,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
throw new InvalidParameterValueException(String.format("Invalid disk offering %s specified for datadisk Template %s. Disk offering size should be greater than or equal to the Template size", dataDiskOffering, dataDiskTemplate));
}
_templateDao.loadDetails(dataDiskTemplate);
resourceLimitService.checkVolumeResourceLimit(owner, true, dataDiskOffering.getDiskSize(), dataDiskOffering);
}
}
@ -5660,11 +5677,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
CheckedReservation memReservation = new CheckedReservation(owner, ResourceType.memory, resourceLimitHostTags, Long.valueOf(offering.getRamSize()), reservationDao, resourceLimitService);
) {
return startVirtualMachineUnchecked(vm, template, podId, clusterId, hostId, additionalParams, deploymentPlannerToUse, isExplicitHost, isRootAdmin);
} catch (ResourceAllocationException | CloudRuntimeException e) {
throw e;
} catch (Exception e) {
logger.error("Failed to start VM {} : error during resource reservation and allocation", e);
throw new CloudRuntimeException(e);
}
} else {
return startVirtualMachineUnchecked(vm, template, podId, clusterId, hostId, additionalParams, deploymentPlannerToUse, isExplicitHost, isRootAdmin);
@ -7387,38 +7399,29 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
return findMigratedVm(vm.getId(), vm.getType());
}
protected void checkVolumesLimits(Account account, List<VolumeVO> volumes) throws ResourceAllocationException {
Long totalVolumes = 0L;
Long totalVolumesSize = 0L;
protected void checkVolumesLimits(Account account, List<VolumeVO> volumes, List<Reserver> reservations) throws ResourceAllocationException {
Map<Long, List<String>> diskOfferingTagsMap = new HashMap<>();
Map<String, Long> tagVolumeCountMap = new HashMap<>();
Map<String, Long> tagSizeMap = new HashMap<>();
for (VolumeVO volume : volumes) {
if (!volume.isDisplay()) {
continue;
}
totalVolumes++;
totalVolumesSize += volume.getSize();
if (!diskOfferingTagsMap.containsKey(volume.getDiskOfferingId())) {
diskOfferingTagsMap.put(volume.getDiskOfferingId(), _resourceLimitMgr.getResourceLimitStorageTags(
_diskOfferingDao.findById(volume.getDiskOfferingId())));
Long diskOfferingId = volume.getDiskOfferingId();
if (!diskOfferingTagsMap.containsKey(diskOfferingId)) {
DiskOffering diskOffering = _diskOfferingDao.findById(diskOfferingId);
List<String> tagsForDiskOffering = _resourceLimitMgr.getResourceLimitStorageTags(diskOffering);
diskOfferingTagsMap.put(diskOfferingId, tagsForDiskOffering);
}
List<String> tags = diskOfferingTagsMap.get(volume.getDiskOfferingId());
for (String tag : tags) {
if (tagVolumeCountMap.containsKey(tag)) {
tagVolumeCountMap.put(tag, tagVolumeCountMap.get(tag) + 1);
tagSizeMap.put(tag, tagSizeMap.get(tag) + volume.getSize());
} else {
tagVolumeCountMap.put(tag, 1L);
tagSizeMap.put(tag, volume.getSize());
}
}
}
_resourceLimitMgr.checkResourceLimit(account, ResourceType.volume, totalVolumes);
_resourceLimitMgr.checkResourceLimit(account, ResourceType.primary_storage, totalVolumesSize);
for (String tag : tagVolumeCountMap.keySet()) {
resourceLimitService.checkResourceLimitWithTag(account, ResourceType.volume, tag, tagVolumeCountMap.get(tag));
resourceLimitService.checkResourceLimitWithTag(account, ResourceType.primary_storage, tag, tagSizeMap.get(tag));
List<String> tags = diskOfferingTagsMap.get(diskOfferingId);
CheckedReservation volumeReservation = new CheckedReservation(account, ResourceType.volume, tags, 1L, reservationDao, resourceLimitService);
reservations.add(volumeReservation);
long size = ObjectUtils.defaultIfNull(volume.getSize(), 0L);
CheckedReservation primaryStorageReservation = new CheckedReservation(account, ResourceType.primary_storage, tags, size, reservationDao, resourceLimitService);
reservations.add(primaryStorageReservation);
}
}
@ -7460,14 +7463,16 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
final ServiceOfferingVO offering = serviceOfferingDao.findByIdIncludingRemoved(vm.getId(), vm.getServiceOfferingId());
VirtualMachineTemplate template = _templateDao.findByIdIncludingRemoved(vm.getTemplateId());
verifyResourceLimitsForAccountAndStorage(newAccount, vm, offering, volumes, template);
validateIfNewOwnerHasAccessToTemplate(vm, newAccount, template);
DomainVO domain = _domainDao.findById(domainId);
logger.trace("Verifying if the new account [{}] has access to the specified domain [{}].", newAccount, domain);
_accountMgr.checkAccess(newAccount, domain);
List<Reserver> reservations = new ArrayList<>();
try {
verifyResourceLimitsForAccountAndStorage(newAccount, vm, offering, volumes, template, reservations);
Network newNetwork = ensureDestinationNetwork(cmd, vm, newAccount);
try {
Transaction.execute(new TransactionCallbackNoReturn() {
@ -7484,6 +7489,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
throw e;
}
} finally {
ReservationHelper.closeAll(reservations);
}
logger.info("VM [{}] now belongs to account [{}].", vm.getInstanceName(), newAccountName);
return vm;
}
@ -7554,18 +7563,18 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
* @param volumes The volumes whose total size can exceed resource limits.
* @throws ResourceAllocationException
*/
protected void verifyResourceLimitsForAccountAndStorage(Account account, UserVmVO vm, ServiceOfferingVO offering, List<VolumeVO> volumes, VirtualMachineTemplate template)
protected void verifyResourceLimitsForAccountAndStorage(Account account, UserVmVO vm, ServiceOfferingVO offering, List<VolumeVO> volumes, VirtualMachineTemplate template, List<Reserver> reservations)
throws ResourceAllocationException {
logger.trace("Verifying if CPU and RAM for VM [{}] do not exceed account [{}] limit.", vm, account);
if (!countOnlyRunningVmsInResourceLimitation()) {
resourceLimitService.checkVmResourceLimit(account, vm.isDisplayVm(), offering, template);
resourceLimitService.checkVmResourceLimit(account, vm.isDisplayVm(), offering, template, reservations);
}
logger.trace("Verifying if volume size for VM [{}] does not exceed account [{}] limit.", vm, account);
checkVolumesLimits(account, volumes);
checkVolumesLimits(account, volumes, reservations);
}
protected boolean countOnlyRunningVmsInResourceLimitation() {
@ -8415,12 +8424,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
VMTemplateVO template = getRestoreVirtualMachineTemplate(caller, newTemplateId, rootVols, vm);
DiskOffering diskOffering = rootDiskOfferingId != null ? _diskOfferingDao.findById(rootDiskOfferingId) : null;
List<Reserver> reservations = new ArrayList<>();
try {
checkRestoreVmFromTemplate(vm, template, rootVols, diskOffering, details);
} catch (ResourceAllocationException e) {
logger.error("Failed to restore VM {} due to {}", vm, e.getMessage(), e);
throw new CloudRuntimeException("Failed to restore VM " + vm.getUuid() + " due to " + e.getMessage(), e);
}
checkRestoreVmFromTemplate(vm, template, rootVols, diskOffering, details, reservations);
if (needRestart) {
try {
@ -8565,6 +8572,12 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
logger.debug("Restore VM {} done successfully", vm);
return vm;
} catch (ResourceAllocationException e) {
logger.error("Failed to restore VM {} due to {}", vm, e.getMessage(), e);
throw new CloudRuntimeException("Failed to restore VM " + vm.getUuid() + " due to " + e.getMessage(), e);
} finally {
ReservationHelper.closeAll(reservations);
}
}
Long getRootVolumeSizeForVmRestore(Volume vol, VMTemplateVO template, UserVmVO userVm, DiskOffering diskOffering, Map<String, String> details, boolean update) {
@ -8664,7 +8677,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
* @param template template
* @throws InvalidParameterValueException if restore is not possible
*/
private void checkRestoreVmFromTemplate(UserVmVO vm, VMTemplateVO template, List<VolumeVO> rootVolumes, DiskOffering newDiskOffering, Map<String,String> details) throws ResourceAllocationException {
private void checkRestoreVmFromTemplate(UserVmVO vm, VMTemplateVO template, List<VolumeVO> rootVolumes, DiskOffering newDiskOffering, Map<String,String> details, List<Reserver> reservations) throws ResourceAllocationException {
TemplateDataStoreVO tmplStore;
if (!template.isDirectDownload()) {
tmplStore = _templateStoreDao.findByTemplateZoneReady(template.getId(), vm.getDataCenterId());
@ -8682,7 +8695,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
if (vm.getTemplateId() != template.getId()) {
ServiceOfferingVO serviceOffering = serviceOfferingDao.findById(vm.getId(), vm.getServiceOfferingId());
VMTemplateVO currentTemplate = _templateDao.findByIdIncludingRemoved(vm.getTemplateId());
_resourceLimitMgr.checkVmResourceLimitsForTemplateChange(owner, vm.isDisplay(), serviceOffering, currentTemplate, template);
_resourceLimitMgr.checkVmResourceLimitsForTemplateChange(owner, vm.isDisplay(), serviceOffering, currentTemplate, template, reservations);
}
for (Volume vol : rootVolumes) {
@ -8693,7 +8706,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
if (newDiskOffering != null || !vol.getSize().equals(newSize)) {
DiskOffering currentOffering = _diskOfferingDao.findById(vol.getDiskOfferingId());
_resourceLimitMgr.checkVolumeResourceLimitForDiskOfferingChange(owner, vol.isDisplay(),
vol.getSize(), newSize, currentOffering, newDiskOffering);
vol.getSize(), newSize, currentOffering, newDiskOffering, reservations);
}
}
}

View File

@ -811,25 +811,31 @@ public class VMSnapshotManagerImpl extends MutualExclusiveIdsManagerBase impleme
}
/**
* If snapshot was taken with a different service offering than actual used in vm, should change it back to it
* @param userVm vm to change service offering (if necessary)
* If snapshot was taken with a different service offering than actual used in vm, should change it back to it.
* We also call <code>changeUserVmServiceOffering</code> in case the service offering is dynamic in order to
* perform resource limit validation, as the amount of CPUs or memory may have been changed.
* @param vmSnapshotVo vm snapshot
*/
protected void updateUserVmServiceOffering(UserVm userVm, VMSnapshotVO vmSnapshotVo) {
if (vmSnapshotVo.getServiceOfferingId() != userVm.getServiceOfferingId()) {
changeUserVmServiceOffering(userVm, vmSnapshotVo);
return;
}
ServiceOfferingVO serviceOffering = _serviceOfferingDao.findById(userVm.getServiceOfferingId());
if (serviceOffering.isDynamic()) {
changeUserVmServiceOffering(userVm, vmSnapshotVo);
}
}
/**
* Get user vm details as a map
* @param userVm user vm
* @param vmSnapshotVo snapshot to get the details from
* @return map
*/
protected Map<String, String> getVmMapDetails(UserVm userVm) {
List<UserVmDetailVO> userVmDetails = _userVmDetailsDao.listDetails(userVm.getId());
protected Map<String, String> getVmMapDetails(VMSnapshotVO vmSnapshotVo) {
List<VMSnapshotDetailsVO> vmSnapshotDetails = _vmSnapshotDetailsDao.listDetails(vmSnapshotVo.getId());
Map<String, String> details = new HashMap<String, String>();
for (UserVmDetailVO detail : userVmDetails) {
for (VMSnapshotDetailsVO detail : vmSnapshotDetails) {
details.put(detail.getName(), detail.getValue());
}
return details;
@ -841,7 +847,7 @@ public class VMSnapshotManagerImpl extends MutualExclusiveIdsManagerBase impleme
* @param vmSnapshotVo vm snapshot
*/
protected void changeUserVmServiceOffering(UserVm userVm, VMSnapshotVO vmSnapshotVo) {
Map<String, String> vmDetails = getVmMapDetails(userVm);
Map<String, String> vmDetails = getVmMapDetails(vmSnapshotVo);
boolean result = upgradeUserVmServiceOffering(userVm, vmSnapshotVo.getServiceOfferingId(), vmDetails);
if (! result){
throw new CloudRuntimeException("Instance Snapshot reverting failed because the Instance service offering couldn't be changed to the one used when Snapshot was taken");
@ -938,8 +944,8 @@ public class VMSnapshotManagerImpl extends MutualExclusiveIdsManagerBase impleme
Transaction.execute(new TransactionCallbackWithExceptionNoReturn<CloudRuntimeException>() {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) throws CloudRuntimeException {
revertCustomServiceOfferingDetailsFromVmSnapshot(userVm, vmSnapshotVo);
updateUserVmServiceOffering(userVm, vmSnapshotVo);
revertCustomServiceOfferingDetailsFromVmSnapshot(userVm, vmSnapshotVo);
}
});
return userVm;

View File

@ -35,6 +35,7 @@ import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.offering.DiskOffering;
import com.cloud.resourcelimit.ReservationHelper;
import com.cloud.storage.DataStoreRole;
import com.cloud.storage.DiskOfferingVO;
import com.cloud.storage.Storage;
@ -68,6 +69,7 @@ import org.apache.cloudstack.api.response.VolumeForImportResponse;
import org.apache.cloudstack.api.response.VolumeResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
import org.apache.cloudstack.resourcelimit.Reserver;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
@ -198,10 +200,7 @@ public class VolumeImportUnmanageManagerImpl implements VolumeImportUnmanageServ
logFailureAndThrowException("Volume is a reference of snapshot on primary: " + volume.getFullPath());
}
// 5. check resource limitation
checkResourceLimitForImportVolume(owner, volume);
// 6. get disk offering
// 5. get disk offering
DiskOfferingVO diskOffering = getOrCreateDiskOffering(owner, cmd.getDiskOfferingId(), pool.getDataCenterId(), pool.isLocal());
if (diskOffering.isCustomized()) {
volumeApiService.validateCustomDiskOfferingSizeRange(volume.getVirtualSize() / ByteScaleUtils.GiB);
@ -210,6 +209,11 @@ public class VolumeImportUnmanageManagerImpl implements VolumeImportUnmanageServ
logFailureAndThrowException(String.format("Disk offering: %s storage tags are not compatible with selected storage pool: %s", diskOffering, pool));
}
List<Reserver> reservations = new ArrayList<>();
try {
// 6. check resource limitation
checkResourceLimitForImportVolume(owner, volume, diskOffering, reservations);
// 7. create records
String volumeName = StringUtils.isNotBlank(cmd.getName()) ? cmd.getName().trim() : volumePath;
VolumeVO volumeVO = importVolumeInternal(volume, diskOffering, owner, pool, volumeName);
@ -221,6 +225,10 @@ public class VolumeImportUnmanageManagerImpl implements VolumeImportUnmanageServ
publicUsageEventForVolumeImportAndUnmanage(volumeVO, true);
return responseGenerator.createVolumeResponse(ResponseObject.ResponseView.Full, volumeVO);
} finally {
ReservationHelper.closeAll(reservations);
}
}
protected VolumeOnStorageTO getVolumeOnStorageAndCheck(StoragePoolVO pool, String volumePath) {
@ -456,11 +464,10 @@ public class VolumeImportUnmanageManagerImpl implements VolumeImportUnmanageServ
return volumeDao.findById(diskProfile.getVolumeId());
}
protected void checkResourceLimitForImportVolume(Account owner, VolumeOnStorageTO volume) {
protected void checkResourceLimitForImportVolume(Account owner, VolumeOnStorageTO volume, DiskOfferingVO diskOffering, List<Reserver> reservations) {
Long volumeSize = volume.getVirtualSize();
try {
resourceLimitService.checkResourceLimit(owner, Resource.ResourceType.volume);
resourceLimitService.checkResourceLimit(owner, Resource.ResourceType.primary_storage, volumeSize);
resourceLimitService.checkVolumeResourceLimit(owner, true, volumeSize, diskOffering, reservations);
} catch (ResourceAllocationException e) {
logger.error("VM resource allocation error for account: {}", owner, e);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("VM resource allocation error for account: %s. %s", owner.getUuid(), StringUtils.defaultString(e.getMessage())));

View File

@ -86,6 +86,8 @@ import com.cloud.offerings.dao.NetworkOfferingDao;
import com.cloud.org.Cluster;
import com.cloud.resource.ResourceManager;
import com.cloud.resource.ResourceState;
import com.cloud.resourcelimit.CheckedReservation;
import com.cloud.resourcelimit.ReservationHelper;
import com.cloud.serializer.GsonHelper;
import com.cloud.server.ManagementService;
import com.cloud.service.ServiceOfferingVO;
@ -164,6 +166,8 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.reservation.dao.ReservationDao;
import org.apache.cloudstack.resourcelimit.Reserver;
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
@ -222,6 +226,8 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
@Inject
private ResourceLimitService resourceLimitService;
@Inject
private ReservationDao reservationDao;
@Inject
private UserVmDetailsDao userVmDetailsDao;
@Inject
private UserVmManager userVmManager;
@ -604,7 +610,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
return new Pair<>(rootDisk, dataDisks);
}
private void checkUnmanagedDiskAndOfferingForImport(String instanceName, UnmanagedInstanceTO.Disk disk, DiskOffering diskOffering, ServiceOffering serviceOffering, final Account owner, final DataCenter zone, final Cluster cluster, final boolean migrateAllowed)
private void checkUnmanagedDiskAndOfferingForImport(String instanceName, UnmanagedInstanceTO.Disk disk, DiskOffering diskOffering, ServiceOffering serviceOffering, final Account owner, final DataCenter zone, final Cluster cluster, final boolean migrateAllowed, List<Reserver> reservations)
throws ServerApiException, PermissionDeniedException, ResourceAllocationException {
if (serviceOffering == null && diskOffering == null) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Disk offering for disk ID [%s] not found during VM [%s] import.", disk.getDiskId(), instanceName));
@ -612,7 +618,6 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
if (diskOffering != null) {
accountService.checkAccess(owner, diskOffering, zone);
}
resourceLimitService.checkVolumeResourceLimit(owner, true, null, diskOffering);
if (disk.getCapacity() == null || disk.getCapacity() == 0) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Size of disk(ID: %s) is found invalid during VM import", disk.getDiskId()));
}
@ -627,9 +632,10 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
if (diskOffering != null && !migrateAllowed && !storagePoolSupportsDiskOffering(storagePool, diskOffering)) {
throw new InvalidParameterValueException(String.format("Disk offering: %s is not compatible with storage pool: %s of unmanaged disk: %s", diskOffering.getUuid(), storagePool.getUuid(), disk.getDiskId()));
}
resourceLimitService.checkVolumeResourceLimit(owner, true, disk.getCapacity(), diskOffering, reservations);
}
private void checkUnmanagedDiskAndOfferingForImport(String intanceName, List<UnmanagedInstanceTO.Disk> disks, final Map<String, Long> diskOfferingMap, final Account owner, final DataCenter zone, final Cluster cluster, final boolean migrateAllowed)
private void checkUnmanagedDiskAndOfferingForImport(String intanceName, List<UnmanagedInstanceTO.Disk> disks, final Map<String, Long> diskOfferingMap, final Account owner, final DataCenter zone, final Cluster cluster, final boolean migrateAllowed, List<Reserver> reservations)
throws ServerApiException, PermissionDeniedException, ResourceAllocationException {
String diskController = null;
for (UnmanagedInstanceTO.Disk disk : disks) {
@ -646,7 +652,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Multiple data disk controllers of different type (%s, %s) are not supported for import. Please make sure that all data disk controllers are of the same type", diskController, disk.getController()));
}
}
checkUnmanagedDiskAndOfferingForImport(intanceName, disk, diskOfferingDao.findById(diskOfferingMap.get(disk.getDiskId())), null, owner, zone, cluster, migrateAllowed);
checkUnmanagedDiskAndOfferingForImport(intanceName, disk, diskOfferingDao.findById(diskOfferingMap.get(disk.getDiskId())), null, owner, zone, cluster, migrateAllowed, reservations);
}
}
@ -1073,40 +1079,6 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
}
}
protected void checkUnmanagedDiskLimits(Account account, UnmanagedInstanceTO.Disk rootDisk, ServiceOffering serviceOffering,
List<UnmanagedInstanceTO.Disk> dataDisks, Map<String, Long> dataDiskOfferingMap) throws ResourceAllocationException {
Long totalVolumes = 0L;
Long totalVolumesSize = 0L;
List<UnmanagedInstanceTO.Disk> disks = new ArrayList<>();
disks.add(rootDisk);
disks.addAll(dataDisks);
Map<String, Long> diskOfferingMap = new HashMap<>(dataDiskOfferingMap);
diskOfferingMap.put(rootDisk.getDiskId(), serviceOffering.getDiskOfferingId());
Map<Long, Long> diskOfferingVolumeCountMap = new HashMap<>();
Map<Long, Long> diskOfferingSizeMap = new HashMap<>();
for (UnmanagedInstanceTO.Disk disk : disks) {
totalVolumes++;
totalVolumesSize += disk.getCapacity();
Long diskOfferingId = diskOfferingMap.get(disk.getDiskId());
if (diskOfferingVolumeCountMap.containsKey(diskOfferingId)) {
diskOfferingVolumeCountMap.put(diskOfferingId, diskOfferingVolumeCountMap.get(diskOfferingId) + 1);
diskOfferingSizeMap.put(diskOfferingId, diskOfferingSizeMap.get(diskOfferingId) + disk.getCapacity());
} else {
diskOfferingVolumeCountMap.put(diskOfferingId, 1L);
diskOfferingSizeMap.put(diskOfferingId, disk.getCapacity());
}
}
resourceLimitService.checkResourceLimit(account, Resource.ResourceType.volume, totalVolumes);
resourceLimitService.checkResourceLimit(account, Resource.ResourceType.primary_storage, totalVolumesSize);
for (Long diskOfferingId : diskOfferingVolumeCountMap.keySet()) {
List<String> tags = resourceLimitService.getResourceLimitStorageTags(diskOfferingDao.findById(diskOfferingId));
for (String tag : tags) {
resourceLimitService.checkResourceLimitWithTag(account, Resource.ResourceType.volume, tag, diskOfferingVolumeCountMap.get(diskOfferingId));
resourceLimitService.checkResourceLimitWithTag(account, Resource.ResourceType.primary_storage, tag, diskOfferingSizeMap.get(diskOfferingId));
}
}
}
private UserVm importVirtualMachineInternal(final UnmanagedInstanceTO unmanagedInstance, final String instanceNameInternal, final DataCenter zone, final Cluster cluster, final HostVO host,
final VirtualMachineTemplate template, final String displayName, final String hostName, final Account caller, final Account owner, final Long userId,
final ServiceOfferingVO serviceOffering, final Map<String, Long> dataDiskOfferingMap,
@ -1164,17 +1136,14 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
allDetails.put(VmDetailConstants.ROOT_DISK_SIZE, String.valueOf(size));
}
List<Reserver> reservations = new ArrayList<>();
try {
checkUnmanagedDiskAndOfferingForImport(unmanagedInstance.getName(), rootDisk, null, validatedServiceOffering, owner, zone, cluster, migrateAllowed);
if (CollectionUtils.isNotEmpty(dataDisks)) { // Data disk(s) present
checkUnmanagedDiskAndOfferingForImport(unmanagedInstance.getName(), dataDisks, dataDiskOfferingMap, owner, zone, cluster, migrateAllowed);
allDetails.put(VmDetailConstants.DATA_DISK_CONTROLLER, dataDisks.get(0).getController());
}
checkUnmanagedDiskLimits(owner, rootDisk, serviceOffering, dataDisks, dataDiskOfferingMap);
} catch (ResourceAllocationException e) {
logger.error("Volume resource allocation error for owner: {}", owner, e);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Volume resource allocation error for owner: %s. %s", owner.getUuid(), StringUtils.defaultString(e.getMessage())));
checkUnmanagedDiskAndOfferingForImport(unmanagedInstance.getName(), rootDisk, null, validatedServiceOffering, owner, zone, cluster, migrateAllowed, reservations);
if (CollectionUtils.isNotEmpty(dataDisks)) { // Data disk(s) present
checkUnmanagedDiskAndOfferingForImport(unmanagedInstance.getName(), dataDisks, dataDiskOfferingMap, owner, zone, cluster, migrateAllowed, reservations);
allDetails.put(VmDetailConstants.DATA_DISK_CONTROLLER, dataDisks.get(0).getController());
}
// Check NICs and supplied networks
Map<String, Network.IpAddresses> nicIpAddressMap = getNicIpAddresses(unmanagedInstance.getNics(), callerNicIpAddressMap);
Map<String, Long> allNicNetworkMap = getUnmanagedNicNetworkMap(unmanagedInstance.getName(), unmanagedInstance.getNics(), nicNetworkMap, nicIpAddressMap, zone, hostName, owner, cluster.getHypervisorType());
@ -1257,6 +1226,13 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
}
publishVMUsageUpdateResourceCount(userVm, validatedServiceOffering, template);
return userVm;
} catch (ResourceAllocationException e) { // This will be thrown by checkUnmanagedDiskAndOfferingForImport, so the VM was not imported yet
logger.error("Volume resource allocation error for owner: {}", owner, e);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Volume resource allocation error for owner: %s. %s", owner.getUuid(), StringUtils.defaultString(e.getMessage())));
} finally {
ReservationHelper.closeAll(reservations);
}
}
private void addImportingVMBootTypeAndModeDetails(String bootType, String bootMode, Map<String, String> allDetails) {
@ -1361,8 +1337,6 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
VMTemplateVO template = getTemplateForImportInstance(cmd.getTemplateId(), cluster.getHypervisorType());
ServiceOfferingVO serviceOffering = getServiceOfferingForImportInstance(cmd.getServiceOfferingId(), owner, zone);
checkResourceLimitForImportInstance(owner);
String displayName = getDisplayNameForImportInstance(cmd.getDisplayName(), instanceName);
String hostName = getHostNameForImportInstance(cmd.getHostName(), cluster.getHypervisorType(), instanceName, displayName);
@ -1378,6 +1352,11 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
List<String> managedVms = new ArrayList<>(additionalNameFilters);
managedVms.addAll(getHostsManagedVms(hosts));
List<String> resourceLimitHostTags = resourceLimitService.getResourceLimitHostTags(serviceOffering, template);
try (CheckedReservation vmReservation = new CheckedReservation(owner, Resource.ResourceType.user_vm, resourceLimitHostTags, 1L, reservationDao, resourceLimitService);
CheckedReservation cpuReservation = new CheckedReservation(owner, Resource.ResourceType.cpu, resourceLimitHostTags, Long.valueOf(serviceOffering.getCpu()), reservationDao, resourceLimitService);
CheckedReservation memReservation = new CheckedReservation(owner, Resource.ResourceType.memory, resourceLimitHostTags, Long.valueOf(serviceOffering.getRamSize()), reservationDao, resourceLimitService)) {
ActionEventUtils.onStartedActionEvent(userId, owner.getId(), EventTypes.EVENT_VM_IMPORT,
cmd.getEventDescription(), null, null, true, 0);
@ -1405,6 +1384,11 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
}
}
} catch (ResourceAllocationException e) {
logger.error(String.format("VM resource allocation error for account: %s", owner.getUuid()), e);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("VM resource allocation error for account: %s. %s", owner.getUuid(), StringUtils.defaultString(e.getMessage())));
}
if (userVm == null) {
ActionEventUtils.onCompletedActionEvent(userId, owner.getId(), EventVO.LEVEL_ERROR, EventTypes.EVENT_VM_IMPORT,
cmd.getEventDescription(), null, null, 0);
@ -1464,15 +1448,6 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
return StringUtils.isEmpty(displayName) ? instanceName : displayName;
}
private void checkResourceLimitForImportInstance(Account owner) {
try {
resourceLimitService.checkResourceLimit(owner, Resource.ResourceType.user_vm, 1);
} catch (ResourceAllocationException e) {
logger.error("VM resource allocation error for account: {}", owner, e);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("VM resource allocation error for account: %s. %s", owner.getUuid(), StringUtils.defaultString(e.getMessage())));
}
}
private ServiceOfferingVO getServiceOfferingForImportInstance(Long serviceOfferingId, Account owner, DataCenter zone) {
if (serviceOfferingId == null) {
throw new InvalidParameterValueException("Service offering ID cannot be null");
@ -2338,12 +2313,6 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
throw new InvalidParameterValueException(String.format("Service offering ID: %d cannot be found", serviceOfferingId));
}
accountService.checkAccess(owner, serviceOffering, zone);
try {
resourceLimitService.checkResourceLimit(owner, Resource.ResourceType.user_vm, 1);
} catch (ResourceAllocationException e) {
logger.error("VM resource allocation error for account: {}", owner, e);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("VM resource allocation error for account: %s. %s", owner.getUuid(), StringUtils.defaultString(e.getMessage())));
}
String displayName = cmd.getDisplayName();
if (StringUtils.isEmpty(displayName)) {
displayName = instanceName;
@ -2431,6 +2400,11 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
UserVm userVm = null;
List<String> resourceLimitHostTags = resourceLimitService.getResourceLimitHostTags(serviceOffering, template);
try (CheckedReservation vmReservation = new CheckedReservation(owner, Resource.ResourceType.user_vm, resourceLimitHostTags, 1L, reservationDao, resourceLimitService);
CheckedReservation cpuReservation = new CheckedReservation(owner, Resource.ResourceType.cpu, resourceLimitHostTags, Long.valueOf(serviceOffering.getCpu()), reservationDao, resourceLimitService);
CheckedReservation memReservation = new CheckedReservation(owner, Resource.ResourceType.memory, resourceLimitHostTags, Long.valueOf(serviceOffering.getRamSize()), reservationDao, resourceLimitService)) {
if (ImportSource.EXTERNAL == importSource) {
String username = cmd.getUsername();
String password = cmd.getPassword();
@ -2451,6 +2425,12 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
throw new RuntimeException(e);
}
}
} catch (ResourceAllocationException e) {
logger.error(String.format("VM resource allocation error for account: %s", owner.getUuid()), e);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("VM resource allocation error for account: %s. %s", owner.getUuid(), StringUtils.defaultString(e.getMessage())));
}
if (userVm == null) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to import Vm with name: %s ", instanceName));
}
@ -2464,7 +2444,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
final VirtualMachineTemplate template, final String displayName, final String hostName, final Account caller, final Account owner, final Long userId,
final ServiceOfferingVO serviceOffering, final Map<String, Long> dataDiskOfferingMap,
final Map<String, Long> nicNetworkMap, final Map<String, Network.IpAddresses> callerNicIpAddressMap,
final String remoteUrl, String username, String password, String tmpPath, final Map<String, String> details) {
final String remoteUrl, String username, String password, String tmpPath, final Map<String, String> details) throws ResourceAllocationException {
UserVm userVm = null;
Map<String, String> allDetails = new HashMap<>(details);
@ -2475,6 +2455,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("No attached disks found for the unmanaged VM: %s", instanceName));
}
DiskOfferingVO diskOffering = diskOfferingDao.findById(serviceOffering.getDiskOfferingId());
Pair<UnmanagedInstanceTO.Disk, List<UnmanagedInstanceTO.Disk>> rootAndDataDisksPair = getRootAndDataDisks(unmanagedInstanceDisks, dataDiskOfferingMap);
final UnmanagedInstanceTO.Disk rootDisk = rootAndDataDisksPair.first();
final List<UnmanagedInstanceTO.Disk> dataDisks = rootAndDataDisksPair.second();
@ -2483,6 +2464,10 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
}
allDetails.put(VmDetailConstants.ROOT_DISK_CONTROLLER, rootDisk.getController());
List<Reserver> reservations = new ArrayList<>();
try {
checkVolumeResourceLimitsForExternalKvmVmImport(owner, rootDisk, dataDisks, diskOffering, dataDiskOfferingMap, reservations);
// Check NICs and supplied networks
Map<String, Network.IpAddresses> nicIpAddressMap = getNicIpAddresses(unmanagedInstance.getNics(), callerNicIpAddressMap);
Map<String, Long> allNicNetworkMap = getUnmanagedNicNetworkMap(unmanagedInstance.getName(), unmanagedInstance.getNics(), nicNetworkMap, nicIpAddressMap, zone, hostName, owner, Hypervisor.HypervisorType.KVM);
@ -2503,16 +2488,12 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
if (userVm == null) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to import vm name: %s", instanceName));
}
DiskOfferingVO diskOffering = diskOfferingDao.findById(serviceOffering.getDiskOfferingId());
String rootVolumeName = String.format("ROOT-%s", userVm.getId());
DiskProfile diskProfile = volumeManager.allocateRawVolume(Volume.Type.ROOT, rootVolumeName, diskOffering, null, null, null, userVm, template, owner, null);
DiskProfile[] dataDiskProfiles = new DiskProfile[dataDisks.size()];
int diskSeq = 0;
for (UnmanagedInstanceTO.Disk disk : dataDisks) {
if (disk.getCapacity() == null || disk.getCapacity() == 0) {
throw new InvalidParameterValueException(String.format("Disk ID: %s size is invalid", disk.getDiskId()));
}
DiskOffering offering = diskOfferingDao.findById(dataDiskOfferingMap.get(disk.getDiskId()));
DiskProfile dataDiskProfile = volumeManager.allocateRawVolume(Volume.Type.DATADISK, String.format("DATA-%d-%s", userVm.getId(), disk.getDiskId()), offering, null, null, null, userVm, template, owner, null);
dataDiskProfiles[diskSeq++] = dataDiskProfile;
@ -2537,10 +2518,6 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
List<Pair<DiskProfile, StoragePool>> diskProfileStoragePoolList = new ArrayList<>();
try {
if (rootDisk.getCapacity() == null || rootDisk.getCapacity() == 0) {
throw new InvalidParameterValueException(String.format("Root disk ID: %s size is invalid", rootDisk.getDiskId()));
}
diskProfileStoragePoolList.add(importExternalDisk(rootDisk, userVm, dest, diskOffering, Volume.Type.ROOT,
template, null, remoteUrl, username, password, tmpPath, diskProfile));
@ -2574,6 +2551,30 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
}
publishVMUsageUpdateResourceCount(userVm, dummyOffering, template);
return userVm;
} finally {
ReservationHelper.closeAll(reservations);
}
}
protected void checkVolumeResourceLimitsForExternalKvmVmImport(Account owner, UnmanagedInstanceTO.Disk rootDisk,
List<UnmanagedInstanceTO.Disk> dataDisks, DiskOfferingVO rootDiskOffering,
Map<String, Long> dataDiskOfferingMap, List<Reserver> reservations) throws ResourceAllocationException {
if (rootDisk.getCapacity() == null || rootDisk.getCapacity() == 0) {
throw new InvalidParameterValueException(String.format("Root disk ID: %s size is invalid", rootDisk.getDiskId()));
}
resourceLimitService.checkVolumeResourceLimit(owner, true, rootDisk.getCapacity(), rootDiskOffering, reservations);
if (CollectionUtils.isEmpty(dataDisks)) {
return;
}
for (UnmanagedInstanceTO.Disk disk : dataDisks) {
if (disk.getCapacity() == null || disk.getCapacity() == 0) {
throw new InvalidParameterValueException(String.format("Data disk ID: %s size is invalid", disk.getDiskId()));
}
DiskOffering offering = diskOfferingDao.findById(dataDiskOfferingMap.get(disk.getDiskId()));
resourceLimitService.checkVolumeResourceLimit(owner, true, disk.getCapacity(), offering, reservations);
}
}
private UserVm importKvmVirtualMachineFromDisk(final ImportSource importSource, final String instanceName, final DataCenter zone,
@ -2641,7 +2642,16 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
if (userVm == null) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to import vm name: %s", instanceName));
}
DiskOfferingVO diskOffering = diskOfferingDao.findById(serviceOffering.getDiskOfferingId());
List<Reserver> reservations = new ArrayList<>();
List<String> resourceLimitStorageTags = resourceLimitService.getResourceLimitStorageTagsForResourceCountOperation(true, diskOffering);
try {
CheckedReservation volumeReservation = new CheckedReservation(owner, Resource.ResourceType.volume, resourceLimitStorageTags,
CollectionUtils.isNotEmpty(resourceLimitStorageTags) ? 1L : 0L, reservationDao, resourceLimitService);
reservations.add(volumeReservation);
String rootVolumeName = String.format("ROOT-%s", userVm.getId());
DiskProfile diskProfile = volumeManager.allocateRawVolume(Volume.Type.ROOT, rootVolumeName, diskOffering, null, null, null, userVm, template, owner, null);
@ -2686,6 +2696,14 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
throw new CloudRuntimeException("Disk not found or is invalid");
}
diskProfile.setSize(checkVolumeAnswer.getSize());
try {
CheckedReservation primaryStorageReservation = new CheckedReservation(owner, Resource.ResourceType.primary_storage, resourceLimitStorageTags,
CollectionUtils.isNotEmpty(resourceLimitStorageTags) ? diskProfile.getSize() : 0L, reservationDao, resourceLimitService);
reservations.add(primaryStorageReservation);
} catch (ResourceAllocationException e) {
cleanupFailedImportVM(userVm);
throw e;
}
List<Pair<DiskProfile, StoragePool>> diskProfileStoragePoolList = new ArrayList<>();
try {
@ -2705,6 +2723,10 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
networkOrchestrationService.importNic(macAddress, 0, network, true, userVm, requestedIpPair, zone, true);
publishVMUsageUpdateResourceCount(userVm, dummyOffering, template);
return userVm;
} finally {
ReservationHelper.closeAll(reservations);
}
}
private void checkVolume(Map<VolumeOnStorageTO.Detail, String> volumeDetails) {

View File

@ -28,6 +28,7 @@ import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.TaggedResourceLimitAndCountResponse;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.reservation.dao.ReservationDao;
import org.apache.cloudstack.resourcelimit.Reserver;
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
@ -40,6 +41,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedConstruction;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
@ -264,6 +266,7 @@ public class ResourceLimitManagerImplTest extends TestCase {
@Test
public void testCheckVmResourceLimit() {
List<Reserver> reservations = new ArrayList<>();
ServiceOffering serviceOffering = Mockito.mock(ServiceOffering.class);
VirtualMachineTemplate template = Mockito.mock(VirtualMachineTemplate.class);
Mockito.when(serviceOffering.getHostTag()).thenReturn(hostTags.get(0));
@ -271,53 +274,12 @@ public class ResourceLimitManagerImplTest extends TestCase {
Mockito.when(serviceOffering.getRamSize()).thenReturn(256);
Mockito.when(template.getTemplateTag()).thenReturn(hostTags.get(0));
Account account = Mockito.mock(Account.class);
try {
Mockito.doNothing().when(resourceLimitManager).checkResourceLimitWithTag(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any());
resourceLimitManager.checkVmResourceLimit(account, true, serviceOffering, template);
try (MockedConstruction<CheckedReservation> mockCheckedReservation = Mockito.mockConstruction(CheckedReservation.class)) {
resourceLimitManager.checkVmResourceLimit(account, true, serviceOffering, template, reservations);
List<String> tags = new ArrayList<>();
tags.add(null);
tags.add(hostTags.get(0));
for (String tag: tags) {
Mockito.verify(resourceLimitManager, Mockito.times(1)).checkResourceLimitWithTag(account, Resource.ResourceType.user_vm, tag);
Mockito.verify(resourceLimitManager, Mockito.times(1)).checkResourceLimitWithTag(account, Resource.ResourceType.cpu, tag, 2L);
Mockito.verify(resourceLimitManager, Mockito.times(1)).checkResourceLimitWithTag(account, Resource.ResourceType.memory, tag, 256L);
}
} catch (ResourceAllocationException e) {
Assert.fail("Exception encountered: " + e.getMessage());
}
}
@Test
public void testCheckVmCpuResourceLimit() {
ServiceOffering serviceOffering = Mockito.mock(ServiceOffering.class);
VirtualMachineTemplate template = Mockito.mock(VirtualMachineTemplate.class);
Mockito.when(serviceOffering.getHostTag()).thenReturn(hostTags.get(0));
Mockito.when(template.getTemplateTag()).thenReturn(hostTags.get(0));
Account account = Mockito.mock(Account.class);
long cpu = 2L;
try {
Mockito.doNothing().when(resourceLimitManager).checkResourceLimitWithTag(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any());
resourceLimitManager.checkVmCpuResourceLimit(account, true, serviceOffering, template, cpu);
Mockito.verify(resourceLimitManager, Mockito.times(1)).checkResourceLimitWithTag(account, Resource.ResourceType.cpu, null, cpu);
Mockito.verify(resourceLimitManager, Mockito.times(1)).checkResourceLimitWithTag(account, Resource.ResourceType.cpu, hostTags.get(0), cpu);
} catch (ResourceAllocationException e) {
Assert.fail("Exception encountered: " + e.getMessage());
}
}
@Test
public void testCheckVmMemoryResourceLimit() {
ServiceOffering serviceOffering = Mockito.mock(ServiceOffering.class);
VirtualMachineTemplate template = Mockito.mock(VirtualMachineTemplate.class);
Mockito.when(serviceOffering.getHostTag()).thenReturn(hostTags.get(0));
Mockito.when(template.getTemplateTag()).thenReturn(hostTags.get(0));
Account account = Mockito.mock(Account.class);
long delta = 256L;
try {
Mockito.doNothing().when(resourceLimitManager).checkResourceLimitWithTag(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any());
resourceLimitManager.checkVmMemoryResourceLimit(account, true, serviceOffering, template, delta);
Mockito.verify(resourceLimitManager, Mockito.times(1)).checkResourceLimitWithTag(account, Resource.ResourceType.memory, null, delta);
Mockito.verify(resourceLimitManager, Mockito.times(1)).checkResourceLimitWithTag(account, Resource.ResourceType.memory, hostTags.get(0), delta);
Assert.assertEquals(3, mockCheckedReservation.constructed().size());
} catch (ResourceAllocationException e) {
Assert.fail("Exception encountered: " + e.getMessage());
}
@ -325,21 +287,15 @@ public class ResourceLimitManagerImplTest extends TestCase {
@Test
public void testCheckVolumeResourceLimit() {
List<Reserver> reservations = new ArrayList<>();
String checkTag = storageTags.get(0);
DiskOffering diskOffering = Mockito.mock(DiskOffering.class);
Mockito.when(diskOffering.getTags()).thenReturn(checkTag);
Mockito.when(diskOffering.getTagsArray()).thenReturn(new String[]{checkTag});
Account account = Mockito.mock(Account.class);
try {
Mockito.doNothing().when(resourceLimitManager).checkResourceLimitWithTag(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any());
resourceLimitManager.checkVolumeResourceLimit(account, true, 100L, diskOffering);
List<String> tags = new ArrayList<>();
tags.add(null);
tags.add(checkTag);
for (String tag: tags) {
Mockito.verify(resourceLimitManager, Mockito.times(1)).checkResourceLimitWithTag(account, Resource.ResourceType.volume, tag);
Mockito.verify(resourceLimitManager, Mockito.times(1)).checkResourceLimitWithTag(account, Resource.ResourceType.primary_storage, tag, 100L);
}
try (MockedConstruction<CheckedReservation> mockCheckedReservation = Mockito.mockConstruction(CheckedReservation.class)) {
resourceLimitManager.checkVolumeResourceLimit(account, true, 100L, diskOffering, reservations);
Assert.assertEquals(2, reservations.size());
} catch (ResourceAllocationException e) {
Assert.fail("Exception encountered: " + e.getMessage());
}
@ -934,13 +890,6 @@ public class ResourceLimitManagerImplTest extends TestCase {
Mockito.anyList(), Mockito.eq(tag));
}
private void mockCheckResourceLimitWithTag() throws ResourceAllocationException {
Mockito.doNothing().when(resourceLimitManager).checkResourceLimitWithTag(
Mockito.any(Account.class), Mockito.any(Resource.ResourceType.class), Mockito.anyString());
Mockito.doNothing().when(resourceLimitManager).checkResourceLimitWithTag(
Mockito.any(Account.class), Mockito.any(Resource.ResourceType.class), Mockito.anyString(), Mockito.anyLong());
}
private void mockIncrementResourceCountWithTag() {
Mockito.doNothing().when(resourceLimitManager).incrementResourceCountWithTag(
Mockito.anyLong(), Mockito.any(Resource.ResourceType.class), Mockito.anyString());
@ -957,6 +906,7 @@ public class ResourceLimitManagerImplTest extends TestCase {
@Test
public void testCheckVolumeResourceCount() throws ResourceAllocationException {
List<Reserver> reservations = new ArrayList<>();
Account account = Mockito.mock(Account.class);
String tag = "tag";
long delta = 10L;
@ -970,12 +920,11 @@ public class ResourceLimitManagerImplTest extends TestCase {
Mockito.doReturn(List.of(tag)).when(resourceLimitManager)
.getResourceLimitStorageTagsForResourceCountOperation(Mockito.anyBoolean(), Mockito.any(DiskOffering.class));
mockCheckResourceLimitWithTag();
resourceLimitManager.checkVolumeResourceLimit(account, false, delta, Mockito.mock(DiskOffering.class));
Mockito.verify(resourceLimitManager, Mockito.times(1)).checkResourceLimitWithTag(
account, Resource.ResourceType.volume, tag);
Mockito.verify(resourceLimitManager, Mockito.times(1))
.checkResourceLimitWithTag(account, Resource.ResourceType.primary_storage, tag, 10L);
try (MockedConstruction<CheckedReservation> mockCheckedReservation = Mockito.mockConstruction(CheckedReservation.class)) {
resourceLimitManager.checkVolumeResourceLimit(account, false, delta, Mockito.mock(DiskOffering.class), reservations);
Assert.assertEquals(2, reservations.size());
}
}
@Test

View File

@ -26,7 +26,6 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
@ -41,6 +40,7 @@ import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import com.cloud.resourcelimit.CheckedReservation;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import org.apache.cloudstack.api.command.user.volume.CheckAndRepairVolumeCmd;
@ -83,6 +83,7 @@ import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedConstruction;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.Spy;
@ -91,7 +92,6 @@ import org.springframework.test.util.ReflectionTestUtils;
import com.cloud.api.query.dao.ServiceOfferingJoinDao;
import com.cloud.configuration.ConfigurationManager;
import com.cloud.configuration.Resource;
import com.cloud.configuration.Resource.ResourceType;
import com.cloud.dc.ClusterVO;
import com.cloud.dc.DataCenterVO;
@ -545,7 +545,9 @@ public class VolumeApiServiceImplTest {
@Test
public void attachRootVolumePositive() throws NoSuchFieldException, IllegalAccessException {
thrown.expect(NullPointerException.class);
volumeApiServiceImpl.attachVolumeToVM(2L, 6L, 0L, false);
try (MockedConstruction<CheckedReservation> mockCheckedReservation = Mockito.mockConstruction(CheckedReservation.class)) {
volumeApiServiceImpl.attachVolumeToVM(2L, 6L, 0L, false);
}
}
// Negative test - attach data volume, to the vm on non-kvm hypervisor
@ -564,7 +566,9 @@ public class VolumeApiServiceImplTest {
DiskOfferingVO diskOffering = Mockito.mock(DiskOfferingVO.class);
when(diskOffering.getEncrypt()).thenReturn(true);
when(_diskOfferingDao.findById(anyLong())).thenReturn(diskOffering);
volumeApiServiceImpl.attachVolumeToVM(4L, 10L, 1L, false);
try (MockedConstruction<CheckedReservation> mockCheckedReservation = Mockito.mockConstruction(CheckedReservation.class)) {
volumeApiServiceImpl.attachVolumeToVM(4L, 10L, 1L, false);
}
}
// volume not Ready
@ -649,9 +653,7 @@ public class VolumeApiServiceImplTest {
* The resource limit check for primary storage should not be skipped for Volume in 'Uploaded' state.
*/
@Test
public void testResourceLimitCheckForUploadedVolume() throws NoSuchFieldException, IllegalAccessException, ResourceAllocationException {
doThrow(new ResourceAllocationException("primary storage resource limit check failed", Resource.ResourceType.primary_storage)).when(resourceLimitServiceMock)
.checkResourceLimit(any(AccountVO.class), any(Resource.ResourceType.class), any(Long.class));
public void testAttachVolumeToVMPerformsResourceReservation() throws NoSuchFieldException, IllegalAccessException, ResourceAllocationException {
UserVmVO vm = Mockito.mock(UserVmVO.class);
AccountVO acc = Mockito.mock(AccountVO.class);
VolumeInfo volumeToAttach = Mockito.mock(VolumeInfo.class);
@ -672,10 +674,10 @@ public class VolumeApiServiceImplTest {
DataCenterVO zoneWithDisabledLocalStorage = Mockito.mock(DataCenterVO.class);
when(_dcDao.findById(anyLong())).thenReturn(zoneWithDisabledLocalStorage);
when(zoneWithDisabledLocalStorage.isLocalStorageEnabled()).thenReturn(true);
try {
doReturn(volumeVoMock).when(volumeApiServiceImpl).getVolumeAttachJobResult(Mockito.any(), Mockito.any(), Mockito.any());
try (MockedConstruction<CheckedReservation> mockCheckedReservation = Mockito.mockConstruction(CheckedReservation.class)) {
volumeApiServiceImpl.attachVolumeToVM(2L, 9L, null, false);
} catch (InvalidParameterValueException e) {
Assert.assertEquals(e.getMessage(), ("primary storage resource limit check failed"));
Assert.assertEquals(1, mockCheckedReservation.constructed().size());
}
}
@ -2199,4 +2201,34 @@ public class VolumeApiServiceImplTest {
Assert.fail();
}
}
@Test
public void getRequiredPrimaryStorageSizeForVolumeAttachTestTagsAreEmptyReturnsZero() {
List<String> tags = new ArrayList<>();
Long result = volumeApiServiceImpl.getRequiredPrimaryStorageSizeForVolumeAttach(tags, volumeInfoMock);
Assert.assertEquals(0L, (long) result);
}
@Test
public void getRequiredPrimaryStorageSizeForVolumeAttachTestVolumeIsReadyReturnsZero() {
List<String> tags = List.of("tag1", "tag2");
Mockito.doReturn(Volume.State.Ready).when(volumeInfoMock).getState();
Long result = volumeApiServiceImpl.getRequiredPrimaryStorageSizeForVolumeAttach(tags, volumeInfoMock);
Assert.assertEquals(0L, (long) result);
}
@Test
public void getRequiredPrimaryStorageSizeForVolumeAttachTestTagsAreNotEmptyAndVolumeIsUploadedReturnsVolumeSize() {
List<String> tags = List.of("tag1", "tag2");
Mockito.doReturn(Volume.State.Uploaded).when(volumeInfoMock).getState();
Mockito.doReturn(2L).when(volumeInfoMock).getSize();
Long result = volumeApiServiceImpl.getRequiredPrimaryStorageSizeForVolumeAttach(tags, volumeInfoMock);
Assert.assertEquals(2L, (long) result);
}
}

View File

@ -42,6 +42,7 @@ import java.util.List;
import java.util.Map;
import com.cloud.network.NetworkService;
import com.cloud.resourcelimit.CheckedReservation;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.SecurityChecker;
import org.apache.cloudstack.api.BaseCmd.HTTPMethod;
@ -54,6 +55,7 @@ import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd;
import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
import org.apache.cloudstack.resourcelimit.Reserver;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.storage.template.VnfTemplateManager;
@ -65,6 +67,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedConstruction;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
@ -609,7 +612,6 @@ public class UserVmManagerImplTest {
Mockito.doNothing().when(userVmManagerImpl).validateOldAndNewAccounts(Mockito.nullable(Account.class), Mockito.nullable(Account.class), Mockito.anyLong(), Mockito.nullable(String.class), Mockito.nullable(Long.class));
Mockito.doNothing().when(userVmManagerImpl).validateIfVmHasNoRules(Mockito.any(), Mockito.anyLong());
Mockito.doNothing().when(userVmManagerImpl).removeInstanceFromInstanceGroup(Mockito.anyLong());
Mockito.doNothing().when(userVmManagerImpl).verifyResourceLimitsForAccountAndStorage(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyList(), Mockito.any());
Mockito.doNothing().when(userVmManagerImpl).validateIfNewOwnerHasAccessToTemplate(Mockito.any(), Mockito.any(), Mockito.any());
Mockito.doNothing().when(userVmManagerImpl).updateVmOwner(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any());
@ -1615,23 +1617,11 @@ public class UserVmManagerImplTest {
Mockito.when(vol5.isDisplay()).thenReturn(true);
List<VolumeVO> volumes = List.of(vol1, undisplayedVolume, vol3, vol4, vol5);
Long size = volumes.stream().filter(VolumeVO::isDisplay).mapToLong(VolumeVO::getSize).sum();
try {
userVmManagerImpl.checkVolumesLimits(account, volumes);
Mockito.verify(resourceLimitMgr, Mockito.times(1))
.checkResourceLimit(account, Resource.ResourceType.volume, 4);
Mockito.verify(resourceLimitMgr, Mockito.times(1))
.checkResourceLimit(account, Resource.ResourceType.primary_storage, size);
Mockito.verify(resourceLimitMgr, Mockito.times(1))
.checkResourceLimitWithTag(account, Resource.ResourceType.volume, "tag1", 2);
Mockito.verify(resourceLimitMgr, Mockito.times(1))
.checkResourceLimitWithTag(account, Resource.ResourceType.volume, "tag2", 3);
Mockito.verify(resourceLimitMgr, Mockito.times(1))
.checkResourceLimitWithTag(account, Resource.ResourceType.primary_storage, "tag1",
vol1.getSize() + vol5.getSize());
Mockito.verify(resourceLimitMgr, Mockito.times(1))
.checkResourceLimitWithTag(account, Resource.ResourceType.primary_storage, "tag2",
vol1.getSize() + vol3.getSize() + vol5.getSize());
List<Reserver> reservations = new ArrayList<>();
try (MockedConstruction<CheckedReservation> mockCheckedReservation = Mockito.mockConstruction(CheckedReservation.class)) {
userVmManagerImpl.checkVolumesLimits(account, volumes, reservations);
Assert.assertEquals(8, reservations.size());
} catch (ResourceAllocationException e) {
Assert.fail(e.getMessage());
}
@ -1922,26 +1912,26 @@ public class UserVmManagerImplTest {
@Test
public void verifyResourceLimitsForAccountAndStorageTestCountOnlyRunningVmsInResourceLimitationIsTrueDoesNotCallVmResourceLimitCheck() throws ResourceAllocationException {
List<Reserver> reservations = new ArrayList<>();
LinkedList<VolumeVO> volumeVoList = new LinkedList<VolumeVO>();
Mockito.doReturn(true).when(userVmManagerImpl).countOnlyRunningVmsInResourceLimitation();
userVmManagerImpl.verifyResourceLimitsForAccountAndStorage(accountMock, userVmVoMock, serviceOfferingVoMock, volumeVoList, virtualMachineTemplateMock);
userVmManagerImpl.verifyResourceLimitsForAccountAndStorage(accountMock, userVmVoMock, serviceOfferingVoMock, volumeVoList, virtualMachineTemplateMock, reservations);
Mockito.verify(resourceLimitMgr, Mockito.never()).checkVmResourceLimit(Mockito.any(), Mockito.anyBoolean(), Mockito.any(), Mockito.any());
Mockito.verify(resourceLimitMgr).checkResourceLimit(accountMock, Resource.ResourceType.volume, 0l);
Mockito.verify(resourceLimitMgr).checkResourceLimit(accountMock, Resource.ResourceType.primary_storage, 0l);
Mockito.verify(resourceLimitMgr, Mockito.never()).checkVmResourceLimit(Mockito.any(), Mockito.anyBoolean(), Mockito.any(), Mockito.any(), Mockito.any());
Mockito.verify(resourceLimitMgr, Mockito.never()).checkVolumeResourceLimit(Mockito.any(), Mockito.anyBoolean(), Mockito.any(), Mockito.any(), Mockito.any());
}
@Test
public void verifyResourceLimitsForAccountAndStorageTestCountOnlyRunningVmsInResourceLimitationIsFalseCallsVmResourceLimitCheck() throws ResourceAllocationException {
List<Reserver> reservations = new ArrayList<>();
LinkedList<VolumeVO> volumeVoList = new LinkedList<VolumeVO>();
Mockito.doReturn(false).when(userVmManagerImpl).countOnlyRunningVmsInResourceLimitation();
userVmManagerImpl.verifyResourceLimitsForAccountAndStorage(accountMock, userVmVoMock, serviceOfferingVoMock, volumeVoList, virtualMachineTemplateMock);
userVmManagerImpl.verifyResourceLimitsForAccountAndStorage(accountMock, userVmVoMock, serviceOfferingVoMock, volumeVoList, virtualMachineTemplateMock, reservations);
Mockito.verify(resourceLimitMgr).checkVmResourceLimit(Mockito.any(), Mockito.anyBoolean(), Mockito.any(), Mockito.any());
Mockito.verify(resourceLimitMgr).checkResourceLimit(accountMock, Resource.ResourceType.volume, 0l);
Mockito.verify(resourceLimitMgr).checkResourceLimit(accountMock, Resource.ResourceType.primary_storage, 0l);
Mockito.verify(resourceLimitMgr).checkVmResourceLimit(Mockito.any(), Mockito.anyBoolean(), Mockito.any(), Mockito.any(), Mockito.any());
Mockito.verify(userVmManagerImpl).checkVolumesLimits(Mockito.any(), Mockito.any(), Mockito.any());
}
@Test
@ -2986,7 +2976,7 @@ public class UserVmManagerImplTest {
configureDoNothingForMethodsThatWeDoNotWantToTest();
Mockito.doThrow(ResourceAllocationException.class).when(userVmManagerImpl).verifyResourceLimitsForAccountAndStorage(Mockito.any(), Mockito.any(),
Mockito.any(), Mockito.any(), Mockito.any());
Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any());
Assert.assertThrows(ResourceAllocationException.class, () -> userVmManagerImpl.moveVmToUser(assignVmCmdMock));
}

View File

@ -357,13 +357,13 @@ public class VMSnapshotManagerTest {
_vmSnapshotMgr.updateUserVmServiceOffering(userVm, vmSnapshotVO);
verify(_vmSnapshotMgr).changeUserVmServiceOffering(userVm, vmSnapshotVO);
verify(_vmSnapshotMgr).getVmMapDetails(userVm);
verify(_vmSnapshotMgr).getVmMapDetails(vmSnapshotVO);
verify(_vmSnapshotMgr).upgradeUserVmServiceOffering(eq(userVm), eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture());
}
@Test
public void testGetVmMapDetails() {
Map<String, String> result = _vmSnapshotMgr.getVmMapDetails(userVm);
Map<String, String> result = _vmSnapshotMgr.getVmMapDetails(vmSnapshotVO);
assert(result.containsKey(userVmDetailCpuNumber.getName()));
assert(result.containsKey(userVmDetailMemory.getName()));
assertEquals(userVmDetails.size(), result.size());
@ -375,7 +375,7 @@ public class VMSnapshotManagerTest {
public void testChangeUserVmServiceOffering() throws ConcurrentOperationException, ResourceUnavailableException, ManagementServerException, VirtualMachineMigrationException {
when(_userVmManager.upgradeVirtualMachine(eq(TEST_VM_ID), eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture())).thenReturn(true);
_vmSnapshotMgr.changeUserVmServiceOffering(userVm, vmSnapshotVO);
verify(_vmSnapshotMgr).getVmMapDetails(userVm);
verify(_vmSnapshotMgr).getVmMapDetails(vmSnapshotVO);
verify(_vmSnapshotMgr).upgradeUserVmServiceOffering(eq(userVm), eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture());
}
@ -383,7 +383,7 @@ public class VMSnapshotManagerTest {
public void testChangeUserVmServiceOfferingFailOnUpgradeVMServiceOffering() throws ConcurrentOperationException, ResourceUnavailableException, ManagementServerException, VirtualMachineMigrationException {
when(_userVmManager.upgradeVirtualMachine(eq(TEST_VM_ID), eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture())).thenReturn(false);
_vmSnapshotMgr.changeUserVmServiceOffering(userVm, vmSnapshotVO);
verify(_vmSnapshotMgr).getVmMapDetails(userVm);
verify(_vmSnapshotMgr).getVmMapDetails(vmSnapshotVO);
verify(_vmSnapshotMgr).upgradeUserVmServiceOffering(eq(userVm), eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture());
}

View File

@ -24,6 +24,7 @@ import javax.naming.ConfigurationException;
import org.apache.cloudstack.api.response.AccountResponse;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.resourcelimit.Reserver;
import org.springframework.stereotype.Component;
import com.cloud.configuration.Resource.ResourceType;
@ -273,7 +274,7 @@ public class MockResourceLimitManagerImpl extends ManagerBase implements Resourc
}
@Override
public void checkVolumeResourceLimit(Account owner, Boolean display, Long size, DiskOffering diskOffering) throws ResourceAllocationException {
public void checkVolumeResourceLimit(Account owner, Boolean display, Long size, DiskOffering diskOffering, List<Reserver> reservations) throws ResourceAllocationException {
}
@ -284,13 +285,13 @@ public class MockResourceLimitManagerImpl extends ManagerBase implements Resourc
@Override
public void checkVolumeResourceLimitForDiskOfferingChange(Account owner, Boolean display, Long currentSize, Long newSize,
DiskOffering currentOffering, DiskOffering newOffering) throws ResourceAllocationException {
DiskOffering currentOffering, DiskOffering newOffering, List<Reserver> reservations) throws ResourceAllocationException {
}
@Override
public void checkPrimaryStorageResourceLimit(Account owner, Boolean display, Long size,
DiskOffering diskOffering) {
DiskOffering diskOffering, List<Reserver> reservations) {
}
@ -334,7 +335,7 @@ public class MockResourceLimitManagerImpl extends ManagerBase implements Resourc
}
@Override
public void checkVmResourceLimit(Account owner, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template) throws ResourceAllocationException {
public void checkVmResourceLimit(Account owner, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Reserver> reservations) throws ResourceAllocationException {
}
@ -351,19 +352,14 @@ public class MockResourceLimitManagerImpl extends ManagerBase implements Resourc
@Override
public void checkVmResourceLimitsForServiceOfferingChange(Account owner, Boolean display, Long currentCpu, Long newCpu,
Long currentMemory, Long newMemory, ServiceOffering currentOffering, ServiceOffering newOffering,
VirtualMachineTemplate template) throws ResourceAllocationException {
VirtualMachineTemplate template, List<Reserver> reservations) throws ResourceAllocationException {
}
@Override
public void checkVmResourceLimitsForTemplateChange(Account owner, Boolean display, ServiceOffering offering,
VirtualMachineTemplate currentTemplate,
VirtualMachineTemplate newTemplate) throws ResourceAllocationException {
}
@Override
public void checkVmCpuResourceLimit(Account owner, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long cpu) throws ResourceAllocationException {
VirtualMachineTemplate newTemplate, List<Reserver> reservations) throws ResourceAllocationException {
}
@ -377,11 +373,6 @@ public class MockResourceLimitManagerImpl extends ManagerBase implements Resourc
}
@Override
public void checkVmMemoryResourceLimit(Account owner, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long memory) throws ResourceAllocationException {
}
@Override
public void incrementVmMemoryResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long memory) {

View File

@ -268,9 +268,6 @@ public class VolumeImportUnmanageManagerImplTest {
doNothing().when(volumeImportUnmanageManager).checkIfVolumeIsEncrypted(volumeOnStorageTO);
doNothing().when(volumeImportUnmanageManager).checkIfVolumeHasBackingFile(volumeOnStorageTO);
doNothing().when(resourceLimitService).checkResourceLimit(account, Resource.ResourceType.volume);
doNothing().when(resourceLimitService).checkResourceLimit(account, Resource.ResourceType.primary_storage, virtualSize);
DiskOfferingVO diskOffering = mock(DiskOfferingVO.class);
when(diskOffering.isCustomized()).thenReturn(true);
doReturn(diskOffering).when(volumeImportUnmanageManager).getOrCreateDiskOffering(account, diskOfferingId, zoneId, isLocal);

View File

@ -38,6 +38,7 @@ import java.util.Map;
import java.util.UUID;
import com.cloud.offering.DiskOffering;
import com.cloud.resourcelimit.CheckedReservation;
import org.apache.cloudstack.api.ResponseGenerator;
import org.apache.cloudstack.api.ResponseObject;
import org.apache.cloudstack.api.ServerApiException;
@ -67,6 +68,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.MockitoAnnotations;
@ -89,7 +91,6 @@ import com.cloud.agent.api.GetUnmanagedInstancesCommand;
import com.cloud.agent.api.ImportConvertedInstanceAnswer;
import com.cloud.agent.api.ImportConvertedInstanceCommand;
import com.cloud.agent.api.to.DataStoreTO;
import com.cloud.configuration.Resource;
import com.cloud.dc.ClusterVO;
import com.cloud.dc.DataCenter;
import com.cloud.dc.DataCenterVO;
@ -106,7 +107,6 @@ import com.cloud.exception.InsufficientServerCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.OperationTimedoutException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.UnsupportedServiceException;
import com.cloud.host.Host;
import com.cloud.host.HostVO;
@ -282,7 +282,6 @@ public class UnmanagedVMsManagerImplTest {
clusterVO.setHypervisorType(Hypervisor.HypervisorType.VMware.toString());
when(clusterDao.findById(anyLong())).thenReturn(clusterVO);
when(configurationDao.getValue(Mockito.anyString())).thenReturn(null);
doNothing().when(resourceLimitService).checkResourceLimit(any(Account.class), any(Resource.ResourceType.class), anyLong());
List<HostVO> hosts = new ArrayList<>();
HostVO hostVO = Mockito.mock(HostVO.class);
when(hostVO.isInMaintenanceStates()).thenReturn(false);
@ -422,7 +421,8 @@ public class UnmanagedVMsManagerImplTest {
when(importUnmanageInstanceCmd.getName()).thenReturn("TestInstance");
when(importUnmanageInstanceCmd.getDomainId()).thenReturn(null);
when(volumeApiService.doesStoragePoolSupportDiskOffering(any(StoragePool.class), any())).thenReturn(true);
try (MockedStatic<UsageEventUtils> ignored = Mockito.mockStatic(UsageEventUtils.class)) {
try (MockedStatic<UsageEventUtils> ignored = Mockito.mockStatic(UsageEventUtils.class);
MockedConstruction<CheckedReservation> mockCheckedReservation = Mockito.mockConstruction(CheckedReservation.class)) {
unmanagedVMsManager.importUnmanagedInstance(importUnmanageInstanceCmd);
}
}
@ -520,7 +520,8 @@ public class UnmanagedVMsManagerImplTest {
CopyRemoteVolumeAnswer copyAnswer = Mockito.mock(CopyRemoteVolumeAnswer.class);
when(copyAnswer.getResult()).thenReturn(true);
when(agentManager.easySend(anyLong(), any(CopyRemoteVolumeCommand.class))).thenReturn(copyAnswer);
try (MockedStatic<UsageEventUtils> ignored = Mockito.mockStatic(UsageEventUtils.class)) {
try (MockedStatic<UsageEventUtils> ignored = Mockito.mockStatic(UsageEventUtils.class);
MockedConstruction<CheckedReservation> mockCheckedReservation = Mockito.mockConstruction(CheckedReservation.class)) {
unmanagedVMsManager.importVm(cmd);
}
}
@ -707,7 +708,8 @@ public class UnmanagedVMsManagerImplTest {
Mockito.lenient().when(agentManager.send(Mockito.eq(convertHostId), Mockito.any(ImportConvertedInstanceCommand.class))).thenReturn(convertImportedInstanceAnswer);
}
try (MockedStatic<UsageEventUtils> ignored = Mockito.mockStatic(UsageEventUtils.class)) {
try (MockedStatic<UsageEventUtils> ignored = Mockito.mockStatic(UsageEventUtils.class);
MockedConstruction<CheckedReservation> mockCheckedReservation = Mockito.mockConstruction(CheckedReservation.class)) {
unmanagedVMsManager.importVm(importVmCmd);
verify(vmwareGuru).getHypervisorVMOutOfBandAndCloneIfRequired(Mockito.eq(host), Mockito.eq(vmName), anyMap());
verify(vmwareGuru).createVMTemplateOutOfBand(Mockito.eq(host), Mockito.eq(vmName), anyMap(), any(DataStoreTO.class), anyInt());
@ -760,7 +762,8 @@ public class UnmanagedVMsManagerImplTest {
when(volumeApiService.doesStoragePoolSupportDiskOffering(any(StoragePool.class), any())).thenReturn(true);
StoragePoolHostVO storagePoolHost = Mockito.mock(StoragePoolHostVO.class);
when(storagePoolHostDao.findByPoolHost(anyLong(), anyLong())).thenReturn(storagePoolHost);
try (MockedStatic<UsageEventUtils> ignored = Mockito.mockStatic(UsageEventUtils.class)) {
try (MockedStatic<UsageEventUtils> ignored = Mockito.mockStatic(UsageEventUtils.class);
MockedConstruction<CheckedReservation> mockCheckedReservation = Mockito.mockConstruction(CheckedReservation.class)) {
unmanagedVMsManager.importVm(cmd);
}
}
@ -1107,40 +1110,4 @@ public class UnmanagedVMsManagerImplTest {
unmanagedVMsManager.selectKVMHostForConversionInCluster(cluster, hostId);
}
@Test
public void testCheckUnmanagedDiskLimits() {
Account owner = Mockito.mock(Account.class);
UnmanagedInstanceTO.Disk disk = Mockito.mock(UnmanagedInstanceTO.Disk.class);
Mockito.when(disk.getDiskId()).thenReturn("disk1");
Mockito.when(disk.getCapacity()).thenReturn(100L);
ServiceOffering serviceOffering = Mockito.mock(ServiceOffering.class);
Mockito.when(serviceOffering.getDiskOfferingId()).thenReturn(1L);
UnmanagedInstanceTO.Disk dataDisk = Mockito.mock(UnmanagedInstanceTO.Disk.class);
Mockito.when(dataDisk.getDiskId()).thenReturn("disk2");
Mockito.when(dataDisk.getCapacity()).thenReturn(1000L);
Map<String, Long> dataDiskMap = new HashMap<>();
dataDiskMap.put("disk2", 2L);
DiskOfferingVO offering1 = Mockito.mock(DiskOfferingVO.class);
Mockito.when(diskOfferingDao.findById(1L)).thenReturn(offering1);
String tag1 = "tag1";
Mockito.when(resourceLimitService.getResourceLimitStorageTags(offering1)).thenReturn(List.of(tag1));
DiskOfferingVO offering2 = Mockito.mock(DiskOfferingVO.class);
Mockito.when(diskOfferingDao.findById(2L)).thenReturn(offering2);
String tag2 = "tag2";
Mockito.when(resourceLimitService.getResourceLimitStorageTags(offering2)).thenReturn(List.of(tag2));
try {
Mockito.doNothing().when(resourceLimitService).checkResourceLimit(any(), any(), any());
Mockito.doNothing().when(resourceLimitService).checkResourceLimitWithTag(any(), any(), any(), any());
unmanagedVMsManager.checkUnmanagedDiskLimits(owner, disk, serviceOffering, List.of(dataDisk), dataDiskMap);
Mockito.verify(resourceLimitService, Mockito.times(1)).checkResourceLimit(owner, Resource.ResourceType.volume, 2);
Mockito.verify(resourceLimitService, Mockito.times(1)).checkResourceLimit(owner, Resource.ResourceType.primary_storage, 1100L);
Mockito.verify(resourceLimitService, Mockito.times(1)).checkResourceLimitWithTag(owner, Resource.ResourceType.volume, tag1,1);
Mockito.verify(resourceLimitService, Mockito.times(1)).checkResourceLimitWithTag(owner, Resource.ResourceType.volume, tag2,1);
Mockito.verify(resourceLimitService, Mockito.times(1)).checkResourceLimitWithTag(owner, Resource.ResourceType.primary_storage, tag1,100L);
Mockito.verify(resourceLimitService, Mockito.times(1)).checkResourceLimitWithTag(owner, Resource.ResourceType.primary_storage, tag2,1000L);
} catch (ResourceAllocationException e) {
Assert.fail("Exception encountered: " + e.getMessage());
}
}
}