Discover Component Graphs
Goal
Use a Discovery resource to resolve the transitive component graph of a
Component, filter it with selectors, and publish either the filtered raw
descriptors or projected free-form records into the Discovery status.
You’ll end up with
- A
Discoveryresource that watches aComponentand publishes a filtered view of its reference graph instatus.componentsorstatus.extracted.
Estimated time: ~10 minutes
Prerequisites
- Controller environment set up
- A
ReadyComponent in the same namespace whose component version references other components
How it works
A Discovery references a Component in the same namespace. Once that
Component is Ready, the controller resolves the entire reachable graph
from its resolved repository, applies the reference, component, and resource
selectors, and publishes filtered raw v2 descriptors in status.components —
or, when spec.extract is set, CEL-projected records in status.extracted.
Traversal is full and fail-fast: the first resolution failure retains the last
successful payload and sets Ready=False. For selector clauses, extraction
modes, status and scheduling semantics, see
Component Discovery.
Steps
Publish the filtered descriptors
Create a
Discoverythat keeps every component in the graph carrying a matching label. Withoutspec.extract, the filtered raw v2 descriptors are published instatus.components.cat <<EOF > discovery.yaml apiVersion: delivery.ocm.software/v1alpha1 kind: Discovery metadata: name: platform-components namespace: default spec: componentRef: name: releasechannel componentSelector: matchLabels: tier: platform EOFkubectl apply -f discovery.yamlConfirm the Discovery is ready
kubectl get discovery platform-components -o wideCheck that the graph was resolved and the observed generation matches:
kubectl get discovery platform-components -o jsonpath='{.status.conditions[?(@.type=="Ready")].status} {.status.observedGeneration} {.metadata.generation}{"\n"}'Both must hold before you consume the payload: a failed Discovery retains its last successful result, so
Ready=Truealone does not mean the payload is current.Project the graph into records
To publish free-form records instead of raw descriptors, add
spec.extract. Each extraction mode returns a list of objects. Set exactly one ofbyResources,byComponents, orexpression.cat <<EOF > discovery.yaml apiVersion: delivery.ocm.software/v1alpha1 kind: Discovery metadata: name: flux-images namespace: default spec: componentRef: name: releasechannel componentSelector: matchLabels: tier: platform resourceSelector: expression: identity.name in ["flux", "image-automation-controller"] extract: byResources: imageRef: resource.access.imageReference resourceName: resource.name componentName: component.name componentVersion: component.version EOFkubectl apply -f discovery.yamlThe projected records appear in
status.extracted:kubectl get discovery flux-images -o jsonpath='{.status.extracted}' | jq
Troubleshooting
Failures surface on the Ready condition, with the reason naming the stage that
failed:
kubectl get discovery platform-components -o jsonpath='{.status.conditions[?(@.type=="Ready")]}' | jqSymptom: Ready=False with reason ResolutionFailed
Cause: The component graph could not be fully resolved — a repository, auth
or network failure, or a referenced component version that does not exist. A
Ready Component only guarantees the root descriptor was fetched, not that
the whole graph is reachable.
Fix: Confirm every referenced component version exists in a reachable
repository and that credentials cover each host. This is retried with backoff
(up to five minutes between attempts), so fixing a Secret revives the object
without a spec change.
Symptom: Ready=False with reason SelectorFailed or ExtractFailed
Cause: A selector or extraction expression failed to compile or evaluate.
The most common case by far is calling size() on a field that serialized as
null rather than being omitted.
Fix: Guard optional reads, for example
component.componentReferences == null ? 0 : size(component.componentReferences).
These are terminal (Stalled=True) and are not requeued, so the object needs a
spec change to recover. See
Absent, null, and missing.
Symptom: Ready=False with reason PayloadTooLarge
Cause: The computed payload exceeds the 1MiB status limit.
Fix: Narrow the selectors, or switch to spec.extract and project only the
fields you need instead of publishing raw descriptors.
Symptom: nothing happens after applying the Discovery
Cause: The referenced Component is not Ready yet, or the object is
suspended. Discovery is watch-driven with no interval.
Fix: Check the Component and spec.suspend:
kubectl get component releasechannel -o wide
kubectl get discovery platform-components -o jsonpath='{.spec.suspend}{"\n"}'Next Steps
- Verify Component Versions in the Controller - Verify component version signatures on reconciliation
Related Documentation
- Concept: Component Discovery - Selectors, extraction, status semantics, and scheduling in detail
- Concept: Kubernetes Controllers - How Discovery fits alongside the reconciliation chain
- Reference: Discovery CRD - Full field reference for the Discovery resource
- How-To: Configure Credentials for OCM Controllers - Set up registry credentials for the controller