feat(chart): integrate operator-managed migrations - #348
Siddhant-K-code wants to merge 25 commits into
Conversation
Replace Helm hook-based migrations with a lightweight Kubernetes operator that watches OpenFGA Deployments, detects version changes, and runs migrations as regular Jobs. - Go operator using controller-runtime (no CRDs) - Helm subchart with opt-in via operator.enabled (default false) - Dedicated migration ServiceAccount (separate from runtime) - Auto-recovery on database failure (delete/retry cycle) - GitHub Actions workflow for multi-arch image builds - Integration test values for local Kubernetes clusters Resolves #211, #107, #120, #100, #126
- Harden pod security (runAsNonRoot, seccompProfile, drop ALL caps) - Find container by name instead of index to handle sidecars - Skip migration for memory datastore - Persist retry-after annotation before Job deletion to survive re-enqueue - Clear MigrationFailed condition on success - Propagate imagePullSecrets and securityContext to migration Jobs - Remove unused RBAC rules (secrets, serviceaccounts) - Add POD_NAMESPACE downward API for namespace-scoped watch default - Remove no-op migration values (timeout, backoffLimit, resources) - Fix migration SA helper to require name when create=false - Guard operator logic on both operator.enabled and migration.enabled - Build and load operator image into kind for chart-testing CI - Add path filters to operator workflow - Fix ADR inaccuracies (retry strategy, default-enabled wording) - Pin Dockerfile base image to golang:1.26.2
- Render extraInitContainers in operator mode (previously skipped) - Add version label to migration Jobs and delete stale Jobs on image change - Use namespaced Role/RoleBinding when watchAllNamespaces is false - Replace Status().Update with Status().Patch to avoid write conflicts - Fix logger.Error(nil, ...) to logger.Info for expected failure state - Wire desiredVersion param into buildMigrationJob for version tracking - Update RBAC: deployments/status verb from update to patch - Don't force replicas: 0 for memory engine in operator mode - Guard migration SA creation on migration.enabled - Document both required labels and mutable tag limitation in README
- Add opt-in annotation (openfga.dev/migration-enabled) so the operator only manages migrations for explicitly opted-in Deployments - Propagate volumes, volumeMounts, and envFrom from the Deployment to migration Jobs for TLS certs and file-based credentials - Remove watchAllNamespaces option; operator is now always namespace-scoped - Update ADR-004 dependency example to match actual file:// reference - Add test for migration-not-enabled skip behavior
- Wrap deployment annotations in conditional to avoid emitting empty annotations: field which produces an invalid manifest - Store full version in annotation (openfga.dev/desired-version) and truncate label to 63 chars to support digest-pinned images - Align operator image default to ghcr.io/openfga/openfga-operator to match CI publishing target
When operator.enabled=true but migration.enabled=false, the legacy wait-for-migration initContainer could render and hang waiting for a Job that will never be created. Gate on operator.enabled instead so the legacy path is fully disabled when the operator is installed.
…essions The double-quoted annotation values contained inner double quotes (e.g. "memory") which produced invalid YAML that IDEs flagged as errors. Switch to single-quote wrappers so the inner Go template strings don't conflict.
20 new tests across 4 files covering the operator-enabled code paths that previously had no unit test coverage: - deployment: annotations, replicas=0, autoscaling conflict, initContainers gating - job: template not rendered when operator enabled - serviceaccount: migration SA creation, custom names, IRSA annotations - rbac: legacy Role/RoleBinding not rendered when operator enabled
The operator was scaling Deployments to 0 replicas during every migration, causing a full outage on every helm upgrade — a regression from the existing rolling update behavior. OpenFGA already gates readiness on schema version (MinimumSupportedDatastoreSchemaRevision in sqlcommon.IsReady), so new pods naturally block until migration completes while old pods keep serving. Use Helm's lookup function to preserve the live replica count on upgrade (falling back to replicas: 0 on fresh install where no Deployment exists). Remove scaleDeploymentToZero from the operator reconcile loop. Update ADR-002 to document the rationale and the readiness gate dependency.
…ent template - findOpenFGAContainer now reads the openfga.dev/container-name annotation emitted by the chart, and returns an error when the target container is missing instead of silently falling back to the first container in the pod spec. - migration_controller surfaces that error to the reconciler instead of logging and skipping, so misconfigured Deployments are visible. - deployment.yaml emits the new container-name annotation, collapses the replica-preservation logic to a single branch (both previous branches already preserved existing replicas), and uses selectorLabels on the pod template to avoid chart-version churn in pod labels across upgrades. - values.yaml documents the openfga-operator subchart values passthrough and clarifies migration service account behavior.
I switched the pod template labels from openfga.labels to openfga.selectorLabels, which would have stripped helm.sh/chart, commonLabels, component, version, managed-by, and part-of from running pods on upgrade — a breaking change for any tooling filtering on those labels. Add a helm-unittest regression guard for both operator on/off modes.
- charts/openfga-operator/ci and charts/openfga/ci values files so chart-testing exercises both the standalone operator subchart and the parent chart with operator.enabled=true. - .github/ci/operator-postgres-values.yaml plus a dedicated workflow step that installs at v1.9.5 and upgrades to v1.14.1 (crossing the v1.10.0 !!REQUIRES MIGRATION!! boundary), asserting the migration ConfigMap and ready rollout at each step.
Both the operator subchart and the parent chart's operator/migration blocks were missing additionalProperties: false, so typos like `migrationjob:` (lowercase), `enbaled: true`, or misplaced fields were silently ignored at install time. Add the guard to all well-defined object blocks — free-form blocks (podAnnotations, resources, securityContext, etc.) stay permissive since they pass through to pod spec.
When operator.enabled=true the workload starts at 0 replicas and only scales up after migration. If the operator pod is unhealthy this looks like a stuck install with no signal. Add NOTES output pointing at the operator deployment, migration Job, and MigrationFailed condition.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…ator-plus-migration-hooks # Conflicts: # charts/openfga/templates/deployment.yaml # charts/openfga/templates/job.yaml
There was a problem hiding this comment.
Pull request overview
Integrates the openfga-operator subchart into charts/openfga to support operator-managed migrations while keeping the existing Helm-managed migration behavior when operator mode is disabled.
Changes:
- Adds
operator.enabled+migration.*values (and schema) and wiresopenfga-operatoras a conditional dependency. - Gates legacy migration Job/hooks, migration initContainers, and legacy RBAC when operator mode is enabled; adds operator-specific Deployment annotations and optional migration ServiceAccount.
- Adds Helm unit tests and CI values to cover operator mode rendering and conflicts (e.g., autoscaling).
Reviewed changes
Copilot reviewed 15 out of 16 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| charts/openfga/values.yaml | Adds operator mode and migration ServiceAccount configuration values. |
| charts/openfga/values.schema.json | Extends schema to validate operator/migration keys and allow openfga-operator passthrough. |
| charts/openfga/Chart.yaml | Adds openfga-operator as an optional subchart dependency gated by operator.enabled. |
| charts/openfga/Chart.lock | Updates dependency lock for the new local subchart dependency. |
| charts/openfga/templates/deployment.yaml | Adds operator annotations, replica gating logic, autoscaling conflict fail, and migration initContainer gating updates. |
| charts/openfga/templates/_helpers.tpl | Adds migration ServiceAccount name helper; disables pre-install hook logic in operator mode. |
| charts/openfga/templates/job.yaml | Disables legacy Helm migration Job rendering when operator mode is enabled. |
| charts/openfga/templates/rbac.yaml | Disables legacy RBAC rendering when operator mode is enabled. |
| charts/openfga/templates/serviceaccount.yaml | Adds optional migration ServiceAccount rendering for operator mode. |
| charts/openfga/templates/NOTES.txt | Adds operator-mode user guidance and troubleshooting notes. |
| charts/openfga/README.md | Documents operator-managed migrations and behavior differences vs Helm-managed modes. |
| charts/openfga/ci/operator-mode-values.yaml | Adds CT/install values to exercise operator mode (memory datastore) in CI. |
| charts/openfga/tests/operator_mode_test.yaml | Adds unit coverage for operator annotations, replica behavior, initContainer gating, and autoscaling conflict. |
| charts/openfga/tests/operator_mode_serviceaccount_test.yaml | Adds unit coverage for operator migration ServiceAccount rendering rules. |
| charts/openfga/tests/operator_mode_rbac_test.yaml | Adds unit coverage ensuring legacy RBAC is suppressed in operator mode. |
| charts/openfga/tests/operator_mode_job_test.yaml | Adds unit coverage ensuring legacy migration Job is suppressed in operator mode. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…k-code-authored-openfga-integration # Conflicts: # charts/openfga/templates/_helpers.tpl # charts/openfga/templates/serviceaccount.yaml
…k-code-authored-openfga-integration
…k-code-authored-openfga-integration # Conflicts: # charts/openfga/Chart.yaml
…k-code-authored-openfga-integration # Conflicts: # charts/openfga/templates/_helpers.tpl
…k-code-authored-openfga-integration
…k-code-authored-openfga-integration
|
Closing this stack for now. We're going to focus first on updating, reviewing, and fixing #309. |
Summary
Integrates the migration operator into the OpenFGA chart while preserving existing migration behavior when operator mode is disabled.
openfga-operatoras an optional subchart controlled byoperator.enabled.Stack
Native stack 351. Open #345 to view the GitHub stack map. Review bottom to top:
mainReplaces closed #339 and carries the OpenFGA chart integration portion of source #331. CI and upgrade E2E remain in the next layer.
Attribution
Validation
ct lintgit diff --check