mirror of https://github.com/apache/cloudstack.git
CLOUDSTACK-9231: Root volume migration from one primary to another primary storage within the same cluster is failing
This situation arises when there are two management server accessing the same database. When the migration request comes the command is forwarded from one management server to another because the host is owned by the second management server. So, serialization of map from one to another fails. This is fixed by converting the maps to lists.
This commit is contained in:
parent
80703ca33c
commit
40e3dfc617
|
|
@ -40,6 +40,13 @@ public class MigrateWithStorageCommand extends Command {
|
|||
this.tgtHost = null;
|
||||
}
|
||||
|
||||
public MigrateWithStorageCommand(VirtualMachineTO vm, List<Pair<VolumeTO, StorageFilerTO>> volumeToFilerAsList) {
|
||||
this.vm = vm;
|
||||
this.volumeToFiler = null;
|
||||
this.volumeToFilerAsList = volumeToFilerAsList;
|
||||
this.tgtHost = null;
|
||||
}
|
||||
|
||||
public MigrateWithStorageCommand(VirtualMachineTO vm, Map<VolumeTO, StorageFilerTO> volumeToFiler, String tgtHost) {
|
||||
this.vm = vm;
|
||||
this.volumeToFiler = volumeToFiler;
|
||||
|
|
|
|||
|
|
@ -19,15 +19,17 @@
|
|||
|
||||
package com.cloud.agent.api;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.cloud.agent.api.to.NicTO;
|
||||
import com.cloud.agent.api.to.VolumeTO;
|
||||
import com.cloud.utils.Pair;
|
||||
|
||||
public class MigrateWithStorageReceiveAnswer extends Answer {
|
||||
|
||||
Map<VolumeTO, String> volumeToSr;
|
||||
Map<NicTO, String> nicToNetwork;
|
||||
List<Pair<VolumeTO, Object>> volumeToSr;
|
||||
List<Pair<NicTO, Object>> nicToNetwork;
|
||||
Map<String, String> token;
|
||||
|
||||
public MigrateWithStorageReceiveAnswer(MigrateWithStorageReceiveCommand cmd, Exception ex) {
|
||||
|
|
@ -37,7 +39,7 @@ public class MigrateWithStorageReceiveAnswer extends Answer {
|
|||
token = null;
|
||||
}
|
||||
|
||||
public MigrateWithStorageReceiveAnswer(MigrateWithStorageReceiveCommand cmd, Map<VolumeTO, String> volumeToSr, Map<NicTO, String> nicToNetwork,
|
||||
public MigrateWithStorageReceiveAnswer(MigrateWithStorageReceiveCommand cmd, List<Pair<VolumeTO, Object>> volumeToSr, List<Pair<NicTO, Object>> nicToNetwork,
|
||||
Map<String, String> token) {
|
||||
super(cmd, true, null);
|
||||
this.volumeToSr = volumeToSr;
|
||||
|
|
@ -45,11 +47,11 @@ public class MigrateWithStorageReceiveAnswer extends Answer {
|
|||
this.token = token;
|
||||
}
|
||||
|
||||
public Map<VolumeTO, String> getVolumeToSr() {
|
||||
public List<Pair<VolumeTO, Object>> getVolumeToSr() {
|
||||
return volumeToSr;
|
||||
}
|
||||
|
||||
public Map<NicTO, String> getNicToNetwork() {
|
||||
public List<Pair<NicTO, Object>> getNicToNetwork() {
|
||||
return nicToNetwork;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,17 +19,18 @@
|
|||
|
||||
package com.cloud.agent.api;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
|
||||
import com.cloud.agent.api.to.StorageFilerTO;
|
||||
import com.cloud.agent.api.to.VirtualMachineTO;
|
||||
import com.cloud.agent.api.to.VolumeTO;
|
||||
import com.cloud.utils.Pair;
|
||||
|
||||
public class MigrateWithStorageReceiveCommand extends Command {
|
||||
VirtualMachineTO vm;
|
||||
Map<VolumeTO, StorageFilerTO> volumeToFiler;
|
||||
List<Pair<VolumeTO, StorageFilerTO>> volumeToFiler;
|
||||
|
||||
public MigrateWithStorageReceiveCommand(VirtualMachineTO vm, Map<VolumeTO, StorageFilerTO> volumeToFiler) {
|
||||
public MigrateWithStorageReceiveCommand(VirtualMachineTO vm, List<Pair<VolumeTO, StorageFilerTO>> volumeToFiler) {
|
||||
this.vm = vm;
|
||||
this.volumeToFiler = volumeToFiler;
|
||||
}
|
||||
|
|
@ -38,7 +39,7 @@ public class MigrateWithStorageReceiveCommand extends Command {
|
|||
return vm;
|
||||
}
|
||||
|
||||
public Map<VolumeTO, StorageFilerTO> getVolumeToFiler() {
|
||||
public List<Pair<VolumeTO, StorageFilerTO>> getVolumeToFiler() {
|
||||
return volumeToFiler;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,19 +19,21 @@
|
|||
|
||||
package com.cloud.agent.api;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.cloud.agent.api.to.NicTO;
|
||||
import com.cloud.agent.api.to.VirtualMachineTO;
|
||||
import com.cloud.agent.api.to.VolumeTO;
|
||||
import com.cloud.utils.Pair;
|
||||
|
||||
public class MigrateWithStorageSendCommand extends Command {
|
||||
VirtualMachineTO vm;
|
||||
Map<VolumeTO, String> volumeToSr;
|
||||
Map<NicTO, String> nicToNetwork;
|
||||
List<Pair<VolumeTO, Object>> volumeToSr;
|
||||
List<Pair<NicTO, Object>> nicToNetwork;
|
||||
Map<String, String> token;
|
||||
|
||||
public MigrateWithStorageSendCommand(VirtualMachineTO vm, Map<VolumeTO, String> volumeToSr, Map<NicTO, String> nicToNetwork, Map<String, String> token) {
|
||||
public MigrateWithStorageSendCommand(VirtualMachineTO vm, List<Pair<VolumeTO, Object>> volumeToSr, List<Pair<NicTO, Object>> nicToNetwork, Map<String, String> token) {
|
||||
this.vm = vm;
|
||||
this.volumeToSr = volumeToSr;
|
||||
this.nicToNetwork = nicToNetwork;
|
||||
|
|
@ -42,11 +44,11 @@ public class MigrateWithStorageSendCommand extends Command {
|
|||
return vm;
|
||||
}
|
||||
|
||||
public Map<VolumeTO, String> getVolumeToSr() {
|
||||
public List<Pair<VolumeTO, Object>> getVolumeToSr() {
|
||||
return volumeToSr;
|
||||
}
|
||||
|
||||
public Map<NicTO, String> getNicToNetwork() {
|
||||
public List<Pair<NicTO, Object>> getNicToNetwork() {
|
||||
return nicToNetwork;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,8 +19,10 @@
|
|||
|
||||
package com.cloud.hypervisor.xenserver.resource.wrapper.xen610;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import org.apache.log4j.Logger;
|
||||
|
|
@ -39,6 +41,7 @@ import com.cloud.network.Networks.TrafficType;
|
|||
import com.cloud.resource.CommandWrapper;
|
||||
import com.cloud.resource.ResourceWrapper;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.xensource.xenapi.Connection;
|
||||
import com.xensource.xenapi.Host;
|
||||
import com.xensource.xenapi.Network;
|
||||
|
|
@ -53,7 +56,7 @@ public final class XenServer610MigrateWithStorageReceiveCommandWrapper extends C
|
|||
public Answer execute(final MigrateWithStorageReceiveCommand command, final XenServer610Resource xenServer610Resource) {
|
||||
final Connection connection = xenServer610Resource.getConnection();
|
||||
final VirtualMachineTO vmSpec = command.getVirtualMachine();
|
||||
final Map<VolumeTO, StorageFilerTO> volumeToFiler = command.getVolumeToFiler();
|
||||
final List<Pair<VolumeTO, StorageFilerTO>> volumeToFiler = command.getVolumeToFiler();
|
||||
|
||||
try {
|
||||
// In a cluster management server setup, the migrate with storage receive and send
|
||||
|
|
@ -66,18 +69,18 @@ public final class XenServer610MigrateWithStorageReceiveCommandWrapper extends C
|
|||
// storage send command execution.
|
||||
Gson gson = new Gson();
|
||||
// Get a map of all the SRs to which the vdis will be migrated.
|
||||
final Map<VolumeTO, String> volumeToSr = new HashMap<VolumeTO, String>();
|
||||
for (final Map.Entry<VolumeTO, StorageFilerTO> entry : volumeToFiler.entrySet()) {
|
||||
final StorageFilerTO storageFiler = entry.getValue();
|
||||
final List<Pair<VolumeTO, Object>> volumeToSr = new ArrayList<Pair<VolumeTO, Object>>();
|
||||
for (final Pair<VolumeTO, StorageFilerTO> entry : volumeToFiler) {
|
||||
final StorageFilerTO storageFiler = entry.second();
|
||||
final SR sr = xenServer610Resource.getStorageRepository(connection, storageFiler.getUuid());
|
||||
volumeToSr.put(entry.getKey(), gson.toJson(sr));
|
||||
volumeToSr.add(new Pair<VolumeTO, Object>(entry.first(), sr));
|
||||
}
|
||||
|
||||
// Get the list of networks to which the vifs will attach.
|
||||
final Map<NicTO, String> nicToNetwork = new HashMap<NicTO, String>();
|
||||
final List<Pair<NicTO, Object>> nicToNetwork = new ArrayList<Pair<NicTO, Object>>();
|
||||
for (final NicTO nicTo : vmSpec.getNics()) {
|
||||
final Network network = xenServer610Resource.getNetwork(connection, nicTo);
|
||||
nicToNetwork.put(nicTo, gson.toJson(network));
|
||||
nicToNetwork.add(new Pair<NicTO, Object>(nicTo, network));
|
||||
}
|
||||
|
||||
final XsLocalNetwork nativeNetworkForTraffic = xenServer610Resource.getNativeNetworkForTraffic(connection, TrafficType.Storage, null);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ package com.cloud.hypervisor.xenserver.resource.wrapper.xen610;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import org.apache.log4j.Logger;
|
||||
|
|
@ -36,6 +37,7 @@ import com.cloud.hypervisor.xenserver.resource.XenServer610Resource;
|
|||
import com.cloud.resource.CommandWrapper;
|
||||
import com.cloud.resource.ResourceWrapper;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.xensource.xenapi.Connection;
|
||||
import com.xensource.xenapi.Network;
|
||||
import com.xensource.xenapi.SR;
|
||||
|
|
@ -55,8 +57,8 @@ public final class XenServer610MigrateWithStorageSendCommandWrapper extends Comm
|
|||
final Connection connection = xenServer610Resource.getConnection();
|
||||
|
||||
final VirtualMachineTO vmSpec = command.getVirtualMachine();
|
||||
final Map<VolumeTO, String> volumeToSr = command.getVolumeToSr();
|
||||
final Map<NicTO, String> nicToNetwork = command.getNicToNetwork();
|
||||
final List<Pair<VolumeTO, Object>> volumeToSr = command.getVolumeToSr();
|
||||
final List<Pair<NicTO, Object>> nicToNetwork = command.getNicToNetwork();
|
||||
final Map<String, String> token = command.getToken();
|
||||
final String vmName = vmSpec.getName();
|
||||
|
||||
|
|
@ -78,10 +80,14 @@ public final class XenServer610MigrateWithStorageSendCommandWrapper extends Comm
|
|||
// Create the vdi map which tells what volumes of the vm need to go
|
||||
// on which sr on the destination.
|
||||
final Map<VDI, SR> vdiMap = new HashMap<VDI, SR>();
|
||||
for (final Map.Entry<VolumeTO, String> entry : volumeToSr.entrySet()) {
|
||||
SR sr = gson.fromJson(entry.getValue(), SR.class);
|
||||
VDI vdi = xenServer610Resource.getVDIbyUuid(connection, entry.getKey().getPath());
|
||||
vdiMap.put(vdi, sr);
|
||||
for (final Pair<VolumeTO, Object> entry : volumeToSr) {
|
||||
if (entry.second() instanceof SR) {
|
||||
final SR sr = (SR)entry.second();
|
||||
final VDI vdi = xenServer610Resource.getVDIbyUuid(connection, entry.first().getPath());
|
||||
vdiMap.put(vdi, sr);
|
||||
} else {
|
||||
throw new CloudRuntimeException("The object " + entry.second() + " passed is not of type SR.");
|
||||
}
|
||||
}
|
||||
|
||||
final Set<VM> vms = VM.getByNameLabel(connection, vmSpec.getName());
|
||||
|
|
@ -92,10 +98,14 @@ public final class XenServer610MigrateWithStorageSendCommandWrapper extends Comm
|
|||
|
||||
// Create the vif map.
|
||||
final Map<VIF, Network> vifMap = new HashMap<VIF, Network>();
|
||||
for (final Map.Entry<NicTO, String> entry : nicToNetwork.entrySet()) {
|
||||
Network network = gson.fromJson(entry.getValue(), Network.class);
|
||||
VIF vif = xenServer610Resource.getVifByMac(connection, vmToMigrate, entry.getKey().getMac());
|
||||
vifMap.put(vif, network);
|
||||
for (final Pair<NicTO, Object> entry : nicToNetwork) {
|
||||
if (entry.second() instanceof Network) {
|
||||
final Network network = (Network)entry.second();
|
||||
final VIF vif = xenServer610Resource.getVifByMac(connection, vmToMigrate, entry.first().getMac());
|
||||
vifMap.put(vif, network);
|
||||
} else {
|
||||
throw new CloudRuntimeException("The object " + entry.second() + " passed is not of type Network.");
|
||||
}
|
||||
}
|
||||
|
||||
// Check migration with storage is possible.
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
package org.apache.cloudstack.storage.motion;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
|
@ -59,6 +59,7 @@ import com.cloud.storage.StoragePool;
|
|||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.storage.dao.VolumeDao;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.vm.VMInstanceVO;
|
||||
import com.cloud.vm.dao.VMInstanceDao;
|
||||
|
||||
|
|
@ -135,12 +136,12 @@ public class XenServerStorageMotionStrategy implements DataMotionStrategy {
|
|||
|
||||
// Initiate migration of a virtual machine with it's volumes.
|
||||
try {
|
||||
Map<VolumeTO, StorageFilerTO> volumeToFilerto = new HashMap<VolumeTO, StorageFilerTO>();
|
||||
List<Pair<VolumeTO, StorageFilerTO>> volumeToFilerto = new ArrayList<Pair<VolumeTO, StorageFilerTO>>();
|
||||
for (Map.Entry<VolumeInfo, DataStore> entry : volumeToPool.entrySet()) {
|
||||
VolumeInfo volume = entry.getKey();
|
||||
VolumeTO volumeTo = new VolumeTO(volume, storagePoolDao.findById(volume.getPoolId()));
|
||||
StorageFilerTO filerTo = new StorageFilerTO((StoragePool)entry.getValue());
|
||||
volumeToFilerto.put(volumeTo, filerTo);
|
||||
volumeToFilerto.add(new Pair<VolumeTO, StorageFilerTO>(volumeTo, filerTo));
|
||||
}
|
||||
|
||||
// Migration across cluster needs to be done in three phases.
|
||||
|
|
@ -193,12 +194,12 @@ public class XenServerStorageMotionStrategy implements DataMotionStrategy {
|
|||
|
||||
// Initiate migration of a virtual machine with it's volumes.
|
||||
try {
|
||||
Map<VolumeTO, StorageFilerTO> volumeToFilerto = new HashMap<VolumeTO, StorageFilerTO>();
|
||||
List<Pair<VolumeTO, StorageFilerTO>> volumeToFilerto = new ArrayList<Pair<VolumeTO, StorageFilerTO>>();
|
||||
for (Map.Entry<VolumeInfo, DataStore> entry : volumeToPool.entrySet()) {
|
||||
VolumeInfo volume = entry.getKey();
|
||||
VolumeTO volumeTo = new VolumeTO(volume, storagePoolDao.findById(volume.getPoolId()));
|
||||
StorageFilerTO filerTo = new StorageFilerTO((StoragePool)entry.getValue());
|
||||
volumeToFilerto.put(volumeTo, filerTo);
|
||||
volumeToFilerto.add(new Pair<VolumeTO, StorageFilerTO>(volumeTo, filerTo));
|
||||
}
|
||||
|
||||
MigrateWithStorageCommand command = new MigrateWithStorageCommand(to, volumeToFilerto);
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ import com.cloud.hypervisor.xenserver.resource.XsLocalNetwork;
|
|||
import com.cloud.network.Networks.TrafficType;
|
||||
import com.cloud.network.PhysicalNetworkSetupInfo;
|
||||
import com.cloud.storage.StoragePool;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.xensource.xenapi.Connection;
|
||||
import com.xensource.xenapi.Network;
|
||||
import com.xensource.xenapi.SR;
|
||||
|
|
@ -203,9 +204,9 @@ public class XenServer610WrapperTest {
|
|||
final StorageFilerTO storage1 = Mockito.mock(StorageFilerTO.class);
|
||||
final StorageFilerTO storage2 = Mockito.mock(StorageFilerTO.class);
|
||||
|
||||
final Map<VolumeTO, StorageFilerTO> volumeToFiler = new HashMap<VolumeTO, StorageFilerTO>();
|
||||
volumeToFiler.put(vol1, storage1);
|
||||
volumeToFiler.put(vol2, storage2);
|
||||
final List<Pair<VolumeTO, StorageFilerTO>> volumeToFiler = new ArrayList<Pair<VolumeTO, StorageFilerTO>>();
|
||||
volumeToFiler.add(new Pair<VolumeTO, StorageFilerTO>(vol1, storage1));
|
||||
volumeToFiler.add(new Pair<VolumeTO, StorageFilerTO>(vol2, storage2));
|
||||
|
||||
final NicTO nicTO1 = Mockito.mock(NicTO.class);
|
||||
final NicTO nicTO2 = Mockito.mock(NicTO.class);
|
||||
|
|
@ -302,14 +303,13 @@ public class XenServer610WrapperTest {
|
|||
final Network network1 = Mockito.mock(Network.class);
|
||||
final Network network2 = Mockito.mock(Network.class);
|
||||
|
||||
final Map<VolumeTO, String> volumeToSr = new HashMap<VolumeTO, String>();
|
||||
Gson gson = new Gson();
|
||||
volumeToSr.put(volume1, gson.toJson(sr1));
|
||||
volumeToSr.put(volume2, gson.toJson(sr2));
|
||||
final List<Pair<VolumeTO, Object>> volumeToSr = new ArrayList<Pair<VolumeTO, Object>>();
|
||||
volumeToSr.add(new Pair<VolumeTO, Object>(volume1, sr1));
|
||||
volumeToSr.add(new Pair<VolumeTO, Object>(volume2, sr2));
|
||||
|
||||
final Map<NicTO, String> nicToNetwork = new HashMap<NicTO, String>();
|
||||
nicToNetwork.put(nic1, gson.toJson(network1));
|
||||
nicToNetwork.put(nic2, gson.toJson(network2));
|
||||
final List<Pair<NicTO, Object>> nicToNetwork = new ArrayList<Pair<NicTO, Object>>();
|
||||
nicToNetwork.add(new Pair<NicTO, Object>(nic1, network1));
|
||||
nicToNetwork.add(new Pair<NicTO, Object>(nic2, network2));
|
||||
|
||||
final Map<String, String> token = new HashMap<String, String>();
|
||||
|
||||
|
|
@ -368,11 +368,11 @@ public class XenServer610WrapperTest {
|
|||
final VolumeTO volume1 = Mockito.mock(VolumeTO.class);
|
||||
final VolumeTO volume2 = Mockito.mock(VolumeTO.class);
|
||||
|
||||
final Map<VolumeTO, String> volumeToSr = new HashMap<VolumeTO, String>();
|
||||
volumeToSr.put(volume1, "a");
|
||||
volumeToSr.put(volume2, "b");
|
||||
final List<Pair<VolumeTO, Object>> volumeToSr = new ArrayList<Pair<VolumeTO, Object>>();
|
||||
volumeToSr.add(new Pair<VolumeTO, Object>(volume1, new String("a")));
|
||||
volumeToSr.add(new Pair<VolumeTO, Object>(volume2, new String("b")));
|
||||
|
||||
final Map<NicTO, String> nicToNetwork = new HashMap<NicTO, String>();
|
||||
final List<Pair<NicTO, Object>> nicToNetwork = new ArrayList<Pair<NicTO, Object>>();
|
||||
final Map<String, String> token = new HashMap<String, String>();
|
||||
|
||||
final MigrateWithStorageSendCommand migrateStorageCommand = new MigrateWithStorageSendCommand(vmSpec, volumeToSr, nicToNetwork, token);
|
||||
|
|
@ -411,13 +411,13 @@ public class XenServer610WrapperTest {
|
|||
final NicTO nic2 = Mockito.mock(NicTO.class);
|
||||
|
||||
Gson gson = new Gson();
|
||||
final Map<VolumeTO, String> volumeToSr = new HashMap<VolumeTO, String>();
|
||||
volumeToSr.put(volume1, gson.toJson(sr1));
|
||||
volumeToSr.put(volume2, gson.toJson(sr2));
|
||||
final List<Pair<VolumeTO, Object>> volumeToSr = new ArrayList<Pair<VolumeTO, Object>>();
|
||||
volumeToSr.add(new Pair<VolumeTO, Object>(volume1, sr1));
|
||||
volumeToSr.add(new Pair<VolumeTO, Object>(volume2, sr2));
|
||||
|
||||
final Map<NicTO, String> nicToNetwork = new HashMap<NicTO, String>();
|
||||
nicToNetwork.put(nic1, "a");
|
||||
nicToNetwork.put(nic2, "b");
|
||||
final List<Pair<NicTO, Object>> nicToNetwork = new ArrayList<Pair<NicTO, Object>>();
|
||||
nicToNetwork.add(new Pair<NicTO, Object>(nic1, new String("a")));
|
||||
nicToNetwork.add(new Pair<NicTO, Object>(nic2, new String("b")));
|
||||
|
||||
final Map<String, String> token = new HashMap<String, String>();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue