mirror of
https://github.com/apache/cloudstack.git
synced 2025-11-02 20:02:29 +01:00
CLOUDSTACK-6510: Fix gson serialization exception in storage migration. Gson couldn't serialize
a map with volume and storagepool objects for logging. Fixed by using volume and storage pool ids instead of objects in the map.
This commit is contained in:
parent
b8adb96ae1
commit
245b7f4c39
@ -39,7 +39,6 @@ import com.cloud.network.Network;
|
||||
import com.cloud.offering.DiskOfferingInfo;
|
||||
import com.cloud.offering.ServiceOffering;
|
||||
import com.cloud.storage.StoragePool;
|
||||
import com.cloud.storage.Volume;
|
||||
import com.cloud.template.VirtualMachineTemplate;
|
||||
import com.cloud.utils.component.Manager;
|
||||
import com.cloud.utils.fsm.NoTransitionException;
|
||||
@ -113,7 +112,7 @@ public interface VirtualMachineManager extends Manager {
|
||||
|
||||
void migrate(String vmUuid, long srcHostId, DeployDestination dest) throws ResourceUnavailableException, ConcurrentOperationException;
|
||||
|
||||
void migrateWithStorage(String vmUuid, long srcId, long destId, Map<Volume, StoragePool> volumeToPool) throws ResourceUnavailableException, ConcurrentOperationException;
|
||||
void migrateWithStorage(String vmUuid, long srcId, long destId, Map<Long, Long> volumeToPool) throws ResourceUnavailableException, ConcurrentOperationException;
|
||||
|
||||
void reboot(String vmUuid, Map<VirtualMachineProfile.Param, Object> params) throws InsufficientCapacityException, ResourceUnavailableException;
|
||||
|
||||
|
||||
@ -26,6 +26,7 @@ import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -1963,24 +1964,26 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
||||
}
|
||||
}
|
||||
|
||||
private Map<Volume, StoragePool> getPoolListForVolumesForMigration(VirtualMachineProfile profile, Host host, Map<Volume, StoragePool> volumeToPool) {
|
||||
private Map<Volume, StoragePool> getPoolListForVolumesForMigration(VirtualMachineProfile profile, Host host, Map<Long, Long> volumeToPool) {
|
||||
List<VolumeVO> allVolumes = _volsDao.findUsableVolumesForInstance(profile.getId());
|
||||
Map<Volume, StoragePool> volumeToPoolObjectMap = new HashMap<Volume, StoragePool> ();
|
||||
for (VolumeVO volume : allVolumes) {
|
||||
StoragePool pool = volumeToPool.get(volume);
|
||||
DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume.getDiskOfferingId());
|
||||
Long poolId = volumeToPool.get(Long.valueOf(volume.getId()));
|
||||
StoragePoolVO pool = _storagePoolDao.findById(poolId);
|
||||
StoragePoolVO currentPool = _storagePoolDao.findById(volume.getPoolId());
|
||||
DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume.getDiskOfferingId());
|
||||
if (pool != null) {
|
||||
// Check if pool is accessible from the destination host and disk offering with which the volume was
|
||||
// created is compliant with the pool type.
|
||||
if (_poolHostDao.findByPoolHost(pool.getId(), host.getId()) == null || pool.isLocal() != diskOffering.getUseLocalStorage()) {
|
||||
// Cannot find a pool for the volume. Throw an exception.
|
||||
throw new CloudRuntimeException("Cannot migrate volume " + volume + " to storage pool " + pool + " while migrating vm to host " + host +
|
||||
". Either the pool is not accessible from the " + "host or because of the offering with which the volume is created it cannot be placed on " +
|
||||
". Either the pool is not accessible from the host or because of the offering with which the volume is created it cannot be placed on " +
|
||||
"the given pool.");
|
||||
} else if (pool.getId() == currentPool.getId()) {
|
||||
// If the pool to migrate too is the same as current pool, remove the volume from the list of
|
||||
// volumes to be migrated.
|
||||
volumeToPool.remove(volume);
|
||||
// If the pool to migrate too is the same as current pool, the volume doesn't need to be migrated.
|
||||
} else {
|
||||
volumeToPoolObjectMap.put(volume, pool);
|
||||
}
|
||||
} else {
|
||||
// Find a suitable pool for the volume. Call the storage pool allocator to find the list of pools.
|
||||
@ -1989,23 +1992,33 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
||||
ExcludeList avoid = new ExcludeList();
|
||||
boolean currentPoolAvailable = false;
|
||||
|
||||
List<StoragePool> poolList = new ArrayList<StoragePool>();
|
||||
for (StoragePoolAllocator allocator : _storagePoolAllocators) {
|
||||
List<StoragePool> poolList = allocator.allocateToPool(diskProfile, profile, plan, avoid, StoragePoolAllocator.RETURN_UPTO_ALL);
|
||||
if (poolList != null && !poolList.isEmpty()) {
|
||||
// Volume needs to be migrated. Pick the first pool from the list. Add a mapping to migrate the
|
||||
// volume to a pool only if it is required; that is the current pool on which the volume resides
|
||||
// is not available on the destination host.
|
||||
if (poolList.contains(currentPool)) {
|
||||
currentPoolAvailable = true;
|
||||
} else {
|
||||
volumeToPool.put(volume, _storagePoolDao.findByUuid(poolList.get(0).getUuid()));
|
||||
}
|
||||
|
||||
break;
|
||||
List<StoragePool> poolListFromAllocator = allocator.allocateToPool(diskProfile, profile, plan, avoid, StoragePoolAllocator.RETURN_UPTO_ALL);
|
||||
if (poolListFromAllocator != null && !poolListFromAllocator.isEmpty()) {
|
||||
poolList.addAll(poolListFromAllocator);
|
||||
}
|
||||
}
|
||||
|
||||
if (!currentPoolAvailable && !volumeToPool.containsKey(volume)) {
|
||||
if (poolList != null && !poolList.isEmpty()) {
|
||||
// Volume needs to be migrated. Pick the first pool from the list. Add a mapping to migrate the
|
||||
// volume to a pool only if it is required; that is the current pool on which the volume resides
|
||||
// is not available on the destination host.
|
||||
Iterator<StoragePool> iter = poolList.iterator();
|
||||
while (iter.hasNext()) {
|
||||
if (currentPool.getId() == iter.next().getId()) {
|
||||
currentPoolAvailable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!currentPoolAvailable) {
|
||||
volumeToPoolObjectMap.put(volume, _storagePoolDao.findByUuid(poolList.get(0).getUuid()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!currentPoolAvailable && !volumeToPoolObjectMap.containsKey(volume)) {
|
||||
// Cannot find a pool for the volume. Throw an exception.
|
||||
throw new CloudRuntimeException("Cannot find a storage pool which is available for volume " + volume + " while migrating virtual machine " +
|
||||
profile.getVirtualMachine() + " to host " + host);
|
||||
@ -2013,7 +2026,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
||||
}
|
||||
}
|
||||
|
||||
return volumeToPool;
|
||||
return volumeToPoolObjectMap;
|
||||
}
|
||||
|
||||
private <T extends VMInstanceVO> void moveVmToMigratingState(T vm, Long hostId, ItWorkVO work) throws ConcurrentOperationException {
|
||||
@ -2043,7 +2056,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
||||
}
|
||||
|
||||
@Override
|
||||
public void migrateWithStorage(String vmUuid, long srcHostId, long destHostId, Map<Volume, StoragePool> volumeToPool)
|
||||
public void migrateWithStorage(String vmUuid, long srcHostId, long destHostId, Map<Long, Long> volumeToPool)
|
||||
throws ResourceUnavailableException, ConcurrentOperationException {
|
||||
|
||||
AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
|
||||
@ -2087,7 +2100,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
||||
}
|
||||
}
|
||||
|
||||
private void orchestrateMigrateWithStorage(String vmUuid, long srcHostId, long destHostId, Map<Volume, StoragePool> volumeToPool) throws ResourceUnavailableException,
|
||||
private void orchestrateMigrateWithStorage(String vmUuid, long srcHostId, long destHostId, Map<Long, Long> volumeToPool) throws ResourceUnavailableException,
|
||||
ConcurrentOperationException {
|
||||
|
||||
VMInstanceVO vm = _vmDao.findByUuid(vmUuid);
|
||||
@ -2103,11 +2116,11 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
||||
|
||||
// Create a map of which volume should go in which storage pool.
|
||||
VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm);
|
||||
volumeToPool = getPoolListForVolumesForMigration(profile, destHost, volumeToPool);
|
||||
Map<Volume, StoragePool> volumeToPoolMap = getPoolListForVolumesForMigration(profile, destHost, volumeToPool);
|
||||
|
||||
// If none of the volumes have to be migrated, fail the call. Administrator needs to make a call for migrating
|
||||
// a vm and not migrating a vm with storage.
|
||||
if (volumeToPool.isEmpty()) {
|
||||
if (volumeToPoolMap == null || volumeToPoolMap.isEmpty()) {
|
||||
throw new InvalidParameterValueException("Migration of the vm " + vm + "from host " + srcHost + " to destination host " + destHost +
|
||||
" doesn't involve migrating the volumes.");
|
||||
}
|
||||
@ -2137,7 +2150,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
||||
boolean migrated = false;
|
||||
try {
|
||||
// Migrate the vm and its volume.
|
||||
volumeMgr.migrateVolumes(vm, to, srcHost, destHost, volumeToPool);
|
||||
volumeMgr.migrateVolumes(vm, to, srcHost, destHost, volumeToPoolMap);
|
||||
|
||||
// Put the vm back to running state.
|
||||
moveVmOutofMigratingStateOnSuccess(vm, destHost.getId(), work);
|
||||
@ -4717,7 +4730,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
||||
|
||||
public Outcome<VirtualMachine> migrateVmWithStorageThroughJobQueue(
|
||||
final String vmUuid, final long srcHostId, final long destHostId,
|
||||
final Map<Volume, StoragePool> volumeToPool) {
|
||||
final Map<Long, Long> volumeToPool) {
|
||||
|
||||
final CallContext context = CallContext.current();
|
||||
final User user = context.getCallingUser();
|
||||
|
||||
@ -18,18 +18,15 @@ package com.cloud.vm;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.cloud.storage.StoragePool;
|
||||
import com.cloud.storage.Volume;
|
||||
|
||||
public class VmWorkMigrateWithStorage extends VmWork {
|
||||
private static final long serialVersionUID = -5626053872453569165L;
|
||||
|
||||
long srcHostId;
|
||||
long destHostId;
|
||||
Map<Volume, StoragePool> volumeToPool;
|
||||
Map<Long, Long> volumeToPool;
|
||||
|
||||
public VmWorkMigrateWithStorage(long userId, long accountId, long vmId, String handlerName, long srcHostId,
|
||||
long destHostId, Map<Volume, StoragePool> volumeToPool) {
|
||||
long destHostId, Map<Long, Long> volumeToPool) {
|
||||
|
||||
super(userId, accountId, vmId, handlerName);
|
||||
|
||||
@ -46,7 +43,7 @@ public class VmWorkMigrateWithStorage extends VmWork {
|
||||
return destHostId;
|
||||
}
|
||||
|
||||
public Map<Volume, StoragePool> getVolumeToPool() {
|
||||
public Map<Long, Long> getVolumeToPool() {
|
||||
return volumeToPool;
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,9 +89,7 @@ import com.cloud.storage.dao.VMTemplateDao;
|
||||
import com.cloud.storage.dao.VolumeDao;
|
||||
import com.cloud.storage.Storage.ProvisioningType;
|
||||
import com.cloud.storage.DiskOfferingVO;
|
||||
import com.cloud.storage.StoragePool;
|
||||
import com.cloud.storage.StoragePoolHostVO;
|
||||
import com.cloud.storage.Volume;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.storage.VMTemplateVO;
|
||||
import com.cloud.user.Account;
|
||||
@ -197,7 +195,7 @@ public class VirtualMachineManagerImplTest {
|
||||
@Mock
|
||||
HostVO _destHostMock;
|
||||
@Mock
|
||||
Map<Volume, StoragePool> _volumeToPoolMock;
|
||||
Map<Long, Long> _volumeToPoolMock;
|
||||
@Mock
|
||||
EntityManager _entityMgr;
|
||||
@Mock
|
||||
@ -356,11 +354,13 @@ public class VirtualMachineManagerImplTest {
|
||||
// Mock the disk offering and pool objects for a volume.
|
||||
when(_volumeMock.getDiskOfferingId()).thenReturn(5L);
|
||||
when(_volumeMock.getPoolId()).thenReturn(200L);
|
||||
when(_volumeMock.getId()).thenReturn(5L);
|
||||
when(_diskOfferingDao.findById(anyLong())).thenReturn(_diskOfferingMock);
|
||||
when(_storagePoolDao.findById(anyLong())).thenReturn(_srcStoragePoolMock);
|
||||
when(_storagePoolDao.findById(200L)).thenReturn(_srcStoragePoolMock);
|
||||
when(_storagePoolDao.findById(201L)).thenReturn(_destStoragePoolMock);
|
||||
|
||||
// Mock the volume to pool mapping.
|
||||
when(_volumeToPoolMock.get(_volumeMock)).thenReturn(_destStoragePoolMock);
|
||||
when(_volumeToPoolMock.get(5L)).thenReturn(201L);
|
||||
when(_destStoragePoolMock.getId()).thenReturn(201L);
|
||||
when(_srcStoragePoolMock.getId()).thenReturn(200L);
|
||||
when(_destStoragePoolMock.isLocal()).thenReturn(false);
|
||||
|
||||
@ -4092,7 +4092,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
}
|
||||
|
||||
List<VolumeVO> vmVolumes = _volsDao.findUsableVolumesForInstance(vm.getId());
|
||||
Map<Volume, StoragePool> volToPoolObjectMap = new HashMap<Volume, StoragePool>();
|
||||
Map<Long, Long> volToPoolObjectMap = new HashMap<Long, Long>();
|
||||
if (!isVMUsingLocalStorage(vm) && destinationHost.getClusterId().equals(srcHost.getClusterId())) {
|
||||
if (volumeToPool.isEmpty()) {
|
||||
// If the destination host is in the same cluster and volumes do not have to be migrated across pools
|
||||
@ -4116,7 +4116,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||
if (!vmVolumes.contains(volume)) {
|
||||
throw new InvalidParameterValueException("There volume " + volume + " doesn't belong to " + "the virtual machine " + vm + " that has to be migrated");
|
||||
}
|
||||
volToPoolObjectMap.put(volume, pool);
|
||||
volToPoolObjectMap.put(Long.valueOf(volume.getId()), Long.valueOf(pool.getId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user