Merge commit '19b4ef106931aa1d6a8fed06984009d86760e4de' into 4.22

This commit is contained in:
Daan Hoogland 2026-04-14 13:15:05 +02:00
commit 1085da4ef8
90 changed files with 3178 additions and 2089 deletions

View File

@ -26,10 +26,13 @@ public final class BucketTO {
private String secretKey;
private long accountId;
public BucketTO(Bucket bucket) {
this.name = bucket.getName();
this.accessKey = bucket.getAccessKey();
this.secretKey = bucket.getSecretKey();
this.accountId = bucket.getAccountId();
}
public BucketTO(String name) {
@ -47,4 +50,8 @@ public final class BucketTO {
public String getSecretKey() {
return this.secretKey;
}
public long getAccountId() {
return this.accountId;
}
}

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

@ -23,9 +23,10 @@ import org.apache.cloudstack.api.InternalIdentity;
public interface VMTemplateStorageResourceAssoc extends InternalIdentity {
public static enum Status {
UNKNOWN, DOWNLOAD_ERROR, NOT_DOWNLOADED, DOWNLOAD_IN_PROGRESS, DOWNLOADED, ABANDONED, UPLOADED, NOT_UPLOADED, UPLOAD_ERROR, UPLOAD_IN_PROGRESS, CREATING, CREATED, BYPASSED
UNKNOWN, DOWNLOAD_ERROR, NOT_DOWNLOADED, DOWNLOAD_IN_PROGRESS, DOWNLOADED, ABANDONED, LIMIT_REACHED, UPLOADED, NOT_UPLOADED, UPLOAD_ERROR, UPLOAD_IN_PROGRESS, CREATING, CREATED, BYPASSED
}
List<Status> ERROR_DOWNLOAD_STATES = List.of(Status.DOWNLOAD_ERROR, Status.ABANDONED, Status.LIMIT_REACHED, Status.UNKNOWN);
List<Status> PENDING_DOWNLOAD_STATES = List.of(Status.NOT_DOWNLOADED, Status.DOWNLOAD_IN_PROGRESS);
String getInstallPath();

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 {
@ -191,6 +192,7 @@ public interface ResourceLimitService {
*/
public void checkResourceLimit(Account account, ResourceCount.ResourceType type, long... count) throws ResourceAllocationException;
public void checkResourceLimitWithTag(Account account, ResourceCount.ResourceType type, String tag, long... count) throws ResourceAllocationException;
public void checkResourceLimitWithTag(Account account, Long domainId, boolean considerSystemAccount, ResourceCount.ResourceType type, String tag, long... count) throws ResourceAllocationException;
/**
* Gets the count of resources for a resource type and account
@ -251,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);
@ -273,25 +275,23 @@ 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);
void checkVmGpuResourceLimit(Account owner, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long gpu) throws ResourceAllocationException;
void incrementVmGpuResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long gpu);
void decrementVmGpuResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long gpu);
long recalculateDomainResourceCount(final long domainId, final ResourceType type, String tag);
}

View File

@ -502,6 +502,7 @@ public class ApiConstants {
public static final String RECOVER = "recover";
public static final String REPAIR = "repair";
public static final String REQUIRES_HVM = "requireshvm";
public static final String RESERVED_RESOURCE_DETAILS = "reservedresourcedetails";
public static final String RESOURCES = "resources";
public static final String RESOURCE_COUNT = "resourcecount";
public static final String RESOURCE_NAME = "resourcename";

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

@ -20,6 +20,7 @@ package org.apache.cloudstack.api.command.user.backup;
import javax.inject.Inject;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.ACL;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
@ -53,6 +54,7 @@ public class RestoreVolumeFromBackupAndAttachToVMCmd extends BaseAsyncCmd {
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@ACL
@Parameter(name = ApiConstants.BACKUP_ID,
type = CommandType.UUID,
entityType = BackupResponse.class,
@ -60,12 +62,14 @@ public class RestoreVolumeFromBackupAndAttachToVMCmd extends BaseAsyncCmd {
description = "ID of the Instance backup")
private Long backupId;
@ACL
@Parameter(name = ApiConstants.VOLUME_ID,
type = CommandType.STRING,
required = true,
description = "ID of the volume backed up")
private String volumeUuid;
@ACL
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID,
type = CommandType.UUID,
entityType = UserVmResponse.class,

View File

@ -51,6 +51,7 @@ public class CreateVMFromBackupCmd extends BaseDeployVMCmd {
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@ACL
@Parameter(name = ApiConstants.BACKUP_ID,
type = CommandType.UUID,
entityType = BackupResponse.class,

View File

@ -85,6 +85,12 @@ public class ExtensionResponse extends BaseResponse {
@Param(description = "Removal timestamp of the extension, if applicable")
private Date removed;
@SerializedName(ApiConstants.RESERVED_RESOURCE_DETAILS)
@Param(description = "Resource detail names as comma separated string that should be reserved and not visible " +
"to end users",
since = "4.22.1")
protected String reservedResourceDetails;
public ExtensionResponse(String id, String name, String description, String type) {
this.id = id;
this.name = name;
@ -179,4 +185,8 @@ public class ExtensionResponse extends BaseResponse {
public void setRemoved(Date removed) {
this.removed = removed;
}
public void setReservedResourceDetails(String reservedResourceDetails) {
this.reservedResourceDetails = reservedResourceDetails;
}
}

View File

@ -17,8 +17,11 @@
package org.apache.cloudstack.extension;
import java.util.List;
public interface ExtensionHelper {
Long getExtensionIdForCluster(long clusterId);
Extension getExtension(long id);
Extension getExtensionForCluster(long clusterId);
List<String> getExtensionReservedResourceDetails(long extensionId);
}

View File

@ -0,0 +1,30 @@
// 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 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

@ -140,7 +140,7 @@ public class DownloadAnswer extends Answer {
}
public Long getTemplateSize() {
return templateSize;
return templateSize == 0 ? templatePhySicalSize : templateSize;
}
public void setTemplatePhySicalSize(long templatePhySicalSize) {

View File

@ -21,6 +21,7 @@ package org.apache.cloudstack.direct.download;
import com.cloud.utils.UriUtils;
import com.cloud.utils.exception.CloudRuntimeException;
import org.apache.cloudstack.utils.security.DigestHelper;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
@ -33,6 +34,7 @@ import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public abstract class DirectTemplateDownloaderImpl implements DirectTemplateDownloader {
@ -128,15 +130,14 @@ public abstract class DirectTemplateDownloaderImpl implements DirectTemplateDown
*/
protected File createTemporaryDirectoryAndFile(String downloadDir) {
createFolder(downloadDir);
return new File(downloadDir + File.separator + getFileNameFromUrl());
return new File(downloadDir + File.separator + getTemporaryFileName());
}
/**
* Return filename from url
* Return filename from the temporary download file
*/
public String getFileNameFromUrl() {
String[] urlParts = url.split("/");
return urlParts[urlParts.length - 1];
public String getTemporaryFileName() {
return String.format("%s.%s", UUID.randomUUID(), FilenameUtils.getExtension(url));
}
@Override

View File

@ -97,7 +97,7 @@ public class MetalinkDirectTemplateDownloader extends DirectTemplateDownloaderIm
DirectTemplateDownloader urlDownloader = createDownloaderForMetalinks(getUrl(), getTemplateId(), getDestPoolPath(),
getChecksum(), headers, connectTimeout, soTimeout, null, temporaryDownloadPath);
try {
setDownloadedFilePath(downloadDir + File.separator + getFileNameFromUrl());
setDownloadedFilePath(downloadDir + File.separator + getTemporaryFileName());
File f = new File(getDownloadedFilePath());
if (f.exists()) {
f.delete();

View File

@ -69,7 +69,7 @@ public class NfsDirectTemplateDownloader extends DirectTemplateDownloaderImpl {
String mount = String.format(mountCommand, srcHost + ":" + srcPath, "/mnt/" + mountSrcUuid);
Script.runSimpleBashScript(mount);
String downloadDir = getDestPoolPath() + File.separator + getDirectDownloadTempPath(getTemplateId());
setDownloadedFilePath(downloadDir + File.separator + getFileNameFromUrl());
setDownloadedFilePath(downloadDir + File.separator + getTemporaryFileName());
Script.runSimpleBashScript("cp /mnt/" + mountSrcUuid + srcPath + " " + getDownloadedFilePath());
Script.runSimpleBashScript("umount /mnt/" + mountSrcUuid);
return new Pair<>(true, getDownloadedFilePath());

View File

@ -19,6 +19,9 @@
package org.apache.cloudstack.storage.command;
import com.cloud.configuration.Resource;
import org.apache.cloudstack.utils.bytescale.ByteScaleUtils;
public class TemplateOrVolumePostUploadCommand {
long entityId;
@ -185,6 +188,11 @@ public class TemplateOrVolumePostUploadCommand {
this.description = description;
}
public void setDefaultMaxSecondaryStorageInBytes(long defaultMaxSecondaryStorageInBytes) {
this.defaultMaxSecondaryStorageInGB = defaultMaxSecondaryStorageInBytes != Resource.RESOURCE_UNLIMITED ?
ByteScaleUtils.bytesToGibibytes(defaultMaxSecondaryStorageInBytes) : Resource.RESOURCE_UNLIMITED;
}
public void setDefaultMaxSecondaryStorageInGB(long defaultMaxSecondaryStorageInGB) {
this.defaultMaxSecondaryStorageInGB = defaultMaxSecondaryStorageInGB;
}

View File

@ -28,6 +28,7 @@ public class UploadStatusCommand extends Command {
}
private String entityUuid;
private EntityType entityType;
private Boolean abort;
protected UploadStatusCommand() {
}
@ -37,6 +38,11 @@ public class UploadStatusCommand extends Command {
this.entityType = entityType;
}
public UploadStatusCommand(String entityUuid, EntityType entityType, Boolean abort) {
this(entityUuid, entityType);
this.abort = abort;
}
public String getEntityUuid() {
return entityUuid;
}
@ -45,6 +51,10 @@ public class UploadStatusCommand extends Command {
return entityType;
}
public Boolean getAbort() {
return abort;
}
@Override
public boolean executeInSequence() {
return false;

View File

@ -310,7 +310,7 @@ public interface NetworkOrchestrationService {
void removeDhcpServiceInSubnet(Nic nic);
boolean resourceCountNeedsUpdate(NetworkOffering ntwkOff, ACLType aclType);
boolean isResourceCountUpdateNeeded(NetworkOffering networkOffering);
void prepareAllNicsForMigration(VirtualMachineProfile vm, DeployDestination dest);

View File

@ -120,7 +120,7 @@ public interface VolumeOrchestrationService {
void destroyVolume(Volume volume);
DiskProfile allocateRawVolume(Type type, String name, DiskOffering offering, Long size, Long minIops, Long maxIops, VirtualMachine vm, VirtualMachineTemplate template,
Account owner, Long deviceId);
Account owner, Long deviceId, boolean incrementResourceCount);
VolumeInfo createVolumeOnPrimaryStorage(VirtualMachine vm, VolumeInfo volume, HypervisorType rootDiskHyperType, StoragePool storagePool) throws NoTransitionException;

View File

@ -50,7 +50,6 @@ import javax.inject.Inject;
import javax.naming.ConfigurationException;
import javax.persistence.EntityExistsException;
import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
import org.apache.cloudstack.annotation.AnnotationService;
import org.apache.cloudstack.annotation.dao.AnnotationDao;
@ -308,7 +307,6 @@ import com.cloud.vm.snapshot.VMSnapshotVO;
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
import com.google.gson.Gson;
public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMachineManager, VmWorkJobHandler, Listener, Configurable {
public static final String VM_WORK_JOB_HANDLER = VirtualMachineManagerImpl.class.getSimpleName();
@ -586,7 +584,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
Long deviceId = dataDiskDeviceIds.get(index++);
String volumeName = deviceId == null ? "DATA-" + persistedVm.getId() : "DATA-" + persistedVm.getId() + "-" + String.valueOf(deviceId);
volumeMgr.allocateRawVolume(Type.DATADISK, volumeName, dataDiskOfferingInfo.getDiskOffering(), dataDiskOfferingInfo.getSize(),
dataDiskOfferingInfo.getMinIops(), dataDiskOfferingInfo.getMaxIops(), persistedVm, template, owner, deviceId);
dataDiskOfferingInfo.getMinIops(), dataDiskOfferingInfo.getMaxIops(), persistedVm, template, owner, deviceId, true);
}
}
if (datadiskTemplateToDiskOfferingMap != null && !datadiskTemplateToDiskOfferingMap.isEmpty()) {
@ -596,7 +594,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
long diskOfferingSize = diskOffering.getDiskSize() / (1024 * 1024 * 1024);
VMTemplateVO dataDiskTemplate = _templateDao.findById(dataDiskTemplateToDiskOfferingMap.getKey());
volumeMgr.allocateRawVolume(Type.DATADISK, "DATA-" + persistedVm.getId() + "-" + String.valueOf( diskNumber), diskOffering, diskOfferingSize, null, null,
persistedVm, dataDiskTemplate, owner, diskNumber);
persistedVm, dataDiskTemplate, owner, diskNumber, true);
diskNumber++;
}
}
@ -626,7 +624,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
String rootVolumeName = String.format("ROOT-%s", vm.getId());
if (template.getFormat() == ImageFormat.ISO) {
volumeMgr.allocateRawVolume(Type.ROOT, rootVolumeName, rootDiskOfferingInfo.getDiskOffering(), rootDiskOfferingInfo.getSize(),
rootDiskOfferingInfo.getMinIops(), rootDiskOfferingInfo.getMaxIops(), vm, template, owner, null);
rootDiskOfferingInfo.getMinIops(), rootDiskOfferingInfo.getMaxIops(), vm, template, owner, null, true);
} else if (Arrays.asList(ImageFormat.BAREMETAL, ImageFormat.EXTERNAL).contains(template.getFormat())) {
logger.debug("{} has format [{}]. Skipping ROOT volume [{}] allocation.", template, template.getFormat(), rootVolumeName);
} else {
@ -2213,7 +2211,6 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
protected boolean sendStop(final VirtualMachineGuru guru, final VirtualMachineProfile profile, final boolean force, final boolean checkBeforeCleanup) {
final VirtualMachine vm = profile.getVirtualMachine();
Map<String, Boolean> vlanToPersistenceMap = getVlanToPersistenceMapForVM(vm.getId());
StopCommand stpCmd = new StopCommand(vm, getExecuteInSequence(vm.getHypervisorType()), checkBeforeCleanup);
updateStopCommandForExternalHypervisorType(vm.getHypervisorType(), profile, stpCmd);
if (MapUtils.isNotEmpty(vlanToPersistenceMap)) {
@ -5272,9 +5269,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

@ -58,6 +58,7 @@ import org.apache.cloudstack.framework.messagebus.PublishScope;
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
import org.apache.cloudstack.network.RoutedIpv4Manager;
import org.apache.cloudstack.network.dao.NetworkPermissionDao;
import org.apache.cloudstack.reservation.dao.ReservationDao;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.ObjectUtils;
@ -86,6 +87,7 @@ import com.cloud.api.query.dao.DomainRouterJoinDao;
import com.cloud.api.query.vo.DomainRouterJoinVO;
import com.cloud.bgp.BGPService;
import com.cloud.configuration.ConfigurationManager;
import com.cloud.configuration.Resource;
import com.cloud.configuration.Resource.ResourceType;
import com.cloud.dc.ASNumberVO;
import com.cloud.dc.ClusterVO;
@ -214,6 +216,7 @@ import com.cloud.offerings.dao.NetworkOfferingDao;
import com.cloud.offerings.dao.NetworkOfferingDetailsDao;
import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
import com.cloud.resource.ResourceManager;
import com.cloud.resourcelimit.CheckedReservation;
import com.cloud.server.ManagementServer;
import com.cloud.user.Account;
import com.cloud.user.ResourceLimitService;
@ -447,6 +450,8 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
ClusterDao clusterDao;
@Inject
RoutedIpv4Manager routedIpv4Manager;
@Inject
private ReservationDao reservationDao;
protected StateMachine2<Network.State, Network.Event, Network> _stateMachine;
ScheduledExecutorService _executor;
@ -2752,12 +2757,6 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
return null;
}
final boolean updateResourceCount = resourceCountNeedsUpdate(ntwkOff, aclType);
//check resource limits
if (updateResourceCount) {
_resourceLimitMgr.checkResourceLimit(owner, ResourceType.network, isDisplayNetworkEnabled);
}
// Validate network offering
if (ntwkOff.getState() != NetworkOffering.State.Enabled) {
// see NetworkOfferingVO
@ -2776,6 +2775,8 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
boolean ipv6 = false;
try (CheckedReservation networkReservation = new CheckedReservation(owner, domainId, Resource.ResourceType.network, null, null, 1L, reservationDao, _resourceLimitMgr)) {
if (StringUtils.isNoneBlank(ip6Gateway, ip6Cidr)) {
ipv6 = true;
}
@ -3115,8 +3116,8 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
}
}
if (updateResourceCount) {
_resourceLimitMgr.incrementResourceCount(owner.getId(), ResourceType.network, isDisplayNetworkEnabled);
if (isResourceCountUpdateNeeded(ntwkOff)) {
changeAccountResourceCountOrRecalculateDomainResourceCount(owner.getAccountId(), domainId, isDisplayNetworkEnabled, true);
}
UsageEventUtils.publishNetworkCreation(network);
@ -3127,6 +3128,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
CallContext.current().setEventDetails("Network Id: " + network.getId());
CallContext.current().putContextParameter(Network.class, network.getUuid());
return network;
}
}
@Override
@ -3492,9 +3494,8 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
}
final NetworkOffering ntwkOff = _entityMgr.findById(NetworkOffering.class, networkFinal.getNetworkOfferingId());
final boolean updateResourceCount = resourceCountNeedsUpdate(ntwkOff, networkFinal.getAclType());
if (updateResourceCount) {
_resourceLimitMgr.decrementResourceCount(networkFinal.getAccountId(), ResourceType.network, networkFinal.getDisplayNetwork());
if (isResourceCountUpdateNeeded(ntwkOff)) {
changeAccountResourceCountOrRecalculateDomainResourceCount(networkFinal.getAccountId(), networkFinal.getDomainId(), networkFinal.getDisplayNetwork(), false);
}
}
return deletedVlans.second();
@ -3517,6 +3518,23 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
return success;
}
/**
* If it is a shared network with {@link ACLType#Domain}, it will belong to account {@link Account#ACCOUNT_ID_SYSTEM} and the resources will be not incremented for the
* domain. Therefore, we force the recalculation of the domain's resource count in this case. Otherwise, it will change the count for the account owner.
* @param incrementAccountResourceCount If true, the account resource count will be incremented by 1; otherwise, it will decremented by 1.
*/
private void changeAccountResourceCountOrRecalculateDomainResourceCount(Long accountId, Long domainId, boolean displayNetwork, boolean incrementAccountResourceCount) {
if (Account.ACCOUNT_ID_SYSTEM == accountId && ObjectUtils.isNotEmpty(domainId)) {
_resourceLimitMgr.recalculateDomainResourceCount(domainId, ResourceType.network, null);
} else {
if (incrementAccountResourceCount) {
_resourceLimitMgr.incrementResourceCount(accountId, ResourceType.network, displayNetwork);
} else {
_resourceLimitMgr.decrementResourceCount(accountId, ResourceType.network, displayNetwork);
}
}
}
private void publishDeletedVlanRanges(List<VlanVO> deletedVlanRangeToPublish) {
if (CollectionUtils.isNotEmpty(deletedVlanRangeToPublish)) {
for (VlanVO vlan : deletedVlanRangeToPublish) {
@ -3526,10 +3544,8 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
}
@Override
public boolean resourceCountNeedsUpdate(final NetworkOffering ntwkOff, final ACLType aclType) {
//Update resource count only for Isolated account specific non-system networks
final boolean updateResourceCount = ntwkOff.getGuestType() == GuestType.Isolated && !ntwkOff.isSystemOnly() && aclType == ACLType.Account;
return updateResourceCount;
public boolean isResourceCountUpdateNeeded(NetworkOffering networkOffering) {
return !networkOffering.isSystemOnly();
}
protected Pair<Boolean, List<VlanVO>> deleteVlansInNetwork(final NetworkVO network, final long userId, final Account callerAccount) {

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;
@ -862,7 +864,7 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
@ActionEvent(eventType = EventTypes.EVENT_VOLUME_CREATE, eventDescription = "creating volume", create = true)
@Override
public DiskProfile allocateRawVolume(Type type, String name, DiskOffering offering, Long size, Long minIops, Long maxIops, VirtualMachine vm, VirtualMachineTemplate template, Account owner,
Long deviceId) {
Long deviceId, boolean incrementResourceCount) {
if (size == null) {
size = offering.getDiskSize();
} else {
@ -901,7 +903,7 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
saveVolumeDetails(offering.getId(), vol.getId());
// Save usage event and update resource count for user vm volumes
if (vm.getType() == VirtualMachine.Type.User) {
if (vm.getType() == VirtualMachine.Type.User && incrementResourceCount) {
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, vol.getAccountId(), vol.getDataCenterId(), vol.getId(), vol.getName(), offering.getId(), null, size,
Volume.class.getName(), vol.getUuid(), vol.getInstanceId(), vol.isDisplayVolume());
_resourceLimitMgr.incrementVolumeResourceCount(vm.getAccountId(), vol.isDisplayVolume(), vol.getSize(), offering);
@ -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

@ -27,6 +27,6 @@ public interface AccountVlanMapDao extends GenericDao<AccountVlanMapVO, Long> {
public List<AccountVlanMapVO> listAccountVlanMapsByVlan(long vlanDbId);
public AccountVlanMapVO findAccountVlanMap(long accountId, long vlanDbId);
public AccountVlanMapVO findAccountVlanMap(Long accountId, long vlanDbId);
}

View File

@ -48,9 +48,9 @@ public class AccountVlanMapDaoImpl extends GenericDaoBase<AccountVlanMapVO, Long
}
@Override
public AccountVlanMapVO findAccountVlanMap(long accountId, long vlanDbId) {
public AccountVlanMapVO findAccountVlanMap(Long accountId, long vlanDbId) {
SearchCriteria<AccountVlanMapVO> sc = AccountVlanSearch.create();
sc.setParameters("accountId", accountId);
sc.setParametersIfNotNull("accountId", accountId);
sc.setParameters("vlanDbId", vlanDbId);
return findOneIncludingRemovedBy(sc);
}

View File

@ -24,5 +24,5 @@ import com.cloud.utils.db.GenericDao;
public interface DomainVlanMapDao extends GenericDao<DomainVlanMapVO, Long> {
public List<DomainVlanMapVO> listDomainVlanMapsByDomain(long domainId);
public List<DomainVlanMapVO> listDomainVlanMapsByVlan(long vlanDbId);
public DomainVlanMapVO findDomainVlanMap(long domainId, long vlanDbId);
public DomainVlanMapVO findDomainVlanMap(Long domainId, long vlanDbId);
}

View File

@ -46,9 +46,9 @@ public class DomainVlanMapDaoImpl extends GenericDaoBase<DomainVlanMapVO, Long>
}
@Override
public DomainVlanMapVO findDomainVlanMap(long domainId, long vlanDbId) {
public DomainVlanMapVO findDomainVlanMap(Long domainId, long vlanDbId) {
SearchCriteria<DomainVlanMapVO> sc = DomainVlanSearch.create();
sc.setParameters("domainId", domainId);
sc.setParametersIfNotNull("domainId", domainId);
sc.setParameters("vlanDbId", vlanDbId);
return findOneIncludingRemovedBy(sc);
}

View File

@ -79,6 +79,7 @@ SELECT
`vm_template`.`format` AS `template_format`,
`vm_template`.`display_text` AS `template_display_text`,
`vm_template`.`enable_password` AS `password_enabled`,
`vm_template`.`extension_id` AS `template_extension_id`,
`iso`.`id` AS `iso_id`,
`iso`.`uuid` AS `iso_uuid`,
`iso`.`name` AS `iso_name`,

View File

@ -230,8 +230,10 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver {
updateBuilder.setJobId(answer.getJobId());
updateBuilder.setLocalDownloadPath(answer.getDownloadPath());
updateBuilder.setInstallPath(answer.getInstallPath());
updateBuilder.setSize(answer.getTemplateSize());
updateBuilder.setPhysicalSize(answer.getTemplatePhySicalSize());
if (!VMTemplateStorageResourceAssoc.ERROR_DOWNLOAD_STATES.contains(answer.getDownloadStatus())) {
updateBuilder.setSize(answer.getTemplateSize());
updateBuilder.setPhysicalSize(answer.getTemplatePhySicalSize());
}
_templateStoreDao.update(tmpltStoreVO.getId(), updateBuilder);
// update size in vm_template table
VMTemplateVO tmlptUpdater = _templateDao.createForUpdate();
@ -241,8 +243,7 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver {
AsyncCompletionCallback<CreateCmdResult> caller = context.getParentCallback();
if (answer.getDownloadStatus() == VMTemplateStorageResourceAssoc.Status.DOWNLOAD_ERROR ||
answer.getDownloadStatus() == VMTemplateStorageResourceAssoc.Status.ABANDONED || answer.getDownloadStatus() == VMTemplateStorageResourceAssoc.Status.UNKNOWN) {
if (VMTemplateStorageResourceAssoc.ERROR_DOWNLOAD_STATES.contains(answer.getDownloadStatus())) {
CreateCmdResult result = new CreateCmdResult(null, null);
result.setSuccess(false);
result.setResult(answer.getErrorString());
@ -285,19 +286,22 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver {
updateBuilder.setJobId(answer.getJobId());
updateBuilder.setLocalDownloadPath(answer.getDownloadPath());
updateBuilder.setInstallPath(answer.getInstallPath());
updateBuilder.setSize(answer.getTemplateSize());
updateBuilder.setPhysicalSize(answer.getTemplatePhySicalSize());
if (!VMTemplateStorageResourceAssoc.ERROR_DOWNLOAD_STATES.contains(answer.getDownloadStatus())) {
updateBuilder.setSize(answer.getTemplateSize());
updateBuilder.setPhysicalSize(answer.getTemplatePhySicalSize());
}
_volumeStoreDao.update(volStoreVO.getId(), updateBuilder);
// update size in volume table
VolumeVO volUpdater = volumeDao.createForUpdate();
volUpdater.setSize(answer.getTemplateSize());
volumeDao.update(obj.getId(), volUpdater);
if (!VMTemplateStorageResourceAssoc.ERROR_DOWNLOAD_STATES.contains(answer.getDownloadStatus())) {
VolumeVO volUpdater = volumeDao.createForUpdate();
volUpdater.setSize(answer.getTemplateSize());
volumeDao.update(obj.getId(), volUpdater);
}
}
AsyncCompletionCallback<CreateCmdResult> caller = context.getParentCallback();
if (answer.getDownloadStatus() == VMTemplateStorageResourceAssoc.Status.DOWNLOAD_ERROR ||
answer.getDownloadStatus() == VMTemplateStorageResourceAssoc.Status.ABANDONED || answer.getDownloadStatus() == VMTemplateStorageResourceAssoc.Status.UNKNOWN) {
if (VMTemplateStorageResourceAssoc.ERROR_DOWNLOAD_STATES.contains(answer.getDownloadStatus())) {
CreateCmdResult result = new CreateCmdResult(null, null);
result.setSuccess(false);
result.setResult(answer.getErrorString());

View File

@ -83,6 +83,12 @@ public class CreateExtensionCmd extends BaseCmd {
description = "Details in key/value pairs using format details[i].keyname=keyvalue. Example: details[0].endpoint.url=urlvalue")
protected Map details;
@Parameter(name = ApiConstants.RESERVED_RESOURCE_DETAILS, type = CommandType.STRING,
description = "Resource detail names as comma separated string that should be reserved and not visible " +
"to end users",
since = "4.22.1")
protected String reservedResourceDetails;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -115,6 +121,10 @@ public class CreateExtensionCmd extends BaseCmd {
return convertDetailsToMap(details);
}
public String getReservedResourceDetails() {
return reservedResourceDetails;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

View File

@ -78,6 +78,12 @@ public class UpdateExtensionCmd extends BaseCmd {
"if false or not set, no action)")
private Boolean cleanupDetails;
@Parameter(name = ApiConstants.RESERVED_RESOURCE_DETAILS, type = CommandType.STRING,
description = "Resource detail names as comma separated string that should be reserved and not visible " +
"to end users",
since = "4.22.1")
protected String reservedResourceDetails;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -106,6 +112,10 @@ public class UpdateExtensionCmd extends BaseCmd {
return cleanupDetails;
}
public String getReservedResourceDetails() {
return reservedResourceDetails;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

View File

@ -216,6 +216,11 @@ public class ExtensionsManagerImpl extends ManagerBase implements ExtensionsMana
@Inject
AccountService accountService;
// Map of in-built extension names and their reserved resource details that shouldn't be accessible to end-users
protected static final Map<String, List<String>> INBUILT_RESERVED_RESOURCE_DETAILS = Map.of(
"proxmox", List.of("proxmox_vmid")
);
private ScheduledExecutorService extensionPathStateCheckExecutor;
protected String getDefaultExtensionRelativePath(String name) {
@ -563,6 +568,25 @@ public class ExtensionsManagerImpl extends ManagerBase implements ExtensionsMana
updateExtensionPathReady(extension, true);
}
protected void addInbuiltExtensionReservedResourceDetails(long extensionId, List<String> reservedResourceDetails) {
ExtensionVO vo = extensionDao.findById(extensionId);
if (vo == null || vo.isUserDefined()) {
return;
}
String lowerName = StringUtils.defaultString(vo.getName()).toLowerCase();
Optional<Map.Entry<String, List<String>>> match = INBUILT_RESERVED_RESOURCE_DETAILS.entrySet().stream()
.filter(e -> lowerName.contains(e.getKey().toLowerCase()))
.findFirst();
if (match.isPresent()) {
Set<String> existing = new HashSet<>(reservedResourceDetails);
for (String detailKey : match.get().getValue()) {
if (existing.add(detailKey)) {
reservedResourceDetails.add(detailKey);
}
}
}
}
@Override
public String getExtensionsPath() {
return externalProvisioner.getExtensionsPath();
@ -577,6 +601,7 @@ public class ExtensionsManagerImpl extends ManagerBase implements ExtensionsMana
String relativePath = cmd.getPath();
final Boolean orchestratorRequiresPrepareVm = cmd.isOrchestratorRequiresPrepareVm();
final String stateStr = cmd.getState();
final String reservedResourceDetails = cmd.getReservedResourceDetails();
ExtensionVO extensionByName = extensionDao.findByName(name);
if (extensionByName != null) {
throw new CloudRuntimeException("Extension by name already exists");
@ -624,6 +649,10 @@ public class ExtensionsManagerImpl extends ManagerBase implements ExtensionsMana
ApiConstants.ORCHESTRATOR_REQUIRES_PREPARE_VM, String.valueOf(orchestratorRequiresPrepareVm),
false));
}
if (StringUtils.isNotBlank(reservedResourceDetails)) {
detailsVOList.add(new ExtensionDetailsVO(extension.getId(),
ApiConstants.RESERVED_RESOURCE_DETAILS, reservedResourceDetails, false));
}
if (CollectionUtils.isNotEmpty(detailsVOList)) {
extensionDetailsDao.saveDetails(detailsVOList);
}
@ -704,6 +733,7 @@ public class ExtensionsManagerImpl extends ManagerBase implements ExtensionsMana
final String stateStr = cmd.getState();
final Map<String, String> details = cmd.getDetails();
final Boolean cleanupDetails = cmd.isCleanupDetails();
final String reservedResourceDetails = cmd.getReservedResourceDetails();
final ExtensionVO extensionVO = extensionDao.findById(id);
if (extensionVO == null) {
throw new InvalidParameterValueException("Failed to find the extension");
@ -732,7 +762,8 @@ public class ExtensionsManagerImpl extends ManagerBase implements ExtensionsMana
throw new CloudRuntimeException(String.format("Failed to updated the extension: %s",
extensionVO.getName()));
}
updateExtensionsDetails(cleanupDetails, details, orchestratorRequiresPrepareVm, id);
updateExtensionsDetails(cleanupDetails, details, orchestratorRequiresPrepareVm, reservedResourceDetails,
id);
return extensionVO;
});
if (StringUtils.isNotBlank(stateStr)) {
@ -748,9 +779,11 @@ public class ExtensionsManagerImpl extends ManagerBase implements ExtensionsMana
return result;
}
protected void updateExtensionsDetails(Boolean cleanupDetails, Map<String, String> details, Boolean orchestratorRequiresPrepareVm, long id) {
protected void updateExtensionsDetails(Boolean cleanupDetails, Map<String, String> details,
Boolean orchestratorRequiresPrepareVm, String reservedResourceDetails, long id) {
final boolean needToUpdateAllDetails = Boolean.TRUE.equals(cleanupDetails) || MapUtils.isNotEmpty(details);
if (!needToUpdateAllDetails && orchestratorRequiresPrepareVm == null) {
if (!needToUpdateAllDetails && orchestratorRequiresPrepareVm == null &&
StringUtils.isBlank(reservedResourceDetails)) {
return;
}
if (needToUpdateAllDetails) {
@ -761,6 +794,9 @@ public class ExtensionsManagerImpl extends ManagerBase implements ExtensionsMana
hiddenDetails.put(ApiConstants.ORCHESTRATOR_REQUIRES_PREPARE_VM,
String.valueOf(orchestratorRequiresPrepareVm));
}
if (StringUtils.isNotBlank(reservedResourceDetails)) {
hiddenDetails.put(ApiConstants.RESERVED_RESOURCE_DETAILS, reservedResourceDetails);
}
if (MapUtils.isNotEmpty(hiddenDetails)) {
hiddenDetails.forEach((key, value) -> detailsVOList.add(
new ExtensionDetailsVO(id, key, value, false)));
@ -775,15 +811,29 @@ public class ExtensionsManagerImpl extends ManagerBase implements ExtensionsMana
extensionDetailsDao.removeDetails(id);
}
} else {
ExtensionDetailsVO detailsVO = extensionDetailsDao.findDetail(id,
ApiConstants.ORCHESTRATOR_REQUIRES_PREPARE_VM);
if (detailsVO == null) {
extensionDetailsDao.persist(new ExtensionDetailsVO(id,
ApiConstants.ORCHESTRATOR_REQUIRES_PREPARE_VM,
String.valueOf(orchestratorRequiresPrepareVm), false));
} else if (Boolean.parseBoolean(detailsVO.getValue()) != orchestratorRequiresPrepareVm) {
detailsVO.setValue(String.valueOf(orchestratorRequiresPrepareVm));
extensionDetailsDao.update(detailsVO.getId(), detailsVO);
if (orchestratorRequiresPrepareVm != null) {
ExtensionDetailsVO detailsVO = extensionDetailsDao.findDetail(id,
ApiConstants.ORCHESTRATOR_REQUIRES_PREPARE_VM);
if (detailsVO == null) {
extensionDetailsDao.persist(new ExtensionDetailsVO(id,
ApiConstants.ORCHESTRATOR_REQUIRES_PREPARE_VM,
String.valueOf(orchestratorRequiresPrepareVm), false));
} else if (Boolean.parseBoolean(detailsVO.getValue()) != orchestratorRequiresPrepareVm) {
detailsVO.setValue(String.valueOf(orchestratorRequiresPrepareVm));
extensionDetailsDao.update(detailsVO.getId(), detailsVO);
}
}
if (StringUtils.isNotBlank(reservedResourceDetails)) {
ExtensionDetailsVO detailsVO = extensionDetailsDao.findDetail(id,
ApiConstants.RESERVED_RESOURCE_DETAILS);
if (detailsVO == null) {
extensionDetailsDao.persist(new ExtensionDetailsVO(id,
ApiConstants.RESERVED_RESOURCE_DETAILS,
reservedResourceDetails, false));
} else if (!reservedResourceDetails.equals(detailsVO.getValue())) {
detailsVO.setValue(reservedResourceDetails);
extensionDetailsDao.update(detailsVO.getId(), detailsVO);
}
}
}
}
@ -961,12 +1011,16 @@ public class ExtensionsManagerImpl extends ManagerBase implements ExtensionsMana
hiddenDetails = extensionDetails.second();
} else {
hiddenDetails = extensionDetailsDao.listDetailsKeyPairs(extension.getId(),
List.of(ApiConstants.ORCHESTRATOR_REQUIRES_PREPARE_VM));
List.of(ApiConstants.ORCHESTRATOR_REQUIRES_PREPARE_VM,
ApiConstants.RESERVED_RESOURCE_DETAILS));
}
if (hiddenDetails.containsKey(ApiConstants.ORCHESTRATOR_REQUIRES_PREPARE_VM)) {
response.setOrchestratorRequiresPrepareVm(Boolean.parseBoolean(
hiddenDetails.get(ApiConstants.ORCHESTRATOR_REQUIRES_PREPARE_VM)));
}
if (hiddenDetails.containsKey(ApiConstants.RESERVED_RESOURCE_DETAILS)) {
response.setReservedResourceDetails(hiddenDetails.get(ApiConstants.RESERVED_RESOURCE_DETAILS));
}
response.setObjectName(Extension.class.getSimpleName().toLowerCase());
return response;
}
@ -1605,6 +1659,24 @@ public class ExtensionsManagerImpl extends ManagerBase implements ExtensionsMana
return extensionDao.findById(extensionId);
}
@Override
public List<String> getExtensionReservedResourceDetails(long extensionId) {
ExtensionDetailsVO detailsVO = extensionDetailsDao.findDetail(extensionId,
ApiConstants.RESERVED_RESOURCE_DETAILS);
if (detailsVO == null || !StringUtils.isNotBlank(detailsVO.getValue())) {
return Collections.emptyList();
}
List<String> reservedDetails = new ArrayList<>();
String[] parts = detailsVO.getValue().split(",");
for (String part : parts) {
if (StringUtils.isNotBlank(part)) {
reservedDetails.add(part.trim());
}
}
addInbuiltExtensionReservedResourceDetails(extensionId, reservedDetails);
return reservedDetails;
}
@Override
public boolean start() {
long pathStateCheckInterval = PathStateCheckInterval.value();

View File

@ -94,4 +94,18 @@ public class CreateExtensionCmdTest {
setField(cmd, "details", details);
assertTrue(MapUtils.isNotEmpty(cmd.getDetails()));
}
@Test
public void getReservedResourceDetailsReturnsValueWhenSet() {
setField(cmd, "reservedResourceDetails", "detail1,detail2,detail3");
String result = cmd.getReservedResourceDetails();
assertEquals("detail1,detail2,detail3", result);
}
@Test
public void getReservedResourceDetailsReturnsNullWhenNotSet() {
setField(cmd, "reservedResourceDetails", null);
String result = cmd.getReservedResourceDetails();
assertNull(result);
}
}

View File

@ -26,6 +26,7 @@ import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.test.util.ReflectionTestUtils.setField;
import java.util.EnumSet;
import java.util.HashMap;
@ -134,6 +135,20 @@ public class UpdateExtensionCmdTest {
assertTrue(cmd.isCleanupDetails());
}
@Test
public void getReservedResourceDetailsReturnsValueWhenSet() {
setField(cmd, "reservedResourceDetails", "detail1,detail2,detail3");
String result = cmd.getReservedResourceDetails();
assertEquals("detail1,detail2,detail3", result);
}
@Test
public void getReservedResourceDetailsReturnsNullWhenNotSet() {
setField(cmd, "reservedResourceDetails", null);
String result = cmd.getReservedResourceDetails();
assertNull(result);
}
@Test
public void executeSetsExtensionResponseWhenManagerSucceeds() {
Extension extension = mock(Extension.class);

View File

@ -23,11 +23,13 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyLong;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
@ -40,6 +42,7 @@ import static org.mockito.Mockito.when;
import java.io.File;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
@ -49,8 +52,6 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.user.AccountService;
import org.apache.cloudstack.acl.Role;
import org.apache.cloudstack.acl.RoleService;
import org.apache.cloudstack.acl.RoleType;
@ -85,9 +86,11 @@ import org.apache.cloudstack.framework.extensions.dao.ExtensionResourceMapDao;
import org.apache.cloudstack.framework.extensions.dao.ExtensionResourceMapDetailsDao;
import org.apache.cloudstack.framework.extensions.vo.ExtensionCustomActionDetailsVO;
import org.apache.cloudstack.framework.extensions.vo.ExtensionCustomActionVO;
import org.apache.cloudstack.framework.extensions.vo.ExtensionDetailsVO;
import org.apache.cloudstack.framework.extensions.vo.ExtensionResourceMapVO;
import org.apache.cloudstack.framework.extensions.vo.ExtensionVO;
import org.apache.cloudstack.utils.identity.ManagementServerNode;
import org.apache.commons.collections.CollectionUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -113,6 +116,7 @@ import com.cloud.dc.dao.ClusterDao;
import com.cloud.exception.AgentUnavailableException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.OperationTimedoutException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.host.Host;
import com.cloud.host.dao.HostDao;
import com.cloud.host.dao.HostDetailsDao;
@ -122,6 +126,7 @@ import com.cloud.org.Cluster;
import com.cloud.serializer.GsonHelper;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.user.Account;
import com.cloud.user.AccountService;
import com.cloud.utils.Pair;
import com.cloud.utils.UuidUtils;
import com.cloud.utils.db.EntityManager;
@ -664,6 +669,8 @@ public class ExtensionsManagerImplTest {
when(cmd.getPath()).thenReturn(null);
when(cmd.isOrchestratorRequiresPrepareVm()).thenReturn(null);
when(cmd.getState()).thenReturn(null);
String reservedResourceDetails = "abc,xyz";
when(cmd.getReservedResourceDetails()).thenReturn(reservedResourceDetails);
when(extensionDao.findByName("ext1")).thenReturn(null);
when(extensionDao.persist(any())).thenAnswer(inv -> {
ExtensionVO extensionVO = inv.getArgument(0);
@ -671,11 +678,20 @@ public class ExtensionsManagerImplTest {
return extensionVO;
});
when(managementServerHostDao.listBy(any())).thenReturn(Collections.emptyList());
List<ExtensionDetailsVO> detailsList = new ArrayList<>();
doAnswer(inv -> {
List<ExtensionDetailsVO> detailsVO = inv.getArgument(0);
detailsList.addAll(detailsVO);
return null;
}).when(extensionDetailsDao).saveDetails(anyList());
Extension ext = extensionsManager.createExtension(cmd);
assertEquals("ext1", ext.getName());
verify(extensionDao).persist(any());
assertTrue(CollectionUtils.isNotEmpty(detailsList));
assertTrue(detailsList.stream()
.anyMatch(detail -> ApiConstants.RESERVED_RESOURCE_DETAILS.equals(detail.getName())
&& reservedResourceDetails.equals(detail.getValue())));
}
@Test
@ -938,14 +954,32 @@ public class ExtensionsManagerImplTest {
public void updateExtensionsDetails_SavesDetails_WhenDetailsProvided() {
long extensionId = 10L;
Map<String, String> details = Map.of("foo", "bar", "baz", "qux");
extensionsManager.updateExtensionsDetails(false, details, null, extensionId);
extensionsManager.updateExtensionsDetails(false, details, null, null, extensionId);
verify(extensionDetailsDao).saveDetails(any());
}
@Test
public void updateExtensionsDetails_PersistReservedDetail_WhenProvided() {
long extensionId = 10L;
when(extensionDetailsDao.persist(any())).thenReturn(mock(ExtensionDetailsVO.class));
extensionsManager.updateExtensionsDetails(false, null, null, "abc,xyz", extensionId);
verify(extensionDetailsDao).persist(any());
}
@Test
public void updateExtensionsDetails_UpdateReservedDetail_WhenProvided() {
long extensionId = 10L;
when(extensionDetailsDao.findDetail(anyLong(), eq(ApiConstants.RESERVED_RESOURCE_DETAILS)))
.thenReturn(mock(ExtensionDetailsVO.class));
when(extensionDetailsDao.update(anyLong(), any())).thenReturn(true);
extensionsManager.updateExtensionsDetails(false, null, null, "abc,xyz", extensionId);
verify(extensionDetailsDao).update(anyLong(), any());
}
@Test
public void updateExtensionsDetails_DoesNothing_WhenDetailsAndCleanupAreNull() {
long extensionId = 11L;
extensionsManager.updateExtensionsDetails(null, null, null, extensionId);
extensionsManager.updateExtensionsDetails(null, null, null, null, extensionId);
verify(extensionDetailsDao, never()).removeDetails(anyLong());
verify(extensionDetailsDao, never()).saveDetails(any());
}
@ -953,7 +987,7 @@ public class ExtensionsManagerImplTest {
@Test
public void updateExtensionsDetails_RemovesDetailsOnly_WhenCleanupIsTrue() {
long extensionId = 12L;
extensionsManager.updateExtensionsDetails(true, null, null, extensionId);
extensionsManager.updateExtensionsDetails(true, null, null, null, extensionId);
verify(extensionDetailsDao).removeDetails(extensionId);
verify(extensionDetailsDao, never()).saveDetails(any());
}
@ -961,7 +995,7 @@ public class ExtensionsManagerImplTest {
@Test
public void updateExtensionsDetails_PersistsOrchestratorFlag_WhenFlagIsNotNull() {
long extensionId = 13L;
extensionsManager.updateExtensionsDetails(false, null, true, extensionId);
extensionsManager.updateExtensionsDetails(false, null, true, null, extensionId);
verify(extensionDetailsDao).persist(any());
}
@ -970,7 +1004,7 @@ public class ExtensionsManagerImplTest {
long extensionId = 14L;
Map<String, String> details = Map.of("foo", "bar");
doThrow(CloudRuntimeException.class).when(extensionDetailsDao).saveDetails(any());
extensionsManager.updateExtensionsDetails(false, details, null, extensionId);
extensionsManager.updateExtensionsDetails(false, details, null, null, extensionId);
}
@Test
@ -1161,7 +1195,8 @@ public class ExtensionsManagerImplTest {
when(externalProvisioner.getExtensionPath("entry2.sh")).thenReturn("/some/path/entry2.sh");
Map<String, String> hiddenDetails = Map.of(ApiConstants.ORCHESTRATOR_REQUIRES_PREPARE_VM, "false");
when(extensionDetailsDao.listDetailsKeyPairs(2L, List.of(ApiConstants.ORCHESTRATOR_REQUIRES_PREPARE_VM)))
when(extensionDetailsDao.listDetailsKeyPairs(2L, List.of(
ApiConstants.ORCHESTRATOR_REQUIRES_PREPARE_VM, ApiConstants.RESERVED_RESOURCE_DETAILS)))
.thenReturn(hiddenDetails);
EnumSet<ApiConstants.ExtensionDetails> viewDetails = EnumSet.noneOf(ApiConstants.ExtensionDetails.class);
@ -2069,4 +2104,118 @@ public class ExtensionsManagerImplTest {
}
}
@Test
public void getExtensionReservedResourceDetailsReturnsEmptyListWhenDetailsNotFound() {
long extensionId = 1L;
when(extensionDetailsDao.findDetail(extensionId, ApiConstants.RESERVED_RESOURCE_DETAILS)).thenReturn(null);
List<String> result = extensionsManager.getExtensionReservedResourceDetails(extensionId);
assertNotNull(result);
assertTrue(result.isEmpty());
}
@Test
public void getExtensionReservedResourceDetailsReturnsEmptyListWhenValueIsBlank() {
long extensionId = 2L;
ExtensionDetailsVO detailsVO = mock(ExtensionDetailsVO.class);
when(detailsVO.getValue()).thenReturn(" ");
when(extensionDetailsDao.findDetail(extensionId, ApiConstants.RESERVED_RESOURCE_DETAILS)).thenReturn(detailsVO);
List<String> result = extensionsManager.getExtensionReservedResourceDetails(extensionId);
assertNotNull(result);
assertTrue(result.isEmpty());
}
@Test
public void getExtensionReservedResourceDetailsReturnsListOfTrimmedDetails() {
long extensionId = 3L;
ExtensionDetailsVO detailsVO = mock(ExtensionDetailsVO.class);
when(detailsVO.getValue()).thenReturn(" detail1 , detail2,detail3 ");
when(extensionDetailsDao.findDetail(extensionId, ApiConstants.RESERVED_RESOURCE_DETAILS)).thenReturn(detailsVO);
List<String> result = extensionsManager.getExtensionReservedResourceDetails(extensionId);
assertNotNull(result);
assertEquals(3, result.size());
assertEquals("detail1", result.get(0));
assertEquals("detail2", result.get(1));
assertEquals("detail3", result.get(2));
}
@Test
public void getExtensionReservedResourceDetailsHandlesEmptyPartsGracefully() {
long extensionId = 4L;
ExtensionDetailsVO detailsVO = mock(ExtensionDetailsVO.class);
when(detailsVO.getValue()).thenReturn("detail1,,detail2, ,detail3");
when(extensionDetailsDao.findDetail(extensionId, ApiConstants.RESERVED_RESOURCE_DETAILS)).thenReturn(detailsVO);
List<String> result = extensionsManager.getExtensionReservedResourceDetails(extensionId);
assertNotNull(result);
assertEquals(3, result.size());
assertEquals("detail1", result.get(0));
assertEquals("detail2", result.get(1));
assertEquals("detail3", result.get(2));
}
@Test
public void getExtensionReservedResourceDetailsReturnsEmptyListWhenSplitResultsInNoParts() {
long extensionId = 5L;
ExtensionDetailsVO detailsVO = mock(ExtensionDetailsVO.class);
when(detailsVO.getValue()).thenReturn(",");
when(extensionDetailsDao.findDetail(extensionId, ApiConstants.RESERVED_RESOURCE_DETAILS)).thenReturn(detailsVO);
List<String> result = extensionsManager.getExtensionReservedResourceDetails(extensionId);
assertNotNull(result);
assertTrue(result.isEmpty());
}
@Test
public void addInbuiltExtensionReservedResourceDetailsDoesNothingWhenExtensionNotFound() {
when(extensionDao.findById(1L)).thenReturn(null);
List<String> reservedResourceDetails = new ArrayList<>();
extensionsManager.addInbuiltExtensionReservedResourceDetails(1L, reservedResourceDetails);
assertTrue(reservedResourceDetails.isEmpty());
}
@Test
public void addInbuiltExtensionReservedResourceDetailsDoesNothingForUserDefinedExtension() {
ExtensionVO extension = mock(ExtensionVO.class);
when(extension.isUserDefined()).thenReturn(true);
when(extensionDao.findById(2L)).thenReturn(extension);
List<String> reservedResourceDetails = new ArrayList<>();
reservedResourceDetails.add("existing-detail");
extensionsManager.addInbuiltExtensionReservedResourceDetails(2L, reservedResourceDetails);
assertEquals(1, reservedResourceDetails.size());
assertTrue(reservedResourceDetails.contains("existing-detail"));
}
@Test
public void addInbuiltExtensionReservedResourceDetailsDoesNothingWhenNoMatchFound() {
ExtensionVO extension = mock(ExtensionVO.class);
when(extension.isUserDefined()).thenReturn(false);
when(extension.getName()).thenReturn("no-such-inbuilt-key-expected");
when(extensionDao.findById(3L)).thenReturn(extension);
List<String> reservedResourceDetails = new ArrayList<>();
extensionsManager.addInbuiltExtensionReservedResourceDetails(3L, reservedResourceDetails);
assertTrue(reservedResourceDetails.isEmpty());
}
@Test
public void addInbuiltExtensionReservedResourceDetailsAddedDetails() {
ExtensionVO extension = mock(ExtensionVO.class);
when(extension.isUserDefined()).thenReturn(false);
Map.Entry<String, List<String>> entry =
ExtensionsManagerImpl.INBUILT_RESERVED_RESOURCE_DETAILS.entrySet().iterator().next();
when(extension.getName()).thenReturn(entry.getKey());
when(extensionDao.findById(3L)).thenReturn(extension);
List<String> reservedResourceDetails = new ArrayList<>();
extensionsManager.addInbuiltExtensionReservedResourceDetails(3L, reservedResourceDetails);
assertFalse(reservedResourceDetails.isEmpty());
assertEquals(reservedResourceDetails.size(), entry.getValue().size());
assertTrue(reservedResourceDetails.containsAll(entry.getValue()));
}
}

View File

@ -106,7 +106,6 @@ public class BareMetalTemplateAdapter extends TemplateAdapterBase implements Tem
}
}
_resourceLimitMgr.incrementResourceCount(profile.getAccountId(), ResourceType.template);
return template;
}

View File

@ -24,6 +24,8 @@ import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
@ -98,6 +100,51 @@ public class MinIOObjectStoreDriverImpl extends BaseObjectStoreDriverImpl {
return String.format("%s-%s", ACS_PREFIX, account.getUuid());
}
private void updateCannedPolicy(long storeId, Account account, String excludeBucket) {
List<BucketVO> buckets = _bucketDao.listByObjectStoreIdAndAccountId(storeId, account.getId());
String resources = buckets.stream()
.map(BucketVO::getName)
.filter(name -> !Objects.equals(name, excludeBucket))
.map(name -> "\"arn:aws:s3:::" + name + "/*\"")
.collect(Collectors.joining(",\n"));
String policy;
if (resources.isEmpty()) {
// Resource cannot be empty in a canned Policy so deny access to all resources if the user has no buckets
policy = " {\n" +
" \"Statement\": [\n" +
" {\n" +
" \"Action\": \"s3:*\",\n" +
" \"Effect\": \"Deny\",\n" +
" \"Resource\": [\"arn:aws:s3:::*\", \"arn:aws:s3:::*/*\"]\n" +
" }\n" +
" ],\n" +
" \"Version\": \"2012-10-17\"\n" +
" }";
} else {
policy = " {\n" +
" \"Statement\": [\n" +
" {\n" +
" \"Action\": \"s3:*\",\n" +
" \"Effect\": \"Allow\",\n" +
" \"Resource\": [" + resources + "]\n" +
" }\n" +
" ],\n" +
" \"Version\": \"2012-10-17\"\n" +
" }";
}
MinioAdminClient minioAdminClient = getMinIOAdminClient(storeId);
String policyName = getUserOrAccessKeyForAccount(account) + "-policy";
String userName = getUserOrAccessKeyForAccount(account);
try {
minioAdminClient.addCannedPolicy(policyName, policy);
minioAdminClient.setPolicy(userName, false, policyName);
} catch (NoSuchAlgorithmException | IOException | InvalidKeyException e) {
throw new CloudRuntimeException(e);
}
}
@Override
public Bucket createBucket(Bucket bucket, boolean objectLock) {
//ToDo Client pool mgmt
@ -125,33 +172,8 @@ public class MinIOObjectStoreDriverImpl extends BaseObjectStoreDriverImpl {
throw new CloudRuntimeException(e);
}
List<BucketVO> buckets = _bucketDao.listByObjectStoreIdAndAccountId(storeId, accountId);
StringBuilder resources_builder = new StringBuilder();
for(BucketVO exitingBucket : buckets) {
resources_builder.append("\"arn:aws:s3:::"+exitingBucket.getName()+"/*\",\n");
}
resources_builder.append("\"arn:aws:s3:::"+bucketName+"/*\"\n");
updateCannedPolicy(storeId, account,null);
String policy = " {\n" +
" \"Statement\": [\n" +
" {\n" +
" \"Action\": \"s3:*\",\n" +
" \"Effect\": \"Allow\",\n" +
" \"Principal\": \"*\",\n" +
" \"Resource\": ["+resources_builder+"]" +
" }\n" +
" ],\n" +
" \"Version\": \"2012-10-17\"\n" +
" }";
MinioAdminClient minioAdminClient = getMinIOAdminClient(storeId);
String policyName = getUserOrAccessKeyForAccount(account) + "-policy";
String userName = getUserOrAccessKeyForAccount(account);
try {
minioAdminClient.addCannedPolicy(policyName, policy);
minioAdminClient.setPolicy(userName, false, policyName);
} catch (Exception e) {
throw new CloudRuntimeException(e);
}
String accessKey = _accountDetailsDao.findDetail(accountId, MINIO_ACCESS_KEY).getValue();
String secretKey = _accountDetailsDao.findDetail(accountId, MINIO_SECRET_KEY).getValue();
ObjectStoreVO store = _storeDao.findById(storeId);
@ -183,6 +205,8 @@ public class MinIOObjectStoreDriverImpl extends BaseObjectStoreDriverImpl {
@Override
public boolean deleteBucket(BucketTO bucket, long storeId) {
String bucketName = bucket.getName();
long accountId = bucket.getAccountId();
Account account = _accountDao.findById(accountId);
MinioClient minioClient = getMinIOClient(storeId);
try {
if(!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
@ -197,6 +221,9 @@ public class MinIOObjectStoreDriverImpl extends BaseObjectStoreDriverImpl {
} catch (Exception e) {
throw new CloudRuntimeException(e);
}
updateCannedPolicy(storeId, account, bucketName);
return true;
}

View File

@ -129,10 +129,15 @@ public class MinIOObjectStoreDriverImplTest {
@Test
public void testDeleteBucket() throws Exception {
String bucketName = "test-bucket";
BucketTO bucket = new BucketTO(bucketName);
BucketVO bucketVO = new BucketVO(1L, 1L, 1L, bucketName, 1, false, false, false, null);
BucketTO bucket = new BucketTO(bucketVO);
when(accountDao.findById(1L)).thenReturn(account);
when(account.getUuid()).thenReturn(UUID.randomUUID().toString());
when(bucketDao.listByObjectStoreIdAndAccountId(anyLong(), anyLong())).thenReturn(new ArrayList<BucketVO>());
doReturn(minioClient).when(minioObjectStoreDriverImpl).getMinIOClient(anyLong());
when(minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())).thenReturn(true);
doNothing().when(minioClient).removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
doReturn(minioAdminClient).when(minioObjectStoreDriverImpl).getMinIOAdminClient(anyLong());
boolean success = minioObjectStoreDriverImpl.deleteBucket(bucket, 1L);
assertTrue(success);
verify(minioClient, times(1)).bucketExists(any());

View File

@ -2289,6 +2289,10 @@ public class ApiDBUtils {
return s_accountService.isAdmin(account.getId());
}
public static Account getSystemAccount() {
return s_accountService.getSystemAccount();
}
public static List<ResourceTagJoinVO> listResourceTagViewByResourceUUID(String resourceUUID, ResourceObjectType resourceType) {
return s_tagJoinDao.listBy(resourceUUID, resourceType);
}

View File

@ -17,14 +17,13 @@
package com.cloud.api.query.dao;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
@ -34,8 +33,6 @@ import java.util.stream.Collectors;
import javax.inject.Inject;
import com.cloud.gpu.dao.VgpuProfileDao;
import com.cloud.service.dao.ServiceOfferingDao;
import org.apache.cloudstack.affinity.AffinityGroupResponse;
import org.apache.cloudstack.annotation.AnnotationService;
import org.apache.cloudstack.annotation.dao.AnnotationDao;
@ -49,6 +46,7 @@ import org.apache.cloudstack.api.response.SecurityGroupResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.api.response.VnfNicResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.extension.ExtensionHelper;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.query.QueryService;
import org.apache.cloudstack.vm.lease.VMLeaseManager;
@ -61,11 +59,13 @@ import com.cloud.api.ApiDBUtils;
import com.cloud.api.ApiResponseHelper;
import com.cloud.api.query.vo.UserVmJoinVO;
import com.cloud.gpu.GPU;
import com.cloud.gpu.dao.VgpuProfileDao;
import com.cloud.host.ControlState;
import com.cloud.network.IpAddress;
import com.cloud.network.vpc.VpcVO;
import com.cloud.network.vpc.dao.VpcDao;
import com.cloud.service.ServiceOfferingDetailsVO;
import com.cloud.service.dao.ServiceOfferingDao;
import com.cloud.storage.DiskOfferingVO;
import com.cloud.storage.GuestOS;
import com.cloud.storage.Storage.TemplateType;
@ -94,7 +94,6 @@ import com.cloud.vm.VirtualMachine.State;
import com.cloud.vm.VmStats;
import com.cloud.vm.dao.NicExtraDhcpOptionDao;
import com.cloud.vm.dao.NicSecondaryIpVO;
import com.cloud.vm.dao.VMInstanceDetailsDao;
@Component
@ -128,6 +127,8 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
private VgpuProfileDao vgpuProfileDao;
@Inject
VMTemplateDao vmTemplateDao;
@Inject
ExtensionHelper extensionHelper;
private final SearchBuilder<UserVmJoinVO> VmDetailSearch;
private final SearchBuilder<UserVmJoinVO> activeVmByIsoSearch;
@ -460,7 +461,16 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
// Remove deny listed settings if user is not admin
if (caller.getType() != Account.Type.ADMIN) {
String[] userVmSettingsToHide = QueryService.UserVMDeniedDetails.value().split(",");
List<String> userVmSettingsToHide = new ArrayList<>();
String[] parts = QueryService.UserVMDeniedDetails.value().split(",");
if (parts.length > 0) {
Collections.addAll(userVmSettingsToHide, parts);
}
if (userVm.getTemplateExtensionId() != null) {
userVmSettingsToHide.addAll(extensionHelper.getExtensionReservedResourceDetails(
userVm.getTemplateExtensionId()));
}
for (String key : userVmSettingsToHide) {
resourceDetails.remove(key.trim());
}
@ -520,7 +530,6 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
return userVmResponse;
}
private long computeLeaseDurationFromExpiryDate(Date created, Date leaseExpiryDate) {
LocalDate createdDate = created.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
LocalDate expiryDate = leaseExpiryDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
@ -556,7 +565,7 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
/**
* The resulting Response attempts to be in line with what is returned from
* @see com.cloud.api.ApiResponseHelper#createNicResponse(Nic)
* @see com.cloud.api.ApiResponseHelper#{code}createNicResponse(Nic){code}
*/
@Override
public UserVmResponse setUserVmResponse(ResponseView view, UserVmResponse userVmData, UserVmJoinVO uvo) {

View File

@ -207,6 +207,9 @@ public class UserVmJoinVO extends BaseViewWithTagInformationVO implements Contro
@Column(name = "template_format")
private Storage.ImageFormat templateFormat;
@Column(name = "template_extension_id")
private Long templateExtensionId;
@Column(name = "password_enabled")
private boolean passwordEnabled;
@ -709,6 +712,10 @@ public class UserVmJoinVO extends BaseViewWithTagInformationVO implements Contro
return templateFormat;
}
public Long getTemplateExtensionId() {
return templateExtensionId;
}
public boolean isPasswordEnabled() {
return passwordEnabled;
}

View File

@ -123,6 +123,7 @@ import org.apache.cloudstack.region.PortableIpVO;
import org.apache.cloudstack.region.Region;
import org.apache.cloudstack.region.RegionVO;
import org.apache.cloudstack.region.dao.RegionDao;
import org.apache.cloudstack.reservation.dao.ReservationDao;
import org.apache.cloudstack.resourcedetail.DiskOfferingDetailVO;
import org.apache.cloudstack.resourcedetail.dao.DiskOfferingDetailsDao;
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
@ -264,6 +265,7 @@ import com.cloud.org.Grouping;
import com.cloud.org.Grouping.AllocationState;
import com.cloud.projects.Project;
import com.cloud.projects.ProjectManager;
import com.cloud.resourcelimit.CheckedReservation;
import com.cloud.server.ManagementService;
import com.cloud.service.ServiceOfferingDetailsVO;
import com.cloud.service.ServiceOfferingVO;
@ -408,6 +410,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
@Inject
ResourceLimitService _resourceLimitMgr;
@Inject
ReservationDao reservationDao;
@Inject
ProjectManager _projectMgr;
@Inject
NetworkOfferingServiceMapDao _ntwkOffServiceMapDao;
@ -646,7 +650,6 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
protected void populateConfigKeysAllowedOnlyForDefaultAdmin() {
configKeysAllowedOnlyForDefaultAdmin.add(AccountManagerImpl.listOfRoleTypesAllowedForOperationsOfSameRoleType.key());
configKeysAllowedOnlyForDefaultAdmin.add(AccountManagerImpl.allowOperationsOnUsersInSameAccount.key());
configKeysAllowedOnlyForDefaultAdmin.add(VirtualMachineManager.SystemVmEnableUserData.key());
configKeysAllowedOnlyForDefaultAdmin.add(ConsoleProxyManager.ConsoleProxyVmUserData.key());
configKeysAllowedOnlyForDefaultAdmin.add(SecondaryStorageVmManager.SecondaryStorageVmUserData.key());
@ -995,7 +998,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
String hypervisors = _configDao.getValue(hypervisorListConfigName);
if (Arrays.asList(hypervisors.split(",")).contains(previousValue)) {
hypervisors = hypervisors.replace(previousValue, newValue);
logger.info("Updating the hypervisor list configuration '{}}' to match the new custom hypervisor display name",
logger.info("Updating the hypervisor list configuration '{}' to match the new custom hypervisor display name",
hypervisorListConfigName);
_configDao.update(hypervisorListConfigName, hypervisors);
}
@ -5043,22 +5046,20 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
throw new InvalidParameterValueException("Gateway, netmask and zoneId have to be passed in for virtual and direct untagged networks");
}
if (forVirtualNetwork) {
if (vlanOwner != null) {
final long accountIpRange = NetUtils.ip2Long(endIP) - NetUtils.ip2Long(startIP) + 1;
// check resource limits
_resourceLimitMgr.checkResourceLimit(vlanOwner, ResourceType.public_ip, accountIpRange);
}
}
// Check if the IP range overlaps with the private ip
if (ipv4) {
checkOverlapPrivateIpRange(zoneId, startIP, endIP);
}
return commitVlan(zoneId, podId, startIP, endIP, newVlanGateway, newVlanNetmask, vlanId, forVirtualNetwork, forSystemVms, networkId, physicalNetworkId, startIPv6, endIPv6, ip6Gateway,
ip6Cidr, domain, vlanOwner, network, sameSubnet, cmd.getProvider());
long reservedIpAddressesAmount = 0L;
if (forVirtualNetwork && vlanOwner != null) {
reservedIpAddressesAmount = NetUtils.ip2Long(endIP) - NetUtils.ip2Long(startIP) + 1;
}
try (CheckedReservation publicIpReservation = new CheckedReservation(vlanOwner, ResourceType.public_ip, null, null, null, reservedIpAddressesAmount, null, reservationDao, _resourceLimitMgr)) {
return commitVlan(zoneId, podId, startIP, endIP, newVlanGateway, newVlanNetmask, vlanId, forVirtualNetwork, forSystemVms, networkId, physicalNetworkId, startIPv6, endIPv6, ip6Gateway,
ip6Cidr, domain, vlanOwner, network, sameSubnet, cmd.getProvider());
}
}
private Network getNetwork(Long networkId) {
@ -5594,7 +5595,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
ip.isSourceNat(), vlan.getVlanType().toString(), ip.getSystem(), usageHidden, ip.getClass().getName(), ip.getUuid());
}
// increment resource count for dedicated public ip's
_resourceLimitMgr.incrementResourceCount(vlanOwner.getId(), ResourceType.public_ip, new Long(ips.size()));
_resourceLimitMgr.incrementResourceCount(vlanOwner.getId(), ResourceType.public_ip, (long)ips.size());
} else if (domain != null && !forSystemVms) {
// This VLAN is domain-wide, so create a DomainVlanMapVO entry
final DomainVlanMapVO domainVlanMapVO = new DomainVlanMapVO(domain.getId(), vlan.getId());
@ -5638,7 +5639,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
String endIpv6,
String ip6Gateway,
String ip6Cidr,
Boolean forSystemVms) throws ConcurrentOperationException {
Boolean forSystemVms) throws ConcurrentOperationException, ResourceAllocationException {
VlanVO vlanRange = _vlanDao.findById(id);
if (vlanRange == null) {
@ -5658,24 +5659,49 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
}
}
AccountVlanMapVO accountMap = _accountVlanMapDao.findAccountVlanMap(null, id);
Account account = accountMap != null ? _accountDao.findById(accountMap.getAccountId()) : null;
DomainVlanMapVO domainMap = _domainVlanMapDao.findDomainVlanMap(null, id);
Long domainId = domainMap != null ? domainMap.getDomainId() : null;
final Boolean isRangeForSystemVM = checkIfVlanRangeIsForSystemVM(id);
if (forSystemVms != null && isRangeForSystemVM != forSystemVms) {
if (VlanType.DirectAttached.equals(vlanRange.getVlanType())) {
throw new InvalidParameterValueException("forSystemVms is not available for this IP range with vlan type: " + VlanType.DirectAttached);
}
// Check if range has already been dedicated
final List<AccountVlanMapVO> maps = _accountVlanMapDao.listAccountVlanMapsByVlan(id);
if (maps != null && !maps.isEmpty()) {
if (account != null) {
throw new InvalidParameterValueException("Specified Public IP range has already been dedicated to an account");
}
List<DomainVlanMapVO> domainmaps = _domainVlanMapDao.listDomainVlanMapsByVlan(id);
if (domainmaps != null && !domainmaps.isEmpty()) {
if (domainId != null) {
throw new InvalidParameterValueException("Specified Public IP range has already been dedicated to a domain");
}
}
if (ipv4) {
updateVlanAndIpv4Range(id, vlanRange, startIp, endIp, gateway, netmask, isRangeForSystemVM, forSystemVms);
long existingIpAddressAmount = 0L;
long newIpAddressAmount = 0L;
if (account != null) {
// IPv4 public range is dedicated to an account (IPv6 cannot be dedicated at the moment).
// We need to update the resource count.
existingIpAddressAmount = _publicIpAddressDao.countIPs(vlanRange.getDataCenterId(), id, false);
newIpAddressAmount = NetUtils.ip2Long(endIp) - NetUtils.ip2Long(startIp) + 1;
}
try (CheckedReservation publicIpReservation = new CheckedReservation(account, ResourceType.public_ip, null, null, null, newIpAddressAmount, existingIpAddressAmount, reservationDao, _resourceLimitMgr)) {
updateVlanAndIpv4Range(id, vlanRange, startIp, endIp, gateway, netmask, isRangeForSystemVM, forSystemVms);
if (account != null) {
long countDiff = newIpAddressAmount - existingIpAddressAmount;
if (countDiff > 0) {
_resourceLimitMgr.incrementResourceCount(account.getId(), ResourceType.public_ip, countDiff);
} else if (countDiff < 0) {
_resourceLimitMgr.decrementResourceCount(account.getId(), ResourceType.public_ip, Math.abs(countDiff));
}
}
}
}
if (ipv6) {
updateVlanAndIpv6Range(id, vlanRange, startIpv6, endIpv6, ip6Gateway, ip6Cidr, isRangeForSystemVM, forSystemVms);
@ -5954,7 +5980,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
} finally {
_vlanDao.releaseFromLockTable(vlanDbId);
if (resourceCountToBeDecrement > 0) { //Making sure to decrement the count of only success operations above. For any reaason if disassociation fails then this number will vary from original range length.
_resourceLimitMgr.decrementResourceCount(acctVln.get(0).getAccountId(), ResourceType.public_ip, new Long(resourceCountToBeDecrement));
_resourceLimitMgr.decrementResourceCount(acctVln.get(0).getAccountId(), ResourceType.public_ip, (long)resourceCountToBeDecrement);
}
}
} else { // !isAccountSpecific
@ -6062,12 +6088,6 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
throw new InvalidParameterValueException("Public IP range can be dedicated to an account only in the zone of type " + NetworkType.Advanced);
}
// Check Public IP resource limits
if (vlanOwner != null) {
final int accountPublicIpRange = _publicIpAddressDao.countIPs(zoneId, vlanDbId, false);
_resourceLimitMgr.checkResourceLimit(vlanOwner, ResourceType.public_ip, accountPublicIpRange);
}
// Check if any of the Public IP addresses is allocated to another
// account
final List<IPAddressVO> ips = _publicIpAddressDao.listByVlanId(vlanDbId);
@ -6088,29 +6108,35 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
}
}
if (vlanOwner != null) {
// Create an AccountVlanMapVO entry
final AccountVlanMapVO accountVlanMapVO = new AccountVlanMapVO(vlanOwner.getId(), vlan.getId());
_accountVlanMapDao.persist(accountVlanMapVO);
// Check Public IP resource limits
long reservedIpAddressesAmount = vlanOwner != null ? _publicIpAddressDao.countIPs(zoneId, vlanDbId, false) : 0L;
try (CheckedReservation publicIpReservation = new CheckedReservation(vlanOwner, ResourceType.public_ip, null, null, null, reservedIpAddressesAmount, null, reservationDao, _resourceLimitMgr)) {
// generate usage event for dedication of every ip address in the range
for (final IPAddressVO ip : ips) {
final boolean usageHidden = _ipAddrMgr.isUsageHidden(ip);
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_ASSIGN, vlanOwner.getId(), ip.getDataCenterId(), ip.getId(), ip.getAddress().toString(), ip.isSourceNat(),
vlan.getVlanType().toString(), ip.getSystem(), usageHidden, ip.getClass().getName(), ip.getUuid());
if (vlanOwner != null) {
// Create an AccountVlanMapVO entry
final AccountVlanMapVO accountVlanMapVO = new AccountVlanMapVO(vlanOwner.getId(), vlan.getId());
_accountVlanMapDao.persist(accountVlanMapVO);
// generate usage event for dedication of every ip address in the range
for (final IPAddressVO ip : ips) {
final boolean usageHidden = _ipAddrMgr.isUsageHidden(ip);
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_ASSIGN, vlanOwner.getId(), ip.getDataCenterId(), ip.getId(), ip.getAddress().toString(), ip.isSourceNat(),
vlan.getVlanType().toString(), ip.getSystem(), usageHidden, ip.getClass().getName(), ip.getUuid());
}
} else if (domain != null) {
// Create an DomainVlanMapVO entry
DomainVlanMapVO domainVlanMapVO = new DomainVlanMapVO(domain.getId(), vlan.getId());
_domainVlanMapDao.persist(domainVlanMapVO);
}
} else if (domain != null) {
// Create an DomainVlanMapVO entry
DomainVlanMapVO domainVlanMapVO = new DomainVlanMapVO(domain.getId(), vlan.getId());
_domainVlanMapDao.persist(domainVlanMapVO);
}
// increment resource count for dedicated public ip's
if (vlanOwner != null) {
_resourceLimitMgr.incrementResourceCount(vlanOwner.getId(), ResourceType.public_ip, new Long(ips.size()));
}
// increment resource count for dedicated public ip's
if (vlanOwner != null) {
_resourceLimitMgr.incrementResourceCount(vlanOwner.getId(), ResourceType.public_ip, (long)ips.size());
}
return vlan;
return vlan;
}
}
@Override
@ -6199,7 +6225,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
}
}
// decrement resource count for dedicated public ip's
_resourceLimitMgr.decrementResourceCount(acctVln.get(0).getAccountId(), ResourceType.public_ip, new Long(ips.size()));
_resourceLimitMgr.decrementResourceCount(acctVln.get(0).getAccountId(), ResourceType.public_ip, (long)ips.size());
success = true;
} else if (isDomainSpecific && _domainVlanMapDao.remove(domainVlan.get(0).getId())) {
logger.debug("Remove the vlan from domain_vlan_map successfully.");
@ -6368,7 +6394,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
final List<Object> newCidrPair = new ArrayList<>();
newCidrPair.add(0, getCidrAddress(cidr));
newCidrPair.add(1, (long)getCidrSize(cidr));
currentPodCidrSubnets.put(new Long(-1), newCidrPair);
currentPodCidrSubnets.put(-1L, newCidrPair);
final DataCenterVO dcVo = _zoneDao.findById(dcId);
final String guestNetworkCidr = dcVo.getGuestNetworkCidr();
@ -6468,7 +6494,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
}
private String getPodName(final long podId) {
return _podDao.findById(new Long(podId)).getName();
return _podDao.findById(podId).getName();
}
private boolean validZone(final String zoneName) {
@ -6480,7 +6506,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
}
private String getZoneName(final long zoneId) {
final DataCenterVO zone = _zoneDao.findById(new Long(zoneId));
final DataCenterVO zone = _zoneDao.findById(zoneId);
if (zone != null) {
return zone.getName();
} else {

View File

@ -41,6 +41,7 @@ import java.util.UUID;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import com.cloud.resourcelimit.CheckedReservation;
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import org.apache.cloudstack.alert.AlertService;
@ -76,6 +77,7 @@ import org.apache.cloudstack.network.NetworkPermissionVO;
import org.apache.cloudstack.network.RoutedIpv4Manager;
import org.apache.cloudstack.network.dao.NetworkPermissionDao;
import org.apache.cloudstack.network.element.InternalLoadBalancerElementService;
import org.apache.cloudstack.reservation.dao.ReservationDao;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.BooleanUtils;
@ -335,6 +337,8 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
@Inject
ResourceLimitService _resourceLimitMgr;
@Inject
ReservationDao reservationDao;
@Inject
DomainManager _domainMgr;
@Inject
ProjectManager _projectMgr;
@ -1152,15 +1156,10 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
if (ipDedicatedAccountId != null && !ipDedicatedAccountId.equals(account.getAccountId())) {
throw new InvalidParameterValueException("Unable to reserve a IP because it is dedicated to another Account.");
}
if (ipDedicatedAccountId == null) {
// Check that the maximum number of public IPs for the given accountId will not be exceeded
try {
_resourceLimitMgr.checkResourceLimit(account, Resource.ResourceType.public_ip);
} catch (ResourceAllocationException ex) {
logger.warn("Failed to allocate resource of type " + ex.getResourceType() + " for account " + account);
throw new AccountLimitException("Maximum number of public IP addresses for account: " + account.getAccountName() + " has been exceeded.");
}
}
long reservedIpAddressesAmount = ipDedicatedAccountId == null ? 1L : 0L;
try (CheckedReservation publicIpAddressReservation = new CheckedReservation(account, Resource.ResourceType.public_ip, reservedIpAddressesAmount, reservationDao, _resourceLimitMgr)) {
List<AccountVlanMapVO> maps = _accountVlanMapDao.listAccountVlanMapsByVlan(ipVO.getVlanId());
ipVO.setAllocatedTime(new Date());
ipVO.setAllocatedToAccountId(account.getAccountId());
@ -1170,10 +1169,15 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
ipVO.setDisplay(displayIp);
}
ipVO = _ipAddressDao.persist(ipVO);
if (ipDedicatedAccountId == null) {
if (reservedIpAddressesAmount > 0) {
_resourceLimitMgr.incrementResourceCount(account.getId(), Resource.ResourceType.public_ip);
}
return ipVO;
} catch (ResourceAllocationException ex) {
logger.warn("Failed to allocate resource of type " + ex.getResourceType() + " for account " + account);
throw new AccountLimitException("Maximum number of public IP addresses for account: " + account.getAccountName() + " has been exceeded.");
}
}
@Override
@ -3209,7 +3213,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
if (displayNetwork != null && displayNetwork != network.getDisplayNetwork()) {
// Update resource count if it needs to be updated
NetworkOffering networkOffering = _networkOfferingDao.findById(network.getNetworkOfferingId());
if (_networkMgr.resourceCountNeedsUpdate(networkOffering, network.getAclType())) {
if (_networkMgr.isResourceCountUpdateNeeded(networkOffering)) {
_resourceLimitMgr.changeResourceCount(network.getAccountId(), Resource.ResourceType.network, displayNetwork);
}

View File

@ -42,29 +42,8 @@ import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import com.cloud.configuration.ConfigurationManager;
import com.cloud.configuration.ConfigurationManagerImpl;
import com.cloud.bgp.BGPService;
import com.cloud.dc.ASNumberVO;
import com.cloud.dc.dao.ASNumberDao;
import com.cloud.dc.Vlan;
import com.cloud.network.RemoteAccessVpn;
import com.cloud.network.Site2SiteVpnConnection;
import com.cloud.network.dao.NetrisProviderDao;
import com.cloud.network.dao.NsxProviderDao;
import com.cloud.network.dao.RemoteAccessVpnDao;
import com.cloud.network.dao.RemoteAccessVpnVO;
import com.cloud.network.dao.Site2SiteCustomerGatewayDao;
import com.cloud.network.dao.Site2SiteCustomerGatewayVO;
import com.cloud.network.dao.Site2SiteVpnConnectionDao;
import com.cloud.network.dao.Site2SiteVpnConnectionVO;
import com.cloud.network.element.NetrisProviderVO;
import com.cloud.network.element.NetworkACLServiceProvider;
import com.cloud.network.element.NsxProviderVO;
import com.cloud.network.rules.RulesManager;
import com.cloud.network.vpn.RemoteAccessVpnService;
import com.cloud.vm.dao.VMInstanceDao;
import com.google.common.collect.Sets;
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
import org.apache.cloudstack.alert.AlertService;
import org.apache.cloudstack.annotation.AnnotationService;
@ -106,12 +85,18 @@ import com.cloud.agent.manager.Commands;
import com.cloud.alert.AlertManager;
import com.cloud.api.query.dao.VpcOfferingJoinDao;
import com.cloud.api.query.vo.VpcOfferingJoinVO;
import com.cloud.bgp.BGPService;
import com.cloud.configuration.Config;
import com.cloud.configuration.ConfigurationManager;
import com.cloud.configuration.ConfigurationManagerImpl;
import com.cloud.configuration.Resource.ResourceType;
import com.cloud.dc.ASNumberVO;
import com.cloud.dc.DataCenter;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.Vlan.VlanType;
import com.cloud.dc.Vlan;
import com.cloud.dc.VlanVO;
import com.cloud.dc.dao.ASNumberDao;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.dc.dao.VlanDao;
import com.cloud.deploy.DeployDestination;
@ -141,18 +126,33 @@ import com.cloud.network.NetworkService;
import com.cloud.network.Networks.BroadcastDomainType;
import com.cloud.network.Networks.TrafficType;
import com.cloud.network.PhysicalNetwork;
import com.cloud.network.RemoteAccessVpn;
import com.cloud.network.Site2SiteVpnConnection;
import com.cloud.network.addr.PublicIp;
import com.cloud.network.dao.FirewallRulesDao;
import com.cloud.network.dao.IPAddressDao;
import com.cloud.network.dao.IPAddressVO;
import com.cloud.network.dao.NetworkDao;
import com.cloud.network.dao.NetworkVO;
import com.cloud.network.dao.NetrisProviderDao;
import com.cloud.network.dao.NsxProviderDao;
import com.cloud.network.dao.RemoteAccessVpnDao;
import com.cloud.network.dao.RemoteAccessVpnVO;
import com.cloud.network.dao.Site2SiteCustomerGatewayDao;
import com.cloud.network.dao.Site2SiteCustomerGatewayVO;
import com.cloud.network.dao.Site2SiteVpnConnectionDao;
import com.cloud.network.dao.Site2SiteVpnConnectionVO;
import com.cloud.network.element.NetrisProviderVO;
import com.cloud.network.element.NetworkACLServiceProvider;
import com.cloud.network.element.NetworkElement;
import com.cloud.network.element.NsxProviderVO;
import com.cloud.network.element.StaticNatServiceProvider;
import com.cloud.network.element.VpcProvider;
import com.cloud.network.router.CommandSetupHelper;
import com.cloud.network.router.NetworkHelper;
import com.cloud.network.router.VpcVirtualNetworkApplianceManager;
import com.cloud.network.rules.RulesManager;
import com.cloud.network.vpn.RemoteAccessVpnService;
import com.cloud.network.vpc.VpcOffering.State;
import com.cloud.network.vpc.dao.NetworkACLDao;
import com.cloud.network.vpc.dao.PrivateIpDao;
@ -171,6 +171,7 @@ import com.cloud.offerings.dao.NetworkOfferingDao;
import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
import com.cloud.org.Grouping;
import com.cloud.projects.Project.ListProjectResourcesCriteria;
import com.cloud.resourcelimit.CheckedReservation;
import com.cloud.server.ResourceTag.ResourceObjectType;
import com.cloud.tags.ResourceTagVO;
import com.cloud.tags.dao.ResourceTagDao;
@ -207,6 +208,7 @@ import com.cloud.vm.ReservationContextImpl;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.dao.DomainRouterDao;
import com.cloud.vm.dao.NicDao;
import com.cloud.vm.dao.VMInstanceDao;
import static com.cloud.offering.NetworkOffering.RoutingMode.Dynamic;
@ -1220,9 +1222,6 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
// Verify that caller can perform actions in behalf of vpc owner
_accountMgr.checkAccess(caller, null, false, owner);
// check resource limit
_resourceLimitMgr.checkResourceLimit(owner, ResourceType.vpc);
// Validate zone
final DataCenter zone = _dcDao.findById(zoneId);
if (zone == null) {
@ -1317,6 +1316,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
vpc.setDisplay(Boolean.TRUE.equals(displayVpc));
vpc.setUseRouterIpResolver(Boolean.TRUE.equals(useVrIpResolver));
try (CheckedReservation vpcReservation = new CheckedReservation(owner, ResourceType.vpc, null, null, 1L, reservationDao, _resourceLimitMgr)) {
if (vpc.getCidr() == null && cidrSize != null) {
// Allocate a CIDR for VPC
Ipv4GuestSubnetNetworkMap subnet = routedIpv4Manager.getOrCreateIpv4SubnetForVpc(vpc, cidrSize);
@ -1336,6 +1336,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
routedIpv4Manager.persistBgpPeersForVpc(newVpc.getId(), bgpPeerIds);
}
return newVpc;
}
}
private void validateVpcCidrSize(Account caller, long accountId, VpcOffering vpcOffering, String cidr, Integer cidrSize, long zoneId) {

View File

@ -36,6 +36,7 @@ import javax.inject.Inject;
import javax.mail.MessagingException;
import javax.naming.ConfigurationException;
import com.cloud.resourcelimit.CheckedReservation;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.ProjectRole;
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
@ -47,6 +48,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.utils.mailing.MailAddress;
import org.apache.cloudstack.utils.mailing.SMTPMailProperties;
import org.apache.cloudstack.utils.mailing.SMTPMailSender;
@ -159,6 +161,8 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager, C
private VpcManager _vpcMgr;
@Inject
MessageBus messageBus;
@Inject
private ReservationDao reservationDao;
protected boolean _invitationRequired = false;
protected long _invitationTimeOut = 86400000;
@ -272,8 +276,7 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager, C
owner = _accountDao.findById(user.getAccountId());
}
//do resource limit check
_resourceLimitMgr.checkResourceLimit(owner, ResourceType.project);
try (CheckedReservation projectReservation = new CheckedReservation(owner, ResourceType.project, null, null, 1L, reservationDao, _resourceLimitMgr)) {
final Account ownerFinal = owner;
User finalUser = user;
@ -308,6 +311,7 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager, C
messageBus.publish(_name, ProjectManager.MESSAGE_CREATE_TUNGSTEN_PROJECT_EVENT, PublishScope.LOCAL, project);
return project;
}
}
@Override
@ -491,6 +495,9 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager, C
//remove account
ProjectAccountVO projectAccount = _projectAccountDao.findByProjectIdAccountId(projectId, account.getId());
success = _projectAccountDao.remove(projectAccount.getId());
if (projectAccount.getAccountRole() == Role.Admin) {
_resourceLimitMgr.decrementResourceCount(account.getId(), ResourceType.project);
}
//remove all invitations for account
if (success) {
@ -537,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);
@ -594,12 +601,20 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager, C
if (username == null) {
throw new InvalidParameterValueException("User information (ID) is required to add user to the project");
}
boolean shouldIncrementResourceCount = projectRole != null && Role.Admin == projectRole;
try (CheckedReservation cr = new CheckedReservation(userAccount, ResourceType.project, shouldIncrementResourceCount ? 1L : 0L, reservationDao, _resourceLimitMgr)) {
if (assignUserToProject(project, user.getId(), user.getAccountId(), projectRole,
Optional.ofNullable(role).map(ProjectRole::getId).orElse(null)) != null) {
if (shouldIncrementResourceCount) {
_resourceLimitMgr.incrementResourceCount(userAccount.getId(), ResourceType.project);
}
return true;
} else {
logger.warn("Failed to add user to project: {}", project);
return false;
}
}
logger.warn("Failed to add user to project: {}", project);
return false;
}
}
@ -652,14 +667,18 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager, C
}
private void updateProjectAccount(ProjectAccountVO futureOwner, Role newAccRole, Long accountId) throws ResourceAllocationException {
_resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(accountId), ResourceType.project);
Account account = _accountMgr.getAccount(accountId);
boolean shouldIncrementResourceCount = Role.Admin == newAccRole;
try (CheckedReservation checkedReservation = new CheckedReservation(account, ResourceType.project, shouldIncrementResourceCount ? 1L : 0L, reservationDao, _resourceLimitMgr)) {
futureOwner.setAccountRole(newAccRole);
_projectAccountDao.update(futureOwner.getId(), futureOwner);
if (newAccRole != null && Role.Admin == newAccRole) {
if (shouldIncrementResourceCount) {
_resourceLimitMgr.incrementResourceCount(accountId, ResourceType.project);
} else {
_resourceLimitMgr.decrementResourceCount(accountId, ResourceType.project);
}
}
}
@Override
@ -701,9 +720,7 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager, C
" doesn't belong to the project. Add it to the project first and then change the project's ownership");
}
//do resource limit check
_resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(futureOwnerAccount.getId()), ResourceType.project);
try (CheckedReservation checkedReservation = new CheckedReservation(futureOwnerAccount, ResourceType.project, null, null, 1L, reservationDao, _resourceLimitMgr)) {
//unset the role for the old owner
ProjectAccountVO currentOwner = _projectAccountDao.findByProjectIdAccountId(projectId, currentOwnerAccount.getId());
currentOwner.setAccountRole(Role.Regular);
@ -714,7 +731,7 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager, C
futureOwner.setAccountRole(Role.Admin);
_projectAccountDao.update(futureOwner.getId(), futureOwner);
_resourceLimitMgr.incrementResourceCount(futureOwnerAccount.getId(), ResourceType.project);
}
} else {
logger.trace("Future owner {}is already the owner of the project {}", newOwnerName, project);
}
@ -792,7 +809,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
@ -857,13 +874,20 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager, C
if (account == null) {
throw new InvalidParameterValueException("Account information is required for assigning account to the project");
}
boolean shouldIncrementResourceCount = projectRoleType != null && Role.Admin == projectRoleType;
try (CheckedReservation cr = new CheckedReservation(account, ResourceType.project, shouldIncrementResourceCount ? 1L : 0L, reservationDao, _resourceLimitMgr)) {
if (assignAccountToProject(project, account.getId(), projectRoleType, null,
Optional.ofNullable(projectRole).map(ProjectRole::getId).orElse(null)) != null) {
if (shouldIncrementResourceCount) {
_resourceLimitMgr.incrementResourceCount(account.getId(), ResourceType.project);
}
return true;
} else {
logger.warn("Failed to add account {} to project {}", accountName, project);
return false;
}
}
}
}
@ -1042,7 +1066,9 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager, C
boolean success = true;
ProjectAccountVO projectAccount = _projectAccountDao.findByProjectIdUserId(projectId, user.getAccountId(), user.getId());
success = _projectAccountDao.remove(projectAccount.getId());
if (projectAccount.getAccountRole() == Role.Admin) {
_resourceLimitMgr.decrementResourceCount(user.getAccountId(), ResourceType.project);
}
if (success) {
logger.debug("Removed user {} from project. Removing any invite sent to the user", user);
ProjectInvitation invite = _projectInvitationDao.findByUserIdProjectId(user.getId(), user.getAccountId(), projectId);

View File

@ -20,13 +20,17 @@ package com.cloud.resourcelimit;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import com.cloud.api.ApiDBUtils;
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;
@ -40,7 +44,7 @@ import com.cloud.utils.db.GlobalLock;
import com.cloud.utils.exception.CloudRuntimeException;
public class CheckedReservation implements AutoCloseable {
public class CheckedReservation implements Reserver {
protected Logger logger = LogManager.getLogger(getClass());
private static final int TRY_TO_GET_LOCK_TIME = 120;
@ -48,11 +52,15 @@ public class CheckedReservation implements AutoCloseable {
ReservationDao reservationDao;
ResourceLimitService resourceLimitService;
private final Account account;
private final ResourceType resourceType;
private Long amount;
private Account account;
private Long domainId;
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);
@ -73,12 +81,12 @@ public class CheckedReservation implements AutoCloseable {
this.reservations = null;
}
protected void checkLimitAndPersistReservations(Account account, ResourceType resourceType, Long resourceId, List<String> resourceLimitTags, Long amount) throws ResourceAllocationException {
protected void checkLimitAndPersistReservations(Account account, Long domainId, ResourceType resourceType, Long resourceId, List<String> resourceLimitTags, Long amount) throws ResourceAllocationException {
try {
checkLimitAndPersistReservation(account, resourceType, resourceId, null, amount);
checkLimitAndPersistReservation(account, domainId, resourceType, resourceId, null, amount);
if (CollectionUtils.isNotEmpty(resourceLimitTags)) {
for (String tag : resourceLimitTags) {
checkLimitAndPersistReservation(account, resourceType, resourceId, tag, amount);
checkLimitAndPersistReservation(account, domainId, resourceType, resourceId, tag, amount);
}
}
} catch (ResourceAllocationException rae) {
@ -87,11 +95,11 @@ public class CheckedReservation implements AutoCloseable {
}
}
protected void checkLimitAndPersistReservation(Account account, ResourceType resourceType, Long resourceId, String tag, Long amount) throws ResourceAllocationException {
protected void checkLimitAndPersistReservation(Account account, Long domainId, ResourceType resourceType, Long resourceId, String tag, Long amount) throws ResourceAllocationException {
if (amount > 0) {
resourceLimitService.checkResourceLimitWithTag(account, resourceType, tag, amount);
resourceLimitService.checkResourceLimitWithTag(account, domainId, true, resourceType, tag, amount);
}
ReservationVO reservationVO = new ReservationVO(account.getAccountId(), account.getDomainId(), resourceType, tag, amount);
ReservationVO reservationVO = new ReservationVO(account.getAccountId(), domainId, resourceType, tag, amount);
if (resourceId != null) {
reservationVO.setResourceId(resourceId);
}
@ -99,9 +107,25 @@ public class CheckedReservation implements AutoCloseable {
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);
}
/**
@ -109,25 +133,48 @@ public class CheckedReservation implements AutoCloseable {
* - 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 {
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;
}
this.reservationDao = reservationDao;
this.resourceLimitService = resourceLimitService;
this.account = account;
this.resourceType = resourceType;
this.amount = amount;
this.reservations = new ArrayList<>();
this.resourceLimitTags = resourceLimitTags;
if (this.amount != null && this.amount != 0) {
if (amount > 0) {
// When allocating to a domain instead of a specific account, consider the system account as the owner for the validations here.
if (account == null) {
account = ApiDBUtils.getSystemAccount();
}
this.account = account;
if (domainId == null) {
domainId = account.getDomainId();
}
this.domainId = domainId;
this.resourceType = resourceType;
this.reservationAmount = reservationAmount;
this.existingAmount = existingAmount;
this.reservations = new ArrayList<>();
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, 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);
@ -138,14 +185,28 @@ public class CheckedReservation implements AutoCloseable {
throw new ResourceAllocationException(String.format("unable to acquire resource reservation \"%s\"", quotaLimitLock.getName()), resourceType);
}
} else {
checkLimitAndPersistReservations(account, 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: {}",
account.getAccountName(), account.getDomainId(), resourceType, getResourceLimitTagsAsString());
account.getAccountName(), this.domainId, resourceType, getResourceLimitTagsAsString());
}
}
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);
@ -153,7 +214,7 @@ public class CheckedReservation implements AutoCloseable {
@NotNull
private void setGlobalLock() {
String lockName = String.format("CheckedReservation-%s/%d", account.getDomainId(), resourceType.getOrdinal());
String lockName = String.format("CheckedReservation-%s/%d", this.domainId, resourceType.getOrdinal());
setQuotaLimitLock(GlobalLock.getInternLock(lockName));
}
@ -162,7 +223,7 @@ public class CheckedReservation implements AutoCloseable {
}
@Override
public void close() throws Exception {
public void close() {
removeAllReservations();
}
@ -171,11 +232,11 @@ public class CheckedReservation implements AutoCloseable {
}
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

@ -54,6 +54,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;
@ -92,6 +93,7 @@ import com.cloud.exception.ResourceAllocationException;
import com.cloud.network.dao.IPAddressDao;
import com.cloud.network.dao.IPAddressVO;
import com.cloud.network.dao.NetworkDao;
import com.cloud.network.dao.NetworkDomainDao;
import com.cloud.network.vpc.dao.VpcDao;
import com.cloud.offering.DiskOffering;
import com.cloud.offering.ServiceOffering;
@ -175,6 +177,8 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
@Inject
private ReservationDao reservationDao;
@Inject
private ResourceLimitService resourceLimitService;
@Inject
protected SnapshotDao _snapshotDao;
@Inject
protected BackupDao backupDao;
@ -204,6 +208,8 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
DiskOfferingDao diskOfferingDao;
@Inject
BucketDao bucketDao;
@Inject
private NetworkDomainDao networkDomainDao;
protected GenericSearchBuilder<TemplateDataStoreVO, SumCount> templateSizeSearch;
protected GenericSearchBuilder<SnapshotDataStoreVO, SumCount> snapshotSizeSearch;
@ -267,7 +273,7 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
templateSizeSearch = _vmTemplateStoreDao.createSearchBuilder(SumCount.class);
templateSizeSearch.select("sum", Func.SUM, templateSizeSearch.entity().getSize());
templateSizeSearch.and("downloadState", templateSizeSearch.entity().getDownloadState(), Op.EQ);
templateSizeSearch.and("downloadState", templateSizeSearch.entity().getDownloadState(), Op.IN);
templateSizeSearch.and("destroyed", templateSizeSearch.entity().getDestroyed(), Op.EQ);
SearchBuilder<VMTemplateVO> join1 = _vmTemplateDao.createSearchBuilder();
join1.and("accountId", join1.entity().getAccountId(), Op.EQ);
@ -515,15 +521,7 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
return max;
}
protected void checkDomainResourceLimit(final Account account, final Project project, final ResourceType type, String tag, long numResources) throws ResourceAllocationException {
// check all domains in the account's domain hierarchy
Long domainId;
if (project != null) {
domainId = project.getDomainId();
} else {
domainId = account.getDomainId();
}
protected void checkDomainResourceLimit(Long domainId, final ResourceType type, String tag, long numResources) throws ResourceAllocationException {
while (domainId != null) {
DomainVO domain = _domainDao.findById(domainId);
// no limit check if it is ROOT domain
@ -645,11 +643,16 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
@Override
public void checkResourceLimitWithTag(final Account account, final ResourceType type, String tag, long... count) throws ResourceAllocationException {
checkResourceLimitWithTag(account, null, false, type, tag, count);
}
@Override
public void checkResourceLimitWithTag(final Account account, Long domainId, boolean considerSystemAccount, final ResourceType type, String tag, long... count) throws ResourceAllocationException {
final long numResources = ((count.length == 0) ? 1 : count[0]);
Project project = null;
// Don't place any limits on system or root admin accounts
if (_accountMgr.isRootAdmin(account.getId())) {
if (_accountMgr.isRootAdmin(account.getId()) && !(considerSystemAccount && Account.ACCOUNT_ID_SYSTEM == account.getId())) {
return;
}
@ -657,6 +660,14 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
project = _projectDao.findByProjectAccountId(account.getId());
}
if (domainId == null) {
if (project != null) {
domainId = project.getDomainId();
} else {
domainId = account.getDomainId();
}
}
Long domainIdFinal = domainId;
final Project projectFinal = project;
Transaction.execute(new TransactionCallbackWithExceptionNoReturn<ResourceAllocationException>() {
@Override
@ -666,7 +677,7 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
// Check account limits
checkAccountResourceLimit(account, projectFinal, type, tag, numResources);
// check all domains in the account's domain hierarchy
checkDomainResourceLimit(account, projectFinal, type, tag, numResources);
checkDomainResourceLimit(domainIdFinal, type, tag, numResources);
}
});
}
@ -1203,7 +1214,7 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
* @param type the resource type to do the recalculation for
* @return the resulting new resource count
*/
protected long recalculateDomainResourceCount(final long domainId, final ResourceType type, String tag) {
public long recalculateDomainResourceCount(final long domainId, final ResourceType type, String tag) {
List<AccountVO> accounts = _accountDao.findActiveAccountsForDomain(domainId);
List<DomainVO> childDomains = _domainDao.findImmediateChildrenForParent(domainId);
@ -1239,9 +1250,8 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
long newResourceCount = 0L;
ResourceCountVO domainRC = null;
// calculate project count here
if (type == ResourceType.project) {
newResourceCount += _projectDao.countProjectsForDomain(domainId);
if (type == ResourceType.network) {
newResourceCount += networkDomainDao.listDomainNetworkMapByDomain(domainId).size();
}
// TODO make sure that the resource counts are not null
@ -1488,7 +1498,7 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
long totalTemplatesSize = 0;
SearchCriteria<SumCount> sc = templateSizeSearch.create();
sc.setParameters("downloadState", Status.DOWNLOADED);
sc.setParameters("downloadState", Status.DOWNLOADED, Status.DOWNLOAD_IN_PROGRESS);
sc.setParameters("destroyed", false);
sc.setJoinParameters("templates", "accountId", accountId);
List<SumCount> templates = _vmTemplateStoreDao.customSearch(sc, null);
@ -1725,7 +1735,8 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
return tags;
}
protected List<String> getResourceLimitStorageTagsForResourceCountOperation(Boolean display, DiskOffering diskOffering) {
@Override
public List<String> getResourceLimitStorageTagsForResourceCountOperation(Boolean display, DiskOffering diskOffering) {
if (Boolean.FALSE.equals(display)) {
return new ArrayList<>();
}
@ -1739,54 +1750,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
@ -2013,20 +2023,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
@ -2076,83 +2093,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
@ -2183,20 +2177,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);
@ -2225,20 +2205,6 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim
}
}
@Override
public void checkVmGpuResourceLimit(Account owner, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long gpu) throws ResourceAllocationException {
List<String> tags = getResourceLimitHostTagsForResourceCountOperation(display, serviceOffering, template);
if (CollectionUtils.isEmpty(tags)) {
return;
}
if (gpu == null) {
gpu = serviceOffering.getGpuCount() != null ? Long.valueOf(serviceOffering.getGpuCount()) : 0L;
}
for (String tag : tags) {
checkResourceLimitWithTag(owner, ResourceType.gpu, tag, gpu);
}
}
@Override
public void incrementVmGpuResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long gpu) {
List<String> tags = getResourceLimitHostTagsForResourceCountOperation(display, serviceOffering, template);

View File

@ -25,7 +25,6 @@ import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import com.cloud.agent.api.to.OVFInformationTO;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
@ -37,6 +36,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
import org.apache.cloudstack.reservation.dao.ReservationDao;
import org.apache.cloudstack.storage.command.UploadStatusAnswer;
import org.apache.cloudstack.storage.command.UploadStatusAnswer.UploadStatus;
import org.apache.cloudstack.storage.command.UploadStatusCommand;
@ -55,6 +55,7 @@ import com.cloud.agent.api.AgentControlCommand;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.to.OVFInformationTO;
import com.cloud.alert.AlertManager;
import com.cloud.api.query.dao.TemplateJoinDao;
import com.cloud.api.query.vo.TemplateJoinVO;
@ -62,15 +63,20 @@ import com.cloud.configuration.Resource;
import com.cloud.event.EventTypes;
import com.cloud.event.UsageEventUtils;
import com.cloud.exception.ConnectionException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.host.Host;
import com.cloud.host.Status;
import com.cloud.host.dao.HostDao;
import com.cloud.resourcelimit.CheckedReservation;
import com.cloud.storage.Volume.Event;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.storage.dao.VMTemplateZoneDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.template.VirtualMachineTemplate;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.ResourceLimitService;
import com.cloud.user.dao.AccountDao;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.concurrency.NamedThreadFactory;
import com.cloud.utils.db.Transaction;
@ -117,6 +123,12 @@ public class ImageStoreUploadMonitorImpl extends ManagerBase implements ImageSto
private TemplateJoinDao templateJoinDao;
@Inject
private DeployAsIsHelper deployAsIsHelper;
@Inject
private AccountDao accountDao;
@Inject
private AccountManager _accountMgr;
@Inject
private ReservationDao reservationDao;
private long _nodeId;
private ScheduledExecutorService _executor = null;
@ -205,6 +217,36 @@ public class ImageStoreUploadMonitorImpl extends ManagerBase implements ImageSto
public UploadStatusCheck() {
}
private Answer sendUploadStatusCommandForVolume(EndPoint ep, UploadStatusCommand cmd, VolumeVO volume) {
Answer answer = null;
try {
answer = ep.sendMessage(cmd);
} catch (CloudRuntimeException e) {
logger.warn("Unable to get upload status for volume {}. Error details: {}", volume, e.getMessage());
answer = new UploadStatusAnswer(cmd, UploadStatus.UNKNOWN, e.getMessage());
}
if (answer == null || !(answer instanceof UploadStatusAnswer)) {
logger.warn("No or invalid answer corresponding to UploadStatusCommand for volume {}", volume);
return null;
}
return answer;
}
private Answer sendUploadStatusCommandForTemplate(EndPoint ep, UploadStatusCommand cmd, VMTemplateVO template) {
Answer answer = null;
try {
answer = ep.sendMessage(cmd);
} catch (CloudRuntimeException e) {
logger.warn("Unable to get upload status for template {}. Error details: {}", template, e.getMessage());
answer = new UploadStatusAnswer(cmd, UploadStatus.UNKNOWN, e.getMessage());
}
if (answer == null || !(answer instanceof UploadStatusAnswer)) {
logger.warn("No or invalid answer corresponding to UploadStatusCommand for template {}", template);
return null;
}
return answer;
}
@Override
protected void runInContext() {
// 1. Select all entries with download_state = Not_Downloaded or Download_In_Progress
@ -231,18 +273,17 @@ public class ImageStoreUploadMonitorImpl extends ManagerBase implements ImageSto
UploadStatusCommand cmd = new UploadStatusCommand(volume.getUuid(), EntityType.Volume);
if (host != null && host.getManagementServerId() != null) {
if (_nodeId == host.getManagementServerId().longValue()) {
Answer answer = null;
try {
answer = ep.sendMessage(cmd);
} catch (CloudRuntimeException e) {
logger.warn("Unable to get upload status for volume {}. Error details: {}", volume, e.getMessage());
answer = new UploadStatusAnswer(cmd, UploadStatus.UNKNOWN, e.getMessage());
}
if (answer == null || !(answer instanceof UploadStatusAnswer)) {
logger.warn("No or invalid answer corresponding to UploadStatusCommand for volume {}", volume);
Answer answer = sendUploadStatusCommandForVolume(ep, cmd, volume);
if (answer == null) {
continue;
}
handleVolumeStatusResponse((UploadStatusAnswer)answer, volume, volumeDataStore);
if (!handleVolumeStatusResponse((UploadStatusAnswer)answer, volume, volumeDataStore)) {
cmd = new UploadStatusCommand(volume.getUuid(), EntityType.Volume, true);
answer = sendUploadStatusCommandForVolume(ep, cmd, volume);
if (answer == null) {
logger.warn("Unable to abort upload for volume {}", volume);
}
}
}
} else {
String error = "Volume " + volume.getUuid() + " failed to upload as SSVM is either destroyed or SSVM agent not in 'Up' state";
@ -275,18 +316,17 @@ public class ImageStoreUploadMonitorImpl extends ManagerBase implements ImageSto
UploadStatusCommand cmd = new UploadStatusCommand(template.getUuid(), EntityType.Template);
if (host != null && host.getManagementServerId() != null) {
if (_nodeId == host.getManagementServerId().longValue()) {
Answer answer = null;
try {
answer = ep.sendMessage(cmd);
} catch (CloudRuntimeException e) {
logger.warn("Unable to get upload status for template {}. Error details: {}", template, e.getMessage());
answer = new UploadStatusAnswer(cmd, UploadStatus.UNKNOWN, e.getMessage());
}
if (answer == null || !(answer instanceof UploadStatusAnswer)) {
logger.warn("No or invalid answer corresponding to UploadStatusCommand for template {}", template);
Answer answer = sendUploadStatusCommandForTemplate(ep, cmd, template);
if (answer == null) {
continue;
}
handleTemplateStatusResponse((UploadStatusAnswer)answer, template, templateDataStore);
if (!handleTemplateStatusResponse((UploadStatusAnswer) answer, template, templateDataStore)) {
cmd = new UploadStatusCommand(template.getUuid(), EntityType.Template, true);
answer = sendUploadStatusCommandForTemplate(ep, cmd, template);
if (answer == null) {
logger.warn("Unable to abort upload for template {}", template);
}
}
}
} else {
String error = String.format(
@ -303,7 +343,41 @@ public class ImageStoreUploadMonitorImpl extends ManagerBase implements ImageSto
}
}
private void handleVolumeStatusResponse(final UploadStatusAnswer answer, final VolumeVO volume, final VolumeDataStoreVO volumeDataStore) {
private Boolean checkAndUpdateSecondaryStorageResourceLimit(Long accountId, Long lastSize, Long currentSize) {
if (lastSize >= currentSize) {
return true;
}
Long usage = currentSize - lastSize;
try (CheckedReservation secStorageReservation = new CheckedReservation(_accountMgr.getAccount(accountId), Resource.ResourceType.secondary_storage, null, null, usage, reservationDao, _resourceLimitMgr)) {
_resourceLimitMgr.incrementResourceCount(accountId, Resource.ResourceType.secondary_storage, usage);
return true;
} catch (Exception e) {
_resourceLimitMgr.decrementResourceCount(accountId, Resource.ResourceType.secondary_storage, lastSize);
return false;
}
}
private Boolean checkAndUpdateVolumeResourceLimit(VolumeVO volume, VolumeDataStoreVO volumeDataStore, UploadStatusAnswer answer) {
boolean success = true;
Long currentSize = answer.getVirtualSize() != 0 ? answer.getVirtualSize() : answer.getPhysicalSize();
Long lastSize = volume.getSize() != null ? volume.getSize() : 0L;
if (!checkAndUpdateSecondaryStorageResourceLimit(volume.getAccountId(), volume.getSize(), currentSize)) {
volumeDataStore.setDownloadState(VMTemplateStorageResourceAssoc.Status.DOWNLOAD_ERROR);
volumeDataStore.setState(State.Failed);
volumeDataStore.setErrorString("Storage Limit Reached");
Account owner = accountDao.findById(volume.getAccountId());
String msg = String.format("Upload of volume [%s] failed because its owner [%s] does not have enough secondary storage space available.", volume.getUuid(), owner.getUuid());
logger.error(msg);
success = false;
}
VolumeVO volumeUpdate = _volumeDao.findById(volume.getId());
volumeUpdate.setSize(currentSize);
_volumeDao.update(volumeUpdate.getId(), volumeUpdate);
return success;
}
private boolean handleVolumeStatusResponse(final UploadStatusAnswer answer, final VolumeVO volume, final VolumeDataStoreVO volumeDataStore) {
final boolean[] needAbort = new boolean[]{false};
final StateMachine2<Volume.State, Event, Volume> stateMachine = Volume.State.getStateMachine();
Transaction.execute(new TransactionCallbackNoReturn() {
@Override
@ -315,6 +389,11 @@ public class ImageStoreUploadMonitorImpl extends ManagerBase implements ImageSto
try {
switch (answer.getStatus()) {
case COMPLETED:
if (!checkAndUpdateVolumeResourceLimit(tmpVolume, tmpVolumeDataStore, answer)) {
stateMachine.transitTo(tmpVolume, Event.OperationFailed, null, _volumeDao);
sendAlert = true;
break;
}
tmpVolumeDataStore.setDownloadState(VMTemplateStorageResourceAssoc.Status.DOWNLOADED);
tmpVolumeDataStore.setState(State.Ready);
tmpVolumeDataStore.setInstallPath(answer.getInstallPath());
@ -326,7 +405,6 @@ public class ImageStoreUploadMonitorImpl extends ManagerBase implements ImageSto
volumeUpdate.setSize(answer.getVirtualSize());
_volumeDao.update(tmpVolume.getId(), volumeUpdate);
stateMachine.transitTo(tmpVolume, Event.OperationSucceeded, null, _volumeDao);
_resourceLimitMgr.incrementResourceCount(volume.getAccountId(), Resource.ResourceType.secondary_storage, answer.getVirtualSize());
// publish usage events
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_UPLOAD, tmpVolume.getAccountId(),
@ -339,6 +417,12 @@ public class ImageStoreUploadMonitorImpl extends ManagerBase implements ImageSto
}
break;
case IN_PROGRESS:
if (!checkAndUpdateVolumeResourceLimit(tmpVolume, tmpVolumeDataStore, answer)) {
stateMachine.transitTo(tmpVolume, Event.OperationFailed, null, _volumeDao);
sendAlert = true;
needAbort[0] = true;
break;
}
if (tmpVolume.getState() == Volume.State.NotUploaded) {
tmpVolumeDataStore.setDownloadState(VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS);
tmpVolumeDataStore.setDownloadPercent(answer.getDownloadPercent());
@ -387,10 +471,29 @@ public class ImageStoreUploadMonitorImpl extends ManagerBase implements ImageSto
}
}
});
return !needAbort[0];
}
private void handleTemplateStatusResponse(final UploadStatusAnswer answer, final VMTemplateVO template, final TemplateDataStoreVO templateDataStore) {
private Boolean checkAndUpdateTemplateResourceLimit(VMTemplateVO template, TemplateDataStoreVO templateDataStore, UploadStatusAnswer answer) {
boolean success = true;
Long currentSize = answer.getVirtualSize() != 0 ? answer.getVirtualSize() : answer.getPhysicalSize();
Long lastSize = template.getSize() != null ? template.getSize() : 0L;
if (!checkAndUpdateSecondaryStorageResourceLimit(template.getAccountId(), lastSize, currentSize)) {
templateDataStore.setDownloadState(VMTemplateStorageResourceAssoc.Status.DOWNLOAD_ERROR);
templateDataStore.setErrorString("Storage Limit Reached");
templateDataStore.setState(State.Failed);
Account owner = accountDao.findById(template.getAccountId());
String msg = String.format("Upload of template [%s] failed because its owner [%s] does not have enough secondary storage space available.", template.getUuid(), owner.getUuid());
logger.error(msg);
success = false;
}
templateDataStore.setSize(currentSize);
return success;
}
private boolean handleTemplateStatusResponse(final UploadStatusAnswer answer, final VMTemplateVO template, final TemplateDataStoreVO templateDataStore) {
final StateMachine2<VirtualMachineTemplate.State, VirtualMachineTemplate.Event, VirtualMachineTemplate> stateMachine = VirtualMachineTemplate.State.getStateMachine();
final boolean[] needAbort = new boolean[]{false};
Transaction.execute(new TransactionCallbackNoReturn() {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) {
@ -401,6 +504,11 @@ public class ImageStoreUploadMonitorImpl extends ManagerBase implements ImageSto
try {
switch (answer.getStatus()) {
case COMPLETED:
if (!checkAndUpdateTemplateResourceLimit(tmpTemplate, tmpTemplateDataStore, answer)) {
stateMachine.transitTo(tmpTemplate, VirtualMachineTemplate.Event.OperationFailed, null, _templateDao);
sendAlert = true;
break;
}
tmpTemplateDataStore.setDownloadState(VMTemplateStorageResourceAssoc.Status.DOWNLOADED);
tmpTemplateDataStore.setState(State.Ready);
tmpTemplateDataStore.setInstallPath(answer.getInstallPath());
@ -436,8 +544,23 @@ public class ImageStoreUploadMonitorImpl extends ManagerBase implements ImageSto
break;
}
}
Account owner = accountDao.findById(template.getAccountId());
long templateSize = answer.getVirtualSize();
try (CheckedReservation secondaryStorageReservation = new CheckedReservation(owner, Resource.ResourceType.secondary_storage, null, null, templateSize, reservationDao, _resourceLimitMgr)) {
_resourceLimitMgr.incrementResourceCount(owner.getId(), Resource.ResourceType.secondary_storage, templateSize);
} catch (ResourceAllocationException e) {
tmpTemplateDataStore.setDownloadState(VMTemplateStorageResourceAssoc.Status.UPLOAD_ERROR);
tmpTemplateDataStore.setState(State.Failed);
stateMachine.transitTo(tmpTemplate, VirtualMachineTemplate.Event.OperationFailed, null, _templateDao);
msg = String.format("Upload of template [%s] failed because its owner [%s] does not have enough secondary storage space available.", template.getUuid(), owner.getUuid());
logger.warn(msg);
sendAlert = true;
break;
}
stateMachine.transitTo(tmpTemplate, VirtualMachineTemplate.Event.OperationSucceeded, null, _templateDao);
_resourceLimitMgr.incrementResourceCount(template.getAccountId(), Resource.ResourceType.secondary_storage, answer.getVirtualSize());
//publish usage event
String etype = EventTypes.EVENT_TEMPLATE_CREATE;
if (tmpTemplate.getFormat() == Storage.ImageFormat.ISO) {
@ -453,6 +576,12 @@ public class ImageStoreUploadMonitorImpl extends ManagerBase implements ImageSto
}
break;
case IN_PROGRESS:
if (!checkAndUpdateTemplateResourceLimit(tmpTemplate, tmpTemplateDataStore, answer)) {
stateMachine.transitTo(tmpTemplate, VirtualMachineTemplate.Event.OperationFailed, null, _templateDao);
sendAlert = true;
needAbort[0] = true;
break;
}
if (tmpTemplate.getState() == VirtualMachineTemplate.State.NotUploaded) {
tmpTemplateDataStore.setDownloadState(VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS);
stateMachine.transitTo(tmpTemplate, VirtualMachineTemplate.Event.UploadRequested, null, _templateDao);
@ -502,6 +631,7 @@ public class ImageStoreUploadMonitorImpl extends ManagerBase implements ImageSto
}
}
});
return !needAbort[0];
}
}

View File

@ -35,16 +35,11 @@ import java.util.stream.Collectors;
import javax.inject.Inject;
import com.cloud.projects.Project;
import com.cloud.projects.ProjectManager;
import com.cloud.vm.snapshot.VMSnapshot;
import com.cloud.vm.snapshot.VMSnapshotDetailsVO;
import com.cloud.vm.snapshot.dao.VMSnapshotDetailsDao;
import org.apache.cloudstack.api.command.user.volume.AssignVolumeCmd;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.InternalIdentity;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.command.user.volume.AssignVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.ChangeOfferingForVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.CheckAndRepairVolumeCmd;
@ -94,10 +89,12 @@ import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO;
import org.apache.cloudstack.framework.jobs.impl.OutcomeImpl;
import org.apache.cloudstack.framework.jobs.impl.VmWorkJobVO;
import org.apache.cloudstack.jobs.JobInfo;
import org.apache.cloudstack.reservation.dao.ReservationDao;
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;
@ -166,8 +163,12 @@ import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao;
import com.cloud.offering.DiskOffering;
import com.cloud.org.Cluster;
import com.cloud.org.Grouping;
import com.cloud.projects.Project;
import com.cloud.projects.ProjectManager;
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.server.ResourceTag;
@ -242,8 +243,12 @@ import com.cloud.vm.VmWorkTakeVolumeSnapshot;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDetailsDao;
import com.cloud.vm.dao.VMInstanceDao;
import com.cloud.vm.snapshot.VMSnapshot;
import com.cloud.vm.snapshot.VMSnapshotDetailsVO;
import com.cloud.vm.snapshot.VMSnapshotVO;
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
import com.cloud.vm.snapshot.dao.VMSnapshotDetailsDao;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParseException;
@ -351,10 +356,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
private ManagementService managementService;
@Inject
protected SnapshotHelper snapshotHelper;
@Inject
protected DomainDao domainDao;
@Inject
protected ProjectManager projectManager;
@Inject
@ -367,7 +370,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
HostPodDao podDao;
@Inject
EndPointSelector _epSelector;
@Inject
private ReservationDao reservationDao;
@Inject
private VMSnapshotDetailsDao vmSnapshotDetailsDao;
@ -440,9 +444,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());
@ -482,77 +494,83 @@ 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
public GetUploadParamsResponse doInTransaction(TransactionStatus status) throws MalformedURLException {
return Transaction.execute(new TransactionCallbackWithException<GetUploadParamsResponse, MalformedURLException>() {
@Override
public GetUploadParamsResponse doInTransaction(TransactionStatus status) throws MalformedURLException {
VolumeVO volume = persistVolume(owner, zoneId, volumeName, null, format, diskOfferingId, Volume.State.NotUploaded);
VolumeVO volume = persistVolume(owner, zoneId, volumeName, null, format, diskOfferingId, Volume.State.NotUploaded);
final DataStore store = _tmpltMgr.getImageStore(imageStoreUuid, zoneId, volume);
final DataStore store = _tmpltMgr.getImageStore(imageStoreUuid, zoneId, volume);
VolumeInfo vol = volFactory.getVolume(volume.getId());
VolumeInfo vol = volFactory.getVolume(volume.getId());
RegisterVolumePayload payload = new RegisterVolumePayload(null, cmd.getChecksum(), format);
vol.addPayload(payload);
RegisterVolumePayload payload = new RegisterVolumePayload(null, cmd.getChecksum(), format);
vol.addPayload(payload);
Pair<EndPoint, DataObject> pair = volService.registerVolumeForPostUpload(vol, store);
EndPoint ep = pair.first();
DataObject dataObject = pair.second();
Pair<EndPoint, DataObject> pair = volService.registerVolumeForPostUpload(vol, store);
EndPoint ep = pair.first();
DataObject dataObject = pair.second();
GetUploadParamsResponse response = new GetUploadParamsResponse();
GetUploadParamsResponse response = new GetUploadParamsResponse();
String ssvmUrlDomain = _configDao.getValue(Config.SecStorageSecureCopyCert.key());
String protocol = UseHttpsToUpload.value() ? "https" : "http";
String ssvmUrlDomain = _configDao.getValue(Config.SecStorageSecureCopyCert.key());
String protocol = UseHttpsToUpload.value() ? "https" : "http";
String url = ImageStoreUtil.generatePostUploadUrl(ssvmUrlDomain, ep.getPublicAddr(), vol.getUuid(), protocol);
response.setPostURL(new URL(url));
String url = ImageStoreUtil.generatePostUploadUrl(ssvmUrlDomain, ep.getPublicAddr(), vol.getUuid(), protocol);
response.setPostURL(new URL(url));
// set the post url, this is used in the monitoring thread to determine the SSVM
VolumeDataStoreVO volumeStore = _volumeStoreDao.findByVolume(vol.getId());
assert (volumeStore != null) : "sincle volume is registered, volumestore cannot be null at this stage";
volumeStore.setExtractUrl(url);
_volumeStoreDao.persist(volumeStore);
// set the post url, this is used in the monitoring thread to determine the SSVM
VolumeDataStoreVO volumeStore = _volumeStoreDao.findByVolume(vol.getId());
assert (volumeStore != null) : "sincle volume is registered, volumestore cannot be null at this stage";
volumeStore.setExtractUrl(url);
_volumeStoreDao.persist(volumeStore);
response.setId(UUID.fromString(vol.getUuid()));
response.setId(UUID.fromString(vol.getUuid()));
int timeout = ImageStoreUploadMonitorImpl.getUploadOperationTimeout();
DateTime currentDateTime = new DateTime(DateTimeZone.UTC);
String expires = currentDateTime.plusMinutes(timeout).toString();
response.setTimeout(expires);
int timeout = ImageStoreUploadMonitorImpl.getUploadOperationTimeout();
DateTime currentDateTime = new DateTime(DateTimeZone.UTC);
String expires = currentDateTime.plusMinutes(timeout).toString();
response.setTimeout(expires);
String key = _configDao.getValue(Config.SSVMPSK.key());
/*
* encoded metadata using the post upload config key
*/
TemplateOrVolumePostUploadCommand command = new TemplateOrVolumePostUploadCommand(vol.getId(), vol.getUuid(), volumeStore.getInstallPath(), cmd.getChecksum(), vol.getType().toString(),
vol.getName(), vol.getFormat().toString(), dataObject.getDataStore().getUri(), dataObject.getDataStore().getRole().toString());
command.setLocalPath(volumeStore.getLocalDownloadPath());
//using the existing max upload size configuration
command.setProcessTimeout(NumbersUtil.parseLong(_configDao.getValue("vmware.package.ova.timeout"), 3600));
command.setMaxUploadSize(_configDao.getValue(Config.MaxUploadVolumeSize.key()));
String key = _configDao.getValue(Config.SSVMPSK.key());
/*
* encoded metadata using the post upload config key
*/
TemplateOrVolumePostUploadCommand command = new TemplateOrVolumePostUploadCommand(vol.getId(), vol.getUuid(), volumeStore.getInstallPath(), cmd.getChecksum(), vol.getType().toString(),
vol.getName(), vol.getFormat().toString(), dataObject.getDataStore().getUri(), dataObject.getDataStore().getRole().toString());
command.setLocalPath(volumeStore.getLocalDownloadPath());
//using the existing max upload size configuration
command.setProcessTimeout(NumbersUtil.parseLong(_configDao.getValue("vmware.package.ova.timeout"), 3600));
command.setMaxUploadSize(_configDao.getValue(Config.MaxUploadVolumeSize.key()));
long accountId = vol.getAccountId();
Account account = _accountDao.findById(accountId);
Domain domain = domainDao.findById(account.getDomainId());
long accountId = vol.getAccountId();
Account account = _accountDao.findById(accountId);
Domain domain = domainDao.findById(account.getDomainId());
command.setDefaultMaxSecondaryStorageInGB(_resourceLimitMgr.findCorrectResourceLimitForAccountAndDomain(account, domain, ResourceType.secondary_storage, null));
command.setAccountId(accountId);
Gson gson = new GsonBuilder().create();
String metadata = EncryptionUtil.encodeData(gson.toJson(command), key);
response.setMetadata(metadata);
command.setDefaultMaxSecondaryStorageInBytes(_resourceLimitMgr.findCorrectResourceLimitForAccountAndDomain(account, domain, ResourceType.secondary_storage, null));
command.setAccountId(accountId);
Gson gson = new GsonBuilder().create();
String metadata = EncryptionUtil.encodeData(gson.toJson(command), key);
response.setMetadata(metadata);
/*
* signature calculated on the url, expiry, metadata.
*/
response.setSignature(EncryptionUtil.generateSignature(metadata + url + expires, key));
return response;
}
});
/*
* signature calculated on the url, expiry, metadata.
*/
response.setSignature(EncryptionUtil.generateSignature(metadata + url + expires, key));
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);
@ -563,7 +581,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);
@ -937,30 +955,39 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
Storage.ProvisioningType provisioningType = diskOffering.getProvisioningType();
// Check that the resource limit for volume & primary storage won't be exceeded
_resourceLimitMgr.checkVolumeResourceLimit(owner,displayVolume, size, diskOffering);
// Verify that zone exists
DataCenterVO zone = _dcDao.findById(zoneId);
if (zone == null) {
throw new InvalidParameterValueException("Unable to find zone by id " + zoneId);
List<String> tags = _resourceLimitMgr.getResourceLimitStorageTagsForResourceCountOperation(displayVolume, diskOffering);
if (tags.size() == 1 && tags.get(0) == null) {
tags = new ArrayList<>();
}
// Check if zone is disabled
if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getId())) {
throw new PermissionDeniedException(String.format("Cannot perform this operation, Zone: %s is currently disabled", zone));
List<Reserver> reservations = new ArrayList<>();
try {
_resourceLimitMgr.checkVolumeResourceLimit(owner, displayVolume, size, diskOffering, reservations);
// Verify that zone exists
DataCenterVO zone = _dcDao.findById(zoneId);
if (zone == null) {
throw new InvalidParameterValueException("Unable to find zone by id " + zoneId);
}
// Check if zone is disabled
if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getId())) {
throw new PermissionDeniedException(String.format("Cannot perform this operation, Zone: %s is currently disabled", zone));
}
// If local storage is disabled then creation of volume with local disk
// offering not allowed
if (!zone.isLocalStorageEnabled() && diskOffering.isUseLocalStorage()) {
throw new InvalidParameterValueException("Zone is not configured to use local storage but volume's disk offering " + diskOffering.getName() + " uses it");
}
String userSpecifiedName = getVolumeNameFromCommand(cmd);
return commitVolume(cmd.getSnapshotId(), caller, owner, displayVolume, zoneId, diskOfferingId, provisioningType, size, minIops, maxIops, parentVolume, userSpecifiedName,
_uuidMgr.generateUuid(Volume.class, cmd.getCustomId()), details);
} finally {
ReservationHelper.closeAll(reservations);
}
// If local storage is disabled then creation of volume with local disk
// offering not allowed
if (!zone.isLocalStorageEnabled() && diskOffering.isUseLocalStorage()) {
throw new InvalidParameterValueException("Zone is not configured to use local storage but volume's disk offering " + diskOffering.getName() + " uses it");
}
String userSpecifiedName = getVolumeNameFromCommand(cmd);
return commitVolume(cmd.getSnapshotId(), caller, owner, displayVolume, zoneId, diskOfferingId, provisioningType, size, minIops, maxIops, parentVolume, userSpecifiedName,
_uuidMgr.generateUuid(Volume.class, cmd.getCustomId()), details);
}
@Override
@ -978,7 +1005,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
return Transaction.execute(new TransactionCallback<VolumeVO>() {
@Override
public VolumeVO doInTransaction(TransactionStatus status) {
VolumeVO volume = new VolumeVO(userSpecifiedName, -1, -1, -1, -1, new Long(-1), null, null, provisioningType, 0, Volume.Type.DATADISK);
VolumeVO volume = new VolumeVO(userSpecifiedName, -1, -1, -1, -1, -1L, null, null, provisioningType, 0, Volume.Type.DATADISK);
volume.setPoolId(null);
volume.setUuid(uuid);
volume.setDataCenterId(zoneId);
@ -1317,134 +1344,141 @@ 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);
// 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
List<Reserver> reservations = new ArrayList<>();
try {
validateVolumeResizeWithSize(volume, currentSize, newSize, shrinkOk, diskOffering, 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
if (volume.getState() == Volume.State.Allocated) {
logger.debug("Volume is in the allocated state, but has never been created. Simply updating database with new size and IOPS.");
// 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
volume.setSize(newSize);
volume.setMinIops(newMinIops);
volume.setMaxIops(newMaxIops);
volume.setHypervisorSnapshotReserve(newHypervisorSnapshotReserve);
/* 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
if (volume.getState() == Volume.State.Allocated) {
logger.debug("Volume is in the allocated state, but has never been created. Simply updating database with new size and IOPS.");
if (newDiskOffering != null) {
volume.setDiskOfferingId(cmd.getNewDiskOfferingId());
}
volume.setSize(newSize);
volume.setMinIops(newMinIops);
volume.setMaxIops(newMaxIops);
volume.setHypervisorSnapshotReserve(newHypervisorSnapshotReserve);
_volsDao.update(volume.getId(), volume);
_resourceLimitMgr.updateVolumeResourceCountForDiskOfferingChange(volume.getAccountId(), volume.isDisplayVolume(), currentSize, newSize,
diskOffering, newDiskOffering);
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_RESIZE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(),
volume.getDiskOfferingId(), volume.getTemplateId(), volume.getSize(), Volume.class.getName(), volume.getUuid());
return volume;
}
Long newDiskOfferingId = newDiskOffering != null ? newDiskOffering.getId() : diskOffering.getId();
boolean volumeMigrateRequired = false;
List<? extends StoragePool> suitableStoragePoolsWithEnoughSpace = null;
StoragePoolVO storagePool = _storagePoolDao.findById(volume.getPoolId());
if (!storageMgr.storagePoolHasEnoughSpaceForResize(storagePool, currentSize, newSize)) {
if (!autoMigrateVolume) {
throw new CloudRuntimeException(String.format("Failed to resize volume %s since the storage pool does not have enough space to accommodate new size for the volume %s, try with automigrate set to true in order to check in the other suitable pools for the new size and then migrate & resize volume there.", volume.getUuid(), volume.getName()));
}
Pair<List<? extends StoragePool>, List<? extends StoragePool>> poolsPair = managementService.listStoragePoolsForSystemMigrationOfVolume(volume.getId(), newDiskOfferingId, currentSize, newMinIops, newMaxIops, true, false);
List<? extends StoragePool> suitableStoragePools = poolsPair.second();
if (CollectionUtils.isEmpty(poolsPair.first()) && CollectionUtils.isEmpty(poolsPair.second())) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Volume resize failed for volume ID: %s as no suitable pool(s) found for migrating to support new disk offering or new size", volume.getUuid()));
}
final Long newSizeFinal = newSize;
suitableStoragePoolsWithEnoughSpace = suitableStoragePools.stream().filter(pool -> storageMgr.storagePoolHasEnoughSpaceForResize(pool, 0L, newSizeFinal)).collect(Collectors.toList());
if (CollectionUtils.isEmpty(suitableStoragePoolsWithEnoughSpace)) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Volume resize failed for volume ID: %s as no suitable pool(s) with enough space found.", volume.getUuid()));
}
Collections.shuffle(suitableStoragePoolsWithEnoughSpace);
volumeMigrateRequired = true;
}
boolean volumeResizeRequired = false;
if (currentSize != newSize || !compareEqualsIncludingNullOrZero(newMaxIops, volume.getMaxIops()) || !compareEqualsIncludingNullOrZero(newMinIops, volume.getMinIops())) {
volumeResizeRequired = true;
}
if (!volumeMigrateRequired && !volumeResizeRequired && newDiskOffering != null) {
_volsDao.updateDiskOffering(volume.getId(), newDiskOffering.getId());
volume = _volsDao.findById(volume.getId());
updateStorageWithTheNewDiskOffering(volume, newDiskOffering);
return volume;
}
if (volumeMigrateRequired) {
MigrateVolumeCmd migrateVolumeCmd = new MigrateVolumeCmd(volume.getId(), suitableStoragePoolsWithEnoughSpace.get(0).getId(), newDiskOfferingId, true);
try {
Volume result = migrateVolume(migrateVolumeCmd);
volume = (result != null) ? _volsDao.findById(result.getId()) : null;
if (volume == null) {
throw new CloudRuntimeException(String.format("Volume resize operation failed for volume ID: %s as migration failed to storage pool %s accommodating new size", volume.getUuid(), suitableStoragePoolsWithEnoughSpace.get(0).getId()));
}
} catch (Exception e) {
throw new CloudRuntimeException(String.format("Volume resize operation failed for volume ID: %s as migration failed to storage pool %s accommodating new size", volume.getUuid(), suitableStoragePoolsWithEnoughSpace.get(0).getId()));
}
}
UserVmVO userVm = _userVmDao.findById(volume.getInstanceId());
if (userVm != null) {
// serialize VM operation
AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
if (jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) {
// avoid re-entrance
VmWorkJobVO placeHolder = null;
placeHolder = createPlaceHolderWork(userVm.getId());
try {
return orchestrateResizeVolume(volume.getId(), currentSize, newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve,
newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk);
} finally {
_workJobDao.expunge(placeHolder.getId());
}
} else {
Outcome<Volume> outcome = resizeVolumeThroughJobQueue(userVm.getId(), volume.getId(), currentSize, newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve,
newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk);
try {
outcome.get();
} catch (InterruptedException e) {
throw new RuntimeException("Operation was interrupted", e);
} catch (ExecutionException e) {
throw new RuntimeException("Execution exception", e);
if (newDiskOffering != null) {
volume.setDiskOfferingId(cmd.getNewDiskOfferingId());
}
Object jobResult = _jobMgr.unmarshallResultObject(outcome.getJob());
_volsDao.update(volume.getId(), volume);
_resourceLimitMgr.updateVolumeResourceCountForDiskOfferingChange(volume.getAccountId(), volume.isDisplayVolume(), currentSize, newSize,
diskOffering, newDiskOffering);
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_RESIZE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(),
volume.getDiskOfferingId(), volume.getTemplateId(), volume.getSize(), Volume.class.getName(), volume.getUuid());
return volume;
}
if (jobResult != null) {
if (jobResult instanceof ConcurrentOperationException) {
throw (ConcurrentOperationException) jobResult;
} else if (jobResult instanceof ResourceAllocationException) {
throw (ResourceAllocationException) jobResult;
} else if (jobResult instanceof RuntimeException) {
throw (RuntimeException) jobResult;
} else if (jobResult instanceof Throwable) {
throw new RuntimeException("Unexpected exception", (Throwable) jobResult);
} else if (jobResult instanceof Long) {
return _volsDao.findById((Long) jobResult);
}
Long newDiskOfferingId = newDiskOffering != null ? newDiskOffering.getId() : diskOffering.getId();
boolean volumeMigrateRequired = false;
List<? extends StoragePool> suitableStoragePoolsWithEnoughSpace = null;
StoragePoolVO storagePool = _storagePoolDao.findById(volume.getPoolId());
if (!storageMgr.storagePoolHasEnoughSpaceForResize(storagePool, currentSize, newSize)) {
if (!autoMigrateVolume) {
throw new CloudRuntimeException(String.format("Failed to resize volume %s since the storage pool does not have enough space to accommodate new size for the volume %s, try with automigrate set to true in order to check in the other suitable pools for the new size and then migrate & resize volume there.", volume.getUuid(), volume.getName()));
}
Pair<List<? extends StoragePool>, List<? extends StoragePool>> poolsPair = managementService.listStoragePoolsForSystemMigrationOfVolume(volume.getId(), newDiskOfferingId, currentSize, newMinIops, newMaxIops, true, false);
List<? extends StoragePool> suitableStoragePools = poolsPair.second();
if (CollectionUtils.isEmpty(poolsPair.first()) && CollectionUtils.isEmpty(poolsPair.second())) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Volume resize failed for volume ID: %s as no suitable pool(s) found for migrating to support new disk offering or new size", volume.getUuid()));
}
final Long newSizeFinal = newSize;
suitableStoragePoolsWithEnoughSpace = suitableStoragePools.stream().filter(pool -> storageMgr.storagePoolHasEnoughSpaceForResize(pool, 0L, newSizeFinal)).collect(Collectors.toList());
if (CollectionUtils.isEmpty(suitableStoragePoolsWithEnoughSpace)) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Volume resize failed for volume ID: %s as no suitable pool(s) with enough space found.", volume.getUuid()));
}
Collections.shuffle(suitableStoragePoolsWithEnoughSpace);
volumeMigrateRequired = true;
}
boolean volumeResizeRequired = false;
if (currentSize != newSize || !compareEqualsIncludingNullOrZero(newMaxIops, volume.getMaxIops()) || !compareEqualsIncludingNullOrZero(newMinIops, volume.getMinIops())) {
volumeResizeRequired = true;
}
if (!volumeMigrateRequired && !volumeResizeRequired && newDiskOffering != null) {
_volsDao.updateDiskOffering(volume.getId(), newDiskOffering.getId());
volume = _volsDao.findById(volume.getId());
updateStorageWithTheNewDiskOffering(volume, newDiskOffering);
return volume;
}
}
return orchestrateResizeVolume(volume.getId(), currentSize, newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve, newDiskOffering != null ? cmd.getNewDiskOfferingId() : null,
shrinkOk);
if (volumeMigrateRequired) {
MigrateVolumeCmd migrateVolumeCmd = new MigrateVolumeCmd(volume.getId(), suitableStoragePoolsWithEnoughSpace.get(0).getId(), newDiskOfferingId, true);
try {
Volume result = migrateVolume(migrateVolumeCmd);
volume = (result != null) ? _volsDao.findById(result.getId()) : null;
if (volume == null) {
throw new CloudRuntimeException(String.format("Volume resize operation failed for volume ID: %s as migration failed to storage pool %s accommodating new size", volume.getUuid(), suitableStoragePoolsWithEnoughSpace.get(0).getId()));
}
} catch (Exception e) {
throw new CloudRuntimeException(String.format("Volume resize operation failed for volume ID: %s as migration failed to storage pool %s accommodating new size", volume.getUuid(), suitableStoragePoolsWithEnoughSpace.get(0).getId()));
}
}
UserVmVO userVm = _userVmDao.findById(volume.getInstanceId());
if (userVm != null) {
// serialize VM operation
AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
if (jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) {
// avoid re-entrance
VmWorkJobVO placeHolder = null;
placeHolder = createPlaceHolderWork(userVm.getId());
try {
return orchestrateResizeVolume(volume.getId(), currentSize, newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve,
newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk);
} finally {
_workJobDao.expunge(placeHolder.getId());
}
} else {
Outcome<Volume> outcome = resizeVolumeThroughJobQueue(userVm.getId(), volume.getId(), currentSize, newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve,
newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk);
try {
outcome.get();
} catch (InterruptedException e) {
throw new RuntimeException("Operation was interrupted", e);
} catch (ExecutionException e) {
throw new RuntimeException("Execution exception", e);
}
Object jobResult = _jobMgr.unmarshallResultObject(outcome.getJob());
if (jobResult != null) {
if (jobResult instanceof ConcurrentOperationException) {
throw (ConcurrentOperationException) jobResult;
} else if (jobResult instanceof ResourceAllocationException) {
throw (ResourceAllocationException) jobResult;
} else if (jobResult instanceof RuntimeException) {
throw (RuntimeException) jobResult;
} else if (jobResult instanceof Throwable) {
throw new RuntimeException("Unexpected exception", (Throwable) jobResult);
} else if (jobResult instanceof Long) {
return _volsDao.findById((Long) jobResult);
}
}
return volume;
}
}
return orchestrateResizeVolume(volume.getId(), currentSize, newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve, newDiskOffering != null ? cmd.getNewDiskOfferingId() : null,
shrinkOk);
} finally {
ReservationHelper.closeAll(reservations);
}
}
protected void validateNoVmSnapshots(VolumeVO volume) {
@ -1901,24 +1935,29 @@ 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());
_resourceLimitMgr.checkVolumeResourceLimit(_accountMgr.getAccount(volume.getAccountId()), volume.isDisplayVolume(), volume.getSize(), diskOffering, reservations);
try {
_volsDao.detachVolume(volume.getId());
stateTransitTo(volume, Volume.Event.RecoverRequested);
} catch (NoTransitionException e) {
logger.debug("Failed to recover volume {}", volume, e);
throw new CloudRuntimeException(String.format("Failed to recover volume %s", volume), e);
}
_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);
}
try {
_volsDao.detachVolume(volume.getId());
stateTransitTo(volume, Volume.Event.RecoverRequested);
} catch (NoTransitionException e) {
logger.debug("Failed to recover volume {}", volume, e);
throw new CloudRuntimeException(String.format("Failed to recover volume %s", volume), e);
}
_resourceLimitMgr.incrementVolumeResourceCount(volume.getAccountId(), volume.isDisplay(),
volume.getSize(), _diskOfferingDao.findById(volume.getDiskOfferingId()));
publishVolumeCreationUsageEvent(volume);
return volume;
@ -2147,96 +2186,102 @@ 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
if (volume.getState() == Volume.State.Allocated) {
logger.debug("Volume {} is in the allocated state, but has never been created. Simply updating database with new size and IOPS.", volume);
/* 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
if (volume.getState() == Volume.State.Allocated) {
logger.debug("Volume {} is in the allocated state, but has never been created. Simply updating database with new size and IOPS.", volume);
volume.setSize(newSize);
volume.setMinIops(newMinIops);
volume.setMaxIops(newMaxIops);
volume.setHypervisorSnapshotReserve(newHypervisorSnapshotReserve);
volume.setSize(newSize);
volume.setMinIops(newMinIops);
volume.setMaxIops(newMaxIops);
volume.setHypervisorSnapshotReserve(newHypervisorSnapshotReserve);
if (newDiskOffering != null) {
volume.setDiskOfferingId(newDiskOfferingId);
_volumeMgr.saveVolumeDetails(newDiskOfferingId, volume.getId());
}
_volsDao.update(volume.getId(), volume);
_resourceLimitMgr.updateVolumeResourceCountForDiskOfferingChange(volume.getAccountId(), volume.isDisplayVolume(), currentSize, newSize,
existingDiskOffering, newDiskOffering);
if (currentSize != newSize) {
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_RESIZE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(),
volume.getDiskOfferingId(), volume.getTemplateId(), volume.getSize(), Volume.class.getName(), volume.getUuid());
}
return volume;
}
if (currentSize != newSize || !compareEqualsIncludingNullOrZero(newMaxIops, volume.getMaxIops()) || !compareEqualsIncludingNullOrZero(newMinIops, volume.getMinIops())) {
volumeResizeRequired = true;
validateVolumeReadyStateAndHypervisorChecks(volume, currentSize, newSize);
}
StoragePoolVO existingStoragePool = _storagePoolDao.findById(volume.getPoolId());
Pair<List<? extends StoragePool>, List<? extends StoragePool>> poolsPair = managementService.listStoragePoolsForSystemMigrationOfVolume(volume.getId(), newDiskOffering.getId(), currentSize, newMinIops, newMaxIops, true, false);
List<? extends StoragePool> suitableStoragePools = poolsPair.second();
if (!suitableStoragePools.stream().anyMatch(p -> (p.getId() == existingStoragePool.getId()))) {
volumeMigrateRequired = true;
if (!autoMigrateVolume) {
throw new InvalidParameterValueException(String.format("Failed to change offering for volume %s since automigrate is set to false but volume needs to migrated", volume.getUuid()));
}
}
if (!volumeMigrateRequired && !volumeResizeRequired) {
_volsDao.updateDiskOffering(volume.getId(), newDiskOffering.getId());
volume = _volsDao.findById(volume.getId());
updateStorageWithTheNewDiskOffering(volume, newDiskOffering);
return volume;
}
if (volumeMigrateRequired) {
if (CollectionUtils.isEmpty(poolsPair.first()) && CollectionUtils.isEmpty(poolsPair.second())) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Volume change offering operation failed for volume: %s as no suitable pool(s) found for migrating to support new disk offering", volume));
}
final Long newSizeFinal = newSize;
List<? extends StoragePool> suitableStoragePoolsWithEnoughSpace = suitableStoragePools.stream().filter(pool -> storageMgr.storagePoolHasEnoughSpaceForResize(pool, 0L, newSizeFinal)).collect(Collectors.toList());
if (CollectionUtils.isEmpty(suitableStoragePoolsWithEnoughSpace)) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Volume change offering operation failed for volume: %s as no suitable pool(s) with enough space found for volume migration.", volume));
}
Collections.shuffle(suitableStoragePoolsWithEnoughSpace);
MigrateVolumeCmd migrateVolumeCmd = new MigrateVolumeCmd(volume.getId(), suitableStoragePoolsWithEnoughSpace.get(0).getId(), newDiskOffering.getId(), true);
try {
Volume result = migrateVolume(migrateVolumeCmd);
volume = (result != null) ? _volsDao.findById(result.getId()) : null;
if (volume == null) {
throw new CloudRuntimeException(String.format("Volume change offering operation failed for volume: %s migration failed to storage pool %s", volume, suitableStoragePools.get(0)));
if (newDiskOffering != null) {
volume.setDiskOfferingId(newDiskOfferingId);
_volumeMgr.saveVolumeDetails(newDiskOfferingId, volume.getId());
}
} catch (Exception e) {
throw new CloudRuntimeException(String.format("Volume change offering operation failed for volume: %s migration failed to storage pool %s due to %s", volume, suitableStoragePools.get(0), e.getMessage()));
}
}
if (volumeResizeRequired) {
// refresh volume data
volume = _volsDao.findById(volume.getId());
try {
volume = resizeVolumeInternal(volume, newDiskOffering, currentSize, newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve, shrinkOk);
} catch (Exception e) {
if (volumeMigrateRequired) {
logger.warn(String.format("Volume change offering operation succeeded for volume ID: %s but volume resize operation failed, so please try resize volume operation separately", volume.getUuid()));
} else {
throw new CloudRuntimeException(String.format("Volume change offering operation failed for volume ID: %s due to resize volume operation failed", volume.getUuid()));
_volsDao.update(volume.getId(), volume);
_resourceLimitMgr.updateVolumeResourceCountForDiskOfferingChange(volume.getAccountId(), volume.isDisplayVolume(), currentSize, newSize,
existingDiskOffering, newDiskOffering);
if (currentSize != newSize) {
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_RESIZE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(),
volume.getDiskOfferingId(), volume.getTemplateId(), volume.getSize(), Volume.class.getName(), volume.getUuid());
}
return volume;
}
if (currentSize != newSize || !compareEqualsIncludingNullOrZero(newMaxIops, volume.getMaxIops()) || !compareEqualsIncludingNullOrZero(newMinIops, volume.getMinIops())) {
volumeResizeRequired = true;
validateVolumeReadyStateAndHypervisorChecks(volume, currentSize, newSize);
}
StoragePoolVO existingStoragePool = _storagePoolDao.findById(volume.getPoolId());
Pair<List<? extends StoragePool>, List<? extends StoragePool>> poolsPair = managementService.listStoragePoolsForSystemMigrationOfVolume(volume.getId(), newDiskOffering.getId(), currentSize, newMinIops, newMaxIops, true, false);
List<? extends StoragePool> suitableStoragePools = poolsPair.second();
if (!suitableStoragePools.stream().anyMatch(p -> (p.getId() == existingStoragePool.getId()))) {
volumeMigrateRequired = true;
if (!autoMigrateVolume) {
throw new InvalidParameterValueException(String.format("Failed to change offering for volume %s since automigrate is set to false but volume needs to migrated", volume.getUuid()));
}
}
}
return volume;
if (!volumeMigrateRequired && !volumeResizeRequired) {
_volsDao.updateDiskOffering(volume.getId(), newDiskOffering.getId());
volume = _volsDao.findById(volume.getId());
updateStorageWithTheNewDiskOffering(volume, newDiskOffering);
return volume;
}
if (volumeMigrateRequired) {
if (CollectionUtils.isEmpty(poolsPair.first()) && CollectionUtils.isEmpty(poolsPair.second())) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Volume change offering operation failed for volume: %s as no suitable pool(s) found for migrating to support new disk offering", volume));
}
final Long newSizeFinal = newSize;
List<? extends StoragePool> suitableStoragePoolsWithEnoughSpace = suitableStoragePools.stream().filter(pool -> storageMgr.storagePoolHasEnoughSpaceForResize(pool, 0L, newSizeFinal)).collect(Collectors.toList());
if (CollectionUtils.isEmpty(suitableStoragePoolsWithEnoughSpace)) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Volume change offering operation failed for volume: %s as no suitable pool(s) with enough space found for volume migration.", volume));
}
Collections.shuffle(suitableStoragePoolsWithEnoughSpace);
MigrateVolumeCmd migrateVolumeCmd = new MigrateVolumeCmd(volume.getId(), suitableStoragePoolsWithEnoughSpace.get(0).getId(), newDiskOffering.getId(), true);
try {
Volume result = migrateVolume(migrateVolumeCmd);
volume = (result != null) ? _volsDao.findById(result.getId()) : null;
if (volume == null) {
throw new CloudRuntimeException(String.format("Volume change offering operation failed for volume: %s migration failed to storage pool %s", volume, suitableStoragePools.get(0)));
}
} catch (Exception e) {
throw new CloudRuntimeException(String.format("Volume change offering operation failed for volume: %s migration failed to storage pool %s due to %s", volume, suitableStoragePools.get(0), e.getMessage()));
}
}
if (volumeResizeRequired) {
// refresh volume data
volume = _volsDao.findById(volume.getId());
try {
volume = resizeVolumeInternal(volume, newDiskOffering, currentSize, newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve, shrinkOk);
} catch (Exception e) {
if (volumeMigrateRequired) {
logger.warn(String.format("Volume change offering operation succeeded for volume ID: %s but volume resize operation failed, so please try resize volume operation separately", volume.getUuid()));
} else {
throw new CloudRuntimeException(String.format("Volume change offering operation failed for volume ID: %s due to resize volume operation failed", volume.getUuid()));
}
}
}
return volume;
} finally {
ReservationHelper.closeAll(reservations);
}
}
private void updateStorageWithTheNewDiskOffering(VolumeVO volume, DiskOfferingVO newDiskOffering) {
@ -2442,7 +2487,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) {
@ -2507,7 +2552,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
@ -2686,7 +2731,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) {
@ -2710,6 +2755,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)) {
@ -2717,9 +2768,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;
@ -2768,21 +2831,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);
@ -4348,7 +4396,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
@ -4358,6 +4408,10 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
});
return volume;
} finally {
ReservationHelper.closeAll(reservations);
}
}
protected void updateVolumeAccount(Account oldAccount, VolumeVO volume, Account newAccount) {
@ -5314,20 +5368,20 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
private Pair<JobInfo.Status, String> orchestrateAttachVolumeToVM(VmWorkAttachVolume work) throws Exception {
Volume vol = orchestrateAttachVolumeToVM(work.getVmId(), work.getVolumeId(), work.getDeviceId());
return new Pair<JobInfo.Status, String>(JobInfo.Status.SUCCEEDED, _jobMgr.marshallResultObject(new Long(vol.getId())));
return new Pair<JobInfo.Status, String>(JobInfo.Status.SUCCEEDED, _jobMgr.marshallResultObject(vol.getId()));
}
@ReflectionUse
private Pair<JobInfo.Status, String> orchestrateDetachVolumeFromVM(VmWorkDetachVolume work) throws Exception {
Volume vol = orchestrateDetachVolumeFromVM(work.getVmId(), work.getVolumeId());
return new Pair<JobInfo.Status, String>(JobInfo.Status.SUCCEEDED, _jobMgr.marshallResultObject(new Long(vol.getId())));
return new Pair<JobInfo.Status, String>(JobInfo.Status.SUCCEEDED, _jobMgr.marshallResultObject(vol.getId()));
}
@ReflectionUse
private Pair<JobInfo.Status, String> orchestrateResizeVolume(VmWorkResizeVolume work) throws Exception {
Volume vol = orchestrateResizeVolume(work.getVolumeId(), work.getCurrentSize(), work.getNewSize(), work.getNewMinIops(), work.getNewMaxIops(), work.getNewHypervisorSnapshotReserve(),
work.getNewServiceOfferingId(), work.isShrinkOk());
return new Pair<JobInfo.Status, String>(JobInfo.Status.SUCCEEDED, _jobMgr.marshallResultObject(new Long(vol.getId())));
return new Pair<JobInfo.Status, String>(JobInfo.Status.SUCCEEDED, _jobMgr.marshallResultObject(vol.getId()));
}
@ReflectionUse

View File

@ -95,6 +95,11 @@ public abstract class DownloadActiveState extends DownloadState {
return Status.ABANDONED.toString();
}
@Override
public String handleLimitReached() {
return Status.LIMIT_REACHED.toString();
}
@Override
public String handleDisconnect() {

View File

@ -60,6 +60,11 @@ public class DownloadErrorState extends DownloadInactiveState {
return Status.ABANDONED.toString();
}
@Override
public String handleLimitReached() {
return Status.LIMIT_REACHED.toString();
}
@Override
public String getName() {
return Status.DOWNLOAD_ERROR.toString();

View File

@ -36,6 +36,12 @@ public abstract class DownloadInactiveState extends DownloadState {
return getName();
}
@Override
public String handleLimitReached() {
// ignore and stay put
return getName();
}
@Override
public String handleDisconnect() {
//ignore and stay put

View File

@ -0,0 +1,54 @@
// 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.storage.download;
import org.apache.cloudstack.storage.command.DownloadProgressCommand.RequestType;
import org.apache.logging.log4j.Level;
import com.cloud.agent.api.storage.DownloadAnswer;
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
public class DownloadLimitReachedState extends DownloadInactiveState {
public DownloadLimitReachedState(DownloadListener dl) {
super(dl);
}
@Override
public String getName() {
return Status.LIMIT_REACHED.toString();
}
@Override
public String handleEvent(DownloadEvent event, Object eventObj) {
if (logger.isTraceEnabled()) {
getDownloadListener().log("handleEvent, event type=" + event + ", curr state=" + getName(), Level.TRACE);
}
return Status.LIMIT_REACHED.toString();
}
@Override
public void onEntry(String prevState, DownloadEvent event, Object evtObj) {
if (!prevState.equalsIgnoreCase(getName())) {
DownloadAnswer answer = new DownloadAnswer("Storage Limit Reached", Status.LIMIT_REACHED);
getDownloadListener().callback(answer);
getDownloadListener().cancelStatusTask();
getDownloadListener().cancelTimeoutTask();
getDownloadListener().scheduleImmediateStatusCheck(RequestType.PURGE);
}
}
}

View File

@ -25,6 +25,15 @@ import java.util.Timer;
import javax.inject.Inject;
import com.cloud.configuration.Resource;
import com.cloud.resourcelimit.CheckedReservation;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.ResourceLimitService;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
@ -34,10 +43,13 @@ import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService;
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
import org.apache.cloudstack.managed.context.ManagedContextTimerTask;
import org.apache.cloudstack.reservation.dao.ReservationDao;
import org.apache.cloudstack.storage.command.DownloadCommand;
import org.apache.cloudstack.storage.command.DownloadCommand.ResourceType;
import org.apache.cloudstack.storage.command.DownloadProgressCommand;
import org.apache.cloudstack.storage.command.DownloadProgressCommand.RequestType;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
import org.apache.cloudstack.utils.cache.LazyCache;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
@ -107,6 +119,7 @@ public class DownloadListener implements Listener {
public static final String DOWNLOAD_ERROR = Status.DOWNLOAD_ERROR.toString();
public static final String DOWNLOAD_IN_PROGRESS = Status.DOWNLOAD_IN_PROGRESS.toString();
public static final String DOWNLOAD_ABANDONED = Status.ABANDONED.toString();
public static final String DOWNLOAD_LIMIT_REACHED = Status.LIMIT_REACHED.toString();
private EndPoint _ssAgent;
@ -137,6 +150,18 @@ public class DownloadListener implements Listener {
private DataStoreManager _storeMgr;
@Inject
private VolumeService _volumeSrv;
@Inject
private VMTemplateDao _templateDao;
@Inject
private TemplateDataStoreDao _templateDataStoreDao;
@Inject
private VolumeDao _volumeDao;
@Inject
private ResourceLimitService _resourceLimitMgr;
@Inject
private AccountManager _accountMgr;
@Inject
ReservationDao _reservationDao;
private LazyCache<Long, List<Hypervisor.HypervisorType>> zoneHypervisorsCache;
@ -160,7 +185,7 @@ public class DownloadListener implements Listener {
_downloadMonitor = downloadMonitor;
_cmd = cmd;
initStateMachine();
_currState = getState(Status.NOT_DOWNLOADED.toString());
_currState = getState(NOT_DOWNLOADED);
this._timer = timer;
_timeoutTask = new TimeoutTask(this);
this._timer.schedule(_timeoutTask, 3 * STATUS_POLL_INTERVAL);
@ -184,11 +209,12 @@ public class DownloadListener implements Listener {
}
private void initStateMachine() {
_stateMap.put(Status.NOT_DOWNLOADED.toString(), new NotDownloadedState(this));
_stateMap.put(Status.DOWNLOADED.toString(), new DownloadCompleteState(this));
_stateMap.put(Status.DOWNLOAD_ERROR.toString(), new DownloadErrorState(this));
_stateMap.put(Status.DOWNLOAD_IN_PROGRESS.toString(), new DownloadInProgressState(this));
_stateMap.put(Status.ABANDONED.toString(), new DownloadAbandonedState(this));
_stateMap.put(NOT_DOWNLOADED, new NotDownloadedState(this));
_stateMap.put(DOWNLOADED, new DownloadCompleteState(this));
_stateMap.put(DOWNLOAD_ERROR, new DownloadErrorState(this));
_stateMap.put(DOWNLOAD_IN_PROGRESS, new DownloadInProgressState(this));
_stateMap.put(DOWNLOAD_ABANDONED, new DownloadAbandonedState(this));
_stateMap.put(DOWNLOAD_LIMIT_REACHED, new DownloadLimitReachedState(this));
}
private DownloadState getState(String stateName) {
@ -239,10 +265,53 @@ public class DownloadListener implements Listener {
return false;
}
private Long getAccountIdForDataObject() {
if (object == null) {
return null;
}
if (DataObjectType.TEMPLATE.equals(object.getType())) {
VMTemplateVO t = _templateDao.findById(object.getId());
return t != null ? t.getAccountId() : null;
} else if (DataObjectType.VOLUME.equals(object.getType())) {
VolumeVO v = _volumeDao.findById(object.getId());
return v != null ? v.getAccountId() : null;
}
return null;
}
private Long getSizeFromDB() {
Long lastSize = 0L;
if (DataObjectType.TEMPLATE.equals(object.getType())) {
TemplateDataStoreVO t = _templateDataStoreDao.findByStoreTemplate(object.getDataStore().getId(), object.getId());
lastSize = t.getSize();
} else if (DataObjectType.VOLUME.equals(object.getType())) {
VolumeVO v = _volumeDao.findById(object.getId());
lastSize = v.getSize();
}
return lastSize;
}
private Boolean checkAndUpdateResourceLimits(DownloadAnswer answer) {
Long lastSize = getSizeFromDB();
Long currentSize = answer.getTemplateSize();
if (currentSize > lastSize) {
Long accountId = getAccountIdForDataObject();
Account account = _accountMgr.getAccount(accountId);
Long usage = currentSize - lastSize;
try (CheckedReservation secStorageReservation = new CheckedReservation(account, Resource.ResourceType.secondary_storage, usage, _reservationDao, _resourceLimitMgr)) {
_resourceLimitMgr.incrementResourceCount(accountId, Resource.ResourceType.secondary_storage, usage);
} catch (Exception e) {
return false;
}
}
return true;
}
@Override
public boolean processAnswers(long agentId, long seq, Answer[] answers) {
boolean processed = false;
if (answers != null & answers.length > 0) {
if (answers != null && answers.length > 0) {
if (answers[0] instanceof DownloadAnswer) {
final DownloadAnswer answer = (DownloadAnswer)answers[0];
if (getJobId() == null) {
@ -250,7 +319,11 @@ public class DownloadListener implements Listener {
} else if (!getJobId().equalsIgnoreCase(answer.getJobId())) {
return false;//TODO
}
transition(DownloadEvent.DOWNLOAD_ANSWER, answer);
if (!checkAndUpdateResourceLimits(answer)) {
transition(DownloadEvent.LIMIT_REACHED, answer);
} else {
transition(DownloadEvent.DOWNLOAD_ANSWER, answer);
}
processed = true;
}
}

View File

@ -26,7 +26,7 @@ import com.cloud.agent.api.storage.DownloadAnswer;
public abstract class DownloadState {
public static enum DownloadEvent {
DOWNLOAD_ANSWER, ABANDON_DOWNLOAD, TIMEOUT_CHECK, DISCONNECT
DOWNLOAD_ANSWER, ABANDON_DOWNLOAD, LIMIT_REACHED, TIMEOUT_CHECK, DISCONNECT
};
protected Logger logger = LogManager.getLogger(getClass());
@ -51,6 +51,8 @@ public abstract class DownloadState {
return handleAnswer(answer);
case ABANDON_DOWNLOAD:
return handleAbort();
case LIMIT_REACHED:
return handleLimitReached();
case TIMEOUT_CHECK:
Date now = new Date();
long update = now.getTime() - dl.getLastUpdated().getTime();
@ -78,6 +80,8 @@ public abstract class DownloadState {
public abstract String handleAbort();
public abstract String handleLimitReached();
public abstract String handleDisconnect();
public abstract String handleAnswer(DownloadAnswer answer);

View File

@ -16,8 +16,6 @@
// under the License.
package com.cloud.storage.snapshot;
import com.cloud.storage.StoragePoolStatus;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@ -36,9 +34,6 @@ import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import com.cloud.host.dao.HostDao;
import com.cloud.storage.Upload;
import com.cloud.storage.dao.SnapshotDetailsDao;
import org.apache.cloudstack.acl.SecurityChecker;
import com.cloud.api.ApiDBUtils;
import org.apache.cloudstack.annotation.AnnotationService;
@ -77,6 +72,7 @@ import org.apache.cloudstack.framework.config.Configurable;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.framework.jobs.AsyncJob;
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
import org.apache.cloudstack.reservation.dao.ReservationDao;
import org.apache.cloudstack.resourcedetail.SnapshotPolicyDetailVO;
import org.apache.cloudstack.resourcedetail.dao.SnapshotPolicyDetailsDao;
import org.apache.cloudstack.snapshot.SnapshotHelper;
@ -119,10 +115,12 @@ import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.exception.StorageUnavailableException;
import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.org.Grouping;
import com.cloud.projects.Project.ListProjectResourcesCriteria;
import com.cloud.resource.ResourceManager;
import com.cloud.resourcelimit.CheckedReservation;
import com.cloud.server.ResourceTag.ResourceObjectType;
import com.cloud.server.TaggedResourceService;
import com.cloud.storage.CreateSnapshotPayload;
@ -135,15 +133,18 @@ import com.cloud.storage.SnapshotPolicyVO;
import com.cloud.storage.SnapshotScheduleVO;
import com.cloud.storage.SnapshotVO;
import com.cloud.storage.Storage;
import com.cloud.storage.StoragePoolStatus;
import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePool;
import com.cloud.storage.Upload;
import com.cloud.storage.VMTemplateStorageResourceAssoc;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.Volume;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.DiskOfferingDao;
import com.cloud.storage.dao.SnapshotDetailsDao;
import com.cloud.storage.dao.SnapshotDao;
import com.cloud.storage.dao.SnapshotPolicyDao;
import com.cloud.storage.dao.SnapshotScheduleDao;
@ -251,7 +252,8 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
public TaggedResourceService taggedResourceService;
@Inject
private AnnotationDao annotationDao;
@Inject
private ReservationDao reservationDao;
@Inject
protected SnapshotHelper snapshotHelper;
@Inject
@ -321,7 +323,7 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
hostIdsToTryFirst = new long[] {vmHostId};
}
List<Long> hostIdsToAvoid = new ArrayList<Long>();
List<Long> hostIdsToAvoid = new ArrayList<>();
for (int retry = _totalRetries; retry >= 0; retry--) {
try {
Pair<Long, Answer> result = _storageMgr.sendToPool(pool, hostIdsToTryFirst, hostIdsToAvoid, cmd);
@ -421,7 +423,7 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
}
public void updateVolumeSizeAndPrimaryStorageCount(VolumeVO volume, SnapshotVO snapshot) {
Long differenceBetweenVolumeAndSnapshotSize = new Long(volume.getSize() - snapshot.getSize());
long differenceBetweenVolumeAndSnapshotSize = volume.getSize() - snapshot.getSize();
if (differenceBetweenVolumeAndSnapshotSize != 0) {
if (differenceBetweenVolumeAndSnapshotSize > 0) {
_resourceLimitMgr.decrementResourceCount(snapshot.getAccountId(), ResourceType.primary_storage, differenceBetweenVolumeAndSnapshotSize);
@ -695,7 +697,7 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
} catch (Exception e) {
logger.debug("Failed to backup Snapshot from Instance Snapshot", e);
_resourceLimitMgr.decrementResourceCount(snapshotOwnerId, ResourceType.snapshot);
_resourceLimitMgr.decrementResourceCount(snapshotOwnerId, ResourceType.secondary_storage, new Long(volume.getSize()));
_resourceLimitMgr.decrementResourceCount(snapshotOwnerId, ResourceType.secondary_storage, volume.getSize());
throw new CloudRuntimeException("Failed to backup Snapshot from Instance Snapshot", e);
} finally {
if (snapshotOnPrimaryStore != null) {
@ -910,43 +912,36 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
List<SnapshotDataStoreVO> snapshotStoreRefs = storeRefAndZones.first();
List<Long> zoneIds = storeRefAndZones.second();
boolean result = snapshotStrategy.deleteSnapshot(snapshotId, zoneId);
if (result) {
for (Long zId : zoneIds) {
if (snapshotCheck.getState() == Snapshot.State.BackedUp) {
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_DELETE, snapshotCheck.getAccountId(), zId, snapshotId,
snapshotCheck.getName(), null, null, 0L, snapshotCheck.getClass().getName(), snapshotCheck.getUuid());
try {
boolean result = snapshotStrategy.deleteSnapshot(snapshotId, zoneId);
if (result) {
for (Long zId : zoneIds) {
if (snapshotCheck.getState() == Snapshot.State.BackedUp) {
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_DELETE, snapshotCheck.getAccountId(), zId, snapshotId,
snapshotCheck.getName(), null, null, 0L, snapshotCheck.getClass().getName(), snapshotCheck.getUuid());
}
}
final SnapshotVO postDeleteSnapshotEntry = _snapshotDao.findById(snapshotId);
if (postDeleteSnapshotEntry == null || Snapshot.State.Destroyed.equals(postDeleteSnapshotEntry.getState())) {
annotationDao.removeByEntityType(AnnotationService.EntityType.SNAPSHOT.name(), snapshotCheck.getUuid());
if (snapshotCheck.getState() != Snapshot.State.Error && snapshotCheck.getState() != Snapshot.State.Destroyed) {
_resourceLimitMgr.decrementResourceCount(snapshotCheck.getAccountId(), ResourceType.snapshot);
}
}
for (SnapshotDataStoreVO snapshotStoreRef : snapshotStoreRefs) {
if (ObjectInDataStoreStateMachine.State.Ready.equals(snapshotStoreRef.getState()) && !DataStoreRole.Primary.equals(snapshotStoreRef.getRole())) {
_resourceLimitMgr.decrementResourceCount(snapshotCheck.getAccountId(), ResourceType.secondary_storage, snapshotStoreRef.getPhysicalSize());
}
}
}
final SnapshotVO postDeleteSnapshotEntry = _snapshotDao.findById(snapshotId);
if (postDeleteSnapshotEntry == null || Snapshot.State.Destroyed.equals(postDeleteSnapshotEntry.getState())) {
annotationDao.removeByEntityType(AnnotationService.EntityType.SNAPSHOT.name(), snapshotCheck.getUuid());
if (snapshotCheck.getState() != Snapshot.State.Error && snapshotCheck.getState() != Snapshot.State.Destroyed) {
_resourceLimitMgr.decrementResourceCount(snapshotCheck.getAccountId(), ResourceType.snapshot);
}
}
for (SnapshotDataStoreVO snapshotStoreRef : snapshotStoreRefs) {
if (ObjectInDataStoreStateMachine.State.Ready.equals(snapshotStoreRef.getState()) && !DataStoreRole.Primary.equals(snapshotStoreRef.getRole())) {
_resourceLimitMgr.decrementResourceCount(snapshotCheck.getAccountId(), ResourceType.secondary_storage, new Long(snapshotStoreRef.getPhysicalSize()));
}
}
}
final SnapshotVO postDeleteSnapshotEntry = _snapshotDao.findById(snapshotId);
if (postDeleteSnapshotEntry == null || Snapshot.State.Destroyed.equals(postDeleteSnapshotEntry.getState())) {
annotationDao.removeByEntityType(AnnotationService.EntityType.SNAPSHOT.name(), snapshotCheck.getUuid());
return result;
} catch (Exception e) {
logger.debug("Failed to delete snapshot {}:{}", snapshotCheck, e.toString());
if (snapshotCheck.getState() != Snapshot.State.Error && snapshotCheck.getState() != Snapshot.State.Destroyed) {
_resourceLimitMgr.decrementResourceCount(snapshotCheck.getAccountId(), ResourceType.snapshot);
}
throw new CloudRuntimeException("Failed to delete snapshot:" + e.toString());
}
for (SnapshotDataStoreVO snapshotStoreRef : snapshotStoreRefs) {
if (ObjectInDataStoreStateMachine.State.Ready.equals(snapshotStoreRef.getState()) && !DataStoreRole.Primary.equals(snapshotStoreRef.getRole())) {
_resourceLimitMgr.decrementResourceCount(snapshotCheck.getAccountId(), ResourceType.secondary_storage, new Long(snapshotStoreRef.getPhysicalSize()));
}
}
return result;
}
@Override
@ -960,7 +955,7 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
Map<String, String> tags = cmd.getTags();
Long zoneId = cmd.getZoneId();
Account caller = CallContext.current().getCallingAccount();
List<Long> permittedAccounts = new ArrayList<Long>();
List<Long> permittedAccounts = new ArrayList<>();
// Verify parameters
if (volumeId != null) {
@ -972,7 +967,7 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
List<Long> ids = getIdsListFromCmd(cmd.getId(), cmd.getIds());
Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(cmd.getDomainId(),
Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<>(cmd.getDomainId(),
cmd.isRecursive(), null);
_accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false);
Long domainId = domainIdRecursiveListProject.first();
@ -1065,7 +1060,7 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
}
Pair<List<SnapshotVO>, Integer> result = _snapshotDao.searchAndCount(sc, searchFilter);
return new Pair<List<? extends Snapshot>, Integer>(result.first(), result.second());
return new Pair<>(result.first(), result.second());
}
@Override
@ -1081,7 +1076,7 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
if (volume.getPoolId() == null) {
continue;
}
Long volumeId = volume.getId();
long volumeId = volume.getId();
Long dcId = volume.getDataCenterId();
if (_snapshotDao.listByVolumeIdIncludingRemoved(volumeId).isEmpty()) {
// This volume doesn't have any snapshots. Nothing do delete.
@ -1125,7 +1120,7 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
if (Type.MANUAL == snapshot.getRecurringType()) {
_resourceLimitMgr.decrementResourceCount(accountId, ResourceType.snapshot);
for (SnapshotDataStoreVO snapshotStoreRef : snapshotStoreRefs) {
_resourceLimitMgr.decrementResourceCount(accountId, ResourceType.secondary_storage, new Long(snapshotStoreRef.getPhysicalSize()));
_resourceLimitMgr.decrementResourceCount(accountId, ResourceType.secondary_storage, snapshotStoreRef.getPhysicalSize());
}
}
@ -1154,7 +1149,6 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
throw new InvalidParameterValueException("Backing up of snapshot is not supported by the zone of the volume. Snapshots can not be taken for multiple zones");
}
boolean isRootAdminCaller = _accountMgr.isRootAdmin(caller.getId());
if (hasZones) {
for (Long zoneId : zoneIds) {
getCheckedDestinationZoneForSnapshotCopy(zoneId, isRootAdminCaller);
@ -1290,7 +1284,6 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
logger.debug("Acquired lock for creating snapshot policy [{}] for volume {}.", intervalType, volume);
try {
SnapshotPolicyVO policy = _snapshotPolicyDao.findOneByVolumeInterval(volumeId, intervalType);
@ -1497,7 +1490,7 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
}
// List only future schedules, not past ones.
List<SnapshotScheduleVO> snapshotSchedules = new ArrayList<SnapshotScheduleVO>();
List<SnapshotScheduleVO> snapshotSchedules = new ArrayList<>();
if (policyId == null) {
List<SnapshotPolicyVO> policyInstances = listPoliciesforVolume(volumeId);
for (SnapshotPolicyVO policyInstance : policyInstances) {
@ -1631,7 +1624,6 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
Long snapshotId = payload.getSnapshotId();
Account snapshotOwner = payload.getAccount();
SnapshotInfo snapshot = snapshotFactory.getSnapshot(snapshotId, volume.getDataStore());
StoragePool storagePool = _storagePoolDao.findById(volume.getPoolId());
@ -1697,7 +1689,7 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
ResourceType storeResourceType = dataStoreRole == DataStoreRole.Image ? ResourceType.secondary_storage : ResourceType.primary_storage;
// Correct the resource count of snapshot in case of delta snapshots.
_resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), storeResourceType, new Long(volume.getSize() - snapshotStoreRef.getPhysicalSize()));
_resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), storeResourceType, volume.getSize() - snapshotStoreRef.getPhysicalSize());
if (!payload.getAsyncBackup()) {
if (backupSnapToSecondary) {
@ -1716,7 +1708,7 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
}
ResourceType storeResourceType = getStoreResourceType(volume.getDataCenterId(), payload.getLocationType());
_resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), ResourceType.snapshot);
_resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), storeResourceType, new Long(volume.getSize()));
_resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), storeResourceType, volume.getSize());
throw cre;
} catch (Exception e) {
if (logger.isDebugEnabled()) {
@ -1724,7 +1716,7 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
}
ResourceType storeResourceType = getStoreResourceType(volume.getDataCenterId(), payload.getLocationType());
_resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), ResourceType.snapshot);
_resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), storeResourceType, new Long(volume.getSize()));
_resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), storeResourceType, volume.getSize());
throw new CloudRuntimeException("Failed to create snapshot", e);
}
return snapshot;
@ -1934,7 +1926,7 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
}
if (policyIds == null) {
policyIds = new ArrayList<Long>();
policyIds = new ArrayList<>();
policyIds.add(policyId);
} else if (policyIds.size() <= 0) {
// Not even sure how this is even possible
@ -2017,20 +2009,6 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
Type snapshotType = getSnapshotType(policyId);
Account owner = _accountMgr.getAccount(volume.getAccountId());
ResourceType storeResourceType = getStoreResourceType(volume.getDataCenterId(), locationType);
try {
_resourceLimitMgr.checkResourceLimit(owner, ResourceType.snapshot);
_resourceLimitMgr.checkResourceLimit(owner, storeResourceType, volume.getSize());
} catch (ResourceAllocationException e) {
if (snapshotType != Type.MANUAL) {
String msg = String.format("Snapshot resource limit exceeded for account %s. Failed to create recurring snapshots", owner);
logger.warn(msg);
_alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_UPDATE_RESOURCE_COUNT, 0L, 0L, msg, "Snapshot resource limit exceeded for account id : " + owner.getId()
+ ". Failed to create recurring snapshots; please use updateResourceLimit to increase the limit");
}
throw e;
}
// Determine the name for this snapshot
// Snapshot Name: VMInstancename + volumeName + timeString
String timeString = DateUtil.getDateDisplayString(DateUtil.GMT_TIMEZONE, new Date(), DateUtil.YYYYMMDD_FORMAT);
@ -2062,6 +2040,14 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
hypervisorType = volume.getHypervisorType();
}
ResourceType storeResourceType = ResourceType.secondary_storage;
if (!isBackupSnapshotToSecondaryForZone(volume.getDataCenterId()) ||
Snapshot.LocationType.PRIMARY.equals(locationType)) {
storeResourceType = ResourceType.primary_storage;
}
try (CheckedReservation volumeSnapshotReservation = new CheckedReservation(owner, ResourceType.snapshot, null, null, 1L, reservationDao, _resourceLimitMgr);
CheckedReservation storageReservation = new CheckedReservation(owner, storeResourceType, null, null, volume.getSize(), reservationDao, _resourceLimitMgr)) {
SnapshotVO snapshotVO = new SnapshotVO(volume.getDataCenterId(), volume.getAccountId(), volume.getDomainId(), volume.getId(), volume.getDiskOfferingId(), snapshotName,
(short)snapshotType.ordinal(), snapshotType.name(), volume.getSize(), volume.getMinIops(), volume.getMaxIops(), hypervisorType, locationType);
@ -2073,6 +2059,14 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
_resourceLimitMgr.incrementResourceCount(volume.getAccountId(), ResourceType.snapshot);
_resourceLimitMgr.incrementResourceCount(volume.getAccountId(), storeResourceType, volume.getSize());
return snapshot;
} 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 e;
}
}
@Override
@ -2122,57 +2116,61 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
@DB
private boolean copySnapshotToZone(SnapshotDataStoreVO snapshotDataStoreVO, DataStore srcSecStore,
DataCenterVO dstZone, DataStore dstSecStore, Account account, boolean kvmIncrementalSnapshot)
DataCenterVO dstZone, DataStore dstSecStore, Account account, boolean kvmIncrementalSnapshot, boolean shouldCheckResourceLimits)
throws ResourceAllocationException {
final long snapshotId = snapshotDataStoreVO.getSnapshotId();
final long dstZoneId = dstZone.getId();
if (checkAndProcessSnapshotAlreadyExistInStore(snapshotId, dstSecStore)) {
return true;
}
_resourceLimitMgr.checkResourceLimit(account, ResourceType.secondary_storage, snapshotDataStoreVO.getSize());
// snapshotId may refer to ID of a removed parent snapshot
SnapshotInfo snapshotOnSecondary = snapshotFactory.getSnapshot(snapshotId, srcSecStore);
if (kvmIncrementalSnapshot) {
snapshotOnSecondary = snapshotHelper.convertSnapshotIfNeeded(snapshotOnSecondary);
}
String copyUrl = null;
try {
AsyncCallFuture<CreateCmdResult> future = snapshotSrv.queryCopySnapshot(snapshotOnSecondary);
CreateCmdResult result = future.get();
if (!result.isFailed()) {
copyUrl = result.getPath();
// Resource limit checks are not performed here at the moment, but they were added in case this method is used
// in the future to copy a standalone snapshot
long requiredSecondaryStorageSpace = shouldCheckResourceLimits ? snapshotDataStoreVO.getSize() : 0L;
try (CheckedReservation secondaryStorageReservation = new CheckedReservation(account, ResourceType.secondary_storage, null, null, null, requiredSecondaryStorageSpace, null, reservationDao, _resourceLimitMgr)) {
// snapshotId may refer to ID of a removed parent snapshot
SnapshotInfo snapshotOnSecondary = snapshotFactory.getSnapshot(snapshotId, srcSecStore);
if (kvmIncrementalSnapshot) {
snapshotOnSecondary = snapshotHelper.convertSnapshotIfNeeded(snapshotOnSecondary);
}
} catch (InterruptedException | ExecutionException | ResourceUnavailableException ex) {
logger.error("Failed to prepare URL for copy for snapshot ID: {} on store: {}", snapshotId, srcSecStore, ex);
}
if (StringUtils.isEmpty(copyUrl)) {
logger.error("Unable to prepare URL for copy for snapshot ID: {} on store: {}", snapshotId, srcSecStore);
return false;
}
logger.debug(String.format("Copying snapshot ID: %d to destination zones using download URL: %s", snapshotId, copyUrl));
try {
AsyncCallFuture<SnapshotResult> future = snapshotSrv.copySnapshot(snapshotOnSecondary, copyUrl, dstSecStore);
SnapshotResult result = future.get();
if (result.isFailed()) {
logger.debug("Copy snapshot ID: {} failed for image store {}: {}", snapshotId, dstSecStore, result.getResult());
String copyUrl = null;
try {
AsyncCallFuture<CreateCmdResult> future = snapshotSrv.queryCopySnapshot(snapshotOnSecondary);
CreateCmdResult result = future.get();
if (!result.isFailed()) {
copyUrl = result.getPath();
}
} catch (InterruptedException | ExecutionException | ResourceUnavailableException ex) {
logger.error("Failed to prepare URL for copy for snapshot ID: {} on store: {}", snapshotId, srcSecStore, ex);
}
if (StringUtils.isEmpty(copyUrl)) {
logger.error("Unable to prepare URL for copy for snapshot ID: {} on store: {}", snapshotId, srcSecStore);
return false;
}
snapshotZoneDao.addSnapshotToZone(snapshotId, dstZoneId);
_resourceLimitMgr.incrementResourceCount(account.getId(), ResourceType.secondary_storage, snapshotDataStoreVO.getSize());
if (account.getId() != Account.ACCOUNT_ID_SYSTEM) {
SnapshotVO snapshotVO = _snapshotDao.findByIdIncludingRemoved(snapshotId);
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_COPY, account.getId(), dstZoneId, snapshotId, null, null, null, snapshotVO.getSize(),
snapshotVO.getSize(), snapshotVO.getClass().getName(), snapshotVO.getUuid());
}
if (kvmIncrementalSnapshot) {
((ImageStoreEntity) srcSecStore).deleteExtractUrl(snapshotOnSecondary.getPath(), copyUrl, Upload.Type.SNAPSHOT);
}
logger.debug(String.format("Copying snapshot ID: %d to destination zones using download URL: %s", snapshotId, copyUrl));
try {
AsyncCallFuture<SnapshotResult> future = snapshotSrv.copySnapshot(snapshotOnSecondary, copyUrl, dstSecStore);
SnapshotResult result = future.get();
if (result.isFailed()) {
logger.debug("Copy snapshot ID: {} failed for image store {}: {}", snapshotId, dstSecStore, result.getResult());
return false;
}
snapshotZoneDao.addSnapshotToZone(snapshotId, dstZoneId);
_resourceLimitMgr.incrementResourceCount(account.getId(), ResourceType.secondary_storage, snapshotDataStoreVO.getSize());
if (account.getId() != Account.ACCOUNT_ID_SYSTEM) {
SnapshotVO snapshotVO = _snapshotDao.findByIdIncludingRemoved(snapshotId);
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_COPY, account.getId(), dstZoneId, snapshotId, null, null, null, snapshotVO.getSize(),
snapshotVO.getSize(), snapshotVO.getClass().getName(), snapshotVO.getUuid());
}
if (kvmIncrementalSnapshot) {
((ImageStoreEntity) srcSecStore).deleteExtractUrl(snapshotOnSecondary.getPath(), copyUrl, Upload.Type.SNAPSHOT);
}
return true;
} catch (InterruptedException | ExecutionException | ResourceUnavailableException ex) {
logger.debug("Failed to copy snapshot ID: {} to image store: {}", snapshotId, dstSecStore);
return true;
} catch (InterruptedException | ExecutionException | ResourceUnavailableException ex) {
logger.debug("Failed to copy snapshot ID: {} to image store: {}", snapshotId, dstSecStore);
}
return false;
}
return false;
}
@DB
@ -2204,13 +2202,6 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
if (CollectionUtils.isEmpty(snapshotChain)) {
return true;
}
try {
_resourceLimitMgr.checkResourceLimit(account, ResourceType.secondary_storage, size);
} catch (ResourceAllocationException e) {
logger.error(String.format("Unable to allocate secondary storage resources for snapshot chain for %s with size: %d", snapshotVO, size), e);
return false;
}
Collections.reverse(snapshotChain);
if (dstSecStore == null) {
// find all eligible image stores for the destination zone
List<DataStore> dstSecStores = dataStoreMgr.getImageStoresByScopeExcludingReadOnly(new ZoneScope(destZoneId));
@ -2222,16 +2213,23 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
throw new StorageUnavailableException("Destination zone is not ready, no image store with free capacity", DataCenter.class, destZoneId);
}
}
logger.debug("Copying snapshot chain for snapshot ID: {} on secondary store: {} of zone ID: {}", snapshotVO, dstSecStore, destZone);
for (SnapshotDataStoreVO snapshotDataStoreVO : snapshotChain) {
if (!copySnapshotToZone(snapshotDataStoreVO, srcSecStore, destZone, dstSecStore, account, kvmIncrementalSnapshot)) {
logger.error("Failed to copy snapshot: {} to zone: {} due to failure to copy snapshot ID: {} from snapshot chain",
snapshotVO, destZone, snapshotDataStoreVO.getSnapshotId());
return false;
try (CheckedReservation secondaryStorageReservation = new CheckedReservation(account, ResourceType.secondary_storage, null, null, null, size, null, reservationDao, _resourceLimitMgr)) {
logger.debug("Copying snapshot chain for snapshot ID: {} on secondary store: {} of zone ID: {}", snapshotVO, dstSecStore, destZone);
Collections.reverse(snapshotChain);
for (SnapshotDataStoreVO snapshotDataStoreVO : snapshotChain) {
if (!copySnapshotToZone(snapshotDataStoreVO, srcSecStore, destZone, dstSecStore, account, kvmIncrementalSnapshot, false)) {
logger.error("Failed to copy snapshot: {} to zone: {} due to failure to copy snapshot ID: {} from snapshot chain",
snapshotVO, destZone, snapshotDataStoreVO.getSnapshotId());
return false;
}
}
return true;
} catch (ResourceAllocationException e) {
logger.error(String.format("Unable to allocate secondary storage resources for snapshot chain for %s with size: %d", snapshotVO, size), e);
return false;
}
return true;
}
@DB
private List<String> copySnapshotToZones(SnapshotVO snapshotVO, DataStore srcSecStore, List<DataCenterVO> dstZones) throws StorageUnavailableException, ResourceAllocationException {
AccountVO account = _accountDao.findById(snapshotVO.getAccountId());

View File

@ -34,10 +34,8 @@ import org.apache.cloudstack.annotation.AnnotationService;
import org.apache.cloudstack.annotation.dao.AnnotationDao;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd;
import org.apache.cloudstack.api.command.user.iso.GetUploadParamsForIsoCmd;
import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd;
import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd;
import org.apache.cloudstack.api.command.user.template.GetUploadParamsForTemplateCmd;
import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.direct.download.DirectDownloadManager;
@ -197,19 +195,6 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase {
profile.setSize(templateSize);
}
profile.setUrl(url);
// Check that the resource limit for secondary storage won't be exceeded
_resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(cmd.getEntityOwnerId()),
ResourceType.secondary_storage,
UriUtils.getRemoteSize(url, followRedirects));
return profile;
}
@Override
public TemplateProfile prepare(GetUploadParamsForIsoCmd cmd) throws ResourceAllocationException {
TemplateProfile profile = super.prepare(cmd);
// Check that the resource limit for secondary storage won't be exceeded
_resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(cmd.getEntityOwnerId()), ResourceType.secondary_storage);
return profile;
}
@ -228,19 +213,7 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase {
profile.setForCks(cmd.isForCks());
}
profile.setUrl(url);
// Check that the resource limit for secondary storage won't be exceeded
_resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(cmd.getEntityOwnerId()),
ResourceType.secondary_storage,
UriUtils.getRemoteSize(url, followRedirects));
return profile;
}
@Override
public TemplateProfile prepare(GetUploadParamsForTemplateCmd cmd) throws ResourceAllocationException {
TemplateProfile profile = super.prepare(cmd);
// Check that the resource limit for secondary storage won't be exceeded
_resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(cmd.getEntityOwnerId()), ResourceType.secondary_storage);
return profile;
}
@ -268,7 +241,6 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase {
persistDirectDownloadTemplate(template.getId(), profile.getSize());
}
_resourceLimitMgr.incrementResourceCount(profile.getAccountId(), ResourceType.template);
return template;
}
@ -377,7 +349,7 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase {
if(payloads.isEmpty()) {
throw new CloudRuntimeException("unable to find zone or an image store with enough capacity");
}
_resourceLimitMgr.incrementResourceCount(profile.getAccountId(), ResourceType.template);
return payloads;
}
});
@ -396,13 +368,12 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase {
CreateTemplateContext<TemplateApiResult> context) {
TemplateApiResult result = callback.getResult();
TemplateInfo template = context.template;
VMTemplateVO tmplt = _tmpltDao.findById(template.getId());
if (result.isSuccess()) {
VMTemplateVO tmplt = _tmpltDao.findById(template.getId());
// need to grant permission for public templates
if (tmplt.isPublicTemplate()) {
_messageBus.publish(_name, TemplateManager.MESSAGE_REGISTER_PUBLIC_TEMPLATE_EVENT, PublishScope.LOCAL, tmplt.getId());
}
long accountId = tmplt.getAccountId();
if (template.getSize() != null) {
// publish usage event
String etype = EventTypes.EVENT_TEMPLATE_CREATE;
@ -431,9 +402,13 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase {
UsageEventUtils.publishUsageEvent(etype, template.getAccountId(), -1, template.getId(), template.getName(), null, null, physicalSize,
template.getSize(), VirtualMachineTemplate.class.getName(), template.getUuid());
}
_resourceLimitMgr.incrementResourceCount(accountId, ResourceType.secondary_storage, template.getSize());
}
}
if (tmplt != null) {
long accountId = tmplt.getAccountId();
Account account = _accountDao.findById(accountId);
_resourceLimitMgr.recalculateResourceCount(accountId, account.getDomainId(), ResourceType.secondary_storage.getOrdinal());
}
return null;
}

View File

@ -244,7 +244,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
Account account = _accountDao.findById(accountId);
Domain domain = _domainDao.findById(account.getDomainId());
payload.setDefaultMaxSecondaryStorageInGB(_resourceLimitMgr.findCorrectResourceLimitForAccountAndDomain(account, domain, ResourceType.secondary_storage, null));
payload.setDefaultMaxSecondaryStorageInBytes(_resourceLimitMgr.findCorrectResourceLimitForAccountAndDomain(account, domain, ResourceType.secondary_storage, null));
payload.setAccountId(accountId);
payload.setRemoteEndPoint(ep.getPublicAddr());
payload.setRequiresHvm(template.requiresHvm());
@ -363,8 +363,6 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
throw new IllegalArgumentException("Unable to find user with id " + userId);
}
_resourceLimitMgr.checkResourceLimit(templateOwner, ResourceType.template);
// If a zoneId is specified, make sure it is valid
if (zoneIdList != null) {
for (Long zoneId :zoneIdList) {

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;
@ -152,6 +153,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;
@ -201,6 +203,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;
@ -302,29 +305,27 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
private VMTemplateDetailsDao _tmpltDetailsDao;
@Inject
private HypervisorGuruManager _hvGuruMgr;
private List<TemplateAdapter> _adapters;
ExecutorService _preloadExecutor;
@Inject
ReservationDao reservationDao;
@Inject
private StorageCacheManager cacheMgr;
@Inject
private EndPointSelector selector;
@Inject
protected SnapshotHelper snapshotHelper;
@Inject
VnfTemplateManager vnfTemplateManager;
@Inject
TemplateDeployAsIsDetailsDao templateDeployAsIsDetailsDao;
@Inject
private SecondaryStorageHeuristicDao secondaryStorageHeuristicDao;
@Inject
private HeuristicRuleHelper heuristicRuleHelper;
private List<TemplateAdapter> _adapters;
ExecutorService _preloadExecutor;
protected boolean backupSnapshotAfterTakingSnapshot = SnapshotInfo.BackupSnapshotAfterTakingSnapshot.value();
private TemplateAdapter getAdapter(HypervisorType type) {
@ -353,14 +354,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");
}
}
}
@ -380,17 +397,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 recalculated 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");
}
}
@ -455,17 +487,35 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
@Override
@ActionEvent(eventType = EventTypes.EVENT_ISO_CREATE, eventDescription = "Creating post upload ISO")
public GetUploadParamsResponse registerIsoForPostUpload(GetUploadParamsForIsoCmd cmd) throws ResourceAllocationException, MalformedURLException {
TemplateAdapter adapter = getAdapter(HypervisorType.None);
TemplateProfile profile = adapter.prepare(cmd);
return registerPostUploadInternal(adapter, profile);
Account owner = _accountMgr.getAccount(cmd.getEntityOwnerId());
try (CheckedReservation templateReservation = new CheckedReservation(owner, ResourceType.template, null, null, 1L, reservationDao, _resourceLimitMgr)) {
TemplateAdapter adapter = getAdapter(HypervisorType.None);
TemplateProfile profile = adapter.prepare(cmd);
GetUploadParamsResponse response = registerPostUploadInternal(adapter, profile);
_resourceLimitMgr.incrementResourceCount(profile.getAccountId(), ResourceType.template);
return response;
}
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "Creating post upload Template")
public GetUploadParamsResponse registerTemplateForPostUpload(GetUploadParamsForTemplateCmd cmd) throws ResourceAllocationException, MalformedURLException {
TemplateAdapter adapter = getAdapter(HypervisorType.getType(cmd.getHypervisor()));
TemplateProfile profile = adapter.prepare(cmd);
return registerPostUploadInternal(adapter, profile);
Account owner = _accountMgr.getAccount(cmd.getEntityOwnerId());
try (CheckedReservation templateReservation = new CheckedReservation(owner, ResourceType.template, null, null, 1L, reservationDao, _resourceLimitMgr)) {
TemplateAdapter adapter = getAdapter(HypervisorType.getType(cmd.getHypervisor()));
TemplateProfile profile = adapter.prepare(cmd);
GetUploadParamsResponse response = registerPostUploadInternal(adapter, profile);
_resourceLimitMgr.incrementResourceCount(profile.getAccountId(), ResourceType.template);
return response;
}
}
@Override
@ -527,7 +577,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
VMTemplateVO vmTemplate = _tmpltDao.findById(templateId);
if (vmTemplate == null) {
throw new InvalidParameterValueException("Unable to find Template id=" + templateId);
throw new InvalidParameterValueException("Unable to find Template ID=" + templateId);
}
_accountMgr.checkAccess(CallContext.current().getCallingAccount(), AccessType.OperateEntry, true, vmTemplate);
@ -832,9 +882,6 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
// find the size of the template to be copied
TemplateDataStoreVO srcTmpltStore = _tmplStoreDao.findByStoreTemplate(srcSecStore.getId(), tmpltId);
_resourceLimitMgr.checkResourceLimit(account, ResourceType.template);
_resourceLimitMgr.checkResourceLimit(account, ResourceType.secondary_storage, new Long(srcTmpltStore.getSize()).longValue());
// Event details
String copyEventType;
if (template.getFormat().equals(ImageFormat.ISO)) {
@ -897,9 +944,6 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
}
}
}
return true;
} catch (Exception ex) {
logger.debug("Failed to copy Template to image store:{} ,will try next one", dstSecStore, ex);
}
@ -981,21 +1025,21 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
// sync template from cache store to region store if it is not there, for cases where we are going to migrate existing NFS to S3.
_tmpltSvr.syncTemplateToRegionStore(template, srcSecStore);
}
AccountVO templateOwner = _accountDao.findById(template.getAccountId());
for (Long destZoneId : destZoneIds) {
DataStore dstSecStore = getImageStore(destZoneId, templateId);
if (dstSecStore != null) {
logger.debug("There is Template {} in secondary storage {} in zone {} , don't need to copy", template, dstSecStore, dataCenterVOs.get(destZoneId));
continue;
}
if (!copy(userId, template, srcSecStore, dataCenterVOs.get(destZoneId))) {
failedZones.add(dataCenterVOs.get(destZoneId).getName());
}
else{
if (template.getSize() != null) {
// increase resource count
long accountId = template.getAccountId();
_resourceLimitMgr.incrementResourceCount(accountId, ResourceType.secondary_storage, template.getSize());
try (CheckedReservation secondaryStorageReservation = new CheckedReservation(templateOwner, ResourceType.secondary_storage, null, null, template.getSize(), reservationDao, _resourceLimitMgr)) {
if (!copy(userId, template, srcSecStore, dataCenterVOs.get(destZoneId))) {
failedZones.add(dataCenterVOs.get(destZoneId).getName());
continue;
}
_resourceLimitMgr.incrementResourceCount(templateOwner.getId(), ResourceType.secondary_storage, template.getSize());
}
}
}
@ -1018,9 +1062,6 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
AccountVO account = _accountDao.findById(template.getAccountId());
_resourceLimitMgr.checkResourceLimit(account, ResourceType.template);
try {
_tmpltDao.addTemplateToZone(template, dstZoneId);
return true;
@ -1839,7 +1880,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
// decrement resource count
if (accountId != null) {
_resourceLimitMgr.decrementResourceCount(accountId, ResourceType.template);
_resourceLimitMgr.decrementResourceCount(accountId, ResourceType.secondary_storage, new Long(volumeFinal != null ? volumeFinal.getSize()
_resourceLimitMgr.decrementResourceCount(accountId, ResourceType.secondary_storage, (long)(volumeFinal != null ? volumeFinal.getSize()
: snapshotFinal.getSize()));
}
}
@ -1990,107 +2031,106 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
}
}
_resourceLimitMgr.checkResourceLimit(templateOwner, ResourceType.template);
_resourceLimitMgr.checkResourceLimit(templateOwner, ResourceType.secondary_storage, new Long(volume != null ? volume.getSize() : snapshot.getSize()).longValue());
long templateSize = volume != null ? volume.getSize() : snapshot.getSize();
try (CheckedReservation templateReservation = new CheckedReservation(templateOwner, ResourceType.template, null, null, 1L, reservationDao, _resourceLimitMgr);
CheckedReservation secondaryStorageReservation = new CheckedReservation(templateOwner, ResourceType.secondary_storage, null, null, templateSize, reservationDao, _resourceLimitMgr)) {
if (!isAdmin || featured == null) {
featured = Boolean.FALSE;
}
Long guestOSId = cmd.getOsTypeId();
GuestOSVO guestOS = _guestOSDao.findById(guestOSId);
if (guestOS == null) {
throw new InvalidParameterValueException("GuestOS with ID: " + guestOSId + " does not exist.");
}
Long nextTemplateId = _tmpltDao.getNextInSequence(Long.class, "id");
String description = cmd.getDisplayText();
boolean isExtractable = false;
Long sourceTemplateId = null;
if (volume != null) {
VMTemplateVO template = ApiDBUtils.findTemplateById(volume.getTemplateId());
isExtractable = template != null && template.isExtractable() && template.getTemplateType() != Storage.TemplateType.SYSTEM;
if (template != null) {
arch = template.getArch();
if (!isAdmin || featured == null) {
featured = Boolean.FALSE;
}
if (volume.getIsoId() != null && volume.getIsoId() != 0) {
sourceTemplateId = volume.getIsoId();
} else if (volume.getTemplateId() != null) {
sourceTemplateId = volume.getTemplateId();
Long guestOSId = cmd.getOsTypeId();
GuestOSVO guestOS = _guestOSDao.findById(guestOSId);
if (guestOS == null) {
throw new InvalidParameterValueException("GuestOS with ID: " + guestOSId + " does not exist.");
}
}
String templateTag = cmd.getTemplateTag();
if (templateTag != null) {
if (logger.isDebugEnabled()) {
logger.debug("Adding Template tag: " + templateTag);
Long nextTemplateId = _tmpltDao.getNextInSequence(Long.class, "id");
String description = cmd.getDisplayText();
boolean isExtractable = false;
Long sourceTemplateId = null;
if (volume != null) {
VMTemplateVO template = ApiDBUtils.findTemplateById(volume.getTemplateId());
isExtractable = template != null && template.isExtractable() && template.getTemplateType() != Storage.TemplateType.SYSTEM;
if (template != null) {
arch = template.getArch();
}
if (volume.getIsoId() != null && volume.getIsoId() != 0) {
sourceTemplateId = volume.getIsoId();
} else if (volume.getTemplateId() != null) {
sourceTemplateId = volume.getTemplateId();
}
}
}
privateTemplate = new VMTemplateVO(nextTemplateId, name, ImageFormat.RAW, isPublic, featured, isExtractable,
TemplateType.USER, null, requiresHvmValue, bitsValue, templateOwner.getId(), null, description,
passwordEnabledValue, guestOS.getId(), true, hyperType, templateTag, cmd.getDetails(), sshKeyEnabledValue, isDynamicScalingEnabled, false, false, arch, null);
if (sourceTemplateId != null) {
if (logger.isDebugEnabled()) {
logger.debug("This Template is getting created from other Template, setting source Template ID to: " + sourceTemplateId);
String templateTag = cmd.getTemplateTag();
if (templateTag != null) {
if (logger.isDebugEnabled()) {
logger.debug("Adding Template tag: " + templateTag);
}
}
}
// for region wide storage, set cross zones flag
List<ImageStoreVO> stores = _imgStoreDao.findRegionImageStores();
if (!CollectionUtils.isEmpty(stores)) {
privateTemplate.setCrossZones(true);
}
privateTemplate.setSourceTemplateId(sourceTemplateId);
VMTemplateVO template = _tmpltDao.persist(privateTemplate);
// Increment the number of templates
if (template != null) {
Map<String, String> details = new HashMap<String, String>();
privateTemplate = new VMTemplateVO(nextTemplateId, name, ImageFormat.RAW, isPublic, featured, isExtractable,
TemplateType.USER, null, requiresHvmValue, bitsValue, templateOwner.getId(), null, description,
passwordEnabledValue, guestOS.getId(), true, hyperType, templateTag, cmd.getDetails(), sshKeyEnabledValue, isDynamicScalingEnabled, false, false, arch, null);
if (sourceTemplateId != null) {
VMTemplateVO sourceTemplate = _tmpltDao.findById(sourceTemplateId);
if (sourceTemplate != null && sourceTemplate.getDetails() != null) {
details.putAll(sourceTemplate.getDetails());
if (logger.isDebugEnabled()) {
logger.debug("This Template is getting created from other Template, setting source Template ID to: " + sourceTemplateId);
}
}
if (volume != null) {
Long vmId = volume.getInstanceId();
if (vmId != null) {
UserVmVO userVm = _userVmDao.findById(vmId);
if (userVm != null) {
_userVmDao.loadDetails(userVm);
Map<String, String> vmDetails = userVm.getDetails();
vmDetails = vmDetails.entrySet()
.stream()
.filter(map -> map.getValue() != null)
.collect(Collectors.toMap(map -> map.getKey(), map -> map.getValue()));
details.putAll(vmDetails);
// for region wide storage, set cross zones flag
List<ImageStoreVO> stores = _imgStoreDao.findRegionImageStores();
if (!CollectionUtils.isEmpty(stores)) {
privateTemplate.setCrossZones(true);
}
privateTemplate.setSourceTemplateId(sourceTemplateId);
VMTemplateVO template = _tmpltDao.persist(privateTemplate);
// Increment the number of templates
if (template != null) {
Map<String, String> details = new HashMap<String, String>();
if (sourceTemplateId != null) {
VMTemplateVO sourceTemplate = _tmpltDao.findById(sourceTemplateId);
if (sourceTemplate != null && sourceTemplate.getDetails() != null) {
details.putAll(sourceTemplate.getDetails());
}
}
}
if (cmd.getDetails() != null) {
details.remove(VmDetailConstants.ENCRYPTED_PASSWORD); // new password will be generated during vm deployment from password enabled template
details.putAll(cmd.getDetails());
}
if (!details.isEmpty()) {
privateTemplate.setDetails(details);
_tmpltDao.saveDetails(privateTemplate);
if (volume != null) {
Long vmId = volume.getInstanceId();
if (vmId != null) {
UserVmVO userVm = _userVmDao.findById(vmId);
if (userVm != null) {
_userVmDao.loadDetails(userVm);
Map<String, String> vmDetails = userVm.getDetails();
vmDetails = vmDetails.entrySet()
.stream()
.filter(map -> map.getValue() != null)
.collect(Collectors.toMap(map -> map.getKey(), map -> map.getValue()));
details.putAll(vmDetails);
}
}
}
if (cmd.getDetails() != null) {
details.remove(VmDetailConstants.ENCRYPTED_PASSWORD); // new password will be generated during vm deployment from password enabled template
details.putAll(cmd.getDetails());
}
if (!details.isEmpty()) {
privateTemplate.setDetails(details);
_tmpltDao.saveDetails(privateTemplate);
}
_resourceLimitMgr.incrementResourceCount(templateOwner.getId(), ResourceType.template);
_resourceLimitMgr.incrementResourceCount(templateOwner.getId(), ResourceType.secondary_storage, templateSize);
}
_resourceLimitMgr.incrementResourceCount(templateOwner.getId(), ResourceType.template);
_resourceLimitMgr.incrementResourceCount(templateOwner.getId(), ResourceType.secondary_storage,
new Long(volume != null ? volume.getSize() : snapshot.getSize()));
if (template != null) {
CallContext.current().putContextParameter(VirtualMachineTemplate.class, template.getUuid());
return template;
} else {
throw new CloudRuntimeException("Failed to create a Template");
}
}
if (template != null) {
CallContext.current().putContextParameter(VirtualMachineTemplate.class, template.getUuid());
return template;
} else {
throw new CloudRuntimeException("Failed to create a Template");
}
}
@Override
@ -2262,7 +2302,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
templateTag == null &&
forCks == null &&
arch == null &&
(!cleanupDetails && details == null) //update details in every case except this one
(! cleanupDetails && details == null) // update details in every case except this one
);
if (!updateNeeded) {
return template;
@ -2457,7 +2497,6 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
if (MapUtils.isEmpty(details)) {
return;
}
String bootMode = details.get(ApiConstants.BootType.UEFI.toString());
if (bootMode == null) {
return;

View File

@ -60,8 +60,7 @@ import javax.naming.ConfigurationException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
import com.cloud.storage.SnapshotPolicyVO;
import com.cloud.storage.dao.SnapshotPolicyDao;
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;
@ -128,6 +127,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeApiResult;
import org.apache.cloudstack.extension.ExtensionHelper;
import org.apache.cloudstack.framework.async.AsyncCallFuture;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
@ -137,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;
@ -266,12 +267,12 @@ import com.cloud.hypervisor.kvm.dpdk.DpdkHelper;
import com.cloud.kubernetes.cluster.KubernetesServiceHelper;
import com.cloud.network.IpAddressManager;
import com.cloud.network.Network;
import com.cloud.network.NetworkService;
import com.cloud.network.Network.GuestType;
import com.cloud.network.Network.IpAddresses;
import com.cloud.network.Network.Provider;
import com.cloud.network.Network.Service;
import com.cloud.network.NetworkModel;
import com.cloud.network.NetworkService;
import com.cloud.network.Networks.TrafficType;
import com.cloud.network.PhysicalNetwork;
import com.cloud.network.as.AutoScaleManager;
@ -325,6 +326,7 @@ import com.cloud.storage.GuestOSCategoryVO;
import com.cloud.storage.GuestOSVO;
import com.cloud.storage.ScopeType;
import com.cloud.storage.Snapshot;
import com.cloud.storage.SnapshotPolicyVO;
import com.cloud.storage.SnapshotVO;
import com.cloud.storage.Storage;
import com.cloud.storage.Storage.ImageFormat;
@ -343,6 +345,7 @@ import com.cloud.storage.dao.DiskOfferingDao;
import com.cloud.storage.dao.GuestOSCategoryDao;
import com.cloud.storage.dao.GuestOSDao;
import com.cloud.storage.dao.SnapshotDao;
import com.cloud.storage.dao.SnapshotPolicyDao;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.storage.dao.VMTemplateZoneDao;
import com.cloud.storage.dao.VolumeDao;
@ -615,29 +618,26 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
SnapshotPolicyDao snapshotPolicyDao;
@Inject
BackupScheduleDao backupScheduleDao;
@Inject
private StatsCollector statsCollector;
@Inject
private UserDataDao userDataDao;
@Inject
protected SnapshotHelper snapshotHelper;
@Inject
private AutoScaleManager autoScaleManager;
@Inject
VMScheduleManager vmScheduleManager;
@Inject
NsxProviderDao nsxProviderDao;
@Inject
NetworkService networkService;
@Inject
SnapshotDataFactory snapshotDataFactory;
@Inject
ExtensionHelper extensionHelper;
private ScheduledExecutorService _executor = null;
private ScheduledExecutorService _vmIpFetchExecutor = null;
private int _expungeInterval;
@ -682,19 +682,19 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
@Inject
VnfTemplateManager vnfTemplateManager;
private static final ConfigKey<Integer> VmIpFetchWaitInterval = new ConfigKey<Integer>("Advanced", Integer.class, "externaldhcp.vmip.retrieval.interval", "180",
private static final ConfigKey<Integer> VmIpFetchWaitInterval = new ConfigKey<>("Advanced", Integer.class, "externaldhcp.vmip.retrieval.interval", "180",
"Wait Interval (in seconds) for shared network vm dhcp ip addr fetch for next iteration ", true);
private static final ConfigKey<Integer> VmIpFetchTrialMax = new ConfigKey<Integer>("Advanced", Integer.class, "externaldhcp.vmip.max.retry", "10",
private static final ConfigKey<Integer> VmIpFetchTrialMax = new ConfigKey<>("Advanced", Integer.class, "externaldhcp.vmip.max.retry", "10",
"The max number of retrieval times for shared network vm dhcp ip fetch, in case of failures", true);
private static final ConfigKey<Integer> VmIpFetchThreadPoolMax = new ConfigKey<Integer>("Advanced", Integer.class, "externaldhcp.vmipFetch.threadPool.max", "10",
private static final ConfigKey<Integer> VmIpFetchThreadPoolMax = new ConfigKey<>("Advanced", Integer.class, "externaldhcp.vmipFetch.threadPool.max", "10",
"number of threads for fetching vms ip address", true);
private static final ConfigKey<Integer> VmIpFetchTaskWorkers = new ConfigKey<Integer>("Advanced", Integer.class, "externaldhcp.vmipfetchtask.workers", "10",
private static final ConfigKey<Integer> VmIpFetchTaskWorkers = new ConfigKey<>("Advanced", Integer.class, "externaldhcp.vmipfetchtask.workers", "10",
"number of worker threads for vm ip fetch task ", true);
private static final ConfigKey<Boolean> AllowDeployVmIfGivenHostFails = new ConfigKey<Boolean>("Advanced", Boolean.class, "allow.deploy.vm.if.deploy.on.given.host.fails", "false",
private static final ConfigKey<Boolean> AllowDeployVmIfGivenHostFails = new ConfigKey<>("Advanced", Boolean.class, "allow.deploy.vm.if.deploy.on.given.host.fails", "false",
"allow vm to deploy on different host if vm fails to deploy on the given host ", true);
private static final ConfigKey<String> KvmAdditionalConfigAllowList = new ConfigKey<>(String.class,
@ -706,7 +706,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
private static final ConfigKey<String> VmwareAdditionalConfigAllowList = new ConfigKey<>(String.class,
"allow.additional.vm.configuration.list.vmware", "Advanced", "", "Comma separated list of allowed additional configuration options.", true, ConfigKey.Scope.Global, null, null, EnableAdditionalVmConfig.key(), null, null, ConfigKey.Kind.CSV, null);
private static final ConfigKey<Boolean> VmDestroyForcestop = new ConfigKey<Boolean>("Advanced", Boolean.class, "vm.destroy.forcestop", "false",
private static final ConfigKey<Boolean> VmDestroyForcestop = new ConfigKey<>("Advanced", Boolean.class, "vm.destroy.forcestop", "false",
"On destroy, force-stop takes this value ", true);
@Override
@ -1192,7 +1192,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
if (dc.getNetworkType() == DataCenter.NetworkType.Advanced) {
//List all networks of vm
List<Long> vmNetworks = _vmNetworkMapDao.getNetworks(vmId);
List<DomainRouterVO> routers = new ArrayList<DomainRouterVO>();
List<DomainRouterVO> routers = new ArrayList<>();
//List the stopped routers
for (long vmNetworkId : vmNetworks) {
List<DomainRouterVO> router = _routerDao.listStopped(vmNetworkId);
@ -1393,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
@ -1418,6 +1421,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
return _vmDao.findById(vmInstance.getId());
} finally {
ReservationHelper.closeAll(reservations);
}
}
/**
@ -2111,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;
@ -2185,6 +2193,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
}
}
return success;
} finally {
ReservationHelper.closeAll(reservations);
}
}
protected void validateDiskOfferingChecks(ServiceOfferingVO currentServiceOffering, ServiceOfferingVO newServiceOffering) {
@ -2370,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());
@ -2398,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);
}
}
});
@ -2832,53 +2850,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);
}
}
@ -2927,6 +2917,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
.map(item -> (item).trim())
.collect(Collectors.toList());
userDenyListedSettings.addAll(QueryService.RootAdminOnlyVmSettings);
if (template != null && template.getExtensionId() != null) {
userDenyListedSettings.addAll(extensionHelper.getExtensionReservedResourceDetails(
template.getExtensionId()));
}
final List<String> userReadOnlySettings = Stream.of(QueryService.UserVMReadOnlyDetails.value().split(","))
.map(item -> (item).trim())
.collect(Collectors.toList());
@ -3234,7 +3229,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
// Verify that vm's hostName is unique
List<NetworkVO> vmNtwks = new ArrayList<NetworkVO>(nics.size());
List<NetworkVO> vmNtwks = new ArrayList<>(nics.size());
for (Nic nic : nics) {
vmNtwks.add(_networkDao.findById(nic.getNetworkId()));
}
@ -3815,7 +3810,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
StorageUnavailableException, ResourceAllocationException {
Account caller = CallContext.current().getCallingAccount();
List<NetworkVO> networkList = new ArrayList<NetworkVO>();
List<NetworkVO> networkList = new ArrayList<>();
// Verify that caller can perform actions in behalf of vm owner
_accountMgr.checkAccess(caller, null, true, owner);
@ -3841,7 +3836,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
//add the default securityGroup only if no security group is specified
if (securityGroupIdList == null || securityGroupIdList.isEmpty()) {
if (securityGroupIdList == null) {
securityGroupIdList = new ArrayList<Long>();
securityGroupIdList = new ArrayList<>();
}
SecurityGroup defaultGroup = _securityGroupMgr.getDefaultSecurityGroup(owner.getId());
if (defaultGroup != null) {
@ -3873,7 +3868,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap, Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId, String vmType, Volume volume, Snapshot snapshot) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException {
Account caller = CallContext.current().getCallingAccount();
List<NetworkVO> networkList = new ArrayList<NetworkVO>();
List<NetworkVO> networkList = new ArrayList<>();
boolean isSecurityGroupEnabledNetworkUsed = false;
boolean isVmWare = (template.getHypervisorType() == HypervisorType.VMware || (hypervisor != null && hypervisor == HypervisorType.VMware));
@ -3951,7 +3946,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
//add the default securityGroup only if no security group is specified
if (securityGroupIdList == null || securityGroupIdList.isEmpty()) {
if (securityGroupIdList == null) {
securityGroupIdList = new ArrayList<Long>();
securityGroupIdList = new ArrayList<>();
}
SecurityGroup defaultGroup = _securityGroupMgr.getDefaultSecurityGroup(owner.getId());
@ -3986,7 +3981,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
StorageUnavailableException, ResourceAllocationException {
Account caller = CallContext.current().getCallingAccount();
List<NetworkVO> networkList = new ArrayList<NetworkVO>();
List<NetworkVO> networkList = new ArrayList<>();
// Verify that caller can perform actions in behalf of vm owner
_accountMgr.checkAccess(caller, null, true, owner);
@ -4385,7 +4380,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);
}
}
@ -4941,10 +4935,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
logger.debug("Allocating in the DB for vm");
DataCenterDeployment plan = new DataCenterDeployment(zone.getId());
List<String> computeTags = new ArrayList<String>();
List<String> computeTags = new ArrayList<>();
computeTags.add(offering.getHostTag());
List<String> rootDiskTags = new ArrayList<String>();
List<String> rootDiskTags = new ArrayList<>();
DiskOfferingVO rootDiskOfferingVO = _diskOfferingDao.findById(rootDiskOfferingId);
rootDiskTags.add(rootDiskOfferingVO.getTags());
@ -5158,7 +5152,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
VirtualMachine.class.getName(), vm.getUuid(), isDisplay);
}
else {
Map<String, String> customParameters = new HashMap<String, String>();
Map<String, String> customParameters = new HashMap<>();
customParameters.put(UsageEventVO.DynamicParameters.cpuNumber.name(), serviceOffering.getCpu().toString());
customParameters.put(UsageEventVO.DynamicParameters.cpuSpeed.name(), serviceOffering.getSpeed().toString());
customParameters.put(UsageEventVO.DynamicParameters.memory.name(), serviceOffering.getRamSize().toString());
@ -5175,7 +5169,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
}
logger.debug("Collect vm network statistics from host before stopping Vm");
long hostId = userVm.getHostId();
List<String> vmNames = new ArrayList<String>();
List<String> vmNames = new ArrayList<>();
vmNames.add(userVm.getInstanceName());
final HostVO host = _hostDao.findById(hostId);
Account account = _accountMgr.getAccount(userVm.getAccountId());
@ -5735,13 +5729,135 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
return startVirtualMachine(vmId, podId, clusterId, hostId, additionalParams, deploymentPlannerToUse, true);
}
private Pair<UserVmVO, Map<VirtualMachineProfile.Param, Object>> startVirtualMachineUnchecked(UserVmVO vm, VMTemplateVO template, Long podId,
Long clusterId, Long hostId, @NotNull Map<VirtualMachineProfile.Param, Object> additionalParams, String deploymentPlannerToUse,
boolean isExplicitHost, boolean isRootAdmin) throws ResourceUnavailableException, InsufficientCapacityException {
// check if vm is security group enabled
if (_securityGroupMgr.isVmSecurityGroupEnabled(vm.getId()) && _securityGroupMgr.getSecurityGroupsForVm(vm.getId()).isEmpty()
&& !_securityGroupMgr.isVmMappedToDefaultSecurityGroup(vm.getId()) && _networkModel.canAddDefaultSecurityGroup()) {
// if vm is not mapped to security group, create a mapping
if (logger.isDebugEnabled()) {
logger.debug("Vm " + vm + " is security group enabled, but not mapped to default security group; creating the mapping automatically");
}
SecurityGroup defaultSecurityGroup = _securityGroupMgr.getDefaultSecurityGroup(vm.getAccountId());
if (defaultSecurityGroup != null) {
List<Long> groupList = new ArrayList<>();
groupList.add(defaultSecurityGroup.getId());
_securityGroupMgr.addInstanceToGroups(vm, groupList);
}
}
// Choose deployment planner
// Host takes 1st preference, Cluster takes 2nd preference and Pod takes 3rd
// Default behaviour is invoked when host, cluster or pod are not specified
Pod destinationPod = getDestinationPod(podId, isRootAdmin);
Cluster destinationCluster = getDestinationCluster(clusterId, isRootAdmin);
HostVO destinationHost = getDestinationHost(hostId, isRootAdmin, isExplicitHost);
DataCenterDeployment plan = null;
boolean deployOnGivenHost = false;
if (destinationHost != null) {
logger.debug("Destination Host to deploy the VM is specified, specifying a deployment plan to deploy the VM");
_hostDao.loadHostTags(destinationHost);
validateStrictHostTagCheck(vm, destinationHost);
final ServiceOfferingVO offering = serviceOfferingDao.findById(vm.getId(), vm.getServiceOfferingId());
Pair<Boolean, Boolean> cpuCapabilityAndCapacity = _capacityMgr.checkIfHostHasCpuCapabilityAndCapacity(destinationHost, offering, false);
if (!cpuCapabilityAndCapacity.first() || !cpuCapabilityAndCapacity.second()) {
String errorMsg;
if (!cpuCapabilityAndCapacity.first()) {
errorMsg = String.format("Cannot deploy the VM to specified host %s, requested CPU and speed is more than the host capability", destinationHost);
} else {
errorMsg = String.format("Cannot deploy the VM to specified host %s, host does not have enough free CPU or RAM, please check the logs", destinationHost);
}
logger.info(errorMsg);
if (!AllowDeployVmIfGivenHostFails.value()) {
throw new InvalidParameterValueException(errorMsg);
}
} else {
plan = new DataCenterDeployment(vm.getDataCenterId(), destinationHost.getPodId(), destinationHost.getClusterId(), destinationHost.getId(), null, null);
if (!AllowDeployVmIfGivenHostFails.value()) {
deployOnGivenHost = true;
}
}
} else if (destinationCluster != null) {
logger.debug("Destination Cluster to deploy the VM is specified, specifying a deployment plan to deploy the VM");
plan = new DataCenterDeployment(vm.getDataCenterId(), destinationCluster.getPodId(), destinationCluster.getId(), null, null, null);
if (!AllowDeployVmIfGivenHostFails.value()) {
deployOnGivenHost = true;
}
} else if (destinationPod != null) {
logger.debug("Destination Pod to deploy the VM is specified, specifying a deployment plan to deploy the VM");
plan = new DataCenterDeployment(vm.getDataCenterId(), destinationPod.getId(), null, null, null, null);
if (!AllowDeployVmIfGivenHostFails.value()) {
deployOnGivenHost = true;
}
}
// Set parameters
Map<VirtualMachineProfile.Param, Object> params = null;
if (vm.isUpdateParameters()) {
_vmDao.loadDetails(vm);
String password = getCurrentVmPasswordOrDefineNewPassword(String.valueOf(additionalParams.getOrDefault(VirtualMachineProfile.Param.VmPassword, "")), vm, template);
if (!validPassword(password)) {
throw new InvalidParameterValueException("A valid password for this virtual machine was not provided.");
}
// Check if an SSH key pair was selected for the instance and if so
// use it to encrypt & save the vm password
encryptAndStorePassword(vm, password);
params = createParameterInParameterMap(params, additionalParams, VirtualMachineProfile.Param.VmPassword, password);
}
if (additionalParams.containsKey(VirtualMachineProfile.Param.BootIntoSetup)) {
if (!HypervisorType.VMware.equals(vm.getHypervisorType())) {
throw new InvalidParameterValueException(ApiConstants.BOOT_INTO_SETUP + " makes no sense for " + vm.getHypervisorType());
}
Object paramValue = additionalParams.get(VirtualMachineProfile.Param.BootIntoSetup);
if (logger.isTraceEnabled()) {
logger.trace("It was specified whether to enter setup mode: " + paramValue.toString());
}
params = createParameterInParameterMap(params, additionalParams, VirtualMachineProfile.Param.BootIntoSetup, paramValue);
}
VirtualMachineEntity vmEntity = _orchSrvc.getVirtualMachine(vm.getUuid());
DeploymentPlanner planner = null;
if (deploymentPlannerToUse != null) {
// if set to null, the deployment planner would be later figured out either from global config var, or from
// the service offering
planner = _planningMgr.getDeploymentPlannerByName(deploymentPlannerToUse);
if (planner == null) {
throw new InvalidParameterValueException("Can't find a planner by name " + deploymentPlannerToUse);
}
}
vmEntity.setParamsToEntity(additionalParams);
UserVO callerUser = _userDao.findById(CallContext.current().getCallingUserId());
String reservationId = vmEntity.reserve(planner, plan, new ExcludeList(), Long.toString(callerUser.getId()));
vmEntity.deploy(reservationId, Long.toString(callerUser.getId()), params, deployOnGivenHost);
Pair<UserVmVO, Map<VirtualMachineProfile.Param, Object>> vmParamPair = new Pair(vm, params);
if (vm.isUpdateParameters()) {
// this value is not being sent to the backend; need only for api
// display purposes
if (template.isEnablePassword()) {
if (vm.getDetail(VmDetailConstants.PASSWORD) != null) {
vmInstanceDetailsDao.removeDetail(vm.getId(), VmDetailConstants.PASSWORD);
}
vm.setUpdateParameters(false);
_vmDao.update(vm.getId(), vm);
}
}
return vmParamPair;
}
@Override
public Pair<UserVmVO, Map<VirtualMachineProfile.Param, Object>> startVirtualMachine(long vmId, Long podId, Long clusterId, Long hostId,
@NotNull Map<VirtualMachineProfile.Param, Object> additionalParams, String deploymentPlannerToUse, boolean isExplicitHost)
throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException {
// Input validation
final Account callerAccount = CallContext.current().getCallingAccount();
UserVO callerUser = _userDao.findById(CallContext.current().getCallingUserId());
// if account is removed, return error
if (callerAccount == null || callerAccount.getRemoved() != null) {
@ -5769,133 +5885,21 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
if (owner.getState() == Account.State.DISABLED) {
throw new PermissionDeniedException(String.format("The owner of %s is disabled: %s", vm, owner));
}
boolean isRootAdmin = _accountService.isRootAdmin(callerAccount.getId());
VMTemplateVO template = _templateDao.findByIdIncludingRemoved(vm.getTemplateId());
if (VirtualMachineManager.ResourceCountRunningVMsonly.value()) {
// check if account/domain is with in resource limits to start a new vm
ServiceOfferingVO offering = serviceOfferingDao.findById(vm.getId(), vm.getServiceOfferingId());
resourceLimitService.checkVmResourceLimit(owner, vm.isDisplayVm(), offering, template);
List<String> resourceLimitHostTags = resourceLimitService.getResourceLimitHostTags(offering, template);
try (CheckedReservation vmReservation = new CheckedReservation(owner, ResourceType.user_vm, resourceLimitHostTags, 1l, reservationDao, resourceLimitService);
CheckedReservation cpuReservation = new CheckedReservation(owner, ResourceType.cpu, resourceLimitHostTags, Long.valueOf(offering.getCpu()), reservationDao, resourceLimitService);
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);
}
} else {
return startVirtualMachineUnchecked(vm, template, podId, clusterId, hostId, additionalParams, deploymentPlannerToUse, isExplicitHost, isRootAdmin);
}
// check if vm is security group enabled
if (_securityGroupMgr.isVmSecurityGroupEnabled(vmId) && _securityGroupMgr.getSecurityGroupsForVm(vmId).isEmpty()
&& !_securityGroupMgr.isVmMappedToDefaultSecurityGroup(vmId) && _networkModel.canAddDefaultSecurityGroup()) {
// if vm is not mapped to security group, create a mapping
if (logger.isDebugEnabled()) {
logger.debug("Vm " + vm + " is security group enabled, but not mapped to default security group; creating the mapping automatically");
}
SecurityGroup defaultSecurityGroup = _securityGroupMgr.getDefaultSecurityGroup(vm.getAccountId());
if (defaultSecurityGroup != null) {
List<Long> groupList = new ArrayList<Long>();
groupList.add(defaultSecurityGroup.getId());
_securityGroupMgr.addInstanceToGroups(vm, groupList);
}
}
// Choose deployment planner
// Host takes 1st preference, Cluster takes 2nd preference and Pod takes 3rd
// Default behaviour is invoked when host, cluster or pod are not specified
boolean isRootAdmin = _accountService.isRootAdmin(callerAccount.getId());
Pod destinationPod = getDestinationPod(podId, isRootAdmin);
Cluster destinationCluster = getDestinationCluster(clusterId, isRootAdmin);
HostVO destinationHost = getDestinationHost(hostId, isRootAdmin, isExplicitHost);
DataCenterDeployment plan = null;
boolean deployOnGivenHost = false;
if (destinationHost != null) {
logger.debug("Destination Host to deploy the VM is specified, specifying a deployment plan to deploy the VM");
_hostDao.loadHostTags(destinationHost);
validateStrictHostTagCheck(vm, destinationHost);
final ServiceOfferingVO offering = serviceOfferingDao.findById(vm.getId(), vm.getServiceOfferingId());
Pair<Boolean, Boolean> cpuCapabilityAndCapacity = _capacityMgr.checkIfHostHasCpuCapabilityAndCapacity(destinationHost, offering, false);
if (!cpuCapabilityAndCapacity.first() || !cpuCapabilityAndCapacity.second()) {
String errorMsg;
if (!cpuCapabilityAndCapacity.first()) {
errorMsg = String.format("Cannot deploy the VM to specified host %s, requested CPU and speed is more than the host capability", destinationHost);
} else {
errorMsg = String.format("Cannot deploy the VM to specified host %s, host does not have enough free CPU or RAM, please check the logs", destinationHost);
}
logger.info(errorMsg);
if (!AllowDeployVmIfGivenHostFails.value()) {
throw new InvalidParameterValueException(errorMsg);
};
} else {
plan = new DataCenterDeployment(vm.getDataCenterId(), destinationHost.getPodId(), destinationHost.getClusterId(), destinationHost.getId(), null, null);
if (!AllowDeployVmIfGivenHostFails.value()) {
deployOnGivenHost = true;
}
}
} else if (destinationCluster != null) {
logger.debug("Destination Cluster to deploy the VM is specified, specifying a deployment plan to deploy the VM");
plan = new DataCenterDeployment(vm.getDataCenterId(), destinationCluster.getPodId(), destinationCluster.getId(), null, null, null);
if (!AllowDeployVmIfGivenHostFails.value()) {
deployOnGivenHost = true;
}
} else if (destinationPod != null) {
logger.debug("Destination Pod to deploy the VM is specified, specifying a deployment plan to deploy the VM");
plan = new DataCenterDeployment(vm.getDataCenterId(), destinationPod.getId(), null, null, null, null);
if (!AllowDeployVmIfGivenHostFails.value()) {
deployOnGivenHost = true;
}
}
// Set parameters
Map<VirtualMachineProfile.Param, Object> params = null;
if (vm.isUpdateParameters()) {
_vmDao.loadDetails(vm);
String password = getCurrentVmPasswordOrDefineNewPassword(String.valueOf(additionalParams.getOrDefault(VirtualMachineProfile.Param.VmPassword, "")), vm, template);
if (!validPassword(password)) {
throw new InvalidParameterValueException("A valid password for this virtual machine was not provided.");
}
// Check if an SSH key pair was selected for the instance and if so
// use it to encrypt & save the vm password
encryptAndStorePassword(vm, password);
params = createParameterInParameterMap(params, additionalParams, VirtualMachineProfile.Param.VmPassword, password);
}
if (additionalParams.containsKey(VirtualMachineProfile.Param.BootIntoSetup)) {
if (! HypervisorType.VMware.equals(vm.getHypervisorType())) {
throw new InvalidParameterValueException(ApiConstants.BOOT_INTO_SETUP + " makes no sense for " + vm.getHypervisorType());
}
Object paramValue = additionalParams.get(VirtualMachineProfile.Param.BootIntoSetup);
if (logger.isTraceEnabled()) {
logger.trace("It was specified whether to enter setup mode: " + paramValue.toString());
}
params = createParameterInParameterMap(params, additionalParams, VirtualMachineProfile.Param.BootIntoSetup, paramValue);
}
VirtualMachineEntity vmEntity = _orchSrvc.getVirtualMachine(vm.getUuid());
DeploymentPlanner planner = null;
if (deploymentPlannerToUse != null) {
// if set to null, the deployment planner would be later figured out either from global config var, or from
// the service offering
planner = _planningMgr.getDeploymentPlannerByName(deploymentPlannerToUse);
if (planner == null) {
throw new InvalidParameterValueException("Can't find a planner by name " + deploymentPlannerToUse);
}
}
vmEntity.setParamsToEntity(additionalParams);
String reservationId = vmEntity.reserve(planner, plan, new ExcludeList(), Long.toString(callerUser.getId()));
vmEntity.deploy(reservationId, Long.toString(callerUser.getId()), params, deployOnGivenHost);
Pair<UserVmVO, Map<VirtualMachineProfile.Param, Object>> vmParamPair = new Pair(vm, params);
if (vm != null && vm.isUpdateParameters()) {
// this value is not being sent to the backend; need only for api
// display purposes
if (template.isEnablePassword()) {
if (vm.getDetail(VmDetailConstants.PASSWORD) != null) {
vmInstanceDetailsDao.removeDetail(vm.getId(), VmDetailConstants.PASSWORD);
}
vm.setUpdateParameters(false);
_vmDao.update(vm.getId(), vm);
}
}
return vmParamPair;
}
/**
@ -6074,7 +6078,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
return;
}
long hostId = userVm.getHostId();
List<String> vmNames = new ArrayList<String>();
List<String> vmNames = new ArrayList<>();
vmNames.add(userVm.getInstanceName());
final HostVO host = _hostDao.findById(hostId);
Account account = _accountMgr.getAccount(userVm.getAccountId());
@ -6939,7 +6943,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
//transform group names to ids here
if (cmd.getSecurityGroupNameList() != null) {
List<Long> securityGroupIds = new ArrayList<Long>();
List<Long> securityGroupIds = new ArrayList<>();
for (String groupName : cmd.getSecurityGroupNameList()) {
SecurityGroup sg = _securityGroupMgr.getSecurityGroup(groupName, cmd.getEntityOwnerId());
if (sg == null) {
@ -7724,7 +7728,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
}
private Map<Long, Long> getVolumePoolMappingForMigrateVmWithStorage(VMInstanceVO vm, Map<String, String> volumeToPool) {
Map<Long, Long> volToPoolObjectMap = new HashMap<Long, Long>();
Map<Long, Long> volToPoolObjectMap = new HashMap<>();
List<VolumeVO> vmVolumes = getVmVolumesForMigrateVmWithStorage(vm);
@ -7868,38 +7872,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);
}
}
@ -7941,14 +7936,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() {
@ -7965,6 +7962,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;
}
@ -8035,18 +8036,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() {
@ -8678,10 +8679,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
/**
* Attempts to create a network suitable for the creation of a VM ({@link NetworkOrchestrationService#createGuestNetwork}).
* If no physical network is found, throws a {@link InvalidParameterValueException}.
* @param caller The account which calls for the network creation.
* @param newAccount The account to which the network will be created.
* @param zone The zone where the network will be created.
* @param requiredOffering The network offering required to create the network.
* @return The NetworkVO for the network created.
* @throws InsufficientCapacityException
* @throws ResourceAllocationException
@ -8945,12 +8944,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 {
@ -9097,6 +9094,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) {
@ -9196,7 +9199,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());
@ -9214,7 +9217,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) {
@ -9225,7 +9228,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

@ -448,7 +448,6 @@ public class VMSnapshotManagerImpl extends MutualExclusiveIdsManagerBase impleme
* Create, persist and return vm snapshot for userVmVo with given parameters.
* Persistence and support for custom service offerings are done on the same transaction
* @param userVmVo user vm
* @param vmId vm id
* @param vsDescription vm description
* @param vmSnapshotName vm snapshot name
* @param vsDisplayName vm snapshot display name
@ -815,37 +814,43 @@ 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;
}
/**
* Update service offering on {@link userVm} to the one specified in {@link vmSnapshotVo}
* Update service offering on {code}userVm{code} to the one specified in {code}vmSnapshotVo{code}
* @param userVm user vm to be updated
* @param vmSnapshotVo vm snapshot
*/
protected void changeUserVmServiceOffering(UserVm userVm, VMSnapshotVO vmSnapshotVo) {
Map<String, String> vmDetails = getVmMapDetails(userVm);
Map<String, String> vmDetails = getVmMapDetails(vmSnapshotVo);
boolean result = upgradeUserVmServiceOffering(userVm, vmSnapshotVo.getServiceOfferingId(), vmDetails);
if (! result){
throw new CloudRuntimeException("Instance Snapshot reverting failed because the Instance service offering couldn't be changed to the one used when Snapshot was taken");
@ -854,8 +859,8 @@ public class VMSnapshotManagerImpl extends MutualExclusiveIdsManagerBase impleme
}
/**
* Upgrade virtual machine {@linkplain vmId} to new service offering {@linkplain serviceOfferingId}
* @param vmId vm id
* Upgrade virtual machine {code}vm{code} to new service offering {code}serviceOfferingId{code}
* @param vm vm
* @param serviceOfferingId service offering id
* @param details vm details
* @return if operation was successful
@ -1293,7 +1298,7 @@ public class VMSnapshotManagerImpl extends MutualExclusiveIdsManagerBase impleme
public Pair<JobInfo.Status, String> orchestrateCreateVMSnapshot(VmWorkCreateVMSnapshot work) throws Exception {
VMSnapshot snapshot = orchestrateCreateVMSnapshot(work.getVmId(), work.getVmSnapshotId(), work.isQuiesceVm());
return new Pair<JobInfo.Status, String>(JobInfo.Status.SUCCEEDED,
_jobMgr.marshallResultObject(new Long(snapshot.getId())));
_jobMgr.marshallResultObject(Long.valueOf(snapshot.getId())));
}
@ReflectionUse

View File

@ -78,6 +78,7 @@ import org.apache.cloudstack.managed.context.ManagedContextRunnable;
import org.apache.cloudstack.managed.context.ManagedContextTimerTask;
import org.apache.cloudstack.poll.BackgroundPollManager;
import org.apache.cloudstack.poll.BackgroundPollTask;
import org.apache.cloudstack.reservation.dao.ReservationDao;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
@ -85,6 +86,8 @@ import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.amazonaws.util.CollectionUtils;
import com.cloud.alert.AlertManager;
@ -119,6 +122,7 @@ import com.cloud.network.dao.NetworkDao;
import com.cloud.offering.DiskOffering;
import com.cloud.offering.ServiceOffering;
import com.cloud.projects.Project;
import com.cloud.resourcelimit.CheckedReservation;
import com.cloud.serializer.GsonHelper;
import com.cloud.service.dao.ServiceOfferingDao;
import com.cloud.storage.DiskOfferingVO;
@ -170,8 +174,6 @@ import com.cloud.vm.dao.VMInstanceDetailsDao;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
public class BackupManagerImpl extends ManagerBase implements BackupManager {
@ -237,6 +239,8 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager {
private AlertManager alertManager;
@Inject
private GuestOSDao _guestOSDao;
@Inject
ReservationDao reservationDao;
private AsyncJobDispatcher asyncJobDispatcher;
private Timer backupTimer;
@ -790,14 +794,6 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager {
Long backupScheduleId = getBackupScheduleId(job);
boolean isScheduledBackup = backupScheduleId != null;
Account owner = accountManager.getAccount(vm.getAccountId());
try {
resourceLimitMgr.checkResourceLimit(owner, Resource.ResourceType.backup);
} catch (ResourceAllocationException e) {
if (isScheduledBackup) {
sendExceededBackupLimitAlert(owner.getUuid(), Resource.ResourceType.backup);
}
throw e;
}
Long backupSize = 0L;
for (final Volume volume: volumeDao.findByInstance(vmId)) {
@ -809,42 +805,57 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager {
backupSize += volumeSize;
}
}
try {
resourceLimitMgr.checkResourceLimit(owner, Resource.ResourceType.backup_storage, backupSize);
} catch (ResourceAllocationException e) {
if (isScheduledBackup) {
sendExceededBackupLimitAlert(owner.getUuid(), Resource.ResourceType.backup_storage);
}
throw e;
}
ActionEventUtils.onStartedActionEvent(User.UID_SYSTEM, vm.getAccountId(),
EventTypes.EVENT_VM_BACKUP_CREATE, "creating backup for VM ID:" + vm.getUuid(),
vmId, ApiCommandResourceType.VirtualMachine.toString(),
true, 0);
Pair<Boolean, Backup> result = backupProvider.takeBackup(vm, cmd.getQuiesceVM());
if (!result.first()) {
throw new CloudRuntimeException("Failed to create VM backup");
}
Backup backup = result.second();
if (backup != null) {
BackupVO vmBackup = backupDao.findById(result.second().getId());
vmBackup.setBackupScheduleId(backupScheduleId);
if (cmd.getName() != null) {
vmBackup.setName(cmd.getName());
}
vmBackup.setDescription(cmd.getDescription());
backupDao.update(vmBackup.getId(), vmBackup);
resourceLimitMgr.incrementResourceCount(vm.getAccountId(), Resource.ResourceType.backup);
resourceLimitMgr.incrementResourceCount(vm.getAccountId(), Resource.ResourceType.backup_storage, backup.getSize());
}
createCheckedBackup(cmd, owner, isScheduledBackup, backupSize, vm, vmId, backupProvider, backupScheduleId);
if (isScheduledBackup) {
deleteOldestBackupFromScheduleIfRequired(vmId, backupScheduleId);
}
return true;
}
private void createCheckedBackup(CreateBackupCmd cmd, Account owner, boolean isScheduledBackup, Long backupSize,
VMInstanceVO vm, Long vmId, BackupProvider backupProvider, Long backupScheduleId)
throws ResourceAllocationException {
try (CheckedReservation backupReservation = new CheckedReservation(owner, Resource.ResourceType.backup,
1L, reservationDao, resourceLimitMgr);
CheckedReservation backupStorageReservation = new CheckedReservation(owner,
Resource.ResourceType.backup_storage, backupSize, reservationDao, resourceLimitMgr)) {
ActionEventUtils.onStartedActionEvent(User.UID_SYSTEM, vm.getAccountId(),
EventTypes.EVENT_VM_BACKUP_CREATE, "creating backup for VM ID:" + vm.getUuid(),
vmId, ApiCommandResourceType.VirtualMachine.toString(),
true, 0);
Pair<Boolean, Backup> result = backupProvider.takeBackup(vm, cmd.getQuiesceVM());
if (!result.first()) {
throw new CloudRuntimeException("Failed to create VM backup");
}
Backup backup = result.second();
if (backup != null) {
BackupVO vmBackup = backupDao.findById(result.second().getId());
vmBackup.setBackupScheduleId(backupScheduleId);
if (cmd.getName() != null) {
vmBackup.setName(cmd.getName());
}
vmBackup.setDescription(cmd.getDescription());
backupDao.update(vmBackup.getId(), vmBackup);
resourceLimitMgr.incrementResourceCount(vm.getAccountId(), Resource.ResourceType.backup);
resourceLimitMgr.incrementResourceCount(vm.getAccountId(), Resource.ResourceType.backup_storage, backup.getSize());
}
} catch (Exception e) {
if (e instanceof ResourceAllocationException) {
ResourceAllocationException rae = (ResourceAllocationException)e;
if (isScheduledBackup && (Resource.ResourceType.backup.equals(rae.getResourceType()) ||
Resource.ResourceType.backup_storage.equals(rae.getResourceType()))) {
sendExceededBackupLimitAlert(owner.getUuid(), rae.getResourceType());
}
throw rae;
} else if (e instanceof CloudRuntimeException) {
throw (CloudRuntimeException)e;
}
throw new CloudRuntimeException("Failed to create backup for VM with ID: " + vm.getUuid(), e);
}
}
/**
* Sends an alert when the backup limit has been exceeded for a given account.
*
@ -971,7 +982,7 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager {
sb.and("backupOfferingId", sb.entity().getBackupOfferingId(), SearchCriteria.Op.EQ);
if (keyword != null) {
sb.or().op("keywordName", sb.entity().getName(), SearchCriteria.Op.LIKE);
sb.and().op("keywordName", sb.entity().getName(), SearchCriteria.Op.LIKE);
SearchBuilder<VMInstanceVO> vmSearch = vmInstanceDao.createSearchBuilder();
sb.join("vmSearch", vmSearch, sb.entity().getVmId(), vmSearch.entity().getId(), JoinBuilder.JoinType.INNER);
sb.or("vmSearch", "keywordVmName", vmSearch.entity().getHostName(), SearchCriteria.Op.LIKE);
@ -1538,19 +1549,35 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager {
throw new CloudRuntimeException(String.format("Backup offering with ID [%s] does not exist.", backup.getBackupOfferingId()));
}
final BackupProvider backupProvider = getBackupProvider(backup.getZoneId());
boolean result = backupProvider.deleteBackup(backup, forced);
if (result) {
resourceLimitMgr.decrementResourceCount(backup.getAccountId(), Resource.ResourceType.backup);
Long backupSize = backup.getSize() != null ? backup.getSize() : 0L;
resourceLimitMgr.decrementResourceCount(backup.getAccountId(), Resource.ResourceType.backup_storage, backupSize);
if (backupDao.remove(backup.getId())) {
checkAndGenerateUsageForLastBackupDeletedAfterOfferingRemove(vm, backup);
return true;
} else {
return false;
return deleteCheckedBackup(forced, backupProvider, backup, vm);
}
private boolean deleteCheckedBackup(Boolean forced, BackupProvider backupProvider, BackupVO backup, VMInstanceVO vm) {
Account owner = accountManager.getAccount(backup.getAccountId());
long backupSize = backup.getSize() != null ? backup.getSize() : 0L;
try (CheckedReservation backupReservation = new CheckedReservation(owner, Resource.ResourceType.backup,
backup.getId(), null, -1L, reservationDao, resourceLimitMgr);
CheckedReservation backupStorageReservation = new CheckedReservation(owner,
Resource.ResourceType.backup_storage, backup.getId(), null, -1 * backupSize,
reservationDao, resourceLimitMgr)) {
boolean result = backupProvider.deleteBackup(backup, forced);
if (result) {
resourceLimitMgr.decrementResourceCount(backup.getAccountId(), Resource.ResourceType.backup);
resourceLimitMgr.decrementResourceCount(backup.getAccountId(), Resource.ResourceType.backup_storage, backupSize);
if (backupDao.remove(backup.getId())) {
checkAndGenerateUsageForLastBackupDeletedAfterOfferingRemove(vm, backup);
return true;
} else {
return false;
}
}
throw new CloudRuntimeException("Failed to delete the backup");
} catch (Exception e) {
if (e instanceof CloudRuntimeException) {
throw (CloudRuntimeException) e;
}
throw new CloudRuntimeException("Failed to delete the backup due to: " + e.getMessage(), e);
}
throw new CloudRuntimeException("Failed to delete the backup");
}
private void checkForPendingBackupJobs(final BackupVO backup) {

View File

@ -16,6 +16,27 @@
// under the License.
package org.apache.cloudstack.storage.object;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import org.apache.cloudstack.api.command.user.bucket.CreateBucketCmd;
import org.apache.cloudstack.api.command.user.bucket.UpdateBucketCmd;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
import org.apache.cloudstack.reservation.dao.ReservationDao;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDao;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreVO;
import org.apache.commons.lang3.ObjectUtils;
import org.jetbrains.annotations.NotNull;
import com.amazonaws.services.s3.internal.BucketNameUtils;
import com.amazonaws.services.s3.model.IllegalBucketNameException;
import com.cloud.agent.api.to.BucketTO;
@ -24,6 +45,7 @@ import com.cloud.event.ActionEvent;
import com.cloud.event.EventTypes;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.resourcelimit.CheckedReservation;
import com.cloud.resourcelimit.ResourceLimitManagerImpl;
import com.cloud.storage.BucketVO;
import com.cloud.storage.DataStoreRole;
@ -36,22 +58,6 @@ import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.concurrency.NamedThreadFactory;
import com.cloud.utils.db.GlobalLock;
import com.cloud.utils.exception.CloudRuntimeException;
import org.apache.cloudstack.api.command.user.bucket.CreateBucketCmd;
import org.apache.cloudstack.api.command.user.bucket.UpdateBucketCmd;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDao;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreVO;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class BucketApiServiceImpl extends ManagerBase implements BucketApiService, Configurable {
@ -68,6 +74,8 @@ public class BucketApiServiceImpl extends ManagerBase implements BucketApiServic
@Inject
private BucketStatisticsDao _bucketStatisticsDao;
@Inject
ReservationDao reservationDao;
private ScheduledExecutorService _executor = null;
@ -136,13 +144,33 @@ public class BucketApiServiceImpl extends ManagerBase implements BucketApiServic
return null;
}
resourceLimitManager.checkResourceLimit(owner, Resource.ResourceType.bucket);
resourceLimitManager.checkResourceLimit(owner, Resource.ResourceType.object_storage, (cmd.getQuota() * Resource.ResourceType.bytesToGiB));
long size = ObjectUtils.defaultIfNull(cmd.getQuota(), 0) * Resource.ResourceType.bytesToGiB;
return createCheckedBucket(cmd, owner, size, ownerId);
}
BucketVO bucket = new BucketVO(ownerId, owner.getDomainId(), cmd.getObjectStoragePoolId(), cmd.getBucketName(), cmd.getQuota(),
cmd.isVersioning(), cmd.isEncryption(), cmd.isObjectLocking(), cmd.getPolicy());
_bucketDao.persist(bucket);
return bucket;
@NotNull
private BucketVO createCheckedBucket(CreateBucketCmd cmd, Account owner, long size, long ownerId) throws ResourceAllocationException {
try (CheckedReservation bucketReservation = new CheckedReservation(owner, Resource.ResourceType.bucket,
1L, reservationDao, resourceLimitManager);
CheckedReservation objectStorageReservation = new CheckedReservation(owner,
Resource.ResourceType.object_storage, size, reservationDao, resourceLimitManager)) {
BucketVO bucket = new BucketVO(ownerId, owner.getDomainId(), cmd.getObjectStoragePoolId(), cmd.getBucketName(), cmd.getQuota(),
cmd.isVersioning(), cmd.isEncryption(), cmd.isObjectLocking(), cmd.getPolicy());
_bucketDao.persist(bucket);
resourceLimitManager.incrementResourceCount(bucket.getAccountId(), Resource.ResourceType.bucket);
if (size > 0) {
resourceLimitManager.incrementResourceCount(bucket.getAccountId(), Resource.ResourceType.object_storage,
(cmd.getQuota() * Resource.ResourceType.bytesToGiB));
}
return bucket;
} catch (Exception e) {
if (e instanceof ResourceAllocationException) {
throw (ResourceAllocationException)e;
} else if (e instanceof CloudRuntimeException) {
throw (CloudRuntimeException)e;
}
throw new CloudRuntimeException(String.format("Failed to create bucket due to: %s", e.getMessage()), e);
}
}
@Override
@ -160,7 +188,6 @@ public class BucketApiServiceImpl extends ManagerBase implements BucketApiServic
try {
bucketTO = new BucketTO(objectStore.createBucket(bucket, objectLock));
bucketCreated = true;
resourceLimitManager.incrementResourceCount(bucket.getAccountId(), Resource.ResourceType.bucket);
if (cmd.isVersioning()) {
objectStore.setBucketVersioning(bucketTO);
@ -172,7 +199,6 @@ public class BucketApiServiceImpl extends ManagerBase implements BucketApiServic
if (cmd.getQuota() != null) {
objectStore.setQuota(bucketTO, cmd.getQuota());
resourceLimitManager.incrementResourceCount(bucket.getAccountId(), Resource.ResourceType.object_storage, (cmd.getQuota() * Resource.ResourceType.bytesToGiB));
if (objectStoreVO.getTotalSize() != null && objectStoreVO.getTotalSize() != 0 && objectStoreVO.getAllocatedSize() != null) {
Long allocatedSize = objectStoreVO.getAllocatedSize() / Resource.ResourceType.bytesToGiB;
Long totalSize = objectStoreVO.getTotalSize() / Resource.ResourceType.bytesToGiB;
@ -193,11 +219,16 @@ public class BucketApiServiceImpl extends ManagerBase implements BucketApiServic
_objectStoreDao.updateAllocatedSize(objectStoreVO, cmd.getQuota() * Resource.ResourceType.bytesToGiB);
}
} catch (Exception e) {
logger.debug("Failed to create bucket with name: "+bucket.getName(), e);
logger.debug("Failed to create bucket with name: {}", bucket.getName(), e);
if(bucketCreated) {
objectStore.deleteBucket(bucketTO);
}
_bucketDao.remove(bucket.getId());
resourceLimitManager.decrementResourceCount(bucket.getAccountId(), Resource.ResourceType.bucket);
if (bucket.getQuota() != null) {
resourceLimitManager.decrementResourceCount(bucket.getAccountId(), Resource.ResourceType.object_storage,
(bucket.getQuota() * Resource.ResourceType.bytesToGiB));
}
throw new CloudRuntimeException("Failed to create bucket with name: "+bucket.getName()+". "+e.getMessage());
}
return bucket;
@ -207,22 +238,39 @@ public class BucketApiServiceImpl extends ManagerBase implements BucketApiServic
@ActionEvent(eventType = EventTypes.EVENT_BUCKET_DELETE, eventDescription = "deleting bucket")
public boolean deleteBucket(long bucketId, Account caller) {
Bucket bucket = _bucketDao.findById(bucketId);
BucketTO bucketTO = new BucketTO(bucket);
if (bucket == null) {
throw new InvalidParameterValueException("Unable to find bucket with ID: " + bucketId);
}
_accountMgr.checkAccess(caller, null, true, bucket);
ObjectStoreVO objectStoreVO = _objectStoreDao.findById(bucket.getObjectStoreId());
ObjectStoreEntity objectStore = (ObjectStoreEntity)_dataStoreMgr.getDataStore(objectStoreVO.getId(), DataStoreRole.Object);
if (objectStore.deleteBucket(bucketTO)) {
resourceLimitManager.decrementResourceCount(bucket.getAccountId(), Resource.ResourceType.bucket);
if (bucket.getQuota() != null) {
resourceLimitManager.decrementResourceCount(bucket.getAccountId(), Resource.ResourceType.object_storage, (bucket.getQuota() * Resource.ResourceType.bytesToGiB));
_objectStoreDao.updateAllocatedSize(objectStoreVO, -(bucket.getQuota() * Resource.ResourceType.bytesToGiB));
return deleteCheckedBucket(objectStore, bucket, objectStoreVO);
}
private boolean deleteCheckedBucket(ObjectStoreEntity objectStore, Bucket bucket, ObjectStoreVO objectStoreVO) {
Account owner = _accountMgr.getAccount(bucket.getAccountId());
try (CheckedReservation bucketReservation = new CheckedReservation(owner, Resource.ResourceType.bucket,
bucket.getId(), null, -1L, reservationDao, resourceLimitManager);
CheckedReservation objectStorageReservation = new CheckedReservation(owner,
Resource.ResourceType.object_storage, bucket.getId(), null,
-1*(ObjectUtils.defaultIfNull(bucket.getQuota(), 0) * Resource.ResourceType.bytesToGiB), reservationDao, resourceLimitManager)) {
BucketTO bucketTO = new BucketTO(bucket);
if (objectStore.deleteBucket(bucketTO)) {
resourceLimitManager.decrementResourceCount(bucket.getAccountId(), Resource.ResourceType.bucket);
if (bucket.getQuota() != null) {
resourceLimitManager.decrementResourceCount(bucket.getAccountId(), Resource.ResourceType.object_storage, (bucket.getQuota() * Resource.ResourceType.bytesToGiB));
_objectStoreDao.updateAllocatedSize(objectStoreVO, -(bucket.getQuota() * Resource.ResourceType.bytesToGiB));
}
_bucketDao.remove(bucket.getId());
return true;
}
return _bucketDao.remove(bucketId);
return false;
} catch (Exception e) {
if (e instanceof CloudRuntimeException) {
throw (CloudRuntimeException) e;
}
throw new CloudRuntimeException(String.format("Failed to delete bucket due to: %s", e.getMessage()), e);
}
return false;
}
@Override

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;
@ -69,6 +70,7 @@ 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.framework.config.ConfigKey;
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;
@ -199,10 +201,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);
@ -211,6 +210,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);
@ -222,6 +226,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) {
@ -457,11 +465,10 @@ public class VolumeImportUnmanageManagerImpl implements VolumeImportUnmanageServ
return volumeDao.findById(diskProfile.getVolumeId());
}
protected void checkResourceLimitForImportVolume(Account owner, VolumeOnStorageTO volume) {
protected void checkResourceLimitForImportVolume(Account owner, VolumeOnStorageTO volume, DiskOfferingVO diskOffering, List<Reserver> reservations) {
Long volumeSize = volume.getVirtualSize();
try {
resourceLimitService.checkResourceLimit(owner, Resource.ResourceType.volume);
resourceLimitService.checkResourceLimit(owner, Resource.ResourceType.primary_storage, volumeSize);
resourceLimitService.checkVolumeResourceLimit(owner, true, volumeSize, diskOffering, reservations);
} catch (ResourceAllocationException e) {
logger.error("VM resource allocation error for account: {}", owner, e);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("VM resource allocation error for account: %s. %s", owner.getUuid(), StringUtils.defaultString(e.getMessage())));

View File

@ -86,6 +86,8 @@ import com.cloud.offerings.dao.NetworkOfferingDao;
import com.cloud.org.Cluster;
import com.cloud.resource.ResourceManager;
import com.cloud.resource.ResourceState;
import com.cloud.resourcelimit.CheckedReservation;
import com.cloud.resourcelimit.ReservationHelper;
import com.cloud.serializer.GsonHelper;
import com.cloud.server.ManagementService;
import com.cloud.service.ServiceOfferingVO;
@ -164,6 +166,8 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.reservation.dao.ReservationDao;
import org.apache.cloudstack.resourcelimit.Reserver;
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
@ -252,6 +256,8 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
@Inject
private ResourceLimitService resourceLimitService;
@Inject
private ReservationDao reservationDao;
@Inject
private VMInstanceDetailsDao vmInstanceDetailsDao;
@Inject
private UserVmManager userVmManager;
@ -575,7 +581,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));
@ -583,7 +589,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()));
}
@ -598,9 +603,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) {
@ -617,7 +623,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);
}
}
@ -1044,40 +1050,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,
@ -1135,99 +1107,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, guestOsId, 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, guestOsId, 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) {
@ -1332,8 +1308,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);
@ -1349,31 +1323,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) {
@ -1462,15 +1446,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");
@ -1705,7 +1680,6 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
Pair<UnmanagedInstanceTO, Boolean> sourceInstanceDetails = getSourceVmwareUnmanagedInstance(vcenter, datacenterName, username, password, clusterName, sourceHostName, sourceVMName, serviceOffering);
sourceVMwareInstance = sourceInstanceDetails.first();
isClonedInstance = sourceInstanceDetails.second();
boolean isWindowsVm = sourceVMwareInstance.getOperatingSystem().toLowerCase().contains("windows");
if (isWindowsVm) {
checkConversionSupportOnHost(convertHost, sourceVMName, true);
@ -2466,12 +2440,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;
@ -2559,26 +2527,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));
}
@ -2592,7 +2571,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);
@ -2603,6 +2582,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();
@ -2611,13 +2591,17 @@ 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 {
checkVolumeResourceLimitsForExternalKvmVmImport(owner, rootDisk, dataDisks, diskOffering, dataDiskOfferingMap, reservations);
// Check NICs and supplied networks
Map<String, Network.IpAddresses> nicIpAddressMap = getNicIpAddresses(unmanagedInstance.getNics(), callerNicIpAddressMap);
Map<String, Long> allNicNetworkMap = getUnmanagedNicNetworkMap(unmanagedInstance.getName(), unmanagedInstance.getNics(), nicNetworkMap, nicIpAddressMap, zone, hostName, owner, Hypervisor.HypervisorType.KVM);
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,
@ -2631,77 +2615,93 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
if (userVm == null) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to import vm name: %s", instanceName));
}
DiskOfferingVO diskOffering = diskOfferingDao.findById(serviceOffering.getDiskOfferingId());
String rootVolumeName = String.format("ROOT-%s", userVm.getId());
DiskProfile diskProfile = volumeManager.allocateRawVolume(Volume.Type.ROOT, rootVolumeName, diskOffering, null, null, null, userVm, template, owner, null);
DiskProfile diskProfile = volumeManager.allocateRawVolume(Volume.Type.ROOT, rootVolumeName, diskOffering, null, null, null, userVm, template, owner, null, false);
DiskProfile[] dataDiskProfiles = new DiskProfile[dataDisks.size()];
int diskSeq = 0;
for (UnmanagedInstanceTO.Disk disk : dataDisks) {
if (disk.getCapacity() == null || disk.getCapacity() == 0) {
throw new InvalidParameterValueException(String.format("Disk ID: %s size is invalid", disk.getDiskId()));
}
DiskOffering offering = diskOfferingDao.findById(dataDiskOfferingMap.get(disk.getDiskId()));
DiskProfile dataDiskProfile = volumeManager.allocateRawVolume(Volume.Type.DATADISK, String.format("DATA-%d-%s", userVm.getId(), disk.getDiskId()), offering, null, null, null, userVm, template, owner, null);
DiskProfile dataDiskProfile = volumeManager.allocateRawVolume(Volume.Type.DATADISK, String.format("DATA-%d-%s", userVm.getId(), disk.getDiskId()), offering, null, null, null, userVm, template, owner, null, false);
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 {
if (rootDisk.getCapacity() == null || rootDisk.getCapacity() == 0) {
throw new InvalidParameterValueException(String.format("Root disk ID: %s size is invalid", rootDisk.getDiskId()));
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()));
}
diskProfileStoragePoolList.add(importExternalDisk(rootDisk, userVm, dest, diskOffering, Volume.Type.ROOT,
template, null, remoteUrl, username, password, tmpPath, diskProfile));
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()));
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++;
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())));
}
} 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++;
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())));
}
} 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("Data disk ID: %s size is invalid", disk.getDiskId()));
}
DiskOffering offering = diskOfferingDao.findById(dataDiskOfferingMap.get(disk.getDiskId()));
resourceLimitService.checkVolumeResourceLimit(owner, true, disk.getCapacity(), offering, reservations);
}
publishVMUsageUpdateResourceCount(userVm, dummyOffering, template);
return userVm;
}
private UserVm importKvmVirtualMachineFromDisk(final ImportSource importSource, final String instanceName, final DataCenter zone,
@ -2769,9 +2769,18 @@ 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);
DiskProfile diskProfile = volumeManager.allocateRawVolume(Volume.Type.ROOT, rootVolumeName, diskOffering, null, null, null, userVm, template, owner, null, false);
final VirtualMachineProfile profile = new VirtualMachineProfileImpl(userVm, template, serviceOffering, owner, null);
ServiceOfferingVO dummyOffering = serviceOfferingDao.findById(userVm.getId(), serviceOffering.getId());
@ -2815,6 +2824,10 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
}
diskProfile.setSize(checkVolumeAnswer.getSize());
CheckedReservation primaryStorageReservation = new CheckedReservation(owner, Resource.ResourceType.primary_storage, resourceLimitStorageTags,
CollectionUtils.isNotEmpty(resourceLimitStorageTags) ? diskProfile.getSize() : 0L, reservationDao, resourceLimitService);
reservations.add(primaryStorageReservation);
List<Pair<DiskProfile, StoragePool>> diskProfileStoragePoolList = new ArrayList<>();
try {
long deviceId = 1L;
@ -2833,6 +2846,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

@ -27,6 +27,7 @@ import org.apache.cloudstack.annotation.dao.AnnotationDao;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ResponseObject;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.extension.ExtensionHelper;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@ -82,6 +83,9 @@ public class UserVmJoinDaoImplTest extends GenericDaoBaseWithTagInformationBaseT
@Mock
private VMTemplateDao vmTemplateDao;
@Mock
ExtensionHelper extensionHelper;
private UserVmJoinVO userVm = new UserVmJoinVO();
private UserVmResponse userVmResponse = new UserVmResponse();

View File

@ -23,7 +23,6 @@ import com.cloud.agent.api.routing.UpdateNetworkCommand;
import com.cloud.agent.api.to.IpAddressTO;
import com.cloud.agent.manager.Commands;
import com.cloud.alert.AlertManager;
import com.cloud.configuration.Resource;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.VlanVO;
import com.cloud.dc.dao.DataCenterDao;
@ -54,6 +53,7 @@ import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao;
import com.cloud.offering.NetworkOffering;
import com.cloud.offerings.NetworkOfferingServiceMapVO;
import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
import com.cloud.resourcelimit.CheckedReservation;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.AccountVO;
@ -81,6 +81,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockedConstruction;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
@ -490,7 +491,6 @@ public class VpcManagerImplTest {
public void testCreateVpcDnsOfferingServiceFailure() {
mockVpcDnsResources(false, false);
try {
doNothing().when(resourceLimitService).checkResourceLimit(account, Resource.ResourceType.vpc);
manager.createVpc(zoneId, vpcOfferingId, vpcOwnerId, vpcName, vpcName, ip4Cidr, vpcDomain,
ip4Dns[0], null, null, null, true, 1500, null, null, null, false);
} catch (ResourceAllocationException e) {
@ -502,7 +502,6 @@ public class VpcManagerImplTest {
public void testCreateVpcDnsIpv6OfferingFailure() {
mockVpcDnsResources(true, false);
try {
doNothing().when(resourceLimitService).checkResourceLimit(account, Resource.ResourceType.vpc);
manager.createVpc(zoneId, vpcOfferingId, vpcOwnerId, vpcName, vpcName, ip4Cidr, vpcDomain,
ip4Dns[0], ip4Dns[1], ip6Dns[0], null, true, 1500, null, null, null, false);
} catch (ResourceAllocationException e) {
@ -516,8 +515,7 @@ public class VpcManagerImplTest {
VpcVO vpc = Mockito.mock(VpcVO.class);
Mockito.when(vpcDao.persist(any(), anyMap())).thenReturn(vpc);
Mockito.when(vpc.getUuid()).thenReturn("uuid");
try {
doNothing().when(resourceLimitService).checkResourceLimit(account, Resource.ResourceType.vpc);
try (MockedConstruction<CheckedReservation> mockCheckedReservation = Mockito.mockConstruction(CheckedReservation.class)) {
manager.createVpc(zoneId, vpcOfferingId, vpcOwnerId, vpcName, vpcName, ip4Cidr, vpcDomain,
ip4Dns[0], ip4Dns[1], null, null, true, 1500, null, null, null, false);
} catch (ResourceAllocationException e) {
@ -533,8 +531,7 @@ public class VpcManagerImplTest {
Mockito.when(vpc.getUuid()).thenReturn("uuid");
doReturn(true).when(routedIpv4Manager).isRoutedVpc(any());
doNothing().when(routedIpv4Manager).getOrCreateIpv4SubnetForVpc(any(), anyString());
try {
doNothing().when(resourceLimitService).checkResourceLimit(account, Resource.ResourceType.vpc);
try (MockedConstruction<CheckedReservation> mockCheckedReservation = Mockito.mockConstruction(CheckedReservation.class)) {
manager.createVpc(zoneId, vpcOfferingId, vpcOwnerId, vpcName, vpcName, ip4Cidr, vpcDomain,
ip4Dns[0], ip4Dns[1], null, null, true, 1500, null, null, null, false);
} catch (ResourceAllocationException e) {
@ -556,8 +553,7 @@ public class VpcManagerImplTest {
Ipv4GuestSubnetNetworkMap ipv4GuestSubnetNetworkMap = Mockito.mock(Ipv4GuestSubnetNetworkMap.class);
doReturn(ipv4GuestSubnetNetworkMap).when(routedIpv4Manager).getOrCreateIpv4SubnetForVpc(any(), anyInt());
List<Long> bgpPeerIds = Arrays.asList(11L, 12L);
try {
doNothing().when(resourceLimitService).checkResourceLimit(account, Resource.ResourceType.vpc);
try (MockedConstruction<CheckedReservation> mockCheckedReservation = Mockito.mockConstruction(CheckedReservation.class)) {
manager.createVpc(zoneId, vpcOfferingId, vpcOwnerId, vpcName, vpcName, null, vpcDomain,
ip4Dns[0], ip4Dns[1], null, null, true, 1500, 24, null, bgpPeerIds, false);
} catch (ResourceAllocationException e) {

View File

@ -149,23 +149,10 @@ public class CheckedReservationTest {
@Test
public void testMultipleReservationsWithOneFailing() {
List<String> tags = List.of("abc", "xyz");
when(account.getAccountId()).thenReturn(1L);
when(account.getDomainId()).thenReturn(4L);
Map<Long, ReservationVO> persistedReservations = new HashMap<>();
Mockito.when(reservationDao.persist(Mockito.any(ReservationVO.class))).thenAnswer((Answer<ReservationVO>) invocation -> {
ReservationVO reservationVO = (ReservationVO) invocation.getArguments()[0];
Long id = (long) (persistedReservations.size() + 1);
ReflectionTestUtils.setField(reservationVO, "id", id);
persistedReservations.put(id, reservationVO);
return reservationVO;
});
Mockito.when(reservationDao.remove(Mockito.anyLong())).thenAnswer((Answer<Boolean>) invocation -> {
Long id = (Long) invocation.getArguments()[0];
persistedReservations.remove(id);
return true;
});
try {
Mockito.doThrow(ResourceAllocationException.class).when(resourceLimitService).checkResourceLimitWithTag(account, Resource.ResourceType.cpu, "xyz", 1L);
Mockito.doThrow(ResourceAllocationException.class).when(resourceLimitService).checkResourceLimitWithTag(account, account.getDomainId(), true, Resource.ResourceType.cpu, "xyz", 1L);
try (CheckedReservation vmReservation = new CheckedReservation(account, Resource.ResourceType.user_vm, tags, 1L, reservationDao, resourceLimitService);
CheckedReservation cpuReservation = new CheckedReservation(account, Resource.ResourceType.cpu, tags, 1L, reservationDao, resourceLimitService);
CheckedReservation memReservation = new CheckedReservation(account, Resource.ResourceType.memory, tags, 256L, reservationDao, resourceLimitService);

View File

@ -34,9 +34,10 @@ 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.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.After;
@ -46,6 +47,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;
@ -83,6 +85,7 @@ import com.cloud.user.ResourceLimitService;
import com.cloud.user.User;
import com.cloud.user.dao.AccountDao;
import com.cloud.utils.Pair;
import com.cloud.utils.StringUtils;
import com.cloud.utils.db.EntityManager;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineManager;
@ -278,6 +281,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));
@ -285,72 +289,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);
} catch (ResourceAllocationException e) {
Assert.fail("Exception encountered: " + e.getMessage());
}
}
@Test
public void testCheckVmGpuResourceLimit() {
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 gpuCount = 2L;
try {
Mockito.doNothing().when(resourceLimitManager).checkResourceLimitWithTag(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any());
resourceLimitManager.checkVmGpuResourceLimit(account, true, serviceOffering, template, gpuCount);
Mockito.verify(resourceLimitManager, Mockito.times(1)).checkResourceLimitWithTag(account, Resource.ResourceType.gpu, null, gpuCount);
Mockito.verify(resourceLimitManager, Mockito.times(1)).checkResourceLimitWithTag(account, Resource.ResourceType.gpu, hostTags.get(0), gpuCount);
Assert.assertEquals(4, mockCheckedReservation.constructed().size());
} catch (ResourceAllocationException e) {
Assert.fail("Exception encountered: " + e.getMessage());
}
@ -358,22 +302,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());
}
@ -626,10 +563,11 @@ public class ResourceLimitManagerImplTest {
public void testCheckResourceLimitWithTagNonAdmin() throws ResourceAllocationException {
AccountVO account = Mockito.mock(AccountVO.class);
Mockito.when(account.getId()).thenReturn(1L);
Mockito.when(account.getDomainId()).thenReturn(1L);
Mockito.when(accountManager.isRootAdmin(1L)).thenReturn(false);
Mockito.doReturn(new ArrayList<ResourceLimitVO>()).when(resourceLimitManager).lockAccountAndOwnerDomainRows(Mockito.anyLong(), Mockito.any(Resource.ResourceType.class), Mockito.anyString());
Mockito.doNothing().when(resourceLimitManager).checkAccountResourceLimit(account, null, Resource.ResourceType.cpu, hostTags.get(0), 1);
Mockito.doNothing().when(resourceLimitManager).checkDomainResourceLimit(account, null, Resource.ResourceType.cpu, hostTags.get(0), 1);
Mockito.doNothing().when(resourceLimitManager).checkDomainResourceLimit(1L, Resource.ResourceType.cpu, hostTags.get(0), 1);
try {
resourceLimitManager.checkResourceLimitWithTag(account, Resource.ResourceType.cpu, hostTags.get(0), 1);
} catch (ResourceAllocationException e) {
@ -645,9 +583,10 @@ public class ResourceLimitManagerImplTest {
Mockito.when(accountManager.isRootAdmin(1L)).thenReturn(false);
ProjectVO projectVO = Mockito.mock(ProjectVO.class);
Mockito.when(projectDao.findByProjectAccountId(Mockito.anyLong())).thenReturn(projectVO);
Mockito.when(projectVO.getDomainId()).thenReturn(1L);
Mockito.doReturn(new ArrayList<ResourceLimitVO>()).when(resourceLimitManager).lockAccountAndOwnerDomainRows(Mockito.anyLong(), Mockito.any(Resource.ResourceType.class), Mockito.anyString());
Mockito.doNothing().when(resourceLimitManager).checkAccountResourceLimit(account, projectVO, Resource.ResourceType.cpu, hostTags.get(0), 1);
Mockito.doNothing().when(resourceLimitManager).checkDomainResourceLimit(account, projectVO, Resource.ResourceType.cpu, hostTags.get(0), 1);
Mockito.doNothing().when(resourceLimitManager).checkDomainResourceLimit(1L, Resource.ResourceType.cpu, hostTags.get(0), 1);
try {
resourceLimitManager.checkResourceLimitWithTag(account, Resource.ResourceType.cpu, hostTags.get(0), 1);
} catch (ResourceAllocationException e) {
@ -991,13 +930,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());
@ -1014,6 +946,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;
@ -1027,12 +960,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

@ -22,7 +22,6 @@ import com.cloud.dc.dao.DataCenterDao;
import com.cloud.event.ActionEventUtils;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.org.Grouping;
import com.cloud.storage.DataStoreRole;
@ -317,12 +316,11 @@ public class SnapshotManagerImplTest {
Mockito.when(result1.isFailed()).thenReturn(false);
AsyncCallFuture<SnapshotResult> future1 = Mockito.mock(AsyncCallFuture.class);
try {
Mockito.doNothing().when(resourceLimitService).checkResourceLimit(Mockito.any(), Mockito.any(), Mockito.anyLong());
Mockito.when(future.get()).thenReturn(result);
Mockito.when(snapshotService.queryCopySnapshot(Mockito.any())).thenReturn(future);
Mockito.when(future1.get()).thenReturn(result1);
Mockito.when(snapshotService.copySnapshot(Mockito.any(SnapshotInfo.class), Mockito.anyString(), Mockito.any(DataStore.class))).thenReturn(future1);
} catch (ResourceAllocationException | ResourceUnavailableException | ExecutionException | InterruptedException e) {
} catch (ResourceUnavailableException | ExecutionException | InterruptedException e) {
Assert.fail(e.getMessage());
}
List<Long> addedZone = new ArrayList<>();

View File

@ -16,6 +16,27 @@
// under the License.
package com.cloud.storage.snapshot;
import org.apache.cloudstack.api.command.user.snapshot.ExtractSnapshotCmd;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotService;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotStrategy;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotStrategy.SnapshotOperation;
import org.apache.cloudstack.engine.subsystem.api.storage.StorageStrategyFactory;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.snapshot.SnapshotHelper;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity;
import com.cloud.api.ApiDBUtils;
import com.cloud.configuration.Resource.ResourceType;
import com.cloud.dc.DataCenter;
@ -27,6 +48,7 @@ import com.cloud.exception.ResourceAllocationException;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.resource.ResourceManager;
import com.cloud.resourcelimit.CheckedReservation;
import com.cloud.server.ResourceTag;
import com.cloud.server.TaggedResourceService;
import com.cloud.storage.DataStoreRole;
@ -57,27 +79,6 @@ import com.cloud.vm.snapshot.VMSnapshot;
import com.cloud.vm.snapshot.VMSnapshotVO;
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
import org.apache.cloudstack.api.command.user.snapshot.ExtractSnapshotCmd;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotService;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotStrategy;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotStrategy.SnapshotOperation;
import org.apache.cloudstack.engine.subsystem.api.storage.StorageStrategyFactory;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.snapshot.SnapshotHelper;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@ -87,6 +88,7 @@ import org.junit.runner.RunWith;
import org.mockito.BDDMockito;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedConstruction;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
@ -237,8 +239,6 @@ public class SnapshotManagerTest {
when(_storageStrategyFactory.getSnapshotStrategy(Mockito.any(SnapshotVO.class), Mockito.eq(SnapshotOperation.BACKUP))).thenReturn(snapshotStrategy);
when(_storageStrategyFactory.getSnapshotStrategy(Mockito.any(SnapshotVO.class), Mockito.eq(SnapshotOperation.REVERT))).thenReturn(snapshotStrategy);
doNothing().when(_resourceLimitMgr).checkResourceLimit(any(Account.class), any(ResourceType.class));
doNothing().when(_resourceLimitMgr).checkResourceLimit(any(Account.class), any(ResourceType.class), anyLong());
doNothing().when(_resourceLimitMgr).incrementResourceCount(anyLong(), any(ResourceType.class));
doNothing().when(_resourceLimitMgr).incrementResourceCount(anyLong(), any(ResourceType.class), anyLong());
@ -320,7 +320,12 @@ public class SnapshotManagerTest {
when(mockList2.size()).thenReturn(0);
when(_vmSnapshotDao.listByInstanceId(TEST_VM_ID, VMSnapshot.State.Creating, VMSnapshot.State.Reverting, VMSnapshot.State.Expunging)).thenReturn(mockList2);
when(_snapshotDao.persist(any(SnapshotVO.class))).thenReturn(snapshotMock);
_snapshotMgr.allocSnapshot(TEST_VOLUME_ID, Snapshot.MANUAL_POLICY_ID, null, null);
try (MockedConstruction<CheckedReservation> mockCheckedReservation = Mockito.mockConstruction(CheckedReservation.class)) {
_snapshotMgr.allocSnapshot(TEST_VOLUME_ID, Snapshot.MANUAL_POLICY_ID, null, null);
} catch (ResourceAllocationException e) {
Assert.fail(String.format("Failure with exception: %s", e.getMessage()));
}
}
@Test(expected = InvalidParameterValueException.class)
@ -468,7 +473,7 @@ public class SnapshotManagerTest {
public void validateCreateTagsForSnapshotPolicyWithValidTags(){
Mockito.doReturn(null).when(taggedResourceServiceMock).createTags(any(), any(), any(), any());
Map map = new HashMap<>();
Map<String, String> map = new HashMap<>();
map.put("test", "test");
_snapshotMgr.createTagsForSnapshotPolicy(map, snapshotPolicyVoMock);

View File

@ -22,7 +22,6 @@ package com.cloud.template;
import com.cloud.agent.AgentManager;
import com.cloud.api.query.dao.SnapshotJoinDao;
import com.cloud.api.query.dao.UserVmJoinDao;
import com.cloud.configuration.Resource;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.deployasis.dao.TemplateDeployAsIsDetailsDao;
import com.cloud.domain.dao.DomainDao;
@ -34,6 +33,7 @@ import com.cloud.host.dao.HostDao;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.hypervisor.HypervisorGuruManager;
import com.cloud.projects.ProjectManager;
import com.cloud.resourcelimit.CheckedReservation;
import com.cloud.storage.DataStoreRole;
import com.cloud.storage.GuestOSVO;
import com.cloud.storage.Snapshot;
@ -64,12 +64,14 @@ import com.cloud.user.User;
import com.cloud.user.UserData;
import com.cloud.user.UserVO;
import com.cloud.user.dao.AccountDao;
import com.cloud.utils.component.ComponentContext;
import com.cloud.utils.concurrency.NamedThreadFactory;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDao;
import junit.framework.TestCase;
import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd;
import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd;
import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd;
@ -92,6 +94,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;
@ -104,14 +107,21 @@ import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
import org.apache.cloudstack.storage.heuristics.HeuristicRuleHelper;
import org.apache.cloudstack.storage.template.VnfTemplateManager;
import org.apache.cloudstack.test.utils.SpringUtils;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedConstruction;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
@ -120,11 +130,7 @@ import org.springframework.context.annotation.FilterType;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import javax.inject.Inject;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@ -137,81 +143,81 @@ import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
public class TemplateManagerImplTest {
@RunWith(MockitoJUnitRunner.class)
public class TemplateManagerImplTest extends TestCase {
@Inject
TemplateManagerImpl templateManager = new TemplateManagerImpl();
@Spy
@InjectMocks
TemplateManagerImpl templateManager;
@Inject
@Mock
DataStoreManager dataStoreManager;
@Inject
@Mock
VMTemplateDao vmTemplateDao;
@Inject
@Mock
VMTemplatePoolDao vmTemplatePoolDao;
@Inject
@Mock
TemplateDataStoreDao templateDataStoreDao;
@Inject
@Mock
StoragePoolHostDao storagePoolHostDao;
@Inject
@Mock
PrimaryDataStoreDao primaryDataStoreDao;
@Inject
@Mock
ResourceLimitService resourceLimitMgr;
@Inject
@Mock
ImageStoreDao imgStoreDao;
@Inject
@Mock
GuestOSDao guestOSDao;
@Inject
VMTemplateDao tmpltDao;
@Inject
@Mock
SnapshotDao snapshotDao;
@Inject
@Mock
VolumeDao volumeDao;
@Mock
VMTemplateDetailsDao tmpltDetailsDao;
@Inject
@Mock
StorageStrategyFactory storageStrategyFactory;
@Inject
@Mock
VMInstanceDao _vmInstanceDao;
@Inject
private VMTemplateDao _tmpltDao;
@Mock
ReservationDao reservationDao;
@Inject
@Mock
HypervisorGuruManager _hvGuruMgr;
@Inject
@Mock
AccountManager _accountMgr;
@Inject
@Mock
VnfTemplateManager vnfTemplateManager;
@Inject
@Mock
SnapshotJoinDao snapshotJoinDao;
@Inject
@Mock
TemplateDeployAsIsDetailsDao templateDeployAsIsDetailsDao;
@Inject
@Mock
HeuristicRuleHelper heuristicRuleHelperMock;
public class CustomThreadPoolExecutor extends ThreadPoolExecutor {
@ -241,7 +247,6 @@ public class TemplateManagerImplTest {
@Before
public void setUp() {
ComponentContext.initComponentsLifeCycle();
AccountVO account = new AccountVO("admin", 1L, "networkDomain", Account.Type.NORMAL, "uuid");
UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN);
CallContext.register(user, account);
@ -275,7 +280,7 @@ public class TemplateManagerImplTest {
List<TemplateAdapter> adapters = new ArrayList<TemplateAdapter>();
adapters.add(templateAdapter);
when(cmd.getId()).thenReturn(0L);
when(_tmpltDao.findById(cmd.getId())).thenReturn(template);
when(vmTemplateDao.findById(cmd.getId())).thenReturn(template);
when(cmd.getZoneId()).thenReturn(null);
when(template.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.None);
@ -296,7 +301,6 @@ public class TemplateManagerImplTest {
//case 2.2: When Force delete flag is 'false' and VM instance VO list is non empty.
when(cmd.isForced()).thenReturn(false);
VMInstanceVO vmInstanceVO = mock(VMInstanceVO.class);
when(vmInstanceVO.getInstanceName()).thenReturn("mydDummyVM");
vmInstanceVOList.add(vmInstanceVO);
when(_vmInstanceDao.listNonExpungedByTemplate(anyLong())).thenReturn(vmInstanceVOList);
try {
@ -311,7 +315,6 @@ public class TemplateManagerImplTest {
when(mockTemplate.getId()).thenReturn(202l);
StoragePoolVO mockPool = mock(StoragePoolVO.class);
when(mockPool.getId()).thenReturn(2l);
PrimaryDataStore mockPrimaryDataStore = mock(PrimaryDataStore.class);
when(mockPrimaryDataStore.getId()).thenReturn(2l);
@ -319,7 +322,6 @@ public class TemplateManagerImplTest {
VMTemplateStoragePoolVO mockTemplateStore = mock(VMTemplateStoragePoolVO.class);
when(mockTemplateStore.getDownloadState()).thenReturn(VMTemplateStorageResourceAssoc.Status.DOWNLOADED);
when(dataStoreManager.getPrimaryDataStore(anyLong())).thenReturn(mockPrimaryDataStore);
when(vmTemplateDao.findById(anyLong(), anyBoolean())).thenReturn(mockTemplate);
when(vmTemplatePoolDao.findByPoolTemplate(anyLong(), anyLong(), nullable(String.class))).thenReturn(mockTemplateStore);
@ -335,13 +337,11 @@ public class TemplateManagerImplTest {
when(mockTemplate.getId()).thenReturn(202l);
StoragePoolVO mockPool = mock(StoragePoolVO.class);
when(mockPool.getId()).thenReturn(2l);
PrimaryDataStore mockPrimaryDataStore = mock(PrimaryDataStore.class);
when(mockPrimaryDataStore.getId()).thenReturn(2l);
when(mockPrimaryDataStore.getDataCenterId()).thenReturn(1l);
when(dataStoreManager.getPrimaryDataStore(anyLong())).thenReturn(mockPrimaryDataStore);
when(vmTemplateDao.findById(anyLong(), anyBoolean())).thenReturn(mockTemplate);
when(vmTemplatePoolDao.findByPoolTemplate(anyLong(), anyLong(), nullable(String.class))).thenReturn(null);
when(templateDataStoreDao.findByTemplateZoneDownloadStatus(202l, 1l, VMTemplateStorageResourceAssoc.Status.DOWNLOADED)).thenReturn(null);
@ -356,7 +356,6 @@ public class TemplateManagerImplTest {
when(mockTemplate.getId()).thenReturn(202l);
StoragePoolVO mockPool = mock(StoragePoolVO.class);
when(mockPool.getId()).thenReturn(2l);
PrimaryDataStore mockPrimaryDataStore = mock(PrimaryDataStore.class);
when(mockPrimaryDataStore.getId()).thenReturn(2l);
@ -364,7 +363,6 @@ public class TemplateManagerImplTest {
TemplateDataStoreVO mockTemplateDataStore = mock(TemplateDataStoreVO.class);
when(dataStoreManager.getPrimaryDataStore(anyLong())).thenReturn(mockPrimaryDataStore);
when(vmTemplateDao.findById(anyLong(), anyBoolean())).thenReturn(mockTemplate);
when(vmTemplatePoolDao.findByPoolTemplate(anyLong(), anyLong(), nullable(String.class))).thenReturn(null);
when(templateDataStoreDao.findByTemplateZoneDownloadStatus(202l, 1l, VMTemplateStorageResourceAssoc.Status.DOWNLOADED)).thenReturn(mockTemplateDataStore);
@ -415,20 +413,10 @@ public class TemplateManagerImplTest {
PrimaryDataStore mockPrimaryDataStore = mock(PrimaryDataStore.class);
VMTemplateStoragePoolVO mockTemplateStore = mock(VMTemplateStoragePoolVO.class);
when(mockPrimaryDataStore.getId()).thenReturn(2l);
when(mockPool.getId()).thenReturn(2l);
when(mockPool.getStatus()).thenReturn(StoragePoolStatus.Disabled);
when(mockPool.getDataCenterId()).thenReturn(1l);
when(mockTemplate.getId()).thenReturn(202l);
when(mockTemplateStore.getDownloadState()).thenReturn(VMTemplateStorageResourceAssoc.Status.DOWNLOADED);
when(vmTemplateDao.findById(anyLong())).thenReturn(mockTemplate);
when(dataStoreManager.getPrimaryDataStore(anyLong())).thenReturn(mockPrimaryDataStore);
when(vmTemplateDao.findById(anyLong(), anyBoolean())).thenReturn(mockTemplate);
when(vmTemplatePoolDao.findByPoolTemplate(anyLong(), anyLong(), nullable(String.class))).thenReturn(mockTemplateStore);
when(primaryDataStoreDao.findById(anyLong())).thenReturn(mockPool);
doNothing().when(mockTemplateStore).setMarkedForGC(anyBoolean());
ExecutorService preloadExecutor = new CustomThreadPoolExecutor(8, 8, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(),
new NamedThreadFactory("Template-Preloader"));
templateManager._preloadExecutor = preloadExecutor;
@ -446,15 +434,10 @@ public class TemplateManagerImplTest {
StoragePoolVO mockPool1 = mock(StoragePoolVO.class);
when(mockPool1.getId()).thenReturn(2l);
when(mockPool1.getStatus()).thenReturn(StoragePoolStatus.Up);
when(mockPool1.getDataCenterId()).thenReturn(1l);
StoragePoolVO mockPool2 = mock(StoragePoolVO.class);
when(mockPool2.getId()).thenReturn(3l);
when(mockPool2.getStatus()).thenReturn(StoragePoolStatus.Up);
when(mockPool2.getDataCenterId()).thenReturn(1l);
StoragePoolVO mockPool3 = mock(StoragePoolVO.class);
when(mockPool3.getId()).thenReturn(4l);
when(mockPool3.getStatus()).thenReturn(StoragePoolStatus.Up);
when(mockPool3.getDataCenterId()).thenReturn(2l);
pools.add(mockPool1);
pools.add(mockPool2);
@ -467,9 +450,6 @@ public class TemplateManagerImplTest {
when(dataStoreManager.getPrimaryDataStore(anyLong())).thenReturn(mockPrimaryDataStore);
when(vmTemplateDao.findById(anyLong(), anyBoolean())).thenReturn(mockTemplate);
when(vmTemplatePoolDao.findByPoolTemplate(anyLong(), anyLong(), nullable(String.class))).thenReturn(mockTemplateStore);
when(primaryDataStoreDao.findById(2l)).thenReturn(mockPool1);
when(primaryDataStoreDao.findById(3l)).thenReturn(mockPool2);
when(primaryDataStoreDao.findById(4l)).thenReturn(mockPool3);
when(primaryDataStoreDao.listByStatus(StoragePoolStatus.Up)).thenReturn(pools);
doNothing().when(mockTemplateStore).setMarkedForGC(anyBoolean());
@ -497,7 +477,6 @@ public class TemplateManagerImplTest {
when(mockCreateCmd.getVolumeId()).thenReturn(null);
when(mockCreateCmd.getSnapshotId()).thenReturn(1L);
when(mockCreateCmd.getOsTypeId()).thenReturn(1L);
when(mockCreateCmd.getEventDescription()).thenReturn("test");
when(mockCreateCmd.getDetails()).thenReturn(null);
when(mockCreateCmd.getZoneId()).thenReturn(null);
@ -510,20 +489,17 @@ public class TemplateManagerImplTest {
when(mockSnapshot.getState()).thenReturn(Snapshot.State.BackedUp);
when(mockSnapshot.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.XenServer);
doNothing().when(resourceLimitMgr).checkResourceLimit(any(Account.class), eq(Resource.ResourceType.template));
doNothing().when(resourceLimitMgr).checkResourceLimit(any(Account.class), eq(Resource.ResourceType.secondary_storage), anyLong());
GuestOSVO mockGuestOS = mock(GuestOSVO.class);
when(guestOSDao.findById(anyLong())).thenReturn(mockGuestOS);
when(tmpltDao.getNextInSequence(eq(Long.class), eq("id"))).thenReturn(1L);
when(vmTemplateDao.getNextInSequence(eq(Long.class), eq("id"))).thenReturn(1L);
List<ImageStoreVO> mockRegionStores = new ArrayList<>();
ImageStoreVO mockRegionStore = mock(ImageStoreVO.class);
mockRegionStores.add(mockRegionStore);
when(imgStoreDao.findRegionImageStores()).thenReturn(mockRegionStores);
when(tmpltDao.persist(any(VMTemplateVO.class))).thenAnswer(new Answer<VMTemplateVO>() {
when(vmTemplateDao.persist(any(VMTemplateVO.class))).thenAnswer(new Answer<VMTemplateVO>() {
@Override
public VMTemplateVO answer(InvocationOnMock invocationOnMock) throws Throwable {
Object[] args = invocationOnMock.getArguments();
@ -531,8 +507,10 @@ public class TemplateManagerImplTest {
}
});
VMTemplateVO template = templateManager.createPrivateTemplateRecord(mockCreateCmd, mockTemplateOwner);
assertTrue("Template in a region store should have cross zones set", template.isCrossZones());
try (MockedConstruction<CheckedReservation> mockCheckedReservation = Mockito.mockConstruction(CheckedReservation.class)) {
VMTemplateVO template = templateManager.createPrivateTemplateRecord(mockCreateCmd, mockTemplateOwner);
assertTrue("Template in a region store should have cross zones set", template.isCrossZones());
}
}
@Test
@ -544,7 +522,7 @@ public class TemplateManagerImplTest {
when(cmd.getUserdataPolicy()).thenReturn(UserData.UserDataOverridePolicy.ALLOWOVERRIDE);
VMTemplateVO template = Mockito.mock(VMTemplateVO.class);
when(_tmpltDao.findById(anyLong())).thenReturn(template);
when(vmTemplateDao.findById(anyLong())).thenReturn(template);
VirtualMachineTemplate resultTemplate = templateManager.linkUserDataToTemplate(cmd);
@ -560,7 +538,6 @@ public class TemplateManagerImplTest {
when(cmd.getUserdataPolicy()).thenReturn(UserData.UserDataOverridePolicy.ALLOWOVERRIDE);
VMTemplateVO template = Mockito.mock(VMTemplateVO.class);
when(_tmpltDao.findById(1L)).thenReturn(template);
templateManager.linkUserDataToTemplate(cmd);
}
@ -574,7 +551,6 @@ public class TemplateManagerImplTest {
when(cmd.getUserdataPolicy()).thenReturn(UserData.UserDataOverridePolicy.ALLOWOVERRIDE);
VMTemplateVO template = Mockito.mock(VMTemplateVO.class);
when(_tmpltDao.findById(1L)).thenReturn(template);
templateManager.linkUserDataToTemplate(cmd);
}
@ -587,7 +563,7 @@ public class TemplateManagerImplTest {
when(cmd.getUserdataId()).thenReturn(2L);
when(cmd.getUserdataPolicy()).thenReturn(UserData.UserDataOverridePolicy.ALLOWOVERRIDE);
when(_tmpltDao.findById(anyLong())).thenReturn(null);
when(vmTemplateDao.findById(anyLong())).thenReturn(null);
templateManager.linkUserDataToTemplate(cmd);
}
@ -602,7 +578,7 @@ public class TemplateManagerImplTest {
VMTemplateVO template = Mockito.mock(VMTemplateVO.class);
when(template.getId()).thenReturn(1L);
when(_tmpltDao.findById(1L)).thenReturn(template);
when(vmTemplateDao.findById(1L)).thenReturn(template);
VirtualMachineTemplate resultTemplate = templateManager.linkUserDataToTemplate(cmd);
@ -633,7 +609,6 @@ public class TemplateManagerImplTest {
DataStore dataStore = Mockito.mock(DataStore.class);
VolumeVO volumeVO = Mockito.mock(VolumeVO.class);
Mockito.when(dataStoreManager.getDataStore(Mockito.anyString(), Mockito.any(DataStoreRole.class))).thenReturn(null);
Mockito.when(heuristicRuleHelperMock.getImageStoreIfThereIsHeuristicRule(Mockito.anyLong(), Mockito.any(HeuristicType.class), Mockito.any(VolumeVO.class))).thenReturn(null);
Mockito.when(dataStoreManager.getImageStoreWithFreeCapacity(Mockito.anyLong())).thenReturn(dataStore);
@ -646,7 +621,6 @@ public class TemplateManagerImplTest {
DataStore dataStore = Mockito.mock(DataStore.class);
VolumeVO volumeVO = Mockito.mock(VolumeVO.class);
Mockito.when(dataStoreManager.getDataStore(Mockito.anyString(), Mockito.any(DataStoreRole.class))).thenReturn(null);
Mockito.when(heuristicRuleHelperMock.getImageStoreIfThereIsHeuristicRule(Mockito.anyLong(), Mockito.any(HeuristicType.class), Mockito.any(VolumeVO.class))).thenReturn(dataStore);
templateManager.getImageStore(null, 1L, volumeVO);
@ -987,6 +961,11 @@ public class TemplateManagerImplTest {
return Mockito.mock(TemplateDeployAsIsDetailsDao.class);
}
@Bean
public ReservationDao reservationDao() {
return Mockito.mock(ReservationDao.class);
}
@Bean
public SnapshotHelper snapshotHelper() {
return Mockito.mock(SnapshotHelper.class);

View File

@ -59,9 +59,20 @@ import java.util.Map;
import java.util.TimeZone;
import java.util.UUID;
import com.cloud.kubernetes.cluster.KubernetesServiceHelper;
import com.cloud.storage.dao.SnapshotPolicyDao;
import com.cloud.utils.fsm.NoTransitionException;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
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;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.test.util.ReflectionTestUtils;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.SecurityChecker;
import org.apache.cloudstack.api.ApiCommandResourceType;
@ -85,6 +96,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;
@ -95,18 +107,6 @@ import org.apache.cloudstack.storage.template.VnfTemplateManager;
import org.apache.cloudstack.userdata.UserDataManager;
import org.apache.cloudstack.vm.UnmanagedVMsManager;
import org.apache.cloudstack.vm.lease.VMLeaseManager;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.test.util.ReflectionTestUtils;
import com.cloud.api.query.dao.ServiceOfferingJoinDao;
import com.cloud.api.query.vo.ServiceOfferingJoinVO;
@ -133,6 +133,7 @@ import com.cloud.host.Host;
import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.kubernetes.cluster.KubernetesServiceHelper;
import com.cloud.network.Network;
import com.cloud.network.NetworkModel;
import com.cloud.network.as.AutoScaleManager;
@ -157,6 +158,7 @@ import com.cloud.offering.NetworkOffering;
import com.cloud.offering.ServiceOffering;
import com.cloud.offerings.NetworkOfferingVO;
import com.cloud.offerings.dao.NetworkOfferingDao;
import com.cloud.resourcelimit.CheckedReservation;
import com.cloud.server.ManagementService;
import com.cloud.service.ServiceOfferingVO;
import com.cloud.service.dao.ServiceOfferingDao;
@ -173,6 +175,7 @@ import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.DiskOfferingDao;
import com.cloud.storage.dao.GuestOSDao;
import com.cloud.storage.dao.SnapshotDao;
import com.cloud.storage.dao.SnapshotPolicyDao;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.template.VirtualMachineTemplate;
@ -195,6 +198,7 @@ import com.cloud.utils.db.EntityManager;
import com.cloud.utils.db.UUIDManager;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.exception.ExceptionProxyObject;
import com.cloud.utils.fsm.NoTransitionException;
import com.cloud.vm.dao.NicDao;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDetailsDao;
@ -692,7 +696,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());
@ -1703,23 +1706,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());
}
@ -2010,26 +2001,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
@ -3074,7 +3065,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

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

View File

@ -952,7 +952,7 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkOrches
}
@Override
public boolean resourceCountNeedsUpdate(NetworkOffering ntwkOff, ACLType aclType) {
public boolean isResourceCountUpdateNeeded(NetworkOffering ntwkOff) {
return false; //To change body of implemented methods use File | Settings | File Templates.
}

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;
@ -237,6 +238,11 @@ public class MockResourceLimitManagerImpl extends ManagerBase implements Resourc
}
@Override
public void checkResourceLimitWithTag(Account account, Long domainId, boolean considerSystemAccount, ResourceType type, String tag, long... count) throws ResourceAllocationException {
}
@Override
public List<String> getResourceLimitHostTags() {
return null;
@ -268,19 +274,24 @@ 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 {
}
@Override
public List<String> getResourceLimitStorageTagsForResourceCountOperation(Boolean display, DiskOffering diskOffering) {
return null;
}
@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) {
}
@ -324,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 {
}
@ -341,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 {
}
@ -367,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) {
@ -382,11 +383,6 @@ public class MockResourceLimitManagerImpl extends ManagerBase implements Resourc
}
@Override
public void checkVmGpuResourceLimit(Account owner, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long gpu) throws ResourceAllocationException {
}
@Override
public void incrementVmGpuResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long gpu) {
@ -396,4 +392,9 @@ public class MockResourceLimitManagerImpl extends ManagerBase implements Resourc
public void decrementVmGpuResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long gpu) {
}
@Override
public long recalculateDomainResourceCount(long domainId, ResourceType type, String tag) {
return 0;
}
}

View File

@ -16,9 +16,73 @@
// under the License.
package org.apache.cloudstack.backup;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.TimeZone;
import java.util.UUID;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import org.springframework.test.util.ReflectionTestUtils;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.command.admin.backup.ImportBackupOfferingCmd;
import org.apache.cloudstack.api.command.admin.backup.UpdateBackupOfferingCmd;
import org.apache.cloudstack.api.command.user.backup.CreateBackupCmd;
import org.apache.cloudstack.api.command.user.backup.CreateBackupScheduleCmd;
import org.apache.cloudstack.api.command.user.backup.DeleteBackupScheduleCmd;
import org.apache.cloudstack.api.command.user.backup.ListBackupScheduleCmd;
import org.apache.cloudstack.api.response.BackupResponse;
import org.apache.cloudstack.backup.dao.BackupDao;
import org.apache.cloudstack.backup.dao.BackupDetailsDao;
import org.apache.cloudstack.backup.dao.BackupOfferingDao;
import org.apache.cloudstack.backup.dao.BackupScheduleDao;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.impl.ConfigDepotImpl;
import org.apache.cloudstack.framework.jobs.AsyncJobManager;
import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO;
import org.apache.cloudstack.reservation.ReservationVO;
import org.apache.cloudstack.reservation.dao.ReservationDao;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import com.cloud.alert.AlertManager;
import com.cloud.api.query.dao.UserVmJoinDao;
import com.cloud.api.query.vo.UserVmJoinVO;
import com.cloud.alert.AlertManager;
import com.cloud.capacity.CapacityVO;
import com.cloud.configuration.Resource;
import com.cloud.dc.DataCenter;
@ -31,6 +95,7 @@ import com.cloud.event.ActionEventUtils;
import com.cloud.event.EventTypes;
import com.cloud.event.UsageEventUtils;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao;
import com.cloud.hypervisor.Hypervisor;
@ -42,7 +107,6 @@ import com.cloud.offering.DiskOffering;
import com.cloud.service.ServiceOfferingVO;
import com.cloud.service.dao.ServiceOfferingDao;
import com.cloud.storage.DiskOfferingVO;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.storage.Storage;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.Volume;
@ -61,6 +125,8 @@ import com.cloud.user.User;
import com.cloud.user.dao.AccountDao;
import com.cloud.utils.DateUtil;
import com.cloud.utils.Pair;
import com.cloud.utils.StringUtils;
import com.cloud.utils.db.DbUtil;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.exception.CloudRuntimeException;
@ -68,68 +134,11 @@ import com.cloud.utils.fsm.NoTransitionException;
import com.cloud.vm.VMInstanceDetailVO;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VmDiskInfo;
import com.cloud.vm.VirtualMachineManager;
import com.cloud.vm.dao.VMInstanceDetailsDao;
import com.cloud.vm.VmDiskInfo;
import com.cloud.vm.dao.VMInstanceDao;
import com.cloud.vm.dao.VMInstanceDetailsDao;
import com.google.gson.Gson;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.command.admin.backup.ImportBackupOfferingCmd;
import org.apache.cloudstack.api.command.admin.backup.UpdateBackupOfferingCmd;
import org.apache.cloudstack.api.command.user.backup.CreateBackupCmd;
import org.apache.cloudstack.api.command.user.backup.CreateBackupScheduleCmd;
import org.apache.cloudstack.api.command.user.backup.DeleteBackupScheduleCmd;
import org.apache.cloudstack.api.command.user.backup.ListBackupScheduleCmd;
import org.apache.cloudstack.api.response.BackupResponse;
import org.apache.cloudstack.backup.dao.BackupDao;
import org.apache.cloudstack.backup.dao.BackupDetailsDao;
import org.apache.cloudstack.backup.dao.BackupOfferingDao;
import org.apache.cloudstack.backup.dao.BackupScheduleDao;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.impl.ConfigDepotImpl;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.framework.jobs.AsyncJobManager;
import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.springframework.test.util.ReflectionTestUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.TimeZone;
import java.util.UUID;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.atLeastOnce;
@RunWith(MockitoJUnitRunner.class)
public class BackupManagerTest {
@ -239,6 +248,9 @@ public class BackupManagerTest {
@Mock
DomainDao domainDao;
@Mock
ReservationDao reservationDao;
@Mock
private GuestOSDao _guestOSDao;
@ -252,6 +264,8 @@ public class BackupManagerTest {
private AutoCloseable closeable;
private ConfigDepotImpl configDepotImpl;
private boolean updatedConfigKeyDepot = false;
private MockedStatic<DbUtil> dbUtilMockedStatic;
private final List<String> mockedGlobalLocks = new ArrayList<>();
@Before
public void setup() throws Exception {
@ -283,6 +297,29 @@ public class BackupManagerTest {
backupProvidersMap.put(backupProvider.getName().toLowerCase(), backupProvider);
ReflectionTestUtils.setField(backupManager, "backupProvidersMap", backupProvidersMap);
when(reservationDao.persist(any(ReservationVO.class)))
.thenAnswer((Answer<ReservationVO>) invocation -> {
ReservationVO reservationVO = (ReservationVO)invocation.getArguments()[0];
ReflectionTestUtils.setField(reservationVO, "id", 10L);
return reservationVO;
});
dbUtilMockedStatic = Mockito.mockStatic(DbUtil.class);
dbUtilMockedStatic.when(() -> DbUtil.getGlobalLock(anyString(), anyInt())).thenAnswer((Answer<Boolean>) invocation -> {
String lockName = invocation.getArgument(0);
if (!StringUtils.isBlank(lockName) && !mockedGlobalLocks.contains(lockName)) {
mockedGlobalLocks.add(lockName);
return true;
}
return false;
});
dbUtilMockedStatic.when(() -> DbUtil.releaseGlobalLock(anyString())).thenAnswer((Answer<Boolean>) invocation -> {
String lockName = invocation.getArgument(0);
if (!StringUtils.isBlank(lockName)) {
mockedGlobalLocks.remove(lockName);
}
return true;
});
Account account = mock(Account.class);
User user = mock(User.class);
CallContext.register(user, account);
@ -290,6 +327,7 @@ public class BackupManagerTest {
@After
public void tearDown() throws Exception {
dbUtilMockedStatic.close();
closeable.close();
if (updatedConfigKeyDepot) {
ReflectionTestUtils.setField(BackupManager.BackupFrameworkEnabled, "s_depot", configDepotImpl);
@ -626,6 +664,7 @@ public class BackupManagerTest {
Long oldestBackupId = 7L;
Long newBackupSize = 1000000000L;
Long oldBackupSize = 400000000L;
long domainId = 101L;
when(vmInstanceDao.findById(vmId)).thenReturn(vmInstanceVOMock);
when(vmInstanceVOMock.getDataCenterId()).thenReturn(zoneId);
@ -640,6 +679,7 @@ public class BackupManagerTest {
Mockito.doReturn(scheduleId).when(backupManager).getBackupScheduleId(asyncJobVOMock);
when(accountManager.getAccount(accountId)).thenReturn(accountVOMock);
when(accountVOMock.getDomainId()).thenReturn(domainId);
BackupScheduleVO schedule = mock(BackupScheduleVO.class);
when(backupScheduleDao.findById(scheduleId)).thenReturn(schedule);
@ -681,8 +721,10 @@ public class BackupManagerTest {
assertTrue(backupManager.createBackup(cmd, asyncJobVOMock));
Mockito.verify(resourceLimitMgr, times(1)).checkResourceLimit(accountVOMock, Resource.ResourceType.backup);
Mockito.verify(resourceLimitMgr, times(1)).checkResourceLimit(accountVOMock, Resource.ResourceType.backup_storage, newBackupSize);
Mockito.verify(resourceLimitMgr, times(1))
.checkResourceLimitWithTag(accountVOMock, domainId, true, Resource.ResourceType.backup, null, 1L);
Mockito.verify(resourceLimitMgr, times(1))
.checkResourceLimitWithTag(accountVOMock, domainId, true, Resource.ResourceType.backup_storage, null, newBackupSize);
Mockito.verify(resourceLimitMgr, times(1)).incrementResourceCount(accountId, Resource.ResourceType.backup);
Mockito.verify(resourceLimitMgr, times(1)).incrementResourceCount(accountId, Resource.ResourceType.backup_storage, newBackupSize);
@ -698,6 +740,7 @@ public class BackupManagerTest {
Long scheduleId = 3L;
Long backupOfferingId = 4L;
Long accountId = 5L;
long domainId = 101L;
when(vmInstanceDao.findById(vmId)).thenReturn(vmInstanceVOMock);
when(vmInstanceVOMock.getDataCenterId()).thenReturn(zoneId);
@ -712,7 +755,9 @@ public class BackupManagerTest {
Account account = Mockito.mock(Account.class);
when(accountManager.getAccount(accountId)).thenReturn(account);
Mockito.doThrow(new ResourceAllocationException("", Resource.ResourceType.backup)).when(resourceLimitMgr).checkResourceLimit(account, Resource.ResourceType.backup);
when(account.getDomainId()).thenReturn(domainId);
Mockito.doThrow(new ResourceAllocationException("", Resource.ResourceType.backup)).when(resourceLimitMgr)
.checkResourceLimitWithTag(account, domainId, true, Resource.ResourceType.backup, null, 1L);
CreateBackupCmd cmd = Mockito.mock(CreateBackupCmd.class);
when(cmd.getVmId()).thenReturn(vmId);
@ -736,6 +781,8 @@ public class BackupManagerTest {
Long scheduleId = 3L;
Long backupOfferingId = 4L;
Long accountId = 5L;
long domainId = 101L;
long size = 10000L;
VMInstanceVO vm = Mockito.mock(VMInstanceVO.class);
when(vmInstanceDao.findById(vmId)).thenReturn(vm);
@ -743,6 +790,11 @@ public class BackupManagerTest {
when(vm.getBackupOfferingId()).thenReturn(backupOfferingId);
when(vm.getAccountId()).thenReturn(accountId);
VolumeVO volume = mock(VolumeVO.class);
when(volumeDao.findByInstance(vmId)).thenReturn(List.of(volume));
when(volume.getState()).thenReturn(Volume.State.Ready);
when(volumeApiService.getVolumePhysicalSize(null, null, null)).thenReturn(size);
overrideBackupFrameworkConfigValue();
BackupOfferingVO offering = Mockito.mock(BackupOfferingVO.class);
when(backupOfferingDao.findById(backupOfferingId)).thenReturn(offering);
@ -753,7 +805,10 @@ public class BackupManagerTest {
Account account = Mockito.mock(Account.class);
when(accountManager.getAccount(accountId)).thenReturn(account);
Mockito.doThrow(new ResourceAllocationException("", Resource.ResourceType.backup_storage)).when(resourceLimitMgr).checkResourceLimit(account, Resource.ResourceType.backup_storage, 0L);
when(account.getDomainId()).thenReturn(domainId);
Mockito.doThrow(new ResourceAllocationException("", Resource.ResourceType.backup_storage))
.when(resourceLimitMgr)
.checkResourceLimitWithTag(account, domainId, true, Resource.ResourceType.backup_storage, null, size);
CreateBackupCmd cmd = Mockito.mock(CreateBackupCmd.class);
when(cmd.getVmId()).thenReturn(vmId);
@ -1491,6 +1546,7 @@ public class BackupManagerTest {
when(backup.getVmId()).thenReturn(vmId);
when(backup.getZoneId()).thenReturn(zoneId);
when(backup.getAccountId()).thenReturn(accountId);
when(accountManager.getAccount(accountId)).thenReturn(accountVOMock);
when(backup.getBackupOfferingId()).thenReturn(backupOfferingId);
when(backup.getSize()).thenReturn(100L);
when(backup.getUuid()).thenReturn("backup-uuid");

View File

@ -16,19 +16,36 @@
// under the License.
package org.apache.cloudstack.storage.object;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.List;
import org.apache.cloudstack.api.command.user.bucket.CreateBucketCmd;
import org.apache.cloudstack.api.command.user.bucket.UpdateBucketCmd;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.reservation.ReservationVO;
import org.apache.cloudstack.reservation.dao.ReservationDao;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDao;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreVO;
import org.apache.commons.lang3.StringUtils;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import org.springframework.test.util.ReflectionTestUtils;
import com.cloud.agent.api.to.BucketTO;
@ -40,6 +57,9 @@ import com.cloud.storage.DataStoreRole;
import com.cloud.storage.dao.BucketDao;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.AccountVO;
import com.cloud.user.User;
import com.cloud.utils.db.DbUtil;
@RunWith(MockitoJUnitRunner.class)
public class BucketApiServiceImplTest {
@ -62,33 +82,90 @@ public class BucketApiServiceImplTest {
@Mock
private BucketDao bucketDao;
@Mock
ReservationDao reservationDao;
@Mock
private AccountVO mockAccountVO;
private MockedStatic<DbUtil> dbUtilMockedStatic;
private final List<String> mockedGlobalLocks = new ArrayList<>();
private static final long ACCOUNT_ID = 1001L;
private static final long DOMAIN_ID = 10L;
@Before
public void setup() {
when(accountManager.getActiveAccountById(ACCOUNT_ID)).thenReturn(mockAccountVO);
when(mockAccountVO.getDomainId()).thenReturn(DOMAIN_ID);
when(reservationDao.persist(any(ReservationVO.class)))
.thenAnswer((Answer<ReservationVO>) invocation -> {
ReservationVO reservationVO = (ReservationVO)invocation.getArguments()[0];
ReflectionTestUtils.setField(reservationVO, "id", 10L);
return reservationVO;
});
dbUtilMockedStatic = Mockito.mockStatic(DbUtil.class);
dbUtilMockedStatic.when(() -> DbUtil.getGlobalLock(anyString(), anyInt()))
.thenAnswer((Answer<Boolean>) invocation -> {
String lockName = invocation.getArgument(0);
if (!StringUtils.isBlank(lockName) && !mockedGlobalLocks.contains(lockName)) {
mockedGlobalLocks.add(lockName);
return true;
}
return false;
});
dbUtilMockedStatic.when(() -> DbUtil.releaseGlobalLock(anyString()))
.thenAnswer((Answer<Boolean>) invocation -> {
String lockName = invocation.getArgument(0);
if (!StringUtils.isBlank(lockName)) {
mockedGlobalLocks.remove(lockName);
}
return true;
});
Account account = mock(Account.class);
User user = mock(User.class);
CallContext.register(user, account);
}
@After
public void tearDown() throws Exception {
dbUtilMockedStatic.close();
CallContext.unregister();
}
@Test
public void testAllocBucket() throws ResourceAllocationException {
String bucketName = "bucket1";
Long accountId = 1L;
Long poolId = 2L;
Long objectStoreId = 3L;
int quota = 1;
CreateBucketCmd cmd = Mockito.mock(CreateBucketCmd.class);
Mockito.when(cmd.getBucketName()).thenReturn(bucketName);
Mockito.when(cmd.getEntityOwnerId()).thenReturn(accountId);
Mockito.when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID);
Mockito.when(cmd.getObjectStoragePoolId()).thenReturn(poolId);
Mockito.when(cmd.getQuota()).thenReturn(1);
Account account = Mockito.mock(Account.class);
Mockito.when(accountManager.getActiveAccountById(accountId)).thenReturn(account);
Mockito.when(cmd.getQuota()).thenReturn(quota);
ObjectStoreVO objectStoreVO = Mockito.mock(ObjectStoreVO.class);
Mockito.when(objectStoreVO.getId()).thenReturn(objectStoreId);
Mockito.when(objectStoreDao.findById(poolId)).thenReturn(objectStoreVO);
ObjectStoreEntity objectStore = Mockito.mock(ObjectStoreEntity.class);
Mockito.when(dataStoreMgr.getDataStore(objectStoreId, DataStoreRole.Object)).thenReturn(objectStore);
Mockito.when(objectStore.createUser(accountId)).thenReturn(true);
Mockito.when(objectStore.createUser(ACCOUNT_ID)).thenReturn(true);
bucketApiService.allocBucket(cmd);
Mockito.verify(resourceLimitManager, Mockito.times(1)).checkResourceLimit(account, Resource.ResourceType.bucket);
Mockito.verify(resourceLimitManager, Mockito.times(1)).checkResourceLimit(account, Resource.ResourceType.object_storage, 1 * Resource.ResourceType.bytesToGiB);
long size = quota * Resource.ResourceType.bytesToGiB;
Mockito.verify(resourceLimitManager, Mockito.times(1))
.checkResourceLimitWithTag(mockAccountVO, DOMAIN_ID, true,
Resource.ResourceType.bucket, null, 1L);
Mockito.verify(resourceLimitManager, Mockito.times(1))
.checkResourceLimitWithTag(mockAccountVO, DOMAIN_ID, true,
Resource.ResourceType.object_storage, null, size);
Mockito.verify(resourceLimitManager, Mockito.times(1))
.incrementResourceCount(ACCOUNT_ID, Resource.ResourceType.bucket);
Mockito.verify(resourceLimitManager, Mockito.times(1))
.incrementResourceCount(ACCOUNT_ID, Resource.ResourceType.object_storage, size);
}
@Test
@ -96,21 +173,21 @@ public class BucketApiServiceImplTest {
Long objectStoreId = 1L;
Long poolId = 2L;
Long bucketId = 3L;
Long accountId = 4L;
String bucketName = "bucket1";
int quota = 3;
CreateBucketCmd cmd = Mockito.mock(CreateBucketCmd.class);
Mockito.when(cmd.getObjectStoragePoolId()).thenReturn(poolId);
Mockito.when(cmd.getEntityId()).thenReturn(bucketId);
Mockito.when(cmd.getQuota()).thenReturn(1);
Mockito.when(cmd.getQuota()).thenReturn(quota);
BucketVO bucket = new BucketVO(bucketName);
Mockito.when(bucketDao.findById(bucketId)).thenReturn(bucket);
ReflectionTestUtils.setField(bucket, "accountId", accountId);
ReflectionTestUtils.setField(bucket, "accountId", ACCOUNT_ID);
ObjectStoreVO objectStoreVO = Mockito.mock(ObjectStoreVO.class);
Mockito.when(objectStoreVO.getId()).thenReturn(objectStoreId);
Mockito.when(objectStoreVO.getTotalSize()).thenReturn(2000000000L);
Mockito.when(objectStoreVO.getTotalSize()).thenReturn(10 * Resource.ResourceType.bytesToGiB);
Mockito.when(objectStoreDao.findById(poolId)).thenReturn(objectStoreVO);
ObjectStoreEntity objectStore = Mockito.mock(ObjectStoreEntity.class);
Mockito.when(dataStoreMgr.getDataStore(objectStoreId, DataStoreRole.Object)).thenReturn(objectStore);
@ -118,23 +195,23 @@ public class BucketApiServiceImplTest {
bucketApiService.createBucket(cmd);
Mockito.verify(resourceLimitManager, Mockito.times(1)).incrementResourceCount(accountId, Resource.ResourceType.bucket);
Mockito.verify(resourceLimitManager, Mockito.times(1)).incrementResourceCount(accountId, Resource.ResourceType.object_storage, 1 * Resource.ResourceType.bytesToGiB);
Assert.assertEquals(bucket.getState(), Bucket.State.Created);
Assert.assertEquals(Bucket.State.Created, bucket.getState());
}
@Test
public void testDeleteBucket() {
Long bucketId = 1L;
Long accountId = 2L;
Long objectStoreId = 3L;
String bucketName = "bucket1";
int quota = 2;
BucketVO bucket = new BucketVO(bucketName);
BucketVO bucket = mock(BucketVO.class);
when(bucket.getName()).thenReturn(bucketName);
when(bucket.getObjectStoreId()).thenReturn(objectStoreId);
when(bucket.getQuota()).thenReturn(quota);
when(bucket.getAccountId()).thenReturn(ACCOUNT_ID);
when(accountManager.getAccount(ACCOUNT_ID)).thenReturn(mock(AccountVO.class));
Mockito.when(bucketDao.findById(bucketId)).thenReturn(bucket);
ReflectionTestUtils.setField(bucket, "objectStoreId", objectStoreId);
ReflectionTestUtils.setField(bucket, "quota", 1);
ReflectionTestUtils.setField(bucket, "accountId", accountId);
ObjectStoreVO objectStoreVO = Mockito.mock(ObjectStoreVO.class);
Mockito.when(objectStoreVO.getId()).thenReturn(objectStoreId);
@ -145,15 +222,17 @@ public class BucketApiServiceImplTest {
bucketApiService.deleteBucket(bucketId, null);
Mockito.verify(resourceLimitManager, Mockito.times(1)).decrementResourceCount(accountId, Resource.ResourceType.bucket);
Mockito.verify(resourceLimitManager, Mockito.times(1)).decrementResourceCount(accountId, Resource.ResourceType.object_storage, 1 * Resource.ResourceType.bytesToGiB);
Mockito.verify(resourceLimitManager, Mockito.times(1))
.decrementResourceCount(ACCOUNT_ID, Resource.ResourceType.bucket);
Mockito.verify(resourceLimitManager, Mockito.times(1))
.decrementResourceCount(ACCOUNT_ID, Resource.ResourceType.object_storage,
quota * Resource.ResourceType.bytesToGiB);
}
@Test
public void testUpdateBucket() throws ResourceAllocationException {
Long bucketId = 1L;
Long objectStoreId = 2L;
Long accountId = 3L;
Integer bucketQuota = 2;
Integer cmdQuota = 1;
String bucketName = "bucket1";
@ -164,12 +243,10 @@ public class BucketApiServiceImplTest {
BucketVO bucket = new BucketVO(bucketName);
ReflectionTestUtils.setField(bucket, "quota", bucketQuota);
ReflectionTestUtils.setField(bucket, "accountId", accountId);
ReflectionTestUtils.setField(bucket, "accountId", ACCOUNT_ID);
ReflectionTestUtils.setField(bucket, "objectStoreId", objectStoreId);
Mockito.when(bucketDao.findById(bucketId)).thenReturn(bucket);
Account account = Mockito.mock(Account.class);
ObjectStoreVO objectStoreVO = Mockito.mock(ObjectStoreVO.class);
Mockito.when(objectStoreVO.getId()).thenReturn(objectStoreId);
Mockito.when(objectStoreDao.findById(objectStoreId)).thenReturn(objectStoreVO);
@ -178,6 +255,8 @@ public class BucketApiServiceImplTest {
bucketApiService.updateBucket(cmd, null);
Mockito.verify(resourceLimitManager, Mockito.times(1)).decrementResourceCount(accountId, Resource.ResourceType.object_storage, (bucketQuota - cmdQuota) * Resource.ResourceType.bytesToGiB);
Mockito.verify(resourceLimitManager, Mockito.times(1))
.decrementResourceCount(ACCOUNT_ID, Resource.ResourceType.object_storage,
(bucketQuota - cmdQuota) * Resource.ResourceType.bytesToGiB);
}
}

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,11 +39,22 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
import com.cloud.offering.DiskOffering;
import com.cloud.storage.Snapshot;
import com.cloud.storage.SnapshotVO;
import com.cloud.storage.dao.SnapshotDao;
import com.cloud.vm.ImportVMTaskVO;
import org.jetbrains.annotations.NotNull;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
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;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ResponseGenerator;
import org.apache.cloudstack.api.ResponseObject;
@ -66,20 +77,6 @@ import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.jetbrains.annotations.NotNull;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.BDDMockito;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import com.cloud.agent.AgentManager;
import com.cloud.agent.api.Answer;
@ -98,7 +95,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;
@ -115,7 +111,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;
@ -128,16 +123,20 @@ import com.cloud.network.Network;
import com.cloud.network.NetworkModel;
import com.cloud.network.dao.NetworkDao;
import com.cloud.network.dao.NetworkVO;
import com.cloud.offering.DiskOffering;
import com.cloud.offering.NetworkOffering;
import com.cloud.offering.ServiceOffering;
import com.cloud.org.Grouping;
import com.cloud.resource.ResourceManager;
import com.cloud.resource.ResourceState;
import com.cloud.resourcelimit.CheckedReservation;
import com.cloud.service.ServiceOfferingVO;
import com.cloud.service.dao.ServiceOfferingDao;
import com.cloud.storage.DataStoreRole;
import com.cloud.storage.DiskOfferingVO;
import com.cloud.storage.ScopeType;
import com.cloud.storage.Snapshot;
import com.cloud.storage.SnapshotVO;
import com.cloud.storage.Storage;
import com.cloud.storage.StoragePool;
import com.cloud.storage.StoragePoolHostVO;
@ -147,6 +146,7 @@ import com.cloud.storage.Volume;
import com.cloud.storage.VolumeApiService;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.DiskOfferingDao;
import com.cloud.storage.dao.SnapshotDao;
import com.cloud.storage.dao.StoragePoolHostDao;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.storage.dao.VMTemplatePoolDao;
@ -164,6 +164,7 @@ import com.cloud.utils.Pair;
import com.cloud.utils.db.EntityManager;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.DiskProfile;
import com.cloud.vm.ImportVMTaskVO;
import com.cloud.vm.NicProfile;
import com.cloud.vm.UserVmManager;
import com.cloud.vm.UserVmVO;
@ -308,7 +309,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);
@ -448,7 +448,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);
}
}
@ -650,7 +651,7 @@ public class UnmanagedVMsManagerImplTest {
DeployDestination mockDest = Mockito.mock(DeployDestination.class);
when(deploymentPlanningManager.planDeployment(any(), any(), any(), any())).thenReturn(mockDest);
DiskProfile diskProfile = Mockito.mock(DiskProfile.class);
when(volumeManager.allocateRawVolume(any(), any(), any(), any(), any(), any(), any(), any(), any(), any()))
when(volumeManager.allocateRawVolume(any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), anyBoolean()))
.thenReturn(diskProfile);
Map<Volume, StoragePool> storage = new HashMap<>();
VolumeVO volume = Mockito.mock(VolumeVO.class);
@ -662,7 +663,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);
}
}
@ -850,7 +852,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());
@ -884,7 +887,7 @@ public class UnmanagedVMsManagerImplTest {
DeployDestination mockDest = Mockito.mock(DeployDestination.class);
when(deploymentPlanningManager.planDeployment(any(), any(), any(), any())).thenReturn(mockDest);
DiskProfile diskProfile = Mockito.mock(DiskProfile.class);
when(volumeManager.allocateRawVolume(any(), any(), any(), any(), any(), any(), any(), any(), any(), any()))
when(volumeManager.allocateRawVolume(any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), anyBoolean()))
.thenReturn(diskProfile);
Map<Volume, StoragePool> storage = new HashMap<>();
VolumeVO volume = Mockito.mock(VolumeVO.class);
@ -903,7 +906,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);
}
}
@ -1251,42 +1255,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);

View File

@ -130,6 +130,7 @@ public class HttpUploadServerHandler extends SimpleChannelInboundHandler<HttpObj
if (decoder != null) {
decoder.cleanFiles();
}
storageResource.deregisterUploadChannel(uuid);
requestProcessed = false;
}
@ -182,6 +183,7 @@ public class HttpUploadServerHandler extends SimpleChannelInboundHandler<HttpObj
requestProcessed = true;
return;
}
storageResource.registerUploadChannel(uuid, ctx.channel());
//set the base directory to download the file
DiskFileUpload.baseDirectory = uploadEntity.getInstallPathPrefix();
this.processTimeout = uploadEntity.getProcessTimeout();

View File

@ -49,6 +49,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -258,7 +259,8 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S
protected String _parent = "/mnt/SecStorage";
final private String _tmpltpp = "template.properties";
protected String createTemplateFromSnapshotXenScript;
private HashMap<String, UploadEntity> uploadEntityStateMap = new HashMap<>();
private final Map<String, UploadEntity> uploadEntityStateMap = new ConcurrentHashMap<>();
private final Map<String, Channel> uploadChannelMap = new ConcurrentHashMap<>();
private String _ssvmPSK = null;
private long processTimeout;
@ -2399,6 +2401,20 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S
String entityUuid = cmd.getEntityUuid();
if (uploadEntityStateMap.containsKey(entityUuid)) {
UploadEntity uploadEntity = uploadEntityStateMap.get(entityUuid);
if (Boolean.TRUE.equals(cmd.getAbort())) {
updateStateMapWithError(entityUuid, "Upload Entity aborted");
String errorMsg = uploadEntity.getErrorMessage();
if (errorMsg == null) {
errorMsg = "Upload aborted by management server";
}
Channel channel = uploadChannelMap.remove(entityUuid);
if (channel != null && channel.isActive()) {
logger.info("Closing upload channel for entity {}", entityUuid);
channel.close();
}
uploadEntityStateMap.remove(entityUuid);
return new UploadStatusAnswer(cmd, UploadStatus.ERROR, errorMsg);
}
if (uploadEntity.getUploadState() == UploadEntity.Status.ERROR) {
uploadEntityStateMap.remove(entityUuid);
return new UploadStatusAnswer(cmd, UploadStatus.ERROR, uploadEntity.getErrorMessage());
@ -2417,6 +2433,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S
UploadStatusAnswer answer = new UploadStatusAnswer(cmd, UploadStatus.IN_PROGRESS);
long downloadedSize = FileUtils.sizeOfDirectory(new File(uploadEntity.getInstallPathPrefix()));
int downloadPercent = (int)(100 * downloadedSize / uploadEntity.getContentLength());
answer.setPhysicalSize(downloadedSize);
answer.setDownloadPercent(Math.min(downloadPercent, 100));
return answer;
}
@ -3446,6 +3463,10 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S
public String postUpload(String uuid, String filename, long processTimeout) {
UploadEntity uploadEntity = uploadEntityStateMap.get(uuid);
if (uploadEntity == null) {
logger.warn("Upload entity not found for uuid: {}. Upload may have been aborted.", uuid);
return "Upload entity not found. Upload may have been aborted.";
}
int installTimeoutPerGig = 180 * 60 * 1000;
String resourcePath = uploadEntity.getInstallPathPrefix();
@ -3596,6 +3617,16 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S
return _ssvmPSK;
}
public void registerUploadChannel(String uuid, Channel channel) {
uploadChannelMap.put(uuid, channel);
}
public void deregisterUploadChannel(String uuid) {
if (uuid != null) {
uploadChannelMap.remove(uuid);
}
}
public void updateStateMapWithError(String uuid, String errorMessage) {
UploadEntity uploadEntity = null;
if (uploadEntityStateMap.get(uuid) != null) {

View File

@ -999,7 +999,7 @@ public class DownloadManagerImpl extends ManagerBase implements DownloadManager
break; // TODO
}
return new DownloadAnswer(jobId, getDownloadPct(jobId), getDownloadError(jobId), getDownloadStatus2(jobId), getDownloadLocalPath(jobId), getInstallPath(jobId),
getDownloadTemplateSize(jobId), getDownloadTemplatePhysicalSize(jobId), getDownloadCheckSum(jobId));
getDownloadTemplateSize(jobId), td.getDownloadedBytes(), getDownloadCheckSum(jobId));
}
private String getInstallPath(String jobId) {

View File

@ -2104,6 +2104,7 @@
"label.requireshvm": "HVM",
"label.requiresupgrade": "Requires upgrade",
"label.reserved": "Reserved",
"label.reservedresourcedetails": "Reserved resource details",
"label.reserved.system.gateway": "Reserved system gateway",
"label.reserved.system.ip": "Reserved system IP",
"label.reserved.system.netmask": "Reserved system netmask",

View File

@ -44,7 +44,7 @@ export default {
}, 'created']
return fields
},
details: ['name', 'description', 'id', 'type', 'details', 'path', 'pathready', 'isuserdefined', 'orchestratorrequirespreparevm', 'created'],
details: ['name', 'description', 'id', 'type', 'details', 'path', 'pathready', 'isuserdefined', 'orchestratorrequirespreparevm', 'reservedresourcedetails', 'created'],
filters: ['orchestrator'],
tabs: [{
name: 'details',

View File

@ -89,6 +89,14 @@
<details-input
v-model:value="form.details" />
</a-form-item>
<a-form-item name="reservedresourcedetails" ref="reservedresourcedetails">
<template #label>
<tooltip-label :title="$t('label.reservedresourcedetails')" :tooltip="apiParams.reservedresourcedetails.description"/>
</template>
<a-input
v-model:value="form.reservedresourcedetails"
:placeholder="apiParams.reservedresourcedetails.description" />
</a-form-item>
<a-form-item name="state" ref="state">
<template #label>
<tooltip-label :title="$t('label.enabled')" :tooltip="apiParams.state.description"/>
@ -201,6 +209,9 @@ export default {
params['details[0].' + key] = value
})
}
if (values.reservedresourcedetails) {
params.reservedresourcedetails = values.reservedresourcedetails
}
postAPI('createExtension', params).then(response => {
this.$emit('refresh-data')
this.$notification.success({

View File

@ -46,6 +46,14 @@
<details-input
v-model:value="form.details" />
</a-form-item>
<a-form-item name="reservedresourcedetails" ref="reservedresourcedetails">
<template #label>
<tooltip-label :title="$t('label.reservedresourcedetails')" :tooltip="apiParams.reservedresourcedetails.description"/>
</template>
<a-input
v-model:value="form.reservedresourcedetails"
:placeholder="apiParams.reservedresourcedetails.description" />
</a-form-item>
<div :span="24" class="action-button">
<a-button @click="closeAction">{{ $t('label.cancel') }}</a-button>
<a-button :loading="loading" ref="submit" type="primary" @click="handleSubmit">{{ $t('label.ok') }}</a-button>
@ -90,13 +98,16 @@ export default {
this.form = reactive({
description: this.resource.description,
details: this.resource.details,
orchestratorrequirespreparevm: this.resource.orchestratorrequirespreparevm
orchestratorrequirespreparevm: this.resource.orchestratorrequirespreparevm,
reservedresourcedetails: this.resource.reservedresourcedetails
})
},
fetchData () {
this.loading = true
getAPI('listExtensions', { id: this.resource.id }).then(json => {
this.form.details = json?.listextensionsresponse?.extension?.[0]?.details
const ext = json?.listextensionsresponse?.extension?.[0] || {}
this.form.details = ext.details
this.form.reservedresourcedetails = ext.reservedresourcedetails
}).finally(() => {
this.loading = false
})
@ -110,7 +121,7 @@ export default {
const params = {
id: this.resource.id
}
const keys = ['description', 'orchestratorrequirespreparevm']
const keys = ['description', 'orchestratorrequirespreparevm', 'reservedresourcedetails']
for (const key of keys) {
if (values[key] !== undefined || values[key] !== null) {
params[key] = values[key]