ACPI Management in KubeVirt#
ACPI (Advanced Configuration and Power Interface) in KubeVirt is modeled as a hypervisor feature flag on the VMI spec — not as a power-state controller. Enabling or disabling ACPI controls whether the libvirt/QEMU domain exposes an ACPI bus to the guest. KubeVirt does not directly drive ACPI guest sleep states (S3/S4); those are initiated by the guest OS. The closest KubeVirt comes to ACPI power-signaling is using the ACPI power-button event as a fallback reboot mechanism.
API Shape#
ACPI is one field inside v1.Features (spec.domain.features.acpi):
spec:
domain:
features:
acpi:
enabled: true # defaults to true when nil
FeatureState.Enabled is a *bool : when nil, it defaults to enabled — the converter treats a nil pointer as true.
Feature Conversion to Libvirt Domain XML#
HypervisorFeaturesDomainConfigurator.Configure in pkg/virt-launcher/virtwrap/converter/compute/hypervisor_features.go translates the VMI spec features to libvirt domain XML. The ACPI conversion rule is:
If
ACPI.Enabled == nilor*ACPI.Enabled == true→ emit<acpi/>in domain features .
Any explicitly-false value suppresses the element, telling QEMU not to present an ACPI controller to the guest.
Architecture-Specific Default: s390x#
s390x does not support ACPI. The mutating webhook applies setS390xDefaultFeatures (called from setDefaultFeatures → SetDefaultVirtualMachineInstance) to force ACPI.Enabled = false on every s390x VMI at admission time:
- If
spec.domain.featuresisnil, it creates the struct with ACPI explicitly disabled . - If
spec.domain.featuresexists butACPI.Enabledisnil(unset), it setsEnabled = false. - If
ACPI.Enabledis already set to an explicit value (eventrue), it is left unchanged — users can override but should not.
This is purely a defaults-layer concern; no runtime enforcement exists beyond the webhook.
Pause/Unpause vs. ACPI Guest Sleep States (S3/S4)#
This is the most common source of confusion:
| Operation | Mechanism | ACPI involved? |
|---|---|---|
PauseVMI | dom.Suspend() — freezes vCPUs at hypervisor level | No |
UnpauseVMI | dom.Resume() — resumes vCPUs | No |
SoftRebootVMI | dom.Reboot() via guest agent; falls back to DOMAIN_REBOOT_ACPI_POWER_BTN | Yes (fallback only) |
| Guest S3/S4 sleep | Initiated by guest OS, surfaced as PMSuspended domain state | Guest-driven |
Pause/Unpause (PauseVMI / UnpauseVMI) are libvirt-level domain suspension operations (DOMAIN_RUNNING → dom.Suspend() and DOMAIN_PAUSED → dom.Resume()). They freeze/thaw vCPUs without touching guest power management at all. After UnpauseVMI, the manager calls setGuestTime to correct the guest clock.
Soft reboot (SoftRebootVMI) prefers the QEMU guest agent (DOMAIN_REBOOT_GUEST_AGENT). When no agent is connected, it falls back to sending an ACPI power-button signal (DOMAIN_REBOOT_ACPI_POWER_BTN) — but only if ACPI is not explicitly disabled . If ACPI is also disabled and no agent is available, the call returns an error.
Guest sleep states (S3/S4) are never initiated by KubeVirt. If the guest OS enters S3 (suspend-to-RAM) or S4 (suspend-to-disk), libvirt transitions the domain to PMSuspended. Currently, virt-handler maps PMSuspended to the Running VMI phase — the state is visible internally but not surfaced as a distinct KubeVirt status. Full suspend-to-disk (hibernation) support is being developed separately (see VM Hibernation and Memory State).
Key Source Files#
| File | Purpose |
|---|---|
staging/src/kubevirt.io/api/core/v1/schema.go | Features struct — ACPI API definition |
pkg/defaults/s390x.go | s390x default: ACPI disabled |
pkg/defaults/defaults.go | setDefaultFeatures — arch dispatch |
pkg/virt-launcher/virtwrap/converter/compute/hypervisor_features.go | Converts VMI features → libvirt XML |
pkg/virt-launcher/virtwrap/manager.go | PauseVMI, UnpauseVMI, SoftRebootVMI implementations |