Live fleet inventory (experimental)
GET /api/v1/enterprise/fleet and Ops → Fleet (/app/fleet) collect live
Kubernetes nodes and KubeVirt VirtualMachines. Reads require cluster.admin,
including scoped API tokens. The console is restricted to administrators.
This is an inventory feature; there are no remote power, migration, enrollment,
or failover APIs.
Enable and enroll
Set both ZORVIA_EXPERIMENTAL=1 and ZORVIA_FEATURE_FLEET=1. With no registry,
the fleet contains local, using Zorvia's existing client and configured VM
namespace. Nodes are cluster-wide. The local client's existing RBAC is unchanged;
a namespace-only deployment may show nodes as unknown.
For remote clusters, mount an administrator-managed JSON registry and set
ZORVIA_FLEET_CONFIG=/etc/zorvia/fleet/registry.json:
[
{
"name": "east",
"kubeconfig": "/etc/zorvia/fleet/east.yaml",
"context": "east-readonly",
"namespaces": ["workloads", "staging"],
"environment": "production",
"region": "east"
}
]
Names must be unique DNS labels (local is reserved). Each enrollment requires
an absolute kubeconfig path, explicit context, and 1–32 unique namespaces.
At most 16 remote clusters are allowed. Each registry/kubeconfig is limited to
1 MiB. Registry errors prevent startup when fleet is enabled; a broken remote
kubeconfig affects only that cluster. Restart after registry changes.
Enroll each physical cluster once: identity is administrator assigned; two
contexts pointing at the same API server would double-count that inventory.
Mount kubeconfigs as read-only Kubernetes Secrets, separately from the
registry ConfigMap. They need HTTPS, verified TLS, and embedded credentials
(token or client-certificate-data/client-key-data) and, for private CAs,
certificate-authority-data. Exec credential plugins, auth providers, credential
file references, CA file references, insecure TLS, proxy overrides, and URLs
containing credentials/query/fragment are rejected. All entries in a kubeconfig
are checked; prefer a dedicated single-context kubeconfig. Never commit real
credentials or return kubeconfigs through HTTP. Remote kubeconfigs are reread
on every uncached refresh, allowing mounted Secret rotation. Static embedded
tokens must be rotated by the operator; this feature does not mint tokens.
The registry is trusted server configuration and deliberately supports private Kubernetes API endpoints. It cannot be changed by browser requests. Restrict network egress and file permissions according to your deployment.
Minimal remote permissions
Use a dedicated identity. Bind this ClusterRole only to that identity:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: zorvia-fleet-nodes-reader
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["list"]
For each enrolled namespace, bind this Role to the same identity:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: zorvia-fleet-vms-reader
namespace: workloads
rules:
- apiGroups: ["kubevirt.io"]
resources: ["virtualmachines"]
verbs: ["list"]
Create the corresponding ClusterRoleBinding and namespace RoleBindings with your own ServiceAccount/user subject. No Secret, pod, VM mutation, or bootstrap permissions are needed. The collector issues only LIST requests (HTTP GET).
Results and limits
- All enrolled targets are probed concurrently (at most 17); each complete connection/inventory attempt has a 10-second deadline. No retries happen inside a probe. Concurrent HTTP requests share a refresh and a 15-second cache. Each server replica has its own cache. The console polls every 30 seconds while visible and labels responses older than 60 seconds as stale.
- Node and VM lists are paginated in pages of 500, with at most 5,000 nodes and 5,000 VMs per cluster and 32 pages per list. A failed page, repeated token, expired list token, or exceeded limit discards that component's partial results. VM namespaces are explicit; one namespace failure makes that cluster's entire VM inventory unknown, rather than reporting a misleading subset as complete.
- Unknown counts/readiness are
null; a successfully observed empty VM list is0. Components can succeed independently. A deadline makes the entire cluster unknown. Kubernetes/transport/configuration error details are redacted. API unavailability does not prove the cluster is down. totals.observed_vmsandobserved_nodessum successful components only.totals.partialandcomplete_clustersdescribe inventory completeness. Treat partial totals as observed counts, never authoritative fleet totals.healthymeans both inventory queries succeeded, at least one node exists, and all observed nodes haveReady=True;degradedmeans complete inventory with zero nodes or at least one node not Ready.unknownmeans an incomplete probe. This is not guest/application health or resource usage. VM readiness comes directly fromstatus.ready; stopped VMs may legitimately be not Ready.- The response exposes VM name, enrolled namespace, printable status and readiness, not VM specs, credentials, endpoint URLs, or raw node details. Searches retain cluster identity, and the console does not route remote VM names into local lifecycle actions. Results are observations, not a transactional snapshot spanning clusters or Kubernetes resource kinds.
Validation before production
Unit/API tests exercise real Kubernetes client requests against mock servers, pagination, permissions, partial failures, redaction, cache coalescing, and configuration guards. Real multi-cluster connectivity, certificate/token rotation, remote least-privilege RBAC, and cluster outages still require a live-cluster trial. The feature remains Experimental.