Skip to main content

Zyvor Guest Control Fabric

Zyvor does not depend on guest networking for VM intelligence. Guest control is transport-independent: the API selects the best available path per VM and per operation.

Transport ladder (priority order)​

TierTransportWhen used
1virtio-serialZyvor agent daemon + QGA channel
2qga-execQGA up → guest-exec → zyvor-guest-agent JSON-RPC
3qga-builtinQGA guest-ping, guest-file-*, freeze/thaw
4in-guest-socketLocal agent socket probe via QGA exec
5https-pushRedis-cached push report or HTTP agent proxy
6offline-diskHalted VM → GuestKit repair/inspect job on root PVC
7console-onlyRunning VM, no QGA — structured error + recommendations

Each pull records attempts: [{ tier, ok, latencyMs, error }] for Agent Doctor and debugging.

Control states (UI)​

StateMeaning
full_agentAgent daemon running with network or push
airgap_liveAgent + QGA, no guest network — host-mediated pull
qga_onlyQGA connected, Zyvor agent missing
disk_onlyVM stopped, offline repair possible
console_onlyVM running, no QGA
blind_vmNo live or offline path

Capability contract​

GET /api/v1/kubevirt/vms/{ns}/{name}/guest/capabilities returns:

{
"ok": true,
"transport": "qga-exec",
"controlState": "airgap_live",
"capabilities": {
"network": false,
"qga": true,
"zyvorAgent": true,
"supports": { "evidence": true, "exec": true, "freeze": true, "pushTelemetry": false }
},
"warnings": ["guest network unavailable"],
"recommendedActions": ["install_agent_via_qga"]
}

API routes​

MethodPathPurpose
GET.../guest/statusControl state + probes
GET.../guest/capabilitiesCapability contract
GET/POST.../guest/doctorAgent Doctor tree; POST runs live guestkit.doctor
GET.../guest/readinessMigration readiness score 0–100
POST.../guest/install-agentStrategy-aware install
POST.../guest/repair-planOffline repair for halted VM
POST.../guest/file/readQGA file read
POST.../guest/file/writeQGA file write (airgap bootstrap)
POST/kubevirt/guest/poll-reconcilePoll AirgapLive VMs without push
GET/kubevirt/guest/poll-telemetryFleet airgap poll rollup
GET.../guest/poll-telemetryPer-VM latest poll sample (latency + attempts)

All guest routes return a GuestControlEnvelope: ok, transport, networkRequired, controlState, capabilities, warnings, recommendedActions, data.

Airgap install (QGA file bootstrap)​

When QGA is up but guest network is down:

  1. API fetches zyvor-vm-tools-linux-amd64.tar.gz from the cluster bundle URL
  2. Chunks are written to /tmp/zyvor-vm-tools.tar.gz via guest-file-open/write/close
  3. guest-exec unpacks and enables zyvor-guest-agent.service — no curl in guest

Trigger: POST .../guest/install-agent with { "strategy": "auto" } (auto-selects qga_file_bootstrap).

Host-mediated polling​

Background worker (GUEST_AIRGAP_POLL_ENABLED, default on) polls VMs in airgap_live without push heartbeat every 30s (GUEST_AIRGAP_POLL_INTERVAL_SECS).

Each cycle stores:

Redis keyContents
guest-agent:vm-poll:{ns}:{name}Per-VM sample: method latency, transport attempts, probe ladder
guest-agent:poll-fleetFleet rollup: scanned/polled/skipped, avg latency, error list, samples

API:

MethodPathPurpose
POST/kubevirt/guest/poll-reconcileRun one reconcile now
GET/kubevirt/guest/poll-telemetryFleet rollup
GET/kubevirt/vms/{ns}/{name}/guest/poll-telemetryLatest VM poll sample

GET .../guest/status includes lastPoll + telemetryMode (pull_via_virt_launcher / push / none).

UI label: Telemetry mode: Pull via virt-launcher.

Security​

GuestActionPolicy CRD extensions:

  • execAllowlist, fileReadAllowlist, fileWriteAllowlist
  • freezeAllowed, maxExecOutputBytes
  • JIT approval for exec, file write, install-agent

Audit events include transport and networkRequired.