diff --git a/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/manager/BareMetalTemplateAdapter.java b/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/manager/BareMetalTemplateAdapter.java index 940897de3c9..c6c38a39809 100644 --- a/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/manager/BareMetalTemplateAdapter.java +++ b/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/manager/BareMetalTemplateAdapter.java @@ -106,7 +106,6 @@ public class BareMetalTemplateAdapter extends TemplateAdapterBase implements Tem } } - _resourceLimitMgr.incrementResourceCount(profile.getAccountId(), ResourceType.template); return template; } diff --git a/server/src/main/java/com/cloud/storage/ImageStoreUploadMonitorImpl.java b/server/src/main/java/com/cloud/storage/ImageStoreUploadMonitorImpl.java index 06da14e4e1c..5c6f8dc6599 100755 --- a/server/src/main/java/com/cloud/storage/ImageStoreUploadMonitorImpl.java +++ b/server/src/main/java/com/cloud/storage/ImageStoreUploadMonitorImpl.java @@ -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; diff --git a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java index d50b0ebdf7a..5861f7ced43 100644 --- a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java @@ -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 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() { - @Override - public GetUploadParamsResponse doInTransaction(TransactionStatus status) throws MalformedURLException { + return Transaction.execute(new TransactionCallbackWithException() { + @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 pair = volService.registerVolumeForPostUpload(vol, store); - EndPoint ep = pair.first(); - DataObject dataObject = pair.second(); + Pair 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 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 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 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> poolsPair = managementService.listStoragePoolsForSystemMigrationOfVolume(volume.getId(), newDiskOfferingId, currentSize, newMinIops, newMaxIops, true, false); - List 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 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 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> poolsPair = managementService.listStoragePoolsForSystemMigrationOfVolume(volume.getId(), newDiskOfferingId, currentSize, newMinIops, newMaxIops, true, false); + List 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 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 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 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> poolsPair = managementService.listStoragePoolsForSystemMigrationOfVolume(volume.getId(), newDiskOffering.getId(), currentSize, newMinIops, newMaxIops, true, false); - List 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 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> poolsPair = managementService.listStoragePoolsForSystemMigrationOfVolume(volume.getId(), newDiskOffering.getId(), currentSize, newMinIops, newMaxIops, true, false); + List 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 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 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 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. diff --git a/server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java b/server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java index 6084987e29c..2599d64f82f 100644 --- a/server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java +++ b/server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java @@ -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 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 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 imageStores, VMTemplateVO template, List payloads) { + Set 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 extends AsyncRpcContext { final TemplateInfo template; diff --git a/server/src/main/java/com/cloud/template/TemplateAdapterBase.java b/server/src/main/java/com/cloud/template/TemplateAdapterBase.java index a9adfa93236..d650ef98db7 100644 --- a/server/src/main/java/com/cloud/template/TemplateAdapterBase.java +++ b/server/src/main/java/com/cloud/template/TemplateAdapterBase.java @@ -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 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); diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java index 3ff374e273f..38fd9ab205b 100755 --- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java @@ -132,6 +132,7 @@ import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenterVO; import com.cloud.dc.dao.DataCenterDao; import com.cloud.deploy.DeployDestination; +import com.cloud.deployasis.dao.TemplateDeployAsIsDetailsDao; import com.cloud.domain.Domain; import com.cloud.domain.dao.DomainDao; import com.cloud.event.ActionEvent; @@ -306,27 +307,25 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, private HypervisorGuruManager _hvGuruMgr; @Inject ReservationDao reservationDao; - - private List _adapters; - - ExecutorService _preloadExecutor; - @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 _adapters; + + ExecutorService _preloadExecutor; + protected boolean backupSnapshotAfterTakingSnapshot = SnapshotInfo.BackupSnapshotAfterTakingSnapshot.value(); private TemplateAdapter getAdapter(HypervisorType type) { @@ -345,14 +344,14 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, } if (adapter == null) { - throw new CloudRuntimeException("Cannot find template adapter for " + type.toString()); + throw new CloudRuntimeException("Cannot find Template adapter for " + type.toString()); } return adapter; } @Override - @ActionEvent(eventType = EventTypes.EVENT_ISO_CREATE, eventDescription = "creating iso") + @ActionEvent(eventType = EventTypes.EVENT_ISO_CREATE, eventDescription = "Creating ISO") public VirtualMachineTemplate registerIso(RegisterIsoCmd cmd) throws ResourceAllocationException { TemplateAdapter adapter = getAdapter(HypervisorType.None); Account owner = _accountMgr.getAccount(cmd.getEntityOwnerId()); @@ -383,7 +382,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, } @Override - @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template") + @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "Creating Template") public VirtualMachineTemplate registerTemplate(RegisterTemplateCmd cmd) throws URISyntaxException, ResourceAllocationException { Account account = CallContext.current().getCallingAccount(); if (cmd.getTemplateTag() != null) { @@ -408,7 +407,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, TemplateProfile profile = adapter.prepare(cmd); VMTemplateVO template = adapter.create(profile); - // Secondary storage resource usage will be incremented in com.cloud.template.HypervisorTemplateAdapter.createTemplateAsyncCallBack + // Secondary storage resource usage will be recalculated in com.cloud.template.HypervisorTemplateAdapter.createTemplateAsyncCallBack // for HypervisorTemplateAdapter _resourceLimitMgr.incrementResourceCount(profile.getAccountId(), ResourceType.template); if (secondaryStorageUsage > 0) { @@ -422,7 +421,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, } return template; } else { - throw new CloudRuntimeException("Failed to create a template"); + throw new CloudRuntimeException("Failed to create a Template"); } } } @@ -481,24 +480,42 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, return response; } else { - throw new CloudRuntimeException("Unable to register template."); + throw new CloudRuntimeException("Unable to register Template."); } } @Override - @ActionEvent(eventType = EventTypes.EVENT_ISO_CREATE, eventDescription = "creating post upload iso") + @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") + @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 @@ -536,7 +553,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, } @Override - @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_EXTRACT, eventDescription = "extracting template", async = true) + @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_EXTRACT, eventDescription = "Extracting Template", async = true) public String extract(ExtractTemplateCmd cmd) { Account caller = CallContext.current().getCallingAccount(); Long templateId = cmd.getId(); @@ -547,7 +564,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, VirtualMachineTemplate 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); } String extractUrl = extract(caller, templateId, url, zoneId, mode, eventId, false); @@ -560,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); @@ -571,7 +588,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, if (pool.getStatus() == StoragePoolStatus.Up && pool.getDataCenterId() == zoneId) { prepareTemplateInOneStoragePool(vmTemplate, pool); } else { - logger.warn("Skip loading template {} into primary storage {} as " + + logger.warn("Skip loading Template {} into primary storage {} as " + "either the pool zone {} is different from the requested zone {} or " + "the pool is currently not available.", vmTemplate::toString, pool::toString, () -> _dcDao.findById(pool.getDataCenterId()), () -> _dcDao.findById(zoneId)); @@ -607,7 +624,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, } } else { if (template.getFormat() == ImageFormat.ISO) { - throw new InvalidParameterValueException("Unsupported format, could not extract the template"); + throw new InvalidParameterValueException("Unsupported format, could not extract the Template"); } } @@ -616,7 +633,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, } if (!_accountMgr.isRootAdmin(caller.getId()) && !template.isExtractable()) { - throw new InvalidParameterValueException(String.format("Unable to extract template %s as it's not extractable", template)); + throw new InvalidParameterValueException(String.format("Unable to extract Template %s as it's not extractable", template)); } _accountMgr.checkAccess(caller, AccessType.OperateEntry, true, template); @@ -670,7 +687,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, if (MapUtils.isNotEmpty(storageForDisks)) { for (StoragePool storagePool : storageForDisks.values()) { if (poolId != null && storagePool.getId() != poolId) { - throw new CloudRuntimeException("Cannot determine where to download iso"); + throw new CloudRuntimeException("Cannot determine where to download ISO"); } poolId = storagePool.getId(); } @@ -705,10 +722,10 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, } private void prepareTemplateInOneStoragePool(final VMTemplateVO template, final StoragePoolVO pool) { - logger.info("Schedule to preload template {} into primary storage {}", template, pool); + logger.info("Schedule to preload Template {} into primary storage {}", template, pool); if (pool.getPoolType() == Storage.StoragePoolType.DatastoreCluster) { List childDataStores = _poolDao.listChildStoragePoolsInDatastoreCluster(pool.getId()); - logger.debug("Schedule to preload template {} into child datastores of DataStore cluster: {}", template, pool); + logger.debug("Schedule to preload Template {} into child datastores of DataStore cluster: {}", template, pool); for (StoragePoolVO childDataStore : childDataStores) { prepareTemplateInOneStoragePoolInternal(template, childDataStore); } @@ -729,10 +746,10 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, } private void reallyRun() { - logger.info("Start to preload template {} into primary storage {}", template, pool); + logger.info("Start to preload Template {} into primary storage {}", template, pool); StoragePool pol = (StoragePool)_dataStoreMgr.getPrimaryDataStore(pool.getId()); prepareTemplateForCreate(template, pol); - logger.info("End of preloading template {} into primary storage {}", template, pool); + logger.info("End of preloading Template {} into primary storage {}", template, pool); } }); } @@ -743,7 +760,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, if (pool.getDataCenterId() == zoneId) { prepareTemplateInOneStoragePool(template, pool); } else { - logger.info("Skip loading template {} into primary storage {} as pool " + + logger.info("Skip loading Template {} into primary storage {} as pool " + "zone {} is different from the requested zone {}", template::toString, pool::toString, () -> _dcDao.findById(pool.getDataCenterId()), () -> _dcDao.findById(zoneId)); } @@ -776,7 +793,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, templateStoreRef = _tmplStoreDao.findByTemplateZoneDownloadStatus(templateId, pool.getDataCenterId(), VMTemplateStorageResourceAssoc.Status.DOWNLOADED); if (templateStoreRef == null) { - logger.error("Unable to find a secondary storage host who has completely downloaded the template."); + logger.error("Unable to find a secondary storage host who has completely downloaded the Template."); return null; } @@ -787,7 +804,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, if (templateStoragePoolRef == null) { if (logger.isDebugEnabled()) { - logger.debug("Downloading template {} to pool {}", template, pool); + logger.debug("Downloading Template {} to pool {}", template, pool); } DataStore srcSecStore = _dataStoreMgr.getDataStore(templateStoreRef.getDataStoreId(), DataStoreRole.Image); TemplateInfo srcTemplate = _tmplFactory.getTemplate(templateId, srcSecStore); @@ -796,13 +813,13 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, try { TemplateApiResult result = future.get(); if (result.isFailed()) { - logger.debug("prepare template failed:" + result.getResult()); + logger.debug("Prepare Template failed:" + result.getResult()); return null; } return _tmpltPoolDao.findByPoolTemplate(poolId, templateId, null); } catch (Exception ex) { - logger.debug("failed to copy template from image store {} to primary storage", srcSecStore); + logger.debug("Failed to copy Template from image store {} to primary storage", srcSecStore); } } @@ -865,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)) { @@ -893,7 +907,8 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, try { TemplateApiResult result = future.get(); if (result.isFailed()) { - logger.debug("copy template failed for image store {}: {}", dstSecStore, result.getResult()); + logger.debug("Copy Template failed for image store {}: {}", dstSecStore, result.getResult()); + _tmplStoreDao.removeByTemplateStore(tmpltId, dstSecStore.getId()); continue; // try next image store } @@ -908,32 +923,31 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, List dataDiskTemplates = _tmpltDao.listByParentTemplatetId(template.getId()); if (dataDiskTemplates != null && !dataDiskTemplates.isEmpty()) { for (VMTemplateVO dataDiskTemplate : dataDiskTemplates) { - logger.debug("Copying {} for source template {}. Copy all Datadisk templates to destination datastore {}", dataDiskTemplates.size(), template, dstSecStore); + logger.debug("Copying {} for source Template {}. Copy all Datadisk Templates to destination datastore {}", dataDiskTemplates.size(), template, dstSecStore); TemplateInfo srcDataDiskTemplate = _tmplFactory.getTemplate(dataDiskTemplate.getId(), srcSecStore); AsyncCallFuture dataDiskCopyFuture = _tmpltSvr.copyTemplate(srcDataDiskTemplate, dstSecStore); try { TemplateApiResult dataDiskCopyResult = dataDiskCopyFuture.get(); if (dataDiskCopyResult.isFailed()) { - logger.error("Copy of datadisk template: {} to image store: {} failed with error: {} , will try copying the next one", srcDataDiskTemplate, dstSecStore, dataDiskCopyResult.getResult()); + logger.error("Copy of datadisk Template: {} to image store: {} failed with error: {} , will try copying the next one", srcDataDiskTemplate, dstSecStore, dataDiskCopyResult.getResult()); continue; // Continue to copy next Datadisk template } _tmpltDao.addTemplateToZone(dataDiskTemplate, dstZoneId); _resourceLimitMgr.incrementResourceCount(dataDiskTemplate.getAccountId(), ResourceType.secondary_storage, dataDiskTemplate.getSize()); } catch (Exception ex) { - logger.error("Failed to copy datadisk template: {} to image store: {} , will try copying the next one", srcDataDiskTemplate, dstSecStore); + logger.error("Failed to copy datadisk Template: {} to image store: {} , will try copying the next one", srcDataDiskTemplate, dstSecStore); } } } } catch (Exception ex) { - logger.debug("failed to copy template to image store:{} ,will try next one", dstSecStore); + logger.debug("Failed to copy Template to image store:{} ,will try next one", dstSecStore, ex); } } return true; - } @Override - @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_COPY, eventDescription = "copying template", async = true) + @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_COPY, eventDescription = "Copying Template", async = true) public VirtualMachineTemplate copyTemplate(CopyTemplateCmd cmd) throws StorageUnavailableException, ResourceAllocationException { Long templateId = cmd.getId(); Long userId = CallContext.current().getCallingUserId(); @@ -944,12 +958,12 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, // Verify parameters VMTemplateVO template = _tmpltDao.findById(templateId); if (template == null || template.getRemoved() != null) { - throw new InvalidParameterValueException("Unable to find template with id"); + throw new InvalidParameterValueException("Unable to find Template with id"); } // Verify template is not Datadisk template if (template.getTemplateType().equals(TemplateType.DATADISK)) { - throw new InvalidParameterValueException(String.format("Template %s is of type Datadisk. Cannot copy Datadisk templates.", template)); + throw new InvalidParameterValueException(String.format("Template %s is of type Datadisk. Cannot copy Datadisk Templates.", template)); } if (sourceZoneId != null) { @@ -999,40 +1013,40 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, } if (srcSecStore == null) { - throw new InvalidParameterValueException(String.format("There is no template %s ready on image store.", template)); + throw new InvalidParameterValueException(String.format("There is no Template %s ready on image store.", template)); } if (template.isCrossZones()) { // 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)); + 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()); } } } if ((destZoneIds != null) && (destZoneIds.size() > failedZones.size())){ if (!failedZones.isEmpty()) { - logger.debug("There were failures when copying template to zones: " + + logger.debug("There were failures when copying Template to zones: " + StringUtils.listToCsvTags(failedZones)); } return template; } else { - throw new CloudRuntimeException("Failed to copy template"); + throw new CloudRuntimeException("Failed to copy Template"); } } @@ -1043,14 +1057,11 @@ 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; } catch (Exception ex) { - logger.debug("failed to copy template from Zone: {} to Zone: {}", sourceZone, dstZone); + logger.debug("Failed to copy Template from Zone: {} to Zone: {}", sourceZone, dstZone); } return false; } @@ -1059,7 +1070,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, public boolean delete(long userId, long templateId, Long zoneId) { VMTemplateVO template = _tmpltDao.findById(templateId); if (template == null || template.getRemoved() != null) { - throw new InvalidParameterValueException("Please specify a valid template."); + throw new InvalidParameterValueException("Please specify a valid Template."); } TemplateAdapter adapter = getAdapter(template.getHypervisorType()); @@ -1121,7 +1132,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, VMTemplateStoragePoolVO templatePoolRef = _tmpltPoolDao.acquireInLockTable(templatePoolVO.getId()); if (templatePoolRef == null) { - logger.debug("Can't acquire the lock for template pool ref: {}", templatePoolVO); + logger.debug("Can't acquire the lock for Template pool ref: {}", templatePoolVO); return; } @@ -1140,11 +1151,11 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, TemplateApiResult result = future.get(); if (result.isFailed()) { - logger.debug("Failed to delete template {} from storage pool {}", template, pool); + logger.debug("Failed to delete Template {} from storage pool {}", template, pool); } else { // Remove the templatePoolVO. if (_tmpltPoolDao.remove(templatePoolVO.getId())) { - logger.debug("Successfully evicted template {} from storage pool {}", template, pool); + logger.debug("Successfully evicted Template {} from storage pool {}", template, pool); } } } else { @@ -1154,14 +1165,14 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, if (answer != null && answer.getResult()) { // Remove the templatePoolVO. if (_tmpltPoolDao.remove(templatePoolVO.getId())) { - logger.debug("Successfully evicted template {} from storage pool {}", template, pool); + logger.debug("Successfully evicted Template {} from storage pool {}", template, pool); } } else { - logger.info("Will retry evict template {} from storage pool {}", template, pool); + logger.info("Will retry evict Template {} from storage pool {}", template, pool); } } } catch (StorageUnavailableException | InterruptedException | ExecutionException e) { - logger.info("Storage is unavailable currently. Will retry evicte template {} from storage pool {}", template, pool); + logger.info("Storage is unavailable currently. Will retry evicte Template {} from storage pool {}", template, pool); } finally { _tmpltPoolDao.releaseFromLockTable(templatePoolRef.getId()); } @@ -1196,7 +1207,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, // always be copied to // primary storage before deploying VM. if (!userVmUsingIso.isEmpty()) { - logger.debug("ISO " + templateId + " is not deleteable because it is attached to " + userVmUsingIso.size() + " VMs"); + logger.debug("ISO " + templateId + " is not deleteable because it is attached to " + userVmUsingIso.size() + " Instances"); return false; } @@ -1222,7 +1233,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, Long isoId = !isVirtualRouter ? ((UserVm) virtualMachine).getIsoId() : isoParamId; if (isoId == null) { - throw new InvalidParameterValueException("The specified VM has no ISO attached to it."); + throw new InvalidParameterValueException("The specified instance has no ISO attached to it."); } CallContext.current().setEventDetails("Vm Id: " + virtualMachine.getUuid() + " ISO Id: " + isoId); @@ -1236,7 +1247,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, if (result) { return result; } else { - throw new CloudRuntimeException("Failed to detach iso"); + throw new CloudRuntimeException("Failed to detach ISO"); } } @@ -1308,7 +1319,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, if (result) { return result; } else { - throw new CloudRuntimeException("Failed to attach iso"); + throw new CloudRuntimeException("Failed to attach ISO"); } } @@ -1334,7 +1345,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, Scope destScope = new ZoneScope(dcId); TemplateInfo cacheData = (TemplateInfo)cacheMgr.createCacheObject(tmplt, destScope); if (cacheData == null) { - logger.error("Failed in copy iso from S3 to cache storage"); + logger.error("Failed in copy ISO from S3 to cache storage"); return null; } return cacheData; @@ -1402,14 +1413,14 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, } @Override - @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_DELETE, eventDescription = "deleting template", async = true) + @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_DELETE, eventDescription = "Deleting Template", async = true) public boolean deleteTemplate(DeleteTemplateCmd cmd) { Long templateId = cmd.getId(); Account caller = CallContext.current().getCallingAccount(); 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); } List vmInstanceVOList; @@ -1420,7 +1431,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, vmInstanceVOList = _vmInstanceDao.listNonExpungedByTemplate(templateId); } if(!cmd.isForced() && CollectionUtils.isNotEmpty(vmInstanceVOList)) { - final String message = String.format("Unable to delete template: %s because VM instances: [%s] are using it.", template, Joiner.on(",").join(vmInstanceVOList)); + final String message = String.format("Unable to delete Template: %s because Instance: [%s] are using it.", template, Joiner.on(",").join(vmInstanceVOList)); logger.warn(message); throw new InvalidParameterValueException(message); } @@ -1428,7 +1439,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, _accountMgr.checkAccess(caller, AccessType.OperateEntry, true, template); if (template.getFormat() == ImageFormat.ISO) { - throw new InvalidParameterValueException("Please specify a valid template."); + throw new InvalidParameterValueException("Please specify a valid Template."); } VnfTemplateUtils.validateApiCommandParams(cmd, template); @@ -1439,7 +1450,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, } @Override - @ActionEvent(eventType = EventTypes.EVENT_ISO_DELETE, eventDescription = "deleting iso", async = true) + @ActionEvent(eventType = EventTypes.EVENT_ISO_DELETE, eventDescription = "Deleting ISO", async = true) public boolean deleteIso(DeleteIsoCmd cmd) { Long templateId = cmd.getId(); Account caller = CallContext.current().getCallingAccount(); @@ -1447,18 +1458,18 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, 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); } _accountMgr.checkAccess(caller, AccessType.OperateEntry, true, template); if (template.getFormat() != ImageFormat.ISO) { - throw new InvalidParameterValueException("Please specify a valid iso."); + throw new InvalidParameterValueException("Please specify a valid ISO."); } // check if there is any VM using this ISO. if (!templateIsDeleteable(templateId)) { - throw new InvalidParameterValueException("Unable to delete iso, as it's used by other vms"); + throw new InvalidParameterValueException("Unable to delete ISO, as it's used by other instances"); } if (zoneId != null && (_dataStoreMgr.getImageStoreWithFreeCapacity(zoneId) == null)) { @@ -1491,11 +1502,11 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, if (cmd instanceof ListTemplatePermissionsCmd) { if (template.getFormat().equals(ImageFormat.ISO)) { - throw new InvalidParameterValueException("Please provide a valid template"); + throw new InvalidParameterValueException("Please provide a valid Template"); } } else if (cmd instanceof ListIsoPermissionsCmd) { if (!template.getFormat().equals(ImageFormat.ISO)) { - throw new InvalidParameterValueException("Please provide a valid iso"); + throw new InvalidParameterValueException("Please provide a valid ISO"); } } @@ -1545,13 +1556,13 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, if (cmd instanceof UpdateTemplatePermissionsCmd) { mediaType = "template"; if (template.getFormat().equals(ImageFormat.ISO)) { - throw new InvalidParameterValueException("Please provide a valid template"); + throw new InvalidParameterValueException("Please provide a valid Template"); } } if (cmd instanceof UpdateIsoPermissionsCmd) { mediaType = "iso"; if (!template.getFormat().equals(ImageFormat.ISO)) { - throw new InvalidParameterValueException("Please provide a valid iso"); + throw new InvalidParameterValueException("Please provide a valid ISO"); } } @@ -1593,7 +1604,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, // if there is no owner of the template then it's probably already a // public template (or domain private template) so // publishing to individual users is irrelevant - throw new InvalidParameterValueException("Update template permissions is an invalid operation on template " + template.getName()); + throw new InvalidParameterValueException("Update Template permissions is an invalid operation on Template " + template.getName()); } if (owner.getType() == Account.Type.PROJECT) { @@ -1612,14 +1623,14 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, if (accountNames != null) { if ((operation == null) || (!operation.equalsIgnoreCase("add") && !operation.equalsIgnoreCase("remove") && !operation.equalsIgnoreCase("reset"))) { throw new InvalidParameterValueException( - "Invalid operation on accounts, the operation must be either 'add' or 'remove' in order to modify launch permissions." + " Given operation is: '" + + "Invalid operation on Accounts, the operation must be either 'add' or 'remove' in order to modify launch permissions." + " Given operation is: '" + operation + "'"); } } //Only admin or owner of the template should be able to change its permissions if (caller.getId() != ownerId && !isAdmin) { - throw new InvalidParameterValueException("Unable to grant permission to account " + caller.getAccountName() + " as it is neither admin nor owner or the template"); + throw new InvalidParameterValueException("Unable to grant permission to Account " + caller.getAccountName() + " as it is neither admin nor owner or the Template"); } VMTemplateVO updatedTemplate = _tmpltDao.createForUpdate(); @@ -1635,7 +1646,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, if (isExtractable != null) { // Only Root admins and owners are allowed to change it for templates if (!template.getFormat().equals(ImageFormat.ISO) && caller.getId() != ownerId && !isAdmin) { - throw new InvalidParameterValueException("Only ROOT admins and template owners are allowed to modify isExtractable attribute."); + throw new InvalidParameterValueException("Only ROOT admins and Template owners are allowed to modify isExtractable attribute."); } else { // For Isos normal user can change it, as their are no derivatives. updatedTemplate.setExtractable(isExtractable.booleanValue()); @@ -1646,7 +1657,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, //when operation is add/remove, accountNames can not be null if (("add".equalsIgnoreCase(operation) || "remove".equalsIgnoreCase(operation)) && accountNames == null) { - throw new InvalidParameterValueException("Operation " + operation + " requires accounts or projectIds to be passed in"); + throw new InvalidParameterValueException("Operation " + operation + " requires Accounts or projectIds to be passed in"); } //Derive the domain id from the template owner as updateTemplatePermissions is not cross domain operation @@ -1671,8 +1682,8 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, _launchPermissionDao.persist(launchPermission); } } else { - throw new InvalidParameterValueException("Unable to grant a launch permission to account " + accountName + " in domain id=" + - domain.getUuid() + ", account not found. " + "No permissions updated, please verify the account names and retry."); + throw new InvalidParameterValueException("Unable to grant a launch permission to Account " + accountName + " in domain id=" + + domain.getUuid() + ", Account not found. " + "No permissions updated, please verify the Account names and retry."); } } } @@ -1716,7 +1727,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, @Override @DB - @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template", async = true) + @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "Creating Template", async = true) public VirtualMachineTemplate createPrivateTemplate(CreateTemplateCmd command) throws CloudRuntimeException { final long templateId = command.getEntityId(); Long volumeId = command.getVolumeId(); @@ -1809,8 +1820,8 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, if (result.isFailed()) { privateTemplate = null; - logger.debug("Failed to create template" + result.getResult()); - throw new CloudRuntimeException("Failed to create template" + result.getResult()); + logger.debug("Failed to create Template" + result.getResult()); + throw new CloudRuntimeException("Failed to create Template" + result.getResult()); } // create entries in template_zone_ref table @@ -1829,11 +1840,11 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, privateTemplate.getSourceTemplateId(), srcTmpltStore.getPhysicalSize(), privateTemplate.getSize()); _usageEventDao.persist(usageEvent); } catch (InterruptedException e) { - logger.debug("Failed to create template", e); - throw new CloudRuntimeException("Failed to create template", e); + logger.debug("Failed to create Template", e); + throw new CloudRuntimeException("Failed to create Template", e); } catch (ExecutionException e) { - logger.debug("Failed to create template", e); - throw new CloudRuntimeException("Failed to create template", e); + logger.debug("Failed to create Template", e); + throw new CloudRuntimeException("Failed to create Template", e); } } finally { @@ -1857,7 +1868,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())); } } @@ -1873,12 +1884,12 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, if (privateTemplate != null) { return privateTemplate; } else { - throw new CloudRuntimeException("Failed to create a template"); + throw new CloudRuntimeException("Failed to create a Template"); } } @Override - @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template", create = true) + @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "Creating Template", create = true) public VMTemplateVO createPrivateTemplateRecord(CreateTemplateCmd cmd, Account templateOwner) throws ResourceAllocationException { Account caller = CallContext.current().getCallingAccount(); boolean isAdmin = (_accountMgr.isAdmin(caller.getId())); @@ -1916,7 +1927,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, boolean allowPublicUserTemplates = AllowPublicUserTemplates.valueIn(templateOwner.getId()); final Long zoneId = cmd.getZoneId(); if (!isAdmin && !allowPublicUserTemplates && isPublic) { - throw new PermissionDeniedException("Failed to create template " + name + ", only private templates can be created."); + throw new PermissionDeniedException("Failed to create Template " + name + ", only private Templates can be created."); } Long volumeId = cmd.getVolumeId(); @@ -1925,11 +1936,11 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, throw new InvalidParameterValueException("Failed to create private template record, zone ID can only be specified together with snapshot ID."); } if ((volumeId == null) && (snapshotId == null)) { - throw new InvalidParameterValueException("Failed to create private template record, neither volume ID nor snapshot ID were specified."); + throw new InvalidParameterValueException("Failed to create private Template record, neither volume ID nor Snapshot ID were specified."); } if ((volumeId != null) && (snapshotId != null)) { - throw new InvalidParameterValueException("Failed to create private template record, please specify only one of volume ID (" + volumeId + - ") and snapshot ID (" + snapshotId + ")"); + throw new InvalidParameterValueException("Failed to create private Template record, please specify only one of volume ID (" + volumeId + + ") and Snapshot ID (" + snapshotId + ")"); } CPU.CPUArch arch = cmd.getArch(); @@ -1940,21 +1951,21 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, if (volumeId != null) { // create template from volume volume = _volumeDao.findById(volumeId); if (volume == null) { - throw new InvalidParameterValueException("Failed to create private template record, unable to find volume " + volumeId); + throw new InvalidParameterValueException("Failed to create private Template record, unable to find volume " + volumeId); } // check permissions _accountMgr.checkAccess(caller, null, true, volume); // Don't support creating templates from encrypted volumes (yet) if (volume.getPassphraseId() != null) { - throw new UnsupportedOperationException("Cannot create templates from encrypted volumes"); + throw new UnsupportedOperationException("Cannot create Templates from encrypted volumes"); } // If private template is created from Volume, check that the volume // will not be active when the private template is // created if (!_volumeMgr.volumeInactive(volume)) { - String msg = String.format("Unable to create private template for volume: %s; volume is attached to a non-stopped VM, please stop the VM first", volume); + String msg = String.format("Unable to create private Template for volume: %s; volume is attached to a non-stopped Instance, please stop the Instance first", volume); if (logger.isInfoEnabled()) { logger.info(msg); } @@ -1968,21 +1979,21 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, } else { // create template from snapshot snapshot = _snapshotDao.findById(snapshotId); if (snapshot == null) { - throw new InvalidParameterValueException("Failed to create private template record, unable to find snapshot " + snapshotId); + throw new InvalidParameterValueException("Failed to create private Template record, unable to find Snapshot " + snapshotId); } // Volume could be removed so find including removed to record source template id. volume = _volumeDao.findByIdIncludingRemoved(snapshot.getVolumeId()); // Don't support creating templates from encrypted volumes (yet) if (volume != null && volume.getPassphraseId() != null) { - throw new UnsupportedOperationException("Cannot create templates from snapshots of encrypted volumes"); + throw new UnsupportedOperationException("Cannot create Templates from Snapshots of encrypted volumes"); } // check permissions _accountMgr.checkAccess(caller, null, true, snapshot); if (snapshot.getState() != Snapshot.State.BackedUp) { - throw new InvalidParameterValueException(String.format("Snapshot %s is not in %s state yet and can't be used for template creation", + throw new InvalidParameterValueException(String.format("Snapshot %s is not in %s state yet and can't be used for Template creation", snapshot, Snapshot.State.BackedUp)); } @@ -2008,107 +2019,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 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 details = new HashMap(); + 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 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 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 details = new HashMap(); + + 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 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 @@ -2196,13 +2206,13 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, } @Override - @ActionEvent(eventType = EventTypes.EVENT_ISO_UPDATE, eventDescription = "updating iso", async = false) + @ActionEvent(eventType = EventTypes.EVENT_ISO_UPDATE, eventDescription = "Updating ISO", async = false) public VMTemplateVO updateTemplate(UpdateIsoCmd cmd) { return updateTemplateOrIso(cmd); } @Override - @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_UPDATE, eventDescription = "updating template", async = false) + @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_UPDATE, eventDescription = "Updating Template", async = false) public VMTemplateVO updateTemplate(UpdateTemplateCmd cmd) { return updateTemplateOrIso(cmd); } @@ -2229,7 +2239,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, // verify that template exists VMTemplateVO template = _tmpltDao.findById(id); if (template == null || template.getRemoved() != null) { - InvalidParameterValueException ex = new InvalidParameterValueException("unable to find template/iso with specified id"); + InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find Template/ISO with specified id"); ex.addProxyObject(String.valueOf(id), "templateId"); throw ex; } @@ -2275,7 +2285,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; @@ -2434,9 +2444,9 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, validateExternalHypervisorTemplateType(hypervisorType, templateType); if (templateType != null && !isAdmin && !Arrays.asList(TemplateType.USER, TemplateType.VNF).contains(templateType)) { if (cmd instanceof RegisterTemplateCmd) { - throw new InvalidParameterValueException(String.format("Users can not register template with template type %s.", templateType)); + throw new InvalidParameterValueException(String.format("Users can not register Template with template type %s.", templateType)); } else if (cmd instanceof UpdateTemplateCmd) { - throw new InvalidParameterValueException(String.format("Users can not update template to template type %s.", templateType)); + throw new InvalidParameterValueException(String.format("Users can not update Template to template type %s.", templateType)); } } return templateType; @@ -2455,13 +2465,12 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, if (MapUtils.isEmpty(details)) { return; } - String bootMode = details.get(ApiConstants.BootType.UEFI.toString()); if (bootMode == null) { return; } if (template.isDeployAsIs()) { - String msg = String.format("Deploy-as-is template %s can not have the UEFI setting. Settings are read directly from the template", template); + String msg = String.format("Deploy-as-is Template %s can not have the UEFI setting. Settings are read directly from the Template", template); throw new InvalidParameterValueException(msg); } try { @@ -2480,7 +2489,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, void verifyTemplateId(Long id) { // Don't allow to modify system template if (id.equals(Long.valueOf(1))) { - InvalidParameterValueException ex = new InvalidParameterValueException("Unable to update template/iso of specified id"); + InvalidParameterValueException ex = new InvalidParameterValueException("Unable to update Template/ISO of specified ID"); ex.addProxyObject(String.valueOf(id), "templateId"); throw ex; } @@ -2513,7 +2522,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, long templateId = template.getId(); TemplateInfo templateObject = _tmplFactory.getTemplate(templateId, role); if (templateObject == null) { - String msg = String.format("Could not find template %s downloaded on store with role %s", template, role.toString()); + String msg = String.format("Could not find Template %s downloaded on store with role %s", template, role.toString()); logger.error(msg); throw new CloudRuntimeException(msg); } @@ -2529,10 +2538,10 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, Account caller = CallContext.current().getCallingAccount(); if (templateId != null && isoId != null) { - throw new InvalidParameterValueException("Both template ID and ISO ID are passed, API accepts only one"); + throw new InvalidParameterValueException("Both Template ID and ISO ID are passed, API accepts only one"); } if (templateId == null && isoId == null) { - throw new InvalidParameterValueException("Atleast one of template ID or ISO ID needs to be passed"); + throw new InvalidParameterValueException("At least one of Template ID or ISO ID needs to be passed"); } VMTemplateVO template = null; @@ -2542,7 +2551,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, template = _tmpltDao.findById(isoId); } if (template == null) { - throw new InvalidParameterValueException(String.format("unable to find template/ISO with id %s", templateId == null? isoId : templateId)); + throw new InvalidParameterValueException(String.format("Unable to find Template/ISO with ID %s", templateId == null? isoId : templateId)); } _accountMgr.checkAccess(caller, AccessType.OperateEntry, true, template); diff --git a/server/src/test/java/com/cloud/template/TemplateManagerImplTest.java b/server/src/test/java/com/cloud/template/TemplateManagerImplTest.java index 99e4512ccef..f5e281a9516 100755 --- a/server/src/test/java/com/cloud/template/TemplateManagerImplTest.java +++ b/server/src/test/java/com/cloud/template/TemplateManagerImplTest.java @@ -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 adapters = new ArrayList(); 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 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() { + when(vmTemplateDao.persist(any(VMTemplateVO.class))).thenAnswer(new Answer() { @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 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);