Operator and CRD development
Evolve declarative APIs and reconciliation safely, including generated schemas, RBAC, chart copies, and envtest.
Gameplane uses Kubernetes Custom Resource Definitions (CRDs) and controller-runtime reconcilers to manage cluster state declaratively. This guide covers the CRD authoring workflow, reconciliation patterns, and testing strategies.
Generated chart CRDs and explicit upgrade instructions must stay synchronized. After editing a CRD, update the chart copies and document any schema changes that affect existing resources.
Controller contract
Reconcile idempotently from spec to owned resources and actionable, current status. A reconciler must be safe to re-run at any time without changing the outcome.
Conditions should follow the Kubernetes conventions: each condition reports one aspect of the resource’s state (type), with status (True/False/Unknown), reason (machine-readable code), and message (human-readable detail). The observedGeneration field tracks which spec generation is reflected in status; when observedGeneration < metadata.generation, the controller hasn’t yet reconciled the latest spec changes.
Change a CRD
Go types and Kubebuilder markers are the source of truth; generated code, schemas, RBAC, and chart copies are reviewed artifacts that must stay in sync.
The zz_generated.deepcopy.go file is regenerated by controller-gen (make generate). The CRD YAML files in operator/config/crd/ are the canonical copies; charts/gameplane/crds/ and charts/gameplane/crd-manifests/ receive copies stamped with a bundle hash for upgrade tracking. Always commit generated files in the same changeset as the type changes.
Test reconciliation
Use unit tests for helpers, envtest for API/controller behavior, and Kind E2E for real scheduling, networking, storage, images, and Jobs.
- Unit tests (
_test.goin the same directory as the code) exercise pure Go logic: helper functions, validation, string parsing, and error handling. Run withgo test ./.... - Envtest (
_envtest_test.gowith//go:build envtestbuild tags) spins up a temporary Kubernetes cluster with the operator and API server installed. Tests can create real CRD resources, trigger reconciliation, and assert on reconciled state. Envtest is faster than Kind (no container images to build or push) and ideal for controller logic and integration between operator and API. - Kind E2E (
test/e2e/*_test.gowith//go:build e2ebuild tags) runs against a fully deployed cluster with all components running in pods. E2E tests verify real scheduling decisions, networking, storage provisioning, and job execution — scenarios where envtest’s mock API cannot fully simulate production behavior.
CRD LOOP
Run make test-integration locally before pushing. It will download the Kubernetes control-plane binaries (envtest) and run all envtest-tagged tests for the operator and API modules. CI runs the full test suite including E2E; do not skip this step locally — wait for CI results to confirm the change works across all tiers.
Workflow summary
- Design: Sketch the CRD fields, enum values, and validation rules in your spec struct.
- Implement: Add Kubebuilder markers (validation, RBAC, OpenAPI schema directives) alongside the type definitions.
- Generate: Run
make generate && make manifests. Review the diffs to ensure no unexpected schema changes. - Test: Write unit tests for helpers, envtest tests for reconciler logic and edge cases.
- Commit: Include types, generated code, CRD manifests, and tests in one commit with a clear message explaining the new capability or fix.
- Deploy: Push to a feature branch. CI will run the full test suite (unit + envtest + E2E) before the change can be merged to main.