Skip to content

Troubleshooting

Most problems show up as a machine landing in FAILED (read last_error via Get) or a libvirt API error in the logs/metrics. Work from those two signals.

The provider won’t start

SymptomCauseFix
--image (golden base volume) is required for the libvirt backendReal backend with no base image.Pass --image (a qcow2 volume in --storage-pool).
no --connect host connections configured--libvirt-backend=libvirt (or --connect-implied auto) with no connections.Set --connect, or use --libvirt-backend=fake for dev.
connect zone … : …A host in --connect is unreachable / auth failed.Check the URI (use the qemu+libssh:// scheme for SSH, not qemu+ssh://, so keyfile/known_hosts params are honoured), the SSH key/known_hosts (or TLS client cert), and that libvirtd is listening.
both --tls-cert and --tls-key are required / --tls-ca set without --tls-cert/--tls-keyHalf-configured gRPC TLS.Provide cert and key (and a CA for mTLS), or none.
Comes up on the fake backend unexpectedly (log: “using the IN-MEMORY fake libvirt backend”)No --connect set, so auto resolved to fake.Set --connect to opt into the real backend.
offering instance_type … is not in the instance-type catalogAn offering names a type not in the catalog.Add it via --instance-types, or use a catalog name.
capacity_type "spot" is not meaningful for libvirtA spot capacity_type in offerings.Use on_demand or bare_metal — a local host has no preemption market.

A machine reaches FAILED

Get the machine and read last_error:

last_error mentionsCauseFix
create domain … : look up base image volumeThe --image volume isn’t in --storage-pool.Stage the golden image in the pool; check the name.
create domain … : create overlay volume / start domainStorage pool full, or the host can’t start the domain (no KVM, bad network).Check pool free space, --network exists, KVM is available on the host.
configure: … guest agent execThe guest agent isn’t running, or the bootstrap hook exited non-zero.Ensure the base image runs qemu-guest-agent and ships /opt/bigfleet/bootstrap; confirm the hook joins the cluster and exits 0.
drain: … guest agent execkubectl drain (via the guest agent) failed or timed out.Confirm kubectl is present in the image and the node name resolves; a strict PDB may exceed the grace period.
transition interrupted by a provider restartThe process was killed mid-transition.Expected after a kill without graceful drain; the shard re-drives on a fresh slot. Enable --state so fence marks/bindings survive.

A FAILED machine is terminal-pending-cleanup: the shard recovers on a different slot, never in place. Don’t re-issue mutations against it.

Placement / packing looks wrong

SymptomCauseFix
Pods won’t schedule on an instance type that should fitresources set to the hardware total, forcing density = 1.resources is the per-replica request (e.g. {cpu:"1"}); leave allocatable to the provider (derived from the instance-type catalog). See Configuration.
topology.kubernetes.io/zone selectors don’t matchZone (host) mismatch.The provider sets zone from the --connect host; confirm the offering’s zone matches a configured connection.
A domain lands on the wrong hostzone in the offering doesn’t match the intended --connect zone.Align the offering zone with the --connect zone=uri key.

Cost ranking looks off

SymptomCauseFix
All prices are 0--capacity-type bare_metal (owned hardware prices at 0).Expected for a bare-metal pool; use on_demand for synthetic pricing.
Prices look too high/lowSynthetic rates not tuned, or an unintended --prices override.Adjust --price-per-vcpu-hour / --price-per-gib-hour, or pin --prices.

Fencing alerts

A spike of FailedPrecondition on bigfleet_libvirt_grpc_requests_total{code="FailedPrecondition"} means a zombie shard (an old shard process) is being correctly rejected. This is the provider doing its job — investigate the shard side (a restart that didn’t take over cleanly), not the provider. FailedPrecondition is reserved for fencing; any other rejection uses a different code.

Useful commands

Terminal window
# What state is a machine in, and why?
grpcurl -plaintext -d '{"id":"<machine-id>"}' localhost:9000 \
bigfleet.v1alpha1.CapacityProvider/Get
# Inventory by state.
grpcurl -plaintext -d '{}' localhost:9000 \
bigfleet.v1alpha1.CapacityProvider/List
# Cross-check against libvirt on a host.
virsh -c qemu+ssh://bigfleet@host-a/system list --all
# Probes and metrics.
curl localhost:9090/healthz
curl localhost:9090/readyz
curl -s localhost:9090/metrics | grep bigfleet_libvirt_