Skip to content

Commit 3748f32

Browse files
authored
engine-orchestration,vmware: hypervisor migration during start vm migration (#7444)
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
1 parent 658daef commit 3748f32

File tree

5 files changed

+93
-31
lines changed

5 files changed

+93
-31
lines changed

engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,8 @@ static String getHypervisorHostname(String name) {
264264

265265
Pair<Long, Long> findClusterAndHostIdForVm(long vmId);
266266

267+
Pair<Long, Long> findClusterAndHostIdForVm(VirtualMachine vm, boolean skipCurrentHostForStartingVm);
268+
267269
/**
268270
* Obtains statistics for a list of VMs; CPU and network utilization
269271
* @param hostId ID of the host

engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,26 @@ protected void checkIfTemplateNeededForCreatingVmVolumes(VMInstanceVO vm) {
10541054
}
10551055
}
10561056

1057+
protected void checkAndAttemptMigrateVmAcrossCluster(final VMInstanceVO vm, final Long destinationClusterId, final Map<Volume, StoragePool> volumePoolMap) {
1058+
if (!HypervisorType.VMware.equals(vm.getHypervisorType()) || vm.getLastHostId() == null) {
1059+
return;
1060+
}
1061+
Host lastHost = _hostDao.findById(vm.getLastHostId());
1062+
if (destinationClusterId.equals(lastHost.getClusterId())) {
1063+
return;
1064+
}
1065+
if (volumePoolMap.values().stream().noneMatch(s -> destinationClusterId.equals(s.getClusterId()))) {
1066+
return;
1067+
}
1068+
Answer[] answer = attemptHypervisorMigration(vm, volumePoolMap, lastHost.getId());
1069+
if (answer == null) {
1070+
s_logger.warn("Hypervisor inter-cluster migration during VM start failed");
1071+
return;
1072+
}
1073+
// Other network related updates will be done using caller
1074+
markVolumesInPool(vm, answer);
1075+
}
1076+
10571077
@Override
10581078
public void orchestrateStart(final String vmUuid, final Map<VirtualMachineProfile.Param, Object> params, final DeploymentPlan planToDeploy, final DeploymentPlanner planner)
10591079
throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException {
@@ -1227,6 +1247,7 @@ public void orchestrateStart(final String vmUuid, final Map<VirtualMachineProfil
12271247
resetVmNicsDeviceId(vm.getId());
12281248
_networkMgr.prepare(vmProfile, dest, ctx);
12291249
if (vm.getHypervisorType() != HypervisorType.BareMetal) {
1250+
checkAndAttemptMigrateVmAcrossCluster(vm, cluster_id, dest.getStorageForDisks());
12301251
volumeMgr.prepare(vmProfile, dest);
12311252
}
12321253

@@ -2355,7 +2376,7 @@ private Answer[] attemptHypervisorMigration(VMInstanceVO vm, Map<Volume, Storage
23552376
try {
23562377
return _agentMgr.send(hostId, commandsContainer);
23572378
} catch (AgentUnavailableException | OperationTimedoutException e) {
2358-
throw new CloudRuntimeException(String.format("Failed to migrate VM: %s", vm.getUuid()),e);
2379+
s_logger.warn(String.format("Hypervisor migration failed for the VM: %s", vm), e);
23592380
}
23602381
}
23612382
return null;
@@ -5712,8 +5733,12 @@ private Pair<Long, Long> findClusterAndHostIdForVmFromVolumes(long vmId) {
57125733
return new Pair<>(clusterId, hostId);
57135734
}
57145735

5715-
private Pair<Long, Long> findClusterAndHostIdForVm(VirtualMachine vm) {
5716-
Long hostId = vm.getHostId();
5736+
@Override
5737+
public Pair<Long, Long> findClusterAndHostIdForVm(VirtualMachine vm, boolean skipCurrentHostForStartingVm) {
5738+
Long hostId = null;
5739+
if (!skipCurrentHostForStartingVm || !State.Starting.equals(vm.getState())) {
5740+
hostId = vm.getHostId();
5741+
}
57175742
Long clusterId = null;
57185743
if(hostId == null) {
57195744
hostId = vm.getLastHostId();
@@ -5731,6 +5756,10 @@ private Pair<Long, Long> findClusterAndHostIdForVm(VirtualMachine vm) {
57315756
return new Pair<>(clusterId, hostId);
57325757
}
57335758

5759+
private Pair<Long, Long> findClusterAndHostIdForVm(VirtualMachine vm) {
5760+
return findClusterAndHostIdForVm(vm, false);
5761+
}
5762+
57345763
@Override
57355764
public Pair<Long, Long> findClusterAndHostIdForVm(long vmId) {
57365765
VMInstanceVO vm = _vmDao.findById(vmId);

engine/orchestration/src/test/java/com/cloud/vm/VirtualMachineManagerImplTest.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,4 +838,34 @@ public void checkIfTemplateNeededForCreatingVmVolumesTemplateAvailable() {
838838
Mockito.when(templateZoneDao.findByZoneTemplate(dcId, templateId)).thenReturn(Mockito.mock(VMTemplateZoneVO.class));
839839
virtualMachineManagerImpl.checkIfTemplateNeededForCreatingVmVolumes(vm);
840840
}
841+
842+
@Test
843+
public void checkAndAttemptMigrateVmAcrossClusterNonValid() {
844+
// Below scenarios shouldn't result in VM migration
845+
846+
VMInstanceVO vm = Mockito.mock(VMInstanceVO.class);
847+
Mockito.when(vm.getHypervisorType()).thenReturn(HypervisorType.KVM);
848+
virtualMachineManagerImpl.checkAndAttemptMigrateVmAcrossCluster(vm, 1L, new HashMap<>());
849+
850+
Mockito.when(vm.getHypervisorType()).thenReturn(HypervisorType.VMware);
851+
Mockito.when(vm.getLastHostId()).thenReturn(null);
852+
virtualMachineManagerImpl.checkAndAttemptMigrateVmAcrossCluster(vm, 1L, new HashMap<>());
853+
854+
Long destinationClusterId = 10L;
855+
Mockito.when(vm.getLastHostId()).thenReturn(1L);
856+
HostVO hostVO = Mockito.mock(HostVO.class);
857+
Mockito.when(hostVO.getClusterId()).thenReturn(destinationClusterId);
858+
Mockito.when(hostDaoMock.findById(1L)).thenReturn(hostVO);
859+
virtualMachineManagerImpl.checkAndAttemptMigrateVmAcrossCluster(vm, destinationClusterId, new HashMap<>());
860+
861+
destinationClusterId = 20L;
862+
Map<Volume, StoragePool> map = new HashMap<>();
863+
StoragePool pool1 = Mockito.mock(StoragePool.class);
864+
Mockito.when(pool1.getClusterId()).thenReturn(10L);
865+
map.put(Mockito.mock(Volume.class), pool1);
866+
StoragePool pool2 = Mockito.mock(StoragePool.class);
867+
Mockito.when(pool2.getClusterId()).thenReturn(null);
868+
map.put(Mockito.mock(Volume.class), pool2);
869+
virtualMachineManagerImpl.checkAndAttemptMigrateVmAcrossCluster(vm, destinationClusterId, map);
870+
}
841871
}

plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VMwareGuru.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,6 @@
2727

2828
import javax.inject.Inject;
2929

30-
import com.cloud.storage.StorageManager;
31-
import com.cloud.storage.StoragePoolHostVO;
32-
import com.cloud.storage.dao.StoragePoolHostDao;
3330
import org.apache.cloudstack.acl.ControlledEntity;
3431
import org.apache.cloudstack.backup.Backup;
3532
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
@@ -112,14 +109,17 @@
112109
import com.cloud.storage.DiskOfferingVO;
113110
import com.cloud.storage.GuestOSVO;
114111
import com.cloud.storage.Storage;
112+
import com.cloud.storage.StorageManager;
115113
import com.cloud.storage.StoragePool;
114+
import com.cloud.storage.StoragePoolHostVO;
116115
import com.cloud.storage.VMTemplateStoragePoolVO;
117116
import com.cloud.storage.VMTemplateStorageResourceAssoc;
118117
import com.cloud.storage.VMTemplateVO;
119118
import com.cloud.storage.Volume;
120119
import com.cloud.storage.VolumeVO;
121120
import com.cloud.storage.dao.DiskOfferingDao;
122121
import com.cloud.storage.dao.GuestOSDao;
122+
import com.cloud.storage.dao.StoragePoolHostDao;
123123
import com.cloud.storage.dao.VMTemplateDao;
124124
import com.cloud.storage.dao.VMTemplatePoolDao;
125125
import com.cloud.storage.dao.VolumeDao;
@@ -1149,10 +1149,10 @@ private String getHostGuidInTargetCluster(boolean isInterClusterMigration, Long
11491149

11501150
@Override
11511151
public List<Command> finalizeMigrate(VirtualMachine vm, Map<Volume, StoragePool> volumeToPool) {
1152-
List<Command> commands = new ArrayList<Command>();
1152+
List<Command> commands = new ArrayList<>();
11531153

11541154
// OfflineVmwareMigration: specialised migration command
1155-
List<Pair<VolumeTO, StorageFilerTO>> volumeToFilerTo = new ArrayList<Pair<VolumeTO, StorageFilerTO>>();
1155+
List<Pair<VolumeTO, StorageFilerTO>> volumeToFilerTo = new ArrayList<>();
11561156
Long poolClusterId = null;
11571157
StoragePool targetLocalPoolForVM = null;
11581158
for (Map.Entry<Volume, StoragePool> entry : volumeToPool.entrySet()) {
@@ -1166,10 +1166,10 @@ public List<Command> finalizeMigrate(VirtualMachine vm, Map<Volume, StoragePool>
11661166
if (volume.getVolumeType().equals(Volume.Type.ROOT) && pool.isLocal()) {
11671167
targetLocalPoolForVM = pool;
11681168
}
1169-
volumeToFilerTo.add(new Pair<VolumeTO, StorageFilerTO>(volumeTo, filerTo));
1169+
volumeToFilerTo.add(new Pair<>(volumeTo, filerTo));
11701170
}
11711171
final Long destClusterId = poolClusterId;
1172-
final Long srcClusterId = vmManager.findClusterAndHostIdForVm(vm.getId()).first();
1172+
final Long srcClusterId = vmManager.findClusterAndHostIdForVm(vm, true).first();
11731173
final boolean isInterClusterMigration = isInterClusterMigration(destClusterId, srcClusterId);
11741174
String targetHostGuid = getTargetHostGuid(targetLocalPoolForVM, destClusterId, isInterClusterMigration);
11751175

plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/guru/VMwareGuruTest.java

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,13 @@
1616
// under the License.
1717
package com.cloud.hypervisor.guru;
1818

19-
import com.cloud.agent.api.Command;
20-
import com.cloud.agent.api.MigrateVmToPoolCommand;
21-
import com.cloud.dc.ClusterDetailsDao;
22-
import com.cloud.host.HostVO;
23-
import com.cloud.host.dao.HostDao;
24-
import com.cloud.storage.Storage.ProvisioningType;
25-
import com.cloud.storage.StoragePool;
26-
import com.cloud.storage.StoragePoolHostVO;
27-
import com.cloud.storage.Volume;
28-
import com.cloud.storage.VolumeVO;
29-
import com.cloud.storage.dao.StoragePoolHostDao;
30-
import com.cloud.utils.Pair;
31-
import com.cloud.vm.VirtualMachine;
32-
import com.cloud.vm.VirtualMachineManager;
19+
import static org.junit.Assert.assertEquals;
20+
21+
import java.util.ArrayList;
22+
import java.util.HashMap;
23+
import java.util.List;
24+
import java.util.Map;
25+
3326
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
3427
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
3528
import org.junit.Assert;
@@ -46,12 +39,20 @@
4639
import org.springframework.test.context.ContextConfiguration;
4740
import org.springframework.test.context.support.AnnotationConfigContextLoader;
4841

49-
import static org.junit.Assert.assertEquals;
50-
51-
import java.util.ArrayList;
52-
import java.util.HashMap;
53-
import java.util.List;
54-
import java.util.Map;
42+
import com.cloud.agent.api.Command;
43+
import com.cloud.agent.api.MigrateVmToPoolCommand;
44+
import com.cloud.dc.ClusterDetailsDao;
45+
import com.cloud.host.HostVO;
46+
import com.cloud.host.dao.HostDao;
47+
import com.cloud.storage.Storage.ProvisioningType;
48+
import com.cloud.storage.StoragePool;
49+
import com.cloud.storage.StoragePoolHostVO;
50+
import com.cloud.storage.Volume;
51+
import com.cloud.storage.VolumeVO;
52+
import com.cloud.storage.dao.StoragePoolHostDao;
53+
import com.cloud.utils.Pair;
54+
import com.cloud.vm.VirtualMachine;
55+
import com.cloud.vm.VirtualMachineManager;
5556

5657
@RunWith(PowerMockRunner.class)
5758
@PrepareForTest({VMwareGuru.class})
@@ -105,7 +106,7 @@ public void finalizeMigrateForLocalStorageToHaveTargetHostGuid(){
105106
Mockito.when(localStorage.isLocal()).thenReturn(true);
106107
Pair<Long, Long> clusterAndHost = new Pair<>(1L, 1L);
107108

108-
Mockito.when(vmManager.findClusterAndHostIdForVm(1L)).thenReturn(clusterAndHost);
109+
Mockito.when(vmManager.findClusterAndHostIdForVm(vm, true)).thenReturn(clusterAndHost);
109110

110111
List<StoragePoolHostVO> storagePoolHostVOS = new ArrayList<>();
111112
storagePoolHostVOS.add(storagePoolHostVO);

0 commit comments

Comments
 (0)