Documentation
¶
Overview ¶
Package resourceapplier reconciles template-declared Kubernetes resources via Server-Side Apply (SSA).
It consumes resources from the authenticated render-cycle snapshot, applies them with Server-Side Apply, and prunes previously owned resources by exact UID and resourceVersion. Resource kinds remain template-defined.
Index ¶
Constants ¶
const ( // ComponentName is the unique identifier for this component. ComponentName = "resource-applier" // EventBufferSize is the size of the event subscription buffer. // High volume: reconciliation.completed fires on every reconcile. Use a // Publishing-tier buffer so churn bursts don't drop these (coalescible) // events before this applier drains them. EventBufferSize = busevents.PublishingSubscriberBuffer // LabelManagedBy is injected onto every applied resource so operators // can locate everything the controller owns with a single // `kubectl get … -l haproxy-haptic.org/managed-by=<name>` selector. LabelManagedBy = "haproxy-haptic.org/managed-by" // DefaultManagedByValue is the value injected into LabelManagedBy when // the chart doesn't override Config.ManagedByValue. Distinct deployments // in the same namespace should set their own values. DefaultManagedByValue = "haptic-controller" // AnnotationOwnership lets templates flag a rendered resource as // jointly owned with another field manager (helm / argocd / kubectl). // When set to OwnershipPartial, the applier: // - does NOT inject the managed-by label (the resource isn't // ours to claim end-to-end); // - does NOT track the resource for orphan-delete (vanishing from // the rendered set must release SSA-owned fields, never delete // the whole object — that would clobber the chart's static // spec); // - always strips the annotation from the payload before SSA so // it remains a controller-internal flag. // SSA's per-list-map-entry ownership (e.g. Service.spec.ports keyed // by (port, protocol)) handles the actual field-level merge with // the other field manager. AnnotationOwnership = "haproxy-haptic.org/ownership" // OwnershipPartial is the AnnotationOwnership value that activates // partial-ownership mode. Any other value (including absence) means // full ownership: existing behaviour, unchanged. OwnershipPartial = "partial" )
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Component ¶
Component reconciles template-declared resources to the cluster.
All-replica subscriber, leader-only applier — same shape as statusapplier.Component. State lives only on the active leader; replicas in standby just observe events.
func New ¶
New constructs an applier and subscribes to the events it needs. Subscription happens in the constructor so events buffered before EventBus.Start() are delivered after — the same all-replica pattern every haptic controller component follows.
func (*Component) CoalescesOn ¶
CoalescesOn opts this applier into component.Base's mailbox coalescing: under churn only the LATEST reconciliation.completed matters (it carries the latest rendered resources, superseding earlier ones), so runs of them collapse in the mailbox and the bus can never overflow this subscriber.
func (*Component) HandleEvent ¶
HandleEvent implements component.EventHandler: it fans out by event type, tracking processing time for the health check. Mirror of statusapplier's HandleEvent shape — different events because resource lifecycle is "rendered → deployed (= apply)" rather than the four-phase status patches use.
func (*Component) HealthCheck ¶
HealthCheck returns nil if the component is healthy.
type Config ¶
type Config struct {
EventBus *busevents.EventBus
DynamicClient dynamic.Interface
// DiscoveryClient is used on leader-acquire to enumerate every
// namespace-scoped API resource type the cluster supports, so the
// applier can rebuild its in-memory `lastAppliedKeys` from cluster
// state via the managed-by label selector. Without this, resources
// the controller applied before a crash but whose desired state was
// removed while the controller was down (e.g. the user deleted the
// parent resource during a controller upgrade) would leak as orphans
// until manually swept. Optional: when nil, startup-orphan recovery is
// skipped and operators must rely on the
// `kubectl get … -l haproxy-haptic.org/managed-by=<name>` mitigation.
DiscoveryClient discovery.DiscoveryInterface
GVRResolver GVRResolver
// ReapplyInterval skips the SSA pass for a cycle whose rendered resources
// are byte-identical to the last successfully applied cycle, for at most
// this long. The expiry re-apply is the periodic authoritative live-state
// verification (wire the drift-prevention interval); zero keeps the
// verify-every-cycle behavior.
ReapplyInterval time.Duration
Logger *slog.Logger
// OwnNamespace is the namespace the controller pod runs in. Required
// when RestrictToOwnNamespace is true.
OwnNamespace string
// RestrictToOwnNamespace refuses cluster-scoped and foreign-namespace resources when enabled.
RestrictToOwnNamespace bool
// ManagedByValue is the label value injected as
// `haproxy-haptic.org/managed-by`. Defaults to the controller name
// ("haptic-controller") so multiple haptic deployments in the same
// cluster don't clobber each other's managed sets.
ManagedByValue string
// OwnerRef identifies the HAProxyTemplateConfig CR that owns the
// applied resources. The applier injects an `ownerReferences`
// entry pointing at this object on every full-ownership SSA
// payload, with `controller: true` and `blockOwnerDeletion: true`
// so Kubernetes garbage collection cascade-deletes the rendered
// resources when the CR is removed (e.g. `helm uninstall`).
//
// Optional: when zero (UID empty), no OwnerReference is injected.
// Partial-ownership entries never get an OwnerReference regardless
// (the chart-static or other field manager already owns the
// resource end-to-end).
OwnerRef OwnerReference
}
Config bundles the dependencies a New caller must provide.
type GVRResolver ¶
type GVRResolver = statusapplier.GVRResolver
GVRResolver resolves apiVersion + kind to a GroupVersionResource. Reused from the statusapplier package to avoid duplicate logic.