Target Controller Documentation¶
Overview¶
The Target controller is the central orchestrator of the SolAr rendering pipeline. It manages the lifecycle of Target custom resources and drives the two-stage rendering pipeline that produces deployable Helm charts for each target cluster.
For each Target, the controller:
- Resolves the render
Registryreferenced byspec.renderRegistryRef. - Builds a pull-secret lookup by listing all
RegistryBindingresources for the Target, resolving each bound Registry, and mappinghostnametotargetPullSecretName. See ADR 010. - Collects all
ReleaseBindingresources that reference the Target. - Runs the release resolver to deduplicate releases by
uniqueName(highest priority wins) and enforce anti-affinity rules. Sets theReleasesResolvedcondition. - Creates a per-release
RenderTaskfor each accepted Release (Stage 1). Each resource'sPullSecretNameis populated from the pull-secret lookup by matching the resource's repository host. - Once all release RenderTasks succeed, creates a bootstrap
RenderTaskthat bundles all rendered release charts (Stage 2). Bootstrap releases use the render registry'stargetPullSecretName. - Manages cleanup of stale RenderTasks when the release set changes.
See Rendering Pipeline for a detailed description of the two-stage pipeline. See ADR 004 for the motivation and design of the release resolver.
Architecture¶
flowchart TD
subgraph Inputs
RB[ReleaseBindings]
RegB[RegistryBindings]
Reg[Registry]
Rel[Releases]
end
subgraph Target Controller
Ctrl[TargetReconciler]
Resolver[Release Resolver]
end
subgraph Outputs
RT1["RenderTask\n(per release)"]
RT2["RenderTask\n(bootstrap)"]
end
RB -->|triggers| Ctrl
RegB -->|triggers| Ctrl
Reg -->|triggers| Ctrl
Rel -->|triggers| Ctrl
RT1 -->|status change triggers| Ctrl
RT2 -->|status change triggers| Ctrl
Ctrl -->|collected bindings| Resolver
Resolver -->|accepted releases| Ctrl
Ctrl -->|creates/tracks| RT1
Ctrl -->|creates/tracks| RT2
Status Conditions¶
stateDiagram-v2
[*] --> RegistryUnresolved: Target created
RegistryUnresolved --> RegistryResolved: Registry found with SolarSecretRef
RegistryResolved --> ReleasesResolved: Release resolver runs
ReleasesResolved --> ReleasesRendering: ReleaseBindings exist and accepted
ReleasesRendering --> ReleasesRendered: All release RenderTasks succeeded
ReleasesRendered --> BootstrapRendering: Bootstrap RenderTask created
BootstrapRendering --> BootstrapReady: Bootstrap RenderTask succeeded
BootstrapRendering --> BootstrapFailed: Bootstrap RenderTask failed
ReleasesRendering --> ReleasesFailed: Any release RenderTask failed
| Condition | Status | Reason | Description |
|---|---|---|---|
RegistryResolved |
True |
Resolved |
Registry found and has solarSecretRef |
RegistryResolved |
False |
NotFound |
Registry resource not found |
RegistryResolved |
False |
MissingSolarSecretRef |
Registry exists but lacks push credentials |
ReleasesResolved |
True |
NoConflicts |
All bound releases accepted; no deduplication or anti-affinity needed |
ReleasesResolved |
True |
Resolved |
Some releases were filtered; message lists filtered bindings |
ReleasesResolved |
False |
NoReleaseBindings |
No ReleaseBindings found for this Target |
ReleasesRendered |
True |
AllRendered |
All release RenderTasks completed successfully |
ReleasesRendered |
False |
NoReleaseBindings |
No ReleaseBindings found for this Target |
ReleasesRendered |
False |
AllReleaseBindingsFiltered |
All ReleaseBindings were filtered by the resolver |
ReleasesRendered |
False |
Pending |
Waiting for release RenderTasks to complete |
ReleasesRendered |
False |
MissingDependencies |
One or more Releases or ComponentVersions not found |
ReleasesRendered |
False |
ReleaseFailed |
At least one release RenderTask failed |
BootstrapReady |
True |
Ready |
Bootstrap RenderTask succeeded; ChartURL populated |
BootstrapReady |
False |
Failed |
Bootstrap RenderTask failed |
Finalizers¶
The Target controller manages two finalizers:
| Finalizer | On resource | Purpose |
|---|---|---|
solar.opendefense.cloud/target-finalizer |
Target | Allows the controller to observe deletion and run cleanup logic before the object is garbage-collected |
solar.opendefense.cloud/registry-ref |
Registry | Prevents deletion of the referenced Registry while any Target or RegistryBinding references it |
On deletion, the controller:
- Checks whether any other active Target or RegistryBinding still references the same Registry.
- If none remain, removes
solar.opendefense.cloud/registry-reffrom the Registry. - Deletes all RenderTasks owned by the Target.
- Removes
solar.opendefense.cloud/target-finalizerfrom the Target, allowing it to be garbage-collected.
Note: solar.opendefense.cloud/registry-ref is a shared finalizer managed by both the Target controller and the RegistryBinding controller. The reference count check always considers both before removing it.
RenderTask Naming¶
| RenderTask type | Name pattern |
|---|---|
| Release | render-rel-<release-name>-<hash> |
| Bootstrap | render-tgt-<target-name>-<version> |
Bootstrap Versioning¶
The bootstrap chart version is incremented whenever the set of bound releases or their resolved content changes, ensuring a new chart is pushed whenever the desired state changes. Stale RenderTasks from prior versions are cleaned up after the current bootstrap succeeds.
Pull Secret Resolution¶
The controller resolves pull credentials for each resource's OCI repository at render time. This replaces the previously hardcoded regcred secret name (#165).
Algorithm¶
- List all
RegistryBindingobjects whosespec.targetRefreferences the current Target. - For each RegistryBinding, resolve the referenced
Registryand recordhostname→targetPullSecretName. - For each source resource in the
ComponentVersion, extract the registry host from the repository URL and look up the pull secret name. - Populate
ResolvedResourceAccess.PullSecretNamewith the matched value (or empty for anonymous pull).
Strict vs Relaxed Mode¶
The controller supports two modes via the --registry-binding-strict flag:
| Mode | Flag value | Behavior on unmatched host |
|---|---|---|
| Relaxed (default) | false |
PullSecretName is left empty; rendered OCIRepository omits secretRef (anonymous pull) |
| Strict | true |
Rendering fails with an error identifying the unmatched host and resource |
The Helm chart exposes this as controller.args.registryBindingStrict.
Watch Triggers¶
| Watched Resource | Mapping |
|---|---|
Target |
Direct reconcile of the Target |
ReleaseBinding |
Reconcile the Target referenced by the binding (resolves spec.targetNamespace for cross-namespace bindings) |
RegistryBinding |
Reconcile the Target referenced by the binding |
RenderTask |
Reconcile the owning Target (status change only) |
Registry |
Reconcile all Targets that reference the Registry |
Release |
Reconcile all Targets bound to the Release |
ReferenceGrant |
Reconcile Targets affected by grant changes: grants covering Target → Registry, Release → ComponentVersion, or ReleaseBinding → Target patterns |
Cross-namespace ReleaseBinding resources — those created by the Profile controller in the provider namespace with spec.targetNamespace set — are collected during reconcile by checking ReferenceGrant resources in the Target's namespace. See ReferenceGrants for the full authorization model.
Sequence Diagrams¶
New Release added via Profile (triggers bootstrap re-render)¶
sequenceDiagram
participant User as Deployment Coordinator
participant K8s as Kubernetes API
participant ProfileCtrl as Profile Controller
participant TargetCtrl as Target Controller
participant RenderTaskCtrl as RenderTask Controller
participant Registry as OCI Registry
User->>K8s: Create Profile (targetSelector, releaseRef)
K8s->>ProfileCtrl: Reconcile(Profile)
ProfileCtrl->>K8s: Create ReleaseBinding (Target ← Release)
K8s->>TargetCtrl: Reconcile(Target) [new ReleaseBinding]
TargetCtrl->>TargetCtrl: Run release resolver (dedup + anti-affinity)
TargetCtrl->>K8s: Create release RenderTask
K8s->>RenderTaskCtrl: Reconcile(RenderTask)
RenderTaskCtrl->>Registry: Push release chart
RenderTaskCtrl->>K8s: Update RenderTask status (succeeded)
K8s->>TargetCtrl: Reconcile(Target) [RenderTask status changed]
TargetCtrl->>K8s: Update status (ReleasesRendered=True)
Note over TargetCtrl: Bootstrap input changed → create new bootstrap RenderTask,<br/>delete stale one from prior version
TargetCtrl->>K8s: Create bootstrap RenderTask
K8s->>RenderTaskCtrl: Reconcile(RenderTask)
RenderTaskCtrl->>Registry: Push bootstrap chart
RenderTaskCtrl->>K8s: Update RenderTask status (succeeded)
K8s->>TargetCtrl: Reconcile(Target) [RenderTask status changed]
TargetCtrl->>K8s: Update status (BootstrapReady=True)
Target deletion¶
sequenceDiagram
participant User as Cluster Maintainer
participant K8s as Kubernetes API
participant TargetCtrl as Target Controller
User->>K8s: Delete Target
K8s->>TargetCtrl: Reconcile(Target) [DeletionTimestamp set]
TargetCtrl->>K8s: List active Targets + RegistryBindings referencing Registry
alt no other active referencers
TargetCtrl->>K8s: Remove registry-ref from Registry
end
TargetCtrl->>K8s: List owned RenderTasks
TargetCtrl->>K8s: Delete all owned RenderTasks
TargetCtrl->>K8s: Remove target-finalizer
Note over K8s: Target is garbage-collected
Relationship to Other Controllers¶
flowchart LR
ProfileCtrl[Profile Controller] -->|creates| ReleaseBinding
ReleaseBinding -->|triggers| TargetCtrl[Target Controller]
TargetCtrl -->|creates| RenderTask
RenderTask -->|managed by| RenderTaskCtrl[RenderTask Controller]
RenderTaskCtrl -->|status update triggers| TargetCtrl