diff --git a/compute/src/main/java/org/zstack/compute/vm/StopVmGC.java b/compute/src/main/java/org/zstack/compute/vm/StopVmGC.java index a55de8878cf..5f4cb98f800 100755 --- a/compute/src/main/java/org/zstack/compute/vm/StopVmGC.java +++ b/compute/src/main/java/org/zstack/compute/vm/StopVmGC.java @@ -43,6 +43,12 @@ protected void triggerNow(GCCompletion completion) { completion.cancel(); return; } + if (state != VmInstanceState.Stopped) { + logger.info(String.format("cancel StopVmGC for vm[uuid:%s,name:%s] on host[uuid:%s], current state is %s, only stopped vm can be stopped on hypervisor by this GC", + inventory.getUuid(), inventory.getName(), hostUuid, state)); + completion.cancel(); + return; + } FlowChain chain = FlowChainBuilder.newSimpleFlowChain(); chain.setName(String.format("gc-stop-vm-%s-on-host-%s", inventory.getUuid(), hostUuid)); diff --git a/test/src/test/groovy/org/zstack/test/integration/kvm/vm/VmGCCase.groovy b/test/src/test/groovy/org/zstack/test/integration/kvm/vm/VmGCCase.groovy index ed2b5520d31..f9925859d5c 100755 --- a/test/src/test/groovy/org/zstack/test/integration/kvm/vm/VmGCCase.groovy +++ b/test/src/test/groovy/org/zstack/test/integration/kvm/vm/VmGCCase.groovy @@ -225,6 +225,7 @@ class VmGCCase extends SubCase { testStopVmWhenHostDisconnect() testStopVmGCJobCancelAfterVmDeleted() + testStopVmGCJobCancelAfterVmStarted() testStopVmGCJobCancelAfterHostDeleted() } } @@ -317,6 +318,46 @@ class VmGCCase extends SubCase { } } + void testStopVmGCJobCancelAfterVmStarted() { + VmInstanceInventory vm = createGCCandidateStoppedVm() + + vm = startVmInstance { + uuid = vm.uuid + } as VmInstanceInventory + + assert dbFindByUuid(vm.uuid, VmInstanceVO.class).state == VmInstanceState.Running + + KVMAgentCommands.StopVmCmd cmd = null + env.afterSimulator(KVMConstant.KVM_STOP_VM_PATH) { rsp, HttpEntity e -> + cmd = json(e.body, KVMAgentCommands.StopVmCmd.class) + return rsp + } + + // reconnect host to trigger the GC + reconnectHost { + uuid = vm.hostUuid + } + + GarbageCollectorInventory inv = null + retryInSecs { + inv = queryGCJob { + conditions=["context~=%${vm.uuid}%"] + }[0] + + // the GC job is cancelled because the vm has already been started again + assert cmd == null + assert inv.status == GCStatus.Done.toString() + } + + deleteGCJob { + uuid = inv.uuid + } + + destroyVmInstance { + uuid = vm.uuid + } + } + void testStopVmWhenHostDisconnect() { VmInstanceInventory vm = createGCCandidateStoppedVm()