diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in index 26cd0474b7c..64a88f75543 100644 --- a/client/tomcatconf/applicationContext.xml.in +++ b/client/tomcatconf/applicationContext.xml.in @@ -709,7 +709,9 @@ - + + + @@ -852,8 +854,7 @@ - - + diff --git a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java index 091bc9286e9..5ba9fafd6e8 100644 --- a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java +++ b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java @@ -43,6 +43,13 @@ import com.cloud.vm.DiskProfile; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; +/** + * VolumeOrchestrationService is a PURE orchestration service on CloudStack + * volumes. It does not understand resource limits, ACL, action events, or + * anything that has to do with the self-service portion of CloudStack. Its + * job is to carry out any orchestration needed among the physical components + * to provision volumes. + */ public interface VolumeOrchestrationService { VolumeInfo moveVolume(VolumeInfo volume, long destPoolDcId, Long destPoolPodId, Long destPoolClusterId, HypervisorType dataDiskHyperType) throws ConcurrentOperationException; diff --git a/engine/orchestration/pom.xml b/engine/orchestration/pom.xml index 49e24a62977..4f8e5d76344 100755 --- a/engine/orchestration/pom.xml +++ b/engine/orchestration/pom.xml @@ -33,6 +33,11 @@ cloud-engine-api ${project.version} + + org.apache.cloudstack + cloud-engine-schema + ${project.version} + org.apache.cloudstack cloud-framework-ipc diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java index 5c0ec66bf84..d82bc79bbce 100644 --- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java @@ -16,10 +16,9 @@ * specific language governing permissions and limitations * under the License. */ -package com.cloud.storage; +package org.apache.cloudstack.engine.orchestration; import java.util.ArrayList; -import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -31,32 +30,11 @@ import java.util.concurrent.ExecutionException; import javax.inject.Inject; import javax.naming.ConfigurationException; -import com.cloud.utils.DateUtil; -import com.cloud.utils.EnumUtils; -import com.cloud.utils.NumbersUtil; -import com.cloud.utils.Pair; -import com.cloud.utils.UriUtils; - import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; -import org.apache.cloudstack.api.BaseCmd; -import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.ExtractVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.UpdateVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd; -import org.apache.cloudstack.context.CallContext; -import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo; +import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager; -import org.apache.cloudstack.engine.subsystem.api.storage.HostScope; -import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo; -import org.apache.cloudstack.engine.subsystem.api.storage.Scope; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator; @@ -68,251 +46,92 @@ import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeApiResult; import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; -import org.apache.cloudstack.framework.jobs.AsyncJob; -import org.apache.cloudstack.framework.jobs.AsyncJobExecutionContext; -import org.apache.cloudstack.framework.jobs.AsyncJobManager; -import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO; -import org.apache.cloudstack.storage.command.AttachAnswer; -import org.apache.cloudstack.storage.command.AttachCommand; import org.apache.cloudstack.storage.command.CommandResult; -import org.apache.cloudstack.storage.command.DettachCommand; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO; -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 com.cloud.agent.AgentManager; -import com.cloud.agent.api.Answer; import com.cloud.agent.api.to.DataTO; import com.cloud.agent.api.to.DiskTO; import com.cloud.agent.api.to.VirtualMachineTO; -import com.cloud.alert.AlertManager; -import com.cloud.api.ApiDBUtils; -import com.cloud.capacity.CapacityManager; -import com.cloud.capacity.dao.CapacityDao; import com.cloud.configuration.Config; -import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.Resource.ResourceType; -import com.cloud.consoleproxy.ConsoleProxyManager; -import com.cloud.dc.ClusterVO; import com.cloud.dc.DataCenter; -import com.cloud.dc.DataCenterVO; -import com.cloud.dc.HostPodVO; import com.cloud.dc.Pod; -import com.cloud.dc.dao.ClusterDao; -import com.cloud.dc.dao.DataCenterDao; -import com.cloud.dc.dao.HostPodDao; +import com.cloud.deploy.DataCenterDeployment; import com.cloud.deploy.DeployDestination; -import com.cloud.domain.Domain; -import com.cloud.domain.dao.DomainDao; -import com.cloud.event.ActionEvent; +import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.event.EventTypes; import com.cloud.event.UsageEventUtils; -import com.cloud.event.dao.EventDao; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientStorageCapacityException; import com.cloud.exception.InvalidParameterValueException; -import com.cloud.exception.PermissionDeniedException; -import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.StorageUnavailableException; import com.cloud.host.Host; -import com.cloud.host.HostVO; -import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.hypervisor.HypervisorCapabilitiesVO; -import com.cloud.hypervisor.HypervisorGuruManager; -import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao; -import com.cloud.network.NetworkModel; -import com.cloud.org.Grouping; +import com.cloud.offering.DiskOffering; +import com.cloud.offering.ServiceOffering; +import com.cloud.org.Cluster; import com.cloud.resource.ResourceManager; -import com.cloud.server.ManagementServer; -import com.cloud.service.ServiceOfferingVO; -import com.cloud.service.dao.ServiceOfferingDao; +import com.cloud.storage.DataStoreRole; +import com.cloud.storage.ScopeType; +import com.cloud.storage.Snapshot; +import com.cloud.storage.Storage; import com.cloud.storage.Storage.ImageFormat; +import com.cloud.storage.StoragePool; +import com.cloud.storage.VMTemplateStorageResourceAssoc; +import com.cloud.storage.Volume; import com.cloud.storage.Volume.Type; -import com.cloud.storage.dao.DiskOfferingDao; -import com.cloud.storage.dao.SnapshotDao; -import com.cloud.storage.dao.SnapshotPolicyDao; -import com.cloud.storage.dao.StoragePoolHostDao; -import com.cloud.storage.dao.StoragePoolWorkDao; -import com.cloud.storage.dao.UploadDao; -import com.cloud.storage.dao.VMTemplateDao; -import com.cloud.storage.dao.VMTemplatePoolDao; +import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.dao.VolumeDetailsDao; -import com.cloud.storage.download.DownloadMonitor; -import com.cloud.storage.secondary.SecondaryStorageVmManager; -import com.cloud.storage.snapshot.SnapshotApiService; -import com.cloud.storage.snapshot.SnapshotManager; -import com.cloud.storage.snapshot.SnapshotScheduler; -import com.cloud.storage.upload.UploadMonitor; -import com.cloud.tags.dao.ResourceTagDao; import com.cloud.template.TemplateManager; +import com.cloud.template.VirtualMachineTemplate; import com.cloud.user.Account; -import com.cloud.user.AccountManager; import com.cloud.user.ResourceLimitService; -import com.cloud.user.VmDiskStatisticsVO; -import com.cloud.user.dao.AccountDao; -import com.cloud.user.dao.UserDao; -import com.cloud.user.dao.VmDiskStatisticsDao; import com.cloud.uservm.UserVm; -import com.cloud.utils.EnumUtils; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; -import com.cloud.utils.UriUtils; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.DB; +import com.cloud.utils.db.EntityManager; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.fsm.NoTransitionException; import com.cloud.utils.fsm.StateMachine2; import com.cloud.vm.DiskProfile; -import com.cloud.vm.UserVmManager; -import com.cloud.vm.UserVmVO; -import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.State; -import com.cloud.vm.VirtualMachineManager; import com.cloud.vm.VirtualMachineProfile; -import com.cloud.vm.dao.ConsoleProxyDao; -import com.cloud.vm.dao.DomainRouterDao; -import com.cloud.vm.dao.SecondaryStorageVmDao; -import com.cloud.vm.dao.UserVmDao; -import com.cloud.vm.dao.VMInstanceDao; -import com.cloud.vm.snapshot.VMSnapshotVO; -import com.cloud.vm.snapshot.dao.VMSnapshotDao; +import com.cloud.vm.VirtualMachineProfileImpl; + +public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrationService { + private static final Logger s_logger = Logger.getLogger(VolumeOrchestrator.class); -@Component -public class VolumeManagerImpl extends ManagerBase implements VolumeManager { - private static final Logger s_logger = Logger - .getLogger(VolumeManagerImpl.class); @Inject - protected UserVmManager _userVmMgr; - @Inject - protected AgentManager _agentMgr; + EntityManager _entityMgr; @Inject protected TemplateManager _tmpltMgr; @Inject - protected AsyncJobManager _asyncMgr; - @Inject - protected SnapshotManager _snapshotMgr; - @Inject - protected SnapshotScheduler _snapshotScheduler; - @Inject - protected AccountManager _accountMgr; - @Inject - protected ConfigurationManager _configMgr; - @Inject - protected ConsoleProxyManager _consoleProxyMgr; - @Inject - protected SecondaryStorageVmManager _secStorageMgr; - @Inject - protected NetworkModel _networkMgr; - @Inject - protected ServiceOfferingDao _serviceOfferingDao; - @Inject protected VolumeDao _volsDao; @Inject - protected HostDao _hostDao; - @Inject - protected ConsoleProxyDao _consoleProxyDao; - @Inject - protected SnapshotDao _snapshotDao; - @Inject - protected SnapshotManager _snapMgr; - @Inject - protected SnapshotPolicyDao _snapshotPolicyDao; - @Inject - protected StoragePoolHostDao _storagePoolHostDao; - @Inject - StoragePoolDetailsDao storagePoolDetailsDao; - @Inject - protected AlertManager _alertMgr; - @Inject - protected TemplateDataStoreDao _vmTemplateStoreDao = null; - @Inject - protected VMTemplatePoolDao _vmTemplatePoolDao = null; - @Inject - protected VMTemplateDao _vmTemplateDao = null; - @Inject - protected StoragePoolHostDao _poolHostDao = null; - @Inject - protected UserVmDao _userVmDao; - @Inject - VolumeDataStoreDao _volumeStoreDao; - @Inject - protected VMInstanceDao _vmInstanceDao; - @Inject protected PrimaryDataStoreDao _storagePoolDao = null; @Inject - protected CapacityDao _capacityDao; - @Inject - protected CapacityManager _capacityMgr; - @Inject - protected DiskOfferingDao _diskOfferingDao; - @Inject - protected AccountDao _accountDao; - @Inject - protected EventDao _eventDao = null; - @Inject - protected DataCenterDao _dcDao = null; - @Inject - protected HostPodDao _podDao = null; - @Inject - protected VMTemplateDao _templateDao; - @Inject - protected ServiceOfferingDao _offeringDao; - @Inject - protected DomainDao _domainDao; - @Inject - protected UserDao _userDao; - @Inject - protected ClusterDao _clusterDao; - @Inject - protected VirtualMachineManager _vmMgr; - @Inject - protected DomainRouterDao _domrDao; - @Inject - protected SecondaryStorageVmDao _secStrgDao; - @Inject - protected StoragePoolWorkDao _storagePoolWorkDao; - @Inject - protected HypervisorGuruManager _hvGuruMgr; + protected TemplateDataStoreDao _vmTemplateStoreDao = null; @Inject protected VolumeDao _volumeDao; @Inject - protected OCFS2Manager _ocfs2Mgr; - @Inject protected ResourceLimitService _resourceLimitMgr; @Inject - protected SecondaryStorageVmManager _ssvmMgr; - @Inject protected ResourceManager _resourceMgr; @Inject - protected DownloadMonitor _downloadMonitor; - @Inject - protected ResourceTagDao _resourceTagDao; - @Inject - protected VmDiskStatisticsDao _vmDiskStatsDao; - @Inject - protected VMSnapshotDao _vmSnapshotDao; - @Inject - protected List _storagePoolAllocators; - @Inject ConfigurationDao _configDao; @Inject VolumeDetailsDao _volDetailDao; @Inject - ManagementServer _msServer; - @Inject DataStoreManager dataStoreMgr; @Inject - DataStoreProviderManager dataStoreProviderMgr; - @Inject VolumeService volService; @Inject VolumeDataFactory volFactory; @@ -320,191 +139,69 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { TemplateDataFactory tmplFactory; @Inject SnapshotDataFactory snapshotFactory; - @Inject - SnapshotApiService snapshotMgr; - @Inject - UploadMonitor _uploadMonitor; - @Inject - UploadDao _uploadDao; - - private int _copyvolumewait; - @Inject - protected HypervisorCapabilitiesDao _hypervisorCapabilitiesDao; private final StateMachine2 _volStateMachine; - @Inject - StorageManager storageMgr; - private int _customDiskOfferingMinSize = 1; - private final int _customDiskOfferingMaxSize = 1024; private long _maxVolumeSizeInGb; private boolean _recreateSystemVmEnabled; + protected List _storagePoolAllocators; - public VolumeManagerImpl() { + public List getStoragePoolAllocators() { + return _storagePoolAllocators; + } + + public void setStoragePoolAllocators(List _storagePoolAllocators) { + this._storagePoolAllocators = _storagePoolAllocators; + } + + protected VolumeOrchestrator() { _volStateMachine = Volume.State.getStateMachine(); } @Override - public VolumeInfo moveVolume(VolumeInfo volume, long destPoolDcId, - Long destPoolPodId, Long destPoolClusterId, - HypervisorType dataDiskHyperType) - throws ConcurrentOperationException { + public VolumeInfo moveVolume(VolumeInfo volume, long destPoolDcId, Long destPoolPodId, Long destPoolClusterId, HypervisorType dataDiskHyperType) + throws ConcurrentOperationException { // Find a destination storage pool with the specified criteria - DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume - .getDiskOfferingId()); + DiskOffering diskOffering = _entityMgr.findById(DiskOffering.class, volume.getDiskOfferingId()); +; DiskProfile dskCh = new DiskProfile(volume.getId(), - volume.getVolumeType(), volume.getName(), diskOffering.getId(), - diskOffering.getDiskSize(), diskOffering.getTagsArray(), - diskOffering.getUseLocalStorage(), - diskOffering.isRecreatable(), null); + volume.getVolumeType(), + volume.getName(), + diskOffering.getId(), + diskOffering.getDiskSize(), + diskOffering.getTagsArray(), + diskOffering.getUseLocalStorage(), + diskOffering.isRecreatable(), + null); dskCh.setHyperType(dataDiskHyperType); - DataCenterVO destPoolDataCenter = _dcDao.findById(destPoolDcId); - HostPodVO destPoolPod = _podDao.findById(destPoolPodId); + DataCenter destPoolDataCenter = _entityMgr.findById(DataCenter.class, destPoolDcId); + Pod destPoolPod = _entityMgr.findById(Pod.class, destPoolPodId); - StoragePool destPool = storageMgr.findStoragePool(dskCh, - destPoolDataCenter, destPoolPod, destPoolClusterId, null, null, - new HashSet()); + StoragePool destPool = findStoragePool(dskCh, destPoolDataCenter, destPoolPod, destPoolClusterId, null, null, new HashSet()); if (destPool == null) { - throw new CloudRuntimeException( - "Failed to find a storage pool with enough capacity to move the volume to."); + throw new CloudRuntimeException("Failed to find a storage pool with enough capacity to move the volume to."); } Volume newVol = migrateVolume(volume, destPool); return volFactory.getVolume(newVol.getId()); } - /* - * Upload the volume to secondary storage. - */ @Override - @DB - @ActionEvent(eventType = EventTypes.EVENT_VOLUME_UPLOAD, eventDescription = "uploading volume", async = true) - public VolumeVO uploadVolume(UploadVolumeCmd cmd) - throws ResourceAllocationException { - Account caller = CallContext.current().getCallingAccount(); - long ownerId = cmd.getEntityOwnerId(); - Account owner = _accountDao.findById(ownerId); - Long zoneId = cmd.getZoneId(); - String volumeName = cmd.getVolumeName(); - String url = cmd.getUrl(); - String format = cmd.getFormat(); - String imageStoreUuid = cmd.getImageStoreUuid(); - DataStore store = _tmpltMgr.getImageStore(imageStoreUuid, zoneId); - - validateVolume(caller, ownerId, zoneId, volumeName, url, format); - - VolumeVO volume = persistVolume(owner, zoneId, volumeName, - url, cmd.getFormat()); - - VolumeInfo vol = volFactory.getVolume(volume.getId()); - - RegisterVolumePayload payload = new RegisterVolumePayload(cmd.getUrl(), cmd.getChecksum(), - cmd.getFormat()); - vol.addPayload(payload); - - volService.registerVolume(vol, store); - return volume; + public Volume allocateDuplicateVolume(Volume oldVol, Long templateId) { + return allocateDuplicateVolumeVO(oldVol, templateId); } - private boolean validateVolume(Account caller, long ownerId, Long zoneId, - String volumeName, String url, String format) - throws ResourceAllocationException { - - // permission check - _accountMgr.checkAccess(caller, null, true, - _accountMgr.getActiveAccountById(ownerId)); - - // Check that the resource limit for volumes won't be exceeded - _resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(ownerId), - ResourceType.volume); - - // 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.getType())) { - throw new PermissionDeniedException( - "Cannot perform this operation, Zone is currently disabled: " - + zoneId); - } - - if (url.toLowerCase().contains("file://")) { - throw new InvalidParameterValueException( - "File:// type urls are currently unsupported"); - } - - ImageFormat imgfmt = ImageFormat.valueOf(format.toUpperCase()); - if (imgfmt == null) { - throw new IllegalArgumentException("Image format is incorrect " - + format + ". Supported formats are " - + EnumUtils.listValues(ImageFormat.values())); - } - - String userSpecifiedName = volumeName; - if (userSpecifiedName == null) { - userSpecifiedName = getRandomVolumeName(); - } - if ((!url.toLowerCase().endsWith("vhd")) - && (!url.toLowerCase().endsWith("vhd.zip")) - && (!url.toLowerCase().endsWith("vhd.bz2")) - && (!url.toLowerCase().endsWith("vhd.gz")) - && (!url.toLowerCase().endsWith("qcow2")) - && (!url.toLowerCase().endsWith("qcow2.zip")) - && (!url.toLowerCase().endsWith("qcow2.bz2")) - && (!url.toLowerCase().endsWith("qcow2.gz")) - && (!url.toLowerCase().endsWith("ova")) - && (!url.toLowerCase().endsWith("ova.zip")) - && (!url.toLowerCase().endsWith("ova.bz2")) - && (!url.toLowerCase().endsWith("ova.gz")) - && (!url.toLowerCase().endsWith("img")) - && (!url.toLowerCase().endsWith("raw"))) { - throw new InvalidParameterValueException("Please specify a valid " - + format.toLowerCase()); - } - - if ((format.equalsIgnoreCase("vhd") && (!url.toLowerCase().endsWith( - ".vhd") - && !url.toLowerCase().endsWith("vhd.zip") - && !url.toLowerCase().endsWith("vhd.bz2") && !url.toLowerCase() - .endsWith("vhd.gz"))) - || (format.equalsIgnoreCase("qcow2") && (!url.toLowerCase() - .endsWith(".qcow2") - && !url.toLowerCase().endsWith("qcow2.zip") - && !url.toLowerCase().endsWith("qcow2.bz2") && !url - .toLowerCase().endsWith("qcow2.gz"))) - || (format.equalsIgnoreCase("ova") && (!url.toLowerCase() - .endsWith(".ova") - && !url.toLowerCase().endsWith("ova.zip") - && !url.toLowerCase().endsWith("ova.bz2") && !url - .toLowerCase().endsWith("ova.gz"))) - || (format.equalsIgnoreCase("raw") && (!url.toLowerCase() - .endsWith(".img") && !url.toLowerCase().endsWith("raw")))) { - throw new InvalidParameterValueException( - "Please specify a valid URL. URL:" + url - + " is an invalid for the format " - + format.toLowerCase()); - } - UriUtils.validateUrl(url); - - // Check that the resource limit for secondary storage won't be exceeded - _resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(ownerId), ResourceType.secondary_storage, - UriUtils.getRemoteSize(url)); - - return false; - } - - @Override - public VolumeVO allocateDuplicateVolume(VolumeVO oldVol, Long templateId) { + public VolumeVO allocateDuplicateVolumeVO(Volume oldVol, Long templateId) { VolumeVO newVol = new VolumeVO(oldVol.getVolumeType(), - oldVol.getName(), oldVol.getDataCenterId(), - oldVol.getDomainId(), oldVol.getAccountId(), - oldVol.getDiskOfferingId(), oldVol.getSize(), - oldVol.getMinIops(), oldVol.getMaxIops(), oldVol.get_iScsiName()); + oldVol.getName(), + oldVol.getDataCenterId(), + oldVol.getDomainId(), + oldVol.getAccountId(), + oldVol.getDiskOfferingId(), + oldVol.getSize(), + oldVol.getMinIops(), + oldVol.getMaxIops(), + oldVol.get_iScsiName()); if (templateId != null) { newVol.setTemplateId(templateId); } else { @@ -517,10 +214,38 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { return _volsDao.persist(newVol); } + @Override + public StoragePool findStoragePool(DiskProfile dskCh, DataCenter dc, Pod pod, Long clusterId, Long hostId, VirtualMachine vm, final Set avoid) { + Long podId = null; + if (pod != null) { + podId = pod.getId(); + } else if (clusterId != null) { + Cluster cluster = _entityMgr.findById(Cluster.class, clusterId); + if (cluster != null) { + podId = cluster.getPodId(); + } + } + + VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm); + for (StoragePoolAllocator allocator : _storagePoolAllocators) { + + ExcludeList avoidList = new ExcludeList(); + for (StoragePool pool : avoid) { + avoidList.addPool(pool.getId()); + } + DataCenterDeployment plan = new DataCenterDeployment(dc.getId(), podId, clusterId, hostId, null, null); + + final List poolList = allocator.allocateToPool(dskCh, profile, plan, avoidList, 1); + if (poolList != null && !poolList.isEmpty()) { + return (StoragePool)dataStoreMgr.getDataStore(poolList.get(0).getId(), DataStoreRole.Primary); + } + } + return null; + } + @DB - protected VolumeInfo createVolumeFromSnapshot(VolumeVO volume, - SnapshotVO snapshot) throws StorageUnavailableException { - Account account = _accountDao.findById(volume.getAccountId()); + protected VolumeInfo createVolumeFromSnapshot(VolumeVO volume, Snapshot snapshot) throws StorageUnavailableException { + Account account = _entityMgr.findById(Account.class, volume.getAccountId()); final HashSet poolsToAvoid = new HashSet(); StoragePool pool = null; @@ -528,18 +253,15 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { Set podsToAvoid = new HashSet(); Pair pod = null; - DiskOfferingVO diskOffering = _diskOfferingDao - .findByIdIncludingRemoved(volume.getDiskOfferingId()); - DataCenterVO dc = _dcDao.findById(volume.getDataCenterId()); - DiskProfile dskCh = new DiskProfile(volume, diskOffering, - snapshot.getHypervisorType()); + DiskOffering diskOffering = _entityMgr.findById(DiskOffering.class, volume.getDiskOfferingId()); + DataCenter dc = _entityMgr.findById(DataCenter.class, volume.getDataCenterId()); + DiskProfile dskCh = new DiskProfile(volume, diskOffering, snapshot.getHypervisorType()); // Determine what pod to store the volume in while ((pod = _resourceMgr.findPod(null, null, dc, account.getId(), podsToAvoid)) != null) { podsToAvoid.add(pod.first().getId()); // Determine what storage pool to store the volume in - while ((pool = storageMgr.findStoragePool(dskCh, dc, pod.first(), null, null, - null, poolsToAvoid)) != null) { + while ((pool = findStoragePool(dskCh, dc, pod.first(), null, null, null, poolsToAvoid)) != null) { break; } } @@ -571,62 +293,63 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { } - protected DiskProfile createDiskCharacteristics(VolumeInfo volume, - VMTemplateVO template, DataCenterVO dc, DiskOfferingVO diskOffering) { - if (volume.getVolumeType() == Type.ROOT - && Storage.ImageFormat.ISO != template.getFormat()) { - TemplateDataStoreVO ss = _vmTemplateStoreDao.findByTemplateZoneDownloadStatus(template.getId(), dc.getId(), - VMTemplateStorageResourceAssoc.Status.DOWNLOADED); + protected DiskProfile createDiskCharacteristics(VolumeInfo volume, VirtualMachineTemplate template, DataCenter dc, DiskOffering diskOffering) { + if (volume.getVolumeType() == Type.ROOT && Storage.ImageFormat.ISO != template.getFormat()) { + TemplateDataStoreVO ss = _vmTemplateStoreDao.findByTemplateZoneDownloadStatus(template.getId(), dc.getId(), VMTemplateStorageResourceAssoc.Status.DOWNLOADED); if (ss == null) { - throw new CloudRuntimeException("Template " - + template.getName() - + " has not been completely downloaded to zone " - + dc.getId()); + throw new CloudRuntimeException("Template " + template.getName() + " has not been completely downloaded to zone " + dc.getId()); } - return new DiskProfile(volume.getId(), volume.getVolumeType(), - volume.getName(), diskOffering.getId(), ss.getSize(), - diskOffering.getTagsArray(), - diskOffering.getUseLocalStorage(), - diskOffering.isRecreatable(), - Storage.ImageFormat.ISO != template.getFormat() ? template - .getId() : null); + return new DiskProfile(volume.getId(), + volume.getVolumeType(), + volume.getName(), + diskOffering.getId(), + ss.getSize(), + diskOffering.getTagsArray(), + diskOffering.getUseLocalStorage(), + diskOffering.isRecreatable(), + Storage.ImageFormat.ISO != template.getFormat() ? template.getId() : null); } else { - return new DiskProfile(volume.getId(), volume.getVolumeType(), - volume.getName(), diskOffering.getId(), - diskOffering.getDiskSize(), diskOffering.getTagsArray(), - diskOffering.getUseLocalStorage(), - diskOffering.isRecreatable(), null); + return new DiskProfile(volume.getId(), + volume.getVolumeType(), + volume.getName(), + diskOffering.getId(), + diskOffering.getDiskSize(), + diskOffering.getTagsArray(), + diskOffering.getUseLocalStorage(), + diskOffering.isRecreatable(), + null); } } protected VolumeVO createVolumeFromSnapshot(VolumeVO volume, long snapshotId) throws StorageUnavailableException { VolumeInfo createdVolume = null; - SnapshotVO snapshot = _snapshotDao.findById(snapshotId); - createdVolume = createVolumeFromSnapshot(volume, - snapshot); + Snapshot snapshot = _entityMgr.findById(Snapshot.class, snapshotId); + createdVolume = createVolumeFromSnapshot(volume, snapshot); - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, createdVolume.getAccountId(), createdVolume.getDataCenterId(), createdVolume.getId(), - createdVolume.getName(), createdVolume.getDiskOfferingId(), null, createdVolume.getSize(), Volume.class.getName(), createdVolume.getUuid()); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, + createdVolume.getAccountId(), + createdVolume.getDataCenterId(), + createdVolume.getId(), + createdVolume.getName(), + createdVolume.getDiskOfferingId(), + null, + createdVolume.getSize(), + Volume.class.getName(), + createdVolume.getUuid()); return _volsDao.findById(createdVolume.getId()); } @DB - public VolumeInfo copyVolumeFromSecToPrimary(VolumeInfo volume, - VMInstanceVO vm, VMTemplateVO template, DataCenterVO dc, - HostPodVO pod, Long clusterId, ServiceOfferingVO offering, - DiskOfferingVO diskOffering, List avoids, - long size, HypervisorType hyperType) throws NoTransitionException { + public VolumeInfo copyVolumeFromSecToPrimary(VolumeInfo volume, VirtualMachine vm, VirtualMachineTemplate template, DataCenter dc, Pod pod, Long clusterId, + ServiceOffering offering, DiskOffering diskOffering, List avoids, long size, HypervisorType hyperType) throws NoTransitionException { - final HashSet avoidPools = new HashSet( - avoids); - DiskProfile dskCh = createDiskCharacteristics(volume, template, dc, - diskOffering); + final HashSet avoidPools = new HashSet(avoids); + DiskProfile dskCh = createDiskCharacteristics(volume, template, dc, diskOffering); dskCh.setHyperType(vm.getHypervisorType()); // Find a suitable storage to create volume on - StoragePool destPool = storageMgr.findStoragePool(dskCh, dc, pod, - clusterId, null, vm, avoidPools); + StoragePool destPool = findStoragePool(dskCh, dc, pod, clusterId, null, vm, avoidPools); DataStore destStore = dataStoreMgr.getDataStore(destPool.getId(), DataStoreRole.Primary); AsyncCallFuture future = volService.copyVolume(volume, destStore); @@ -647,11 +370,8 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { } @DB - public VolumeInfo createVolume(VolumeInfo volume, VMInstanceVO vm, - VMTemplateVO template, DataCenterVO dc, HostPodVO pod, - Long clusterId, ServiceOfferingVO offering, - DiskOfferingVO diskOffering, List avoids, - long size, HypervisorType hyperType) { + public VolumeInfo createVolume(VolumeInfo volume, VirtualMachine vm, VirtualMachineTemplate template, DataCenter dc, Pod pod, Long clusterId, ServiceOffering offering, + DiskOffering diskOffering, List avoids, long size, HypervisorType hyperType) { StoragePool pool = null; if (diskOffering != null && diskOffering.isCustomized()) { @@ -659,24 +379,19 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { } DiskProfile dskCh = null; - if (volume.getVolumeType() == Type.ROOT - && Storage.ImageFormat.ISO != template.getFormat()) { + if (volume.getVolumeType() == Type.ROOT && Storage.ImageFormat.ISO != template.getFormat()) { dskCh = createDiskCharacteristics(volume, template, dc, offering); } else { - dskCh = createDiskCharacteristics(volume, template, dc, - diskOffering); + dskCh = createDiskCharacteristics(volume, template, dc, diskOffering); } dskCh.setHyperType(hyperType); - final HashSet avoidPools = new HashSet( - avoids); + final HashSet avoidPools = new HashSet(avoids); - pool = storageMgr.findStoragePool(dskCh, dc, pod, clusterId, vm.getHostId(), - vm, avoidPools); + pool = findStoragePool(dskCh, dc, pod, clusterId, vm.getHostId(), vm, avoidPools); if (pool == null) { - s_logger.warn("Unable to find storage pool when create volume " - + volume.getName()); + s_logger.warn("Unable to find storage pool when create volume " + volume.getName()); throw new CloudRuntimeException("Unable to find storage pool when create volume" + volume.getName()); } @@ -714,44 +429,8 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { return UUID.randomUUID().toString(); } - private VolumeVO persistVolume(Account owner, Long zoneId, - String volumeName, String url, String format) { - - Transaction txn = Transaction.currentTxn(); - txn.start(); - - VolumeVO volume = new VolumeVO(volumeName, zoneId, -1, -1, -1, - new Long(-1), null, null, 0, Volume.Type.DATADISK); - volume.setPoolId(null); - volume.setDataCenterId(zoneId); - volume.setPodId(null); - volume.setAccountId(owner.getAccountId()); - volume.setDomainId(owner.getDomainId()); - long diskOfferingId = _diskOfferingDao.findByUniqueName( - "Cloud.com-Custom").getId(); - volume.setDiskOfferingId(diskOfferingId); - // volume.setSize(size); - volume.setInstanceId(null); - volume.setUpdated(new Date()); - volume.setDomainId((owner == null) ? Domain.ROOT_DOMAIN : owner - .getDomainId()); - volume.setFormat(ImageFormat.valueOf(format)); - volume = _volsDao.persist(volume); - CallContext.current().setEventDetails("Volume Id: " + volume.getId()); - - // Increment resource count during allocation; if actual creation fails, - // decrement it - _resourceLimitMgr.incrementResourceCount(volume.getAccountId(), - ResourceType.volume); - _resourceLimitMgr.incrementResourceCount(volume.getAccountId(), ResourceType.secondary_storage, - UriUtils.getRemoteSize(url)); - - txn.commit(); - return volume; - } - @Override - public boolean volumeOnSharedStoragePool(VolumeVO volume) { + public boolean volumeOnSharedStoragePool(Volume volume) { Long poolId = volume.getPoolId(); if (poolId == null) { return false; @@ -770,7 +449,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { public boolean volumeInactive(Volume volume) { Long vmId = volume.getInstanceId(); if (vmId != null) { - UserVm vm = _userVmDao.findById(vmId); + UserVm vm = _entityMgr.findById(UserVm.class, vmId); if (vm == null) { return true; } @@ -786,7 +465,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { public String getVmNameOnVolume(Volume volume) { Long vmId = volume.getInstanceId(); if (vmId != null) { - VMInstanceVO vm = _vmInstanceDao.findById(vmId); + VirtualMachine vm = _entityMgr.findById(VirtualMachine.class, vmId); if (vm == null) { return null; @@ -796,614 +475,46 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { return null; } - /* - * Just allocate a volume in the database, don't send the createvolume cmd - * to hypervisor. The volume will be finally created only when it's attached - * to a VM. - */ - @Override - @DB - @ActionEvent(eventType = EventTypes.EVENT_VOLUME_CREATE, eventDescription = "creating volume", create = true) - public VolumeVO allocVolume(CreateVolumeCmd cmd) - throws ResourceAllocationException { - // FIXME: some of the scheduled event stuff might be missing here... - Account caller = CallContext.current().getCallingAccount(); - - long ownerId = cmd.getEntityOwnerId(); - Boolean displayVolumeEnabled = cmd.getDisplayVolume(); - - // permission check - _accountMgr.checkAccess(caller, null, true, - _accountMgr.getActiveAccountById(ownerId)); - - // Check that the resource limit for volumes won't be exceeded - _resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(ownerId), - ResourceType.volume); - - Long zoneId = cmd.getZoneId(); - Long diskOfferingId = null; - DiskOfferingVO diskOffering = null; - Long size = null; - Long minIops = null; - Long maxIops = null; - // Volume VO used for extracting the source template id - VolumeVO parentVolume = null; - - // validate input parameters before creating the volume - if ((cmd.getSnapshotId() == null && cmd.getDiskOfferingId() == null) - || (cmd.getSnapshotId() != null && cmd.getDiskOfferingId() != null)) { - throw new InvalidParameterValueException( - "Either disk Offering Id or snapshot Id must be passed whilst creating volume"); - } - - if (cmd.getSnapshotId() == null) {// create a new volume - - diskOfferingId = cmd.getDiskOfferingId(); - size = cmd.getSize(); - Long sizeInGB = size; - if (size != null) { - if (size > 0) { - size = size * 1024 * 1024 * 1024; // user specify size in GB - } else { - throw new InvalidParameterValueException( - "Disk size must be larger than 0"); - } - } - - // Check that the the disk offering is specified - diskOffering = _diskOfferingDao.findById(diskOfferingId); - if ((diskOffering == null) || diskOffering.getRemoved() != null - || !DiskOfferingVO.Type.Disk.equals(diskOffering.getType())) { - throw new InvalidParameterValueException( - "Please specify a valid disk offering."); - } - - if (diskOffering.isCustomized()) { - if (size == null) { - throw new InvalidParameterValueException( - "This disk offering requires a custom size specified"); - } - if ((sizeInGB < _customDiskOfferingMinSize) - || (sizeInGB > _customDiskOfferingMaxSize)) { - throw new InvalidParameterValueException("Volume size: " - + sizeInGB + "GB is out of allowed range. Max: " - + _customDiskOfferingMaxSize + " Min:" - + _customDiskOfferingMinSize); - } - } - - if (!diskOffering.isCustomized() && size != null) { - throw new InvalidParameterValueException( - "This disk offering does not allow custom size"); - } - - if (diskOffering.getDomainId() == null) { - // do nothing as offering is public - } else { - _configMgr.checkDiskOfferingAccess(caller, diskOffering); - } - - if (diskOffering.getDiskSize() > 0) { - size = diskOffering.getDiskSize(); - } - - Boolean isCustomizedIops = diskOffering.isCustomizedIops(); - - if (isCustomizedIops != null) { - if (isCustomizedIops) { - minIops = cmd.getMinIops(); - maxIops = cmd.getMaxIops(); - - if (minIops == null && maxIops == null) { - minIops = 0L; - maxIops = 0L; - } - else { - if (minIops == null || minIops <= 0) { - throw new InvalidParameterValueException("The min IOPS must be greater than 0."); - } - - if (maxIops == null) { - maxIops = 0L; - } - - if (minIops > maxIops) { - throw new InvalidParameterValueException("The min IOPS must be less than or equal to the max IOPS."); - } - } - } - else { - minIops = diskOffering.getMinIops(); - maxIops = diskOffering.getMaxIops(); - } - } - - if (!validateVolumeSizeRange(size)) {// convert size from mb to gb - // for validation - throw new InvalidParameterValueException( - "Invalid size for custom volume creation: " + size - + " ,max volume size is:" + _maxVolumeSizeInGb); - } - } else { // create volume from snapshot - Long snapshotId = cmd.getSnapshotId(); - SnapshotVO snapshotCheck = _snapshotDao.findById(snapshotId); - if (snapshotCheck == null) { - throw new InvalidParameterValueException( - "unable to find a snapshot with id " + snapshotId); - } - - if (snapshotCheck.getState() != Snapshot.State.BackedUp) { - throw new InvalidParameterValueException("Snapshot id=" - + snapshotId + " is not in " + Snapshot.State.BackedUp - + " state yet and can't be used for volume creation"); - } - parentVolume = _volsDao.findByIdIncludingRemoved(snapshotCheck.getVolumeId()); - - diskOfferingId = snapshotCheck.getDiskOfferingId(); - diskOffering = _diskOfferingDao.findById(diskOfferingId); - zoneId = snapshotCheck.getDataCenterId(); - size = snapshotCheck.getSize(); // ; disk offering is used for tags - // purposes - - // check snapshot permissions - _accountMgr.checkAccess(caller, null, true, snapshotCheck); - } - - if(displayVolumeEnabled == null){ - displayVolumeEnabled = true; - } else{ - if(!_accountMgr.isRootAdmin(caller.getType())){ - throw new PermissionDeniedException( "Cannot update parameter displayvolume, only admin permitted "); - } - } - - // Check that the resource limit for primary storage won't be exceeded - _resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(ownerId), ResourceType.primary_storage, - new Long(size)); - - // 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.getType())) { - throw new PermissionDeniedException( - "Cannot perform this operation, Zone is currently disabled: " - + zoneId); - } - - // If local storage is disabled then creation of volume with local disk - // offering not allowed - if (!zone.isLocalStorageEnabled() && diskOffering.getUseLocalStorage()) { - throw new InvalidParameterValueException( - "Zone is not configured to use local storage but volume's disk offering " - + diskOffering.getName() + " uses it"); - } - - String userSpecifiedName = cmd.getVolumeName(); - if (userSpecifiedName == null) { - userSpecifiedName = getRandomVolumeName(); - } - - Transaction txn = Transaction.currentTxn(); - txn.start(); - - VolumeVO volume = new VolumeVO(userSpecifiedName, -1, -1, -1, -1, - new Long(-1), null, null, 0, Volume.Type.DATADISK); - volume.setPoolId(null); - volume.setDataCenterId(zoneId); - volume.setPodId(null); - volume.setAccountId(ownerId); - volume.setDomainId(((caller == null) ? Domain.ROOT_DOMAIN : caller - .getDomainId())); - volume.setDiskOfferingId(diskOfferingId); - volume.setSize(size); - volume.setMinIops(minIops); - volume.setMaxIops(maxIops); - volume.setInstanceId(null); - volume.setUpdated(new Date()); - volume.setDomainId((caller == null) ? Domain.ROOT_DOMAIN : caller - .getDomainId()); - volume.setDisplayVolume(displayVolumeEnabled); - if (parentVolume != null) { - volume.setTemplateId(parentVolume.getTemplateId()); - volume.setFormat(parentVolume.getFormat()); - } else { - volume.setTemplateId(null); - } - - volume = _volsDao.persist(volume); - if (cmd.getSnapshotId() == null) { - // for volume created from snapshot, create usage event after volume creation - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(), diskOfferingId, - null, size, Volume.class.getName(), volume.getUuid()); - } - - CallContext.current().setEventDetails("Volume Id: " + volume.getId()); - - // Increment resource count during allocation; if actual creation fails, - // decrement it - _resourceLimitMgr.incrementResourceCount(volume.getAccountId(), - ResourceType.volume); - _resourceLimitMgr.incrementResourceCount(volume.getAccountId(), ResourceType.primary_storage, - new Long(volume.getSize())); - - txn.commit(); - - return volume; - } - - @Override - @DB - @ActionEvent(eventType = EventTypes.EVENT_VOLUME_CREATE, eventDescription = "creating volume", async = true) - public VolumeVO createVolume(CreateVolumeCmd cmd) { - VolumeVO volume = _volsDao.findById(cmd.getEntityId()); - boolean created = true; - - try { - if (cmd.getSnapshotId() != null) { - volume = createVolumeFromSnapshot(volume, cmd.getSnapshotId()); - if (volume.getState() != Volume.State.Ready) { - created = false; - } - } - return volume; - } catch(Exception e) { - created = false; - s_logger.debug("Failed to create volume: " + volume.getId(), e); - return null; - } finally { - if (!created) { - s_logger.trace("Decrementing volume resource count for account id=" - + volume.getAccountId() - + " as volume failed to create on the backend"); - _resourceLimitMgr.decrementResourceCount(volume.getAccountId(), - ResourceType.volume); - _resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.primary_storage, - new Long(volume.getSize())); - } - } - } - - @Override - @DB - @ActionEvent(eventType = EventTypes.EVENT_VOLUME_RESIZE, eventDescription = "resizing volume", async = true) - public VolumeVO resizeVolume(ResizeVolumeCmd cmd) - throws ResourceAllocationException { - Long newSize = null; - boolean shrinkOk = cmd.getShrinkOk(); - - VolumeVO volume = _volsDao.findById(cmd.getEntityId()); - if (volume == null) { - throw new InvalidParameterValueException("No such volume"); - } - - DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume - .getDiskOfferingId()); - DiskOfferingVO newDiskOffering = null; - - newDiskOffering = _diskOfferingDao.findById(cmd.getNewDiskOfferingId()); - - /* - * Volumes with no hypervisor have never been assigned, and can be - * resized by recreating. perhaps in the future we can just update the - * db entry for the volume - */ - if (_volsDao.getHypervisorType(volume.getId()) == HypervisorType.None) { - throw new InvalidParameterValueException( - "Can't resize a volume that has never been attached, not sure which hypervisor type. Recreate volume to resize."); - } - - /* Only works for KVM/Xen for now */ - if (_volsDao.getHypervisorType(volume.getId()) != HypervisorType.KVM - && _volsDao.getHypervisorType(volume.getId()) != HypervisorType.XenServer - && _volsDao.getHypervisorType(volume.getId()) != HypervisorType.VMware) { - throw new InvalidParameterValueException( - "Cloudstack currently only supports volumes marked as KVM or XenServer hypervisor for resize"); - } - - - if (volume.getState() != Volume.State.Ready) { - throw new InvalidParameterValueException( - "Volume should be in ready state before attempting a resize"); - } - - if (!volume.getVolumeType().equals(Volume.Type.DATADISK)) { - throw new InvalidParameterValueException( - "Can only resize DATA volumes"); - } - - /* - * figure out whether or not a new disk offering or size parameter is - * required, get the correct size value - */ - if (newDiskOffering == null) { - if (diskOffering.isCustomized()) { - newSize = cmd.getSize(); - - if (newSize == null) { - throw new InvalidParameterValueException( - "new offering is of custom size, need to specify a size"); - } - - newSize = (newSize << 30); - } else { - throw new InvalidParameterValueException("current offering" - + volume.getDiskOfferingId() - + " cannot be resized, need to specify a disk offering"); - } - } else { - - if (newDiskOffering.getRemoved() != null - || !DiskOfferingVO.Type.Disk.equals(newDiskOffering - .getType())) { - throw new InvalidParameterValueException( - "Disk offering ID is missing or invalid"); - } - - if (diskOffering.getTags() != null) { - if (!newDiskOffering.getTags().equals(diskOffering.getTags())) { - throw new InvalidParameterValueException( - "Tags on new and old disk offerings must match"); - } - } else if (newDiskOffering.getTags() != null) { - throw new InvalidParameterValueException( - "There are no tags on current disk offering, new disk offering needs to have no tags"); - } - - if (newDiskOffering.getDomainId() == null) { - // do nothing as offering is public - } else { - _configMgr.checkDiskOfferingAccess(CallContext.current() - .getCallingAccount(), newDiskOffering); - } - - if (newDiskOffering.isCustomized()) { - newSize = cmd.getSize(); - - if (newSize == null) { - throw new InvalidParameterValueException( - "new offering is of custom size, need to specify a size"); - } - - newSize = (newSize << 30); - } else { - newSize = newDiskOffering.getDiskSize(); - } - } - - if (newSize == null) { - throw new InvalidParameterValueException( - "could not detect a size parameter or fetch one from the diskofferingid parameter"); - } - - if (!validateVolumeSizeRange(newSize)) { - throw new InvalidParameterValueException( - "Requested size out of range"); - } - - /* does the caller have the authority to act on this volume? */ - _accountMgr.checkAccess(CallContext.current().getCallingAccount(), null, true, - volume); - - UserVmVO userVm = _userVmDao.findById(volume.getInstanceId()); - - long currentSize = volume.getSize(); - - /* - * lets make certain they (think they) know what they're doing if they - * want to shrink, by forcing them to provide the shrinkok parameter. - * This will be checked again at the hypervisor level where we can see - * the actual disk size - */ - if (currentSize > newSize && !shrinkOk) { - throw new InvalidParameterValueException( - "Going from existing size of " - + currentSize - + " to size of " - + newSize - + " would shrink the volume, need to sign off by supplying the shrinkok parameter with value of true"); - } - - if (!shrinkOk) { - /* Check resource limit for this account on primary storage resource */ - _resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(volume.getAccountId()), - ResourceType.primary_storage, new Long(newSize - currentSize)); - } - - /* - * get a list of hosts to send the commands to, try the system the - * associated vm is running on first, then the last known place it ran. - * If not attached to a userVm, we pass 'none' and resizevolume.sh is ok - * with that since it only needs the vm name to live resize - */ - long[] hosts = null; - String instanceName = "none"; - if (userVm != null) { - instanceName = userVm.getInstanceName(); - if (userVm.getHostId() != null) { - hosts = new long[] { userVm.getHostId() }; - } else if (userVm.getLastHostId() != null) { - hosts = new long[] { userVm.getLastHostId() }; - } - - /* Xen only works offline, SR does not support VDI.resizeOnline */ - if (_volsDao.getHypervisorType(volume.getId()) == HypervisorType.XenServer - && !userVm.getState().equals(State.Stopped)) { - throw new InvalidParameterValueException( - "VM must be stopped or disk detached in order to resize with the Xen HV"); - } - } - - ResizeVolumePayload payload = new ResizeVolumePayload(newSize, shrinkOk, instanceName, hosts); - - try { - VolumeInfo vol = volFactory.getVolume(volume.getId()); - vol.addPayload(payload); - - AsyncCallFuture future = volService.resize(vol); - VolumeApiResult result = future.get(); - if (result.isFailed()) { - s_logger.warn("Failed to resize the volume " + volume); - return null; - } - - volume = _volsDao.findById(volume.getId()); - - if (newDiskOffering != null) { - volume.setDiskOfferingId(cmd.getNewDiskOfferingId()); - } - _volsDao.update(volume.getId(), volume); - // Log usage event for volumes belonging user VM's only - 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()); - - /* Update resource count for the account on primary storage resource */ - if (!shrinkOk) { - _resourceLimitMgr.incrementResourceCount(volume.getAccountId(), ResourceType.primary_storage, - new Long(newSize - currentSize)); - } else { - _resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.primary_storage, - new Long(currentSize - newSize)); - } - return volume; - } catch (InterruptedException e) { - s_logger.warn("failed get resize volume result", e); - } catch (ExecutionException e) { - s_logger.warn("failed get resize volume result", e); - } catch (Exception e) { - s_logger.warn("failed get resize volume result", e); - } - - return null; - } - - @Override - @DB - @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DELETE, eventDescription = "deleting volume") - public boolean deleteVolume(long volumeId, Account caller) - throws ConcurrentOperationException { - - VolumeVO volume = _volsDao.findById(volumeId); - if (volume == null) { - throw new InvalidParameterValueException( - "Unable to aquire volume with ID: " + volumeId); - } - - if (!_snapshotMgr.canOperateOnVolume(volume)) { - throw new InvalidParameterValueException( - "There are snapshot creating on it, Unable to delete the volume"); - } - - _accountMgr.checkAccess(caller, null, true, volume); - - if (volume.getInstanceId() != null) { - throw new InvalidParameterValueException( - "Please specify a volume that is not attached to any VM."); - } - - if (volume.getState() == Volume.State.UploadOp) { - VolumeDataStoreVO volumeStore = _volumeStoreDao.findByVolume(volume - .getId()); - if (volumeStore.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS) { - throw new InvalidParameterValueException( - "Please specify a volume that is not uploading"); - } - } - - try { - if (volume.getState() != Volume.State.Destroy && volume.getState() != Volume.State.Expunging && volume.getState() != Volume.State.Expunging) { - Long instanceId = volume.getInstanceId(); - if (!volService.destroyVolume(volume.getId())) { - return false; - } - - VMInstanceVO vmInstance = _vmInstanceDao.findById(instanceId); - if (instanceId == null - || (vmInstance.getType().equals(VirtualMachine.Type.User))) { - // Decrement the resource count for volumes and primary storage belonging user VM's only - _resourceLimitMgr.decrementResourceCount(volume.getAccountId(), - ResourceType.volume); - /* If volume is in primary storage, decrement primary storage count else decrement secondary - storage count (in case of upload volume). */ - if (volume.getFolder() != null || volume.getPath() != null || volume.getState() == Volume.State.Allocated) { - _resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.primary_storage, - new Long(volume.getSize())); - } else { - _resourceLimitMgr.recalculateResourceCount(volume.getAccountId(), volume.getDomainId(), - ResourceType.secondary_storage.getOrdinal()); - } - - // Log usage event for volumes belonging user VM's only - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_DELETE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(), - Volume.class.getName(), volume.getUuid()); - } - } - // Mark volume as removed if volume has not been created on primary or secondary - if (volume.getState() == Volume.State.Allocated) { - _volsDao.remove(volumeId); - stateTransitTo(volume, Volume.Event.DestroyRequested); - return true; - } - // expunge volume from primary if volume is on primary - VolumeInfo volOnPrimary = volFactory.getVolume(volume.getId(), DataStoreRole.Primary); - if (volOnPrimary != null) { - s_logger.info("Expunging volume " + volume.getId() + " from primary data store"); - AsyncCallFuture future = volService.expungeVolumeAsync(volOnPrimary); - future.get(); - } - // expunge volume from secondary if volume is on image store - VolumeInfo volOnSecondary = volFactory.getVolume(volume.getId(), DataStoreRole.Image); - if (volOnSecondary != null) { - s_logger.info("Expunging volume " + volume.getId() + " from secondary data store"); - AsyncCallFuture future2 = volService.expungeVolumeAsync(volOnSecondary); - future2.get(); - } - } catch (Exception e) { - s_logger.warn("Failed to expunge volume:", e); - return false; - } - - return true; - } - @Override public boolean validateVolumeSizeRange(long size) { if (size < 0 || (size > 0 && size < (1024 * 1024 * 1024))) { - throw new InvalidParameterValueException( - "Please specify a size of at least 1 Gb."); + throw new InvalidParameterValueException("Please specify a size of at least 1 Gb."); } else if (size > (_maxVolumeSizeInGb * 1024 * 1024 * 1024)) { - throw new InvalidParameterValueException("volume size " + size - + ", but the maximum size allowed is " + _maxVolumeSizeInGb - + " Gb."); + throw new InvalidParameterValueException("volume size " + size + ", but the maximum size allowed is " + _maxVolumeSizeInGb + " Gb."); } return true; } - protected DiskProfile toDiskProfile(VolumeVO vol, DiskOfferingVO offering) { - return new DiskProfile(vol.getId(), vol.getVolumeType(), vol.getName(), - offering.getId(), vol.getSize(), offering.getTagsArray(), - offering.getUseLocalStorage(), offering.isRecreatable(), - vol.getTemplateId()); + protected DiskProfile toDiskProfile(Volume vol, DiskOffering offering) { + return new DiskProfile(vol.getId(), + vol.getVolumeType(), + vol.getName(), + offering.getId(), + vol.getSize(), + offering.getTagsArray(), + offering.getUseLocalStorage(), + offering.isRecreatable(), + vol.getTemplateId()); } @Override - public DiskProfile allocateRawVolume(Type type, - String name, DiskOfferingVO offering, Long size, VMInstanceVO vm, VMTemplateVO template, Account owner) { - Long isoId=null; + public DiskProfile allocateRawVolume(Type type, String name, DiskOffering offering, Long size, VirtualMachine vm, VirtualMachineTemplate template, Account owner) { if (size == null) { size = offering.getDiskSize(); } else { size = (size * 1024 * 1024 * 1024); } - VolumeVO vol = new VolumeVO(type, name, vm.getDataCenterId(), - owner.getDomainId(), owner.getId(), offering.getId(), size, - offering.getMinIops(), offering.getMaxIops(), null); + VolumeVO vol = new VolumeVO(type, + name, + vm.getDataCenterId(), + owner.getDomainId(), + owner.getId(), + offering.getId(), + size, + offering.getMinIops(), + offering.getMaxIops(), + null); if (vm != null) { vol.setInstanceId(vm.getId()); } @@ -1423,28 +534,39 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { // Save usage event and update resource count for user vm volumes if (vm instanceof UserVm) { - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, vol.getAccountId(), vol.getDataCenterId(), vol.getId(), vol.getName(), offering.getId(), null, size, - Volume.class.getName(), vol.getUuid()); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, + vol.getAccountId(), + vol.getDataCenterId(), + vol.getId(), + vol.getName(), + offering.getId(), + null, + size, + Volume.class.getName(), + vol.getUuid()); - _resourceLimitMgr.incrementResourceCount(vm.getAccountId(), - ResourceType.volume); - _resourceLimitMgr.incrementResourceCount(vm.getAccountId(), ResourceType.primary_storage, - new Long(vol.getSize())); + _resourceLimitMgr.incrementResourceCount(vm.getAccountId(), ResourceType.volume); + _resourceLimitMgr.incrementResourceCount(vm.getAccountId(), ResourceType.primary_storage, new Long(vol.getSize())); } return toDiskProfile(vol, offering); } @Override - public DiskProfile allocateTemplatedVolume( - Type type, String name, DiskOfferingVO offering, - VMTemplateVO template, VMInstanceVO vm, Account owner) { + public DiskProfile allocateTemplatedVolume(Type type, String name, DiskOffering offering, VirtualMachineTemplate template, VirtualMachine vm, Account owner) { assert (template.getFormat() != ImageFormat.ISO) : "ISO is not a template really...."; Long size = _tmpltMgr.getTemplateSize(template.getId(), vm.getDataCenterId()); - VolumeVO vol = new VolumeVO(type, name, vm.getDataCenterId(), - owner.getDomainId(), owner.getId(), offering.getId(), size, - offering.getMinIops(), offering.getMaxIops(), null); + VolumeVO vol = new VolumeVO(type, + name, + vm.getDataCenterId(), + owner.getDomainId(), + owner.getId(), + offering.getId(), + size, + offering.getMinIops(), + offering.getMaxIops(), + null); vol.setFormat(getSupportedImageFormatForCluster(template.getHypervisorType())); if (vm != null) { vol.setInstanceId(vm.getId()); @@ -1467,22 +589,26 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { Long offeringId = null; - if (offering.getType() == DiskOfferingVO.Type.Disk) { - offeringId = offering.getId(); - } + offeringId = offering.getId(); - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, vol.getAccountId(), vol.getDataCenterId(), vol.getId(), vol.getName(), offeringId, null, size, - Volume.class.getName(), vol.getUuid()); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, + vol.getAccountId(), + vol.getDataCenterId(), + vol.getId(), + vol.getName(), + offeringId, + null, + size, + Volume.class.getName(), + vol.getUuid()); - _resourceLimitMgr.incrementResourceCount(vm.getAccountId(), - ResourceType.volume); - _resourceLimitMgr.incrementResourceCount(vm.getAccountId(), ResourceType.primary_storage, - new Long(vol.getSize())); + _resourceLimitMgr.incrementResourceCount(vm.getAccountId(), ResourceType.volume); + _resourceLimitMgr.incrementResourceCount(vm.getAccountId(), ResourceType.primary_storage, new Long(vol.getSize())); } return toDiskProfile(vol, offering); } - private ImageFormat getSupportedImageFormatForCluster(HypervisorType hyperType) { + private ImageFormat getSupportedImageFormatForCluster(HypervisorType hyperType) { if (hyperType == HypervisorType.XenServer) { return ImageFormat.VHD; } else if (hyperType == HypervisorType.KVM) { @@ -1496,61 +622,48 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { } } - private VolumeInfo copyVolume(StoragePoolVO rootDiskPool - , VolumeInfo volume, VMInstanceVO vm, VMTemplateVO rootDiskTmplt, DataCenterVO dcVO, - HostPodVO pod, DiskOfferingVO diskVO, ServiceOfferingVO svo, HypervisorType rootDiskHyperType) throws NoTransitionException { + private VolumeInfo copyVolume(StoragePool rootDiskPool, VolumeInfo volume, VirtualMachine vm, VirtualMachineTemplate rootDiskTmplt, DataCenter dcVO, Pod pod, + DiskOffering diskVO, ServiceOffering svo, HypervisorType rootDiskHyperType) throws NoTransitionException { - if (!volume - .getFormat() - .equals( - getSupportedImageFormatForCluster(rootDiskHyperType))) { - throw new InvalidParameterValueException( - "Failed to attach volume to VM since volumes format " - + volume.getFormat() - .getFileExtension() - + " is not compatible with the vm hypervisor type"); + if (!volume.getFormat().equals(getSupportedImageFormatForCluster(rootDiskHyperType))) { + throw new InvalidParameterValueException("Failed to attach volume to VM since volumes format " + volume.getFormat().getFileExtension() + + " is not compatible with the vm hypervisor type"); } VolumeInfo volumeOnPrimary = copyVolumeFromSecToPrimary(volume, - vm, rootDiskTmplt, dcVO, pod, - rootDiskPool.getClusterId(), svo, diskVO, - new ArrayList(), - volume.getSize(), rootDiskHyperType); + vm, + rootDiskTmplt, + dcVO, + pod, + rootDiskPool.getClusterId(), + svo, + diskVO, + new ArrayList(), + volume.getSize(), + rootDiskHyperType); return volumeOnPrimary; } - private VolumeInfo createVolumeOnPrimaryStorage(VMInstanceVO vm, VolumeVO rootVolumeOfVm, VolumeInfo volume, HypervisorType rootDiskHyperType) throws NoTransitionException { - VMTemplateVO rootDiskTmplt = _templateDao.findById(vm - .getTemplateId()); - DataCenterVO dcVO = _dcDao.findById(vm - .getDataCenterId()); - HostPodVO pod = _podDao.findById(vm.getPodIdToDeployIn()); - StoragePoolVO rootDiskPool = _storagePoolDao - .findById(rootVolumeOfVm.getPoolId()); - ServiceOfferingVO svo = _serviceOfferingDao.findById(vm - .getServiceOfferingId()); - DiskOfferingVO diskVO = _diskOfferingDao.findById(volume - .getDiskOfferingId()); - Long clusterId = (rootDiskPool == null ? null : rootDiskPool - .getClusterId()); + @Override + public VolumeInfo createVolumeOnPrimaryStorage(VirtualMachine vm, Volume rootVolumeOfVm, VolumeInfo volume, HypervisorType rootDiskHyperType) throws NoTransitionException { + VirtualMachineTemplate rootDiskTmplt = _entityMgr.findById(VirtualMachineTemplate.class, vm.getTemplateId()); + DataCenter dcVO = _entityMgr.findById(DataCenter.class, vm.getDataCenterId()); + Pod pod = _entityMgr.findById(Pod.class, vm.getPodIdToDeployIn()); + StoragePoolVO rootDiskPool = _storagePoolDao.findById(rootVolumeOfVm.getPoolId()); + ServiceOffering svo = _entityMgr.findById(ServiceOffering.class, vm.getServiceOfferingId()); + DiskOffering diskVO = _entityMgr.findById(DiskOffering.class, volume.getDiskOfferingId()); + Long clusterId = (rootDiskPool == null ? null : rootDiskPool.getClusterId()); VolumeInfo vol = null; if (volume.getState() == Volume.State.Allocated) { - vol = createVolume(volume, vm, - rootDiskTmplt, dcVO, pod, clusterId, svo, diskVO, - new ArrayList(), volume.getSize(), - rootDiskHyperType); + vol = createVolume(volume, vm, rootDiskTmplt, dcVO, pod, clusterId, svo, diskVO, new ArrayList(), volume.getSize(), rootDiskHyperType); } else if (volume.getState() == Volume.State.Uploaded) { - vol = copyVolume(rootDiskPool - , volume, vm, rootDiskTmplt, dcVO, - pod, diskVO, svo, rootDiskHyperType); + vol = copyVolume(rootDiskPool, volume, vm, rootDiskTmplt, dcVO, pod, diskVO, svo, rootDiskHyperType); if (vol != null) { // Moving of Volume is successful, decrement the volume resource count from secondary for an account and increment it into primary storage under same account. - _resourceLimitMgr.decrementResourceCount(volume.getAccountId(), - ResourceType.secondary_storage, new Long(volume.getSize())); - _resourceLimitMgr.incrementResourceCount(volume.getAccountId(), - ResourceType.primary_storage, new Long(volume.getSize())); + _resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.secondary_storage, new Long(volume.getSize())); + _resourceLimitMgr.incrementResourceCount(volume.getAccountId(), ResourceType.primary_storage, new Long(volume.getSize())); } } @@ -1560,508 +673,8 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { return volFactory.getVolume(volVO.getId()); } - private boolean needMoveVolume(VolumeVO rootVolumeOfVm, VolumeInfo volume) { - if (rootVolumeOfVm.getPoolId() == null || volume.getPoolId() == null) { - return false; - } - - DataStore storeForRootVol = dataStoreMgr.getPrimaryDataStore(rootVolumeOfVm.getPoolId()); - DataStore storeForDataVol = dataStoreMgr.getPrimaryDataStore(volume.getPoolId()); - - Scope storeForRootStoreScope = storeForRootVol.getScope(); - if (storeForRootStoreScope == null) { - throw new CloudRuntimeException("Can't get scope of data store: " + storeForRootVol.getId()); - } - - Scope storeForDataStoreScope = storeForDataVol.getScope(); - if (storeForDataStoreScope == null) { - throw new CloudRuntimeException("Can't get scope of data store: " + storeForDataVol.getId()); - } - - if (storeForDataStoreScope.getScopeType() == ScopeType.ZONE) { - return false; - } - - if (storeForRootStoreScope.getScopeType() != storeForDataStoreScope.getScopeType()) { - if (storeForDataStoreScope.getScopeType() == ScopeType.CLUSTER && storeForRootStoreScope.getScopeType() == ScopeType.HOST) { - HostScope hs = (HostScope)storeForRootStoreScope; - if (storeForDataStoreScope.getScopeId().equals(hs.getClusterId())) { - return false; - } - } - if (storeForRootStoreScope.getScopeType() == ScopeType.CLUSTER && storeForDataStoreScope.getScopeType() == ScopeType.HOST) { - HostScope hs = (HostScope)storeForDataStoreScope; - if (storeForRootStoreScope.getScopeId().equals(hs.getClusterId())) { - return false; - } - } - throw new CloudRuntimeException("Can't move volume between scope: " + storeForDataStoreScope.getScopeType() + " and " + storeForRootStoreScope.getScopeType()); - } - - return !storeForRootStoreScope.isSameScope(storeForDataStoreScope); - } - - private VolumeVO sendAttachVolumeCommand(UserVmVO vm, VolumeVO volumeToAttach, Long deviceId) { - String errorMsg = "Failed to attach volume: " + volumeToAttach.getName() - + " to VM: " + vm.getHostName(); - boolean sendCommand = (vm.getState() == State.Running); - AttachAnswer answer = null; - Long hostId = vm.getHostId(); - if (hostId == null) { - hostId = vm.getLastHostId(); - HostVO host = _hostDao.findById(hostId); - if (host != null - && host.getHypervisorType() == HypervisorType.VMware) { - sendCommand = true; - } - } - - StoragePoolVO volumeToAttachStoragePool = null; - - if (sendCommand) { - volumeToAttachStoragePool = _storagePoolDao.findById(volumeToAttach.getPoolId()); - long storagePoolId = volumeToAttachStoragePool.getId(); - - DataTO volTO = volFactory.getVolume(volumeToAttach.getId()).getTO(); - DiskTO disk = new DiskTO(volTO, deviceId, null, volumeToAttach.getVolumeType()); - - AttachCommand cmd = new AttachCommand(disk, vm.getInstanceName()); - - cmd.setManaged(volumeToAttachStoragePool.isManaged()); - - cmd.setStorageHost(volumeToAttachStoragePool.getHostAddress()); - cmd.setStoragePort(volumeToAttachStoragePool.getPort()); - - cmd.set_iScsiName(volumeToAttach.get_iScsiName()); - - VolumeInfo volumeInfo = volFactory.getVolume(volumeToAttach.getId()); - DataStore dataStore = dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); - ChapInfo chapInfo = volService.getChapInfo(volumeInfo, dataStore); - - if (chapInfo != null) { - cmd.setChapInitiatorUsername(chapInfo.getInitiatorUsername()); - cmd.setChapInitiatorPassword(chapInfo.getInitiatorSecret()); - cmd.setChapTargetUsername(chapInfo.getTargetUsername()); - cmd.setChapTargetPassword(chapInfo.getTargetSecret()); - } - - try { - answer = (AttachAnswer)_agentMgr.send(hostId, cmd); - } catch (Exception e) { - throw new CloudRuntimeException(errorMsg + " due to: " - + e.getMessage()); - } - } - - if (!sendCommand || (answer != null && answer.getResult())) { - // Mark the volume as attached - if (sendCommand) { - DiskTO disk = answer.getDisk(); - _volsDao.attachVolume(volumeToAttach.getId(), vm.getId(), - disk.getDiskSeq()); - - volumeToAttach = _volsDao.findById(volumeToAttach.getId()); - - if (volumeToAttachStoragePool.isManaged() && - volumeToAttach.getPath() == null) { - volumeToAttach.setPath(answer.getDisk().getVdiUuid()); - - _volsDao.update(volumeToAttach.getId(), volumeToAttach); - } - } else { - _volsDao.attachVolume(volumeToAttach.getId(), vm.getId(), deviceId); - } - - // insert record for disk I/O statistics - VmDiskStatisticsVO diskstats = _vmDiskStatsDao.findBy(vm.getAccountId(), vm.getDataCenterId(),vm.getId(), volumeToAttach.getId()); - if (diskstats == null) { - diskstats = new VmDiskStatisticsVO(vm.getAccountId(), vm.getDataCenterId(),vm.getId(), volumeToAttach.getId()); - _vmDiskStatsDao.persist(diskstats); - } - - return _volsDao.findById(volumeToAttach.getId()); - } else { - if (answer != null) { - String details = answer.getDetails(); - if (details != null && !details.isEmpty()) { - errorMsg += "; " + details; - } - } - throw new CloudRuntimeException(errorMsg); - } - } - - private int getMaxDataVolumesSupported(UserVmVO vm) { - Long hostId = vm.getHostId(); - if (hostId == null) { - hostId = vm.getLastHostId(); - } - HostVO host = _hostDao.findById(hostId); - Integer maxDataVolumesSupported = null; - if (host != null) { - _hostDao.loadDetails(host); - maxDataVolumesSupported = _hypervisorCapabilitiesDao - .getMaxDataVolumesLimit(host.getHypervisorType(), - host.getDetail("product_version")); - } - if (maxDataVolumesSupported == null) { - maxDataVolumesSupported = 6; // 6 data disks by default if nothing - // is specified in - // 'hypervisor_capabilities' table - } - - return maxDataVolumesSupported.intValue(); - } - - @Override - @ActionEvent(eventType = EventTypes.EVENT_VOLUME_ATTACH, eventDescription = "attaching volume", async = true) - public Volume attachVolumeToVM(AttachVolumeCmd command) { - Long vmId = command.getVirtualMachineId(); - Long volumeId = command.getId(); - Long deviceId = command.getDeviceId(); - Account caller = CallContext.current().getCallingAccount(); - - // Check that the volume ID is valid - VolumeInfo volume = volFactory.getVolume(volumeId); - // Check that the volume is a data volume - if (volume == null || volume.getVolumeType() != Volume.Type.DATADISK) { - throw new InvalidParameterValueException( - "Please specify a valid data volume."); - } - - // Check that the volume is not currently attached to any VM - if (volume.getInstanceId() != null) { - throw new InvalidParameterValueException( - "Please specify a volume that is not attached to any VM."); - } - - // Check that the volume is not destroyed - if (volume.getState() == Volume.State.Destroy) { - throw new InvalidParameterValueException( - "Please specify a volume that is not destroyed."); - } - - // Check that the virtual machine ID is valid and it's a user vm - UserVmVO vm = _userVmDao.findById(vmId); - if (vm == null || vm.getType() != VirtualMachine.Type.User) { - throw new InvalidParameterValueException( - "Please specify a valid User VM."); - } - - // Check that the VM is in the correct state - if (vm.getState() != State.Running && vm.getState() != State.Stopped) { - throw new InvalidParameterValueException( - "Please specify a VM that is either running or stopped."); - } - - // Check that the device ID is valid - if (deviceId != null) { - if (deviceId.longValue() == 0) { - throw new InvalidParameterValueException( - "deviceId can't be 0, which is used by Root device"); - } - } - - // Check that the number of data volumes attached to VM is less than - // that supported by hypervisor - List existingDataVolumes = _volsDao.findByInstanceAndType( - vmId, Volume.Type.DATADISK); - int maxDataVolumesSupported = getMaxDataVolumesSupported(vm); - if (existingDataVolumes.size() >= maxDataVolumesSupported) { - throw new InvalidParameterValueException( - "The specified VM already has the maximum number of data disks (" - + maxDataVolumesSupported - + "). Please specify another VM."); - } - - // Check that the VM and the volume are in the same zone - if (vm.getDataCenterId() != volume.getDataCenterId()) { - throw new InvalidParameterValueException( - "Please specify a VM that is in the same zone as the volume."); - } - - // If local storage is disabled then attaching a volume with local disk - // offering not allowed - DataCenterVO dataCenter = _dcDao.findById(volume.getDataCenterId()); - if (!dataCenter.isLocalStorageEnabled()) { - DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume - .getDiskOfferingId()); - if (diskOffering.getUseLocalStorage()) { - throw new InvalidParameterValueException( - "Zone is not configured to use local storage but volume's disk offering " - + diskOffering.getName() + " uses it"); - } - } - - // if target VM has associated VM snapshots - List vmSnapshots = _vmSnapshotDao.findByVm(vmId); - if(vmSnapshots.size() > 0){ - throw new InvalidParameterValueException( - "Unable to attach volume, please specify a VM that does not have VM snapshots"); - } - - // permission check - _accountMgr.checkAccess(caller, null, true, volume, vm); - - if (!(Volume.State.Allocated.equals(volume.getState()) - || Volume.State.Ready.equals(volume.getState()) || Volume.State.Uploaded - .equals(volume.getState()))) { - throw new InvalidParameterValueException( - "Volume state must be in Allocated, Ready or in Uploaded state"); - } - - VolumeVO rootVolumeOfVm = null; - List rootVolumesOfVm = _volsDao.findByInstanceAndType(vmId, - Volume.Type.ROOT); - if (rootVolumesOfVm.size() != 1) { - throw new CloudRuntimeException( - "The VM " - + vm.getHostName() - + " has more than one ROOT volume and is in an invalid state."); - } else { - rootVolumeOfVm = rootVolumesOfVm.get(0); - } - - HypervisorType rootDiskHyperType = vm.getHypervisorType(); - - HypervisorType dataDiskHyperType = _volsDao.getHypervisorType(volume - .getId()); - if (dataDiskHyperType != HypervisorType.None - && rootDiskHyperType != dataDiskHyperType) { - throw new InvalidParameterValueException( - "Can't attach a volume created by: " + dataDiskHyperType - + " to a " + rootDiskHyperType + " vm"); - } - - - deviceId = getDeviceId(vmId, deviceId); - VolumeInfo volumeOnPrimaryStorage = volume; - - // Check if volume is stored on secondary storage - boolean isVolumeOnSec = false; - VolumeInfo volOnSecondary = volFactory.getVolume(volume.getId(), DataStoreRole.Image); - if (volOnSecondary != null) { - isVolumeOnSec = true; - if(volOnSecondary.getState() != Volume.State.Uploaded) { - throw new InvalidParameterValueException("Volume is not uploaded yet. Please try this operation once the volume is uploaded"); - } - } - - boolean createVolumeOnBackend = true; - if (rootVolumeOfVm.getState() == Volume.State.Allocated) { - createVolumeOnBackend = false; - if(isVolumeOnSec) { - throw new CloudRuntimeException("Cant attach uploaded volume to the vm which is not created. Please start it and then retry"); - } - } - - // Create volume on the backend only when VM's root volume is allocated - if (createVolumeOnBackend) { - if (volume.getState().equals(Volume.State.Allocated) - || volume.getState() == Volume.State.Uploaded) { - try { - volumeOnPrimaryStorage = createVolumeOnPrimaryStorage(vm, rootVolumeOfVm, volume, rootDiskHyperType); - } catch (NoTransitionException e) { - s_logger.debug("Failed to create volume on primary storage", e); - throw new CloudRuntimeException("Failed to create volume on primary storage", e); - } - } - - // reload the volume from db - volumeOnPrimaryStorage = volFactory.getVolume(volumeOnPrimaryStorage.getId()); - boolean moveVolumeNeeded = needMoveVolume(rootVolumeOfVm, volumeOnPrimaryStorage); - - if (moveVolumeNeeded) { - PrimaryDataStoreInfo primaryStore = (PrimaryDataStoreInfo)volumeOnPrimaryStorage.getDataStore(); - if (primaryStore.isLocal()) { - throw new CloudRuntimeException( - "Failed to attach local data volume " - + volume.getName() - + " to VM " - + vm.getDisplayName() - + " as migration of local data volume is not allowed"); - } - StoragePoolVO vmRootVolumePool = _storagePoolDao - .findById(rootVolumeOfVm.getPoolId()); - - try { - volumeOnPrimaryStorage = moveVolume(volumeOnPrimaryStorage, - vmRootVolumePool.getDataCenterId(), - vmRootVolumePool.getPodId(), - vmRootVolumePool.getClusterId(), - dataDiskHyperType); - } catch (ConcurrentOperationException e) { - s_logger.debug("move volume failed", e); - throw new CloudRuntimeException("move volume failed", e); - } - } - } - - - AsyncJobExecutionContext asyncExecutionContext = AsyncJobExecutionContext.getCurrentExecutionContext(); - - if (asyncExecutionContext != null) { - AsyncJob job = asyncExecutionContext.getJob(); - - if (s_logger.isInfoEnabled()) { - s_logger.info("Trying to attaching volume " + volumeId - + " to vm instance:" + vm.getId() - + ", update async job-" + job.getId() - + " progress status"); - } - - _asyncMgr.updateAsyncJobAttachment(job.getId(), "volume", volumeId); - _asyncMgr.updateAsyncJobStatus(job.getId(), BaseCmd.PROGRESS_INSTANCE_CREATED, Long.toString(volumeId)); - } - - VolumeVO newVol = _volumeDao.findById(volumeOnPrimaryStorage.getId()); - newVol = sendAttachVolumeCommand(vm, newVol, deviceId); - return newVol; - } - - @Override - public Volume updateVolume(UpdateVolumeCmd cmd){ - Long volumeId = cmd.getId(); - String path = cmd.getPath(); - - if(path == null){ - throw new InvalidParameterValueException("Failed to update the volume as path was null"); - } - - VolumeVO volume = ApiDBUtils.findVolumeById(volumeId); - volume.setPath(path); - _volumeDao.update(volumeId, volume); - - return volume; - } - - - @Override - @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DETACH, eventDescription = "detaching volume", async = true) - public Volume detachVolumeFromVM(DetachVolumeCmd cmmd) { - Account caller = CallContext.current().getCallingAccount(); - if ((cmmd.getId() == null && cmmd.getDeviceId() == null && cmmd - .getVirtualMachineId() == null) - || (cmmd.getId() != null && (cmmd.getDeviceId() != null || cmmd - .getVirtualMachineId() != null)) - || (cmmd.getId() == null && (cmmd.getDeviceId() == null || cmmd - .getVirtualMachineId() == null))) { - throw new InvalidParameterValueException( - "Please provide either a volume id, or a tuple(device id, instance id)"); - } - - Long volumeId = cmmd.getId(); - VolumeVO volume = null; - - if (volumeId != null) { - volume = _volsDao.findById(volumeId); - } else { - volume = _volsDao.findByInstanceAndDeviceId( - cmmd.getVirtualMachineId(), cmmd.getDeviceId()).get(0); - } - - Long vmId = null; - - if (cmmd.getVirtualMachineId() == null) { - vmId = volume.getInstanceId(); - } else { - vmId = cmmd.getVirtualMachineId(); - } - - // Check that the volume ID is valid - if (volume == null) { - throw new InvalidParameterValueException( - "Unable to find volume with ID: " + volumeId); - } - - // Permissions check - _accountMgr.checkAccess(caller, null, true, volume); - - // Check that the volume is a data volume - if (volume.getVolumeType() != Volume.Type.DATADISK) { - throw new InvalidParameterValueException( - "Please specify a data volume."); - } - - // Check that the volume is currently attached to a VM - if (vmId == null) { - throw new InvalidParameterValueException( - "The specified volume is not attached to a VM."); - } - - // Check that the VM is in the correct state - UserVmVO vm = _userVmDao.findById(vmId); - if (vm.getState() != State.Running && vm.getState() != State.Stopped - && vm.getState() != State.Destroyed) { - throw new InvalidParameterValueException( - "Please specify a VM that is either running or stopped."); - } - - AsyncJobExecutionContext asyncExecutionContext = AsyncJobExecutionContext.getCurrentExecutionContext(); - if (asyncExecutionContext != null) { - AsyncJob job = asyncExecutionContext.getJob(); - - if (s_logger.isInfoEnabled()) { - s_logger.info("Trying to attaching volume " + volumeId - + "to vm instance:" + vm.getId() - + ", update async job-" + job.getId() - + " progress status"); - } - - _asyncMgr.updateAsyncJobAttachment(job.getId(), "volume", volumeId); - _asyncMgr.updateAsyncJobStatus(job.getId(), BaseCmd.PROGRESS_INSTANCE_CREATED, volumeId.toString()); - } - - String errorMsg = "Failed to detach volume: " + volume.getName() - + " from VM: " + vm.getHostName(); - boolean sendCommand = (vm.getState() == State.Running); - Answer answer = null; - - if (sendCommand) { - StoragePoolVO volumePool = _storagePoolDao.findById(volume.getPoolId()); - - DataTO volTO = volFactory.getVolume(volume.getId()).getTO(); - DiskTO disk = new DiskTO(volTO, volume.getDeviceId(), null, volume.getVolumeType()); - - DettachCommand cmd = new DettachCommand(disk, vm.getInstanceName()); - - cmd.setManaged(volumePool.isManaged()); - - cmd.setStorageHost(volumePool.getHostAddress()); - cmd.setStoragePort(volumePool.getPort()); - - cmd.set_iScsiName(volume.get_iScsiName()); - - try { - answer = _agentMgr.send(vm.getHostId(), cmd); - } catch (Exception e) { - throw new CloudRuntimeException(errorMsg + " due to: " - + e.getMessage()); - } - } - - if (!sendCommand || (answer != null && answer.getResult())) { - // Mark the volume as detached - _volsDao.detachVolume(volume.getId()); - - return _volsDao.findById(volumeId); - } else { - - if (answer != null) { - String details = answer.getDetails(); - if (details != null && !details.isEmpty()) { - errorMsg += "; " + details; - } - } - - throw new CloudRuntimeException(errorMsg); - } - } - @DB - protected VolumeVO switchVolume(VolumeVO existingVolume, - VirtualMachineProfile vm) - throws StorageUnavailableException { + protected VolumeVO switchVolume(VolumeVO existingVolume, VirtualMachineProfile vm) throws StorageUnavailableException { Transaction txn = Transaction.currentTxn(); Long templateIdToUse = null; @@ -2069,18 +682,14 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { long vmTemplateId = vm.getTemplateId(); if (volTemplateId != null && volTemplateId.longValue() != vmTemplateId) { if (s_logger.isDebugEnabled()) { - s_logger.debug("switchVolume: Old Volume's templateId: " - + volTemplateId - + " does not match the VM's templateId: " - + vmTemplateId - + ", updating templateId in the new Volume"); + s_logger.debug("switchVolume: Old Volume's templateId: " + volTemplateId + " does not match the VM's templateId: " + vmTemplateId + + ", updating templateId in the new Volume"); } templateIdToUse = vmTemplateId; } txn.start(); - VolumeVO newVolume = allocateDuplicateVolume(existingVolume, - templateIdToUse); + VolumeVO newVolume = allocateDuplicateVolumeVO(existingVolume, templateIdToUse); // In case of Vmware if vm reference is not removed then during root // disk cleanup // the vm also gets deleted, so remove the reference @@ -2097,13 +706,11 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { } - @Override public void release(VirtualMachineProfile profile) { // add code here } - @Override @DB public void cleanupVolumes(long vmId) throws ConcurrentOperationException { @@ -2117,9 +724,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { for (VolumeVO vol : volumesForVm) { if (vol.getVolumeType().equals(Type.ROOT)) { // Destroy volume if not already destroyed - boolean volumeAlreadyDestroyed = (vol.getState() == Volume.State.Destroy || - vol.getState() == Volume.State.Expunged || - vol.getState() == Volume.State.Expunging); + boolean volumeAlreadyDestroyed = (vol.getState() == Volume.State.Destroy || vol.getState() == Volume.State.Expunged || vol.getState() == Volume.State.Expunging); if (!volumeAlreadyDestroyed) { volService.destroyVolume(vol.getId()); } else { @@ -2147,79 +752,9 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { } } - @DB @Override - public Volume migrateVolume(MigrateVolumeCmd cmd) { - Long volumeId = cmd.getVolumeId(); - Long storagePoolId = cmd.getStoragePoolId(); - - VolumeVO vol = _volsDao.findById(volumeId); - if (vol == null) { - throw new InvalidParameterValueException( - "Failed to find the volume id: " + volumeId); - } - - if (vol.getState() != Volume.State.Ready) { - throw new InvalidParameterValueException( - "Volume must be in ready state"); - } - - if (storagePoolId == vol.getPoolId()) { - throw new InvalidParameterValueException("Specified destination pool and the current volume storage pool are same"); - } - - boolean liveMigrateVolume = false; - Long instanceId = vol.getInstanceId(); - VMInstanceVO vm = null; - if (instanceId != null) { - vm = _vmInstanceDao.findById(instanceId); - } - - if (vm != null && vm.getState() == State.Running) { - // Check if the underlying hypervisor supports storage motion. - Long hostId = vm.getHostId(); - if (hostId != null) { - HostVO host = _hostDao.findById(hostId); - HypervisorCapabilitiesVO capabilities = null; - if (host != null) { - capabilities = _hypervisorCapabilitiesDao.findByHypervisorTypeAndVersion(host.getHypervisorType(), - host.getHypervisorVersion()); - } - - if (capabilities != null) { - liveMigrateVolume = capabilities.isStorageMotionSupported(); - } - } - } - - if (liveMigrateVolume && !cmd.isLiveMigrate()) { - throw new InvalidParameterValueException("The volume " + vol + "is attached to a vm and for migrating it " + - "the parameter livemigrate should be specified"); - } - - StoragePool destPool = (StoragePool)dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); - if (destPool == null) { - throw new InvalidParameterValueException( - "Failed to find the destination storage pool: " - + storagePoolId); - } - - if (!volumeOnSharedStoragePool(vol)) { - throw new InvalidParameterValueException( - "Migration of volume from local storage pool is not supported"); - } - - Volume newVol = null; - if (liveMigrateVolume) { - newVol = liveMigrateVolume(vol, destPool); - } else { - newVol = migrateVolume(vol, destPool); - } - return newVol; - } - @DB - protected Volume migrateVolume(Volume volume, StoragePool destPool) { + public Volume migrateVolume(Volume volume, StoragePool destPool) { VolumeInfo vol = volFactory.getVolume(volume.getId()); AsyncCallFuture future = volService.copyVolume(vol, (DataStore)destPool); try { @@ -2259,8 +794,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { } @Override - public void migrateVolumes(VirtualMachine vm, VirtualMachineTO vmTo, Host srcHost, Host destHost, - Map volumeToPool) { + public void migrateVolumes(VirtualMachine vm, VirtualMachineTO vmTo, Host srcHost, Host destHost, Map volumeToPool) { // Check if all the vms being migrated belong to the vm. // Check if the storage pool is of the right type. // Create a VolumeInfo to DataStore map too. @@ -2268,12 +802,10 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { for (Map.Entry entry : volumeToPool.entrySet()) { Volume volume = entry.getKey(); StoragePool storagePool = entry.getValue(); - StoragePool destPool = (StoragePool)dataStoreMgr.getDataStore(storagePool.getId(), - DataStoreRole.Primary); + StoragePool destPool = (StoragePool)dataStoreMgr.getDataStore(storagePool.getId(), DataStoreRole.Primary); if (volume.getInstanceId() != vm.getId()) { - throw new CloudRuntimeException("Volume " + volume + " that has to be migrated doesn't belong to the" + - " instance " + vm); + throw new CloudRuntimeException("Volume " + volume + " that has to be migrated doesn't belong to the" + " instance " + vm); } if (destPool == null) { @@ -2288,8 +820,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { CommandResult result = future.get(); if (result.isFailed()) { s_logger.debug("Failed to migrated vm " + vm + " along with its volumes. " + result.getResult()); - throw new CloudRuntimeException("Failed to migrated vm " + vm + " along with its volumes. " + - result.getResult()); + throw new CloudRuntimeException("Failed to migrated vm " + vm + " along with its volumes. " + result.getResult()); } } catch (InterruptedException e) { s_logger.debug("Failed to migrated vm " + vm + " along with its volumes.", e); @@ -2299,23 +830,18 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { } @Override - public boolean storageMigration( - VirtualMachineProfile vm, - StoragePool destPool) { + public boolean storageMigration(VirtualMachineProfile vm, StoragePool destPool) { List vols = _volsDao.findUsableVolumesForInstance(vm.getId()); List volumesNeedToMigrate = new ArrayList(); for (VolumeVO volume : vols) { if (volume.getState() != Volume.State.Ready) { - s_logger.debug("volume: " + volume.getId() + " is in " - + volume.getState() + " state"); - throw new CloudRuntimeException("volume: " + volume.getId() - + " is in " + volume.getState() + " state"); + s_logger.debug("volume: " + volume.getId() + " is in " + volume.getState() + " state"); + throw new CloudRuntimeException("volume: " + volume.getId() + " is in " + volume.getState() + " state"); } if (volume.getPoolId() == destPool.getId()) { - s_logger.debug("volume: " + volume.getId() - + " is on the same storage pool: " + destPool.getId()); + s_logger.debug("volume: " + volume.getId() + " is on the same storage pool: " + destPool.getId()); continue; } @@ -2337,9 +863,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { } @Override - public void prepareForMigration( - VirtualMachineProfile vm, - DeployDestination dest) { + public void prepareForMigration(VirtualMachineProfile vm, DeployDestination dest) { List vols = _volsDao.findUsableVolumesForInstance(vm.getId()); if (s_logger.isDebugEnabled()) { s_logger.debug("Preparing " + vols.size() + " volumes for " + vm); @@ -2358,17 +882,15 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { } } - - private static enum VolumeTaskType { - RECREATE, - NOP, - MIGRATE + RECREATE, NOP, MIGRATE } + private static class VolumeTask { final VolumeTaskType type; final StoragePoolVO pool; final VolumeVO volume; + VolumeTask(VolumeTaskType type, VolumeVO volume, StoragePoolVO pool) { this.type = type; this.pool = pool; @@ -2392,54 +914,37 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { } if (assignedPool != null || recreate) { Volume.State state = vol.getState(); - if (state == Volume.State.Allocated - || state == Volume.State.Creating) { + if (state == Volume.State.Allocated || state == Volume.State.Creating) { VolumeTask task = new VolumeTask(VolumeTaskType.RECREATE, vol, null); tasks.add(task); } else { if (vol.isRecreatable()) { if (s_logger.isDebugEnabled()) { - s_logger.debug("Volume " + vol - + " will be recreated on storage pool " - + assignedPool - + " assigned by deploymentPlanner"); + s_logger.debug("Volume " + vol + " will be recreated on storage pool " + assignedPool + " assigned by deploymentPlanner"); } VolumeTask task = new VolumeTask(VolumeTaskType.RECREATE, vol, null); tasks.add(task); } else { if (assignedPool.getId() != vol.getPoolId()) { if (s_logger.isDebugEnabled()) { - s_logger.debug("Mismatch in storage pool " - + assignedPool - + " assigned by deploymentPlanner and the one associated with volume " - + vol); + s_logger.debug("Mismatch in storage pool " + assignedPool + " assigned by deploymentPlanner and the one associated with volume " + vol); } - DiskOfferingVO diskOffering = _diskOfferingDao - .findById(vol.getDiskOfferingId()); + DiskOffering diskOffering = _entityMgr.findById(DiskOffering.class, vol.getDiskOfferingId()); if (diskOffering.getUseLocalStorage()) { // Currently migration of local volume is not supported so bail out if (s_logger.isDebugEnabled()) { - s_logger.debug("Local volume " - + vol - + " cannot be recreated on storagepool " - + assignedPool - + " assigned by deploymentPlanner"); + s_logger.debug("Local volume " + vol + " cannot be recreated on storagepool " + assignedPool + " assigned by deploymentPlanner"); } throw new CloudRuntimeException("Local volume " + vol + " cannot be recreated on storagepool " + assignedPool + " assigned by deploymentPlanner"); } else { if (s_logger.isDebugEnabled()) { - s_logger.debug("Shared volume " - + vol - + " will be migrated on storage pool " - + assignedPool - + " assigned by deploymentPlanner"); + s_logger.debug("Shared volume " + vol + " will be migrated on storage pool " + assignedPool + " assigned by deploymentPlanner"); } VolumeTask task = new VolumeTask(VolumeTaskType.MIGRATE, vol, assignedPool); tasks.add(task); } } else { - StoragePoolVO pool = _storagePoolDao - .findById(vol.getPoolId()); + StoragePoolVO pool = _storagePoolDao.findById(vol.getPoolId()); VolumeTask task = new VolumeTask(VolumeTaskType.NOP, vol, pool); tasks.add(task); } @@ -2448,17 +953,14 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { } } else { if (vol.getPoolId() == null) { - throw new StorageUnavailableException( - "Volume has no pool associate and also no storage pool assigned in DeployDestination, Unable to create " - + vol, Volume.class, vol.getId()); + throw new StorageUnavailableException("Volume has no pool associate and also no storage pool assigned in DeployDestination, Unable to create " + vol, + Volume.class, + vol.getId()); } if (s_logger.isDebugEnabled()) { - s_logger.debug("No need to recreate the volume: " + vol - + ", since it already has a pool assigned: " - + vol.getPoolId() + ", adding disk to VM"); + s_logger.debug("No need to recreate the volume: " + vol + ", since it already has a pool assigned: " + vol.getPoolId() + ", adding disk to VM"); } - StoragePoolVO pool = _storagePoolDao.findById(vol - .getPoolId()); + StoragePoolVO pool = _storagePoolDao.findById(vol.getPoolId()); VolumeTask task = new VolumeTask(VolumeTaskType.NOP, vol, pool); tasks.add(task); } @@ -2467,14 +969,11 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { return tasks; } - private Pair recreateVolume(VolumeVO vol, VirtualMachineProfile vm, - DeployDestination dest) throws StorageUnavailableException { + private Pair recreateVolume(VolumeVO vol, VirtualMachineProfile vm, DeployDestination dest) throws StorageUnavailableException { VolumeVO newVol; boolean recreate = _recreateSystemVmEnabled; DataStore destPool = null; - if (recreate - && (dest.getStorageForDisks() == null || dest - .getStorageForDisks().get(vol) == null)) { + if (recreate && (dest.getStorageForDisks() == null || dest.getStorageForDisks().get(vol) == null)) { destPool = dataStoreMgr.getDataStore(vol.getPoolId(), DataStoreRole.Primary); s_logger.debug("existing pool: " + destPool.getId()); } else { @@ -2482,23 +981,19 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { destPool = dataStoreMgr.getDataStore(pool.getId(), DataStoreRole.Primary); } - if (vol.getState() == Volume.State.Allocated - || vol.getState() == Volume.State.Creating) { + if (vol.getState() == Volume.State.Allocated || vol.getState() == Volume.State.Creating) { newVol = vol; } else { newVol = switchVolume(vol, vm); // update the volume->PrimaryDataStoreVO map since volumeId has // changed - if (dest.getStorageForDisks() != null - && dest.getStorageForDisks().containsKey(vol)) { - StoragePool poolWithOldVol = dest - .getStorageForDisks().get(vol); + if (dest.getStorageForDisks() != null && dest.getStorageForDisks().containsKey(vol)) { + StoragePool poolWithOldVol = dest.getStorageForDisks().get(vol); dest.getStorageForDisks().put(newVol, poolWithOldVol); dest.getStorageForDisks().remove(vol); } if (s_logger.isDebugEnabled()) { - s_logger.debug("Created new volume " + newVol - + " for old volume " + vol); + s_logger.debug("Created new volume " + newVol + " for old volume " + vol); } } VolumeInfo volume = volFactory.getVolume(newVol.getId(), destPool); @@ -2514,43 +1009,33 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { try { result = future.get(); if (result.isFailed()) { - s_logger.debug("Unable to create " - + newVol + ":" + result.getResult()); - throw new StorageUnavailableException("Unable to create " - + newVol + ":" + result.getResult(), destPool.getId()); + s_logger.debug("Unable to create " + newVol + ":" + result.getResult()); + throw new StorageUnavailableException("Unable to create " + newVol + ":" + result.getResult(), destPool.getId()); } newVol = _volsDao.findById(newVol.getId()); } catch (InterruptedException e) { s_logger.error("Unable to create " + newVol, e); - throw new StorageUnavailableException("Unable to create " - + newVol + ":" + e.toString(), destPool.getId()); + throw new StorageUnavailableException("Unable to create " + newVol + ":" + e.toString(), destPool.getId()); } catch (ExecutionException e) { s_logger.error("Unable to create " + newVol, e); - throw new StorageUnavailableException("Unable to create " - + newVol + ":" + e.toString(), destPool.getId()); + throw new StorageUnavailableException("Unable to create " + newVol + ":" + e.toString(), destPool.getId()); } return new Pair(newVol, destPool); } @Override - public void prepare(VirtualMachineProfile vm, - DeployDestination dest) throws StorageUnavailableException, - InsufficientStorageCapacityException, ConcurrentOperationException { + public void prepare(VirtualMachineProfile vm, DeployDestination dest) throws StorageUnavailableException, InsufficientStorageCapacityException, ConcurrentOperationException { if (dest == null) { if (s_logger.isDebugEnabled()) { - s_logger.debug("DeployDestination cannot be null, cannot prepare Volumes for the vm: " - + vm); + s_logger.debug("DeployDestination cannot be null, cannot prepare Volumes for the vm: " + vm); } - throw new CloudRuntimeException( - "Unable to prepare Volume for vm because DeployDestination is null, vm:" - + vm); + throw new CloudRuntimeException("Unable to prepare Volume for vm because DeployDestination is null, vm:" + vm); } List vols = _volsDao.findUsableVolumesForInstance(vm.getId()); if (s_logger.isDebugEnabled()) { - s_logger.debug("Checking if we need to prepare " + vols.size() - + " volumes for " + vm); + s_logger.debug("Checking if we need to prepare " + vols.size() + " volumes for " + vm); } List tasks = getTasks(vols, dest.getStorageForDisks()); @@ -2575,44 +1060,10 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { } } - private Long getDeviceId(long vmId, Long deviceId) { - // allocate deviceId - List vols = _volsDao.findByInstance(vmId); - if (deviceId != null) { - if (deviceId.longValue() > 15 || deviceId.longValue() == 0 - || deviceId.longValue() == 3) { - throw new RuntimeException("deviceId should be 1,2,4-15"); - } - for (VolumeVO vol : vols) { - if (vol.getDeviceId().equals(deviceId)) { - throw new RuntimeException("deviceId " + deviceId - + " is used by vm" + vmId); - } - } - } else { - // allocate deviceId here - List devIds = new ArrayList(); - for (int i = 1; i < 15; i++) { - devIds.add(String.valueOf(i)); - } - devIds.remove("3"); - for (VolumeVO vol : vols) { - devIds.remove(vol.getDeviceId().toString().trim()); - } - deviceId = Long.parseLong(devIds.iterator().next()); - } - - return deviceId; - } - - private boolean stateTransitTo(Volume vol, Volume.Event event) - throws NoTransitionException { + private boolean stateTransitTo(Volume vol, Volume.Event event) throws NoTransitionException { return _volStateMachine.transitTo(vol, event, null, _volsDao); } - - - @Override public boolean canVmRestartOnAnotherServer(long vmId) { List vols = _volsDao.findCreatedByInstance(vmId); @@ -2625,24 +1076,12 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { } @Override - public boolean configure(String name, Map params) - throws ConfigurationException { - String _customDiskOfferingMinSizeStr = _configDao - .getValue(Config.CustomDiskOfferingMinSize.toString()); - _customDiskOfferingMinSize = NumbersUtil.parseInt( - _customDiskOfferingMinSizeStr, Integer - .parseInt(Config.CustomDiskOfferingMinSize - .getDefaultValue())); - - String maxVolumeSizeInGbString = _configDao - .getValue("storage.max.volume.size"); - _maxVolumeSizeInGb = NumbersUtil.parseLong(maxVolumeSizeInGbString, - 2000); + public boolean configure(String name, Map params) throws ConfigurationException { + String maxVolumeSizeInGbString = _configDao.getValue("storage.max.volume.size"); + _maxVolumeSizeInGb = NumbersUtil.parseLong(maxVolumeSizeInGbString, 2000); String value = _configDao.getValue(Config.RecreateSystemVmEnabled.key()); _recreateSystemVmEnabled = Boolean.parseBoolean(value); - _copyvolumewait = NumbersUtil.parseInt(value, - Integer.parseInt(Config.CopyVolumeWait.getDefaultValue())); return true; } @@ -2663,7 +1102,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { } @Override - public void destroyVolume(VolumeVO volume) { + public void destroyVolume(Volume volume) { try { volService.destroyVolume(volume.getId()); } catch (ConcurrentOperationException e) { @@ -2672,181 +1111,6 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { } } - - @Override - public Snapshot takeSnapshot(Long volumeId, Long policyId, Long snapshotId, Account account) throws ResourceAllocationException { - VolumeInfo volume = volFactory.getVolume(volumeId); - if (volume == null) { - throw new InvalidParameterValueException("Creating snapshot failed due to volume:" + volumeId + " doesn't exist"); - } - - if (volume.getState() != Volume.State.Ready) { - throw new InvalidParameterValueException("VolumeId: " + volumeId + " is not in " + Volume.State.Ready + " state but " + volume.getState() + ". Cannot take snapshot."); - } - - CreateSnapshotPayload payload = new CreateSnapshotPayload(); - payload.setSnapshotId(snapshotId); - payload.setSnapshotPolicyId(policyId); - payload.setAccount(account); - volume.addPayload(payload); - return volService.takeSnapshot(volume); - } - - @Override - public Snapshot allocSnapshot(Long volumeId, Long policyId) throws ResourceAllocationException { - Account caller = CallContext.current().getCallingAccount(); - - VolumeInfo volume = volFactory.getVolume(volumeId); - if (volume == null) { - throw new InvalidParameterValueException("Creating snapshot failed due to volume:" + volumeId + " doesn't exist"); - } - DataCenter zone = _dcDao.findById(volume.getDataCenterId()); - if (zone == null) { - throw new InvalidParameterValueException("Can't find zone by id " + volume.getDataCenterId()); - } - - if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getType())) { - throw new PermissionDeniedException("Cannot perform this operation, Zone is currently disabled: " + zone.getName()); - } - - if (volume.getState() != Volume.State.Ready) { - throw new InvalidParameterValueException("VolumeId: " + volumeId + " is not in " + Volume.State.Ready + " state but " + volume.getState() + ". Cannot take snapshot."); - } - - if ( volume.getTemplateId() != null ) { - VMTemplateVO template = _templateDao.findById(volume.getTemplateId()); - if( template != null && template.getTemplateType() == Storage.TemplateType.SYSTEM ) { - throw new InvalidParameterValueException("VolumeId: " + volumeId + " is for System VM , Creating snapshot against System VM volumes is not supported"); - } - } - - StoragePool storagePool = (StoragePool)volume.getDataStore(); - if (storagePool == null) { - throw new InvalidParameterValueException("VolumeId: " + volumeId + " please attach this volume to a VM before create snapshot for it"); - } - - return snapshotMgr.allocSnapshot(volumeId, policyId); - } - - - @Override - @ActionEvent(eventType = EventTypes.EVENT_VOLUME_EXTRACT, eventDescription = "extracting volume", async = true) - public String extractVolume(ExtractVolumeCmd cmd) { - Long volumeId = cmd.getId(); - Long zoneId = cmd.getZoneId(); - String mode = cmd.getMode(); - Account account = CallContext.current().getCallingAccount(); - - if (!_accountMgr.isRootAdmin(account.getType()) && ApiDBUtils.isExtractionDisabled()) { - throw new PermissionDeniedException("Extraction has been disabled by admin"); - } - - VolumeVO volume = _volumeDao.findById(volumeId); - if (volume == null) { - InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find volume with specified volumeId"); - ex.addProxyObject(volumeId.toString(), "volumeId"); - throw ex; - } - - // perform permission check - _accountMgr.checkAccess(account, null, true, volume); - - if (_dcDao.findById(zoneId) == null) { - throw new InvalidParameterValueException("Please specify a valid zone."); - } - if (volume.getPoolId() == null) { - throw new InvalidParameterValueException("The volume doesnt belong to a storage pool so cant extract it"); - } - // Extract activity only for detached volumes or for volumes whose - // instance is stopped - if (volume.getInstanceId() != null && ApiDBUtils.findVMInstanceById(volume.getInstanceId()).getState() != State.Stopped) { - s_logger.debug("Invalid state of the volume with ID: " + volumeId - + ". It should be either detached or the VM should be in stopped state."); - PermissionDeniedException ex = new PermissionDeniedException( - "Invalid state of the volume with specified ID. It should be either detached or the VM should be in stopped state."); - ex.addProxyObject(volume.getUuid(), "volumeId"); - throw ex; - } - - if (volume.getVolumeType() != Volume.Type.DATADISK) { - // Datadisk dont have any template dependence. - - VMTemplateVO template = ApiDBUtils.findTemplateById(volume.getTemplateId()); - if (template != null) { // For ISO based volumes template = null and - // we allow extraction of all ISO based - // volumes - boolean isExtractable = template.isExtractable() && template.getTemplateType() != Storage.TemplateType.SYSTEM; - if (!isExtractable && account != null && account.getType() != Account.ACCOUNT_TYPE_ADMIN) { - // Global admins are always allowed to extract - PermissionDeniedException ex = new PermissionDeniedException("The volume with specified volumeId is not allowed to be extracted"); - ex.addProxyObject(volume.getUuid(), "volumeId"); - throw ex; - } - } - } - - Upload.Mode extractMode; - if (mode == null || (!mode.equals(Upload.Mode.FTP_UPLOAD.toString()) && !mode.equals(Upload.Mode.HTTP_DOWNLOAD.toString()))) { - throw new InvalidParameterValueException("Please specify a valid extract Mode "); - } else { - extractMode = mode.equals(Upload.Mode.FTP_UPLOAD.toString()) ? Upload.Mode.FTP_UPLOAD : Upload.Mode.HTTP_DOWNLOAD; - } - - // Check if the url already exists - VolumeDataStoreVO volumeStoreRef = _volumeStoreDao.findByVolume(volumeId); - if(volumeStoreRef != null && volumeStoreRef.getExtractUrl() != null){ - return volumeStoreRef.getExtractUrl(); - } - - // Clean up code to remove all those previous uploadVO and uploadMonitor code. Previous code is trying to fake an async operation purely in - // db table with uploadVO and async_job entry, but internal implementation is actually synchronous. - ImageStoreEntity secStore = (ImageStoreEntity) dataStoreMgr.getImageStore(zoneId); - - // Copy volume from primary to secondary storage - VolumeInfo srcVol = volFactory.getVolume(volume.getId()); - AsyncCallFuture cvAnswer = volService.copyVolume(srcVol, secStore); - // Check if you got a valid answer. - VolumeApiResult cvResult = null; - try { - cvResult = cvAnswer.get(); - } catch (InterruptedException e1) { - s_logger.debug("failed copy volume", e1); - throw new CloudRuntimeException("Failed to copy volume", e1); - } catch (ExecutionException e1) { - s_logger.debug("failed copy volume", e1); - throw new CloudRuntimeException("Failed to copy volume", e1); - } - if (cvResult == null || cvResult.isFailed()) { - String errorString = "Failed to copy the volume from the source primary storage pool to secondary storage."; - throw new CloudRuntimeException(errorString); - } - - VolumeInfo vol = cvResult.getVolume(); - - String extractUrl = secStore.createEntityExtractUrl(vol.getPath(), vol.getFormat(), vol); - volumeStoreRef = _volumeStoreDao.findByVolume(volumeId); - volumeStoreRef.setExtractUrl(extractUrl); - _volumeStoreDao.update(volumeStoreRef.getId(), volumeStoreRef); - - return extractUrl; - } - - private String getFormatForPool(StoragePool pool) { - ClusterVO cluster = ApiDBUtils.findClusterById(pool.getClusterId()); - - if (cluster.getHypervisorType() == HypervisorType.XenServer) { - return "vhd"; - } else if (cluster.getHypervisorType() == HypervisorType.KVM) { - return "qcow2"; - } else if (cluster.getHypervisorType() == HypervisorType.VMware) { - return "ova"; - } else if (cluster.getHypervisorType() == HypervisorType.Ovm) { - return "raw"; - } else { - return null; - } - } - @Override public String getVmNameFromVolumeId(long volumeId) { VolumeVO volume = _volsDao.findById(volumeId); diff --git a/server/src/com/cloud/resource/ResourceManager.java b/server/src/com/cloud/resource/ResourceManager.java index e35e89a20c2..6efe867568b 100755 --- a/server/src/com/cloud/resource/ResourceManager.java +++ b/server/src/com/cloud/resource/ResourceManager.java @@ -22,6 +22,7 @@ import java.util.Set; import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupRoutingCommand; +import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; import com.cloud.dc.Pod; @@ -33,8 +34,8 @@ import com.cloud.host.HostStats; import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.offering.ServiceOffering; import com.cloud.resource.ResourceState.Event; -import com.cloud.service.ServiceOfferingVO; import com.cloud.template.VirtualMachineTemplate; import com.cloud.utils.Pair; import com.cloud.utils.fsm.NoTransitionException; @@ -124,7 +125,7 @@ public interface ResourceManager extends ResourceService { * @param userId * @return */ - Pair findPod(VirtualMachineTemplate template, ServiceOfferingVO offering, DataCenterVO dc, long accountId, Set avoids); + Pair findPod(VirtualMachineTemplate template, ServiceOffering offering, DataCenter dc, long accountId, Set avoids); HostStats getHostStatistics(long hostId); diff --git a/server/src/com/cloud/resource/ResourceManagerImpl.java b/server/src/com/cloud/resource/ResourceManagerImpl.java index 090b7ca06d6..23ebfe3a12d 100755 --- a/server/src/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/com/cloud/resource/ResourceManagerImpl.java @@ -20,12 +20,12 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URLDecoder; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.Collections; import javax.ejb.Local; import javax.inject.Inject; @@ -80,6 +80,7 @@ import com.cloud.configuration.ConfigurationManager; import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.ClusterDetailsVO; import com.cloud.dc.ClusterVO; +import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.DataCenterIpAddressVO; import com.cloud.dc.DataCenterVO; @@ -119,12 +120,12 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.kvm.discoverer.KvmDummyResourceBase; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.IPAddressVO; +import com.cloud.offering.ServiceOffering; import com.cloud.org.Cluster; import com.cloud.org.Grouping; import com.cloud.org.Grouping.AllocationState; import com.cloud.org.Managed; import com.cloud.serializer.GsonHelper; -import com.cloud.service.ServiceOfferingVO; import com.cloud.storage.GuestOSCategoryVO; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; @@ -2449,7 +2450,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, } @Override - public Pair findPod(VirtualMachineTemplate template, ServiceOfferingVO offering, DataCenterVO dc, long accountId, + public Pair findPod(VirtualMachineTemplate template, ServiceOffering offering, DataCenter dc, long accountId, Set avoids) { for (PodAllocator allocator : _podAllocators) { final Pair pod = allocator.allocateTo(template, offering, dc, accountId, avoids); diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index 4e61380e539..23e713ef059 100755 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -31,6 +31,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Random; +import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; diff --git a/server/test/com/cloud/resource/MockResourceManagerImpl.java b/server/test/com/cloud/resource/MockResourceManagerImpl.java index 6beb0648573..651badcf3eb 100644 --- a/server/test/com/cloud/resource/MockResourceManagerImpl.java +++ b/server/test/com/cloud/resource/MockResourceManagerImpl.java @@ -26,10 +26,17 @@ import javax.naming.ConfigurationException; import org.apache.cloudstack.api.command.admin.cluster.AddClusterCmd; import org.apache.cloudstack.api.command.admin.cluster.DeleteClusterCmd; -import org.apache.cloudstack.api.command.admin.host.*; -import org.apache.cloudstack.api.command.admin.storage.*; +import org.apache.cloudstack.api.command.admin.host.AddHostCmd; +import org.apache.cloudstack.api.command.admin.host.AddSecondaryStorageCmd; +import org.apache.cloudstack.api.command.admin.host.CancelMaintenanceCmd; +import org.apache.cloudstack.api.command.admin.host.PrepareForMaintenanceCmd; +import org.apache.cloudstack.api.command.admin.host.ReconnectHostCmd; +import org.apache.cloudstack.api.command.admin.host.UpdateHostCmd; +import org.apache.cloudstack.api.command.admin.host.UpdateHostPasswordCmd; + import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupRoutingCommand; +import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; import com.cloud.dc.Pod; @@ -44,10 +51,9 @@ import com.cloud.host.HostStats; import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.offering.ServiceOffering; import com.cloud.org.Cluster; import com.cloud.resource.ResourceState.Event; -import com.cloud.service.ServiceOfferingVO; -import com.cloud.storage.ImageStore; import com.cloud.template.VirtualMachineTemplate; import com.cloud.utils.Pair; import com.cloud.utils.component.ManagerBase; @@ -428,7 +434,7 @@ public class MockResourceManagerImpl extends ManagerBase implements ResourceMana * @see com.cloud.resource.ResourceManager#findPod(com.cloud.template.VirtualMachineTemplate, com.cloud.service.ServiceOfferingVO, com.cloud.dc.DataCenterVO, long, java.util.Set) */ @Override - public Pair findPod(VirtualMachineTemplate template, ServiceOfferingVO offering, DataCenterVO dc, + public Pair findPod(VirtualMachineTemplate template, ServiceOffering offering, DataCenter dc, long accountId, Set avoids) { // TODO Auto-generated method stub return null;