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

This commit is contained in:
Fabricio Duarte 2026-03-06 18:47:37 +05:30 committed by Daan Hoogland
parent f7f0e75122
commit 9c0c8da706
28 changed files with 859 additions and 751 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 {
@ -252,12 +253,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);
@ -274,20 +275,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

@ -5222,9 +5222,20 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
private void saveCustomOfferingDetails(long vmId, ServiceOffering serviceOffering) {
Map<String, String> details = vmInstanceDetailsDao.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<VMInstanceDetailVO> detailList = new ArrayList<>();
for (Map.Entry<String, String> entry: details.entrySet()) {
VMInstanceDetailVO detailVO = new VMInstanceDetailVO(vmId, entry.getKey(), entry.getValue(), true);

View File

@ -3123,9 +3123,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

@ -40,6 +40,7 @@ import javax.naming.ConfigurationException;
import com.cloud.deploy.DeploymentClusterPlanner;
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;
@ -82,6 +83,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;
@ -1942,14 +1944,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 {
@ -1957,9 +1965,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

@ -53,6 +53,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;
@ -175,6 +176,8 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
@Inject
private ReservationDao reservationDao;
@Inject
private ResourceLimitService resourceLimitService;
@Inject
protected SnapshotDao _snapshotDao;
@Inject
protected BackupDao backupDao;
@ -1744,54 +1747,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
@ -2018,20 +2020,27 @@ 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;
CheckedReservation memReservation = new CheckedReservation(owner, ResourceType.memory, tags, ram, reservationDao, resourceLimitService);
reservations.add(memReservation);
Long gpu = serviceOffering.getGpuCount() != null ? Long.valueOf(serviceOffering.getGpuCount()) : 0L;
for (String tag : tags) {
checkResourceLimitWithTag(owner, ResourceType.user_vm, tag);
checkResourceLimitWithTag(owner, ResourceType.cpu, tag, cpu);
checkResourceLimitWithTag(owner, ResourceType.memory, tag, ram);
checkResourceLimitWithTag(owner, ResourceType.gpu, tag, gpu);
}
CheckedReservation gpuReservation = new CheckedReservation(owner, ResourceType.gpu, tags, gpu, reservationDao, resourceLimitService);
reservations.add(gpuReservation);
}
@Override
@ -2081,83 +2090,60 @@ 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;
}
CheckedReservation memReservation = new CheckedReservation(owner, ResourceType.memory, null, tagsAfterUpdate,
currentTags, newMemory, currentMemory, reservationDao, resourceLimitService);
reservations.add(memReservation);
Long currentGpu = currentOffering.getGpuCount() != null ? Long.valueOf(currentOffering.getGpuCount()) : 0L;
Long newGpu = newOffering.getGpuCount() != null ? Long.valueOf(newOffering.getGpuCount()) : 0L;
Set<String> sameTags = updatedResourceLimitHostTags.first();
Set<String> newTags = updatedResourceLimitHostTags.second();
if (newCpu - currentCpu > 0 || newMemory - currentMemory > 0 || newGpu - currentGpu > 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);
}
if (newGpu - currentGpu > 0) {
checkResourceLimitWithTag(owner, ResourceType.gpu, tag, newGpu - currentGpu);
}
}
}
for (String tag : newTags) {
checkResourceLimitWithTag(owner, ResourceType.user_vm, tag, 1L);
checkResourceLimitWithTag(owner, ResourceType.cpu, tag, newCpu);
checkResourceLimitWithTag(owner, ResourceType.memory, tag, newMemory);
checkResourceLimitWithTag(owner, ResourceType.gpu, tag, newGpu);
}
}
@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 gpuReservation = new CheckedReservation(owner, ResourceType.gpu, null, tagsAfterUpdate,
currentTags, newGpu, currentGpu, reservationDao, resourceLimitService);
reservations.add(gpuReservation);
}
@Override
@ -2188,20 +2174,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

@ -35,6 +35,7 @@ import java.util.stream.Collectors;
import javax.inject.Inject;
import com.cloud.resourcelimit.ReservationHelper;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.InternalIdentity;
@ -94,6 +95,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;
@ -445,9 +447,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());
@ -487,7 +497,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
@ -557,9 +569,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);
@ -570,7 +586,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);
@ -948,8 +964,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);
@ -972,9 +990,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
return commitVolume(cmd.getSnapshotId(), 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);
}
}
@ -1300,7 +1317,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
@ -1428,6 +1448,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);
}
}
protected void validateNoVmSnapshots(VolumeVO volume) {
@ -1884,12 +1908,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());
@ -1901,6 +1924,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);
@ -2130,7 +2159,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
@ -2220,6 +2251,10 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
}
return volume;
} finally {
ReservationHelper.closeAll(reservations);
}
}
private void updateStorageWithTheNewDiskOffering(VolumeVO volume, DiskOfferingVO newDiskOffering) {
@ -2425,7 +2460,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) {
@ -2489,7 +2524,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
@ -2668,7 +2703,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
checkForBackups(vm, true);
checkRightsToAttach(caller, volumeToAttach, vm);
_accountMgr.checkAccess(caller, null, true, volumeToAttach, vm);
StoragePoolVO volumeToAttachStoragePool = _storagePoolDao.findById(volumeToAttach.getPoolId());
if (logger.isTraceEnabled() && volumeToAttachStoragePool != null) {
@ -2692,6 +2727,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)) {
@ -2699,9 +2740,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;
@ -2750,21 +2803,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);
@ -4328,7 +4366,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
@ -4338,6 +4378,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

@ -2031,16 +2031,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

