Skip to content

Commit 81c442d

Browse files
authored
fix HA-enabled VMs stuck in Running after out-of-band stop (OOM-kill) (#14)
* power state * update
1 parent 150d977 commit 81c442d

2 files changed

Lines changed: 43 additions & 2 deletions

File tree

engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,10 @@
209209
import com.cloud.exception.ResourceUnavailableException;
210210
import com.cloud.exception.StorageAccessException;
211211
import com.cloud.exception.StorageUnavailableException;
212+
import com.cloud.ha.HaWorkVO;
212213
import com.cloud.ha.HighAvailabilityManager;
213214
import com.cloud.ha.HighAvailabilityManager.WorkType;
215+
import com.cloud.ha.dao.HighAvailabilityDao;
214216
import com.cloud.host.Host;
215217
import com.cloud.host.HostVO;
216218
import com.cloud.host.Status;
@@ -361,6 +363,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
361363
@Inject
362364
private HighAvailabilityManager _haMgr;
363365
@Inject
366+
private HighAvailabilityDao _haDao;
367+
@Inject
364368
private HostPodDao _podDao;
365369
@Inject
366370
private DataCenterDao _dcDao;
@@ -5395,9 +5399,43 @@ private void handlePowerOffReportWithNoPendingJobsOnVM(final VMInstanceVO vm) {
53955399
&& HaVmRestartHostUp.value()
53965400
&& vm.getHypervisorType() != HypervisorType.VMware
53975401
&& vm.getHypervisorType() != HypervisorType.Hyperv) {
5398-
logger.info("Detected out-of-band stop of a HA enabled VM {}, will schedule restart.", vm);
5402+
logger.info("Detected out-of-band stop of HA enabled VM {}, transitioning to Stopped and scheduling HA restart (investigate=false).", vm);
53995403
if (!_haMgr.hasPendingHaWork(vm.getId())) {
5400-
_haMgr.scheduleRestart(vm, true);
5404+
// The power state report already confirmed the VM is off
5405+
// (e.g. OOM-killed QEMU process). We cannot use _haMgr.scheduleRestart() because it
5406+
// calls advanceStop(), which submits a VM work job and blocks waiting for completion.
5407+
// This code runs on the AgentManager-Handler thread, and the VM job queue does not
5408+
// dispatch jobs from this context — causing an indefinite block that leaves the VM
5409+
// stuck in Running. Instead we release resources, transition to Stopped, and insert
5410+
// an HA work item directly into op_ha_work (Step.Scheduled) for the HA worker to pick up.
5411+
final VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm);
5412+
releaseVmResources(profile, true);
5413+
5414+
// Save lastHostId before transition (stateTransitTo sets hostId=null)
5415+
final Long lastHostId = vm.getHostId();
5416+
try {
5417+
stateTransitTo(vm, VirtualMachine.Event.FollowAgentPowerOffReport, null);
5418+
} catch (final NoTransitionException e) {
5419+
logger.warn("Failed to transition VM {} to Stopped state: {}", vm, e.getMessage());
5420+
return;
5421+
}
5422+
5423+
_alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_SYNC, vm.getDataCenterId(), vm.getPodIdToDeployIn(),
5424+
VM_SYNC_ALERT_SUBJECT, String.format("VM %s(%s) stopped out-of-band (OOM-killed or crashed). HA restart scheduled.",
5425+
vm.getHostName(), vm.getInstanceName()));
5426+
5427+
// Insert HA work item directly — bypasses advanceStop/job queue entirely
5428+
final VMInstanceVO refreshedVm = _vmDao.findByUuid(vm.getUuid());
5429+
final Long haHostId = lastHostId != null ? lastHostId : refreshedVm.getLastHostId();
5430+
if (haHostId == null || haHostId == 0L) {
5431+
logger.warn("Cannot schedule HA for VM {} — no valid host_id available (would violate FK constraint).", vm);
5432+
} else {
5433+
final HaWorkVO work = new HaWorkVO(refreshedVm.getId(), refreshedVm.getType(),
5434+
WorkType.HA, HighAvailabilityManager.Step.Scheduled, haHostId,
5435+
refreshedVm.getState(), 0, refreshedVm.getUpdated(), null);
5436+
_haDao.persist(work);
5437+
logger.info("Scheduled VM for HA: {}", refreshedVm);
5438+
}
54015439
} else {
54025440
logger.info("VM {} already has a pending HA task working on it.", vm);
54035441
}

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,9 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
533533
POWER_STATES_TABLE.put(DomainState.VIR_DOMAIN_BLOCKED, PowerState.PowerOn);
534534
POWER_STATES_TABLE.put(DomainState.VIR_DOMAIN_NOSTATE, PowerState.PowerUnknown);
535535
POWER_STATES_TABLE.put(DomainState.VIR_DOMAIN_SHUTDOWN, PowerState.PowerOff);
536+
// Report crashed domains as PowerOff immediately instead of omitting them
537+
// from the report (which delays detection via the "missing VM" threshold).
538+
POWER_STATES_TABLE.put(DomainState.VIR_DOMAIN_CRASHED, PowerState.PowerOff);
536539
}
537540

538541
public VirtualRoutingResource virtRouterResource;

0 commit comments

Comments
 (0)