Skip to content

feat(infrastructure): template catalog hardening — worker + cron-job, honest redis knobs, tenant LimitRange#415

Merged
mjudeikis merged 1 commit into
mainfrom
feat/template-catalog-hardening
Jul 10, 2026
Merged

feat(infrastructure): template catalog hardening — worker + cron-job, honest redis knobs, tenant LimitRange#415
mjudeikis merged 1 commit into
mainfrom
feat/template-catalog-hardening

Conversation

@mjudeikis

Copy link
Copy Markdown
Contributor

Batch one of the template-catalog review (follow-up to #414), aimed at two personas: simple developers (coverage gaps) and enterprise actors (resource honesty + bounds).

redis-cache v0.2.0 — make the knobs honest

The size input claimed to "pick the memory limit" but the StatefulSet set no resources at all, and persistent was accepted while no PVC existed — two silent no-ops. Now:

  • size wires the container memory request+limit (64Mi/256Mi/1Gi) and redis --maxmemory (~25% under the limit, allkeys-lru) so a full cache evicts instead of OOM-killing.
  • persistent is removed; the template is explicitly an ephemeral cache ("never a system of record" in the agent guidance).
  • Portal view block added.

New: worker template

One container running forever — no Service, no route, no URL. Queue consumers, bots, pollers. Development-capable (single component claiming the workspace root, node toolchain, full sync/restart/log/env data plane); image required in production only, same CEL pattern as simple-webapp. Fills the "my app doesn't serve HTTP" gap that previously forced everything onto a web template.

New: cron-job template

A container on a 5-field cron schedule (instance kind ScheduledJob): concurrencyPolicy: Forbid, 3 retries, history limits. Deliberately no dev mode (the dev overlay supports Deployments only) — the agent contract says bake the task into the image entrypoint and exit 0.

Tenant LimitRange (noisy-neighbor bound)

No seed template pins its own CPU/memory, so tenant workloads on the shared runtime cluster were unbounded. EnsureTenantNamespace now stamps a create-only kedge-defaults LimitRange into every tenant namespace: defaultRequest 50m/128Mi, default limit 500m/512Mi, max 2cpu/2Gi per container.

  • Create-only: an operator-tuned copy is never overwritten.
  • Sits before the namespace cache store, so a provider restart retrofits pre-existing namespaces.
  • Opt out with KEDGE_TENANT_LIMITRANGE=disabled / chart tenantLimitRange.enabled: false for clusters that manage their own resource policy.

Smaller

  • database: portal view block (connection, version, readiness) instead of the raw values dump.
  • e2e: worker/simple-webapp dev instances are created without their image inputs to prove development mode needs none; dead e2eMinimalSpecs entries dropped (every seed template now ships sampleValues).

Verification

  • Unit: new kro package tests pin the LimitRange stamp, the never-overwrite rule, and the opt-out; full go test ./..., go vet, and helm lint/helm template pass.
  • Full local kind e2e (make e2e-infrastructure): all six seed templates apply; worker passes both production and development sweeps.

Follow-ups from the review, not in this PR: external/BYO database mode on application, python dev toolchain, api-service template, internal-only exposure, object storage.

🤖 Generated with Claude Code

… honest redis knobs, tenant LimitRange

Batch one of the catalog review, aimed at simple developers (coverage
gaps) and enterprise actors (resource honesty + bounds):

- redis-cache (v0.2.0): the size knob claimed to pick a memory limit
  but the StatefulSet set no resources, and persistent was accepted
  while no PVC existed — two silent no-ops. size is now wired to the
  container memory request+limit (64Mi/256Mi/1Gi) AND redis maxmemory
  (~25% under the limit, allkeys-lru) so a full cache evicts instead of
  OOM-killing; persistent is removed — the template is explicitly an
  ephemeral cache. Portal view + agent guidance updated to match.

- worker (new): one container running forever, no Service, no URL —
  queue consumers, bots, pollers. Development-capable: single component
  claiming the workspace root on the node toolchain, full data-plane
  verbs; image required in production only (the simple-webapp CEL
  pattern).

- cron-job (new): a container on a 5-field cron schedule (ScheduledJob
  instance kind) — Forbid concurrency, 3 retries, history limits. No
  dev mode by design (the dev overlay supports Deployments only); the
  agent contract says bake the task into the image entrypoint.

- Tenant LimitRange: every tenant namespace now gets a create-only
  "kedge-defaults" LimitRange (defaultRequest 50m/128Mi, default limit
  500m/512Mi, max 2cpu/2Gi per container) stamped by
  EnsureTenantNamespace — no seed template pins its own resources, so
  tenant workloads on the shared runtime cluster were unbounded.
  Create-only means operator-tuned copies are never overwritten; a
  provider restart retrofits pre-existing namespaces. Opt out with
  KEDGE_TENANT_LIMITRANGE=disabled (chart: tenantLimitRange.enabled).

- database: portal view block (connection, version, readiness) so it
  stops rendering as a raw values dump.

- e2e: worker/simple-webapp dev instances are created without their
  image inputs to prove dev mode needs none; dead e2eMinimalSpecs
  entries dropped (every seed template now ships sampleValues).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 10, 2026 18:34

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens the infrastructure provider’s template catalog by (1) making template inputs reflect real runtime behavior (not silent no-ops), (2) expanding the catalog to cover common workload shapes (background workers + scheduled jobs), and (3) enforcing a baseline tenant resource policy in runtime namespaces via a create-only LimitRange.

Changes:

  • Stamp a create-only kedge-defaults LimitRange into each tenant namespace (with an env/chart opt-out) and add unit tests for the behavior.
  • Add new worker and cron-job seed templates, and improve portal presentation blocks for existing templates (e.g., redis-cache/database).
  • Update infra-provider e2e coverage to reflect dev-mode behavior (instances created without image fields) and simplify minimal-spec plumbing.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
providers/infrastructure/kro/namespace.go Adds tenant LimitRange stamping during tenant namespace ensure.
providers/infrastructure/kro/namespace_test.go Unit tests for LimitRange creation, idempotency (never overwrite), and opt-out.
providers/infrastructure/install/templates/worker.yaml New development-capable “worker” template (no Service/URL), plus data plane verbs for dev mode.
providers/infrastructure/install/templates/cron-job.yaml New “cron-job” template (CronJob-only, no dev mode) with schedule surfaced in status/view.
providers/infrastructure/install/templates/redis-cache.yaml Makes size behavior “honest” by wiring resources + Redis maxmemory/eviction; removes persistence knob; adds portal view fields.
providers/infrastructure/install/templates/database.yaml Adds portal view detail/columns for connection/version/readiness.
providers/infrastructure/deploy/chart/values.yaml Adds tenantLimitRange.enabled chart value (default true).
providers/infrastructure/deploy/chart/templates/deployment.yaml Wires chart opt-out into KEDGE_TENANT_LIMITRANGE=disabled env var.
providers/infrastructure/backend/kro/e2e_test.go Removes now-unused minimal specs map content (but comment needs update).
providers/infrastructure/backend/kro/e2e_devmode_test.go Extends dev-mode e2e coverage to strip image for simple-webapp and worker.

- name: KEDGE_GATEWAY_NAMESPACE
value: {{ . | quote }}
{{- end }}
{{- if not .Values.tenantLimitRange.enabled }}
Comment on lines 82 to +84
// e2eMinimalSpecs supplies a valid instance spec for templates that ship no
// sampleValues (those that do — application, database — use them directly).
var e2eMinimalSpecs = map[string]map[string]any{
"redis-cache": {"name": "e2e-redis"},
}
var e2eMinimalSpecs = map[string]map[string]any{}
@mjudeikis mjudeikis merged commit 960f90e into main Jul 10, 2026
22 checks passed
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.

2 participants