Documentation
¶
Overview ¶
pkg/reconciler/conditions.go
pkg/reconciler/cross_util.go
pkg/reconciler/generic.go
pkg/reconciler/generic_autoscale.go
AutoscaleTarget implementation for GenericReconciler.
GenericReconciler implements the three AutoscaleTarget methods so it can be passed directly to NewAutoscaler. The autoscaler calls these methods; user code should not call them directly.
ResizeWorkers — fully wired via ResizableSemaphore. SetQueueDepthLimit — enforced atomically in Workqueue.Enqueue. SetResyncInterval — drives an independent resync goroutine that re-enqueues
all cached objects at the declared interval. 0 = idle (informer handles baseline resync). The goroutine is started once by startCRDWorkers via the ResyncLoopStarter interface; SetResyncInterval adjusts its rate at runtime.
pkg/reconciler/generic_namespace.go
Namespace guard wiring for GenericReconciler.
RestrictedNamespaces and AllowedNamespaces live on orktypes.CRDEntry directly — not on OperatorBoxConfig. GenericReconciler stores the full CRDEntry as r.crd, so the guard reads r.crd.RestrictedNamespaces and r.crd.AllowedNamespaces directly.
namespaceGuardFunc is called once per runResourceGroup invocation and returns a closure. run_*.go files call it after resolving the target namespace and before condition evaluation.
Fast path: returns nil when CRD has no restrictions — all run_*.go guard with "if guard != nil" so nil means zero allocation, zero check.
pkg/reconciler/generic_registry.go
KatalogRegistry — the interface GenericReconciler needs from the Kordinator registry to perform zero-API-call cross-CRD observation.
Why a local interface instead of importing pkg/kordinator directly:
pkg/reconciler → pkg/kordinator would create an import cycle. pkg/kordinator already imports pkg/reconciler (for domain.Reconciler). A local interface breaks the cycle — Go's implicit interface satisfaction means *kordinator.ResourceKatalog satisfies this automatically.
pkg/reconciler/kube_reader_adapter.go
KubeReader adapter — bridges kubeclient.Kubeclient to the orktypes.KubeReader interface used by provider libraries.
Providers receive KubeReader not kubeclient.KubeClient because:
- The interface is narrow: GetSecret and GetConfigMap only — no write access
- Providers must not write Kubernetes resources (Orkestra owns cluster state)
- A narrow interface is easier to mock in provider tests
- The kubeclient package is internal; providers should not depend on it
pkg/reconciler/normalize.go
applyNormalize — canonical spec transformation.
Called as the first step of reconcileImpl, before mutation and validation. Returns a deep copy of the CR with normalize.spec fields replaced by their rendered values. The informer cache object is never modified.
Pipeline position:
informer cache → DeepCopy → applyNormalize → mutation → validation → runTemplateReconcile
After applyNormalize, every downstream step sees the normalized spec. The raw CR in etcd is unchanged — normalize is purely an in-memory operation.
Example — CronJob accepting both string and map schedule:
normalize:
spec:
schedule: >
{{ if eq (typeOf .spec.schedule) "map" }}
{{ cronExpr .spec.schedule.minute .spec.schedule.hour .spec.schedule.dayOfMonth .spec.schedule.month .spec.schedule.dayOfWeek }}
{{ else }}
{{ .spec.schedule }}
{{ end }}
After normalize, .spec.schedule is always a cron string. onReconcile templates use {{ .spec.schedule }} directly — no branching needed.
pkg/reconciler/ptr_hooks.go
── Design note: pointer type parameter and the ObjectHooks adapter ───────────
WHY PTR, NOT T ────────────── GenericReconciler uses the type parameter name PTR rather than the conventional T to make the pointer expectation visible at every call site. Kubernetes informers store and return pointer values: when you create an informer for Database objects for example, every item retrieved from its cache is a *Database. The reconciler type-asserts the raw interface{} value from the cache with raw.(PTR), which succeeds only when PTR is a pointer type.
Users therefore write:
domain.ReconcileHooks[*Database]{OnReconcile: myFunc}
not:
domain.ReconcileHooks[Database]{OnReconcile: myFunc} // wrong
This matches the pattern used throughout the Kubernetes ecosystem: controller-runtime, kubebuilder, and all typed client-go code work with pointer receivers and pointer type arguments for the same reason.
THE MISMATCH PROBLEM ──────────────────── Go generics are invariant: ReconcileHooks[*Database] and ReconcileHooks[domain.Object] are unrelated types even though *Database implements domain.Object. A direct type assertion:
anyHooks.(domain.ReconcileHooks[PTR])
fails at runtime whenever the caller provides ReconcileHooks[*Database] but PTR is inferred as domain.Object — which is exactly what happens in the runtime registry path inside runtime_konstructor.go, where the concrete type is not known at compile time.
WHY NOT TWO TYPE PARAMETERS ─────────────────────────── The constraint PTR interface{ *S; domain.Object } (with a second parameter S any) enforces at compile time that PTR is a pointer to a concrete struct. However, it cannot be satisfied by domain.Object (an interface), so the runtime registry path in runtime_konstructor.go — which infers PTR = domain.Object — would fail to compile. Updating runtime_konstructor.go to supply concrete types would require the registry to carry a separate typed factory per CRD, a much larger change with no benefit for the dynamic template path where no hooks exist.
THE OBJECTHOOKS ADAPTER ─────────────────────── Instead of storing domain.ReconcileHooks[PTR] on the reconciler, we store domain.ObjectHooks — a plain struct whose function fields are parameterised on domain.Object. The adapter is built once in NewGenericReconciler via the domain.HookBinder interface:
binder, ok := anyHooks.(domain.HookBinder) hooks = binder.BindToObjectHooks()
Every domain.ReconcileHooks[T] value satisfies HookBinder automatically through its BindToObjectHooks() method. That method wraps each hook in a closure that performs obj.(T) before delegating to the typed function:
oh.OnReconcile = func(ctx context.Context, obj domain.Object) error {
return fn(ctx, obj.(T)) // T = *Database at runtime
}
The assertion is safe because:
- The informer is always constructed for a single concrete type.
- Every item returned from its cache IS that type, even when retrieved as domain.Object (or interface{}).
- GenericReconciler already asserts raw.(PTR) earlier in reconcileCore, so obj arriving at the hook is guaranteed to be of the right type.
END-TO-END CALL PATH FOR TYPED HOOKS ──────────────────────────────────────
User writes: func DatabaseHooks() domain.AnyReconcileHooks { return domain.ReconcileHooks[*Database]{OnReconcile: onReconcile} }
Generated registry registers DatabaseHooks in HookRegistry.
runtime_konstructor.go calls HookFactory() → gets ReconcileHooks[*Database].
NewGenericReconciler receives it as domain.AnyReconcileHooks. PTR is inferred as domain.Object (from func() domain.Object newObj).
anyHooks.(domain.HookBinder) succeeds because ReconcileHooks[*Database] has BindToObjectHooks() via the generic method.
BindToObjectHooks() builds ObjectHooks with closures: obj.(*Database).
At reconcile time, reconcileCore does raw.(*Database or domain.Object) — whichever PTR resolves to — producing a domain.Object value whose underlying type is *Database.
r.hooks.OnReconcile(ctx, obj) invokes the closure from step 6. obj.(*Database) succeeds. The user's typed function receives *Database. ✓
CUSTOM HOOK WRAPPERS ──────────────────── If you wrap ReconcileHooks[T] in your own struct (e.g. to add middleware), implement domain.HookBinder by forwarding to the inner hooks:
type LoggingHooks[T domain.Object] struct {
Inner domain.ReconcileHooks[T]
}
func (h LoggingHooks[T]) isHooks() {}
func (h LoggingHooks[T]) BindToObjectHooks() domain.ObjectHooks {
oh := h.Inner.BindToObjectHooks()
inner := oh.OnReconcile
oh.OnReconcile = func(ctx context.Context, obj domain.Object) error {
log.Info("reconciling", "name", obj.GetName())
return inner(ctx, obj)
}
return oh
}
pkg/reconciler/rollback.go
Rollback implementation for GenericReconciler.
Three responsibilities:
snapshotSpec — writes the current spec to the previous-spec annotation before any spec change is applied. Called when generation changes.
shouldRollback — reads the operatorbox health state and evaluates the rollback trigger. Returns true when rollback should activate.
runRollback — applies the onRollback resource group using the previous spec hydrated into the resolver as .previous.*.
The rollback phase state lives in status.phase. The reconciler checks it at the top of reconcileImpl and blocks normal reconciliation while active. The only exit from rollback is a spec generation change.
pkg/reconciler/run_cross.go
Cross-CRD HTTP fallback — fetches a CR detail from another Orkestra instance.
The primary path (informer cache, zero API calls) lives in run_template_reconcile.go in ReadCrossFromDeclarations. That function calls fetchCrossViaHTTP when the informer is unavailable (cross-binary, cross-cluster).
The full informer-cache path requires threading the Kordinator registry into GenericReconciler. ReadCrossFromInformer is called instead of fetchCrossViaHTTP for same-binary CRDs.
pkg/reconciler/run_delete_ordered.go
Sequential deletion with completion gates.
When onDelete.ordered: true the reconciler deletes resources in stages rather than relying on garbage collection. Each stage is a HookTemplates block. After submitting all deletes in a stage the reconciler polls the API server until every resource is confirmed gone, then advances to the next stage.
Deletion order within a stage is undefined; order is enforced between stages.
pkg/reconciler/run_docker.go
Docker build/push dispatch — runs before resource groups in runTemplateReconcile.
The Docker hook performs a minimal docker build and optional push of the declared image. Results are injected into the resolver context via resolver.WithDocker() so subsequent template expressions and when: conditions can reference them.
Call sequence in runTemplateReconcile:
- resolver = NewResolver(ctx, obj)
- resolver = resolver.WithCross(ReadCross(...)) ← cross-CRD first
- resolver, err = runGit(ctx, ...) ← Git second
- resolver, err = runExternal(ctx, ...) ← HTTP third
- resolver, err = runDocker(ctx, ...) ← Docker fourth
- runDeployments, runServices, ... etc.
Results in template context:
.docker.image → built image reference .docker.buildSucceeded → "true" or "false" .docker.error → error message (if any) .docker.called → "true" if hook executed
When: conditions can gate on these:
when:
- field: docker.buildSucceeded
equals: "true"
pkg/reconciler/run_docker_helper.go
pkg/reconciler/run_external.go
External HTTP call dispatch — runs before resource groups in runTemplateReconcile.
Calls are executed sequentially in declaration order. Results are injected into the resolver context via resolver.WithExternal() so subsequent template expressions and when: conditions can reference them.
Call sequence in runTemplateReconcile:
- resolver = NewResolver(ctx, obj)
- resolver = resolver.WithCross(ReadCross(...)) ← cross-CRD first
- resolver, err = runExternal(ctx, resolver, ...) ← HTTP calls second
- runDeployments, runServices, ... etc. ← resources use results
Results in template context:
.external.<name>.status → HTTP status code ("200", "404", "503")
.external.<name>.body → response body (first 4096 bytes)
.external.<name>.error → error message on failure
.external.<name>.called → "true" if the call was made
When: conditions on deployments can gate on these:
when:
- field: external.health-check.status
equals: "200"
pkg/reconciler/run_git.go
Git hook dispatch — runs before external calls and resource groups in runTemplateReconcile.
The Git hook performs a minimal clone/fetch of the declared repository, computes the current commit hash, detects whether the commit changed since the previous reconcile, and injects results into the resolver context via resolver.WithGit().
Call sequence in runTemplateReconcile:
- resolver = NewResolver(ctx, obj)
- resolver = resolver.WithCross(ReadCross(...)) ← cross-CRD first
- resolver, err = runGit(ctx, gvk, resolver, ...) ← Git second
- resolver, err = runExternal(ctx, ...) ← HTTP third
- resolver, err = runDocker(ctx, ...) ← Docker fourth
- runDeployments, runServices, ... etc.
Results in template context:
.git.commit → HEAD commit hash .git.changed → "true" if commit changed since last reconcile .git.path → working directory path .git.error → error message if operation failed .git.called → "true" if Git hook executed .git.succeeded → "true" if Git operation succeeded
When: conditions can gate on these:
when:
- field: git.changed
equals: "true"
Change detection is annotation-based — the last-seen commit is stored in:
orkestra.orkspace.io/last-commit
This annotation survives pod restarts, preventing spurious rebuilds.
pkg/reconciler/run_mutation.go
pkg/reconciler/run_namespace_guard.go
pkg/reconciler/run_providers.go
Provider dispatch — the engine that connects Katalog declarations to registered provider libraries.
This file is called from runTemplateReconcile after all Kubernetes resource groups (deployments, services, jobs, etc.) have been reconciled. It:
- Skips immediately if no provider blocks are declared or no providers registered
- Resolves template expressions in every declaration field
- Evaluates when: conditions — drops declarations that do not pass
- Calls provider.Reconcile(ctx, req) for each active block
On CR deletion (finalizer path), runProviderDelete is called instead. It calls provider.Delete for all declarations — no condition filtering.
Integration in runTemplateReconcile (after all Kubernetes resource groups):
if err := runProviders(ctx, obj, resolver, rc.ProviderBlocks, providerRegistry, kubeReader); err != nil {
return fmt.Errorf("providers: %w", err)
}
Integration in the finalizer handler:
if err := runProviderDelete(ctx, obj, resolver, rc.ProviderBlocks, providerRegistry, kubeReader); err != nil {
return fmt.Errorf("provider cleanup: %w", err)
}
pkg/reconciler/run_status.go
Status management — three layers:
Layer 1 — Automatic Ready condition.
Written after every reconcile regardless of Katalog declarations. reason: ReconcileSucceeded on success, ReconcileError on failure. No Katalog declaration required. Requires subresources.status in the CRD.
Layer 2 — Declarative status fields.
Written from status.fields declarations in the Katalog. Template expressions resolved against the live CR object map. Optional when: conditions gate individual field writes — this is what makes declarative state machines possible. Written only on successful reconcile.
Layer 3 — Child resource propagation.
Children are read after runTemplateReconcile and injected into the
resolver context via WithChildren. The returned resolver is used for
all subsequent status resolution.
Status field expressions reference children as:
{{ .children.deployment.status.readyReplicas }}
{{ .children.cronjob.status.lastScheduleTime }}
Children are keyed by lowercase Kind — matches kubectl conventions.
pkg/reconciler/run_template_reconcile.go
Execution order (each step can reference all previous steps):
- Recieve NewResolver → .spec.*, .status.*, .metadata.*
- r.readCross → .cross.<crd>.status.* (informer cache, zero API calls)
- runExternal → .external.<n>.status, .body (HTTP calls)
- forEach expand → N sources from N-element list fields
- onCreate groups → deployments, services, secrets, configmaps, ...
- onReconcile groups
- runProviders → aws:, mongodb:, ... (external infra)
pkg/reconciler/run_validation.go
Index ¶
- Variables
- func AddFinalizer(o domain.Object, finalizer string) (updated bool)
- func ContainsFinalizer(o domain.Object, finalizer string) bool
- func ReadCrossFromInformer(indexer cache.Indexer, key string, sourceCrossAccess *bool) map[string]interface{}
- func ReadCrossFromInformerByLabel(indexer cache.Indexer, labelKey, labelValue string) map[string]interface{}
- func RemoveFinalizer(o domain.Object, finalizer string) (updated bool)
- type AutoscalerRunner
- type DockerBuildResult
- type DockerPushResult
- type GenericReconciler
- func (r *GenericReconciler[PTR]) GetAutoMetrics() *autoscaler.AutoMetrics
- func (r *GenericReconciler[PTR]) Reconcile(ctx context.Context, key string) error
- func (r *GenericReconciler[PTR]) ReportQueueDepth(depth int64)
- func (r *GenericReconciler[PTR]) ResizeWorkers(n int)
- func (r *GenericReconciler[PTR]) RunAutoscaler(ctx context.Context)
- func (r *GenericReconciler[PTR]) SetQueue(wq *orkqueue.Workqueue)
- func (r *GenericReconciler[PTR]) SetQueueDepthLimit(n int)
- func (r *GenericReconciler[PTR]) SetResyncInterval(d time.Duration)
- func (r *GenericReconciler[PTR]) SetRollbackNotifiers(onTrigger, onClear func())
- func (r *GenericReconciler[PTR]) SetSpawnWorker(fn func())
- func (r *GenericReconciler[PTR]) StartResyncLoop(ctx context.Context)
- func (r *GenericReconciler[PTR]) WorkerInfo(configuredResync string, configuredWorkers, configuredQueueDepth int) *autoscaler.WorkerInfo
- type GitOperationResult
- type KatalogRegistry
- type MutationChange
- type MutationResult
- type NamespaceGuardResult
- type QueueDepthReporter
- type QueueInjector
- type ResyncLoopStarter
- type ValidationResult
- func (r *ValidationResult) Blocked() bool
- func (r *ValidationResult) DenialError() error
- func (r *ValidationResult) DenialMessage() string
- func (r *ValidationResult) Denied() bool
- func (r *ValidationResult) Error() error
- func (r *ValidationResult) HasViolations() bool
- func (r *ValidationResult) HasWarnings() bool
- func (r *ValidationResult) Log(crd, name, ns string)
- func (r *ValidationResult) ViolationSummary() string
- func (r *ValidationResult) WarningSummary() string
- type ValidationViolation
Constants ¶
This section is empty.
Variables ¶
var ExternalHTTPTransport http.RoundTripper
ExternalHTTPTransport is the http.RoundTripper used for all external: calls. nil uses http.DefaultTransport (production). Set to a stub in tests or simulation to prevent real network calls. Used by ork simulate
Functions ¶
func ReadCrossFromInformer ¶
func ReadCrossFromInformer( indexer cache.Indexer, key string, sourceCrossAccess *bool, ) map[string]interface{}
ReadCrossFromInformer reads one CR from an informer cache by namespace/name key. Zero API server calls — pure in-memory map lookup.
key is "namespace/name" for namespaced CRDs or "name" for cluster-scoped. sourceCrossAccess is the CrossAccess field of the target CRD entry — nil means allowed (default). When false, returns notFoundCrossResult() without reading.
Returns a consistent map shape regardless of whether the CR was found — callers use .found == "true" to gate their logic.
func ReadCrossFromInformerByLabel ¶ added in v0.1.9
func ReadCrossFromInformerByLabel( indexer cache.Indexer, labelKey, labelValue string, ) map[string]interface{}
ReadCrossFromInformerByLabel reads the first CR from an informer cache whose labels contain labelKey=labelValue.
The original implementation incorrectly called GetByKey with the label key string. This function correctly iterates indexer.List() and filters.
Returns the first match. When multiple CRs share the label, the first returned by List() is used — List() order is not guaranteed. If you need a specific CR, use name-based lookup (ReadCrossFromInformer) instead.
Types ¶
type AutoscalerRunner ¶
AutoscalerRunner is an optional interface implemented by reconcilers that carry an embedded autoscaler. DependencyKordinator checks for this after calling ReconcilerFactory() and launches the goroutine if present.
type DockerBuildResult ¶
type DockerBuildResult struct {
Error string
}
type DockerPushResult ¶
type DockerPushResult struct {
Error string
}
type GenericReconciler ¶
GenericReconciler manages the full lifecycle of one CRD.
This file is a pure dispatcher. It owns:
- Context enrichment
- Cache reads
- Deletion routing
- Finalizer/Annotation/Label management
- Template interpretation
- Reconcile priority (Go hooks → declarative templates → no-op)
- Event firing and logging
Resource-specific logic lives in separate files:
run_deployments.go — Deployment create/update run_services.go — Service create/update run_secrets.go — Secret create/copy/sync run_configmaps.go — ConfigMap create/copy/sync run_serviceaccounts.go — ServiceAccount create run_jobs.go — Job create (onDelete cleanup) run_cronjobs.go — CronJob create/update
Adding a new resource type:
- Add a file run_<resource>.go with a runXxx() function
- Call it from runTemplateReconcile() and/or runTemplateOnDelete()
- Add the field to orktypes.HookTemplates That is all — generic.go does not change.
Type parameter PTR:
PTR must be a pointer to the concrete CR struct (e.g. *Database). This matches Kubernetes informer semantics: the informer stores pointer values so the type assertion raw.(PTR) in reconcileCore succeeds only for pointer types. When used through the dynamic registry path in runtime_konstructor.go, PTR is inferred as domain.Object (the interface), which also satisfies the constraint and is safe because the informer cache always holds the correct underlying concrete type. See pkg/reconciler/ptr_hooks.go for the full design rationale.
func NewGenericReconciler ¶
func NewGenericReconciler[PTR domain.Object]( crd orktypes.CRDEntry, informer cache.SharedIndexInformer, ev event.Recorder, kube kubeclient.KubeClient, anyHooks domain.AnyReconcileHooks, newObj func() PTR, katalogRegistry *kordinator.ResourceKatalog, crdHealthRegistry map[string]*kordinator.CRDHealth, providerRegistry orktypes.ProviderRegistry, providerStats providerStatsRecorder, kat *katalog.Katalog, ) *GenericReconciler[PTR]
NewGenericReconciler constructs a GenericReconciler for the given CRD.
PTR must be a pointer to the concrete CR type (e.g. *Database). When called from the runtime registry path in runtime_konstructor.go, PTR is inferred as domain.Object (the interface) — this is also valid because the constraint domain.Object is satisfied and the informer stores the correct concrete type.
anyHooks, if non-nil, must implement domain.HookBinder. Every domain.ReconcileHooks[T] value satisfies HookBinder automatically via its BindToObjectHooks() method. Passing any other type panics at startup.
func (*GenericReconciler[PTR]) GetAutoMetrics ¶ added in v0.1.9
func (r *GenericReconciler[PTR]) GetAutoMetrics() *autoscaler.AutoMetrics
GetAutoMetrics returns the live AutoMetrics for this reconciler. Called by kordinator to register it in the cross-metrics registry.
func (*GenericReconciler[PTR]) Reconcile ¶
func (r *GenericReconciler[PTR]) Reconcile(ctx context.Context, key string) error
Reconcile dispatches to the correct reconcile implementation. Order:
- Conditional provisioning (when blocks) — handled by runTemplateReconcile
- Go hooks → Declarative templates → No-op (through reconcileImpl())
The semaphore gates concurrent execution — when an autoscaler is active it can reduce effective concurrency below the goroutine count without stopping goroutines.
func (*GenericReconciler[PTR]) ReportQueueDepth ¶
func (r *GenericReconciler[PTR]) ReportQueueDepth(depth int64)
ReportQueueDepth updates the live queue depth metric read by the autoscaler. Called by the worker loop after each item is processed.
func (*GenericReconciler[PTR]) ResizeWorkers ¶
func (r *GenericReconciler[PTR]) ResizeWorkers(n int)
ResizeWorkers adjusts the semaphore capacity and, when scaling up, starts additional goroutines via the injected spawnWorker function so that goroutine count stays equal to the effective concurrency limit.
func (*GenericReconciler[PTR]) RunAutoscaler ¶
func (r *GenericReconciler[PTR]) RunAutoscaler(ctx context.Context)
RunAutoscaler starts the autoscale evaluation loop. Blocks until ctx is cancelled. Called by DependencyKordinator in a dedicated goroutine. No-op when no autoscale spec is declared.
func (*GenericReconciler[PTR]) SetQueue ¶
func (r *GenericReconciler[PTR]) SetQueue(wq *orkqueue.Workqueue)
SetQueue injects the per-CRD workqueue. Called by startCRDWorkers after ReconcilerFactory() so both SetQueueDepthLimit and the resync goroutine have a reference to the right queue.
func (*GenericReconciler[PTR]) SetQueueDepthLimit ¶
func (r *GenericReconciler[PTR]) SetQueueDepthLimit(n int)
SetQueueDepthLimit updates the workqueue's depth limit. New enqueue calls that would push the queue beyond this limit are dropped with a warning. 0 means unlimited (the default). Safe to call at any time.
func (*GenericReconciler[PTR]) SetResyncInterval ¶
func (r *GenericReconciler[PTR]) SetResyncInterval(d time.Duration)
SetResyncInterval sets the resync goroutine's fire rate. 0 idles the goroutine — the informer's built-in resync handles the baseline cadence. Non-zero values trigger an additional re-enqueue of all cached objects at that interval, independently of the informer's resync period.
func (*GenericReconciler[PTR]) SetRollbackNotifiers ¶ added in v0.1.9
func (r *GenericReconciler[PTR]) SetRollbackNotifiers(onTrigger, onClear func())
SetRollbackNotifiers injects CRDHealth callbacks for rollback tracking. Called once by kordinator after constructing the reconciler.
func (*GenericReconciler[PTR]) SetSpawnWorker ¶ added in v0.1.9
func (r *GenericReconciler[PTR]) SetSpawnWorker(fn func())
SetSpawnWorker injects the goroutine-spawn function from kordinator. Called once after construction — before the autoscaler starts.
func (*GenericReconciler[PTR]) StartResyncLoop ¶
func (r *GenericReconciler[PTR]) StartResyncLoop(ctx context.Context)
StartResyncLoop launches the adjustable resync goroutine. Called once by startCRDWorkers when autoscale: is declared on the operatorbox.
func (*GenericReconciler[PTR]) WorkerInfo ¶ added in v0.1.9
func (r *GenericReconciler[PTR]) WorkerInfo(configuredResync string, configuredWorkers, configuredQueueDepth int) *autoscaler.WorkerInfo
WorkerInfo returns a live WorkerInfo snapshot for the /katalog/{crd} endpoint. configuredWorkers and configuredQueueDepth come from the CRD entry at startup.
type GitOperationResult ¶
type KatalogRegistry ¶
type KatalogRegistry interface {
// GetInformerByName returns the SharedIndexInformer for a CRD by its
// lowercase name (the map key in spec.crds).
// Returns nil, false when the CRD is not registered.
GetInformerByName(name string) (cache.SharedIndexInformer, bool)
// GetInformerByLabelSelector returns the SharedIndexInformer for a CRD whose
// metadata.labelSelector contain the given key/value pair.
//
// This enables semantic grouping of CRDs for cross-CRD observation
// (e.g. "tier=platform", "domain=payments") without requiring callers
// to know the CRD's short name. Lookup is case-insensitive on both
// key and value. Returns nil, false when no CRD matches.
GetInformerByLabel(key, value string) (cache.SharedIndexInformer, bool)
// GetCrossAccessByName returns the CrossAccess field of the named CRD.
// nil means the CRD allows cross reads (default). *false means opted out.
// Returns nil when the CRD is not registered.
GetCrossAccessByName(name string) *bool
}
KatalogRegistry is the interface GenericReconciler uses to look up sibling CRD informers for cross-CRD observation. Satisfied by *kordinator.ResourceKatalog without importing that package.
type MutationChange ¶
type MutationChange struct {
Field string
OldValue string
NewValue interface{}
Type string // "default" or "override"
}
MutationChange describes one field mutation that was applied.
type MutationResult ¶
type MutationResult struct {
Applied int
Changes []MutationChange
}
MutationResult holds the outcome of applying mutation rules.
type NamespaceGuardResult ¶
type NamespaceGuardResult struct {
Allowed bool
Namespace string
Pattern string // matched restricted or allowed pattern (for logs)
Reason string // "restricted", "not-allowed", or ""
}
NamespaceGuardResult holds the outcome of a namespace restriction check.
func CheckNamespace ¶
func CheckNamespace( ctx context.Context, obj domain.Object, targetNamespace string, restricted orktypes.RestrictedNamespaces, allowed orktypes.AllowedNamespaces, crdName string, ) *NamespaceGuardResult
CheckNamespace determines whether a target namespace is permitted for child resource creation. It evaluates both RestrictedNamespaces and AllowedNamespaces with the following precedence:
- RestrictedNamespaces — deny-list (always wins)
- AllowedNamespaces — allow-list (optional; empty = allow all)
Called before onCreate, onReconcile, onDelete, and before registry dispatch.
func (*NamespaceGuardResult) EventMessage ¶
func (r *NamespaceGuardResult) EventMessage(resourceKind, resourceName string) string
EventMessage returns the Kubernetes event message for a blocked namespace.
type QueueDepthReporter ¶
type QueueDepthReporter interface {
ReportQueueDepth(depth int64)
}
QueueDepthReporter is an optional interface reconcilers may implement to receive live queue depth updates from the worker loop.
type QueueInjector ¶
QueueInjector is an optional interface for injecting the per-CRD workqueue after the reconciler is constructed. Called by startCRDWorkers.
type ResyncLoopStarter ¶
ResyncLoopStarter is an optional interface for reconcilers that support an adjustable resync goroutine. DependencyKordinator starts it once per CRD.
type ValidationResult ¶
type ValidationResult struct {
// Passed — true when all rules passed
Passed bool
// Deny
Deny bool
// Violations — one entry per failed rule
// Warning
Warnings []ValidationViolation // action: warn violations
Violations []ValidationViolation // action: deny violations
}
ValidationResult holds the outcome of running all validation rules for one reconcile.
func RunValidation ¶ added in v0.3.7
func RunValidation(obj domain.Object, cfg *orktypes.ValidationConfig, crdName string) *ValidationResult
RunValidation exposes runValidation for integration tests.
func (*ValidationResult) Blocked ¶
func (r *ValidationResult) Blocked() bool
Blocked returns true if reconciliation must stop. Deny takes precedence; warnings alone do NOT block.
func (*ValidationResult) DenialError ¶
func (r *ValidationResult) DenialError() error
DenialError returns a proper error describing the denial reason.
func (*ValidationResult) DenialMessage ¶
func (r *ValidationResult) DenialMessage() string
DenialMessage returns a human‑readable summary of the denial cause.
func (*ValidationResult) Denied ¶
func (r *ValidationResult) Denied() bool
Denied returns true if validation rules explicitly blocked reconciliation.
func (*ValidationResult) Error ¶
func (r *ValidationResult) Error() error
Error returns a combined error message for all violations.
func (*ValidationResult) HasViolations ¶
func (r *ValidationResult) HasViolations() bool
HasViolations returns true if any rules failed.
func (*ValidationResult) HasWarnings ¶
func (r *ValidationResult) HasWarnings() bool
HasWarnings returns true if any advisory warnings were produced.
func (*ValidationResult) Log ¶
func (r *ValidationResult) Log(crd, name, ns string)
Log helper for debugging
func (*ValidationResult) ViolationSummary ¶
func (r *ValidationResult) ViolationSummary() string
ViolationSummary returns a semicolon‑joined list of violations.
func (*ValidationResult) WarningSummary ¶
func (r *ValidationResult) WarningSummary() string
WarningSummary returns a semicolon‑joined list of warnings.
type ValidationViolation ¶
type ValidationViolation struct {
Field string
Rule string
Value string // the actual CR field value that failed
Message string // the user-defined message from the Katalog
Action orktypes.ValidationAction // 'warn' or 'deny' as defined by user
}
ValidationViolation describes one failed validation rule.
Source Files
¶
- conditions.go
- cross_util.go
- generic.go
- generic_autoscale.go
- generic_namespace.go
- generic_registry.go
- gvr.go
- helper.go
- kube_reader_adapter.go
- normalize.go
- ptr_hooks.go
- rollback.go
- run_admission.go
- run_cross.go
- run_customresource.go
- run_delete_ordered.go
- run_docker.go
- run_docker_helper.go
- run_external.go
- run_git.go
- run_git_helper.go
- run_mutations.go
- run_namespace_guard.go
- run_providers.go
- run_status.go
- run_template_reconcile.go
- run_validations.go
- test_exports.go