mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
refactor: migrate vm with storage (#5030)
* refactor: migrate with storage host capability check Refactors Boolean HypervisorCapabilitiesDao::isStorageMotionSupported to boolean HypervisorCapabilitiesDao::isStorageMotionSupported for simplifying callers. Refactors log messages. Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> * simplify Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> * refactor Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> * changes Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> * review comments addressed Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> * var rename Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
This commit is contained in:
parent
757bc2d917
commit
50a16979c5
@ -19,7 +19,6 @@ package com.cloud.storage;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
import com.cloud.agent.api.ModifyStoragePoolAnswer;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener;
|
||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||
@ -27,6 +26,7 @@ import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||
|
||||
import com.cloud.agent.api.Answer;
|
||||
import com.cloud.agent.api.Command;
|
||||
import com.cloud.agent.api.ModifyStoragePoolAnswer;
|
||||
import com.cloud.agent.api.StoragePoolInfo;
|
||||
import com.cloud.agent.api.to.DataTO;
|
||||
import com.cloud.agent.api.to.DiskTO;
|
||||
@ -252,7 +252,7 @@ public interface StorageManager extends StorageService {
|
||||
|
||||
boolean storagePoolCompatibleWithVolumePool(StoragePool pool, Volume volume);
|
||||
|
||||
boolean isStoragePoolComplaintWithStoragePolicy(List<Volume> volumes, StoragePool pool) throws StorageUnavailableException;
|
||||
boolean isStoragePoolCompliantWithStoragePolicy(List<Volume> volumes, StoragePool pool) throws StorageUnavailableException;
|
||||
|
||||
boolean registerHostListener(String providerUuid, HypervisorHostListener listener);
|
||||
|
||||
|
||||
@ -38,5 +38,5 @@ public interface HypervisorCapabilitiesDao extends GenericDao<HypervisorCapabili
|
||||
|
||||
List<HypervisorType> getHypervisorsWithDefaultEntries();
|
||||
|
||||
Boolean isStorageMotionSupported(HypervisorType hypervisorType, String hypervisorVersion);
|
||||
boolean isStorageMotionSupported(HypervisorType hypervisorType, String hypervisorVersion);
|
||||
}
|
||||
|
||||
@ -121,7 +121,7 @@ public class HypervisorCapabilitiesDaoImpl extends GenericDaoBase<HypervisorCapa
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isStorageMotionSupported(HypervisorType hypervisorType, String hypervisorVersion) {
|
||||
public boolean isStorageMotionSupported(HypervisorType hypervisorType, String hypervisorVersion) {
|
||||
HypervisorCapabilitiesVO hostCapabilities = findByHypervisorTypeAndVersion(hypervisorType, hypervisorVersion);
|
||||
if (hostCapabilities == null && HypervisorType.KVM.equals(hypervisorType)) {
|
||||
List<HypervisorCapabilitiesVO> hypervisorCapabilitiesList = listAllByHypervisorType(HypervisorType.KVM);
|
||||
|
||||
@ -241,7 +241,7 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement
|
||||
}
|
||||
|
||||
try {
|
||||
boolean isStoragePoolStoragepolicyComplaince = storageMgr.isStoragePoolComplaintWithStoragePolicy(requestVolumes, pool);
|
||||
boolean isStoragePoolStoragepolicyComplaince = storageMgr.isStoragePoolCompliantWithStoragePolicy(requestVolumes, pool);
|
||||
if (!isStoragePoolStoragepolicyComplaince) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1411,7 +1411,7 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
||||
hostCanAccessPool = true;
|
||||
if (potentialHost.getHypervisorType() == HypervisorType.VMware) {
|
||||
try {
|
||||
boolean isStoragePoolStoragepolicyComplaince = _storageMgr.isStoragePoolComplaintWithStoragePolicy(allVolumes, storagePool);
|
||||
boolean isStoragePoolStoragepolicyComplaince = _storageMgr.isStoragePoolCompliantWithStoragePolicy(allVolumes, storagePool);
|
||||
if (!isStoragePoolStoragepolicyComplaince) {
|
||||
continue;
|
||||
}
|
||||
@ -1450,7 +1450,7 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
||||
|
||||
if (potentialHost.getHypervisorType() == HypervisorType.VMware) {
|
||||
try {
|
||||
boolean isStoragePoolStoragepolicyComplaince = _storageMgr.isStoragePoolComplaintWithStoragePolicy(requestVolumes, potentialSPool);
|
||||
boolean isStoragePoolStoragepolicyComplaince = _storageMgr.isStoragePoolCompliantWithStoragePolicy(requestVolumes, potentialSPool);
|
||||
if (!isStoragePoolStoragepolicyComplaince) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1291,7 +1291,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
||||
boolean canMigrateWithStorage = false;
|
||||
|
||||
if (VirtualMachine.Type.User.equals(vm.getType()) || HypervisorType.VMware.equals(vm.getHypervisorType())) {
|
||||
canMigrateWithStorage = Boolean.TRUE.equals(_hypervisorCapabilitiesDao.isStorageMotionSupported(srcHost.getHypervisorType(), srcHostVersion));
|
||||
canMigrateWithStorage = _hypervisorCapabilitiesDao.isStorageMotionSupported(srcHost.getHypervisorType(), srcHostVersion);
|
||||
}
|
||||
|
||||
// Check if the vm is using any disks on local storage.
|
||||
@ -1345,11 +1345,8 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
||||
// source volume.
|
||||
iterator.remove();
|
||||
} else {
|
||||
boolean hostSupportsStorageMigration = false;
|
||||
if ((srcHostVersion != null && srcHostVersion.equals(hostVersion)) ||
|
||||
Boolean.TRUE.equals(_hypervisorCapabilitiesDao.isStorageMotionSupported(host.getHypervisorType(), hostVersion))) {
|
||||
hostSupportsStorageMigration = true;
|
||||
}
|
||||
boolean hostSupportsStorageMigration = (srcHostVersion != null && srcHostVersion.equals(hostVersion)) ||
|
||||
_hypervisorCapabilitiesDao.isStorageMotionSupported(host.getHypervisorType(), hostVersion);
|
||||
if (hostSupportsStorageMigration && hasSuitablePoolsForVolume(volume, host, vmProfile)) {
|
||||
requiresStorageMotion.put(host, true);
|
||||
} else {
|
||||
|
||||
@ -16,6 +16,8 @@
|
||||
// under the License.
|
||||
package com.cloud.storage;
|
||||
|
||||
import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
@ -29,11 +31,11 @@ import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
@ -41,11 +43,6 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.cloud.agent.api.to.StorageFilerTO;
|
||||
import com.cloud.dc.VsphereStoragePolicyVO;
|
||||
import com.cloud.dc.dao.VsphereStoragePolicyDao;
|
||||
import com.cloud.service.dao.ServiceOfferingDetailsDao;
|
||||
import com.cloud.utils.StringUtils;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.command.admin.storage.CancelPrimaryStorageMaintenanceCmd;
|
||||
import org.apache.cloudstack.api.command.admin.storage.CreateSecondaryStagingStoreCmd;
|
||||
@ -53,8 +50,8 @@ import org.apache.cloudstack.api.command.admin.storage.CreateStoragePoolCmd;
|
||||
import org.apache.cloudstack.api.command.admin.storage.DeleteImageStoreCmd;
|
||||
import org.apache.cloudstack.api.command.admin.storage.DeletePoolCmd;
|
||||
import org.apache.cloudstack.api.command.admin.storage.DeleteSecondaryStagingStoreCmd;
|
||||
import org.apache.cloudstack.api.command.admin.storage.UpdateStoragePoolCmd;
|
||||
import org.apache.cloudstack.api.command.admin.storage.SyncStoragePoolCmd;
|
||||
import org.apache.cloudstack.api.command.admin.storage.UpdateStoragePoolCmd;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
||||
@ -121,12 +118,13 @@ import com.cloud.agent.api.GetStorageStatsAnswer;
|
||||
import com.cloud.agent.api.GetStorageStatsCommand;
|
||||
import com.cloud.agent.api.GetVolumeStatsAnswer;
|
||||
import com.cloud.agent.api.GetVolumeStatsCommand;
|
||||
import com.cloud.agent.api.ModifyStoragePoolAnswer;
|
||||
import com.cloud.agent.api.ModifyStoragePoolCommand;
|
||||
import com.cloud.agent.api.StoragePoolInfo;
|
||||
import com.cloud.agent.api.VolumeStatsEntry;
|
||||
import com.cloud.agent.api.to.DataTO;
|
||||
import com.cloud.agent.api.to.DiskTO;
|
||||
import com.cloud.agent.api.ModifyStoragePoolCommand;
|
||||
import com.cloud.agent.api.ModifyStoragePoolAnswer;
|
||||
import com.cloud.agent.api.to.StorageFilerTO;
|
||||
import com.cloud.agent.manager.Commands;
|
||||
import com.cloud.api.ApiDBUtils;
|
||||
import com.cloud.api.query.dao.TemplateJoinDao;
|
||||
@ -143,8 +141,10 @@ import com.cloud.configuration.ConfigurationManagerImpl;
|
||||
import com.cloud.configuration.Resource.ResourceType;
|
||||
import com.cloud.dc.ClusterVO;
|
||||
import com.cloud.dc.DataCenterVO;
|
||||
import com.cloud.dc.VsphereStoragePolicyVO;
|
||||
import com.cloud.dc.dao.ClusterDao;
|
||||
import com.cloud.dc.dao.DataCenterDao;
|
||||
import com.cloud.dc.dao.VsphereStoragePolicyDao;
|
||||
import com.cloud.event.ActionEvent;
|
||||
import com.cloud.event.EventTypes;
|
||||
import com.cloud.exception.AgentUnavailableException;
|
||||
@ -172,6 +172,7 @@ import com.cloud.org.Grouping.AllocationState;
|
||||
import com.cloud.resource.ResourceState;
|
||||
import com.cloud.server.ConfigurationServer;
|
||||
import com.cloud.server.ManagementServer;
|
||||
import com.cloud.service.dao.ServiceOfferingDetailsDao;
|
||||
import com.cloud.storage.Storage.ImageFormat;
|
||||
import com.cloud.storage.Storage.StoragePoolType;
|
||||
import com.cloud.storage.Volume.Type;
|
||||
@ -195,6 +196,7 @@ import com.cloud.user.dao.UserDao;
|
||||
import com.cloud.utils.DateUtil;
|
||||
import com.cloud.utils.NumbersUtil;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.StringUtils;
|
||||
import com.cloud.utils.UriUtils;
|
||||
import com.cloud.utils.component.ComponentContext;
|
||||
import com.cloud.utils.component.ManagerBase;
|
||||
@ -218,8 +220,6 @@ import com.cloud.vm.VMInstanceVO;
|
||||
import com.cloud.vm.VirtualMachine.State;
|
||||
import com.cloud.vm.dao.VMInstanceDao;
|
||||
|
||||
import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
|
||||
|
||||
@Component
|
||||
public class StorageManagerImpl extends ManagerBase implements StorageManager, ClusterManagerListener, Configurable {
|
||||
private static final Logger s_logger = Logger.getLogger(StorageManagerImpl.class);
|
||||
@ -2392,8 +2392,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStoragePoolComplaintWithStoragePolicy(List<Volume> volumes, StoragePool pool) throws StorageUnavailableException {
|
||||
if (volumes == null || volumes.isEmpty()) {
|
||||
public boolean isStoragePoolCompliantWithStoragePolicy(List<Volume> volumes, StoragePool pool) throws StorageUnavailableException {
|
||||
if (CollectionUtils.isEmpty(volumes)) {
|
||||
return false;
|
||||
}
|
||||
List<Pair<Volume, Answer>> answers = new ArrayList<Pair<Volume, Answer>>();
|
||||
|
||||
@ -2441,7 +2441,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
||||
HypervisorType hypervisorType = _volsDao.getHypervisorType(volumeId);
|
||||
if (hypervisorType.equals(HypervisorType.VMware)) {
|
||||
try {
|
||||
boolean isStoragePoolStoragepolicyComplaince = storageMgr.isStoragePoolComplaintWithStoragePolicy(Arrays.asList(vol), destPool);
|
||||
boolean isStoragePoolStoragepolicyComplaince = storageMgr.isStoragePoolCompliantWithStoragePolicy(Arrays.asList(vol), destPool);
|
||||
if (!isStoragePoolStoragepolicyComplaince) {
|
||||
throw new CloudRuntimeException(String.format("Storage pool %s is not storage policy compliance with the volume %s", poolUuid, vol.getUuid()));
|
||||
}
|
||||
|
||||
@ -582,6 +582,13 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
private static final ConfigKey<Boolean> VmDestroyForcestop = new ConfigKey<Boolean>("Advanced", Boolean.class, "vm.destroy.forcestop", "false",
|
||||
"On destroy, force-stop takes this value ", true);
|
||||
|
||||
public static final List<HypervisorType> VM_STORAGE_MIGRATION_SUPPORTING_HYPERVISORS = new ArrayList<>(Arrays.asList(
|
||||
HypervisorType.KVM,
|
||||
HypervisorType.VMware,
|
||||
HypervisorType.XenServer,
|
||||
HypervisorType.Simulator
|
||||
));
|
||||
|
||||
@Override
|
||||
public UserVmVO getVirtualMachine(long vmId) {
|
||||
return _vmDao.findById(vmId);
|
||||
@ -6266,56 +6273,18 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ActionEvent(eventType = EventTypes.EVENT_VM_MIGRATE, eventDescription = "migrating VM", async = true)
|
||||
public VirtualMachine migrateVirtualMachineWithVolume(Long vmId, Host destinationHost, Map<String, String> volumeToPool) throws ResourceUnavailableException,
|
||||
ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException {
|
||||
// Access check - only root administrator can migrate VM.
|
||||
Account caller = CallContext.current().getCallingAccount();
|
||||
if (!_accountMgr.isRootAdmin(caller.getId())) {
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("Caller is not a root admin, permission denied to migrate the VM");
|
||||
}
|
||||
throw new PermissionDeniedException("No permission to migrate VM, Only Root Admin can migrate a VM!");
|
||||
}
|
||||
|
||||
VMInstanceVO vm = _vmInstanceDao.findById(vmId);
|
||||
if (vm == null) {
|
||||
throw new InvalidParameterValueException("Unable to find the vm by id " + vmId);
|
||||
}
|
||||
|
||||
// OfflineVmwareMigration: this would be it ;) if multiple paths exist: unify
|
||||
if (vm.getState() != State.Running) {
|
||||
// OfflineVmwareMigration: and not vmware
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("VM is not Running, unable to migrate the vm " + vm);
|
||||
}
|
||||
CloudRuntimeException ex = new CloudRuntimeException("VM is not Running, unable to migrate the vm with" + " specified id");
|
||||
ex.addProxyObject(vm.getUuid(), "vmId");
|
||||
throw ex;
|
||||
}
|
||||
|
||||
if(serviceOfferingDetailsDao.findDetail(vm.getServiceOfferingId(), GPU.Keys.pciDevice.toString()) != null) {
|
||||
throw new InvalidParameterValueException("Live Migration of GPU enabled VM is not supported");
|
||||
}
|
||||
|
||||
// OfflineVmwareMigration: this condition is to complicated. (already a method somewhere)
|
||||
if (!vm.getHypervisorType().equals(HypervisorType.XenServer) && !vm.getHypervisorType().equals(HypervisorType.VMware) && !vm.getHypervisorType().equals(HypervisorType.KVM)
|
||||
&& !vm.getHypervisorType().equals(HypervisorType.Ovm) && !vm.getHypervisorType().equals(HypervisorType.Hyperv)
|
||||
&& !vm.getHypervisorType().equals(HypervisorType.Simulator)) {
|
||||
throw new InvalidParameterValueException("Unsupported hypervisor type for vm migration, we support" + " XenServer/VMware/KVM only");
|
||||
}
|
||||
|
||||
private Pair<Host, Host> getHostsForMigrateVmWithStorage(VMInstanceVO vm, Host destinationHost) throws VirtualMachineMigrationException {
|
||||
long srcHostId = vm.getHostId();
|
||||
Host srcHost = _resourceMgr.getHost(srcHostId);
|
||||
|
||||
if (srcHost == null) {
|
||||
throw new InvalidParameterValueException("Cannot migrate VM, host with id: " + srcHostId + " for VM not found");
|
||||
throw new InvalidParameterValueException("Cannot migrate VM, host with ID: " + srcHostId + " for VM not found");
|
||||
}
|
||||
|
||||
// Check if source and destination hosts are valid and migrating to same host
|
||||
if (destinationHost.getId() == srcHostId) {
|
||||
throw new InvalidParameterValueException("Cannot migrate VM, VM is already present on this host, please" + " specify valid destination host to migrate the VM");
|
||||
throw new InvalidParameterValueException(String.format("Cannot migrate VM as it is already present on host %s (ID: %s), please specify valid destination host to migrate the VM",
|
||||
destinationHost.getName(), destinationHost.getUuid()));
|
||||
}
|
||||
|
||||
String srcHostVersion = srcHost.getHypervisorVersion();
|
||||
@ -6345,39 +6314,45 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
}
|
||||
}
|
||||
|
||||
if (!Boolean.TRUE.equals(_hypervisorCapabilitiesDao.isStorageMotionSupported(srcHost.getHypervisorType(), srcHostVersion))) {
|
||||
throw new CloudRuntimeException("Migration with storage isn't supported for source host ID: " + srcHost.getUuid() + " on hypervisor " + srcHost.getHypervisorType() + " of version " + srcHost.getHypervisorVersion());
|
||||
if (!_hypervisorCapabilitiesDao.isStorageMotionSupported(srcHost.getHypervisorType(), srcHostVersion)) {
|
||||
throw new CloudRuntimeException(String.format("Migration with storage isn't supported for source host %s (ID: %s) on hypervisor %s with version %s", srcHost.getName(), srcHost.getUuid(), srcHost.getHypervisorType(), srcHost.getHypervisorVersion()));
|
||||
}
|
||||
|
||||
if (srcHostVersion == null || !srcHostVersion.equals(destHostVersion)) {
|
||||
if (!Boolean.TRUE.equals(_hypervisorCapabilitiesDao.isStorageMotionSupported(destinationHost.getHypervisorType(), destHostVersion))) {
|
||||
throw new CloudRuntimeException("Migration with storage isn't supported for target host ID: " + srcHost.getUuid() + " on hypervisor " + srcHost.getHypervisorType() + " of version " + srcHost.getHypervisorVersion());
|
||||
if (!_hypervisorCapabilitiesDao.isStorageMotionSupported(destinationHost.getHypervisorType(), destHostVersion)) {
|
||||
throw new CloudRuntimeException(String.format("Migration with storage isn't supported for target host %s (ID: %s) on hypervisor %s with version %s", destinationHost.getName(), destinationHost.getUuid(), destinationHost.getHypervisorType(), destinationHost.getHypervisorVersion()));
|
||||
}
|
||||
}
|
||||
|
||||
// Check if destination host is up.
|
||||
if (destinationHost.getState() != com.cloud.host.Status.Up || destinationHost.getResourceState() != ResourceState.Enabled) {
|
||||
throw new CloudRuntimeException("Cannot migrate VM, destination host is not in correct state, has " + "status: " + destinationHost.getState() + ", state: "
|
||||
+ destinationHost.getResourceState());
|
||||
throw new CloudRuntimeException(String.format("Cannot migrate VM, destination host %s (ID: %s) is not in correct state, has status: %s, state: %s",
|
||||
destinationHost.getName(), destinationHost.getUuid(), destinationHost.getState(), destinationHost.getResourceState()));
|
||||
}
|
||||
|
||||
// Check that Vm does not have VM Snapshots
|
||||
if (_vmSnapshotDao.findByVm(vmId).size() > 0) {
|
||||
throw new InvalidParameterValueException("VM with VM Snapshots cannot be migrated with storage, please remove all VM snapshots");
|
||||
// Check max guest vm limit for the destinationHost.
|
||||
if (_capacityMgr.checkIfHostReachMaxGuestLimit(destinationHost)) {
|
||||
throw new VirtualMachineMigrationException(String.format("Cannot migrate VM as destination host %s (ID: %s) already has max running vms (count includes system VMs)",
|
||||
destinationHost.getName(), destinationHost.getUuid()));
|
||||
}
|
||||
|
||||
return new Pair<>(srcHost, destinationHost);
|
||||
}
|
||||
|
||||
private List<VolumeVO> getVmVolumesForMigrateVmWithStorage(VMInstanceVO vm) {
|
||||
List<VolumeVO> vmVolumes = _volsDao.findUsableVolumesForInstance(vm.getId());
|
||||
Map<Long, Long> volToPoolObjectMap = new HashMap<Long, Long>();
|
||||
if (!isVMUsingLocalStorage(vm) && MapUtils.isEmpty(volumeToPool)
|
||||
&& (destinationHost.getClusterId().equals(srcHost.getClusterId()) || isVmVolumesOnZoneWideStore(vm))){
|
||||
// If volumes do not have to be migrated
|
||||
// call migrateVirtualMachine for non-user VMs else throw exception
|
||||
if (!VirtualMachine.Type.User.equals(vm.getType())) {
|
||||
return migrateVirtualMachine(vmId, destinationHost);
|
||||
for (VolumeVO volume : vmVolumes) {
|
||||
if (volume.getState() != Volume.State.Ready) {
|
||||
throw new CloudRuntimeException(String.format("Volume %s (ID: %s) of the VM is not in Ready state. Cannot migrate the VM %s (ID: %s) with its volumes", volume.getName(), volume.getUuid(), vm.getInstanceName(), vm.getUuid()));
|
||||
}
|
||||
throw new InvalidParameterValueException("Migration of the vm " + vm + "from host " + srcHost + " to destination host " + destinationHost
|
||||
+ " doesn't involve migrating the volumes.");
|
||||
}
|
||||
return vmVolumes;
|
||||
}
|
||||
|
||||
private Map<Long, Long> getVolumePoolMappingForMigrateVmWithStorage(VMInstanceVO vm, Map<String, String> volumeToPool) {
|
||||
Map<Long, Long> volToPoolObjectMap = new HashMap<Long, Long>();
|
||||
|
||||
List<VolumeVO> vmVolumes = getVmVolumesForMigrateVmWithStorage(vm);
|
||||
|
||||
if (MapUtils.isNotEmpty(volumeToPool)) {
|
||||
// Check if all the volumes and pools passed as parameters are valid.
|
||||
@ -6394,15 +6369,15 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
} else {
|
||||
// Verify the volume given belongs to the vm.
|
||||
if (!vmVolumes.contains(volume)) {
|
||||
throw new InvalidParameterValueException("There volume " + volume + " doesn't belong to " + "the virtual machine " + vm + " that has to be migrated");
|
||||
throw new InvalidParameterValueException(String.format("Volume " + volume + " doesn't belong to the VM %s (ID: %s) that has to be migrated", vm.getInstanceName(), vm.getUuid()));
|
||||
}
|
||||
volToPoolObjectMap.put(Long.valueOf(volume.getId()), Long.valueOf(pool.getId()));
|
||||
volToPoolObjectMap.put(volume.getId(), pool.getId());
|
||||
}
|
||||
HypervisorType hypervisorType = _volsDao.getHypervisorType(volume.getId());
|
||||
if (hypervisorType.equals(HypervisorType.VMware)) {
|
||||
try {
|
||||
boolean isStoragePoolStoragepolicyComplaince = storageManager.isStoragePoolComplaintWithStoragePolicy(Arrays.asList(volume), pool);
|
||||
if (!isStoragePoolStoragepolicyComplaince) {
|
||||
boolean isStoragePoolStoragepolicyCompliance = storageManager.isStoragePoolCompliantWithStoragePolicy(Arrays.asList(volume), pool);
|
||||
if (!isStoragePoolStoragepolicyCompliance) {
|
||||
throw new CloudRuntimeException(String.format("Storage pool %s is not storage policy compliance with the volume %s", pool.getUuid(), volume.getUuid()));
|
||||
}
|
||||
} catch (StorageUnavailableException e) {
|
||||
@ -6411,24 +6386,69 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
}
|
||||
}
|
||||
}
|
||||
return volToPoolObjectMap;
|
||||
}
|
||||
|
||||
// Check if all the volumes are in the correct state.
|
||||
for (VolumeVO volume : vmVolumes) {
|
||||
if (volume.getState() != Volume.State.Ready) {
|
||||
throw new CloudRuntimeException("Volume " + volume + " of the VM is not in Ready state. Cannot " + "migrate the vm with its volumes.");
|
||||
@Override
|
||||
@ActionEvent(eventType = EventTypes.EVENT_VM_MIGRATE, eventDescription = "migrating VM", async = true)
|
||||
public VirtualMachine migrateVirtualMachineWithVolume(Long vmId, Host destinationHost, Map<String, String> volumeToPool) throws ResourceUnavailableException,
|
||||
ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException {
|
||||
// Access check - only root administrator can migrate VM.
|
||||
Account caller = CallContext.current().getCallingAccount();
|
||||
if (!_accountMgr.isRootAdmin(caller.getId())) {
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("Caller is not a root admin, permission denied to migrate the VM");
|
||||
}
|
||||
throw new PermissionDeniedException("No permission to migrate VM, Only Root Admin can migrate a VM!");
|
||||
}
|
||||
|
||||
// Check max guest vm limit for the destinationHost.
|
||||
HostVO destinationHostVO = _hostDao.findById(destinationHost.getId());
|
||||
if (_capacityMgr.checkIfHostReachMaxGuestLimit(destinationHostVO)) {
|
||||
throw new VirtualMachineMigrationException("Host name: " + destinationHost.getName() + ", hostId: " + destinationHost.getId()
|
||||
+ " already has max running vms (count includes system VMs). Cannot" + " migrate to this host");
|
||||
VMInstanceVO vm = _vmInstanceDao.findById(vmId);
|
||||
if (vm == null) {
|
||||
throw new InvalidParameterValueException("Unable to find the VM by ID " + vmId);
|
||||
}
|
||||
|
||||
checkHostsDedication(vm, srcHostId, destinationHost.getId());
|
||||
// OfflineVmwareMigration: this would be it ;) if multiple paths exist: unify
|
||||
if (vm.getState() != State.Running) {
|
||||
// OfflineVmwareMigration: and not vmware
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("VM is not Running, unable to migrate the vm " + vm);
|
||||
}
|
||||
CloudRuntimeException ex = new CloudRuntimeException(String.format("Unable to migrate the VM %s (ID: %s) as it is not in Running state", vm.getInstanceName(), vm.getUuid()));
|
||||
ex.addProxyObject(vm.getUuid(), "vmId");
|
||||
throw ex;
|
||||
}
|
||||
|
||||
_itMgr.migrateWithStorage(vm.getUuid(), srcHostId, destinationHost.getId(), volToPoolObjectMap);
|
||||
if(serviceOfferingDetailsDao.findDetail(vm.getServiceOfferingId(), GPU.Keys.pciDevice.toString()) != null) {
|
||||
throw new InvalidParameterValueException("Live Migration of GPU enabled VM is not supported");
|
||||
}
|
||||
|
||||
if (VM_STORAGE_MIGRATION_SUPPORTING_HYPERVISORS.contains(vm.getHypervisorType())) {
|
||||
throw new InvalidParameterValueException(String.format("Unsupported hypervisor: %s for VM migration, we support XenServer/VMware/KVM only", vm.getHypervisorType()));
|
||||
}
|
||||
|
||||
if (_vmSnapshotDao.findByVm(vmId).size() > 0) {
|
||||
throw new InvalidParameterValueException("VM with VM Snapshots cannot be migrated with storage, please remove all VM snapshots");
|
||||
}
|
||||
|
||||
Pair<Host, Host> sourceDestinationHosts = getHostsForMigrateVmWithStorage(vm, destinationHost);
|
||||
Host srcHost = sourceDestinationHosts.first();
|
||||
|
||||
if (!isVMUsingLocalStorage(vm) && MapUtils.isEmpty(volumeToPool)
|
||||
&& (destinationHost.getClusterId().equals(srcHost.getClusterId()) || isVmVolumesOnZoneWideStore(vm))){
|
||||
// If volumes do not have to be migrated
|
||||
// call migrateVirtualMachine for non-user VMs else throw exception
|
||||
if (!VirtualMachine.Type.User.equals(vm.getType())) {
|
||||
return migrateVirtualMachine(vmId, destinationHost);
|
||||
}
|
||||
throw new InvalidParameterValueException(String.format("Migration of the VM: %s (ID: %s) from host %s (ID: %s) to destination host %s (ID: %s) doesn't involve migrating the volumes",
|
||||
vm.getInstanceName(), vm.getUuid(), srcHost.getName(), srcHost.getUuid(), destinationHost.getName(), destinationHost.getUuid()));
|
||||
}
|
||||
|
||||
Map<Long, Long> volToPoolObjectMap = getVolumePoolMappingForMigrateVmWithStorage(vm, volumeToPool);
|
||||
|
||||
checkHostsDedication(vm, srcHost.getId(), destinationHost.getId());
|
||||
|
||||
_itMgr.migrateWithStorage(vm.getUuid(), srcHost.getId(), destinationHost.getId(), volToPoolObjectMap);
|
||||
return findMigratedVm(vm.getId(), vm.getType());
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user