v0.7.7 — New packs, typed group overrides, universal e2e, breaking: operatorBox.reconciler

4 min read

New pack: from-controller-runtime

ork init my-operator --pack from-controller-runtime

Eight examples tracing the migration path from an existing controller-runtime operator to Orkestra:

ExampleWhat you get
00-baselineThe controller-runtime starting point
01-declarativeZero Go. Same behaviour. Two CRDs including a Worker with rotateAfter: 30d token rotation
02-hybridDeclarative + one Go hook for what templates can’t express
03-hooks-onlyAll resources in Go, typed access to your CRD spec
04-constructor-migrationLift the existing reconcile loop into Orkestra’s constructor
05-constructor-orkestra-resourcesSame constructor, Orkestra resource helpers replace manual Get/Create/Patch
06-ork-migrateork migrate rewrites controller-runtime reconcilers automatically
07-all-optionsAll five options in one binary via Komposer — komposer-local.yaml for local dev, komposer.yaml for OCI distribution

The step-by-step narrative lives in documentation/guides/migration/.

New pack: ecosystem-composition

ork init my-operator --pack ecosystem-composition

Seven examples building an internal developer platform on top of the tools you already run:

ExampleWhat you get
00-argocdApp CRD → ArgoCD Application. Admission. Status propagation
01-cert-managerSecurityConfig CRD → Certificate
02-prometheusMonitoringConfig CRD → ServiceMonitor + PrometheusRule
03-crossplaneInfra CRD → Crossplane Composite Claim
04-platform-stackAll four, composed with Komposer
05-policy-layerShared admission motif across all CRDs. Deletion protection
06-all-in-oneSingle PlatformResource CRD with workloadType discriminator routing to the right tool

The 06-all-in-one guide (documentation/guides/ecosystem/07-all-in-one.md) includes a full trade-off comparison between focused CRDs and a unified CRD.

New pack: resilience

ork init my-operator --pack resilience

Operators that stay running — through panics, cascading failures, and degraded dependencies:

ExampleWhat you get
safe-reconcilePanic isolation in the worker pool. Nil pointer in a typed hook, caught by safeReconcile. Two declarative CRDs keep reconciling while the typed one degrades.

The deep-dive lives in documentation/concepts/operatorbox/01-reconcile-pipeline/03-panic-recovery.md.

Typed apiTypes group override (marketplace-ready patterns)

Typed katalogs can now be published under one API group and consumed under another. Set apiTypes.group in your komposer override — the generated registry uses AddKnownTypeWithName to register the Go type under the override group rather than the package’s compiled-in GroupVersion constant. apiTypes.location is now purely the import path for the Go structs, not an implicit API identity contract.

This enables the marketplace model: pull a typed pattern from OCI, set your org’s group, build, run. No source fork required.

Patch API simplified

PatchStatus, PatchFinalizers, PatchLabels, PatchAnnotations, and PatchSpec no longer take an explicit gvr schema.GroupVersionResource. GVR is resolved internally from the object’s Go type via the scheme and REST mapper — the same mechanism used by Get, Create, and Patch. Constructor reconcilers no longer need to reference GroupVersionResource constants at all.

// before
r.kube.PatchStatus(ctx, obj, apiv1.GroupVersionResource, fields)

// after
r.kube.PatchStatus(ctx, obj, fields)

Breaking: operatorBox.reconciler sub-block

default, hooks, and constructor have moved under an operatorBox.reconciler: key.

Before:

operatorBox:
  default: true
  hooks:
    location: ...
    function: ...

After:

operatorBox:
  reconciler:
    hooks:
      location: ...
      function: ...

Migration rules:

  • Declarative-only katalogs (no hooks: or constructor:): delete default: true entirely. A nil reconciler: block means GenericReconciler — default: true is now implicit and redundant.
  • Hook katalogs: wrap hooks: (and default: true if present) under reconciler:. Move default: and hooks: in by two spaces; everything else (onCreate:, status:, etc.) stays at the operatorBox: level.
  • Constructor katalogs: wrap default: false and constructor: under reconciler:. Move both in by two spaces.

utils.StrictUnmarshal rejects unknown fields, so an old katalog with top-level default: or hooks: under operatorBox will fail at parse time with a clear error before any validation runs.

ork e2e is now a universal Kubernetes test harness

spec.customOperator: true is replaced by spec.custom.target: kubernetes. The new field names the thing being tested rather than describing what to skip.

Supported targets:

ValueStatus
kubernetesSupported
containerComing soon

Migration — find and replace in all e2e.yaml files:

# before
spec:
  customOperator: true

# after
spec:
  custom:
    target: kubernetes

ork validate e2e now fast-fails with a clear error on unknown target values. If container is specified, it exits with “coming soon” rather than silently doing nothing.

The docs reframe custom.target: kubernetes as what it is: ork e2e with any workload that runs on Kubernetes — operators, Helm charts, raw manifests, third-party tools. The cluster lifecycle, assertion polling, and cleanup are Orkestra’s. The workload is yours.

New guide: documentation/guides/e2e-universal.md — “Test Anything That Runs in Kubernetes”