Skip to content

Commit a30d518

Browse files
authored
vmware: fix stopped VM volume migration (#4758)
* prevent other vm disks getting deleted Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> * vmware: fix inter-cluster stopped vm migration Fixes #4838 For inter-cluster migration without shared storage, VMware needs a host to be specified. Fix is to specify an appropriate host in the target cluster. Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> * fix detached volume inter-cluster migration Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> * cleanup unused method Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> * review changes Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> * changes Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> * vmware: allow attached volume migration using VmwareStorageMotionStrategy Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> * find vm clusterid with multiple ROOT volumes VM can have multiple ROOT volumes and some can be on zone-wide store therefore iterate over all of them till a cluster ID is found. Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> * fix successive storage migration Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> * fix intercluster check Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> * refactor vm cluster, host method Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> * remove inter-pod check Added by mistake, VMware won't have pods Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> * address review comment Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
1 parent b4ee4ac commit a30d518

File tree

8 files changed

+184
-159
lines changed

8 files changed

+184
-159
lines changed

core/src/main/java/com/cloud/agent/api/storage/MigrateVolumeCommand.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ public MigrateVolumeCommand(long volumeId, String volumePath, StoragePool pool,
5555
this.setWait(timeout);
5656
}
5757

58-
public MigrateVolumeCommand(long volumeId, String volumePath, StoragePool sourcePool, StoragePool targetPool, String hostGuidInTargetCluster) {
59-
this(volumeId,volumePath,targetPool, null, Volume.Type.UNKNOWN, -1);
58+
public MigrateVolumeCommand(long volumeId, String volumePath, String attachedVmName, StoragePool sourcePool, StoragePool targetPool, String hostGuidInTargetCluster) {
59+
this(volumeId,volumePath,targetPool, attachedVmName, Volume.Type.UNKNOWN, -1);
6060
this.sourcePool = new StorageFilerTO(sourcePool);
6161
this.hostGuidInTargetCluster = hostGuidInTargetCluster;
6262
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import com.cloud.template.VirtualMachineTemplate;
4545
import com.cloud.user.Account;
4646
import com.cloud.uservm.UserVm;
47+
import com.cloud.utils.Pair;
4748
import com.cloud.utils.component.Manager;
4849
import com.cloud.utils.fsm.NoTransitionException;
4950

@@ -255,4 +256,6 @@ static String getHypervisorHostname(String name) {
255256
boolean unmanage(String vmUuid);
256257

257258
UserVm restoreVirtualMachine(long vmId, Long newTemplateId) throws ResourceUnavailableException, InsufficientCapacityException;
259+
260+
Pair<Long, Long> findClusterAndHostIdForVm(long vmId);
258261
}

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

Lines changed: 49 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2294,43 +2294,6 @@ private void markVolumesInPool(VMInstanceVO vm, StoragePool destPool, Answer[] h
22942294
}
22952295
}
22962296

2297-
private Pair<Long, Long> findClusterAndHostIdForVm(VMInstanceVO vm) {
2298-
Long hostId = vm.getHostId();
2299-
Long clusterId = null;
2300-
// OfflineVmwareMigration: probably this is null when vm is stopped
2301-
if(hostId == null) {
2302-
hostId = vm.getLastHostId();
2303-
if (s_logger.isDebugEnabled()) {
2304-
s_logger.debug(String.format("host id is null, using last host id %d", hostId) );
2305-
}
2306-
}
2307-
if (hostId == null) {
2308-
List<VolumeVO> volumes = _volsDao.findByInstanceAndType(vm.getId(), Type.ROOT);
2309-
if (CollectionUtils.isNotEmpty(volumes)) {
2310-
for (VolumeVO rootVolume : volumes) {
2311-
if (rootVolume.getPoolId() != null) {
2312-
StoragePoolVO pool = _storagePoolDao.findById(rootVolume.getPoolId());
2313-
if (pool != null && pool.getClusterId() != null) {
2314-
clusterId = pool.getClusterId();
2315-
List<HostVO> hosts = _hostDao.findHypervisorHostInCluster(pool.getClusterId());
2316-
if (CollectionUtils.isNotEmpty(hosts)) {
2317-
hostId = hosts.get(0).getId();
2318-
break;
2319-
}
2320-
}
2321-
}
2322-
}
2323-
}
2324-
}
2325-
if (clusterId == null && hostId != null) {
2326-
HostVO host = _hostDao.findById(hostId);
2327-
if (host != null) {
2328-
clusterId = host.getClusterId();
2329-
}
2330-
}
2331-
return new Pair<>(clusterId, hostId);
2332-
}
2333-
23342297
private void migrateThroughHypervisorOrStorage(StoragePool destPool, VMInstanceVO vm) throws StorageUnavailableException, InsufficientCapacityException {
23352298
final VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm);
23362299
Pair<Long, Long> vmClusterAndHost = findClusterAndHostIdForVm(vm);
@@ -5913,4 +5876,53 @@ private Pair<JobInfo.Status, String> orchestrateUpdateDefaultNic(final VmWorkUpd
59135876
_jobMgr.marshallResultObject(result));
59145877
}
59155878

5879+
private Pair<Long, Long> findClusterAndHostIdForVmFromVolumes(long vmId) {
5880+
Long clusterId = null;
5881+
Long hostId = null;
5882+
List<VolumeVO> volumes = _volsDao.findByInstance(vmId);
5883+
for (VolumeVO volume : volumes) {
5884+
if (Volume.State.Ready.equals(volume.getState()) &&
5885+
volume.getPoolId() != null) {
5886+
StoragePoolVO pool = _storagePoolDao.findById(volume.getPoolId());
5887+
if (pool != null && pool.getClusterId() != null) {
5888+
clusterId = pool.getClusterId();
5889+
// hostId to be used only for sending commands, capacity check skipped
5890+
List<HostVO> hosts = _hostDao.findHypervisorHostInCluster(pool.getClusterId());
5891+
if (CollectionUtils.isNotEmpty(hosts)) {
5892+
hostId = hosts.get(0).getId();
5893+
break;
5894+
}
5895+
}
5896+
}
5897+
}
5898+
return new Pair<>(clusterId, hostId);
5899+
}
5900+
5901+
private Pair<Long, Long> findClusterAndHostIdForVm(VirtualMachine vm) {
5902+
Long hostId = vm.getHostId();
5903+
Long clusterId = null;
5904+
if(hostId == null) {
5905+
hostId = vm.getLastHostId();
5906+
if (s_logger.isDebugEnabled()) {
5907+
s_logger.debug(String.format("host id is null, using last host id %d", hostId) );
5908+
}
5909+
}
5910+
if (hostId == null) {
5911+
return findClusterAndHostIdForVmFromVolumes(vm.getId());
5912+
}
5913+
HostVO host = _hostDao.findById(hostId);
5914+
if (host != null) {
5915+
clusterId = host.getClusterId();
5916+
}
5917+
return new Pair<>(clusterId, hostId);
5918+
}
5919+
5920+
@Override
5921+
public Pair<Long, Long> findClusterAndHostIdForVm(long vmId) {
5922+
VMInstanceVO vm = _vmDao.findById(vmId);
5923+
if (vm == null) {
5924+
return new Pair<>(null, null);
5925+
}
5926+
return findClusterAndHostIdForVm(vm);
5927+
}
59165928
}

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