@ -86,6 +86,7 @@ import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.framework.messagebus.MessageBus;
import org.apache.cloudstack.framework.messagebus.PublishScope;
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
import org.apache.cloudstack.reservation.dao.ReservationDao;
import org.apache.cloudstack.secstorage.dao.SecondaryStorageHeuristicDao;
import org.apache.cloudstack.secstorage.heuristics.HeuristicType;
import org.apache.cloudstack.snapshot.SnapshotHelper;
@ -150,6 +151,7 @@ import com.cloud.hypervisor.HypervisorGuru;
import com.cloud.hypervisor.HypervisorGuruManager;
import com.cloud.projects.Project;
import com.cloud.projects.ProjectManager;
import com.cloud.resourcelimit.CheckedReservation;
import com.cloud.storage.DataStoreRole;
import com.cloud.storage.GuestOSVO;
import com.cloud.storage.ImageStoreUploadMonitorImpl;
@ -199,6 +201,7 @@ import com.cloud.utils.EncryptionUtil;
import com.cloud.utils.EnumUtils;
import com.cloud.utils.Pair;
import com.cloud.utils.StringUtils;
import com.cloud.utils.UriUtils;
import com.cloud.utils.component.AdapterBase;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.concurrency.NamedThreadFactory;
@ -301,6 +304,8 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
private VMTemplateDetailsDao _tmpltDetailsDao;
@Inject
private HypervisorGuruManager _hvGuruMgr;
@Inject
ReservationDao reservationDao;
private List<TemplateAdapter> _adapters;
@ -350,14 +355,30 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
@ActionEvent(eventType = EventTypes.EVENT_ISO_CREATE, eventDescription = "creating iso")
public VirtualMachineTemplate registerIso(RegisterIsoCmd cmd) throws ResourceAllocationException {
TemplateAdapter adapter = getAdapter(HypervisorType.None);
TemplateProfile profile = adapter.prepare(cmd);
VMTemplateVO template = adapter.create(profile);
Account owner = _accountMgr.getAccount(cmd.getEntityOwnerId());
if (template != null) {
CallContext.current().putContextParameter(VirtualMachineTemplate.class, template.getUuid());
return template;
} else {
throw new CloudRuntimeException("Failed to create ISO");
// 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;
try (CheckedReservation templateReservation = new CheckedReservation(owner, ResourceType.template, null, null, 1L, reservationDao, _resourceLimitMgr);
CheckedReservation secondaryStorageReservation = new CheckedReservation(owner, ResourceType.secondary_storage, null, null, secondaryStorageUsage, reservationDao, _resourceLimitMgr)) {
TemplateProfile profile = adapter.prepare(cmd);
VMTemplateVO template = adapter.create(profile);
// 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);
}
if (template != null) {
CallContext.current().putContextParameter(VirtualMachineTemplate.class, template.getUuid());
return template;
} else {
throw new CloudRuntimeException("Failed to create ISO");
}
}
}
@ -377,17 +398,32 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
}
TemplateAdapter adapter = getAdapter(HypervisorType.getType(cmd.getHypervisor()));
TemplateProfile profile = adapter.prepare(cmd);
VMTemplateVO template = adapter.create(profile);
Account owner = _accountMgr.getAccount(cmd.getEntityOwnerId());
if (template != null) {
CallContext.current().putContextParameter(VirtualMachineTemplate.class, template.getUuid());
if (cmd instanceof RegisterVnfTemplateCmd) {
vnfTemplateManager.persistVnfTemplate(template.getId(), (RegisterVnfTemplateCmd) cmd);
long secondaryStorageUsage = adapter instanceof HypervisorTemplateAdapter && !cmd.isDirectDownload() ?
UriUtils.getRemoteSize(cmd.getUrl(), StorageManager.DataStoreDownloadFollowRedirects.value()) : 0L;
try (CheckedReservation templateReservation = new CheckedReservation(owner, ResourceType.template, null, null, 1L, reservationDao, _resourceLimitMgr);
CheckedReservation secondaryStorageReservation = new CheckedReservation(owner, ResourceType.secondary_storage, null, null, secondaryStorageUsage, reservationDao, _resourceLimitMgr)) {
TemplateProfile profile = adapter.prepare(cmd);
VMTemplateVO template = adapter.create(profile);
// Secondary storage resource usage will be incremented in com.cloud.template.HypervisorTemplateAdapter.createTemplateAsyncCallBack
// for HypervisorTemplateAdapter
_resourceLimitMgr.incrementResourceCount(profile.getAccountId(), ResourceType.template);
if (secondaryStorageUsage > 0) {
_resourceLimitMgr.incrementResourceCount(profile.getAccountId(), ResourceType.secondary_storage, secondaryStorageUsage);
}
if (template != null) {
CallContext.current().putContextParameter(VirtualMachineTemplate.class, template.getUuid());
if (cmd instanceof RegisterVnfTemplateCmd) {
vnfTemplateManager.persistVnfTemplate(template.getId(), (RegisterVnfTemplateCmd) cmd);
}
return template;
} else {
throw new CloudRuntimeException("Failed to create a template");
}
return template;
} else {
throw new CloudRuntimeException("Failed to create a template");
}
}

View File

@ -60,6 +60,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;
@ -136,6 +137,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;
@ -1391,9 +1393,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
@ -1416,6 +1421,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
return _vmDao.findById(vmInstance.getId());
} finally {
ReservationHelper.closeAll(reservations);
}
}
/**
@ -2109,9 +2117,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;
@ -2183,6 +2193,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
}
}
return success;
} finally {
ReservationHelper.closeAll(reservations);
}
}
protected void validateDiskOfferingChecks(ServiceOfferingVO currentServiceOffering, ServiceOfferingVO newServiceOffering) {
@ -2368,10 +2382,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());
@ -2396,6 +2412,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);
}
}
});
@ -2812,53 +2832,25 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
long currentCpu = currentServiceOffering.getCpu();
long currentMemory = currentServiceOffering.getRamSize();
VMTemplateVO template = _templateDao.findByIdIncludingRemoved(vmInstance.getTemplateId());
Long currentGpu = currentServiceOffering.getGpuCount() != null ? Long.valueOf(currentServiceOffering.getGpuCount()) : 0L;
Long newGpu = svcOffering.getGpuCount() != null ? Long.valueOf(svcOffering.getGpuCount()) : 0L;
List<Reserver> reservations = new ArrayList<>();
try {
checkVmLimits(owner, vmInstance, svcOffering, template, newCpu, currentCpu, newMemory, currentMemory, newGpu, currentGpu);
_resourceLimitMgr.checkVmResourceLimitsForServiceOfferingChange(owner, vmInstance.isDisplay(), currentCpu, newCpu,
currentMemory, newMemory, currentServiceOffering, svcOffering, template, reservations);
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);
}
} catch (ResourceAllocationException e) {
logger.error(String.format("Failed to updated VM due to: %s", e.getLocalizedMessage()));
throw new InvalidParameterValueException(e.getLocalizedMessage());
}
adjustVmLimits(owner, vmInstance, svcOffering, template, newCpu, currentCpu, newMemory, currentMemory, newGpu, currentGpu);
}
private void checkVmLimits(Account owner, UserVmVO vmInstance, ServiceOfferingVO svcOffering,
VMTemplateVO template, Long newCpu, Long currentCpu, Long newMemory, Long currentMemory,
Long newGpu, Long currentGpu
) throws ResourceAllocationException {
if (newCpu > currentCpu) {
_resourceLimitMgr.checkVmCpuResourceLimit(owner, vmInstance.isDisplay(), svcOffering,
template, newCpu - currentCpu);
}
if (newMemory > currentMemory) {
_resourceLimitMgr.checkVmMemoryResourceLimit(owner, vmInstance.isDisplay(), svcOffering,
template, newMemory - currentMemory);
}
if (newGpu > currentGpu) {
_resourceLimitMgr.checkVmGpuResourceLimit(owner, vmInstance.isDisplay(), svcOffering,
template, newGpu - currentGpu);
}
}
private void adjustVmLimits(Account owner, UserVmVO vmInstance, ServiceOfferingVO svcOffering,
VMTemplateVO template, Long newCpu, Long currentCpu, Long newMemory, Long currentMemory,
Long newGpu, Long currentGpu
) {
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);
}
if (newGpu > currentGpu) {
_resourceLimitMgr.incrementVmGpuResourceCount(owner.getAccountId(), vmInstance.isDisplay(), svcOffering, template, newGpu - currentGpu);
} else if (newGpu > 0 && currentGpu > newGpu){
_resourceLimitMgr.decrementVmGpuResourceCount(owner.getAccountId(), vmInstance.isDisplay(), svcOffering, template, currentGpu - newGpu);
} finally {
ReservationHelper.closeAll(reservations);
}
}
@ -4345,7 +4337,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);
}
}
@ -5844,11 +5835,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);
@ -7823,38 +7809,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);
}
}
@ -7896,14 +7873,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() {
@ -7920,6 +7899,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;
}
@ -7990,18 +7973,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() {
@ -8894,12 +8877,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 {
@ -9044,6 +9025,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) {
@ -9143,7 +9130,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());
@ -9161,7 +9148,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) {
@ -9172,7 +9159,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

@ -808,25 +808,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<VMInstanceDetailVO> userVmDetails = _vmInstanceDetailsDao.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 (VMInstanceDetailVO detail : userVmDetails) {
for (VMSnapshotDetailsVO detail : vmSnapshotDetails) {
details.put(detail.getName(), detail.getValue());
}
return details;
@ -838,7 +844,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("VM Snapshot reverting failed due to vm service offering couldn't be changed to the one used when snapshot was taken");
@ -935,8 +941,8 @@ public class VMSnapshotManagerImpl extends MutualExclusiveIdsManagerBase impleme
Transaction.execute(new TransactionCallbackWithExceptionNoReturn<CloudRuntimeException>() {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) throws CloudRuntimeException {
revertUserVmDetailsFromVmSnapshot(userVm, vmSnapshotVo);
updateUserVmServiceOffering(userVm, vmSnapshotVo);
revertUserVmDetailsFromVmSnapshot(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;
@ -166,6 +168,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;
@ -254,6 +258,8 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
@Inject
private ResourceLimitService resourceLimitService;
@Inject
private ReservationDao reservationDao;
@Inject
private VMInstanceDetailsDao vmInstanceDetailsDao;
@Inject
private UserVmManager userVmManager;
@ -639,7 +645,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));
@ -647,7 +653,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()));
}
@ -662,9 +667,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) {
@ -681,7 +687,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);
}
}
@ -1108,40 +1114,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,
@ -1199,99 +1171,103 @@ 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);
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);
checkUnmanagedDiskAndOfferingForImport(unmanagedInstance.getName(), dataDisks, dataDiskOfferingMap, owner, zone, cluster, migrateAllowed, reservations);
allDetails.put(VmDetailConstants.DATA_DISK_CONTROLLER, dataDisks.get(0).getController());
}
checkUnmanagedDiskLimits(owner, rootDisk, serviceOffering, dataDisks, dataDiskOfferingMap);
} catch (ResourceAllocationException e) {
// 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());
if (!CollectionUtils.isEmpty(unmanagedInstance.getNics())) {
allDetails.put(VmDetailConstants.NIC_ADAPTER, unmanagedInstance.getNics().get(0).getAdapterType());
}
if (StringUtils.isNotEmpty(unmanagedInstance.getVncPassword())) {
allDetails.put(VmDetailConstants.KVM_VNC_PASSWORD, unmanagedInstance.getVncPassword());
}
addImportingVMBootTypeAndModeDetails(unmanagedInstance.getBootType(), unmanagedInstance.getBootMode(), allDetails);
VirtualMachine.PowerState powerState = VirtualMachine.PowerState.PowerOff;
if (unmanagedInstance.getPowerState().equals(UnmanagedInstanceTO.PowerState.PowerOn)) {
powerState = VirtualMachine.PowerState.PowerOn;
}
try {
userVm = userVmManager.importVM(zone, host, template, internalCSName, displayName, owner,
null, caller, true, null, owner.getAccountId(), userId,
validatedServiceOffering, null, hostName,
cluster.getHypervisorType(), allDetails, powerState, null);
} catch (InsufficientCapacityException ice) {
String errorMsg = String.format("Failed to import VM [%s] due to [%s].", displayName, ice.getMessage());
logger.error(errorMsg, ice);
throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, errorMsg);
}
if (userVm == null) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to import vm name: %s", displayName));
}
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()));
}
Long minIops = null;
if (details.containsKey(MIN_IOPS)) {
minIops = Long.parseLong(details.get(MIN_IOPS));
}
Long maxIops = null;
if (details.containsKey(MAX_IOPS)) {
maxIops = Long.parseLong(details.get(MAX_IOPS));
}
DiskOfferingVO diskOffering = diskOfferingDao.findById(serviceOffering.getDiskOfferingId());
diskProfileStoragePoolList.add(importDisk(rootDisk, userVm, cluster, diskOffering, Volume.Type.ROOT, String.format("ROOT-%d", userVm.getId()),
rootDisk.getCapacity(), minIops, maxIops, template, owner, null));
long deviceId = 1L;
for (UnmanagedInstanceTO.Disk disk : dataDisks) {
if (disk.getCapacity() == null || disk.getCapacity() == 0) {
throw new InvalidParameterValueException(String.format("Disk ID: %s size is invalid", rootDisk.getDiskId()));
}
DiskOffering offering = diskOfferingDao.findById(dataDiskOfferingMap.get(disk.getDiskId()));
diskProfileStoragePoolList.add(importDisk(disk, userVm, cluster, offering, Volume.Type.DATADISK, String.format("DATA-%d-%s", userVm.getId(), disk.getDiskId()),
disk.getCapacity(), offering.getMinIops(), offering.getMaxIops(),
template, owner, deviceId));
deviceId++;
}
} catch (Exception e) {
logger.error(String.format("Failed to import volumes while importing vm: %s", displayName), e);
cleanupFailedImportVM(userVm);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to import volumes while importing vm: %s. %s", displayName, StringUtils.defaultString(e.getMessage())));
}
try {
int nicIndex = 0;
for (UnmanagedInstanceTO.Nic nic : unmanagedInstance.getNics()) {
Network network = networkDao.findById(allNicNetworkMap.get(nic.getNicId()));
Network.IpAddresses ipAddresses = nicIpAddressMap.get(nic.getNicId());
importNic(nic, userVm, network, ipAddresses, nicIndex, nicIndex == 0, forced);
nicIndex++;
}
} catch (Exception e) {
logger.error(String.format("Failed to import NICs while importing vm: %s", displayName), e);
cleanupFailedImportVM(userVm);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to import NICs while importing vm: %s. %s", displayName, StringUtils.defaultString(e.getMessage())));
}
if (migrateAllowed) {
userVm = migrateImportedVM(host, template, validatedServiceOffering, userVm, owner, diskProfileStoragePoolList);
}
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);
}
// 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());
if (!CollectionUtils.isEmpty(unmanagedInstance.getNics())) {
allDetails.put(VmDetailConstants.NIC_ADAPTER, unmanagedInstance.getNics().get(0).getAdapterType());
}
if (StringUtils.isNotEmpty(unmanagedInstance.getVncPassword())) {
allDetails.put(VmDetailConstants.KVM_VNC_PASSWORD, unmanagedInstance.getVncPassword());
}
addImportingVMBootTypeAndModeDetails(unmanagedInstance.getBootType(), unmanagedInstance.getBootMode(), allDetails);
VirtualMachine.PowerState powerState = VirtualMachine.PowerState.PowerOff;
if (unmanagedInstance.getPowerState().equals(UnmanagedInstanceTO.PowerState.PowerOn)) {
powerState = VirtualMachine.PowerState.PowerOn;
}
try {
userVm = userVmManager.importVM(zone, host, template, internalCSName, displayName, owner,
null, caller, true, null, owner.getAccountId(), userId,
validatedServiceOffering, null, hostName,
cluster.getHypervisorType(), allDetails, powerState, null);
} catch (InsufficientCapacityException ice) {
String errorMsg = String.format("Failed to import VM [%s] due to [%s].", displayName, ice.getMessage());
logger.error(errorMsg, ice);
throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, errorMsg);
}
if (userVm == null) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to import vm name: %s", displayName));
}
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()));
}
Long minIops = null;
if (details.containsKey(MIN_IOPS)) {
minIops = Long.parseLong(details.get(MIN_IOPS));
}
Long maxIops = null;
if (details.containsKey(MAX_IOPS)) {
maxIops = Long.parseLong(details.get(MAX_IOPS));
}
DiskOfferingVO diskOffering = diskOfferingDao.findById(serviceOffering.getDiskOfferingId());
diskProfileStoragePoolList.add(importDisk(rootDisk, userVm, cluster, diskOffering, Volume.Type.ROOT, String.format("ROOT-%d", userVm.getId()),
rootDisk.getCapacity(), minIops, maxIops, template, owner, null));
long deviceId = 1L;
for (UnmanagedInstanceTO.Disk disk : dataDisks) {
if (disk.getCapacity() == null || disk.getCapacity() == 0) {
throw new InvalidParameterValueException(String.format("Disk ID: %s size is invalid", rootDisk.getDiskId()));
}
DiskOffering offering = diskOfferingDao.findById(dataDiskOfferingMap.get(disk.getDiskId()));
diskProfileStoragePoolList.add(importDisk(disk, userVm, cluster, offering, Volume.Type.DATADISK, String.format("DATA-%d-%s", userVm.getId(), disk.getDiskId()),
disk.getCapacity(), offering.getMinIops(), offering.getMaxIops(),
template, owner, deviceId));
deviceId++;
}
} catch (Exception e) {
logger.error(String.format("Failed to import volumes while importing vm: %s", displayName), e);
cleanupFailedImportVM(userVm);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to import volumes while importing vm: %s. %s", displayName, StringUtils.defaultString(e.getMessage())));
}
try {
int nicIndex = 0;
for (UnmanagedInstanceTO.Nic nic : unmanagedInstance.getNics()) {
Network network = networkDao.findById(allNicNetworkMap.get(nic.getNicId()));
Network.IpAddresses ipAddresses = nicIpAddressMap.get(nic.getNicId());
importNic(nic, userVm, network, ipAddresses, nicIndex, nicIndex == 0, forced);
nicIndex++;
}
} catch (Exception e) {
logger.error(String.format("Failed to import NICs while importing vm: %s", displayName), e);
cleanupFailedImportVM(userVm);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to import NICs while importing vm: %s. %s", displayName, StringUtils.defaultString(e.getMessage())));
}
if (migrateAllowed) {
userVm = migrateImportedVM(host, template, validatedServiceOffering, userVm, owner, diskProfileStoragePoolList);
}
publishVMUsageUpdateResourceCount(userVm, validatedServiceOffering, template);
return userVm;
}
private void addImportingVMBootTypeAndModeDetails(String bootType, String bootMode, Map<String, String> allDetails) {
@ -1396,8 +1372,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);
@ -1413,31 +1387,41 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
List<String> managedVms = new ArrayList<>(additionalNameFilters);
managedVms.addAll(getHostsManagedVms(hosts));
ActionEventUtils.onStartedActionEvent(userId, owner.getId(), EventTypes.EVENT_VM_IMPORT,
cmd.getEventDescription(), null, null, true, 0);
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 (cmd instanceof ImportVmCmd) {
ImportVmCmd importVmCmd = (ImportVmCmd) cmd;
if (StringUtils.isBlank(importVmCmd.getImportSource())) {
throw new CloudRuntimeException("Please provide an import source for importing the VM");
}
String source = importVmCmd.getImportSource().toUpperCase();
ImportSource importSource = Enum.valueOf(ImportSource.class, source);
if (ImportSource.VMWARE == importSource) {
userVm = importUnmanagedInstanceFromVmwareToKvm(zone, cluster,
template, instanceName, displayName, hostName, caller, owner, userId,
serviceOffering, dataDiskOfferingMap,
nicNetworkMap, nicIpAddressMap,
details, importVmCmd, forced);
}
} else {
if (List.of(Hypervisor.HypervisorType.VMware, Hypervisor.HypervisorType.KVM).contains(cluster.getHypervisorType())) {
userVm = importUnmanagedInstanceFromHypervisor(zone, cluster, hosts, additionalNameFilters,
template, instanceName, displayName, hostName, caller, owner, userId,
serviceOffering, dataDiskOfferingMap,
nicNetworkMap, nicIpAddressMap,
details, cmd.getMigrateAllowed(), managedVms, forced);
ActionEventUtils.onStartedActionEvent(userId, owner.getId(), EventTypes.EVENT_VM_IMPORT,
cmd.getEventDescription(), null, null, true, 0);
if (cmd instanceof ImportVmCmd) {
ImportVmCmd importVmCmd = (ImportVmCmd) cmd;
if (StringUtils.isBlank(importVmCmd.getImportSource())) {
throw new CloudRuntimeException("Please provide an import source for importing the VM");
}
String source = importVmCmd.getImportSource().toUpperCase();
ImportSource importSource = Enum.valueOf(ImportSource.class, source);
if (ImportSource.VMWARE == importSource) {
userVm = importUnmanagedInstanceFromVmwareToKvm(zone, cluster,
template, instanceName, displayName, hostName, caller, owner, userId,
serviceOffering, dataDiskOfferingMap,
nicNetworkMap, nicIpAddressMap,
details, importVmCmd, forced);
}
} else {
if (List.of(Hypervisor.HypervisorType.VMware, Hypervisor.HypervisorType.KVM).contains(cluster.getHypervisorType())) {
userVm = importUnmanagedInstanceFromHypervisor(zone, cluster, hosts, additionalNameFilters,
template, instanceName, displayName, hostName, caller, owner, userId,
serviceOffering, dataDiskOfferingMap,
nicNetworkMap, nicIpAddressMap,
details, cmd.getMigrateAllowed(), managedVms, forced);
}
}
} 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) {
@ -1526,15 +1510,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");
@ -2520,12 +2495,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;
@ -2613,26 +2582,37 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
UserVm userVm = null;
if (ImportSource.EXTERNAL == importSource) {
String username = cmd.getUsername();
String password = cmd.getPassword();
String tmpPath = cmd.getTmpPath();
userVm = importExternalKvmVirtualMachine(unmanagedInstanceTO, instanceName, zone,
template, displayName, hostName, caller, owner, userId,
serviceOffering, dataDiskOfferingMap,
nicNetworkMap, nicIpAddressMap, remoteUrl, username, password, tmpPath, details);
} else if (ImportSource.SHARED == importSource || ImportSource.LOCAL == importSource) {
try {
userVm = importKvmVirtualMachineFromDisk(importSource, instanceName, zone,
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();
String tmpPath = cmd.getTmpPath();
userVm = importExternalKvmVirtualMachine(unmanagedInstanceTO, instanceName, zone,
template, displayName, hostName, caller, owner, userId,
serviceOffering, dataDiskOfferingMap, networkId, hostId, poolId, diskPath,
details);
} catch (InsufficientCapacityException e) {
throw new RuntimeException(e);
} catch (ResourceAllocationException e) {
throw new RuntimeException(e);
serviceOffering, dataDiskOfferingMap,
nicNetworkMap, nicIpAddressMap, remoteUrl, username, password, tmpPath, details);
} else if (ImportSource.SHARED == importSource || ImportSource.LOCAL == importSource) {
try {
userVm = importKvmVirtualMachineFromDisk(importSource, instanceName, zone,
template, displayName, hostName, caller, owner, userId,
serviceOffering, dataDiskOfferingMap, networkId, hostId, poolId, diskPath,
details);
} catch (InsufficientCapacityException e) {
throw new RuntimeException(e);
} catch (ResourceAllocationException e) {
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));
}
@ -2646,7 +2626,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);
@ -2657,6 +2637,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();
@ -2665,97 +2646,117 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
}
allDetails.put(VmDetailConstants.ROOT_DISK_CONTROLLER, rootDisk.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, Hypervisor.HypervisorType.KVM);
if (!CollectionUtils.isEmpty(unmanagedInstance.getNics())) {
allDetails.put(VmDetailConstants.NIC_ADAPTER, unmanagedInstance.getNics().get(0).getAdapterType());
}
VirtualMachine.PowerState powerState = VirtualMachine.PowerState.PowerOff;
List<Reserver> reservations = new ArrayList<>();
try {
userVm = userVmManager.importVM(zone, null, template, null, displayName, owner,
null, caller, true, null, owner.getAccountId(), userId,
serviceOffering, null, hostName,
Hypervisor.HypervisorType.KVM, allDetails, powerState, null);
} catch (InsufficientCapacityException ice) {
logger.error(String.format("Failed to import vm name: %s", instanceName), ice);
throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, ice.getMessage());
}
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);
checkVolumeResourceLimitsForExternalKvmVmImport(owner, rootDisk, dataDisks, diskOffering, dataDiskOfferingMap, reservations);
DiskProfile[] dataDiskProfiles = new DiskProfile[dataDisks.size()];
int diskSeq = 0;
// 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);
if (!CollectionUtils.isEmpty(unmanagedInstance.getNics())) {
allDetails.put(VmDetailConstants.NIC_ADAPTER, unmanagedInstance.getNics().get(0).getAdapterType());
}
VirtualMachine.PowerState powerState = VirtualMachine.PowerState.PowerOff;
try {
userVm = userVmManager.importVM(zone, null, template, null, displayName, owner,
null, caller, true, null, owner.getAccountId(), userId,
serviceOffering, null, hostName,
Hypervisor.HypervisorType.KVM, allDetails, powerState, null);
} catch (InsufficientCapacityException ice) {
logger.error(String.format("Failed to import vm name: %s", instanceName), ice);
throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, ice.getMessage());
}
if (userVm == null) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to import vm name: %s", instanceName));
}
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) {
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;
}
final VirtualMachineProfile profile = new VirtualMachineProfileImpl(userVm, template, serviceOffering, owner, null);
ServiceOfferingVO dummyOffering = serviceOfferingDao.findById(userVm.getId(), serviceOffering.getId());
profile.setServiceOffering(dummyOffering);
DeploymentPlanner.ExcludeList excludeList = new DeploymentPlanner.ExcludeList();
final DataCenterDeployment plan = new DataCenterDeployment(zone.getId(), null, null, null, null, null);
DeployDestination dest = null;
try {
dest = deploymentPlanningManager.planDeployment(profile, plan, excludeList, null);
} catch (Exception e) {
logger.warn("Import failed for Vm: {} while finding deployment destination", userVm, e);
cleanupFailedImportVM(userVm);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Import failed for Vm: %s while finding deployment destination", userVm.getInstanceName()));
}
if(dest == null) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Import failed for Vm: %s. Suitable deployment destination not found", userVm.getInstanceName()));
}
List<Pair<DiskProfile, StoragePool>> diskProfileStoragePoolList = new ArrayList<>();
try {
diskProfileStoragePoolList.add(importExternalDisk(rootDisk, userVm, dest, diskOffering, Volume.Type.ROOT,
template, null, remoteUrl, username, password, tmpPath, diskProfile));
long deviceId = 1L;
diskSeq = 0;
for (UnmanagedInstanceTO.Disk disk : dataDisks) {
DiskProfile dataDiskProfile = dataDiskProfiles[diskSeq++];
DiskOffering offering = diskOfferingDao.findById(dataDiskOfferingMap.get(disk.getDiskId()));
diskProfileStoragePoolList.add(importExternalDisk(disk, userVm, dest, offering, Volume.Type.DATADISK,
template, deviceId, remoteUrl, username, password, tmpPath, dataDiskProfile));
deviceId++;
}
} catch (Exception e) {
logger.error(String.format("Failed to import volumes while importing vm: %s", instanceName), e);
cleanupFailedImportVM(userVm);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to import volumes while importing vm: %s. %s", instanceName, StringUtils.defaultString(e.getMessage())));
}
try {
int nicIndex = 0;
for (UnmanagedInstanceTO.Nic nic : unmanagedInstance.getNics()) {
Network network = networkDao.findById(allNicNetworkMap.get(nic.getNicId()));
Network.IpAddresses ipAddresses = nicIpAddressMap.get(nic.getNicId());
importNic(nic, userVm, network, ipAddresses, nicIndex, nicIndex==0, true);
nicIndex++;
}
} catch (Exception e) {
logger.error(String.format("Failed to import NICs while importing vm: %s", instanceName), e);
cleanupFailedImportVM(userVm);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to import NICs while importing vm: %s. %s", instanceName, StringUtils.defaultString(e.getMessage())));
}
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("Disk ID: %s size is invalid", disk.getDiskId()));
throw new InvalidParameterValueException(String.format("Data 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;
resourceLimitService.checkVolumeResourceLimit(owner, true, disk.getCapacity(), offering, reservations);
}
final VirtualMachineProfile profile = new VirtualMachineProfileImpl(userVm, template, serviceOffering, owner, null);
ServiceOfferingVO dummyOffering = serviceOfferingDao.findById(userVm.getId(), serviceOffering.getId());
profile.setServiceOffering(dummyOffering);
DeploymentPlanner.ExcludeList excludeList = new DeploymentPlanner.ExcludeList();
final DataCenterDeployment plan = new DataCenterDeployment(zone.getId(), null, null, null, null, null);
DeployDestination dest = null;
try {
dest = deploymentPlanningManager.planDeployment(profile, plan, excludeList, null);
} catch (Exception e) {
logger.warn("Import failed for Vm: {} while finding deployment destination", userVm, e);
cleanupFailedImportVM(userVm);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Import failed for Vm: %s while finding deployment destination", userVm.getInstanceName()));
}
if(dest == null) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Import failed for Vm: %s. Suitable deployment destination not found", userVm.getInstanceName()));
}
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));
long deviceId = 1L;
diskSeq = 0;
for (UnmanagedInstanceTO.Disk disk : dataDisks) {
DiskProfile dataDiskProfile = dataDiskProfiles[diskSeq++];
DiskOffering offering = diskOfferingDao.findById(dataDiskOfferingMap.get(disk.getDiskId()));
diskProfileStoragePoolList.add(importExternalDisk(disk, userVm, dest, offering, Volume.Type.DATADISK,
template, deviceId, remoteUrl, username, password, tmpPath, dataDiskProfile));
deviceId++;
}
} catch (Exception e) {
logger.error(String.format("Failed to import volumes while importing vm: %s", instanceName), e);
cleanupFailedImportVM(userVm);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to import volumes while importing vm: %s. %s", instanceName, StringUtils.defaultString(e.getMessage())));
}
try {
int nicIndex = 0;
for (UnmanagedInstanceTO.Nic nic : unmanagedInstance.getNics()) {
Network network = networkDao.findById(allNicNetworkMap.get(nic.getNicId()));
Network.IpAddresses ipAddresses = nicIpAddressMap.get(nic.getNicId());
importNic(nic, userVm, network, ipAddresses, nicIndex, nicIndex==0, true);
nicIndex++;
}
} catch (Exception e) {
logger.error(String.format("Failed to import NICs while importing vm: %s", instanceName), e);
cleanupFailedImportVM(userVm);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to import NICs while importing vm: %s. %s", instanceName, StringUtils.defaultString(e.getMessage())));
}
publishVMUsageUpdateResourceCount(userVm, dummyOffering, template);
return userVm;
}
private UserVm importKvmVirtualMachineFromDisk(final ImportSource importSource, final String instanceName, final DataCenter zone,
@ -2823,7 +2824,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);
@ -2868,6 +2878,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 {
@ -2887,6 +2905,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

@ -34,6 +34,7 @@ import org.apache.cloudstack.api.response.TaggedResourceLimitAndCountResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.reservation.dao.ReservationDao;
import org.apache.cloudstack.resourcelimit.Reserver;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
@ -45,6 +46,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.MockedStatic;
import org.mockito.Mockito;
import org.mockito.Spy;
@ -275,6 +277,7 @@ public class ResourceLimitManagerImplTest {
@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));
@ -282,54 +285,12 @@ public class ResourceLimitManagerImplTest {
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.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(4, mockCheckedReservation.constructed().size());
} catch (ResourceAllocationException e) {
Assert.fail("Exception encountered: " + e.getMessage());
}
@ -355,22 +316,15 @@ public class ResourceLimitManagerImplTest {
@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.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());
}
@ -989,13 +943,6 @@ public class ResourceLimitManagerImplTest {
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());
@ -1012,6 +959,7 @@ public class ResourceLimitManagerImplTest {
@Test
public void testCheckVolumeResourceCount() throws ResourceAllocationException {
List<Reserver> reservations = new ArrayList<>();
Account account = Mockito.mock(Account.class);
String tag = "tag";
long delta = 10L;
@ -1025,12 +973,11 @@ public class ResourceLimitManagerImplTest {
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;
@ -44,6 +43,7 @@ import java.util.concurrent.ExecutionException;
import com.cloud.event.EventTypes;
import com.cloud.event.UsageEventUtils;
import com.cloud.host.HostVO;
import com.cloud.resourcelimit.CheckedReservation;
import com.cloud.service.ServiceOfferingVO;
import com.cloud.service.dao.ServiceOfferingDao;
import com.cloud.vm.snapshot.VMSnapshot;
@ -91,6 +91,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;
@ -99,7 +100,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;
@ -551,7 +551,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
@ -570,7 +572,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
@ -655,9 +659,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);
@ -678,10 +680,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());
}
}
@ -2208,6 +2210,36 @@ public class VolumeApiServiceImplTest {
}
}
@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);
}
@Test
public void validateNoVmSnapshotsTestNoInstanceId() {
Mockito.doReturn(null).when(volumeVoMock).getInstanceId();

View File

@ -91,6 +91,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.framework.messagebus.MessageBus;
import org.apache.cloudstack.reservation.dao.ReservationDao;
import org.apache.cloudstack.secstorage.dao.SecondaryStorageHeuristicDao;
import org.apache.cloudstack.secstorage.heuristics.HeuristicType;
import org.apache.cloudstack.snapshot.SnapshotHelper;
@ -207,6 +208,8 @@ public class TemplateManagerImplTest {
VnfTemplateManager vnfTemplateManager;
@Inject
SnapshotJoinDao snapshotJoinDao;
@Inject
ReservationDao reservationDao;
@Inject
HeuristicRuleHelper heuristicRuleHelperMock;
@ -959,6 +962,11 @@ public class TemplateManagerImplTest {
return Mockito.mock(VnfTemplateManager.class);
}
@Bean
public ReservationDao reservationDao() {
return Mockito.mock(ReservationDao.class);
}
@Bean
public SnapshotHelper snapshotHelper() {
return Mockito.mock(SnapshotHelper.class);

View File

@ -59,6 +59,7 @@ import java.util.Map;
import java.util.TimeZone;
import java.util.UUID;
import com.cloud.resourcelimit.CheckedReservation;
import com.cloud.storage.dao.SnapshotPolicyDao;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.SecurityChecker;
@ -83,6 +84,7 @@ import org.apache.cloudstack.backup.dao.BackupDao;
import org.apache.cloudstack.backup.dao.BackupScheduleDao;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
import org.apache.cloudstack.resourcelimit.Reserver;
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.Scope;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
@ -100,6 +102,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.MockedStatic;
import org.mockito.Mockito;
import org.mockito.Spy;
@ -690,7 +693,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(), 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());
@ -1696,23 +1698,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, times(1))
.checkResourceLimit(account, Resource.ResourceType.volume, 4);
Mockito.verify(resourceLimitMgr, times(1))
.checkResourceLimit(account, Resource.ResourceType.primary_storage, size);
Mockito.verify(resourceLimitMgr, times(1))
.checkResourceLimitWithTag(account, Resource.ResourceType.volume, "tag1", 2);
Mockito.verify(resourceLimitMgr, times(1))
.checkResourceLimitWithTag(account, Resource.ResourceType.volume, "tag2", 3);
Mockito.verify(resourceLimitMgr, times(1))
.checkResourceLimitWithTag(account, Resource.ResourceType.primary_storage, "tag1",
vol1.getSize() + vol5.getSize());
Mockito.verify(resourceLimitMgr, 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());
}
@ -2003,26 +1993,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
@ -3067,7 +3057,7 @@ public class UserVmManagerImplTest {
configureDoNothingForMethodsThatWeDoNotWantToTest();
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

@ -352,13 +352,13 @@ public class VMSnapshotManagerTest {
_vmSnapshotMgr.updateUserVmServiceOffering(userVm, vmSnapshotVO);
verify(_vmSnapshotMgr).changeUserVmServiceOffering(userVm, vmSnapshotVO);
verify(_vmSnapshotMgr).getVmMapDetails(userVm);
verify(_vmSnapshotMgr).getVmMapDetails(vmSnapshotVO);
verify(_vmSnapshotMgr).upgradeUserVmServiceOffering(ArgumentMatchers.eq(userVm), ArgumentMatchers.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());
@ -370,7 +370,7 @@ public class VMSnapshotManagerTest {
public void testChangeUserVmServiceOffering() throws ConcurrentOperationException, ResourceUnavailableException, ManagementServerException, VirtualMachineMigrationException {
when(_userVmManager.upgradeVirtualMachine(ArgumentMatchers.eq(TEST_VM_ID), ArgumentMatchers.eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture())).thenReturn(true);
_vmSnapshotMgr.changeUserVmServiceOffering(userVm, vmSnapshotVO);
verify(_vmSnapshotMgr).getVmMapDetails(userVm);
verify(_vmSnapshotMgr).getVmMapDetails(vmSnapshotVO);
verify(_vmSnapshotMgr).upgradeUserVmServiceOffering(ArgumentMatchers.eq(userVm), ArgumentMatchers.eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture());
}
@ -378,7 +378,7 @@ public class VMSnapshotManagerTest {
public void testChangeUserVmServiceOfferingFailOnUpgradeVMServiceOffering() throws ConcurrentOperationException, ResourceUnavailableException, ManagementServerException, VirtualMachineMigrationException {
when(_userVmManager.upgradeVirtualMachine(ArgumentMatchers.eq(TEST_VM_ID), ArgumentMatchers.eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture())).thenReturn(false);
_vmSnapshotMgr.changeUserVmServiceOffering(userVm, vmSnapshotVO);
verify(_vmSnapshotMgr).getVmMapDetails(userVm);
verify(_vmSnapshotMgr).getVmMapDetails(vmSnapshotVO);
verify(_vmSnapshotMgr).upgradeUserVmServiceOffering(ArgumentMatchers.eq(userVm), ArgumentMatchers.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

@ -39,6 +39,7 @@ import java.util.Map;
import java.util.UUID;
import com.cloud.offering.DiskOffering;
import com.cloud.resourcelimit.CheckedReservation;
import com.cloud.vm.ImportVMTaskVO;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ResponseGenerator;
@ -58,6 +59,7 @@ 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.storage.datastore.db.ImageStoreDao;
import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
@ -71,6 +73,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;
@ -94,7 +97,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;
@ -111,7 +113,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;
@ -241,6 +242,8 @@ public class UnmanagedVMsManagerImplTest {
private StoragePoolHostDao storagePoolHostDao;
@Mock
private ImportVmTasksManager importVmTasksManager;
@Mock
private ReservationDao reservationDao;
@Mock
private VMInstanceVO virtualMachine;
@ -302,7 +305,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);
@ -442,7 +444,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);
}
}
@ -609,7 +612,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);
}
}
@ -797,7 +801,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());
@ -850,7 +855,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);
}
}
@ -1198,42 +1204,6 @@ 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());
}
}
@Test
public void testCheckConversionStoragePoolSecondaryStorageStaging() {
unmanagedVMsManager.checkConversionStoragePool(null, false);