ServiceMonitor Capability Detection in virt-operator#
virt-operator probes for the Prometheus ServiceMonitor CRD at startup to decide whether to enable ServiceMonitor reconciliation. This is a general capability-probing pattern in KubeVirt: the operator checks for optional third-party CRDs (ServiceMonitor, PrometheusRule, ValidatingAdmissionPolicy, OpenShift SCC/Route) and activates the corresponding reconciliation paths only when those APIs are present. This avoids hard-coupling KubeVirt to optional ecosystem components.
Startup Detection: IsServiceMonitorEnabled#
During Execute() in application.go, the operator calls util.IsServiceMonitorEnabled before constructing informers. This function uses the Kubernetes discovery client (DiscoveryClient().ServerGroupsAndResources()) to fetch all registered API groups and resources, then searches for the servicemonitors resource under the monitoring.coreos.com group (the Prometheus Operator schema group). It returns true if found, false if absent, and propagates any non-group-discovery error as fatal .
The result drives two decisions :
app.config.ServiceMonitorEnabled = trueβ signals downstream reconcilers that the API exists.- Informer selection β if enabled,
app.informers.ServiceMonitoris set to a realSharedIndexInformerviaOperatorServiceMonitor(), which watchesmonitoring.coreos.com/v1ServiceMonitor objects via the Prometheus REST client filtered by the operator label. If disabled, it falls back to a no-op dummy informer viaDummyOperatorServiceMonitor(), which is backed by a fake in-memory store.
The same Informers struct field is used by the controller whether the API is present or not β the dummy/real swap is the only branching point .
Runtime Change Detection: configModificationCallback and HasServiceMonitorAPI#
The startup check is static (point-in-time). KubeVirt also handles the case where the ServiceMonitor CRD is added or removed after startup via configModificationCallback, registered as a ClusterConfig callback .
This callback calls clusterConfig.HasServiceMonitorAPI(), which re-checks the CRD store (in-memory, kept current by the CRD informer) under a mutex lock. The helper isServiceMonitor matches on Kind == "ServiceMonitor" and Group == "monitoring.coreos.com", and also excludes CRDs pending deletion (DeletionTimestamp != nil).
If the detected state diverges from app.config.ServiceMonitorEnabled, the operator signals reInitChan to trigger a full restart/re-initialization of the operator . There is no live hot-swap β a re-init is required to rebuild informers correctly.
The Two Detection Mechanisms Compared#
Startup (IsServiceMonitorEnabled) | Runtime (HasServiceMonitorAPI) | |
|---|---|---|
| Trigger | Once, at Execute() | Every ClusterConfig modification callback |
| Data source | Kubernetes API discovery (ServerGroupsAndResources) | CRD informer cache (in-memory) |
| Location | pkg/virt-operator/util/client.go | pkg/virt-config/configuration.go |
| On change | N/A (one-shot) | Sends to reInitChan β operator restarts |
Key Files#
| File | Role |
|---|---|
pkg/virt-operator/application.go | Startup detection, informer wiring, re-init callback |
pkg/virt-operator/util/client.go | IsServiceMonitorEnabled β discovery-based probe |
pkg/virt-config/configuration.go | HasServiceMonitorAPI β CRD-cache-based probe |
pkg/controller/virtinformers.go | OperatorServiceMonitor / DummyOperatorServiceMonitor informer factories |
The PrometheusRule CRD follows an identical pattern (see lines 283β294 and 499β507 in application.go), making this a reusable template for any optional CRD capability check in virt-operator.