refactor: breaking changes#10
Merged
Merged
Conversation
…* → banjo.*
Foundation for the 0.4.0 restructure. Three independent cleanups bundled:
- Bump chart version to 0.4.0-dev1 (dev cycle until release)
- Drop redis/rabbitmq/postgresql/minio subchart dependencies; delete
Chart.lock; remove global.security.allowInsecureImages (Bitnami-only).
Infrastructure ships via a separate chart.
- Rename all django-app.* template helpers and references to banjo.*
across _helpers.tpl and 14 templates. Internal change; no impact on
consumer values.yaml.
- Rewrite the secrets: example block to drop $.Subcharts.* references.
values-{1,2,3}.yaml test fixtures and linter_values.yaml updated to
match. All 56 existing helm-unittest cases still pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
K8s defaults to 10 old ReplicaSets per Deployment; this caps to 1. Single top-level knob applied uniformly to api, worker queues, worker-beat, and celery-flower Deployments. Per-component override intentionally not exposed — one value works for all of this chart's workloads. Tests: assert spec.revisionHistoryLimit on each Deployment under defaults; new test asserts override propagates when set chart-wide. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
BREAKING CHANGE:
API block reshaped per the refactor plan:
- command: [] default (was Toggle-Corp-specific run_prod.sh path).
Template now conditionally renders command: only when non-empty.
- api.annotations: {} merged into pod template metadata
- api.extraEnv: {} inline per-pod env, tpl-evaluated against root
- resources: requests + memory limit only (no CPU limit) at 100m/256Mi/512Mi
- replicaCount default already nil-guarded; no value-side default
New banjo.extraEnvBlock helper deep-merges defaults+override env maps
(item wins per key) and renders as a k8s env array with tpl evaluation.
This is the first of three new helpers; queues/addons/cronjobs/hooks
will adopt it in later slices.
Tests: resource shape regression (no CPU limit), command nil-guard,
annotations passthrough, extraEnv merge + tpl evaluation.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add banjo.dictOrArray + banjo.envVarsBlock helpers. The top-level
extraEnvVars now accepts either:
- Array form (current shape; full wholesale reset via -f overlay)
- Dict form keyed by env-var name (additive merge via -f overlay)
Dict-form values are k8s-native env-var specs minus the name field —
{value: ...} or {valueFrom: {configMapKeyRef|secretKeyRef|fieldRef|...}}.
No string shorthand: the top-level env: covers plain k=v cases.
banjo.dictOrArray normalizes either shape into a YAML list and is
shared infrastructure for slices 05–08 (queues, addons, cronjobs.jobs,
hooks.jobs all reuse it).
Existing array-form behavior unchanged; existing tests still pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
BREAKING CHANGE: Replace worker.queueCommandPrefix + worker.queueDefaultResources with a queueDefaults sibling block containing commandPrefix, extraEnv, annotations, resources. worker.queues is now dict-or-array — dict form merges with chart defaults via -f; array form replaces wholesale. Each queue inherits defaults via banjo.extraEnvBlock (env merge, queue wins per key) and banjo.resourcesConfig (deep-merge, override wins). replicaCount nil-guard preserved so KEDA can own scaling. Removed seeded default: queue (was enabled: true in 0.3.x) — consumers define their own queues now. Test fixtures updated to new shape including an array-form fixture (values-3.yaml) that exercises wholesale reset. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Generalize auxiliary worker processes into a worker.addons map. Beat
and flower are no longer special — they're addon entries alongside
celery-exporter, leek, or any other singleton process. Adding a new
addon needs zero chart changes.
BREAKING CHANGE:
- New addonDefaults sibling block (extraEnv, annotations, resources)
- worker.addons is dict-or-array (merge or reset semantics)
- Each addon: enabled, command, optional replicaCount, optional service:
{enabled, port, targetPort}, extraEnv, annotations, resources
- New templates/worker-addons/{deployment,service}.yaml iterate the map.
Service rendered only when addon has service.enabled.
- Deleted templates/worker-beat/, templates/celery-flower/, and their
test dirs.
Reuses banjo.dictOrArray normalization pattern and banjo.extraEnvBlock
merge from earlier slices.
Linter values + test fixtures updated. values-3.yaml exercises the
array-reset form for addons.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Consolidate cronjobs.image and cronjobs.defaultResources into a cronjobs.defaults block (matches the hooks/api pattern). cronjobs.jobs is now dict-or-array — dict form merges, array form replaces. BREAKING CHANGE: New default knobs in cronjobs.defaults: - successfulJobsHistoryLimit: 1 (k8s default is 3) - failedJobsHistoryLimit: 1 (matches k8s default; explicit by chart convention) - extraEnv, annotations, resources Per-job overrides for history limits (default → cronjobs.defaults.* if unset). Per-job extraEnv merges with defaults via banjo.extraEnvBlock. Tests cover history-limit defaults + per-job override, extraEnv merge, dict-array equivalence, resource shape (no CPU limit regression guard). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ation
BREAKING CHANGE:
Rename argoHook → hooks (tool-agnostic; ArgoCD and Helm hooks render
the same Job template, distinguished only by annotation namespace).
hooks.hooks → hooks.jobs (dict-or-array).
Hook job schema:
- annotations: {} — passed verbatim onto the Job. Consumer writes any
combination of argocd.argoproj.io/* or helm.sh/* annotations.
- useGenerateName, activeDeadlineSeconds, ttlSecondsAfterFinished —
typed spec-level fields, rendered only when set.
- extraEnv merges from hooks.defaults via banjo.extraEnvBlock.
Removed (breaking):
- hook: PostSync shortcut — write the full annotation instead
- preserveHistory — renamed to useGenerateName
Seeded jobs:
- wait-for-resources: opt-in (banjo-utils dependency), sync-wave 10,
HookSucceeded.
- db-migrate: useGenerateName + activeDeadlineSeconds=3600 +
ttlSecondsAfterFinished=604800 (7d). Sync-wave 20.
- collect-static: static name, BeforeHookCreation, sync-wave 20.
CRITICAL: db-migrate's annotations intentionally do NOT include
argocd.argoproj.io/hook-delete-policy. ArgoCD docs explicitly state
BeforeHookCreation and generateName are alternatives, not a combo —
name-based lookup never matches generateName-derived names. The 0.3.x
chart shipped the inert combination and jobs accumulated forever.
Regression test in tests/hooks/job_test.yaml asserts the annotation
is absent on db-migrate.
References:
- https://argo-cd.readthedocs.io/en/stable/user-guide/resource_hooks/
- argoproj/argo-cd#4295
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Possible version: 0.4.0 MIGRATION.md targets Claude consumption: - Rename table at top — every 0.3.x → 0.4.0 path change in one grep-able view - Section-by-section before/after values.yaml snippets (api, worker queues, worker addons, cronjobs, hooks, subchart removal) - Behavioral changes separated from renames: replicaCount removal, hook lifecycle correction (with bug citation), CPU limits, sync-wave, dict-or-array. - Verification protocol baked in: helm template before/after + diff, with explicit lists of expected vs suspicious diff lines so Claude can self-check during migration. CHANGELOG follows the existing 0.3.0 release format with a leading breaking-changes block, features, fixes, testing, and migration notes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Snapshots in chart/snapshots/values-{1,2,3}.yaml are full helm template
output against the corresponding tests/values-{1,2,3}.yaml fixtures.
Regenerated after all the breaking restructures land:
- values-1 (everything-enabled, dict form across queues/addons/hooks)
- values-2 (everything-enabled with custom hooks and per-component env)
- values-3 (array-form reset for queues and addons; CNPG extraManifests)
Confirmed in snapshots:
- db-migrate hook ships with generateName + ttlSecondsAfterFinished +
activeDeadlineSeconds; no hook-delete-policy annotation (regression
guard against the inert ArgoCD combination).
- revisionHistoryLimit: 1 on every Deployment.
- No limits.cpu on chart-default resources.
- worker-addons rendered (beat + flower) in place of the deleted
worker-beat and celery-flower templates.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-locates the Ingress under its only consumer (the api service). Matches the chart's existing "group under owner" pattern (worker.addons, cronjobs.defaults, hooks.defaults). Pure rename — template logic unchanged, snapshots stable. BREAKING CHANGE: top-level `ingress:` is now `api.ingress:`. Downstream values.yaml files must nest the entire ingress block under `api:`. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Swap `required` for a `{{- with }}` block on api.ingress.className. When
unset (or empty string), spec.ingressClassName is omitted entirely and
Kubernetes uses the cluster's default IngressClass (the IngressClass
annotated with ingressclass.kubernetes.io/is-default-class: "true").
Assumes the target cluster has a single default IngressClass configured —
that's a cluster-side concern, not the chart's. Two new helm-unittest cases
guard the unset and empty-string paths; the empty-string case specifically
prevents a future `if` vs `with` regression.
BREAKING CHANGE: `api.ingress.className` is no longer required. Previously
missing className would fail `helm template` with a clear error; it now
renders an Ingress without spec.ingressClassName. Downstream consumers
relying on that error to catch misconfiguration should set className
explicitly or audit cluster IngressClass defaults.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Rename table: add ingress.* -> api.ingress.* (block move, sub-keys unchanged) and ingress.className required -> api.ingress.className optional. Section-by-section: new ingress: -> api.ingress: block with before/after. Behavioral changes #6: explain that omitted className falls through to the cluster's default IngressClass, including the failure mode if no default exists (Ingress created but traffic silently unrouted). Verification protocol: add "absent spec.ingressClassName" to expected diff when consumer drops className. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…r graceful shutdown Add api.lifecycle.preStopSleepSeconds (default 8) using the K8s 1.30+ native lifecycle.sleep action to close the kube-proxy endpoint-propagation race. Compute spec.terminationGracePeriodSeconds as preStopSleepSeconds + 30s drain when the hook is on; overridable via api.terminationGracePeriodSeconds. Pin Chart.yaml kubeVersion >= 1.30.0-0 (native sleep action GA). BREAKING CHANGE: Chart now requires Kubernetes >= 1.30. The api Deployment ships with a default 8s preStop sleep and a computed terminationGracePeriodSeconds of 38s. Set api.lifecycle.preStopSleepSeconds: 0 to disable, or api.terminationGracePeriodSeconds: <n> to override the grace ceiling. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds livenessProbe / readinessProbe / startupProbe to the api Deployment,
gated on api.probes.enabled (default false; opt-in matches the existing
wait-for-resources hook pattern, no migration impact for current users).
Defaults target banjo-utils' HealthCheckMiddleware endpoints
(/healthz/live/, /healthz/ready/). Tuning budgets:
- liveness: 20s × 6 = 120s wedge budget (restart is dangerous; converge
conservatively).
- readiness: 10s × 6 = 60s endpoint-drop budget (endpoint flap is cheap;
pull sick pods out of rotation fast).
- startup: 5s × 30 = 150s cold-boot budget; mirrors readiness path so the
same pod-local endpoint serves both.
Schema is k8s-native passthrough (toYaml the whole probe block), with
{{- with }} skipping any block set to null. Switching handler or skipping
a single probe via overlay needs --set api.probes.<probe>=null because
Helm -f overlays cannot remove default keys via explicit null
(helm/helm#9136); values.yaml comments document the workaround.
Tests cover: default-off skips all three probe keys, defaults render
with expected paths/thresholds, single-knob override deep-merges
through, nulling a probe block skips just that probe, custom path
merges with default port, oneOf deep-merge gotcha (httpGet + tcpSocket
both render — apiserver rejects, must null), and the supported
handler-switch via httpGet=null.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Wire jobTemplate.spec.ttlSecondsAfterFinished from cronjobs.defaults or a per-job override for age-based GC of finished Jobs (and their pods). Defaults to 7 days (604800s); set cronjobs.defaults.ttlSecondsAfterFinished to null to disable globally and fall back to count-based history limits. Note: Helm strips null leaves on values merge, so a per-job null inherits the default rather than disabling — disable globally, then opt jobs back in with a positive override. Regenerated values-2 render snapshot. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add volumes/volumeMounts to worker queueDefaults/queues and addonDefaults/addons, keyed by name. Dict form merges defaults with per-item by name (item wins); array form wholesale-resets, matching the queues/addons idiom. New banjo.namedListConfig helper resolves the merge and delegates to banjo.dictOrArray for name injection. appDefaultVolumes/appDefaultVolumeMounts now take (Context, Extra) and concatenate the per-workload list after the CSI volume + podVolumes. Output is byte-identical when no per-workload volumes are set. Serves the optional RAM-backed emptyDir heartbeat mount for the banjo-utils celery probe, scoped to workers/beat instead of leaking onto api/flower via the global podVolumes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… addons Add an opt-in probes block to worker queueDefaults/queues and addonDefaults/addons, mirroring the api.probes passthrough: a new banjo.probesConfig helper merges defaults with per-item (item wins) and, when enabled, renders livenessProbe/readinessProbe/startupProbe verbatim. Replaces the # TODO: livenessProbe placeholder in the worker template and adds the same to worker-addons. Intended for banjo-utils' banjo-celery-probe exec probe (heartbeat-file liveness for the non-HTTP worker and beat processes); values.yaml ships commented examples for the worker and beat variants. Renders nothing when unset, so defaults stay byte-identical apart from dropping the placeholder comment. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a Deployment strategy passthrough to worker queueDefaults/queues and
addonDefaults/addons so the beat addon can set strategy: {type: Recreate}
and never run two schedulers during a rolling update (duplicate beats fire
duplicate scheduled tasks).
Whole-block coalesce (per-item replaces defaults entirely), NOT a deep
merge — Recreate and rollingUpdate are mutually exclusive, so merging a
RollingUpdate default with a per-item Recreate would emit an invalid spec.
Default omitted preserves k8s RollingUpdate; renders byte-identical when unset.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a plain terminationGracePeriodSeconds integer passthrough to worker queueDefaults/queues and addonDefaults/addons, sized to the longest task so celery's SIGTERM warm shutdown can drain in-flight work. No preStop sleep — workers are non-HTTP, so the api's endpoint-drain dance does not apply. Coalesce (per-item wins, else defaults); default omitted preserves the k8s 30s default and renders byte-identical when unset. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Make the worker queue and beat examples uncomment-and-go: a user uncomments the block, sets their app module (myapp), and gets a working worker/beat with a banjo-celery-probe liveness, the BANJO_CELERY_HEARTBEAT_FILE env, the RAM emptyDir, and (for beat) strategy: Recreate — all internally consistent. - queues.default and addons.beat are now self-contained examples carrying the full heartbeat wiring (env + volume + volumeMount + probes). - Trim queueDefaults.probes prose to a pointer at the queues.default example, and drop the duplicate commented probe block that would collide with the active extraEnv/volumes/volumeMounts keys on uncomment. Comment-only change: no rendered output changes, snapshots untouched. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Deploy banjo-helm + banjo-alpha-deps as one multi-source ArgoCD app with a
single startup-ordering contract:
wave 0 : deps (tcpg/dragonfly/minio) — regular Sync resources in
banjo-alpha-deps, gated by their own readiness probes (no annotation)
wave 10 : hooks.jobs.wait-for-resources (argocd hook: Sync)
wave 20 : hooks.jobs.db-migrate, collect-static (argocd hook: Sync)
wave 30 : api, worker (all queues), worker.addons (incl. beat), api.ingress
Hooks are Sync (not PreSync — would deadlock before deps are applied; not
PostSync — would run after api is already serving). App workloads are pushed up
to wave 30 so the deps subcharts stay unannotated.
Implementation:
- chart/values.yaml: hooks flipped PostSync->Sync; wait-for-resources enabled by
default. The wave-30 default is a normal resource-level annotation, not a
custom scalar: api.deploymentAnnotations, worker.queueDefaults.deploymentAnnotations,
worker.addonDefaults.deploymentAnnotations, and api.ingress.annotations each
default to {argocd.argoproj.io/sync-wave: "30"}. deploymentAnnotations is the
resource-level surface, distinct from the pod-level annotations on the same
components.
- _helpers.tpl banjo.appDefaultDeploymentAnnotations: merges a passed Annotations
map with the reloader default (passed keys win); api/worker/worker-addons pass
their merged deploymentAnnotations (per-item wins over the *Defaults map).
cronjobs are out of scope.
- api/ingress.yaml: renders api.ingress.annotations directly.
- helm-unittest suite updated/extended; 131 tests green.
BREAKING CHANGE: api/worker/beat are now gated behind hooks at sync-wave 30 and
no longer start until the wave-10/20 hooks succeed. Hooks run in the Sync phase
instead of PostSync. wait-for-resources is enabled by default and requires the
wait_for_resources management command from banjo-utils — disable it
(hooks.jobs.wait-for-resources.enabled: false) if your image lacks it. The wave
is set via the resource-level *.deploymentAnnotations / api.ingress.annotations
defaults; override those maps to change or drop it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add hooks.jobs.<name>.files: a per-job map of filename -> content rendered into a ConfigMap and mounted into that hook's pod, so a job can run e.g. `sh -c "./manage.py shell < /etc/hook-files/seed.py"`. The files ConfigMap (named <fullname>-<jobName>-files) inherits the job's argocd hook + sync-wave annotations and forces hook-delete-policy: BeforeHookCreation so content is applied fresh alongside the Job every sync. Mount path defaults to /etc/hook-files, overridable per job via filesMountPath. The volume uses a constant name (hook-files) to stay within the 63-char volume-name limit while the ConfigMap carries the unique 253-bounded name. Render-time validations fail fast with clear messages: lowercase RFC 1123 job name, absolute filesMountPath, ConfigMap name <= 253, and valid ConfigMap file keys. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.