v0.7.10 — E2E DSL extensions, cluster improvements, endpoint control, children forEach fixes, ork proxy
ork proxy — port-forward for Helm-deployed Orkestra
Inspired by kubectl proxy, ork proxy replaces manual kubectl port-forward calls when working with a deployed Orkestra. It discovers components by the orkestra.orkspace.io/komponent label, resolves the Runtime leader via the orkestra-konductor Lease, and reconnects automatically on pod replacement (rollouts, leader failover).
ork proxy # Forward Runtime, Control Center, and Gateway
ork proxy --for cc # Control Center only
ork proxy --for runtime,cc # Runtime and Control Center
ork proxy -n my-platform-ns # Custom namespace
ork proxy --runtime-port 9090 # Remap a port to avoid conflicts
The Runtime forward always targets the leader pod — not a random replica — so the forwarded connection reaches the replica with authoritative reconciler state. Port conflicts are caught before any tunnel opens. The --for flag uses the same vocabulary as ork generate bundle --for.
E2E: kubectl subprocess calls migrated to Go client
Three operations in the e2e runner previously shelled out to kubectl. They now use the Go client directly, removing the kubectl install requirement for these paths:
- Leader Lease resolution (
leaderElection:onport-forward,logs,exec,delete) —CoordinationV1().Leases().Get()instead ofkubectl get lease -o jsonpath - Auth checks (
kubectl.auth) —SelfSubjectAccessReviewwhen no--asis set (matchingkubectl auth can-idefault behaviour);SubjectAccessReviewwithUserwhen--asis specified. The previousSubjectAccessReviewwith an empty user field was rejected by the API server. - Port-forward assertions (
kubectl.port-forward) — SPDY portforward viak8s.io/client-go/tools/portforward+net/http. UsesreadyChanfor an exact ready signal instead of the old curl-retry polling loop.
Fix: kind node readiness spinner
The spinner during ork e2e cluster setup was interleaving kubectl output on the same terminal line. Node readiness output is now captured via os.Pipe and never written to the terminal. The spinner updates with (N/total) progress as each node becomes ready and marks success once all nodes are up.
kubectl.restart and kubectl.scale — new E2E DSL subcommands
Two new mutation subcommands under kubectl: for steps that need to trigger a rollout or change replica count as part of a test sequence.
kubectl.restart calls kubectl rollout restart and waits for the rollout to complete (ready: true by default):
kubectl:
restart:
- kind: Deployment
name: my-app
namespace: default
kubectl.scale calls kubectl scale --replicas=N and waits for the rollout to settle:
kubectl:
scale:
- kind: Deployment
name: my-app
namespace: default
replicas: 3
Both support ready: false to skip the rollout status wait. Neither appears in onFailure diagnostics — mutations do not belong in the diagnostic path.
Typical use: disabling deletion protection for e2e cleanup (patch ConfigMap → kubectl.restart gateway so housekeeper starts with enabled: false and removes the ValidatingWebhookConfiguration).
leaderElection: on kubectl.delete and kubectl.exec
leaderElection: was previously supported only on port-forward and logs. It now works on delete and exec as well, completing all four kubectl subcommands.
kubectl.delete with leaderElection: resolves the current Lease holder at test time and deletes the pod by name — without hardcoding it. The leader-failover example now uses this for its “Kill the konductor pod” step, replacing a raw shell command embedded in YAML.
kubectl.exec with leaderElection: runs a command inside the leader pod.
Type rename: E2EKubectlPortForwardLeaderElection → E2EKubectlLeaderElection
The type is now used by all four kubectl subcommands. The old name was misleading. YAML schema keys (leaderElection:) are unchanged.
ork create cluster — --workers and --version
--workers <n> provisions n worker nodes in addition to the control-plane. --version <v> selects which kind release to download and cache at ~/.orkestra/bin/kind-<version>; previously hardcoded to v0.27.0. An explicit --version skips any kind binary already in PATH and uses the versioned cache entry. The same --workers flag is accepted on ork e2e and ork push.
ork delete cluster
New command — the complement to ork create cluster. Deletes a kind cluster by name:
ork delete cluster
ork delete cluster --name ork-e2e
e2e.New Options struct
New(e2eFile string, opts Options) replaces a long positional parameter list. Workers and KindVersion propagate into sub-runner New calls for imports.
ork run <name>:<version> — OCI positional argument
ork run postgres:v1.0.0 pulls the pattern from the registry (if not cached) and starts the runtime directly. No -f flag, no local files required.
ork run postgres:v1.0.0 --dev # pull + cluster + runtime
ork run postgres:v1.0.0 --dev --apply-cr # + apply example crd.yaml and cr.yaml
ork run postgres:v1.0.0 --dev --use-komposer # run via the pattern's komposer.yaml
ork run postgres:v1.0.0 --dev --refresh # re-pull before running
--apply-cr applies crd.yaml from the pattern, waits for the CRD to establish, then applies cr.yaml. The operator starts with a CR already in the cluster.
--use-komposer uses komposer.yaml from the cached pattern instead of katalog.yaml. Only applies to the OCI positional arg path.
komposer.yaml now included in pushed artifacts
komposer.yaml was missing from OptionalFiles for Katalog patterns — it was never included as an OCI layer when pushing. Added FileKomposer constant and added it to the optional files list. Patterns must be re-pushed to include it.
Endpoint control — endpoints: and crossAccess: surfaced in the Control Center
Disabled endpoints no longer show as degraded in the CC. The /katalog summary now carries healthEnabled, infoEnabled, and crossAccess flags alongside the static CRD fields (GVK, GVR, Mode, Namespaced, Description) that were previously only available from the per-CRD info endpoint.
The CC reads these flags and skips disabled endpoint calls, synthesising health and info from the always-available /katalog summary. A CRD with endpoints: enabled: false returns state: "endpoints-disabled" and renders a clean disabled page instead of zeros or error states.
All three CC templates updated:
- Katalog card — health badge +
⊘icon when health is disabled; metrics rows hidden when info is disabled;⊘ info endpoint disabledrow when fully dark - CRD detail — three explicit disabled states: full-page notice, health section notice, operatorBox section notice
- Generated docs — new Endpoints section (always shown); Cross-read access row in Overview; operatorBox summary table (hooks, constructor, finalizers); Configuration section hidden for disabled CRDs
crossAccess: is now visible in the generated docs page for each CRD — ✓ allowed or ⊘ denied with a plain-English explanation.
Advanced pack — 19-endpoint-control
Three new examples under examples/advanced/19-endpoint-control/, each with ork validate, ork simulate, ork run walkthrough, and a fully passing ork e2e:
| Example | What it teaches |
|---|---|
01-selective-health | endpoints: health: false — info and CR list active, health endpoint removed |
02-full-disable | endpoints: enabled: false — all HTTP surfaces removed, operator reconciles normally |
03-fully-dark | crossAccess: false + endpoints: enabled: false — dark operator reads its open sibling via cross:; sibling’s cross-read is denied; both outcomes visible in status printer columns |
Root simulate.yaml and e2e.yaml use imports: to chain all three sub-examples.
Control Center — generated docs page
New documentation page in documentation/orkestra-core/03-controlcenter/generated-docs.md covering the live-generated per-CRD docs: what sections appear, when, and how disabled endpoints affect the output.
Bug fixes
forEach:silently no-op on NetworkPolicy, ResourceQuota, LimitRange, ClusterRole, ClusterRoleBinding:forEach:support for these five resource types was deferred from v0.7.8 when they were first introduced. A declaredforEach:block was silently dropped — no expansion, no error. Fixed:ExpandForEach*wrappers added inpkg/children/foreach.go; runner calls inrun_template_reconcile.gonow pass through the expand step.ForEachfield missing on NetworkPolicy, ResourceQuota, LimitRange, ClusterRole, ClusterRoleBinding template sources:forEach:was undeclared on these types — any YAML using it would be silently ignored. Fixed:ForEach *ForEachSpecadded to all five structs.NetworkPolicy invisible to child tracker:
mergeTemplatesinpkg/children/read.gomerged all v0.7.8 resources exceptNetworkPolicies— they never appeared in the CR detail children map. Fixed.ResourceQuota and LimitRange invisible to CR detail view:
ResourceQuotaGVRandLimitRangeGVRwere absent frompkg/children/gvr.go— these resources could not be read back as children after reconcile. Fixed: GVR vars andChildGVRs()entries added.NetworkPolicy, ResourceQuota, LimitRange, ClusterRole, ClusterRoleBinding not tracked as children: No
*Nameshelper orchildren.goread block existed for any of the five types. Fixed: helpers and read blocks added; resources now appear in CR detail and the Control Center Resources tab.Node-ready race:
waitForNodesReadychecked the condition type (Ready) not its status (True). A node could be type=Ready status=False and still be reported ready. Replaced withkubectl wait --for=condition=Ready node --all.--versionsilently ignored when kind is in PATH:resolveKindalways checked PATH first regardless of the version flag. Fixed: empty version checks PATH then falls back to default; non-empty version skips PATH entirely.Spinner output leaking during setup waits:
WaitForResourceused.Run()for ready checks, lettingkubectl rollout statusandkubectl waitwrite progress to the terminal while the spinner goroutine was running. Replaced with.Output().helm repo add/updatehad the same issue during the Installing spinner.
ork e2e --report-file
--report-file <path> writes results as a GFM markdown table after every run. The file contains two tables — passed cases (icon, test, time) and failed cases (icon, test, time, error) — with a summary line. Newlines in error messages are replaced with . so the table renders correctly.
ork e2e --report-file results.md
ork e2e --report-file "$GITHUB_STEP_SUMMARY" # render directly in GitHub Actions
Terminal output is now also split: passed cases print first, then failed cases with the full error indented line-by-line — consistent with how most language test frameworks present results.
spec.onFailure and per-expectation onFailure
Two levels of diagnostic output when a test fails:
spec.onFailure — runs once after all expectations complete, when at least one failed. Use for a global cluster snapshot.
expect[].onFailure — runs immediately when that specific checkpoint fails, before moving to the next. Use to capture state at the moment of failure.
Both accept the same DSL:
spec:
onFailure:
kubectl:
logs:
- labelSelector: app=my-operator
namespace: default
since: 2m
commands:
- kubectl get pods -A -o wide
expect:
- name: Operator reaches Ready
after: cr-applied
timeout: 120s
kubectl:
get:
- kind: MyResource
name: my-cr
namespace: default
field: .status.phase
equals: Ready
onFailure:
kubectl:
describe:
- kind: Deployment
name: my-operator
namespace: default
Assertion fields on the kubectl: structs are present but never evaluated — output is always printed. onFailure never blocks teardown.