Skip to content

Commit 637a102

Browse files
Fix for VMware VM migration with volume in local storage (apache#6483)
* Fix VMware VM migration with volume in case of local storage * Break the loop once target host is found * Code optimisations in getting the target host guid for local storage * Fixed code smells and added unit test
1 parent 2326164 commit 637a102

File tree

2 files changed

+147
-1
lines changed

2 files changed

+147
-1
lines changed

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

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727

2828
import javax.inject.Inject;
2929

30+
import com.cloud.storage.StoragePoolHostVO;
31+
import com.cloud.storage.dao.StoragePoolHostDao;
3032
import org.apache.cloudstack.acl.ControlledEntity;
3133
import org.apache.cloudstack.backup.Backup;
3234
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
@@ -184,6 +186,7 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
184186
@Inject UserVmDao userVmDao;
185187
@Inject DiskOfferingDao diskOfferingDao;
186188
@Inject PhysicalNetworkDao physicalNetworkDao;
189+
@Inject StoragePoolHostDao storagePoolHostDao;
187190

188191
protected VMwareGuru() {
189192
super();
@@ -1070,6 +1073,13 @@ private boolean isInterClusterMigration(Long srcClusterId, Long destClusterId) {
10701073
return srcClusterId != null && destClusterId != null && ! srcClusterId.equals(destClusterId);
10711074
}
10721075

1076+
private String getHostGuidForLocalStorage(StoragePool pool) {
1077+
List<StoragePoolHostVO> storagePoolHostVOs = storagePoolHostDao.listByPoolId(pool.getId());
1078+
StoragePoolHostVO storagePoolHostVO = storagePoolHostVOs.get(0);
1079+
HostVO hostVO = _hostDao.findById(storagePoolHostVO.getHostId());
1080+
return hostVO.getGuid();
1081+
}
1082+
10731083
private String getHostGuidInTargetCluster(boolean isInterClusterMigration, Long destClusterId) {
10741084
String hostGuidInTargetCluster = null;
10751085
if (isInterClusterMigration) {
@@ -1096,6 +1106,7 @@ public List<Command> finalizeMigrate(VirtualMachine vm, Map<Volume, StoragePool>
10961106
// OfflineVmwareMigration: specialised migration command
10971107
List<Pair<VolumeTO, StorageFilerTO>> volumeToFilerTo = new ArrayList<Pair<VolumeTO, StorageFilerTO>>();
10981108
Long poolClusterId = null;
1109+
StoragePool targetLocalPoolForVM = null;
10991110
for (Map.Entry<Volume, StoragePool> entry : volumeToPool.entrySet()) {
11001111
Volume volume = entry.getKey();
11011112
StoragePool pool = entry.getValue();
@@ -1104,13 +1115,18 @@ public List<Command> finalizeMigrate(VirtualMachine vm, Map<Volume, StoragePool>
11041115
if (pool.getClusterId() != null) {
11051116
poolClusterId = pool.getClusterId();
11061117
}
1118+
if (volume.getVolumeType().equals(Volume.Type.ROOT) && pool.isLocal()) {
1119+
targetLocalPoolForVM = pool;
1120+
}
11071121
volumeToFilerTo.add(new Pair<VolumeTO, StorageFilerTO>(volumeTo, filerTo));
11081122
}
11091123
final Long destClusterId = poolClusterId;
11101124
final Long srcClusterId = vmManager.findClusterAndHostIdForVm(vm.getId()).first();
11111125
final boolean isInterClusterMigration = isInterClusterMigration(destClusterId, srcClusterId);
1126+
String targetHostGuid = getTargetHostGuid(targetLocalPoolForVM, destClusterId, isInterClusterMigration);
1127+
11121128
MigrateVmToPoolCommand migrateVmToPoolCommand = new MigrateVmToPoolCommand(vm.getInstanceName(),
1113-
volumeToFilerTo, getHostGuidInTargetCluster(isInterClusterMigration, destClusterId), true);
1129+
volumeToFilerTo, targetHostGuid, true);
11141130
commands.add(migrateVmToPoolCommand);
11151131

11161132
// OfflineVmwareMigration: cleanup if needed
@@ -1127,6 +1143,17 @@ public List<Command> finalizeMigrate(VirtualMachine vm, Map<Volume, StoragePool>
11271143
return commands;
11281144
}
11291145

1146+
private String getTargetHostGuid(StoragePool targetLocalPoolForVM, Long destClusterId, boolean isInterClusterMigration) {
1147+
String targetHostGuid = null;
1148+
if (targetLocalPoolForVM != null) {
1149+
// Get the target host for local storage migration
1150+
targetHostGuid = getHostGuidForLocalStorage(targetLocalPoolForVM);
1151+
} else {
1152+
targetHostGuid = getHostGuidInTargetCluster(isInterClusterMigration, destClusterId);
1153+
}
1154+
return targetHostGuid;
1155+
}
1156+
11301157
@Override
11311158
protected VirtualMachineTO toVirtualMachineTO(VirtualMachineProfile vmProfile) {
11321159
return super.toVirtualMachineTO(vmProfile);
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package com.cloud.hypervisor.guru;
18+
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.StoragePool;
25+
import com.cloud.storage.StoragePoolHostVO;
26+
import com.cloud.storage.Volume;
27+
import com.cloud.storage.dao.StoragePoolHostDao;
28+
import com.cloud.utils.Pair;
29+
import com.cloud.vm.VirtualMachine;
30+
import com.cloud.vm.VirtualMachineManager;
31+
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
32+
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
33+
import org.junit.Assert;
34+
import org.junit.Before;
35+
import org.junit.Test;
36+
import org.junit.runner.RunWith;
37+
import org.mockito.InjectMocks;
38+
import org.mockito.Mock;
39+
import org.mockito.Mockito;
40+
import org.mockito.MockitoAnnotations;
41+
import org.mockito.Spy;
42+
import org.powermock.core.classloader.annotations.PrepareForTest;
43+
import org.powermock.modules.junit4.PowerMockRunner;
44+
import org.springframework.test.context.ContextConfiguration;
45+
import org.springframework.test.context.support.AnnotationConfigContextLoader;
46+
47+
import java.util.ArrayList;
48+
import java.util.HashMap;
49+
import java.util.List;
50+
import java.util.Map;
51+
52+
@RunWith(PowerMockRunner.class)
53+
@PrepareForTest({VMwareGuru.class})
54+
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
55+
public class VMwareGuruTest {
56+
57+
@Spy
58+
@InjectMocks
59+
private VMwareGuru vMwareGuru = new VMwareGuru();
60+
61+
@Mock
62+
PrimaryDataStoreDao _storagePoolDao;
63+
64+
@Mock
65+
StoragePoolHostDao storagePoolHostDao;
66+
67+
@Mock
68+
HostDao _hostDao;
69+
70+
@Mock
71+
VirtualMachineManager vmManager;
72+
73+
@Mock
74+
ClusterDetailsDao _clusterDetailsDao;
75+
76+
@Before
77+
public void testSetUp() throws Exception {
78+
MockitoAnnotations.initMocks(this);
79+
}
80+
81+
@Test
82+
public void finalizeMigrateForLocalStorageToHaveTargetHostGuid(){
83+
VirtualMachine vm = Mockito.mock(VirtualMachine.class);
84+
Map<Volume, StoragePool> volumeToPool = new HashMap<>();
85+
Volume rootVolume = Mockito.mock(Volume.class);
86+
Volume dataVolume = Mockito.mock(Volume.class);
87+
StoragePool localStorage = Mockito.mock(StoragePool.class);
88+
volumeToPool.put(rootVolume, localStorage);
89+
volumeToPool.put(dataVolume, localStorage);
90+
91+
// prepare localstorage host guid
92+
StoragePoolVO storagePoolVO = Mockito.mock(StoragePoolVO.class);
93+
StoragePoolHostVO storagePoolHostVO = Mockito.mock(StoragePoolHostVO.class);
94+
HostVO hostVO = Mockito.mock(HostVO.class);
95+
96+
Mockito.when(localStorage.getId()).thenReturn(1L);
97+
Mockito.when(vm.getId()).thenReturn(1L);
98+
Mockito.when(_storagePoolDao.findById(1L)).thenReturn(storagePoolVO);
99+
Mockito.when(rootVolume.getVolumeType()).thenReturn(Volume.Type.ROOT);
100+
Mockito.when(dataVolume.getVolumeType()).thenReturn(Volume.Type.DATADISK);
101+
Mockito.when(localStorage.isLocal()).thenReturn(true);
102+
Pair<Long, Long> clusterAndHost = new Pair<>(1L, 1L);
103+
104+
Mockito.when(vmManager.findClusterAndHostIdForVm(1L)).thenReturn(clusterAndHost);
105+
106+
List<StoragePoolHostVO> storagePoolHostVOS = new ArrayList<>();
107+
storagePoolHostVOS.add(storagePoolHostVO);
108+
Mockito.when(storagePoolHostDao.listByPoolId(1L)).thenReturn(storagePoolHostVOS);
109+
Mockito.when(storagePoolHostVO.getHostId()).thenReturn(2L);
110+
Mockito.when(_hostDao.findById(2L)).thenReturn(hostVO);
111+
Mockito.when(hostVO.getGuid()).thenReturn("HostSystem:[email protected]");
112+
113+
List<Command> commandsList = vMwareGuru.finalizeMigrate(vm, volumeToPool);
114+
115+
MigrateVmToPoolCommand migrateVmToPoolCommand = (MigrateVmToPoolCommand) commandsList.get(0);
116+
Assert.assertEquals("HostSystem:[email protected]", migrateVmToPoolCommand.getHostGuidInTargetCluster());
117+
}
118+
119+
}

0 commit comments

Comments
 (0)