Skip to content

Commit f0fca60

Browse files
committed
Merge pull request apache#1336 from nitin-maharana/CloudStack-Nitin19_4.7
CLOUDSTACK-9231: Root volume migration from one primary to another primary storage within the same cluster is failingEXPECTED BEHAVIOUR: ==================== Root Volume migration within cluster should work. ACTUAL BEHAVIOUR: ================== Root volume migration within cluster failed. 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, serialisation of map from one to another fails. Fix: === This is fixed by converting the maps to lists. * pr/1336: CLOUDSTACK-9231: Root volume migration from one primary to another primary storage within the same cluster is failing Signed-off-by: Remi Bergsma <github@remi.nl>
2 parents 1f1da0f + 40e3dfc commit f0fca60

8 files changed

Lines changed: 82 additions & 56 deletions

File tree

core/src/com/cloud/agent/api/MigrateWithStorageCommand.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ public MigrateWithStorageCommand(VirtualMachineTO vm, Map<VolumeTO, StorageFiler
4040
this.tgtHost = null;
4141
}
4242

43+
public MigrateWithStorageCommand(VirtualMachineTO vm, List<Pair<VolumeTO, StorageFilerTO>> volumeToFilerAsList) {
44+
this.vm = vm;
45+
this.volumeToFiler = null;
46+
this.volumeToFilerAsList = volumeToFilerAsList;
47+
this.tgtHost = null;
48+
}
49+
4350
public MigrateWithStorageCommand(VirtualMachineTO vm, Map<VolumeTO, StorageFilerTO> volumeToFiler, String tgtHost) {
4451
this.vm = vm;
4552
this.volumeToFiler = volumeToFiler;

core/src/com/cloud/agent/api/MigrateWithStorageReceiveAnswer.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,17 @@
1919

2020
package com.cloud.agent.api;
2121

22+
import java.util.List;
2223
import java.util.Map;
2324

2425
import com.cloud.agent.api.to.NicTO;
2526
import com.cloud.agent.api.to.VolumeTO;
27+
import com.cloud.utils.Pair;
2628

2729
public class MigrateWithStorageReceiveAnswer extends Answer {
2830

29-
Map<VolumeTO, String> volumeToSr;
30-
Map<NicTO, String> nicToNetwork;
31+
List<Pair<VolumeTO, Object>> volumeToSr;
32+
List<Pair<NicTO, Object>> nicToNetwork;
3133
Map<String, String> token;
3234

3335
public MigrateWithStorageReceiveAnswer(MigrateWithStorageReceiveCommand cmd, Exception ex) {
@@ -37,19 +39,19 @@ public MigrateWithStorageReceiveAnswer(MigrateWithStorageReceiveCommand cmd, Exc
3739
token = null;
3840
}
3941

40-
public MigrateWithStorageReceiveAnswer(MigrateWithStorageReceiveCommand cmd, Map<VolumeTO, String> volumeToSr, Map<NicTO, String> nicToNetwork,
42+
public MigrateWithStorageReceiveAnswer(MigrateWithStorageReceiveCommand cmd, List<Pair<VolumeTO, Object>> volumeToSr, List<Pair<NicTO, Object>> nicToNetwork,
4143
Map<String, String> token) {
4244
super(cmd, true, null);
4345
this.volumeToSr = volumeToSr;
4446
this.nicToNetwork = nicToNetwork;
4547
this.token = token;
4648
}
4749

48-
public Map<VolumeTO, String> getVolumeToSr() {
50+
public List<Pair<VolumeTO, Object>> getVolumeToSr() {
4951
return volumeToSr;
5052
}
5153

52-
public Map<NicTO, String> getNicToNetwork() {
54+
public List<Pair<NicTO, Object>> getNicToNetwork() {
5355
return nicToNetwork;
5456
}
5557

core/src/com/cloud/agent/api/MigrateWithStorageReceiveCommand.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,18 @@
1919

2020
package com.cloud.agent.api;
2121

22-
import java.util.Map;
22+
import java.util.List;
2323

2424
import com.cloud.agent.api.to.StorageFilerTO;
2525
import com.cloud.agent.api.to.VirtualMachineTO;
2626
import com.cloud.agent.api.to.VolumeTO;
27+
import com.cloud.utils.Pair;
2728

2829
public class MigrateWithStorageReceiveCommand extends Command {
2930
VirtualMachineTO vm;
30-
Map<VolumeTO, StorageFilerTO> volumeToFiler;
31+
List<Pair<VolumeTO, StorageFilerTO>> volumeToFiler;
3132

32-
public MigrateWithStorageReceiveCommand(VirtualMachineTO vm, Map<VolumeTO, StorageFilerTO> volumeToFiler) {
33+
public MigrateWithStorageReceiveCommand(VirtualMachineTO vm, List<Pair<VolumeTO, StorageFilerTO>> volumeToFiler) {
3334
this.vm = vm;
3435
this.volumeToFiler = volumeToFiler;
3536
}
@@ -38,7 +39,7 @@ public VirtualMachineTO getVirtualMachine() {
3839
return vm;
3940
}
4041

41-
public Map<VolumeTO, StorageFilerTO> getVolumeToFiler() {
42+
public List<Pair<VolumeTO, StorageFilerTO>> getVolumeToFiler() {
4243
return volumeToFiler;
4344
}
4445

core/src/com/cloud/agent/api/MigrateWithStorageSendCommand.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,21 @@
1919

2020
package com.cloud.agent.api;
2121

22+
import java.util.List;
2223
import java.util.Map;
2324

2425
import com.cloud.agent.api.to.NicTO;
2526
import com.cloud.agent.api.to.VirtualMachineTO;
2627
import com.cloud.agent.api.to.VolumeTO;
28+
import com.cloud.utils.Pair;
2729

2830
public class MigrateWithStorageSendCommand extends Command {
2931
VirtualMachineTO vm;
30-
Map<VolumeTO, String> volumeToSr;
31-
Map<NicTO, String> nicToNetwork;
32+
List<Pair<VolumeTO, Object>> volumeToSr;
33+
List<Pair<NicTO, Object>> nicToNetwork;
3234
Map<String, String> token;
3335

34-
public MigrateWithStorageSendCommand(VirtualMachineTO vm, Map<VolumeTO, String> volumeToSr, Map<NicTO, String> nicToNetwork, Map<String, String> token) {
36+
public MigrateWithStorageSendCommand(VirtualMachineTO vm, List<Pair<VolumeTO, Object>> volumeToSr, List<Pair<NicTO, Object>> nicToNetwork, Map<String, String> token) {
3537
this.vm = vm;
3638
this.volumeToSr = volumeToSr;
3739
this.nicToNetwork = nicToNetwork;
@@ -42,11 +44,11 @@ public VirtualMachineTO getVirtualMachine() {
4244
return vm;
4345
}
4446

45-
public Map<VolumeTO, String> getVolumeToSr() {
47+
public List<Pair<VolumeTO, Object>> getVolumeToSr() {
4648
return volumeToSr;
4749
}
4850

49-
public Map<NicTO, String> getNicToNetwork() {
51+
public List<Pair<NicTO, Object>> getNicToNetwork() {
5052
return nicToNetwork;
5153
}
5254

plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xen610/XenServer610MigrateWithStorageReceiveCommandWrapper.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@
1919

2020
package com.cloud.hypervisor.xenserver.resource.wrapper.xen610;
2121

22+
import java.util.ArrayList;
2223
import java.util.HashMap;
2324
import java.util.Map;
25+
import java.util.List;
2426

2527
import com.google.gson.Gson;
2628
import org.apache.log4j.Logger;
@@ -39,6 +41,7 @@
3941
import com.cloud.resource.CommandWrapper;
4042
import com.cloud.resource.ResourceWrapper;
4143
import com.cloud.utils.exception.CloudRuntimeException;
44+
import com.cloud.utils.Pair;
4245
import com.xensource.xenapi.Connection;
4346
import com.xensource.xenapi.Host;
4447
import com.xensource.xenapi.Network;
@@ -53,7 +56,7 @@ public final class XenServer610MigrateWithStorageReceiveCommandWrapper extends C
5356
public Answer execute(final MigrateWithStorageReceiveCommand command, final XenServer610Resource xenServer610Resource) {
5457
final Connection connection = xenServer610Resource.getConnection();
5558
final VirtualMachineTO vmSpec = command.getVirtualMachine();
56-
final Map<VolumeTO, StorageFilerTO> volumeToFiler = command.getVolumeToFiler();
59+
final List<Pair<VolumeTO, StorageFilerTO>> volumeToFiler = command.getVolumeToFiler();
5760

5861
try {
5962
// In a cluster management server setup, the migrate with storage receive and send
@@ -66,18 +69,18 @@ public Answer execute(final MigrateWithStorageReceiveCommand command, final XenS
6669
// storage send command execution.
6770
Gson gson = new Gson();
6871
// Get a map of all the SRs to which the vdis will be migrated.
69-
final Map<VolumeTO, String> volumeToSr = new HashMap<VolumeTO, String>();
70-
for (final Map.Entry<VolumeTO, StorageFilerTO> entry : volumeToFiler.entrySet()) {
71-
final StorageFilerTO storageFiler = entry.getValue();
72+
final List<Pair<VolumeTO, Object>> volumeToSr = new ArrayList<Pair<VolumeTO, Object>>();
73+
for (final Pair<VolumeTO, StorageFilerTO> entry : volumeToFiler) {
74+
final StorageFilerTO storageFiler = entry.second();
7275
final SR sr = xenServer610Resource.getStorageRepository(connection, storageFiler.getUuid());
73-
volumeToSr.put(entry.getKey(), gson.toJson(sr));
76+
volumeToSr.add(new Pair<VolumeTO, Object>(entry.first(), sr));
7477
}
7578

7679
// Get the list of networks to which the vifs will attach.
77-
final Map<NicTO, String> nicToNetwork = new HashMap<NicTO, String>();
80+
final List<Pair<NicTO, Object>> nicToNetwork = new ArrayList<Pair<NicTO, Object>>();
7881
for (final NicTO nicTo : vmSpec.getNics()) {
7982
final Network network = xenServer610Resource.getNetwork(connection, nicTo);
80-
nicToNetwork.put(nicTo, gson.toJson(network));
83+
nicToNetwork.add(new Pair<NicTO, Object>(nicTo, network));
8184
}
8285

8386
final XsLocalNetwork nativeNetworkForTraffic = xenServer610Resource.getNativeNetworkForTraffic(connection, TrafficType.Storage, null);

plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xen610/XenServer610MigrateWithStorageSendCommandWrapper.java

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.util.HashMap;
2323
import java.util.Map;
2424
import java.util.Set;
25+
import java.util.List;
2526

2627
import com.google.gson.Gson;
2728
import org.apache.log4j.Logger;
@@ -36,6 +37,7 @@
3637
import com.cloud.resource.CommandWrapper;
3738
import com.cloud.resource.ResourceWrapper;
3839
import com.cloud.utils.exception.CloudRuntimeException;
40+
import com.cloud.utils.Pair;
3941
import com.xensource.xenapi.Connection;
4042
import com.xensource.xenapi.Network;
4143
import com.xensource.xenapi.SR;
@@ -55,8 +57,8 @@ public Answer execute(final MigrateWithStorageSendCommand command, final XenServ
5557
final Connection connection = xenServer610Resource.getConnection();
5658

5759
final VirtualMachineTO vmSpec = command.getVirtualMachine();
58-
final Map<VolumeTO, String> volumeToSr = command.getVolumeToSr();
59-
final Map<NicTO, String> nicToNetwork = command.getNicToNetwork();
60+
final List<Pair<VolumeTO, Object>> volumeToSr = command.getVolumeToSr();
61+
final List<Pair<NicTO, Object>> nicToNetwork = command.getNicToNetwork();
6062
final Map<String, String> token = command.getToken();
6163
final String vmName = vmSpec.getName();
6264

@@ -78,10 +80,14 @@ public Answer execute(final MigrateWithStorageSendCommand command, final XenServ
7880
// Create the vdi map which tells what volumes of the vm need to go
7981
// on which sr on the destination.
8082
final Map<VDI, SR> vdiMap = new HashMap<VDI, SR>();
81-
for (final Map.Entry<VolumeTO, String> entry : volumeToSr.entrySet()) {
82-
SR sr = gson.fromJson(entry.getValue(), SR.class);
83-
VDI vdi = xenServer610Resource.getVDIbyUuid(connection, entry.getKey().getPath());
84-
vdiMap.put(vdi, sr);
83+
for (final Pair<VolumeTO, Object> entry : volumeToSr) {
84+
if (entry.second() instanceof SR) {
85+
final SR sr = (SR)entry.second();
86+
final VDI vdi = xenServer610Resource.getVDIbyUuid(connection, entry.first().getPath());
87+
vdiMap.put(vdi, sr);
88+
} else {
89+
throw new CloudRuntimeException("The object " + entry.second() + " passed is not of type SR.");
90+
}
8591
}
8692

8793
final Set<VM> vms = VM.getByNameLabel(connection, vmSpec.getName());
@@ -92,10 +98,14 @@ public Answer execute(final MigrateWithStorageSendCommand command, final XenServ
9298

9399
// Create the vif map.
94100
final Map<VIF, Network> vifMap = new HashMap<VIF, Network>();
95-
for (final Map.Entry<NicTO, String> entry : nicToNetwork.entrySet()) {
96-
Network network = gson.fromJson(entry.getValue(), Network.class);
97-
VIF vif = xenServer610Resource.getVifByMac(connection, vmToMigrate, entry.getKey().getMac());
98-
vifMap.put(vif, network);
101+
for (final Pair<NicTO, Object> entry : nicToNetwork) {
102+
if (entry.second() instanceof Network) {
103+
final Network network = (Network)entry.second();
104+
final VIF vif = xenServer610Resource.getVifByMac(connection, vmToMigrate, entry.first().getMac());
105+
vifMap.put(vif, network);
106+
} else {
107+
throw new CloudRuntimeException("The object " + entry.second() + " passed is not of type Network.");
108+
}
99109
}
100110

101111
// Check migration with storage is possible.

plugins/hypervisors/xenserver/src/org/apache/cloudstack/storage/motion/XenServerStorageMotionStrategy.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
*/
1919
package org.apache.cloudstack.storage.motion;
2020

21-
import java.util.HashMap;
21+
import java.util.ArrayList;
2222
import java.util.List;
2323
import java.util.Map;
2424

@@ -59,6 +59,7 @@
5959
import com.cloud.storage.VolumeVO;
6060
import com.cloud.storage.dao.VolumeDao;
6161
import com.cloud.utils.exception.CloudRuntimeException;
62+
import com.cloud.utils.Pair;
6263
import com.cloud.vm.VMInstanceVO;
6364
import com.cloud.vm.dao.VMInstanceDao;
6465

@@ -135,12 +136,12 @@ private Answer migrateVmWithVolumesAcrossCluster(VMInstanceVO vm, VirtualMachine
135136

136137
// Initiate migration of a virtual machine with it's volumes.
137138
try {
138-
Map<VolumeTO, StorageFilerTO> volumeToFilerto = new HashMap<VolumeTO, StorageFilerTO>();
139+
List<Pair<VolumeTO, StorageFilerTO>> volumeToFilerto = new ArrayList<Pair<VolumeTO, StorageFilerTO>>();
139140
for (Map.Entry<VolumeInfo, DataStore> entry : volumeToPool.entrySet()) {
140141
VolumeInfo volume = entry.getKey();
141142
VolumeTO volumeTo = new VolumeTO(volume, storagePoolDao.findById(volume.getPoolId()));
142143
StorageFilerTO filerTo = new StorageFilerTO((StoragePool)entry.getValue());
143-
volumeToFilerto.put(volumeTo, filerTo);
144+
volumeToFilerto.add(new Pair<VolumeTO, StorageFilerTO>(volumeTo, filerTo));
144145
}
145146

146147
// Migration across cluster needs to be done in three phases.
@@ -193,12 +194,12 @@ private Answer migrateVmWithVolumesWithinCluster(VMInstanceVO vm, VirtualMachine
193194

194195
// Initiate migration of a virtual machine with it's volumes.
195196
try {
196-
Map<VolumeTO, StorageFilerTO> volumeToFilerto = new HashMap<VolumeTO, StorageFilerTO>();
197+
List<Pair<VolumeTO, StorageFilerTO>> volumeToFilerto = new ArrayList<Pair<VolumeTO, StorageFilerTO>>();
197198
for (Map.Entry<VolumeInfo, DataStore> entry : volumeToPool.entrySet()) {
198199
VolumeInfo volume = entry.getKey();
199200
VolumeTO volumeTo = new VolumeTO(volume, storagePoolDao.findById(volume.getPoolId()));
200201
StorageFilerTO filerTo = new StorageFilerTO((StoragePool)entry.getValue());
201-
volumeToFilerto.put(volumeTo, filerTo);
202+
volumeToFilerto.add(new Pair<VolumeTO, StorageFilerTO>(volumeTo, filerTo));
202203
}
203204

204205
MigrateWithStorageCommand command = new MigrateWithStorageCommand(to, volumeToFilerto);

plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer610WrapperTest.java

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
import com.cloud.network.Networks.TrafficType;
5757
import com.cloud.network.PhysicalNetworkSetupInfo;
5858
import com.cloud.storage.StoragePool;
59+
import com.cloud.utils.Pair;
5960
import com.xensource.xenapi.Connection;
6061
import com.xensource.xenapi.Network;
6162
import com.xensource.xenapi.SR;
@@ -203,9 +204,9 @@ public void testMigrateWithStorageReceiveCommand() {
203204
final StorageFilerTO storage1 = Mockito.mock(StorageFilerTO.class);
204205
final StorageFilerTO storage2 = Mockito.mock(StorageFilerTO.class);
205206

206-
final Map<VolumeTO, StorageFilerTO> volumeToFiler = new HashMap<VolumeTO, StorageFilerTO>();
207-
volumeToFiler.put(vol1, storage1);
208-
volumeToFiler.put(vol2, storage2);
207+
final List<Pair<VolumeTO, StorageFilerTO>> volumeToFiler = new ArrayList<Pair<VolumeTO, StorageFilerTO>>();
208+
volumeToFiler.add(new Pair<VolumeTO, StorageFilerTO>(vol1, storage1));
209+
volumeToFiler.add(new Pair<VolumeTO, StorageFilerTO>(vol2, storage2));
209210

210211
final NicTO nicTO1 = Mockito.mock(NicTO.class);
211212
final NicTO nicTO2 = Mockito.mock(NicTO.class);
@@ -302,14 +303,13 @@ public void testMigrateWithStorageSendCommand() {
302303
final Network network1 = Mockito.mock(Network.class);
303304
final Network network2 = Mockito.mock(Network.class);
304305

305-
final Map<VolumeTO, String> volumeToSr = new HashMap<VolumeTO, String>();
306-
Gson gson = new Gson();
307-
volumeToSr.put(volume1, gson.toJson(sr1));
308-
volumeToSr.put(volume2, gson.toJson(sr2));
306+
final List<Pair<VolumeTO, Object>> volumeToSr = new ArrayList<Pair<VolumeTO, Object>>();
307+
volumeToSr.add(new Pair<VolumeTO, Object>(volume1, sr1));
308+
volumeToSr.add(new Pair<VolumeTO, Object>(volume2, sr2));
309309

310-
final Map<NicTO, String> nicToNetwork = new HashMap<NicTO, String>();
311-
nicToNetwork.put(nic1, gson.toJson(network1));
312-
nicToNetwork.put(nic2, gson.toJson(network2));
310+
final List<Pair<NicTO, Object>> nicToNetwork = new ArrayList<Pair<NicTO, Object>>();
311+
nicToNetwork.add(new Pair<NicTO, Object>(nic1, network1));
312+
nicToNetwork.add(new Pair<NicTO, Object>(nic2, network2));
313313

314314
final Map<String, String> token = new HashMap<String, String>();
315315

@@ -368,11 +368,11 @@ public void testMigrateWithStorageSendCommandSRException() {
368368
final VolumeTO volume1 = Mockito.mock(VolumeTO.class);
369369
final VolumeTO volume2 = Mockito.mock(VolumeTO.class);
370370

371-
final Map<VolumeTO, String> volumeToSr = new HashMap<VolumeTO, String>();
372-
volumeToSr.put(volume1, "a");
373-
volumeToSr.put(volume2, "b");
371+
final List<Pair<VolumeTO, Object>> volumeToSr = new ArrayList<Pair<VolumeTO, Object>>();
372+
volumeToSr.add(new Pair<VolumeTO, Object>(volume1, new String("a")));
373+
volumeToSr.add(new Pair<VolumeTO, Object>(volume2, new String("b")));
374374

375-
final Map<NicTO, String> nicToNetwork = new HashMap<NicTO, String>();
375+
final List<Pair<NicTO, Object>> nicToNetwork = new ArrayList<Pair<NicTO, Object>>();
376376
final Map<String, String> token = new HashMap<String, String>();
377377

378378
final MigrateWithStorageSendCommand migrateStorageCommand = new MigrateWithStorageSendCommand(vmSpec, volumeToSr, nicToNetwork, token);
@@ -411,13 +411,13 @@ public void testMigrateWithStorageSendCommandNetException() {
411411
final NicTO nic2 = Mockito.mock(NicTO.class);
412412

413413
Gson gson = new Gson();
414-
final Map<VolumeTO, String> volumeToSr = new HashMap<VolumeTO, String>();
415-
volumeToSr.put(volume1, gson.toJson(sr1));
416-
volumeToSr.put(volume2, gson.toJson(sr2));
414+
final List<Pair<VolumeTO, Object>> volumeToSr = new ArrayList<Pair<VolumeTO, Object>>();
415+
volumeToSr.add(new Pair<VolumeTO, Object>(volume1, sr1));
416+
volumeToSr.add(new Pair<VolumeTO, Object>(volume2, sr2));
417417

418-
final Map<NicTO, String> nicToNetwork = new HashMap<NicTO, String>();
419-
nicToNetwork.put(nic1, "a");
420-
nicToNetwork.put(nic2, "b");
418+
final List<Pair<NicTO, Object>> nicToNetwork = new ArrayList<Pair<NicTO, Object>>();
419+
nicToNetwork.add(new Pair<NicTO, Object>(nic1, new String("a")));
420+
nicToNetwork.add(new Pair<NicTO, Object>(nic2, new String("b")));
421421

422422
final Map<String, String> token = new HashMap<String, String>();
423423

0 commit comments

Comments
 (0)