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.math.BigDecimal;
|
||||||
import java.util.List;
|
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.DataStore;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener;
|
import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener;
|
||||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
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.Answer;
|
||||||
import com.cloud.agent.api.Command;
|
import com.cloud.agent.api.Command;
|
||||||
|
import com.cloud.agent.api.ModifyStoragePoolAnswer;
|
||||||
import com.cloud.agent.api.StoragePoolInfo;
|
import com.cloud.agent.api.StoragePoolInfo;
|
||||||
import com.cloud.agent.api.to.DataTO;
|
import com.cloud.agent.api.to.DataTO;
|
||||||
import com.cloud.agent.api.to.DiskTO;
|
import com.cloud.agent.api.to.DiskTO;
|
||||||
@ -252,7 +252,7 @@ public interface StorageManager extends StorageService {
|
|||||||
|
|
||||||
boolean storagePoolCompatibleWithVolumePool(StoragePool pool, Volume volume);
|
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);
|
boolean registerHostListener(String providerUuid, HypervisorHostListener listener);
|
||||||
|
|
||||||
|
|||||||
@ -38,5 +38,5 @@ public interface HypervisorCapabilitiesDao extends GenericDao<HypervisorCapabili
|
|||||||
|
|
||||||
List<HypervisorType> getHypervisorsWithDefaultEntries();
|
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
|
@Override
|
||||||
public Boolean isStorageMotionSupported(HypervisorType hypervisorType, String hypervisorVersion) {
|
public boolean isStorageMotionSupported(HypervisorType hypervisorType, String hypervisorVersion) {
|
||||||
HypervisorCapabilitiesVO hostCapabilities = findByHypervisorTypeAndVersion(hypervisorType, hypervisorVersion);
|
HypervisorCapabilitiesVO hostCapabilities = findByHypervisorTypeAndVersion(hypervisorType, hypervisorVersion);
|
||||||
if (hostCapabilities == null && HypervisorType.KVM.equals(hypervisorType)) {
|
if (hostCapabilities == null && HypervisorType.KVM.equals(hypervisorType)) {
|
||||||
List<HypervisorCapabilitiesVO> hypervisorCapabilitiesList = listAllByHypervisorType(HypervisorType.KVM);
|
List<HypervisorCapabilitiesVO> hypervisorCapabilitiesList = listAllByHypervisorType(HypervisorType.KVM);
|
||||||
|
|||||||
@ -241,7 +241,7 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
boolean isStoragePoolStoragepolicyComplaince = storageMgr.isStoragePoolComplaintWithStoragePolicy(requestVolumes, pool);
|
boolean isStoragePoolStoragepolicyComplaince = storageMgr.isStoragePoolCompliantWithStoragePolicy(requestVolumes, pool);
|
||||||
if (!isStoragePoolStoragepolicyComplaince) {
|
if (!isStoragePoolStoragepolicyComplaince) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1411,7 +1411,7 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||||||
hostCanAccessPool = true;
|
hostCanAccessPool = true;
|
||||||
if (potentialHost.getHypervisorType() == HypervisorType.VMware) {
|
if (potentialHost.getHypervisorType() == HypervisorType.VMware) {
|
||||||
try {
|
try {
|
||||||
boolean isStoragePoolStoragepolicyComplaince = _storageMgr.isStoragePoolComplaintWithStoragePolicy(allVolumes, storagePool);
|
boolean isStoragePoolStoragepolicyComplaince = _storageMgr.isStoragePoolCompliantWithStoragePolicy(allVolumes, storagePool);
|
||||||
if (!isStoragePoolStoragepolicyComplaince) {
|
if (!isStoragePoolStoragepolicyComplaince) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1450,7 +1450,7 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||||||
|
|
||||||
if (potentialHost.getHypervisorType() == HypervisorType.VMware) {
|
if (potentialHost.getHypervisorType() == HypervisorType.VMware) {
|
||||||
try {
|
try {
|
||||||
boolean isStoragePoolStoragepolicyComplaince = _storageMgr.isStoragePoolComplaintWithStoragePolicy(requestVolumes, potentialSPool);
|
boolean isStoragePoolStoragepolicyComplaince = _storageMgr.isStoragePoolCompliantWithStoragePolicy(requestVolumes, potentialSPool);
|
||||||
if (!isStoragePoolStoragepolicyComplaince) {
|
if (!isStoragePoolStoragepolicyComplaince) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1291,7 +1291,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
|||||||
boolean canMigrateWithStorage = false;
|
boolean canMigrateWithStorage = false;
|
||||||
|
|
||||||
if (VirtualMachine.Type.User.equals(vm.getType()) || HypervisorType.VMware.equals(vm.getHypervisorType())) {
|
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.
|
// Check if the vm is using any disks on local storage.
|
||||||
@ -1345,11 +1345,8 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
|||||||
// source volume.
|
// source volume.
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
} else {
|
} else {
|
||||||
boolean hostSupportsStorageMigration = false;
|
boolean hostSupportsStorageMigration = (srcHostVersion != null && srcHostVersion.equals(hostVersion)) ||
|
||||||
if ((srcHostVersion != null && srcHostVersion.equals(hostVersion)) ||
|
_hypervisorCapabilitiesDao.isStorageMotionSupported(host.getHypervisorType(), hostVersion);
|
||||||
Boolean.TRUE.equals(_hypervisorCapabilitiesDao.isStorageMotionSupported(host.getHypervisorType(), hostVersion))) {
|
|
||||||
hostSupportsStorageMigration = true;
|
|
||||||
}
|
|
||||||
if (hostSupportsStorageMigration && hasSuitablePoolsForVolume(volume, host, vmProfile)) {
|
if (hostSupportsStorageMigration && hasSuitablePoolsForVolume(volume, host, vmProfile)) {
|
||||||
requiresStorageMotion.put(host, true);
|
requiresStorageMotion.put(host, true);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -16,6 +16,8 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package com.cloud.storage;
|
package com.cloud.storage;
|
||||||
|
|
||||||
|
import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
@ -29,11 +31,11 @@ import java.util.Date;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
@ -41,11 +43,6 @@ import java.util.concurrent.TimeUnit;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
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.ApiConstants;
|
||||||
import org.apache.cloudstack.api.command.admin.storage.CancelPrimaryStorageMaintenanceCmd;
|
import org.apache.cloudstack.api.command.admin.storage.CancelPrimaryStorageMaintenanceCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.storage.CreateSecondaryStagingStoreCmd;
|
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.DeleteImageStoreCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.storage.DeletePoolCmd;
|
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.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.SyncStoragePoolCmd;
|
||||||
|
import org.apache.cloudstack.api.command.admin.storage.UpdateStoragePoolCmd;
|
||||||
import org.apache.cloudstack.context.CallContext;
|
import org.apache.cloudstack.context.CallContext;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
|
import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
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.GetStorageStatsCommand;
|
||||||
import com.cloud.agent.api.GetVolumeStatsAnswer;
|
import com.cloud.agent.api.GetVolumeStatsAnswer;
|
||||||
import com.cloud.agent.api.GetVolumeStatsCommand;
|
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.StoragePoolInfo;
|
||||||
import com.cloud.agent.api.VolumeStatsEntry;
|
import com.cloud.agent.api.VolumeStatsEntry;
|
||||||
import com.cloud.agent.api.to.DataTO;
|
import com.cloud.agent.api.to.DataTO;
|
||||||
import com.cloud.agent.api.to.DiskTO;
|
import com.cloud.agent.api.to.DiskTO;
|
||||||
import com.cloud.agent.api.ModifyStoragePoolCommand;
|
import com.cloud.agent.api.to.StorageFilerTO;
|
||||||
import com.cloud.agent.api.ModifyStoragePoolAnswer;
|
|
||||||
import com.cloud.agent.manager.Commands;
|
import com.cloud.agent.manager.Commands;
|
||||||
import com.cloud.api.ApiDBUtils;
|
import com.cloud.api.ApiDBUtils;
|
||||||
import com.cloud.api.query.dao.TemplateJoinDao;
|
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.configuration.Resource.ResourceType;
|
||||||
import com.cloud.dc.ClusterVO;
|
import com.cloud.dc.ClusterVO;
|
||||||
import com.cloud.dc.DataCenterVO;
|
import com.cloud.dc.DataCenterVO;
|
||||||
|
import com.cloud.dc.VsphereStoragePolicyVO;
|
||||||
import com.cloud.dc.dao.ClusterDao;
|
import com.cloud.dc.dao.ClusterDao;
|
||||||
import com.cloud.dc.dao.DataCenterDao;
|
import com.cloud.dc.dao.DataCenterDao;
|
||||||
|
import com.cloud.dc.dao.VsphereStoragePolicyDao;
|
||||||
import com.cloud.event.ActionEvent;
|
import com.cloud.event.ActionEvent;
|
||||||
import com.cloud.event.EventTypes;
|
import com.cloud.event.EventTypes;
|
||||||
import com.cloud.exception.AgentUnavailableException;
|
import com.cloud.exception.AgentUnavailableException;
|
||||||
@ -172,6 +172,7 @@ import com.cloud.org.Grouping.AllocationState;
|
|||||||
import com.cloud.resource.ResourceState;
|
import com.cloud.resource.ResourceState;
|
||||||
import com.cloud.server.ConfigurationServer;
|
import com.cloud.server.ConfigurationServer;
|
||||||
import com.cloud.server.ManagementServer;
|
import com.cloud.server.ManagementServer;
|
||||||
|
import com.cloud.service.dao.ServiceOfferingDetailsDao;
|
||||||
import com.cloud.storage.Storage.ImageFormat;
|
import com.cloud.storage.Storage.ImageFormat;
|
||||||
import com.cloud.storage.Storage.StoragePoolType;
|
import com.cloud.storage.Storage.StoragePoolType;
|
||||||
import com.cloud.storage.Volume.Type;
|
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.DateUtil;
|
||||||
import com.cloud.utils.NumbersUtil;
|
import com.cloud.utils.NumbersUtil;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
|
import com.cloud.utils.StringUtils;
|
||||||
import com.cloud.utils.UriUtils;
|
import com.cloud.utils.UriUtils;
|
||||||
import com.cloud.utils.component.ComponentContext;
|
import com.cloud.utils.component.ComponentContext;
|
||||||
import com.cloud.utils.component.ManagerBase;
|
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.VirtualMachine.State;
|
||||||
import com.cloud.vm.dao.VMInstanceDao;
|
import com.cloud.vm.dao.VMInstanceDao;
|
||||||
|
|
||||||
import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
|
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class StorageManagerImpl extends ManagerBase implements StorageManager, ClusterManagerListener, Configurable {
|
public class StorageManagerImpl extends ManagerBase implements StorageManager, ClusterManagerListener, Configurable {
|
||||||
private static final Logger s_logger = Logger.getLogger(StorageManagerImpl.class);
|
private static final Logger s_logger = Logger.getLogger(StorageManagerImpl.class);
|
||||||
@ -2392,8 +2392,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isStoragePoolComplaintWithStoragePolicy(List<Volume> volumes, StoragePool pool) throws StorageUnavailableException {
|
public boolean isStoragePoolCompliantWithStoragePolicy(List<Volume> volumes, StoragePool pool) throws StorageUnavailableException {
|
||||||
if (volumes == null || volumes.isEmpty()) {
|
if (CollectionUtils.isEmpty(volumes)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
List<Pair<Volume, Answer>> answers = new ArrayList<Pair<Volume, Answer>>();
|
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);
|
HypervisorType hypervisorType = _volsDao.getHypervisorType(volumeId);
|
||||||
if (hypervisorType.equals(HypervisorType.VMware)) {
|
if (hypervisorType.equals(HypervisorType.VMware)) {
|
||||||
try {
|
try {
|
||||||
boolean isStoragePoolStoragepolicyComplaince = storageMgr.isStoragePoolComplaintWithStoragePolicy(Arrays.asList(vol), destPool);
|
boolean isStoragePoolStoragepolicyComplaince = storageMgr.isStoragePoolCompliantWithStoragePolicy(Arrays.asList(vol), destPool);
|
||||||
if (!isStoragePoolStoragepolicyComplaince) {
|
if (!isStoragePoolStoragepolicyComplaince) {
|
||||||
throw new CloudRuntimeException(String.format("Storage pool %s is not storage policy compliance with the volume %s", poolUuid, vol.getUuid()));
|
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",
|
private static final ConfigKey<Boolean> VmDestroyForcestop = new ConfigKey<Boolean>("Advanced", Boolean.class, "vm.destroy.forcestop", "false",
|
||||||
"On destroy, force-stop takes this value ", true);
|
"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
|
@Override
|
||||||
public UserVmVO getVirtualMachine(long vmId) {
|
public UserVmVO getVirtualMachine(long vmId) {
|
||||||
return _vmDao.findById(vmId);
|
return _vmDao.findById(vmId);
|
||||||
@ -6266,56 +6273,18 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private Pair<Host, Host> getHostsForMigrateVmWithStorage(VMInstanceVO vm, Host destinationHost) throws VirtualMachineMigrationException {
|
||||||
@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");
|
|
||||||
}
|
|
||||||
|
|
||||||
long srcHostId = vm.getHostId();
|
long srcHostId = vm.getHostId();
|
||||||
Host srcHost = _resourceMgr.getHost(srcHostId);
|
Host srcHost = _resourceMgr.getHost(srcHostId);
|
||||||
|
|
||||||
if (srcHost == null) {
|
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
|
// Check if source and destination hosts are valid and migrating to same host
|
||||||
if (destinationHost.getId() == srcHostId) {
|
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();
|
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))) {
|
if (!_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());
|
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 (srcHostVersion == null || !srcHostVersion.equals(destHostVersion)) {
|
||||||
if (!Boolean.TRUE.equals(_hypervisorCapabilitiesDao.isStorageMotionSupported(destinationHost.getHypervisorType(), destHostVersion))) {
|
if (!_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());
|
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.
|
// Check if destination host is up.
|
||||||
if (destinationHost.getState() != com.cloud.host.Status.Up || destinationHost.getResourceState() != ResourceState.Enabled) {
|
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: "
|
throw new CloudRuntimeException(String.format("Cannot migrate VM, destination host %s (ID: %s) is not in correct state, has status: %s, state: %s",
|
||||||
+ destinationHost.getResourceState());
|
destinationHost.getName(), destinationHost.getUuid(), destinationHost.getState(), destinationHost.getResourceState()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that Vm does not have VM Snapshots
|
// Check max guest vm limit for the destinationHost.
|
||||||
if (_vmSnapshotDao.findByVm(vmId).size() > 0) {
|
if (_capacityMgr.checkIfHostReachMaxGuestLimit(destinationHost)) {
|
||||||
throw new InvalidParameterValueException("VM with VM Snapshots cannot be migrated with storage, please remove all VM snapshots");
|
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());
|
List<VolumeVO> vmVolumes = _volsDao.findUsableVolumesForInstance(vm.getId());
|
||||||
Map<Long, Long> volToPoolObjectMap = new HashMap<Long, Long>();
|
for (VolumeVO volume : vmVolumes) {
|
||||||
if (!isVMUsingLocalStorage(vm) && MapUtils.isEmpty(volumeToPool)
|
if (volume.getState() != Volume.State.Ready) {
|
||||||
&& (destinationHost.getClusterId().equals(srcHost.getClusterId()) || isVmVolumesOnZoneWideStore(vm))){
|
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()));
|
||||||
// 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("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)) {
|
if (MapUtils.isNotEmpty(volumeToPool)) {
|
||||||
// Check if all the volumes and pools passed as parameters are valid.
|
// 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 {
|
} else {
|
||||||
// Verify the volume given belongs to the vm.
|
// Verify the volume given belongs to the vm.
|
||||||
if (!vmVolumes.contains(volume)) {
|
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());
|
HypervisorType hypervisorType = _volsDao.getHypervisorType(volume.getId());
|
||||||
if (hypervisorType.equals(HypervisorType.VMware)) {
|
if (hypervisorType.equals(HypervisorType.VMware)) {
|
||||||
try {
|
try {
|
||||||
boolean isStoragePoolStoragepolicyComplaince = storageManager.isStoragePoolComplaintWithStoragePolicy(Arrays.asList(volume), pool);
|
boolean isStoragePoolStoragepolicyCompliance = storageManager.isStoragePoolCompliantWithStoragePolicy(Arrays.asList(volume), pool);
|
||||||
if (!isStoragePoolStoragepolicyComplaince) {
|
if (!isStoragePoolStoragepolicyCompliance) {
|
||||||
throw new CloudRuntimeException(String.format("Storage pool %s is not storage policy compliance with the volume %s", pool.getUuid(), volume.getUuid()));
|
throw new CloudRuntimeException(String.format("Storage pool %s is not storage policy compliance with the volume %s", pool.getUuid(), volume.getUuid()));
|
||||||
}
|
}
|
||||||
} catch (StorageUnavailableException e) {
|
} 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.
|
@Override
|
||||||
for (VolumeVO volume : vmVolumes) {
|
@ActionEvent(eventType = EventTypes.EVENT_VM_MIGRATE, eventDescription = "migrating VM", async = true)
|
||||||
if (volume.getState() != Volume.State.Ready) {
|
public VirtualMachine migrateVirtualMachineWithVolume(Long vmId, Host destinationHost, Map<String, String> volumeToPool) throws ResourceUnavailableException,
|
||||||
throw new CloudRuntimeException("Volume " + volume + " of the VM is not in Ready state. Cannot " + "migrate the vm with its volumes.");
|
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.
|
VMInstanceVO vm = _vmInstanceDao.findById(vmId);
|
||||||
HostVO destinationHostVO = _hostDao.findById(destinationHost.getId());
|
if (vm == null) {
|
||||||
if (_capacityMgr.checkIfHostReachMaxGuestLimit(destinationHostVO)) {
|
throw new InvalidParameterValueException("Unable to find the VM by ID " + vmId);
|
||||||
throw new VirtualMachineMigrationException("Host name: " + destinationHost.getName() + ", hostId: " + destinationHost.getId()
|
|
||||||
+ " already has max running vms (count includes system VMs). Cannot" + " migrate to this host");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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());
|
return findMigratedVm(vm.getId(), vm.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user