Skip to content

Add TemporalWorkerOwnedResource CRD#211

Closed
carlydf wants to merge 5 commits intomainfrom
temporal-worker-owned-resource
Closed

Add TemporalWorkerOwnedResource CRD#211
carlydf wants to merge 5 commits intomainfrom
temporal-worker-owned-resource

Conversation

@carlydf
Copy link
Collaborator

@carlydf carlydf commented Feb 26, 2026

Summary

  • Introduces a new TemporalWorkerOwnedResource (TWOR) CRD that attaches arbitrary namespaced Kubernetes resources (HPA, PDB, WPA, custom CRDs, etc.) to each per-Build-ID versioned Deployment managed by a TemporalWorkerDeployment
  • One copy of the attached resource is created per active Build ID, owned by the corresponding versioned Deployment — Kubernetes GC handles cleanup automatically when a Deployment is removed
  • Resources are applied via Server-Side Apply (idempotent create-or-update), coexisting safely with other field managers (e.g. the HPA controller)

Two-layer auto-population for well-known fields:

  • Layer 1: scaleTargetRef: null and matchLabels: null in spec.object are auto-injected with the versioned Deployment's identity and selector labels
  • Layer 2: Go template expressions ({{ .DeploymentName }}, {{ .BuildID }}, {{ .Namespace }}) are rendered in all string values before SSA apply

Naming: Generated resource names use a hash-suffix scheme ({prefix}-{8-char-hash}) to guarantee uniqueness per (twdName, tworName, buildID) triple even when the human-readable prefix is truncated. The buildID is always uniquely represented in the hash regardless of input lengths.

Single source of truth: ComputeSelectorLabels is now used both in Deployment creation and in owned-resource matchLabels injection, eliminating any risk of label drift.

Test plan

  • Unit tests for name generation: determinism, length bound (≤ 253), uniqueness across buildIDs including with fully-truncated prefixes
  • Unit tests for auto-injection (scaleTargetRef, matchLabels) and Go template rendering
  • Unit tests for full RenderOwnedResource lifecycle (metadata, owner ref, label propagation)
  • Build passes: go build ./...
  • All existing tests continue to pass: go test ./...

🤖 Generated with Claude Code

…ned Deployments

Introduces a new `TemporalWorkerOwnedResource` (TWOR) CRD that lets users attach
arbitrary namespaced Kubernetes resources (HPA, PDB, WPA, custom CRDs, etc.) to
each per-Build-ID versioned Deployment managed by a TemporalWorkerDeployment.

Key design points:
- One copy of the attached resource is created per active Build ID, owned by the
  corresponding versioned Deployment — Kubernetes GC deletes it automatically when
  the Deployment is removed, requiring no explicit cleanup logic.
- Resources are applied via Server-Side Apply (create-or-update), so the controller
  is idempotent and co-exists safely with other field managers (e.g. the HPA controller).
- Two-layer auto-population for well-known fields:
    Layer 1: `scaleTargetRef: null` and `matchLabels: null` in spec.object are
             auto-injected with the versioned Deployment's identity and selector labels.
    Layer 2: Go template expressions (`{{ .DeploymentName }}`, `{{ .BuildID }}`,
             `{{ .Namespace }}`) are rendered in all string values before apply.
- Generated resource names use a hash-suffix scheme (`{prefix}-{8-char-hash}`) to
  guarantee uniqueness per (twdName, tworName, buildID) triple even when the prefix
  is truncated; the buildID is always represented in the hash regardless of name length.
- `ComputeSelectorLabels` is now the single source of truth for selector labels used
  both in Deployment creation and in owned-resource matchLabels injection.
- Partial-failure isolation: all owned resources are attempted on each reconcile even
  if some fail; errors are collected and surfaced together.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@carlydf carlydf requested review from a team and jlegrone as code owners February 26, 2026 23:59
@carlydf carlydf marked this pull request as draft February 27, 2026 00:11
carlydf and others added 4 commits February 26, 2026 16:22
- Extract getOwnedResourceApplies into planner package so it can be
  tested without a live API client
- Add OwnedResourceApply type and OwnedResourceApplies slice to Plan
- Thread twors []TemporalWorkerOwnedResource through GeneratePlan
- Add TestGetOwnedResourceApplies (8 cases: nil/empty inputs, N×M
  cartesian, nil Raw skipped, invalid template skipped)
- Add TestGetOwnedResourceApplies_ApplyContents (field manager, kind,
  owner reference, deterministic name)
- Add TestGetOwnedResourceApplies_FieldManagerDistinctPerTWOR
- Add two TWOR cases to TestGeneratePlan for end-to-end count check
- Add helpers: createTestTWOR, createDeploymentWithUID,
  createTestTWORWithInvalidTemplate

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Both the controller plan field and the planner Plan field now share the
same name, making the copy-assignment self-documenting:
  plan.ApplyOwnedResources = planResult.ApplyOwnedResources

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Users don't need to template the k8s namespace (they already know it
when creating their TWOR in that namespace). The Temporal namespace is
more useful since it configures where the worker connects to.

- TemplateData.Namespace → TemplateData.TemporalNamespace
- RenderOwnedResource gains a temporalNamespace string parameter
- getOwnedResourceApplies threads the value from
  spec.WorkerOptions.TemporalNamespace down to RenderOwnedResource
- Update all tests: {{ .Namespace }} → {{ .TemporalNamespace }}
- GoTemplateRendering test now uses distinct k8s ns ("k8s-production")
  and Temporal ns ("temporal-production") to make the difference clear

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@carlydf carlydf closed this Feb 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant