mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Fix resize volume and migrate volume to update volume path if DRS is applied on volume in datastore cluster (#5539)
* Fix resize volume and migrate volume to update volume path if DRS is applied on volume in datastore cluster * Change in constructors * Naming changes * Remove commented code * Refactor code for more readability * Addressed review comments on code refactor
This commit is contained in:
parent
6e216dd0d1
commit
cd4e7e031a
@ -30,6 +30,7 @@ import com.cloud.storage.Volume;
|
|||||||
public class MigrateVolumeCommand extends Command {
|
public class MigrateVolumeCommand extends Command {
|
||||||
long volumeId;
|
long volumeId;
|
||||||
String volumePath;
|
String volumePath;
|
||||||
|
String chainInfo;
|
||||||
StorageFilerTO pool;
|
StorageFilerTO pool;
|
||||||
StorageFilerTO sourcePool;
|
StorageFilerTO sourcePool;
|
||||||
String attachedVmName;
|
String attachedVmName;
|
||||||
@ -49,14 +50,22 @@ public class MigrateVolumeCommand extends Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public MigrateVolumeCommand(long volumeId, String volumePath, StoragePool pool, String attachedVmName, Volume.Type volumeType, int timeout) {
|
public MigrateVolumeCommand(long volumeId, String volumePath, StoragePool pool, String attachedVmName, Volume.Type volumeType, int timeout) {
|
||||||
this(volumeId,volumePath,pool,timeout);
|
this(volumeId, volumePath, pool, timeout);
|
||||||
this.attachedVmName = attachedVmName;
|
this.attachedVmName = attachedVmName;
|
||||||
this.volumeType = volumeType;
|
this.volumeType = volumeType;
|
||||||
this.setWait(timeout);
|
this.setWait(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MigrateVolumeCommand(long volumeId, String volumePath, String attachedVmName, StoragePool sourcePool, StoragePool targetPool, String hostGuidInTargetCluster) {
|
public MigrateVolumeCommand(long volumeId, String volumePath, StoragePool pool, String attachedVmName, Volume.Type volumeType, int timeout, String chainInfo) {
|
||||||
this(volumeId,volumePath,targetPool, attachedVmName, Volume.Type.UNKNOWN, -1);
|
this(volumeId, volumePath, pool, timeout);
|
||||||
|
this.attachedVmName = attachedVmName;
|
||||||
|
this.volumeType = volumeType;
|
||||||
|
this.chainInfo = chainInfo;
|
||||||
|
this.setWait(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MigrateVolumeCommand(long volumeId, String volumePath, String attachedVmName, StoragePool sourcePool, StoragePool targetPool, String hostGuidInTargetCluster, String chainInfo) {
|
||||||
|
this(volumeId,volumePath,targetPool, attachedVmName, Volume.Type.UNKNOWN, -1, chainInfo);
|
||||||
this.sourcePool = new StorageFilerTO(sourcePool);
|
this.sourcePool = new StorageFilerTO(sourcePool);
|
||||||
this.hostGuidInTargetCluster = hostGuidInTargetCluster;
|
this.hostGuidInTargetCluster = hostGuidInTargetCluster;
|
||||||
}
|
}
|
||||||
@ -134,4 +143,6 @@ public class MigrateVolumeCommand extends Command {
|
|||||||
public int getWaitInMillSeconds() {
|
public int getWaitInMillSeconds() {
|
||||||
return getWait() * 1000;
|
return getWait() * 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getChainInfo() { return chainInfo; }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,6 +29,7 @@ public class ResizeVolumeCommand extends Command {
|
|||||||
private Long newSize;
|
private Long newSize;
|
||||||
private boolean shrinkOk;
|
private boolean shrinkOk;
|
||||||
private String vmInstance;
|
private String vmInstance;
|
||||||
|
private String chainInfo;
|
||||||
|
|
||||||
/* For managed storage */
|
/* For managed storage */
|
||||||
private boolean managed;
|
private boolean managed;
|
||||||
@ -47,6 +48,11 @@ public class ResizeVolumeCommand extends Command {
|
|||||||
this.managed = false;
|
this.managed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ResizeVolumeCommand(String path, StorageFilerTO pool, Long currentSize, Long newSize, boolean shrinkOk, String vmInstance, String chainInfo) {
|
||||||
|
this(path, pool, currentSize, newSize, shrinkOk, vmInstance);
|
||||||
|
this.chainInfo = chainInfo;
|
||||||
|
}
|
||||||
|
|
||||||
public ResizeVolumeCommand(String path, StorageFilerTO pool, Long currentSize, Long newSize, boolean shrinkOk, String vmInstance,
|
public ResizeVolumeCommand(String path, StorageFilerTO pool, Long currentSize, Long newSize, boolean shrinkOk, String vmInstance,
|
||||||
boolean isManaged, String iScsiName) {
|
boolean isManaged, String iScsiName) {
|
||||||
this(path, pool, currentSize, newSize, shrinkOk, vmInstance);
|
this(path, pool, currentSize, newSize, shrinkOk, vmInstance);
|
||||||
@ -81,6 +87,8 @@ public class ResizeVolumeCommand extends Command {
|
|||||||
|
|
||||||
public String get_iScsiName() {return iScsiName; }
|
public String get_iScsiName() {return iScsiName; }
|
||||||
|
|
||||||
|
public String getChainInfo() {return chainInfo; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -24,6 +24,8 @@ import java.util.Map;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.to.DiskTO;
|
||||||
|
import com.cloud.storage.Storage;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
|
import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
|
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy;
|
||||||
@ -447,8 +449,13 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
|
|||||||
int waitInterval = NumbersUtil.parseInt(value, Integer.parseInt(Config.MigrateWait.getDefaultValue()));
|
int waitInterval = NumbersUtil.parseInt(value, Integer.parseInt(Config.MigrateWait.getDefaultValue()));
|
||||||
|
|
||||||
VolumeInfo volume = (VolumeInfo)srcData;
|
VolumeInfo volume = (VolumeInfo)srcData;
|
||||||
|
StoragePool srcPool = (StoragePool)dataStoreMgr.getDataStore(srcData.getDataStore().getId(), DataStoreRole.Primary);
|
||||||
StoragePool destPool = (StoragePool)dataStoreMgr.getDataStore(destData.getDataStore().getId(), DataStoreRole.Primary);
|
StoragePool destPool = (StoragePool)dataStoreMgr.getDataStore(destData.getDataStore().getId(), DataStoreRole.Primary);
|
||||||
MigrateVolumeCommand command = new MigrateVolumeCommand(volume.getId(), volume.getPath(), destPool, volume.getAttachedVmName(), volume.getVolumeType(), waitInterval);
|
MigrateVolumeCommand command = new MigrateVolumeCommand(volume.getId(), volume.getPath(), destPool, volume.getAttachedVmName(), volume.getVolumeType(), waitInterval, volume.getChainInfo());
|
||||||
|
if (srcPool.getParent() != 0) {
|
||||||
|
command.setContextParam(DiskTO.PROTOCOL_TYPE, Storage.StoragePoolType.DatastoreCluster.toString());
|
||||||
|
}
|
||||||
|
|
||||||
EndPoint ep = selector.select(srcData, StorageAction.MIGRATEVOLUME);
|
EndPoint ep = selector.select(srcData, StorageAction.MIGRATEVOLUME);
|
||||||
Answer answer = null;
|
Answer answer = null;
|
||||||
if (ep == null) {
|
if (ep == null) {
|
||||||
|
|||||||
@ -775,9 +775,13 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
String vmName = cmd.getInstanceName();
|
String vmName = cmd.getInstanceName();
|
||||||
long newSize = cmd.getNewSize() / ResourceType.bytesToKiB;
|
long newSize = cmd.getNewSize() / ResourceType.bytesToKiB;
|
||||||
long oldSize = cmd.getCurrentSize() / ResourceType.bytesToKiB;
|
long oldSize = cmd.getCurrentSize() / ResourceType.bytesToKiB;
|
||||||
|
boolean managed = cmd.isManaged();
|
||||||
|
String poolUUID = cmd.getPoolUuid();
|
||||||
|
String chainInfo = cmd.getChainInfo();
|
||||||
boolean useWorkerVm = false;
|
boolean useWorkerVm = false;
|
||||||
|
|
||||||
VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext());
|
VmwareContext context = getServiceContext();
|
||||||
|
VmwareHypervisorHost hyperHost = getHyperHost(context);
|
||||||
VirtualMachineMO vmMo = null;
|
VirtualMachineMO vmMo = null;
|
||||||
|
|
||||||
String vmdkDataStorePath = null;
|
String vmdkDataStorePath = null;
|
||||||
@ -789,24 +793,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
} else if (newSize == oldSize) {
|
} else if (newSize == oldSize) {
|
||||||
return new ResizeVolumeAnswer(cmd, true, "success", newSize * ResourceType.bytesToKiB);
|
return new ResizeVolumeAnswer(cmd, true, "success", newSize * ResourceType.bytesToKiB);
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
// FR41 this is yet to fix
|
|
||||||
ManagedObjectReference morDS1 = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, cmd.getPoolUuid());
|
|
||||||
DatastoreMO dsMo1 = new DatastoreMO(hyperHost.getContext(), morDS1);
|
|
||||||
vmdkDataStorePath = VmwareStorageLayoutHelper.getLegacyDatastorePathFromVmdkFileName(dsMo1, path + VMDK_EXTENSION);
|
|
||||||
DatastoreFile dsFile1 = new DatastoreFile(vmdkDataStorePath);
|
|
||||||
|
|
||||||
s_logger.debug("vDiskid does not exist for volume " + vmdkDataStorePath + " registering the disk now");
|
|
||||||
VirtualStorageObjectManagerMO vStorageObjectManagerMO = new VirtualStorageObjectManagerMO(getServiceContext());
|
|
||||||
try {
|
|
||||||
VStorageObject vStorageObject = vStorageObjectManagerMO.registerVirtualDisk(dsFile1, null, dsMo1.getOwnerDatacenter().second());
|
|
||||||
VStorageObjectConfigInfo diskConfigInfo = vStorageObject.getConfig();
|
|
||||||
ID vdiskId = diskConfigInfo.getId();
|
|
||||||
} catch (Throwable e) {
|
|
||||||
if (e instanceof AlreadyExistsFaultMsg) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
if (vmName.equalsIgnoreCase("none")) {
|
if (vmName.equalsIgnoreCase("none")) {
|
||||||
// OfflineVmwareMigration: we need to refactor the worker vm creation out for use in migration methods as well as here
|
// OfflineVmwareMigration: we need to refactor the worker vm creation out for use in migration methods as well as here
|
||||||
@ -852,26 +838,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
throw new Exception(msg);
|
throw new Exception(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// OfflineVmwareMigration: 5. ignore/replace the rest of the try-block; It is the functional bit
|
|
||||||
Pair<VirtualDisk, String> vdisk = vmMo.getDiskDevice(path);
|
|
||||||
|
|
||||||
if (vdisk == null) {
|
|
||||||
if (s_logger.isTraceEnabled()) {
|
|
||||||
s_logger.trace("resize volume done (failed)");
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Exception("No such disk device: " + path);
|
|
||||||
}
|
|
||||||
|
|
||||||
// IDE virtual disk cannot be re-sized if VM is running
|
|
||||||
if (vdisk.second() != null && vdisk.second().contains("ide")) {
|
|
||||||
throw new Exception("Re-sizing a virtual disk over an IDE controller is not supported in the VMware hypervisor. " +
|
|
||||||
"Please re-try when virtual disk is attached to a VM using a SCSI controller.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cmd.isManaged()) {
|
|
||||||
VmwareContext context = getServiceContext();
|
|
||||||
|
|
||||||
|
if (managed) {
|
||||||
ManagedObjectReference morCluster = hyperHost.getHyperHostCluster();
|
ManagedObjectReference morCluster = hyperHost.getHyperHostCluster();
|
||||||
ClusterMO clusterMO = new ClusterMO(context, morCluster);
|
ClusterMO clusterMO = new ClusterMO(context, morCluster);
|
||||||
|
|
||||||
@ -892,15 +860,26 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
_storageProcessor.expandDatastore(hostDatastoreSystem, dsMo);
|
_storageProcessor.expandDatastore(hostDatastoreSystem, dsMo);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vdisk.second() != null && !vdisk.second().toLowerCase().startsWith("scsi")) {
|
boolean volumePathChangeObserved = false;
|
||||||
s_logger.error("Unsupported disk device bus " + vdisk.second());
|
boolean datastoreChangeObserved = false;
|
||||||
throw new Exception("Unsupported disk device bus " + vdisk.second());
|
|
||||||
|
Pair<String, String> pathAndChainInfo = getNewPathAndChainInfoInDatastoreCluster(vmMo, path, chainInfo, managed, cmd.get_iScsiName(), poolUUID, cmd.getContextParam(DiskTO.PROTOCOL_TYPE));
|
||||||
|
Pair<String, String> poolUUIDandChainInfo = getNewPoolUUIDAndChainInfoInDatastoreCluster(vmMo, path, chainInfo, managed, cmd.get_iScsiName(), poolUUID, cmd.getContextParam(DiskTO.PROTOCOL_TYPE));
|
||||||
|
|
||||||
|
if (pathAndChainInfo != null) {
|
||||||
|
volumePathChangeObserved = true;
|
||||||
|
path = pathAndChainInfo.first();
|
||||||
|
chainInfo = pathAndChainInfo.second();
|
||||||
}
|
}
|
||||||
VirtualDisk disk = vdisk.first();
|
|
||||||
if ((VirtualDiskFlatVer2BackingInfo) disk.getBacking() != null && ((VirtualDiskFlatVer2BackingInfo) disk.getBacking()).getParent() != null) {
|
if (poolUUIDandChainInfo != null) {
|
||||||
s_logger.error("Resize is not supported because Disk device has Parent " + ((VirtualDiskFlatVer2BackingInfo) disk.getBacking()).getParent().getUuid());
|
datastoreChangeObserved = true;
|
||||||
throw new Exception("Resize is not supported because Disk device has Parent " + ((VirtualDiskFlatVer2BackingInfo) disk.getBacking()).getParent().getUuid());
|
poolUUID = poolUUIDandChainInfo.first();
|
||||||
|
chainInfo = poolUUIDandChainInfo.second();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OfflineVmwareMigration: 5. ignore/replace the rest of the try-block; It is the functional bit
|
||||||
|
VirtualDisk disk = getDiskAfterResizeDiskValidations(vmMo, path);
|
||||||
String vmdkAbsFile = getAbsoluteVmdkFile(disk);
|
String vmdkAbsFile = getAbsoluteVmdkFile(disk);
|
||||||
|
|
||||||
if (vmdkAbsFile != null && !vmdkAbsFile.isEmpty()) {
|
if (vmdkAbsFile != null && !vmdkAbsFile.isEmpty()) {
|
||||||
@ -922,7 +901,17 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
throw new Exception("Failed to configure VM to resize disk. vmName: " + vmName);
|
throw new Exception("Failed to configure VM to resize disk. vmName: " + vmName);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ResizeVolumeAnswer(cmd, true, "success", newSize * 1024);
|
ResizeVolumeAnswer answer = new ResizeVolumeAnswer(cmd, true, "success", newSize * 1024);
|
||||||
|
if (datastoreChangeObserved) {
|
||||||
|
answer.setContextParam("datastoreUUID", poolUUID);
|
||||||
|
answer.setContextParam("chainInfo", chainInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (volumePathChangeObserved) {
|
||||||
|
answer.setContextParam("volumePath", path);
|
||||||
|
answer.setContextParam("chainInfo", chainInfo);
|
||||||
|
}
|
||||||
|
return answer;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
s_logger.error("Unable to resize volume", e);
|
s_logger.error("Unable to resize volume", e);
|
||||||
|
|
||||||
@ -944,6 +933,79 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private VirtualDisk getDiskAfterResizeDiskValidations(VirtualMachineMO vmMo, String volumePath) throws Exception {
|
||||||
|
Pair<VirtualDisk, String> vdisk = vmMo.getDiskDevice(volumePath);
|
||||||
|
if (vdisk == null) {
|
||||||
|
if (s_logger.isTraceEnabled()) {
|
||||||
|
s_logger.trace("resize volume done (failed)");
|
||||||
|
}
|
||||||
|
throw new Exception("No such disk device: " + volumePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDE virtual disk cannot be re-sized if VM is running
|
||||||
|
if (vdisk.second() != null && vdisk.second().contains("ide")) {
|
||||||
|
throw new Exception("Re-sizing a virtual disk over an IDE controller is not supported in the VMware hypervisor. " +
|
||||||
|
"Please re-try when virtual disk is attached to a VM using a SCSI controller.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vdisk.second() != null && !vdisk.second().toLowerCase().startsWith("scsi")) {
|
||||||
|
s_logger.error("Unsupported disk device bus " + vdisk.second());
|
||||||
|
throw new Exception("Unsupported disk device bus " + vdisk.second());
|
||||||
|
}
|
||||||
|
VirtualDisk disk = vdisk.first();
|
||||||
|
if ((VirtualDiskFlatVer2BackingInfo) disk.getBacking() != null && ((VirtualDiskFlatVer2BackingInfo) disk.getBacking()).getParent() != null) {
|
||||||
|
s_logger.error("Resize is not supported because Disk device has Parent " + ((VirtualDiskFlatVer2BackingInfo) disk.getBacking()).getParent().getUuid());
|
||||||
|
throw new Exception("Resize is not supported because Disk device has Parent " + ((VirtualDiskFlatVer2BackingInfo) disk.getBacking()).getParent().getUuid());
|
||||||
|
}
|
||||||
|
return disk;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Pair<String, String> getNewPathAndChainInfoInDatastoreCluster(VirtualMachineMO vmMo, String path, String chainInfo, boolean managed, String iscsiName, String poolUUID, String poolType) throws Exception {
|
||||||
|
VmwareContext context = getServiceContext();
|
||||||
|
VmwareHypervisorHost hyperHost = getHyperHost(context);
|
||||||
|
if (poolType != null && poolType.equalsIgnoreCase(Storage.StoragePoolType.DatastoreCluster.toString())) {
|
||||||
|
VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder();
|
||||||
|
VirtualMachineDiskInfo matchingExistingDisk = getMatchingExistingDiskWithVolumeDetails(diskInfoBuilder, path, chainInfo, managed, iscsiName, poolUUID, hyperHost, context);
|
||||||
|
if (diskInfoBuilder != null && matchingExistingDisk != null) {
|
||||||
|
String[] diskChain = matchingExistingDisk.getDiskChain();
|
||||||
|
DatastoreFile file = new DatastoreFile(diskChain[0]);
|
||||||
|
if (!file.getFileBaseName().equalsIgnoreCase(path)) {
|
||||||
|
if (s_logger.isInfoEnabled())
|
||||||
|
s_logger.info("Detected disk-chain top file change on volume: " + path + " -> " + file.getFileBaseName());
|
||||||
|
path = file.getFileBaseName();
|
||||||
|
chainInfo = _gson.toJson(matchingExistingDisk);
|
||||||
|
return new Pair<>(path, chainInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Pair<String, String> getNewPoolUUIDAndChainInfoInDatastoreCluster(VirtualMachineMO vmMo, String path, String chainInfo, boolean managed, String iscsiName, String poolUUID, String poolType) throws Exception {
|
||||||
|
VmwareContext context = getServiceContext();
|
||||||
|
VmwareHypervisorHost hyperHost = getHyperHost(context);
|
||||||
|
if (poolType != null && poolType.equalsIgnoreCase(Storage.StoragePoolType.DatastoreCluster.toString())) {
|
||||||
|
VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder();
|
||||||
|
VirtualMachineDiskInfo matchingExistingDisk = getMatchingExistingDiskWithVolumeDetails(diskInfoBuilder, path, chainInfo, managed, iscsiName, poolUUID, hyperHost, context);
|
||||||
|
if (diskInfoBuilder != null && matchingExistingDisk != null) {
|
||||||
|
String[] diskChain = matchingExistingDisk.getDiskChain();
|
||||||
|
DatastoreFile file = new DatastoreFile(diskChain[0]);
|
||||||
|
DatacenterMO dcMo = new DatacenterMO(hyperHost.getContext(), hyperHost.getHyperHostDatacenter());
|
||||||
|
DatastoreMO diskDatastoreMofromVM = new DatastoreMO(context, dcMo.findDatastore(file.getDatastoreName()));
|
||||||
|
if (diskDatastoreMofromVM != null) {
|
||||||
|
String actualPoolUuid = diskDatastoreMofromVM.getCustomFieldValue(CustomFieldConstants.CLOUD_UUID);
|
||||||
|
if (!actualPoolUuid.equalsIgnoreCase(poolUUID)) {
|
||||||
|
s_logger.warn(String.format("Volume %s found to be in a different storage pool %s", path, actualPoolUuid));
|
||||||
|
poolUUID = actualPoolUuid;
|
||||||
|
chainInfo = _gson.toJson(matchingExistingDisk);
|
||||||
|
return new Pair<>(poolUUID, chainInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
protected Answer execute(CheckNetworkCommand cmd) {
|
protected Answer execute(CheckNetworkCommand cmd) {
|
||||||
if (s_logger.isInfoEnabled()) {
|
if (s_logger.isInfoEnabled()) {
|
||||||
s_logger.info("Executing resource CheckNetworkCommand " + _gson.toJson(cmd));
|
s_logger.info("Executing resource CheckNetworkCommand " + _gson.toJson(cmd));
|
||||||
@ -1911,7 +1973,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
s_logger.error(msg);
|
s_logger.error(msg);
|
||||||
throw new Exception(msg);
|
throw new Exception(msg);
|
||||||
}
|
}
|
||||||
if (rootDisk.getDetails().get(DiskTO.PROTOCOL_TYPE) != null && rootDisk.getDetails().get(DiskTO.PROTOCOL_TYPE).equalsIgnoreCase("DatastoreCluster")) {
|
if (rootDisk.getDetails().get(DiskTO.PROTOCOL_TYPE) != null && rootDisk.getDetails().get(DiskTO.PROTOCOL_TYPE).equalsIgnoreCase(Storage.StoragePoolType.DatastoreCluster.toString())) {
|
||||||
if (diskInfoBuilder != null) {
|
if (diskInfoBuilder != null) {
|
||||||
DatastoreMO diskDatastoreMofromVM = getDataStoreWhereDiskExists(hyperHost, context, diskInfoBuilder, rootDisk, diskDatastores);
|
DatastoreMO diskDatastoreMofromVM = getDataStoreWhereDiskExists(hyperHost, context, diskInfoBuilder, rootDisk, diskDatastores);
|
||||||
if (diskDatastoreMofromVM != null) {
|
if (diskDatastoreMofromVM != null) {
|
||||||
@ -3254,70 +3316,82 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
nicIndex++;
|
nicIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private VirtualMachineDiskInfo getMatchingExistingDiskWithVolumeDetails(VirtualMachineDiskInfoBuilder diskInfoBuilder, String volumePath,
|
||||||
|
String chainInfo, boolean isManaged, String iScsiName, String datastoreUUID,
|
||||||
|
VmwareHypervisorHost hyperHost, VmwareContext context) throws Exception {
|
||||||
|
|
||||||
private VirtualMachineDiskInfo getMatchingExistingDisk(VirtualMachineDiskInfoBuilder diskInfoBuilder, DiskTO vol, VmwareHypervisorHost hyperHost, VmwareContext context)
|
Pair<String, String> dsNameAndFileName = getVMDiskInfo(volumePath, isManaged, iScsiName, datastoreUUID, hyperHost, context);
|
||||||
throws Exception {
|
String dsName = dsNameAndFileName.first();
|
||||||
if (diskInfoBuilder != null) {
|
String diskBackingFileBaseName = dsNameAndFileName.second();
|
||||||
VolumeObjectTO volume = (VolumeObjectTO) vol.getData();
|
|
||||||
|
|
||||||
String dsName = null;
|
VirtualMachineDiskInfo diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(diskBackingFileBaseName, dsName);
|
||||||
String diskBackingFileBaseName = null;
|
if (diskInfo != null) {
|
||||||
|
s_logger.info("Found existing disk info from volume path: " + volumePath);
|
||||||
Map<String, String> details = vol.getDetails();
|
return diskInfo;
|
||||||
boolean isManaged = details != null && Boolean.parseBoolean(details.get(DiskTO.MANAGED));
|
} else {
|
||||||
|
if (chainInfo != null) {
|
||||||
if (isManaged) {
|
VirtualMachineDiskInfo infoInChain = _gson.fromJson(chainInfo, VirtualMachineDiskInfo.class);
|
||||||
String iScsiName = details.get(DiskTO.IQN);
|
if (infoInChain != null) {
|
||||||
|
String[] disks = infoInChain.getDiskChain();
|
||||||
// if the storage is managed, iScsiName should not be null
|
if (disks.length > 0) {
|
||||||
dsName = VmwareResource.getDatastoreName(iScsiName);
|
for (String diskPath : disks) {
|
||||||
|
DatastoreFile file = new DatastoreFile(diskPath);
|
||||||
diskBackingFileBaseName = new DatastoreFile(volume.getPath()).getFileBaseName();
|
diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(file.getFileBaseName(), dsName);
|
||||||
} else {
|
|
||||||
ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, volume.getDataStore().getUuid());
|
|
||||||
DatastoreMO dsMo = new DatastoreMO(context, morDs);
|
|
||||||
|
|
||||||
dsName = dsMo.getName();
|
|
||||||
|
|
||||||
diskBackingFileBaseName = volume.getPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
VirtualMachineDiskInfo diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(diskBackingFileBaseName, dsName);
|
|
||||||
if (diskInfo != null) {
|
|
||||||
s_logger.info("Found existing disk info from volume path: " + volume.getPath());
|
|
||||||
return diskInfo;
|
|
||||||
} else {
|
|
||||||
String chainInfo = volume.getChainInfo();
|
|
||||||
if (chainInfo != null) {
|
|
||||||
VirtualMachineDiskInfo infoInChain = _gson.fromJson(chainInfo, VirtualMachineDiskInfo.class);
|
|
||||||
if (infoInChain != null) {
|
|
||||||
String[] disks = infoInChain.getDiskChain();
|
|
||||||
if (disks.length > 0) {
|
|
||||||
for (String diskPath : disks) {
|
|
||||||
DatastoreFile file = new DatastoreFile(diskPath);
|
|
||||||
diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(file.getFileBaseName(), dsName);
|
|
||||||
if (diskInfo != null) {
|
|
||||||
s_logger.info("Found existing disk from chain info: " + diskPath);
|
|
||||||
return diskInfo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (diskInfo == null) {
|
|
||||||
diskInfo = diskInfoBuilder.getDiskInfoByDeviceBusName(infoInChain.getDiskDeviceBusName());
|
|
||||||
if (diskInfo != null) {
|
if (diskInfo != null) {
|
||||||
s_logger.info("Found existing disk from from chain device bus information: " + infoInChain.getDiskDeviceBusName());
|
s_logger.info("Found existing disk from chain info: " + diskPath);
|
||||||
return diskInfo;
|
return diskInfo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (diskInfo == null) {
|
||||||
|
diskInfo = diskInfoBuilder.getDiskInfoByDeviceBusName(infoInChain.getDiskDeviceBusName());
|
||||||
|
if (diskInfo != null) {
|
||||||
|
s_logger.info("Found existing disk from from chain device bus information: " + infoInChain.getDiskDeviceBusName());
|
||||||
|
return diskInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Pair<String, String> getVMDiskInfo(String volumePath, boolean isManaged, String iScsiName, String datastoreUUID,
|
||||||
|
VmwareHypervisorHost hyperHost, VmwareContext context) throws Exception {
|
||||||
|
String dsName = null;
|
||||||
|
String diskBackingFileBaseName = null;
|
||||||
|
|
||||||
|
if (isManaged) {
|
||||||
|
// if the storage is managed, iScsiName should not be null
|
||||||
|
dsName = VmwareResource.getDatastoreName(iScsiName);
|
||||||
|
diskBackingFileBaseName = new DatastoreFile(volumePath).getFileBaseName();
|
||||||
|
} else {
|
||||||
|
ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, datastoreUUID);
|
||||||
|
DatastoreMO dsMo = new DatastoreMO(context, morDs);
|
||||||
|
dsName = dsMo.getName();
|
||||||
|
diskBackingFileBaseName = volumePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Pair<>(dsName, diskBackingFileBaseName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private VirtualMachineDiskInfo getMatchingExistingDisk(VirtualMachineDiskInfoBuilder diskInfoBuilder, DiskTO vol, VmwareHypervisorHost hyperHost, VmwareContext context)
|
||||||
|
throws Exception {
|
||||||
|
if (diskInfoBuilder != null) {
|
||||||
|
VolumeObjectTO volume = (VolumeObjectTO) vol.getData();
|
||||||
|
String chainInfo = volume.getChainInfo();
|
||||||
|
Map<String, String> details = vol.getDetails();
|
||||||
|
boolean isManaged = details != null && Boolean.parseBoolean(details.get(DiskTO.MANAGED));
|
||||||
|
String iScsiName = details.get(DiskTO.IQN);
|
||||||
|
String datastoreUUID = volume.getDataStore().getUuid();
|
||||||
|
|
||||||
|
return getMatchingExistingDiskWithVolumeDetails(diskInfoBuilder, volume.getPath(), chainInfo, isManaged, iScsiName, datastoreUUID, hyperHost, context);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private String getDiskController(VirtualMachineMO vmMo, VirtualMachineDiskInfo matchingExistingDisk, DiskTO vol, Pair<String, String> controllerInfo, boolean deployAsIs) throws Exception {
|
private String getDiskController(VirtualMachineMO vmMo, VirtualMachineDiskInfo matchingExistingDisk, DiskTO vol, Pair<String, String> controllerInfo, boolean deployAsIs) throws Exception {
|
||||||
DiskControllerType controllerType = DiskControllerType.none;
|
DiskControllerType controllerType = DiskControllerType.none;
|
||||||
if (deployAsIs && matchingExistingDisk != null) {
|
if (deployAsIs && matchingExistingDisk != null) {
|
||||||
@ -4791,7 +4865,9 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
// OfflineVmwareMigration: refactor to be able to handle a detached volume
|
// OfflineVmwareMigration: refactor to be able to handle a detached volume
|
||||||
private Answer execute(MigrateVolumeCommand cmd) {
|
private Answer execute(MigrateVolumeCommand cmd) {
|
||||||
String volumePath = cmd.getVolumePath();
|
String volumePath = cmd.getVolumePath();
|
||||||
|
String chainInfo = cmd.getChainInfo();
|
||||||
StorageFilerTO poolTo = cmd.getPool();
|
StorageFilerTO poolTo = cmd.getPool();
|
||||||
|
VolumeObjectTO volumeObjectTO = (VolumeObjectTO)cmd.getSrcData();
|
||||||
|
|
||||||
if (s_logger.isInfoEnabled()) {
|
if (s_logger.isInfoEnabled()) {
|
||||||
s_logger.info("Executing resource MigrateVolumeCommand: " + _gson.toJson(cmd));
|
s_logger.info("Executing resource MigrateVolumeCommand: " + _gson.toJson(cmd));
|
||||||
@ -4838,6 +4914,22 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
}
|
}
|
||||||
|
|
||||||
DatastoreMO targetDsMo = new DatastoreMO(srcHyperHost.getContext(), morDs);
|
DatastoreMO targetDsMo = new DatastoreMO(srcHyperHost.getContext(), morDs);
|
||||||
|
if (cmd.getContextParam(DiskTO.PROTOCOL_TYPE) != null && cmd.getContextParam(DiskTO.PROTOCOL_TYPE).equalsIgnoreCase("DatastoreCluster")) {
|
||||||
|
VmwareContext context = getServiceContext();
|
||||||
|
VmwareHypervisorHost hyperHost = getHyperHost(context);
|
||||||
|
VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder();
|
||||||
|
VirtualMachineDiskInfo matchingExistingDisk = getMatchingExistingDiskWithVolumeDetails(diskInfoBuilder, volumePath, chainInfo, false, null, poolTo.getUuid(), hyperHost, context);
|
||||||
|
if (diskInfoBuilder != null && matchingExistingDisk != null) {
|
||||||
|
String[] diskChain = matchingExistingDisk.getDiskChain();
|
||||||
|
DatastoreFile file = new DatastoreFile(diskChain[0]);
|
||||||
|
if (!file.getFileBaseName().equalsIgnoreCase(volumePath)) {
|
||||||
|
if (s_logger.isInfoEnabled())
|
||||||
|
s_logger.info("Detected disk-chain top file change on volume: " + volumePath + " -> " + file.getFileBaseName());
|
||||||
|
volumePath = file.getFileBaseName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String fullVolumePath = VmwareStorageLayoutHelper.getVmwareDatastorePathFromVmdkFileName(targetDsMo, vmName, volumePath + VMDK_EXTENSION);
|
String fullVolumePath = VmwareStorageLayoutHelper.getVmwareDatastorePathFromVmdkFileName(targetDsMo, vmName, volumePath + VMDK_EXTENSION);
|
||||||
Pair<VirtualDisk, String> diskInfo = getVirtualDiskInfo(vmMo, appendFileType(volumePath, VMDK_EXTENSION));
|
Pair<VirtualDisk, String> diskInfo = getVirtualDiskInfo(vmMo, appendFileType(volumePath, VMDK_EXTENSION));
|
||||||
String vmdkAbsFile = getAbsoluteVmdkFile(diskInfo.first());
|
String vmdkAbsFile = getAbsoluteVmdkFile(diskInfo.first());
|
||||||
@ -4892,7 +4984,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder();
|
VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder();
|
||||||
String chainInfo = _gson.toJson(diskInfoBuilder.getDiskInfoByBackingFileBaseName(volumePath, targetDsMo.getName()));
|
chainInfo = _gson.toJson(diskInfoBuilder.getDiskInfoByBackingFileBaseName(volumePath, targetDsMo.getName()));
|
||||||
MigrateVolumeAnswer answer = new MigrateVolumeAnswer(cmd, true, null, volumePath);
|
MigrateVolumeAnswer answer = new MigrateVolumeAnswer(cmd, true, null, volumePath);
|
||||||
answer.setVolumeChainInfo(chainInfo);
|
answer.setVolumeChainInfo(chainInfo);
|
||||||
return answer;
|
return answer;
|
||||||
|
|||||||
@ -26,6 +26,8 @@ import java.util.Map;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.to.DiskTO;
|
||||||
|
import com.cloud.storage.Storage;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
|
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
|
||||||
@ -247,7 +249,10 @@ public class VmwareStorageMotionStrategy implements DataMotionStrategy {
|
|||||||
, vm != null ? vm.getInstanceName() : null
|
, vm != null ? vm.getInstanceName() : null
|
||||||
, sourcePool
|
, sourcePool
|
||||||
, targetPool
|
, targetPool
|
||||||
, hostIdForVmAndHostGuidInTargetCluster.second());
|
, hostIdForVmAndHostGuidInTargetCluster.second(), ((VolumeObjectTO) srcData.getTO()).getChainInfo());
|
||||||
|
if (sourcePool.getParent() != 0) {
|
||||||
|
cmd.setContextParam(DiskTO.PROTOCOL_TYPE, Storage.StoragePoolType.DatastoreCluster.toString());
|
||||||
|
}
|
||||||
Answer answer;
|
Answer answer;
|
||||||
if (hostId != null) {
|
if (hostId != null) {
|
||||||
answer = agentMgr.easySend(hostId, cmd);
|
answer = agentMgr.easySend(hostId, cmd);
|
||||||
|
|||||||
@ -26,6 +26,8 @@ import java.util.UUID;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.to.DiskTO;
|
||||||
|
import com.cloud.storage.VolumeVO;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo;
|
import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
|
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
|
import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
|
||||||
@ -408,7 +410,10 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri
|
|||||||
|
|
||||||
ResizeVolumeCommand resizeCmd =
|
ResizeVolumeCommand resizeCmd =
|
||||||
new ResizeVolumeCommand(vol.getPath(), new StorageFilerTO(pool), vol.getSize(), resizeParameter.newSize, resizeParameter.shrinkOk,
|
new ResizeVolumeCommand(vol.getPath(), new StorageFilerTO(pool), vol.getSize(), resizeParameter.newSize, resizeParameter.shrinkOk,
|
||||||
resizeParameter.instanceName);
|
resizeParameter.instanceName, vol.getChainInfo());
|
||||||
|
if (pool.getParent() != 0) {
|
||||||
|
resizeCmd.setContextParam(DiskTO.PROTOCOL_TYPE, Storage.StoragePoolType.DatastoreCluster.toString());
|
||||||
|
}
|
||||||
CreateCmdResult result = new CreateCmdResult(null, null);
|
CreateCmdResult result = new CreateCmdResult(null, null);
|
||||||
try {
|
try {
|
||||||
ResizeVolumeAnswer answer = (ResizeVolumeAnswer) storageMgr.sendToPool(pool, resizeParameter.hosts, resizeCmd);
|
ResizeVolumeAnswer answer = (ResizeVolumeAnswer) storageMgr.sendToPool(pool, resizeParameter.hosts, resizeCmd);
|
||||||
@ -418,6 +423,8 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri
|
|||||||
|
|
||||||
vol.setSize(finalSize);
|
vol.setSize(finalSize);
|
||||||
vol.update();
|
vol.update();
|
||||||
|
|
||||||
|
updateVolumePathDetails(vol, answer);
|
||||||
} else if (answer != null) {
|
} else if (answer != null) {
|
||||||
result.setResult(answer.getDetails());
|
result.setResult(answer.getDetails());
|
||||||
} else {
|
} else {
|
||||||
@ -433,6 +440,31 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri
|
|||||||
callback.complete(result);
|
callback.complete(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateVolumePathDetails(VolumeObject vol, ResizeVolumeAnswer answer) {
|
||||||
|
VolumeVO volumeVO = volumeDao.findById(vol.getId());
|
||||||
|
String datastoreUUID = answer.getContextParam("datastoreUUID");
|
||||||
|
if (datastoreUUID != null) {
|
||||||
|
StoragePoolVO storagePoolVO = primaryStoreDao.findByUuid(datastoreUUID);
|
||||||
|
if (storagePoolVO != null) {
|
||||||
|
volumeVO.setPoolId(storagePoolVO.getId());
|
||||||
|
} else {
|
||||||
|
s_logger.warn(String.format("Unable to find datastore %s while updating the new datastore of the volume %d", datastoreUUID, vol.getId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String volumePath = answer.getContextParam("volumePath");
|
||||||
|
if (volumePath != null) {
|
||||||
|
volumeVO.setPath(volumePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
String chainInfo = answer.getContextParam("chainInfo");
|
||||||
|
if (chainInfo != null) {
|
||||||
|
volumeVO.setChainInfo(chainInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
volumeDao.update(volumeVO.getId(), volumeVO);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleQualityOfServiceForVolumeMigration(VolumeInfo volumeInfo, QualityOfServiceState qualityOfServiceState) {}
|
public void handleQualityOfServiceForVolumeMigration(VolumeInfo volumeInfo, QualityOfServiceState qualityOfServiceState) {}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user