mirror of https://github.com/apache/cloudstack.git
Merge remote-tracking branch 'origin/4.15'
This commit is contained in:
commit
4742ac15f7
|
|
@ -56,9 +56,9 @@ public interface TemplateApiService {
|
|||
|
||||
VirtualMachineTemplate prepareTemplate(long templateId, long zoneId, Long storageId);
|
||||
|
||||
boolean detachIso(long vmId);
|
||||
boolean detachIso(long vmId, boolean forced);
|
||||
|
||||
boolean attachIso(long isoId, long vmId);
|
||||
boolean attachIso(long isoId, long vmId, boolean forced);
|
||||
|
||||
/**
|
||||
* Deletes a template
|
||||
|
|
|
|||
|
|
@ -54,6 +54,10 @@ public class AttachIsoCmd extends BaseAsyncCmd implements UserCmd {
|
|||
required = true, description = "the ID of the virtual machine")
|
||||
protected Long virtualMachineId;
|
||||
|
||||
@Parameter(name = ApiConstants.FORCED, type = CommandType.BOOLEAN,
|
||||
description = "If true, ejects existing ISO before attaching on VMware. Default: false", since = "4.15.1")
|
||||
protected Boolean forced;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
@ -66,6 +70,10 @@ public class AttachIsoCmd extends BaseAsyncCmd implements UserCmd {
|
|||
return virtualMachineId;
|
||||
}
|
||||
|
||||
public Boolean isForced() {
|
||||
return forced != null;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
@ -98,7 +106,7 @@ public class AttachIsoCmd extends BaseAsyncCmd implements UserCmd {
|
|||
@Override
|
||||
public void execute() {
|
||||
CallContext.current().setEventDetails("Vm Id: " + getVirtualMachineId() + " ISO ID: " + getId());
|
||||
boolean result = _templateService.attachIso(id, virtualMachineId);
|
||||
boolean result = _templateService.attachIso(id, virtualMachineId, isForced());
|
||||
if (result) {
|
||||
UserVm userVm = _responseGenerator.findUserVmById(virtualMachineId);
|
||||
if (userVm != null) {
|
||||
|
|
|
|||
|
|
@ -44,10 +44,14 @@ public class DetachIsoCmd extends BaseAsyncCmd implements UserCmd {
|
|||
//////////////// API parameters /////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Parameter(name=ApiConstants.VIRTUAL_MACHINE_ID, type=CommandType.UUID, entityType = UserVmResponse.class,
|
||||
required=true, description="The ID of the virtual machine")
|
||||
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID, type = CommandType.UUID, entityType = UserVmResponse.class,
|
||||
required = true, description = "The ID of the virtual machine")
|
||||
protected Long virtualMachineId;
|
||||
|
||||
@Parameter(name = ApiConstants.FORCED, type = CommandType.BOOLEAN,
|
||||
description = "If true, ejects the ISO before detaching on VMware. Default: false", since = "4.15.1")
|
||||
protected Boolean forced;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
@ -56,6 +60,10 @@ public class DetachIsoCmd extends BaseAsyncCmd implements UserCmd {
|
|||
return virtualMachineId;
|
||||
}
|
||||
|
||||
public Boolean isForced() {
|
||||
return forced != null;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
@ -87,7 +95,7 @@ public class DetachIsoCmd extends BaseAsyncCmd implements UserCmd {
|
|||
|
||||
@Override
|
||||
public void execute() {
|
||||
boolean result = _templateService.detachIso(virtualMachineId);
|
||||
boolean result = _templateService.detachIso(virtualMachineId, isForced());
|
||||
if (result) {
|
||||
UserVm userVm = _entityMgr.findById(UserVm.class, virtualMachineId);
|
||||
UserVmResponse response = _responseGenerator.createUserVmResponse(getResponseView(), "virtualmachine", userVm).get(0);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ public final class AttachCommand extends StorageSubSystemCommand {
|
|||
private DiskTO disk;
|
||||
private String vmName;
|
||||
private boolean inSeq = false;
|
||||
private boolean forced = false;
|
||||
private Map<String, String> controllerInfo;
|
||||
|
||||
public AttachCommand(final DiskTO disk, final String vmName) {
|
||||
|
|
@ -69,6 +70,14 @@ public final class AttachCommand extends StorageSubSystemCommand {
|
|||
this.vmName = vmName;
|
||||
}
|
||||
|
||||
public boolean isForced() {
|
||||
return forced;
|
||||
}
|
||||
|
||||
public void setForced(boolean forced) {
|
||||
this.forced = forced;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExecuteInSequence(final boolean inSeq) {
|
||||
this.inSeq = inSeq;
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ public class DettachCommand extends StorageSubSystemCommand {
|
|||
private String _storageHost;
|
||||
private int _storagePort;
|
||||
private Map<String, String> params;
|
||||
private boolean forced;
|
||||
|
||||
public DettachCommand(final DiskTO disk, final String vmName) {
|
||||
super();
|
||||
|
|
@ -106,6 +107,14 @@ public class DettachCommand extends StorageSubSystemCommand {
|
|||
this.params = params;
|
||||
}
|
||||
|
||||
public boolean isForced() {
|
||||
return forced;
|
||||
}
|
||||
|
||||
public void setForced(boolean forced) {
|
||||
this.forced = forced;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExecuteInSequence(final boolean inSeq) {
|
||||
|
||||
|
|
|
|||
|
|
@ -200,7 +200,9 @@ public class DataMigrationUtility {
|
|||
snapshotVO != null && snapshotVO.getHypervisorType() != Hypervisor.HypervisorType.Simulator
|
||||
&& snapshot.getParentSnapshotId() == 0 ) {
|
||||
SnapshotInfo snap = snapshotFactory.getSnapshot(snapshotVO.getSnapshotId(), DataStoreRole.Image);
|
||||
files.add(snap);
|
||||
if (snap != null) {
|
||||
files.add(snap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -87,6 +87,9 @@ public class SnapshotDataFactoryImpl implements SnapshotDataFactory {
|
|||
@Override
|
||||
public SnapshotInfo getSnapshot(long snapshotId, DataStoreRole role) {
|
||||
SnapshotVO snapshot = snapshotDao.findById(snapshotId);
|
||||
if (snapshot == null) {
|
||||
return null;
|
||||
}
|
||||
SnapshotDataStoreVO snapshotStore = snapshotStoreDao.findBySnapshot(snapshotId, role);
|
||||
if (snapshotStore == null) {
|
||||
snapshotStore = snapshotStoreDao.findByVolume(snapshot.getVolumeId(), role);
|
||||
|
|
|
|||
|
|
@ -142,7 +142,10 @@ public class SnapshotObject implements SnapshotInfo {
|
|||
List<SnapshotInfo> children = new ArrayList<>();
|
||||
if (vos != null) {
|
||||
for (SnapshotDataStoreVO vo : vos) {
|
||||
children.add(snapshotFactory.getSnapshot(vo.getSnapshotId(), DataStoreRole.Image));
|
||||
SnapshotInfo info = snapshotFactory.getSnapshot(vo.getSnapshotId(), DataStoreRole.Image);
|
||||
if (info != null) {
|
||||
children.add(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
return children;
|
||||
|
|
|
|||
|
|
@ -1097,6 +1097,10 @@ public class AsyncJobManagerImpl extends ManagerBase implements AsyncJobManager,
|
|||
final List<SnapshotDetailsVO> snapshotList = _snapshotDetailsDao.findDetails(AsyncJob.Constants.MS_ID, Long.toString(msid), false);
|
||||
for (final SnapshotDetailsVO snapshotDetailsVO : snapshotList) {
|
||||
SnapshotInfo snapshot = snapshotFactory.getSnapshot(snapshotDetailsVO.getResourceId(), DataStoreRole.Primary);
|
||||
if (snapshot == null) {
|
||||
_snapshotDetailsDao.remove(snapshotDetailsVO.getId());
|
||||
continue;
|
||||
}
|
||||
snapshotSrv.processEventOnSnapshotObject(snapshot, Snapshot.Event.OperationFailed);
|
||||
_snapshotDetailsDao.removeDetail(snapshotDetailsVO.getResourceId(), AsyncJob.Constants.MS_ID);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2038,35 +2038,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||
if (volIso != null) {
|
||||
for (DiskTO vol : disks) {
|
||||
if (vol.getType() == Volume.Type.ISO) {
|
||||
|
||||
TemplateObjectTO iso = (TemplateObjectTO) vol.getData();
|
||||
|
||||
if (iso.getPath() != null && !iso.getPath().isEmpty()) {
|
||||
DataStoreTO imageStore = iso.getDataStore();
|
||||
if (!(imageStore instanceof NfsTO)) {
|
||||
s_logger.debug("unsupported protocol");
|
||||
throw new Exception("unsupported protocol");
|
||||
}
|
||||
NfsTO nfsImageStore = (NfsTO) imageStore;
|
||||
String isoPath = nfsImageStore.getUrl() + File.separator + iso.getPath();
|
||||
Pair<String, ManagedObjectReference> isoDatastoreInfo = getIsoDatastoreInfo(hyperHost, isoPath);
|
||||
assert (isoDatastoreInfo != null);
|
||||
assert (isoDatastoreInfo.second() != null);
|
||||
|
||||
deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec();
|
||||
Pair<VirtualDevice, Boolean> isoInfo =
|
||||
VmwareHelper.prepareIsoDevice(vmMo, isoDatastoreInfo.first(), isoDatastoreInfo.second(), true, true, ideUnitNumber++, i + 1);
|
||||
deviceConfigSpecArray[i].setDevice(isoInfo.first());
|
||||
if (isoInfo.second()) {
|
||||
if (s_logger.isDebugEnabled())
|
||||
s_logger.debug("Prepare ISO volume at new device " + _gson.toJson(isoInfo.first()));
|
||||
deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD);
|
||||
} else {
|
||||
if (s_logger.isDebugEnabled())
|
||||
s_logger.debug("Prepare ISO volume at existing device " + _gson.toJson(isoInfo.first()));
|
||||
deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.EDIT);
|
||||
}
|
||||
}
|
||||
configureIso(hyperHost, vmMo, vol, deviceConfigSpecArray, ideUnitNumber++, i);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
|
@ -2094,8 +2066,16 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||
//
|
||||
// Setup ROOT/DATA disk devices
|
||||
//
|
||||
if (multipleIsosAtached(sortedDisks) && deployAsIs) {
|
||||
sortedDisks = getDisks(sortedDisks);
|
||||
}
|
||||
|
||||
for (DiskTO vol : sortedDisks) {
|
||||
if (vol.getType() == Volume.Type.ISO) {
|
||||
if (deployAsIs) {
|
||||
configureIso(hyperHost, vmMo, vol, deviceConfigSpecArray, ideUnitNumber++, i);
|
||||
i++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -2476,6 +2456,46 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||
}
|
||||
}
|
||||
|
||||
private boolean multipleIsosAtached(DiskTO[] sortedDisks) {
|
||||
return Arrays.stream(sortedDisks).filter(disk -> disk.getType() == Volume.Type.ISO).count() > 1;
|
||||
}
|
||||
|
||||
private DiskTO[] getDisks(DiskTO[] sortedDisks) {
|
||||
return Arrays.stream(sortedDisks).filter(vol -> ((vol.getPath() != null &&
|
||||
vol.getPath().contains("configdrive"))) || (vol.getType() != Volume.Type.ISO)).toArray(DiskTO[]::new);
|
||||
}
|
||||
private void configureIso(VmwareHypervisorHost hyperHost, VirtualMachineMO vmMo, DiskTO vol,
|
||||
VirtualDeviceConfigSpec[] deviceConfigSpecArray, int ideUnitNumber, int i) throws Exception {
|
||||
TemplateObjectTO iso = (TemplateObjectTO) vol.getData();
|
||||
|
||||
if (iso.getPath() != null && !iso.getPath().isEmpty()) {
|
||||
DataStoreTO imageStore = iso.getDataStore();
|
||||
if (!(imageStore instanceof NfsTO)) {
|
||||
s_logger.debug("unsupported protocol");
|
||||
throw new Exception("unsupported protocol");
|
||||
}
|
||||
NfsTO nfsImageStore = (NfsTO) imageStore;
|
||||
String isoPath = nfsImageStore.getUrl() + File.separator + iso.getPath();
|
||||
Pair<String, ManagedObjectReference> isoDatastoreInfo = getIsoDatastoreInfo(hyperHost, isoPath);
|
||||
assert (isoDatastoreInfo != null);
|
||||
assert (isoDatastoreInfo.second() != null);
|
||||
|
||||
deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec();
|
||||
Pair<VirtualDevice, Boolean> isoInfo =
|
||||
VmwareHelper.prepareIsoDevice(vmMo, isoDatastoreInfo.first(), isoDatastoreInfo.second(), true, true, ideUnitNumber, i + 1);
|
||||
deviceConfigSpecArray[i].setDevice(isoInfo.first());
|
||||
if (isoInfo.second()) {
|
||||
if (s_logger.isDebugEnabled())
|
||||
s_logger.debug("Prepare ISO volume at new device " + _gson.toJson(isoInfo.first()));
|
||||
deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD);
|
||||
} else {
|
||||
if (s_logger.isDebugEnabled())
|
||||
s_logger.debug("Prepare ISO volume at existing device " + _gson.toJson(isoInfo.first()));
|
||||
deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.EDIT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String mapAdapterType(String adapterStringFromOVF) {
|
||||
if (StringUtils.isBlank(adapterStringFromOVF) || adapterStringFromOVF.equalsIgnoreCase(VirtualEthernetCardType.E1000.toString())) {
|
||||
return VirtualEthernetCardType.E1000.toString();
|
||||
|
|
@ -5147,7 +5167,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||
"Failed to unmount vmware-tools installer ISO as the corresponding CDROM device is locked by VM. Please unmount the CDROM device inside the VM and ret-try.");
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
vmMo.detachIso(null);
|
||||
vmMo.detachIso(null, cmd.isForce());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -5176,7 +5196,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||
String isoDatastorePath = String.format("[%s] %s%s", storeName, isoStorePathFromRoot, isoFileName);
|
||||
|
||||
if (cmd.isAttach()) {
|
||||
vmMo.attachIso(isoDatastorePath, morSecondaryDs, true, false, cmd.getDeviceKey());
|
||||
vmMo.attachIso(isoDatastorePath, morSecondaryDs, true, false, cmd.getDeviceKey(), cmd.isForce());
|
||||
return new AttachIsoAnswer(cmd);
|
||||
} else {
|
||||
int key = vmMo.detachIso(isoDatastorePath, cmd.isForce());
|
||||
|
|
|
|||
|
|
@ -2045,7 +2045,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
|||
|
||||
@Override
|
||||
public Answer attachIso(AttachCommand cmd) {
|
||||
return this.attachIso(cmd.getDisk(), true, cmd.getVmName());
|
||||
return this.attachIso(cmd.getDisk(), true, cmd.getVmName(), cmd.isForced());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -2411,7 +2411,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
|||
return morDatastore;
|
||||
}
|
||||
|
||||
private Answer attachIso(DiskTO disk, boolean isAttach, String vmName) {
|
||||
private Answer attachIso(DiskTO disk, boolean isAttach, String vmName, boolean force) {
|
||||
try {
|
||||
VmwareContext context = hostService.getServiceContext(null);
|
||||
VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, null);
|
||||
|
|
@ -2441,7 +2441,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
|||
return new AttachAnswer("Failed to unmount vmware-tools installer ISO as the corresponding CDROM device is locked by VM. Please unmount the CDROM device inside the VM and ret-try.");
|
||||
}
|
||||
} catch(Throwable e){
|
||||
vmMo.detachIso(null);
|
||||
vmMo.detachIso(null, force);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2469,9 +2469,9 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
|||
String isoDatastorePath = String.format("[%s] %s/%s", storeName, isoStorePathFromRoot, isoFileName);
|
||||
|
||||
if (isAttach) {
|
||||
vmMo.attachIso(isoDatastorePath, morSecondaryDs, true, false);
|
||||
vmMo.attachIso(isoDatastorePath, morSecondaryDs, true, false, force);
|
||||
} else {
|
||||
vmMo.detachIso(isoDatastorePath);
|
||||
vmMo.detachIso(isoDatastorePath, force);
|
||||
}
|
||||
|
||||
return new AttachAnswer(disk);
|
||||
|
|
@ -2497,7 +2497,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
|||
|
||||
@Override
|
||||
public Answer dettachIso(DettachCommand cmd) {
|
||||
return this.attachIso(cmd.getDisk(), false, cmd.getVmName());
|
||||
return this.attachIso(cmd.getDisk(), false, cmd.getVmName(), cmd.isForced());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -319,7 +319,7 @@ public class KubernetesClusterActionWorker {
|
|||
}
|
||||
for (UserVm vm : clusterVMs) {
|
||||
try {
|
||||
templateService.attachIso(iso.getId(), vm.getId());
|
||||
templateService.attachIso(iso.getId(), vm.getId(), true);
|
||||
if (LOGGER.isInfoEnabled()) {
|
||||
LOGGER.info(String.format("Attached binaries ISO for VM : %s in cluster: %s", vm.getDisplayName(), kubernetesCluster.getName()));
|
||||
}
|
||||
|
|
@ -337,7 +337,7 @@ public class KubernetesClusterActionWorker {
|
|||
for (UserVm vm : clusterVMs) {
|
||||
boolean result = false;
|
||||
try {
|
||||
result = templateService.detachIso(vm.getId());
|
||||
result = templateService.detachIso(vm.getId(), true);
|
||||
} catch (CloudRuntimeException ex) {
|
||||
LOGGER.warn(String.format("Failed to detach binaries ISO from VM : %s in the Kubernetes cluster : %s ", vm.getDisplayName(), kubernetesCluster.getName()), ex);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -328,7 +328,9 @@ public class KubernetesClusterResourceModifierActionWorker extends KubernetesClu
|
|||
for (int i = offset + 1; i <= nodeCount; i++) {
|
||||
UserVm vm = createKubernetesNode(publicIpAddress, i);
|
||||
addKubernetesClusterVm(kubernetesCluster.getId(), vm.getId());
|
||||
resizeNodeVolume(vm);
|
||||
if (kubernetesCluster.getNodeRootDiskSize() > 0) {
|
||||
resizeNodeVolume(vm);
|
||||
}
|
||||
startKubernetesVM(vm);
|
||||
vm = userVmDao.findById(vm.getId());
|
||||
if (vm == null) {
|
||||
|
|
|
|||
|
|
@ -277,7 +277,9 @@ public class KubernetesClusterStartWorker extends KubernetesClusterResourceModif
|
|||
UserVm k8sMasterVM = null;
|
||||
k8sMasterVM = createKubernetesMaster(network, publicIpAddress);
|
||||
addKubernetesClusterVm(kubernetesCluster.getId(), k8sMasterVM.getId());
|
||||
resizeNodeVolume(k8sMasterVM);
|
||||
if (kubernetesCluster.getNodeRootDiskSize() > 0) {
|
||||
resizeNodeVolume(k8sMasterVM);
|
||||
}
|
||||
startKubernetesVM(k8sMasterVM);
|
||||
k8sMasterVM = userVmDao.findById(k8sMasterVM.getId());
|
||||
if (k8sMasterVM == null) {
|
||||
|
|
@ -297,7 +299,9 @@ public class KubernetesClusterStartWorker extends KubernetesClusterResourceModif
|
|||
UserVm vm = null;
|
||||
vm = createKubernetesAdditionalMaster(publicIpAddress, i);
|
||||
addKubernetesClusterVm(kubernetesCluster.getId(), vm.getId());
|
||||
resizeNodeVolume(vm);
|
||||
if (kubernetesCluster.getNodeRootDiskSize() > 0) {
|
||||
resizeNodeVolume(vm);
|
||||
}
|
||||
startKubernetesVM(vm);
|
||||
vm = userVmDao.findById(vm.getId());
|
||||
if (vm == null) {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ import org.apache.cloudstack.framework.config.Configurable;
|
|||
import com.cloud.agent.api.Answer;
|
||||
import com.cloud.agent.api.Command;
|
||||
import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.storage.Snapshot;
|
||||
import com.cloud.storage.SnapshotVO;
|
||||
import com.cloud.storage.Volume;
|
||||
|
||||
|
|
@ -85,7 +84,5 @@ public interface SnapshotManager extends Configurable {
|
|||
|
||||
SnapshotVO getParentSnapshot(VolumeInfo volume);
|
||||
|
||||
Snapshot backupSnapshot(Long snapshotId);
|
||||
|
||||
SnapshotInfo takeSnapshot(VolumeInfo volume) throws ResourceAllocationException;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -420,16 +420,6 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
|
|||
return snapshotOnSecondary;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Snapshot backupSnapshot(Long snapshotId) {
|
||||
SnapshotInfo snapshot = snapshotFactory.getSnapshot(snapshotId, DataStoreRole.Image);
|
||||
if (snapshot != null) {
|
||||
throw new CloudRuntimeException("Already in the backup snapshot:" + snapshotId);
|
||||
}
|
||||
|
||||
return snapshotSrv.backupSnapshot(snapshot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Snapshot backupSnapshotFromVmSnapshot(Long snapshotId, Long vmId, Long volumeId, Long vmSnapshotId) {
|
||||
VMInstanceVO vm = _vmDao.findById(vmId);
|
||||
|
|
|
|||
|
|
@ -1150,7 +1150,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
|
|||
|
||||
@Override
|
||||
@ActionEvent(eventType = EventTypes.EVENT_ISO_DETACH, eventDescription = "detaching ISO", async = true)
|
||||
public boolean detachIso(long vmId) {
|
||||
public boolean detachIso(long vmId, boolean forced) {
|
||||
Account caller = CallContext.current().getCallingAccount();
|
||||
Long userId = CallContext.current().getCallingUserId();
|
||||
|
||||
|
|
@ -1178,7 +1178,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
|
|||
throw new InvalidParameterValueException("Please specify a VM that is either Stopped or Running.");
|
||||
}
|
||||
|
||||
boolean result = attachISOToVM(vmId, userId, isoId, false); // attach=false
|
||||
boolean result = attachISOToVM(vmId, userId, isoId, false, forced); // attach=false
|
||||
// => detach
|
||||
if (result) {
|
||||
return result;
|
||||
|
|
@ -1189,7 +1189,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
|
|||
|
||||
@Override
|
||||
@ActionEvent(eventType = EventTypes.EVENT_ISO_ATTACH, eventDescription = "attaching ISO", async = true)
|
||||
public boolean attachIso(long isoId, long vmId) {
|
||||
public boolean attachIso(long isoId, long vmId, boolean forced) {
|
||||
Account caller = CallContext.current().getCallingAccount();
|
||||
Long userId = CallContext.current().getCallingUserId();
|
||||
|
||||
|
|
@ -1231,7 +1231,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
|
|||
if ("vmware-tools.iso".equals(iso.getName()) && vm.getHypervisorType() != Hypervisor.HypervisorType.VMware) {
|
||||
throw new InvalidParameterValueException("Cannot attach VMware tools drivers to incompatible hypervisor " + vm.getHypervisorType());
|
||||
}
|
||||
boolean result = attachISOToVM(vmId, userId, isoId, true);
|
||||
boolean result = attachISOToVM(vmId, userId, isoId, true, forced);
|
||||
if (result) {
|
||||
return result;
|
||||
} else {
|
||||
|
|
@ -1270,7 +1270,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
|
|||
}
|
||||
}
|
||||
|
||||
private boolean attachISOToVM(long vmId, long isoId, boolean attach) {
|
||||
private boolean attachISOToVM(long vmId, long isoId, boolean attach, boolean forced) {
|
||||
UserVmVO vm = _userVmDao.findById(vmId);
|
||||
|
||||
if (vm == null) {
|
||||
|
|
@ -1302,19 +1302,21 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
|
|||
|
||||
Command cmd = null;
|
||||
if (attach) {
|
||||
cmd = new AttachCommand(disk, vmName, vmTO.getDetails());
|
||||
cmd = new AttachCommand(disk, vmName);
|
||||
((AttachCommand)cmd).setForced(forced);
|
||||
} else {
|
||||
cmd = new DettachCommand(disk, vmName, vmTO.getDetails());
|
||||
cmd = new DettachCommand(disk, vmName);
|
||||
((DettachCommand)cmd).setForced(forced);
|
||||
}
|
||||
Answer a = _agentMgr.easySend(vm.getHostId(), cmd);
|
||||
return (a != null && a.getResult());
|
||||
}
|
||||
|
||||
private boolean attachISOToVM(long vmId, long userId, long isoId, boolean attach) {
|
||||
private boolean attachISOToVM(long vmId, long userId, long isoId, boolean attach, boolean forced) {
|
||||
UserVmVO vm = _userVmDao.findById(vmId);
|
||||
VMTemplateVO iso = _tmpltDao.findById(isoId);
|
||||
|
||||
boolean success = attachISOToVM(vmId, isoId, attach);
|
||||
boolean success = attachISOToVM(vmId, isoId, attach, forced);
|
||||
if (success && attach) {
|
||||
vm.setIsoId(iso.getId());
|
||||
_userVmDao.update(vmId, vm);
|
||||
|
|
|
|||
|
|
@ -5405,7 +5405,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
for (VMTemplateVO tmpl: child_templates){
|
||||
if (tmpl.getFormat() == Storage.ImageFormat.ISO){
|
||||
s_logger.info("MDOV trying to attach disk to the VM " + tmpl.getId() + " vmid=" + vm.getId());
|
||||
_tmplService.attachIso(tmpl.getId(), vm.getId());
|
||||
_tmplService.attachIso(tmpl.getId(), vm.getId(), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ class TestScaleVm(cloudstackTestCase):
|
|||
cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
|
||||
cls.services['mode'] = cls.zone.networktype
|
||||
|
||||
if cls.hypervisor.lower() == 'simulator':
|
||||
if cls.hypervisor.lower() in ['simulator', 'vmware']:
|
||||
cls.template = get_template(
|
||||
cls.apiclient,
|
||||
cls.zone.id,
|
||||
|
|
|
|||
|
|
@ -83,6 +83,10 @@ export default {
|
|||
component: DetailsTab
|
||||
}]
|
||||
}
|
||||
},
|
||||
historyTab: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data () {
|
||||
|
|
@ -128,6 +132,7 @@ export default {
|
|||
)
|
||||
}).join('&')
|
||||
)
|
||||
this.$emit('onTabChange', key)
|
||||
},
|
||||
showTab (tab) {
|
||||
if ('networkServiceFilter' in tab) {
|
||||
|
|
@ -158,7 +163,20 @@ export default {
|
|||
}
|
||||
},
|
||||
setActiveTab () {
|
||||
this.activeTab = this.$route.query.tab ? this.$route.query.tab : this.tabs[0].name
|
||||
if (this.$route.query.tab) {
|
||||
this.activeTab = this.$route.query.tab
|
||||
return
|
||||
}
|
||||
if (!this.historyTab || !this.$route.meta.tabs || this.$route.meta.tabs.length === 0) {
|
||||
this.activeTab = this.tabs[0].name
|
||||
return
|
||||
}
|
||||
const tabIdx = this.$route.meta.tabs.findIndex(tab => tab.name === this.historyTab)
|
||||
if (tabIdx === -1) {
|
||||
this.activeTab = this.tabs[0].name
|
||||
} else {
|
||||
this.activeTab = this.historyTab
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -255,7 +255,13 @@ export default {
|
|||
label: 'label.action.detach.iso',
|
||||
message: 'message.detach.iso.confirm',
|
||||
dataView: true,
|
||||
args: ['virtualmachineid'],
|
||||
args: (record, store) => {
|
||||
var args = ['virtualmachineid']
|
||||
if (record && record.hypervisor && record.hypervisor === 'VMware') {
|
||||
args.push('forced')
|
||||
}
|
||||
return args
|
||||
},
|
||||
show: (record) => { return ['Running', 'Stopped'].includes(record.state) && 'isoid' in record && record.isoid },
|
||||
mapping: {
|
||||
virtualmachineid: {
|
||||
|
|
|
|||
|
|
@ -325,7 +325,16 @@ const user = {
|
|||
})
|
||||
})
|
||||
},
|
||||
|
||||
UpdateConfiguration ({ commit }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
api('listLdapConfigurations').then(response => {
|
||||
const ldapEnable = (response.ldapconfigurationresponse.count > 0)
|
||||
commit('SET_LDAP', ldapEnable)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
SetDomainStore ({ commit }, domainStore) {
|
||||
commit('SET_DOMAIN_STORE', domainStore)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -963,6 +963,9 @@ export default {
|
|||
break
|
||||
}
|
||||
}
|
||||
if (['addLdapConfiguration', 'deleteLdapConfiguration'].includes(action.api)) {
|
||||
this.$store.dispatch('UpdateConfiguration')
|
||||
}
|
||||
return false
|
||||
},
|
||||
execSubmit (e) {
|
||||
|
|
|
|||
|
|
@ -33,6 +33,9 @@
|
|||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item :label="$t('label.forced')" v-if="resource && resource.hypervisor === 'VMware'">
|
||||
<a-switch v-decorator="['forced']" :auto-focus="true" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<div :span="24" class="action-button">
|
||||
<a-button @click="closeAction">{{ this.$t('label.cancel') }}</a-button>
|
||||
|
|
@ -116,6 +119,11 @@ export default {
|
|||
id: values.id,
|
||||
virtualmachineid: this.resource.id
|
||||
}
|
||||
|
||||
if (values.forced) {
|
||||
params.forced = values.forced
|
||||
}
|
||||
|
||||
this.loading = true
|
||||
const title = this.$t('label.action.attach.iso')
|
||||
api('attachIso', params).then(json => {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,9 @@
|
|||
v-if="isPublicIpAddress && 'id' in resource"
|
||||
:loading="loading"
|
||||
:resource="resource"
|
||||
:tabs="tabs" />
|
||||
:historyTab="activeTab"
|
||||
:tabs="tabs"
|
||||
@onTabChange="(tab) => { this.activeTab = tab }" />
|
||||
</div>
|
||||
</autogen-view>
|
||||
</div>
|
||||
|
|
@ -63,7 +65,8 @@ export default {
|
|||
tabs: [{
|
||||
name: 'details',
|
||||
component: () => import('@/components/view/DetailsTab.vue')
|
||||
}]
|
||||
}],
|
||||
activeTab: ''
|
||||
}
|
||||
},
|
||||
mixins: [mixinDevice],
|
||||
|
|
|
|||
|
|
@ -19,7 +19,9 @@
|
|||
<resource-view
|
||||
:loading="loading"
|
||||
:resource="quotaResource"
|
||||
:tabs="tabs"/>
|
||||
:tabs="tabs"
|
||||
:historyTab="activeTab"
|
||||
@onTabChange="(tab) => { this.activeTab = tab }"/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
@ -48,7 +50,8 @@ export default {
|
|||
loading: false,
|
||||
quotaResource: {},
|
||||
networkService: null,
|
||||
pattern: 'YYYY-MM-DD'
|
||||
pattern: 'YYYY-MM-DD',
|
||||
activeTab: ''
|
||||
}
|
||||
},
|
||||
created () {
|
||||
|
|
|
|||
|
|
@ -1498,117 +1498,11 @@ public class VirtualMachineMO extends BaseMO {
|
|||
s_logger.trace("vCenter API trace - detachAllDisk() done(successfully)");
|
||||
}
|
||||
|
||||
// isoDatastorePath: [datastore name] isoFilePath
|
||||
public void attachIso(String isoDatastorePath, ManagedObjectReference morDs, boolean connect, boolean connectAtBoot) throws Exception {
|
||||
attachIso(isoDatastorePath, morDs, connect, connectAtBoot, null);
|
||||
}
|
||||
|
||||
// isoDatastorePath: [datastore name] isoFilePath
|
||||
public void attachIso(String isoDatastorePath, ManagedObjectReference morDs,
|
||||
boolean connect, boolean connectAtBoot, Integer key) throws Exception {
|
||||
|
||||
if (s_logger.isTraceEnabled())
|
||||
s_logger.trace("vCenter API trace - attachIso(). target MOR: " + _mor.getValue() + ", isoDatastorePath: " + isoDatastorePath + ", datastore: " +
|
||||
morDs.getValue() + ", connect: " + connect + ", connectAtBoot: " + connectAtBoot);
|
||||
|
||||
assert (isoDatastorePath != null);
|
||||
assert (morDs != null);
|
||||
|
||||
boolean newCdRom = false;
|
||||
VirtualCdrom cdRom;
|
||||
if (key == null) {
|
||||
cdRom = (VirtualCdrom) getIsoDevice();
|
||||
} else {
|
||||
cdRom = (VirtualCdrom) getIsoDevice(key);
|
||||
}
|
||||
if (cdRom == null) {
|
||||
newCdRom = true;
|
||||
cdRom = new VirtualCdrom();
|
||||
cdRom.setControllerKey(getIDEDeviceControllerKey());
|
||||
|
||||
int deviceNumber = getNextIDEDeviceNumber();
|
||||
cdRom.setUnitNumber(deviceNumber);
|
||||
cdRom.setKey(-deviceNumber);
|
||||
}
|
||||
|
||||
VirtualDeviceConnectInfo cInfo = new VirtualDeviceConnectInfo();
|
||||
cInfo.setConnected(connect);
|
||||
cInfo.setStartConnected(connectAtBoot);
|
||||
cdRom.setConnectable(cInfo);
|
||||
|
||||
VirtualCdromIsoBackingInfo backingInfo = new VirtualCdromIsoBackingInfo();
|
||||
backingInfo.setFileName(isoDatastorePath);
|
||||
backingInfo.setDatastore(morDs);
|
||||
cdRom.setBacking(backingInfo);
|
||||
|
||||
VirtualMachineConfigSpec reConfigSpec = new VirtualMachineConfigSpec();
|
||||
//VirtualDeviceConfigSpec[] deviceConfigSpecArray = new VirtualDeviceConfigSpec[1];
|
||||
VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec();
|
||||
|
||||
deviceConfigSpec.setDevice(cdRom);
|
||||
if (newCdRom) {
|
||||
deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD);
|
||||
} else {
|
||||
deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.EDIT);
|
||||
}
|
||||
|
||||
//deviceConfigSpecArray[0] = deviceConfigSpec;
|
||||
reConfigSpec.getDeviceChange().add(deviceConfigSpec);
|
||||
|
||||
ManagedObjectReference morTask = _context.getService().reconfigVMTask(_mor, reConfigSpec);
|
||||
boolean result = _context.getVimClient().waitForTask(morTask);
|
||||
|
||||
if (!result) {
|
||||
if (s_logger.isTraceEnabled())
|
||||
s_logger.trace("vCenter API trace - attachIso() done(failed)");
|
||||
throw new Exception("Failed to attach ISO due to " + TaskMO.getTaskFailureInfo(_context, morTask));
|
||||
}
|
||||
|
||||
_context.waitForTaskProgressDone(morTask);
|
||||
|
||||
if (s_logger.isTraceEnabled())
|
||||
s_logger.trace("vCenter API trace - attachIso() done(successfully)");
|
||||
}
|
||||
|
||||
public int detachIso(String isoDatastorePath) throws Exception {
|
||||
return detachIso(isoDatastorePath, false);
|
||||
}
|
||||
|
||||
public int detachIso(String isoDatastorePath, final boolean force) throws Exception {
|
||||
if (s_logger.isTraceEnabled())
|
||||
s_logger.trace("vCenter API trace - detachIso(). target MOR: " + _mor.getValue() + ", isoDatastorePath: " + isoDatastorePath);
|
||||
|
||||
VirtualDevice device = getIsoDevice(isoDatastorePath);
|
||||
if (device == null) {
|
||||
if (s_logger.isTraceEnabled())
|
||||
s_logger.trace("vCenter API trace - detachIso() done(failed)");
|
||||
throw new Exception("Unable to find a CDROM device");
|
||||
}
|
||||
|
||||
VirtualCdromRemotePassthroughBackingInfo backingInfo = new VirtualCdromRemotePassthroughBackingInfo();
|
||||
backingInfo.setDeviceName("");
|
||||
device.setBacking(backingInfo);
|
||||
|
||||
VirtualMachineConfigSpec reConfigSpec = new VirtualMachineConfigSpec();
|
||||
//VirtualDeviceConfigSpec[] deviceConfigSpecArray = new VirtualDeviceConfigSpec[1];
|
||||
VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec();
|
||||
|
||||
deviceConfigSpec.setDevice(device);
|
||||
deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.EDIT);
|
||||
|
||||
//deviceConfigSpecArray[0] = deviceConfigSpec;
|
||||
reConfigSpec.getDeviceChange().add(deviceConfigSpec);
|
||||
|
||||
ManagedObjectReference morTask = _context.getService().reconfigVMTask(_mor, reConfigSpec);
|
||||
|
||||
// Monitor VM questions
|
||||
final Boolean[] flags = {false};
|
||||
final VirtualMachineMO vmMo = this;
|
||||
private Future<?> answerVmwareQuestion(Boolean[] flags, VirtualMachineMO vmMo, boolean force) {
|
||||
Future<?> future = MonitorServiceExecutor.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
s_logger.info("VM Question monitor started...");
|
||||
|
||||
while (!flags[0]) {
|
||||
try {
|
||||
VirtualMachineRuntimeInfo runtimeInfo = vmMo.getRuntimeInfo();
|
||||
|
|
@ -1670,6 +1564,119 @@ public class VirtualMachineMO extends BaseMO {
|
|||
s_logger.info("VM Question monitor stopped");
|
||||
}
|
||||
});
|
||||
return future;
|
||||
}
|
||||
// isoDatastorePath: [datastore name] isoFilePath
|
||||
public void attachIso(String isoDatastorePath, ManagedObjectReference morDs, boolean connect, boolean connectAtBoot, boolean forced) throws Exception {
|
||||
attachIso(isoDatastorePath, morDs, connect, connectAtBoot, null, forced);
|
||||
}
|
||||
|
||||
// isoDatastorePath: [datastore name] isoFilePath
|
||||
public void attachIso(String isoDatastorePath, ManagedObjectReference morDs,
|
||||
boolean connect, boolean connectAtBoot, Integer key, boolean force) throws Exception {
|
||||
|
||||
if (s_logger.isTraceEnabled())
|
||||
s_logger.trace("vCenter API trace - attachIso(). target MOR: " + _mor.getValue() + ", isoDatastorePath: " + isoDatastorePath + ", datastore: " +
|
||||
morDs.getValue() + ", connect: " + connect + ", connectAtBoot: " + connectAtBoot);
|
||||
|
||||
assert (isoDatastorePath != null);
|
||||
assert (morDs != null);
|
||||
|
||||
boolean newCdRom = false;
|
||||
VirtualCdrom cdRom;
|
||||
if (key == null) {
|
||||
cdRom = (VirtualCdrom) getIsoDevice();
|
||||
} else {
|
||||
cdRom = (VirtualCdrom) getIsoDevice(key);
|
||||
}
|
||||
if (cdRom == null) {
|
||||
newCdRom = true;
|
||||
cdRom = new VirtualCdrom();
|
||||
cdRom.setControllerKey(getIDEDeviceControllerKey());
|
||||
|
||||
int deviceNumber = getNextIDEDeviceNumber();
|
||||
cdRom.setUnitNumber(deviceNumber);
|
||||
cdRom.setKey(-deviceNumber);
|
||||
}
|
||||
|
||||
VirtualDeviceConnectInfo cInfo = new VirtualDeviceConnectInfo();
|
||||
cInfo.setConnected(connect);
|
||||
cInfo.setStartConnected(connectAtBoot);
|
||||
cdRom.setConnectable(cInfo);
|
||||
|
||||
VirtualCdromIsoBackingInfo backingInfo = new VirtualCdromIsoBackingInfo();
|
||||
backingInfo.setFileName(isoDatastorePath);
|
||||
backingInfo.setDatastore(morDs);
|
||||
cdRom.setBacking(backingInfo);
|
||||
|
||||
VirtualMachineConfigSpec reConfigSpec = new VirtualMachineConfigSpec();
|
||||
//VirtualDeviceConfigSpec[] deviceConfigSpecArray = new VirtualDeviceConfigSpec[1];
|
||||
VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec();
|
||||
|
||||
deviceConfigSpec.setDevice(cdRom);
|
||||
if (newCdRom) {
|
||||
deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD);
|
||||
} else {
|
||||
deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.EDIT);
|
||||
}
|
||||
|
||||
//deviceConfigSpecArray[0] = deviceConfigSpec;
|
||||
reConfigSpec.getDeviceChange().add(deviceConfigSpec);
|
||||
|
||||
ManagedObjectReference morTask = _context.getService().reconfigVMTask(_mor, reConfigSpec);
|
||||
|
||||
final Boolean[] flags = {false};
|
||||
final VirtualMachineMO vmMo = this;
|
||||
Future<?> future = answerVmwareQuestion(flags, vmMo, force);
|
||||
try {
|
||||
boolean result = _context.getVimClient().waitForTask(morTask);
|
||||
|
||||
if (!result) {
|
||||
if (s_logger.isTraceEnabled())
|
||||
s_logger.trace("vCenter API trace - attachIso() done(failed)");
|
||||
throw new Exception("Failed to attach ISO due to " + TaskMO.getTaskFailureInfo(_context, morTask));
|
||||
}
|
||||
_context.waitForTaskProgressDone(morTask);
|
||||
|
||||
if (s_logger.isTraceEnabled())
|
||||
s_logger.trace("vCenter API trace - attachIso() done(successfully)");
|
||||
} finally {
|
||||
flags[0] = true;
|
||||
future.cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
public int detachIso(String isoDatastorePath, final boolean force) throws Exception {
|
||||
if (s_logger.isTraceEnabled())
|
||||
s_logger.trace("vCenter API trace - detachIso(). target MOR: " + _mor.getValue() + ", isoDatastorePath: " + isoDatastorePath);
|
||||
|
||||
VirtualDevice device = getIsoDevice(isoDatastorePath);
|
||||
if (device == null) {
|
||||
if (s_logger.isTraceEnabled())
|
||||
s_logger.trace("vCenter API trace - detachIso() done(failed)");
|
||||
throw new Exception("Unable to find a CDROM device");
|
||||
}
|
||||
|
||||
VirtualCdromRemotePassthroughBackingInfo backingInfo = new VirtualCdromRemotePassthroughBackingInfo();
|
||||
backingInfo.setDeviceName("");
|
||||
device.setBacking(backingInfo);
|
||||
|
||||
VirtualMachineConfigSpec reConfigSpec = new VirtualMachineConfigSpec();
|
||||
//VirtualDeviceConfigSpec[] deviceConfigSpecArray = new VirtualDeviceConfigSpec[1];
|
||||
VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec();
|
||||
|
||||
deviceConfigSpec.setDevice(device);
|
||||
deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.EDIT);
|
||||
|
||||
//deviceConfigSpecArray[0] = deviceConfigSpec;
|
||||
reConfigSpec.getDeviceChange().add(deviceConfigSpec);
|
||||
|
||||
ManagedObjectReference morTask = _context.getService().reconfigVMTask(_mor, reConfigSpec);
|
||||
|
||||
// Monitor VM questions
|
||||
final Boolean[] flags = {false};
|
||||
final VirtualMachineMO vmMo = this;
|
||||
Future<?> future = answerVmwareQuestion(flags, vmMo, force);
|
||||
try {
|
||||
boolean result = _context.getVimClient().waitForTask(morTask);
|
||||
if (!result) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue