mirror of https://github.com/apache/cloudstack.git
Implement/fix limit validation for secondary storage
This commit is contained in:
parent
86c9f7bd94
commit
e8d57d1b0d
|
|
@ -106,7 +106,6 @@ public class BareMetalTemplateAdapter extends TemplateAdapterBase implements Tem
|
|||
}
|
||||
}
|
||||
|
||||
_resourceLimitMgr.incrementResourceCount(profile.getAccountId(), ResourceType.template);
|
||||
return template;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ 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;
|
||||
|
|
@ -543,6 +544,22 @@ 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);
|
||||
//publish usage event
|
||||
String etype = EventTypes.EVENT_TEMPLATE_CREATE;
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ import java.util.stream.Collectors;
|
|||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.cloud.resourcelimit.ReservationHelper;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.InternalIdentity;
|
||||
|
|
@ -111,6 +110,7 @@ import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao;
|
|||
import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreVO;
|
||||
import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity;
|
||||
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
||||
import org.apache.cloudstack.utils.bytescale.ByteScaleUtils;
|
||||
import org.apache.cloudstack.utils.identity.ManagementServerNode;
|
||||
import org.apache.cloudstack.utils.imagestore.ImageStoreUtil;
|
||||
import org.apache.cloudstack.utils.jsinterpreter.TagAsRuleHelper;
|
||||
|
|
@ -169,6 +169,7 @@ 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;
|
||||
|
|
@ -356,10 +357,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||
private ManagementService managementService;
|
||||
@Inject
|
||||
protected SnapshotHelper snapshotHelper;
|
||||
|
||||
@Inject
|
||||
protected DomainDao domainDao;
|
||||
|
||||
@Inject
|
||||
protected ProjectManager projectManager;
|
||||
@Inject
|
||||
|
|
@ -374,7 +373,6 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||
EndPointSelector _epSelector;
|
||||
@Inject
|
||||
private ReservationDao reservationDao;
|
||||
|
||||
@Inject
|
||||
private VMSnapshotDetailsDao vmSnapshotDetailsDao;
|
||||
|
||||
|
|
@ -499,76 +497,77 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||
|
||||
List<Reserver> reservations = new ArrayList<>();
|
||||
try {
|
||||
validateVolume(caller, ownerId, zoneId, volumeName, null, format, diskOfferingId, reservations);
|
||||
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());
|
||||
|
||||
// one of the two following might have to be removed
|
||||
command.setDefaultMaxSecondaryStorageInGB(_resourceLimitMgr.findCorrectResourceLimitForAccountAndDomain(account, domain, ResourceType.secondary_storage, null));
|
||||
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);
|
||||
// one of the two following might have to be removed
|
||||
command.setDefaultMaxSecondaryStorageInGB(_resourceLimitMgr.findCorrectResourceLimitForAccountAndDomain(account, domain, ResourceType.secondary_storage, null));
|
||||
command.setDefaultMaxSecondaryStorageInGB(ByteScaleUtils.bytesToGibibytes(_resourceLimitMgr.findCorrectResourceLimitForAccountAndDomain(account, domain, ResourceType.secondary_storage, null)));
|
||||
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);
|
||||
|
|
@ -967,29 +966,29 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||
|
||||
List<Reserver> reservations = new ArrayList<>();
|
||||
try {
|
||||
_resourceLimitMgr.checkVolumeResourceLimit(owner, displayVolume, size, diskOffering, reservations);
|
||||
_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);
|
||||
}
|
||||
// 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));
|
||||
}
|
||||
// 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");
|
||||
}
|
||||
// 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);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
|
@ -1320,134 +1319,134 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||
|
||||
List<Reserver> reservations = new ArrayList<>();
|
||||
try {
|
||||
validateVolumeResizeWithSize(volume, currentSize, newSize, shrinkOk, diskOffering, newDiskOffering, reservations);
|
||||
validateVolumeResizeWithSize(volume, currentSize, newSize, shrinkOk, diskOffering, newDiskOffering, reservations);
|
||||
|
||||
// Note: The storage plug-in in question should perform validation on the IOPS to check if a sufficient number of IOPS is available to perform
|
||||
// the requested change
|
||||
// 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
|
||||
|
||||
/* 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 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.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(cmd.getNewDiskOfferingId());
|
||||
}
|
||||
|
||||
_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);
|
||||
|
|
@ -1912,17 +1911,17 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||
|
||||
List<Reserver> reservations = new ArrayList<>();
|
||||
try {
|
||||
_resourceLimitMgr.checkVolumeResourceLimit(_accountMgr.getAccount(volume.getAccountId()), volume.isDisplayVolume(), volume.getSize(), diskOffering, reservations);
|
||||
_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()));
|
||||
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);
|
||||
|
|
@ -2161,96 +2160,96 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||
|
||||
List<Reserver> reservations = new ArrayList<>();
|
||||
try {
|
||||
validateVolumeResizeWithSize(volume, currentSize, newSize, shrinkOk, existingDiskOffering, newDiskOffering, reservations);
|
||||
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);
|
||||
|
|
@ -2807,7 +2806,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||
// if target VM has associated VM snapshots
|
||||
List<VMSnapshotVO> vmSnapshots = _vmSnapshotDao.findByVm(vmId);
|
||||
if (vmSnapshots.size() > 0) {
|
||||
throw new InvalidParameterValueException(String.format("Unable to attach volume to VM %s/%s, please specify a VM that does not have VM snapshots", vm.getName(), vm.getUuid()));
|
||||
throw new InvalidParameterValueException(String.format("Unable to attach volume to Instance %s/%s, please specify an Instance that does not have Instance Snapshots", vm.getName(), vm.getUuid()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3130,7 +3129,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||
// Don't allow detach if target VM has associated VM snapshots
|
||||
List<VMSnapshotVO> vmSnapshots = _vmSnapshotDao.findByVm(vmId);
|
||||
if (CollectionUtils.isNotEmpty(vmSnapshots)) {
|
||||
throw new InvalidParameterValueException("Unable to detach volume, please specify a VM that does not have VM snapshots");
|
||||
throw new InvalidParameterValueException("Unable to detach volume, please specify an Instance that does not have Instance Snapshots");
|
||||
}
|
||||
|
||||
checkForBackups(vm, false);
|
||||
|
|
@ -3426,7 +3425,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||
// Check that Vm to which this volume is attached does not have VM Snapshots
|
||||
// OfflineVmwareMigration: consider if this is needed and desirable
|
||||
if (vm != null && _vmSnapshotDao.findByVm(vm.getId()).size() > 0) {
|
||||
throw new InvalidParameterValueException("Volume cannot be migrated, please remove all VM snapshots for VM to which this volume is attached");
|
||||
throw new InvalidParameterValueException("Volume cannot be migrated, please remove all Instance Snapshots for Instance to which this volume is attached");
|
||||
}
|
||||
|
||||
StoragePoolVO srcStoragePoolVO = _storagePoolDao.findById(vol.getPoolId());
|
||||
|
|
@ -3435,7 +3434,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||
if (vm != null && State.Running.equals(vm.getState())) {
|
||||
// Check if the VM is GPU enabled.
|
||||
if (_serviceOfferingDetailsDao.findDetail(vm.getServiceOfferingId(), GPU.Keys.pciDevice.toString()) != null) {
|
||||
throw new InvalidParameterValueException("Live Migration of GPU enabled VM is not supported");
|
||||
throw new InvalidParameterValueException("Live Migration of GPU enabled Instance is not supported");
|
||||
}
|
||||
|
||||
// Check if the underlying hypervisor supports storage motion.
|
||||
|
|
|
|||
|
|
@ -34,14 +34,14 @@ 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;
|
||||
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.EndPoint;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.Scope;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService;
|
||||
|
|
@ -57,15 +57,18 @@ import org.apache.cloudstack.storage.command.TemplateOrVolumePostUploadCommand;
|
|||
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
|
||||
import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity;
|
||||
import org.apache.cloudstack.utils.bytescale.ByteScaleUtils;
|
||||
import org.apache.cloudstack.utils.security.DigestHelper;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
||||
import com.cloud.agent.AgentManager;
|
||||
import com.cloud.agent.api.Answer;
|
||||
import com.cloud.alert.AlertManager;
|
||||
import com.cloud.configuration.Config;
|
||||
import com.cloud.configuration.Resource.ResourceType;
|
||||
import com.cloud.dc.DataCenterVO;
|
||||
import com.cloud.dc.dao.DataCenterDao;
|
||||
import com.cloud.domain.Domain;
|
||||
import com.cloud.deployasis.dao.TemplateDeployAsIsDetailsDao;
|
||||
import com.cloud.event.EventTypes;
|
||||
import com.cloud.event.UsageEventUtils;
|
||||
|
|
@ -73,6 +76,7 @@ import com.cloud.exception.InvalidParameterValueException;
|
|||
import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.host.HostVO;
|
||||
import com.cloud.hypervisor.Hypervisor;
|
||||
import com.cloud.org.Grouping;
|
||||
import com.cloud.resource.ResourceManager;
|
||||
import com.cloud.storage.ScopeType;
|
||||
import com.cloud.storage.Storage.ImageFormat;
|
||||
|
|
@ -197,19 +201,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 +219,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 +247,6 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase {
|
|||
persistDirectDownloadTemplate(template.getId(), profile.getSize());
|
||||
}
|
||||
|
||||
_resourceLimitMgr.incrementResourceCount(profile.getAccountId(), ResourceType.template);
|
||||
return template;
|
||||
}
|
||||
|
||||
|
|
@ -322,6 +300,44 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase {
|
|||
}
|
||||
}
|
||||
|
||||
protected boolean isZoneAndImageStoreAvailable(DataStore imageStore, Long zoneId, Set<Long> zoneSet, boolean isTemplatePrivate) {
|
||||
if (zoneId == null) {
|
||||
logger.warn(String.format("Zone ID is null, cannot allocate ISO/template in image store [%s].", imageStore));
|
||||
return false;
|
||||
}
|
||||
|
||||
DataCenterVO zone = _dcDao.findById(zoneId);
|
||||
if (zone == null) {
|
||||
logger.warn("Unable to find zone by id [{}], so skip downloading template to its image store [{}].", zoneId, imageStore);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Grouping.AllocationState.Disabled == zone.getAllocationState()) {
|
||||
logger.info("Zone [{}] is disabled. Skip downloading template to its image store [{}].", zone, imageStore);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_statsCollector.imageStoreHasEnoughCapacity(imageStore)) {
|
||||
logger.info("Image store doesn't have enough capacity. Skip downloading template to this image store [{}].", imageStore);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (zoneSet == null) {
|
||||
logger.info(String.format("Zone set is null; therefore, the ISO/template should be allocated in every secondary storage of zone [%s].", zone));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isTemplatePrivate && zoneSet.contains(zoneId)) {
|
||||
logger.info(String.format("The template is private and it is already allocated in a secondary storage in zone [%s]; therefore, image store [%s] will be skipped.",
|
||||
zone, imageStore));
|
||||
return false;
|
||||
}
|
||||
|
||||
logger.info(String.format("Private template will be allocated in image store [%s] in zone [%s].", imageStore, zone));
|
||||
zoneSet.add(zoneId);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TemplateOrVolumePostUploadCommand> createTemplateForPostUpload(final TemplateProfile profile) {
|
||||
// persist entry in vm_template, vm_template_details and template_zone_ref tables, not that entry at template_store_ref is not created here, and created in createTemplateAsync.
|
||||
|
|
@ -369,12 +385,67 @@ 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;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* If the template/ISO is marked as private, then it is allocated to a random secondary storage; otherwise, allocates to every storage pool in every zone given by the
|
||||
* {@link TemplateProfile#getZoneIdList()}.
|
||||
*/
|
||||
protected void postUploadAllocation(List<DataStore> imageStores, VMTemplateVO template, List<TemplateOrVolumePostUploadCommand> payloads) {
|
||||
Set<Long> zoneSet = new HashSet<>();
|
||||
Collections.shuffle(imageStores);
|
||||
for (DataStore imageStore : imageStores) {
|
||||
Long zoneId_is = imageStore.getScope().getScopeId();
|
||||
|
||||
if (!isZoneAndImageStoreAvailable(imageStore, zoneId_is, zoneSet, isPrivateTemplate(template))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TemplateInfo tmpl = imageFactory.getTemplate(template.getId(), imageStore);
|
||||
|
||||
// persist template_store_ref entry
|
||||
DataObject templateOnStore = imageStore.create(tmpl);
|
||||
|
||||
// update template_store_ref and template state
|
||||
EndPoint ep = _epSelector.select(templateOnStore);
|
||||
if (ep == null) {
|
||||
String errMsg = String.format("There is no secondary storage VM for downloading template to image store %s", imageStore);
|
||||
logger.warn(errMsg);
|
||||
throw new CloudRuntimeException(errMsg);
|
||||
}
|
||||
|
||||
TemplateOrVolumePostUploadCommand payload = new TemplateOrVolumePostUploadCommand(template.getId(), template.getUuid(), tmpl.getInstallPath(), tmpl
|
||||
.getChecksum(), tmpl.getType().toString(), template.getUniqueName(), template.getFormat().toString(), templateOnStore.getDataStore().getUri(),
|
||||
templateOnStore.getDataStore().getRole().toString());
|
||||
//using the existing max template size configuration
|
||||
payload.setMaxUploadSize(_configDao.getValue(Config.MaxTemplateAndIsoSize.key()));
|
||||
|
||||
Long accountId = template.getAccountId();
|
||||
Account account = _accountDao.findById(accountId);
|
||||
Domain domain = _domainDao.findById(account.getDomainId());
|
||||
|
||||
payload.setDefaultMaxSecondaryStorageInGB(ByteScaleUtils.bytesToGibibytes(_resourceLimitMgr.findCorrectResourceLimitForAccountAndDomain(account, domain, ResourceType.secondary_storage, null)));
|
||||
payload.setAccountId(accountId);
|
||||
payload.setRemoteEndPoint(ep.getPublicAddr());
|
||||
payload.setRequiresHvm(template.requiresHvm());
|
||||
payload.setDescription(template.getDisplayText());
|
||||
payloads.add(payload);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isPrivateTemplate(VMTemplateVO template){
|
||||
|
||||
// if public OR featured OR system template
|
||||
if(template.isPublicTemplate() || template.isFeatured() || template.getTemplateType() == TemplateType.SYSTEM)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
private class CreateTemplateContext<T> extends AsyncRpcContext<T> {
|
||||
final TemplateInfo template;
|
||||
|
||||
|
|
|
|||
|
|
@ -293,7 +293,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
|
|||
}
|
||||
GuestOS noneGuestOs = ApiDBUtils.findGuestOSByDisplayName(ApiConstants.ISO_GUEST_OS_NONE);
|
||||
if ((guestOSId == null || guestOSId == noneGuestOs.getId()) && bootable == true) {
|
||||
throw new InvalidParameterValueException("Please pass a valid GuestOS Id");
|
||||
throw new InvalidParameterValueException("Please pass a valid GuestOS ID");
|
||||
}
|
||||
if (bootable == false) {
|
||||
guestOSId = noneGuestOs.getId(); //Guest os id of None.
|
||||
|
|
@ -309,7 +309,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
|
|||
requiresHVM = true;
|
||||
}
|
||||
if (deployAsIs) {
|
||||
logger.info("Setting default guest OS for deploy-as-is template while the template registration is not completed");
|
||||
logger.info("Setting default guest OS for deploy-as-is Template while the Template registration is not completed");
|
||||
guestOSId = getDefaultDeployAsIsGuestOsId();
|
||||
}
|
||||
}
|
||||
|
|
@ -342,7 +342,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
|
|||
// check whether owner can create public templates
|
||||
boolean allowPublicUserTemplates = TemplateManager.AllowPublicUserTemplates.valueIn(templateOwner.getId());
|
||||
if (!isAdmin && !allowPublicUserTemplates && isPublic) {
|
||||
throw new InvalidParameterValueException("Only private templates/ISO can be created.");
|
||||
throw new InvalidParameterValueException("Only private Templates/ISO can be created.");
|
||||
}
|
||||
|
||||
if (!isAdmin || featured == null) {
|
||||
|
|
@ -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) {
|
||||
|
|
@ -386,7 +384,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
|
|||
Objects.equals(template.getArch(), arch)) {
|
||||
logger.error("{} for same arch {} is having same name or description", template,
|
||||
template.getArch());
|
||||
throw new IllegalArgumentException("Cannot use reserved names for templates");
|
||||
throw new IllegalArgumentException("Cannot use reserved names for Templates");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -442,11 +440,11 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
|
|||
if (cmd.isDeployAsIs()) {
|
||||
if (MapUtils.isNotEmpty(details)) {
|
||||
if (details.containsKey(VmDetailConstants.ROOT_DISK_CONTROLLER)) {
|
||||
logger.info("Ignoring the rootDiskController detail provided, as we honour what is defined in the template");
|
||||
logger.info("Ignoring the rootDiskController detail provided, as we honour what is defined in the Template");
|
||||
details.remove(VmDetailConstants.ROOT_DISK_CONTROLLER);
|
||||
}
|
||||
if (details.containsKey(VmDetailConstants.NIC_ADAPTER)) {
|
||||
logger.info("Ignoring the nicAdapter detail provided, as we honour what is defined in the template");
|
||||
logger.info("Ignoring the nicAdapter detail provided, as we honour what is defined in the Template");
|
||||
details.remove(VmDetailConstants.NIC_ADAPTER);
|
||||
}
|
||||
}
|
||||
|
|
@ -512,7 +510,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
|
|||
public TemplateProfile prepare(GetUploadParamsForTemplateCmd cmd) throws ResourceAllocationException {
|
||||
Long osTypeId = cmd.getOsTypeId();
|
||||
if (osTypeId == null) {
|
||||
logger.info("Setting the default guest OS for deploy-as-is templates while the template upload is not completed");
|
||||
logger.info("Setting the default guest OS for deploy-as-is Templates while the Template upload is not completed");
|
||||
osTypeId = getDefaultDeployAsIsGuestOsId();
|
||||
}
|
||||
UploadParams params = new TemplateUploadParams(CallContext.current().getCallingUserId(), cmd.getName(),
|
||||
|
|
@ -574,7 +572,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
|
|||
List<DataCenterVO> dcs = _dcDao.listAll();
|
||||
|
||||
if (dcs.isEmpty()) {
|
||||
throw new CloudRuntimeException("No zones are present in the system, can't add template");
|
||||
throw new CloudRuntimeException("No zones are present in the system, can't add Template");
|
||||
}
|
||||
|
||||
template.setCrossZones(true);
|
||||
|
|
@ -604,7 +602,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
|
|||
Account owner = _accountMgr.getAccount(template.getAccountId());
|
||||
if (owner.getType() == Account.Type.PROJECT) {
|
||||
if (!_projectMgr.canAccessProjectAccount(account, owner.getId())) {
|
||||
throw new PermissionDeniedException(msg + ". Permission denied. The caller can't access project's template");
|
||||
throw new PermissionDeniedException(msg + ". Permission denied. The caller can't access project's Template");
|
||||
}
|
||||
} else {
|
||||
throw new PermissionDeniedException(msg + ". Permission denied.");
|
||||
|
|
@ -638,10 +636,10 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
|
|||
|
||||
VMTemplateVO template = _tmpltDao.findById(templateId);
|
||||
if (template == null) {
|
||||
throw new InvalidParameterValueException("unable to find template with id " + templateId);
|
||||
throw new InvalidParameterValueException("Unable to find Template with ID " + templateId);
|
||||
}
|
||||
|
||||
userId = accountAndUserValidation(account, userId, null, template, "Unable to delete template ");
|
||||
userId = accountAndUserValidation(account, userId, null, template, "Unable to delete Template ");
|
||||
|
||||
UserVO user = _userDao.findById(userId);
|
||||
if (user == null) {
|
||||
|
|
@ -649,11 +647,11 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
|
|||
}
|
||||
|
||||
if (template.getFormat() == ImageFormat.ISO) {
|
||||
throw new InvalidParameterValueException("Please specify a valid template.");
|
||||
throw new InvalidParameterValueException("Please specify a valid Template.");
|
||||
}
|
||||
|
||||
if (template.getState() == VirtualMachineTemplate.State.NotUploaded || template.getState() == VirtualMachineTemplate.State.UploadInProgress) {
|
||||
throw new InvalidParameterValueException("The template is either getting uploaded or it may be initiated shortly, please wait for it to be completed");
|
||||
throw new InvalidParameterValueException("The Template is either getting uploaded or it may be initiated shortly, please wait for it to be completed");
|
||||
}
|
||||
|
||||
return new TemplateProfile(userId, template, zoneId);
|
||||
|
|
@ -667,7 +665,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
|
|||
|
||||
VMTemplateVO template = _tmpltDao.findById(templateId);
|
||||
if (template == null) {
|
||||
throw new InvalidParameterValueException("unable to find template with id " + templateId);
|
||||
throw new InvalidParameterValueException("Unable to find Template with ID " + templateId);
|
||||
}
|
||||
return new TemplateProfile(userId, template, zoneId);
|
||||
}
|
||||
|
|
@ -681,10 +679,10 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
|
|||
|
||||
VMTemplateVO template = _tmpltDao.findById(templateId);
|
||||
if (template == null) {
|
||||
throw new InvalidParameterValueException("unable to find iso with id " + templateId);
|
||||
throw new InvalidParameterValueException("Unable to find ISO with ID " + templateId);
|
||||
}
|
||||
|
||||
userId = accountAndUserValidation(account, userId, null, template, "Unable to delete iso ");
|
||||
userId = accountAndUserValidation(account, userId, null, template, "Unable to delete ISO ");
|
||||
|
||||
UserVO user = _userDao.findById(userId);
|
||||
if (user == null) {
|
||||
|
|
@ -692,11 +690,11 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
|
|||
}
|
||||
|
||||
if (template.getFormat() != ImageFormat.ISO) {
|
||||
throw new InvalidParameterValueException("Please specify a valid iso.");
|
||||
throw new InvalidParameterValueException("Please specify a valid ISO.");
|
||||
}
|
||||
|
||||
if (template.getState() == VirtualMachineTemplate.State.NotUploaded || template.getState() == VirtualMachineTemplate.State.UploadInProgress) {
|
||||
throw new InvalidParameterValueException("The iso is either getting uploaded or it may be initiated shortly, please wait for it to be completed");
|
||||
throw new InvalidParameterValueException("The ISO is either getting uploaded or it may be initiated shortly, please wait for it to be completed");
|
||||
}
|
||||
|
||||
return new TemplateProfile(userId, template, zoneId);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -22,8 +22,8 @@ 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;
|
||||
import com.cloud.event.dao.UsageEventDao;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
|
|
@ -33,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;
|
||||
|
|
@ -63,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;
|
||||
|
|
@ -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;
|
||||
|
||||
@Inject
|
||||
HypervisorGuruManager _hvGuruMgr;
|
||||
|
||||
@Inject
|
||||
AccountManager _accountMgr;
|
||||
@Inject
|
||||
VnfTemplateManager vnfTemplateManager;
|
||||
@Inject
|
||||
SnapshotJoinDao snapshotJoinDao;
|
||||
@Inject
|
||||
@Mock
|
||||
ReservationDao reservationDao;
|
||||
|
||||
@Inject
|
||||
@Mock
|
||||
HypervisorGuruManager _hvGuruMgr;
|
||||
|
||||
@Mock
|
||||
AccountManager _accountMgr;
|
||||
|
||||
@Mock
|
||||
VnfTemplateManager vnfTemplateManager;
|
||||
@Mock
|
||||
SnapshotJoinDao snapshotJoinDao;
|
||||
@Mock
|
||||
TemplateDeployAsIsDetailsDao templateDeployAsIsDetailsDao;
|
||||
|
||||
@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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue