mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
vmware: Add force parameter to iso attach/detach operations (#4907)
Fixes: #4808, #4941 This PR adds a force flag to the attachIso / detachIso commands, especially for VMware where it is noticed that when trying to either detach an iso or attach an iso when there already exists another present it fails to do the necessary operation as from ACS end we either answer the question returned by Esxi for CDRom disconnect operation as No (for detach operation) or do not answer the question at all (for Attach operation). Co-authored-by: Pearl Dsilva <pearl.dsilva@shapeblue.com>
This commit is contained in:
parent
73f82ae9dd
commit
98e2ed3c4f
@ -56,9 +56,9 @@ public interface TemplateApiService {
|
|||||||
|
|
||||||
VirtualMachineTemplate prepareTemplate(long templateId, long zoneId, Long storageId);
|
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
|
* Deletes a template
|
||||||
|
|||||||
@ -54,6 +54,10 @@ public class AttachIsoCmd extends BaseAsyncCmd implements UserCmd {
|
|||||||
required = true, description = "the ID of the virtual machine")
|
required = true, description = "the ID of the virtual machine")
|
||||||
protected Long virtualMachineId;
|
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 ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -66,6 +70,10 @@ public class AttachIsoCmd extends BaseAsyncCmd implements UserCmd {
|
|||||||
return virtualMachineId;
|
return virtualMachineId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean isForced() {
|
||||||
|
return forced != null;
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////// API Implementation///////////////////
|
/////////////// API Implementation///////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -98,7 +106,7 @@ public class AttachIsoCmd extends BaseAsyncCmd implements UserCmd {
|
|||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() {
|
||||||
CallContext.current().setEventDetails("Vm Id: " + getVirtualMachineId() + " ISO ID: " + getId());
|
CallContext.current().setEventDetails("Vm Id: " + getVirtualMachineId() + " ISO ID: " + getId());
|
||||||
boolean result = _templateService.attachIso(id, virtualMachineId);
|
boolean result = _templateService.attachIso(id, virtualMachineId, isForced());
|
||||||
if (result) {
|
if (result) {
|
||||||
UserVm userVm = _responseGenerator.findUserVmById(virtualMachineId);
|
UserVm userVm = _responseGenerator.findUserVmById(virtualMachineId);
|
||||||
if (userVm != null) {
|
if (userVm != null) {
|
||||||
|
|||||||
@ -44,10 +44,14 @@ public class DetachIsoCmd extends BaseAsyncCmd implements UserCmd {
|
|||||||
//////////////// API parameters /////////////////////
|
//////////////// API parameters /////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Parameter(name=ApiConstants.VIRTUAL_MACHINE_ID, type=CommandType.UUID, entityType = UserVmResponse.class,
|
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID, type = CommandType.UUID, entityType = UserVmResponse.class,
|
||||||
required=true, description="The ID of the virtual machine")
|
required = true, description = "The ID of the virtual machine")
|
||||||
protected Long virtualMachineId;
|
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 ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -56,6 +60,10 @@ public class DetachIsoCmd extends BaseAsyncCmd implements UserCmd {
|
|||||||
return virtualMachineId;
|
return virtualMachineId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean isForced() {
|
||||||
|
return forced != null;
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////// API Implementation///////////////////
|
/////////////// API Implementation///////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -87,7 +95,7 @@ public class DetachIsoCmd extends BaseAsyncCmd implements UserCmd {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() {
|
||||||
boolean result = _templateService.detachIso(virtualMachineId);
|
boolean result = _templateService.detachIso(virtualMachineId, isForced());
|
||||||
if (result) {
|
if (result) {
|
||||||
UserVm userVm = _entityMgr.findById(UserVm.class, virtualMachineId);
|
UserVm userVm = _entityMgr.findById(UserVm.class, virtualMachineId);
|
||||||
UserVmResponse response = _responseGenerator.createUserVmResponse(getResponseView(), "virtualmachine", userVm).get(0);
|
UserVmResponse response = _responseGenerator.createUserVmResponse(getResponseView(), "virtualmachine", userVm).get(0);
|
||||||
|
|||||||
@ -27,6 +27,7 @@ public final class AttachCommand extends StorageSubSystemCommand {
|
|||||||
private DiskTO disk;
|
private DiskTO disk;
|
||||||
private String vmName;
|
private String vmName;
|
||||||
private boolean inSeq = false;
|
private boolean inSeq = false;
|
||||||
|
private boolean forced = false;
|
||||||
private Map<String, String> controllerInfo;
|
private Map<String, String> controllerInfo;
|
||||||
|
|
||||||
public AttachCommand(final DiskTO disk, final String vmName) {
|
public AttachCommand(final DiskTO disk, final String vmName) {
|
||||||
@ -69,6 +70,14 @@ public final class AttachCommand extends StorageSubSystemCommand {
|
|||||||
this.vmName = vmName;
|
this.vmName = vmName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isForced() {
|
||||||
|
return forced;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setForced(boolean forced) {
|
||||||
|
this.forced = forced;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setExecuteInSequence(final boolean inSeq) {
|
public void setExecuteInSequence(final boolean inSeq) {
|
||||||
this.inSeq = inSeq;
|
this.inSeq = inSeq;
|
||||||
|
|||||||
@ -31,6 +31,7 @@ public class DettachCommand extends StorageSubSystemCommand {
|
|||||||
private String _storageHost;
|
private String _storageHost;
|
||||||
private int _storagePort;
|
private int _storagePort;
|
||||||
private Map<String, String> params;
|
private Map<String, String> params;
|
||||||
|
private boolean forced;
|
||||||
|
|
||||||
public DettachCommand(final DiskTO disk, final String vmName) {
|
public DettachCommand(final DiskTO disk, final String vmName) {
|
||||||
super();
|
super();
|
||||||
@ -106,6 +107,14 @@ public class DettachCommand extends StorageSubSystemCommand {
|
|||||||
this.params = params;
|
this.params = params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isForced() {
|
||||||
|
return forced;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setForced(boolean forced) {
|
||||||
|
this.forced = forced;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setExecuteInSequence(final boolean inSeq) {
|
public void setExecuteInSequence(final boolean inSeq) {
|
||||||
|
|
||||||
|
|||||||
@ -2019,35 +2019,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
if (volIso != null) {
|
if (volIso != null) {
|
||||||
for (DiskTO vol : disks) {
|
for (DiskTO vol : disks) {
|
||||||
if (vol.getType() == Volume.Type.ISO) {
|
if (vol.getType() == Volume.Type.ISO) {
|
||||||
|
configureIso(hyperHost, vmMo, vol, deviceConfigSpecArray, ideUnitNumber++, i);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2075,8 +2047,16 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
//
|
//
|
||||||
// Setup ROOT/DATA disk devices
|
// Setup ROOT/DATA disk devices
|
||||||
//
|
//
|
||||||
|
if (multipleIsosAtached(sortedDisks) && deployAsIs) {
|
||||||
|
sortedDisks = getDisks(sortedDisks);
|
||||||
|
}
|
||||||
|
|
||||||
for (DiskTO vol : sortedDisks) {
|
for (DiskTO vol : sortedDisks) {
|
||||||
if (vol.getType() == Volume.Type.ISO) {
|
if (vol.getType() == Volume.Type.ISO) {
|
||||||
|
if (deployAsIs) {
|
||||||
|
configureIso(hyperHost, vmMo, vol, deviceConfigSpecArray, ideUnitNumber++, i);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2457,6 +2437,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) {
|
private String mapAdapterType(String adapterStringFromOVF) {
|
||||||
if (StringUtils.isBlank(adapterStringFromOVF) || adapterStringFromOVF.equalsIgnoreCase(VirtualEthernetCardType.E1000.toString())) {
|
if (StringUtils.isBlank(adapterStringFromOVF) || adapterStringFromOVF.equalsIgnoreCase(VirtualEthernetCardType.E1000.toString())) {
|
||||||
return VirtualEthernetCardType.E1000.toString();
|
return VirtualEthernetCardType.E1000.toString();
|
||||||
@ -5382,7 +5402,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.");
|
"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) {
|
} catch (Throwable e) {
|
||||||
vmMo.detachIso(null);
|
vmMo.detachIso(null, cmd.isForce());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5411,7 +5431,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
String isoDatastorePath = String.format("[%s] %s%s", storeName, isoStorePathFromRoot, isoFileName);
|
String isoDatastorePath = String.format("[%s] %s%s", storeName, isoStorePathFromRoot, isoFileName);
|
||||||
|
|
||||||
if (cmd.isAttach()) {
|
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);
|
return new AttachIsoAnswer(cmd);
|
||||||
} else {
|
} else {
|
||||||
int key = vmMo.detachIso(isoDatastorePath, cmd.isForce());
|
int key = vmMo.detachIso(isoDatastorePath, cmd.isForce());
|
||||||
|
|||||||
@ -2045,7 +2045,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Answer attachIso(AttachCommand cmd) {
|
public Answer attachIso(AttachCommand cmd) {
|
||||||
return this.attachIso(cmd.getDisk(), true, cmd.getVmName());
|
return this.attachIso(cmd.getDisk(), true, cmd.getVmName(), cmd.isForced());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -2411,7 +2411,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
|||||||
return morDatastore;
|
return morDatastore;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Answer attachIso(DiskTO disk, boolean isAttach, String vmName) {
|
private Answer attachIso(DiskTO disk, boolean isAttach, String vmName, boolean force) {
|
||||||
try {
|
try {
|
||||||
VmwareContext context = hostService.getServiceContext(null);
|
VmwareContext context = hostService.getServiceContext(null);
|
||||||
VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, 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.");
|
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){
|
} 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);
|
String isoDatastorePath = String.format("[%s] %s/%s", storeName, isoStorePathFromRoot, isoFileName);
|
||||||
|
|
||||||
if (isAttach) {
|
if (isAttach) {
|
||||||
vmMo.attachIso(isoDatastorePath, morSecondaryDs, true, false);
|
vmMo.attachIso(isoDatastorePath, morSecondaryDs, true, false, force);
|
||||||
} else {
|
} else {
|
||||||
vmMo.detachIso(isoDatastorePath);
|
vmMo.detachIso(isoDatastorePath, force);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new AttachAnswer(disk);
|
return new AttachAnswer(disk);
|
||||||
@ -2497,7 +2497,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Answer dettachIso(DettachCommand cmd) {
|
public Answer dettachIso(DettachCommand cmd) {
|
||||||
return this.attachIso(cmd.getDisk(), false, cmd.getVmName());
|
return this.attachIso(cmd.getDisk(), false, cmd.getVmName(), cmd.isForced());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -319,7 +319,7 @@ public class KubernetesClusterActionWorker {
|
|||||||
}
|
}
|
||||||
for (UserVm vm : clusterVMs) {
|
for (UserVm vm : clusterVMs) {
|
||||||
try {
|
try {
|
||||||
templateService.attachIso(iso.getId(), vm.getId());
|
templateService.attachIso(iso.getId(), vm.getId(), true);
|
||||||
if (LOGGER.isInfoEnabled()) {
|
if (LOGGER.isInfoEnabled()) {
|
||||||
LOGGER.info(String.format("Attached binaries ISO for VM : %s in cluster: %s", vm.getDisplayName(), kubernetesCluster.getName()));
|
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) {
|
for (UserVm vm : clusterVMs) {
|
||||||
boolean result = false;
|
boolean result = false;
|
||||||
try {
|
try {
|
||||||
result = templateService.detachIso(vm.getId());
|
result = templateService.detachIso(vm.getId(), true);
|
||||||
} catch (CloudRuntimeException ex) {
|
} 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);
|
LOGGER.warn(String.format("Failed to detach binaries ISO from VM : %s in the Kubernetes cluster : %s ", vm.getDisplayName(), kubernetesCluster.getName()), ex);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1150,7 +1150,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ActionEvent(eventType = EventTypes.EVENT_ISO_DETACH, eventDescription = "detaching ISO", async = true)
|
@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();
|
Account caller = CallContext.current().getCallingAccount();
|
||||||
Long userId = CallContext.current().getCallingUserId();
|
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.");
|
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
|
// => detach
|
||||||
if (result) {
|
if (result) {
|
||||||
return result;
|
return result;
|
||||||
@ -1189,7 +1189,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ActionEvent(eventType = EventTypes.EVENT_ISO_ATTACH, eventDescription = "attaching ISO", async = true)
|
@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();
|
Account caller = CallContext.current().getCallingAccount();
|
||||||
Long userId = CallContext.current().getCallingUserId();
|
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) {
|
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());
|
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) {
|
if (result) {
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} 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);
|
UserVmVO vm = _userVmDao.findById(vmId);
|
||||||
|
|
||||||
if (vm == null) {
|
if (vm == null) {
|
||||||
@ -1302,19 +1302,21 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
|
|||||||
|
|
||||||
Command cmd = null;
|
Command cmd = null;
|
||||||
if (attach) {
|
if (attach) {
|
||||||
cmd = new AttachCommand(disk, vmName, vmTO.getDetails());
|
cmd = new AttachCommand(disk, vmName);
|
||||||
|
((AttachCommand)cmd).setForced(forced);
|
||||||
} else {
|
} else {
|
||||||
cmd = new DettachCommand(disk, vmName, vmTO.getDetails());
|
cmd = new DettachCommand(disk, vmName);
|
||||||
|
((DettachCommand)cmd).setForced(forced);
|
||||||
}
|
}
|
||||||
Answer a = _agentMgr.easySend(vm.getHostId(), cmd);
|
Answer a = _agentMgr.easySend(vm.getHostId(), cmd);
|
||||||
return (a != null && a.getResult());
|
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);
|
UserVmVO vm = _userVmDao.findById(vmId);
|
||||||
VMTemplateVO iso = _tmpltDao.findById(isoId);
|
VMTemplateVO iso = _tmpltDao.findById(isoId);
|
||||||
|
|
||||||
boolean success = attachISOToVM(vmId, isoId, attach);
|
boolean success = attachISOToVM(vmId, isoId, attach, forced);
|
||||||
if (success && attach) {
|
if (success && attach) {
|
||||||
vm.setIsoId(iso.getId());
|
vm.setIsoId(iso.getId());
|
||||||
_userVmDao.update(vmId, vm);
|
_userVmDao.update(vmId, vm);
|
||||||
|
|||||||
@ -5350,7 +5350,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
for (VMTemplateVO tmpl: child_templates){
|
for (VMTemplateVO tmpl: child_templates){
|
||||||
if (tmpl.getFormat() == Storage.ImageFormat.ISO){
|
if (tmpl.getFormat() == Storage.ImageFormat.ISO){
|
||||||
s_logger.info("MDOV trying to attach disk to the VM " + tmpl.getId() + " vmid=" + vm.getId());
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -253,7 +253,13 @@ export default {
|
|||||||
label: 'label.action.detach.iso',
|
label: 'label.action.detach.iso',
|
||||||
message: 'message.detach.iso.confirm',
|
message: 'message.detach.iso.confirm',
|
||||||
dataView: true,
|
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 },
|
show: (record) => { return ['Running', 'Stopped'].includes(record.state) && 'isoid' in record && record.isoid },
|
||||||
mapping: {
|
mapping: {
|
||||||
virtualmachineid: {
|
virtualmachineid: {
|
||||||
|
|||||||
@ -33,6 +33,9 @@
|
|||||||
</a-select-option>
|
</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</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>
|
</a-form>
|
||||||
<div :span="24" class="action-button">
|
<div :span="24" class="action-button">
|
||||||
<a-button @click="closeAction">{{ this.$t('label.cancel') }}</a-button>
|
<a-button @click="closeAction">{{ this.$t('label.cancel') }}</a-button>
|
||||||
@ -116,6 +119,11 @@ export default {
|
|||||||
id: values.id,
|
id: values.id,
|
||||||
virtualmachineid: this.resource.id
|
virtualmachineid: this.resource.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (values.forced) {
|
||||||
|
params.forced = values.forced
|
||||||
|
}
|
||||||
|
|
||||||
this.loading = true
|
this.loading = true
|
||||||
const title = this.$t('label.action.attach.iso')
|
const title = this.$t('label.action.attach.iso')
|
||||||
api('attachIso', params).then(json => {
|
api('attachIso', params).then(json => {
|
||||||
|
|||||||
@ -1498,117 +1498,11 @@ public class VirtualMachineMO extends BaseMO {
|
|||||||
s_logger.trace("vCenter API trace - detachAllDisk() done(successfully)");
|
s_logger.trace("vCenter API trace - detachAllDisk() done(successfully)");
|
||||||
}
|
}
|
||||||
|
|
||||||
// isoDatastorePath: [datastore name] isoFilePath
|
private Future<?> answerVmwareQuestion(Boolean[] flags, VirtualMachineMO vmMo, boolean force) {
|
||||||
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;
|
|
||||||
Future<?> future = MonitorServiceExecutor.submit(new Runnable() {
|
Future<?> future = MonitorServiceExecutor.submit(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
s_logger.info("VM Question monitor started...");
|
s_logger.info("VM Question monitor started...");
|
||||||
|
|
||||||
while (!flags[0]) {
|
while (!flags[0]) {
|
||||||
try {
|
try {
|
||||||
VirtualMachineRuntimeInfo runtimeInfo = vmMo.getRuntimeInfo();
|
VirtualMachineRuntimeInfo runtimeInfo = vmMo.getRuntimeInfo();
|
||||||
@ -1670,6 +1564,119 @@ public class VirtualMachineMO extends BaseMO {
|
|||||||
s_logger.info("VM Question monitor stopped");
|
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 {
|
try {
|
||||||
boolean result = _context.getVimClient().waitForTask(morTask);
|
boolean result = _context.getVimClient().waitForTask(morTask);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user