Lines changed: 3 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -206,48 +206,7 @@ protected VMwareGuru() {
206206
@Override public VirtualMachineTO implement(VirtualMachineProfile vm) {
207207
vmwareVmImplementer.setGlobalNestedVirtualisationEnabled(VmwareEnableNestedVirtualization.value());
208208
vmwareVmImplementer.setGlobalNestedVPerVMEnabled(VmwareEnableNestedVirtualizationPerVM.value());
209-
return vmwareVmImplementer.implement(vm, toVirtualMachineTO(vm), getClusterId(vm.getId()));
210-
}
211-
212-
private Long getClusterIdFromVmVolume(long vmId) {
213-
Long clusterId = null;
214-
List<VolumeVO> volumes = _volumeDao.findByInstanceAndType(vmId, Volume.Type.ROOT);
215-
if (CollectionUtils.isNotEmpty(volumes)) {
216-
for (VolumeVO rootVolume : volumes) {
217-
if (rootVolume.getPoolId() != null) {
218-
StoragePoolVO pool = _storagePoolDao.findById(rootVolume.getPoolId());
219-
if (pool != null && pool.getClusterId() != null) {
220-
clusterId = pool.getClusterId();
221-
break;
222-
}
223-
}
224-
}
225-
}
226-
return clusterId;
227-
}
228-
229-
private Long getClusterId(long vmId) {
230-
Long clusterId = null;
231-
Long hostId = null;
232-
VMInstanceVO vm = _vmDao.findById(vmId);
233-
if (vm != null) {
234-
hostId = _vmDao.findById(vmId).getHostId();
235-
}
236-
if (vm != null && hostId == null) {
237-
// If VM is in stopped state then hostId would be undefined. Hence read last host's Id instead.
238-
hostId = _vmDao.findById(vmId).getLastHostId();
239-
}
240-
HostVO host = null;
241-
if (hostId != null) {
242-
host = _hostDao.findById(hostId);
243-
}
244-
if (host != null) {
245-
clusterId = host.getClusterId();
246-
} else {
247-
clusterId = getClusterIdFromVmVolume(vmId);
248-
}
249-
250-
return clusterId;
209+
return vmwareVmImplementer.implement(vm, toVirtualMachineTO(vm), vmManager.findClusterAndHostIdForVm(vm.getId()).first());
251210
}
252211

253212
@Override @DB public Pair<Boolean, Long> getCommandHostDelegation(long hostId, Command cmd) {
@@ -445,7 +404,7 @@ private static String resolveNameInGuid(String guid) {
445404

446405
@Override public Map<String, String> getClusterSettings(long vmId) {
447406
Map<String, String> details = new HashMap<String, String>();
448-
Long clusterId = getClusterId(vmId);
407+
Long clusterId = vmManager.findClusterAndHostIdForVm(vmId).first();
449408
if (clusterId != null) {
450409
details.put(VmwareReserveCpu.key(), VmwareReserveCpu.valueIn(clusterId).toString());
451410
details.put(VmwareReserveMemory.key(), VmwareReserveMemory.valueIn(clusterId).toString());
@@ -1120,7 +1079,7 @@ private String getHostGuidInTargetCluster(boolean isInterClusterMigration, Long
11201079
}
11211080

11221081
final Long destClusterId = destination.getClusterId();
1123-
final Long srcClusterId = getClusterId(vm.getId());
1082+
final Long srcClusterId = vmManager.findClusterAndHostIdForVm(vm.getId()).first();
11241083
final boolean isInterClusterMigration = isInterClusterMigration(destClusterId, srcClusterId);
11251084
MigrateVmToPoolCommand migrateVmToPoolCommand = new MigrateVmToPoolCommand(vm.getInstanceName(),
11261085
vols, destination.getUuid(), getHostGuidInTargetCluster(isInterClusterMigration, destClusterId), true);

plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,6 @@
3434
import java.util.concurrent.Executors;
3535
import java.util.concurrent.TimeUnit;
3636

37-
import com.cloud.hypervisor.vmware.mo.VirtualStorageObjectManagerMO;
38-
import com.cloud.hypervisor.vmware.mo.VirtualMachineDiskInfoBuilder;
39-
import com.vmware.vim25.BaseConfigInfoDiskFileBackingInfo;
40-
import com.vmware.vim25.VStorageObject;
41-
import com.vmware.vim25.VirtualDiskType;
4237
import org.apache.cloudstack.agent.directdownload.DirectDownloadCommand;
4338
import org.apache.cloudstack.storage.command.AttachAnswer;
4439
import org.apache.cloudstack.storage.command.AttachCommand;
@@ -84,7 +79,9 @@
8479
import com.cloud.hypervisor.vmware.mo.HostStorageSystemMO;
8580
import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper;
8681
import com.cloud.hypervisor.vmware.mo.NetworkDetails;
82+
import com.cloud.hypervisor.vmware.mo.VirtualMachineDiskInfoBuilder;
8783
import com.cloud.hypervisor.vmware.mo.VirtualMachineMO;
84+
import com.cloud.hypervisor.vmware.mo.VirtualStorageObjectManagerMO;
8885
import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost;
8986
import com.cloud.hypervisor.vmware.resource.VmwareResource;
9087
import com.cloud.hypervisor.vmware.util.VmwareContext;
@@ -104,6 +101,7 @@
104101
import com.cloud.vm.VmDetailConstants;
105102
import com.google.common.base.Strings;
106103
import com.google.gson.Gson;
104+
import com.vmware.vim25.BaseConfigInfoDiskFileBackingInfo;
107105
import com.vmware.vim25.DatastoreHostMount;
108106
import com.vmware.vim25.HostHostBusAdapter;
109107
import com.vmware.vim25.HostInternetScsiHba;
@@ -122,11 +120,13 @@
122120
import com.vmware.vim25.HostUnresolvedVmfsVolume;
123121
import com.vmware.vim25.InvalidStateFaultMsg;
124122
import com.vmware.vim25.ManagedObjectReference;
123+
import com.vmware.vim25.VStorageObject;
125124
import com.vmware.vim25.VirtualDeviceBackingInfo;
126125
import com.vmware.vim25.VirtualDeviceConfigSpec;
127126
import com.vmware.vim25.VirtualDeviceConfigSpecOperation;
128127
import com.vmware.vim25.VirtualDisk;
129128
import com.vmware.vim25.VirtualDiskFlatVer2BackingInfo;
129+
import com.vmware.vim25.VirtualDiskType;
130130
import com.vmware.vim25.VirtualMachineConfigSpec;
131131
import com.vmware.vim25.VmConfigInfo;
132132
import com.vmware.vim25.VmfsDatastoreExpandSpec;
@@ -2683,15 +2683,14 @@ public Answer deleteVolume(DeleteCommand cmd) {
26832683
List<VirtualDisk> virtualDisks = vmMo.getVirtualDisks();
26842684
List<String> managedDatastoreNames = getManagedDatastoreNamesFromVirtualDisks(virtualDisks);
26852685

2686+
// Preserve other disks of the VM
2687+
List<String> detachedDisks = vmMo.detachAllDisksExcept(vol.getPath(), diskInfo != null ? diskInfo.getDiskDeviceBusName() : null);
2688+
VmwareStorageLayoutHelper.moveVolumeToRootFolder(new DatacenterMO(context, morDc), detachedDisks);
26862689
// let vmMo.destroy to delete volume for us
26872690
// vmMo.tearDownDevices(new Class<?>[] { VirtualDisk.class, VirtualEthernetCard.class });
2688-
26892691
if (isManaged) {
2690-
List<String> detachedDisks = vmMo.detachAllDisksExcept(vol.getPath(), diskInfo != null ? diskInfo.getDiskDeviceBusName() : null);
2691-
VmwareStorageLayoutHelper.moveVolumeToRootFolder(new DatacenterMO(context, morDc), detachedDisks);
26922692
vmMo.unregisterVm();
2693-
}
2694-
else {
2693+
} else {
26952694
vmMo.destroy();
26962695
}
26972696

0 commit comments

Comments
 (0)