diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/StopVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/StopVMCmd.java index ece41b8dcc2..5b2f0208e0b 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/StopVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/StopVMCmd.java @@ -54,7 +54,7 @@ public class StopVMCmd extends BaseAsyncCmd { private Long id; @Parameter(name = ApiConstants.FORCED, type = CommandType.BOOLEAN, required = false, description = "Force stop the VM " - + "(vm is marked as Stopped even when command fails to be send to the backend). The caller knows the VM is stopped.") + + "(vm is marked as Stopped even when command fails to be send to the backend, otherwise a force poweroff is attempted). The caller knows the VM is stopped.") private Boolean forced; // /////////////////////////////////////////////////// diff --git a/core/src/com/cloud/agent/api/StopCommand.java b/core/src/com/cloud/agent/api/StopCommand.java index b723d746cc3..869af3a7f4a 100644 --- a/core/src/com/cloud/agent/api/StopCommand.java +++ b/core/src/com/cloud/agent/api/StopCommand.java @@ -28,6 +28,7 @@ public class StopCommand extends RebootCommand { private String publicConsoleProxyIpAddress = null; private GPUDeviceTO gpuDevice; boolean checkBeforeCleanup = false; + boolean forceStop = false; protected StopCommand() { } @@ -45,6 +46,12 @@ public class StopCommand extends RebootCommand { this.checkBeforeCleanup = checkBeforeCleanup; } + public StopCommand(VirtualMachine vm, boolean executeInSequence, boolean checkBeforeCleanup, boolean forceStop) { + super(vm.getInstanceName(), executeInSequence); + this.checkBeforeCleanup = checkBeforeCleanup; + this.forceStop = forceStop; + } + public StopCommand(String vmName, boolean executeInSequence, boolean checkBeforeCleanup) { super(vmName, executeInSequence); this.checkBeforeCleanup = checkBeforeCleanup; @@ -82,4 +89,8 @@ public class StopCommand extends RebootCommand { public boolean checkBeforeCleanup() { return this.checkBeforeCleanup; } + + public boolean isForceStop() { + return forceStop; + } } diff --git a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java index 03a37987752..dfc48d5ccd6 100644 --- a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -1536,7 +1536,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac vmGuru.prepareStop(profile); - final StopCommand stop = new StopCommand(vm, getExecuteInSequence(vm.getHypervisorType()), false); + final StopCommand stop = new StopCommand(vm, getExecuteInSequence(vm.getHypervisorType()), false, cleanUpEvenIfUnableToStop); boolean stopped = false; Answer answer = null; diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index c26c3e2bef1..7a3f93667ef 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -2703,7 +2703,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv } } s_logger.debug(vmDef); - msg = stopVM(conn, vmName); + msg = stopVM(conn, vmName, false); msg = startVM(conn, vmName, vmDef); return null; } catch (final LibvirtException e) { @@ -2725,14 +2725,17 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv return msg; } - public String stopVM(final Connect conn, final String vmName) { + public String stopVM(final Connect conn, final String vmName, final boolean forceStop) { DomainState state = null; Domain dm = null; s_logger.debug("Try to stop the vm at first"); + if (forceStop) { + return stopVMInternal(conn, vmName, true); + } String ret = stopVM(conn, vmName, false); if (ret == Script.ERR_TIMEOUT) { - ret = stopVM(conn, vmName, true); + ret = stopVMInternal(conn, vmName, true); } else if (ret != null) { /* * There is a race condition between libvirt and qemu: libvirt @@ -2765,7 +2768,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv if (state != DomainState.VIR_DOMAIN_SHUTOFF) { s_logger.debug("Try to destroy the vm"); - ret = stopVM(conn, vmName, true); + ret = stopVMInternal(conn, vmName, true); if (ret != null) { return ret; } @@ -2775,7 +2778,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv return null; } - protected String stopVM(final Connect conn, final String vmName, final boolean force) { + protected String stopVMInternal(final Connect conn, final String vmName, final boolean force) { Domain dm = null; try { dm = conn.domainLookupByName(vmName); diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtStopCommandWrapper.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtStopCommandWrapper.java index f7e088bfd23..feec1c339d9 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtStopCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtStopCommandWrapper.java @@ -67,7 +67,8 @@ public final class LibvirtStopCommandWrapper extends CommandWrapper ifaces = libvirtComputingResource.getInterfaces(conn, vmName); libvirtComputingResource.destroyNetworkRulesForVM(conn, vmName); - final String result = libvirtComputingResource.stopVM(conn, vmName); + final String result = libvirtComputingResource.stopVM(conn, vmName, command.isForceStop()); + if (result == null) { for (final DiskDef disk : disks) { libvirtComputingResource.cleanupDisk(disk); diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 56ca4ea0966..10f0fd32a8d 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -3150,13 +3150,18 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa vmMo.setCustomFieldValue(CustomFieldConstants.CLOUD_VM_INTERNAL_NAME, cmd.getVmName()); if (getVmPowerState(vmMo) != PowerState.PowerOff) { - if (vmMo.safePowerOff(_shutdownWaitMs)) { - return new StopAnswer(cmd, "Stop VM " + cmd.getVmName() + " Succeed", true); + String msg = "Stop VM " + cmd.getVmName() + " Succeed"; + boolean success = false; + if (cmd.isForceStop()) { + success = vmMo.powerOff(); } else { - String msg = "Have problem in powering off VM " + cmd.getVmName() + ", let the process continue"; - s_logger.warn(msg); - return new StopAnswer(cmd, msg, true); + success = vmMo.safePowerOff(_shutdownWaitMs); } + if (!success) { + msg = "Have problem in powering off VM " + cmd.getVmName() + ", let the process continue"; + s_logger.warn(msg); + } + return new StopAnswer(cmd, msg, true); } String msg = "VM " + cmd.getVmName() + " is already in stopped state"; diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java index ca8a645532e..54840396d5f 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java @@ -4862,10 +4862,15 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe return null; } - public void shutdownVM(final Connection conn, final VM vm, final String vmName) throws XmlRpcException { + public void shutdownVM(final Connection conn, final VM vm, final String vmName, final boolean forcedStop) throws XmlRpcException { Task task = null; try { - task = vm.cleanShutdownAsync(conn); + if (forcedStop) { + task = vm.hardShutdownAsync(conn); + } else { + task = vm.cleanShutdownAsync(conn); + } + try { // poll every 1 seconds , timeout after 10 minutes waitForTask(conn, task, 1000, 10 * 60 * 1000); @@ -4878,7 +4883,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe throw new CloudRuntimeException("Shutdown VM catch HandleInvalid and VM is not in HALTED state"); } } catch (final XenAPIException e) { - s_logger.debug("Unable to cleanShutdown VM(" + vmName + ") on host(" + _host.getUuid() + ") due to " + e.toString()); + s_logger.debug("Unable to shutdown VM(" + vmName + ") with force=" + forcedStop + " on host(" + _host.getUuid() + ") due to " + e.toString()); try { VmPowerState state = vm.getPowerState(conn); if (state == VmPowerState.RUNNING) { diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStopCommandWrapper.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStopCommandWrapper.java index af94d83858a..42d7d3bcb01 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStopCommandWrapper.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStopCommandWrapper.java @@ -113,7 +113,7 @@ public final class CitrixStopCommandWrapper extends CommandWrapper