Skip to content

feat(operator): add LimitRange defaults for Cluster Autoscaler bin-packing#1040

Merged
Gkrumbach07 merged 1 commit intoambient-code:mainfrom
chambridge:fix/limitrange-default-requests
Mar 26, 2026
Merged

feat(operator): add LimitRange defaults for Cluster Autoscaler bin-packing#1040
Gkrumbach07 merged 1 commit intoambient-code:mainfrom
chambridge:fix/limitrange-default-requests

Conversation

@chambridge
Copy link
Copy Markdown
Contributor

Add LimitRange objects with defaultRequest values to both the platform namespace (static YAML manifest) and project namespaces (dynamically created by the operator during ProjectSettings reconciliation). This ensures containers without explicit resource requests receive a non-zero scheduling footprint, which is critical for Cluster Autoscaler bin-packing accuracy on ROSA.

Changes:

  • Static LimitRange manifest for the platform namespace (250m CPU, 256Mi memory defaultRequest; 2 CPU, 4Gi memory default limit)
  • ensureLimitRange() in ProjectSettings reconciler for dynamic per-project namespace creation with OwnerReference lifecycle
  • Extracted buildOwnerRef() helper to reduce duplication between ensureLimitRange() and ensureSessionTriggerRBAC()
  • RBAC: granted operator limitranges get/create permissions
  • Three unit tests: creation, idempotency, multi-namespace isolation

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 25, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 51217de0-bd61-4dec-b4a3-628bde8a3e33

📥 Commits

Reviewing files that changed from the base of the PR and between 84ec8ac and 522f0b3.

📒 Files selected for processing (6)
  • components/manifests/base/core/kustomization.yaml
  • components/manifests/base/core/limitrange.yaml
  • components/manifests/base/crds/projectsettings-crd.yaml
  • components/manifests/base/rbac/operator-clusterrole.yaml
  • components/operator/internal/handlers/projectsettings.go
  • components/operator/internal/handlers/projectsettings_test.go

Walkthrough

Adds a LimitRange resource and registers it in kustomize; grants operator RBAC for limitranges; reconciler ensures per-namespace LimitRanges and updates status.limitRangeReady; CRD status schema and status subresource added; unit tests for ensureLimitRange included.

Changes

Cohort / File(s) Summary
Kustomize / Core Manifests
components/manifests/base/core/limitrange.yaml, components/manifests/base/core/kustomization.yaml
Add LimitRange manifest ambient-default-limits (container defaultRequest: cpu=250m, memory=256Mi; default: cpu="2", memory=4Gi) and include it in kustomize resources.
RBAC
components/manifests/base/rbac/operator-clusterrole.yaml
Add ClusterRole rule granting get and create on core limitranges.
Operator logic
components/operator/internal/handlers/projectsettings.go
Add ensureLimitRange(namespace, obj) to reconciliation, introduce buildOwnerRef helper, set status.limitRangeReady, and refactor RBAC ownerRef usage; LimitRange creation failures are non-fatal for status.
Unit tests
components/operator/internal/handlers/projectsettings_test.go
Add tests for ensureLimitRange: creation, idempotency, and multiple-namespace behavior.
CRD
components/manifests/base/crds/projectsettings-crd.yaml
Add status.limitRangeReady: boolean to ProjectSettings status schema and enable subresources.status.

Sequence Diagram

sequenceDiagram
    participant Reconciler as ProjectSettingsReconciler
    participant Handler as ensureLimitRange
    participant KubeAPI as Kubernetes API
    participant CR as ProjectSettings CR

    Reconciler->>Handler: ensureLimitRange(namespace, owner)
    Handler->>KubeAPI: GET LimitRange "ambient-default-limits" in namespace
    alt exists
        KubeAPI-->>Handler: returns LimitRange
        Handler->>CR: mark status.limitRangeReady = true
    else not found
        KubeAPI-->>Handler: NotFound
        Handler->>Handler: build LimitRange manifest (defaults + ownerRef)
        Handler->>KubeAPI: CREATE LimitRange
        KubeAPI-->>Handler: created
        Handler->>CR: mark status.limitRangeReady = true
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and specifically describes the main change: adding LimitRange defaults for Cluster Autoscaler bin-packing in the operator.
Description check ✅ Passed The description is directly related to the changeset, detailing the LimitRange additions, reconciler changes, RBAC updates, and unit tests.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@components/operator/internal/handlers/projectsettings.go`:
- Around line 153-158: The code currently treats ensureLimitRange(namespace,
obj) failures as non-fatal by setting limitRangeReady = false and continuing;
change this to fail the reconcile immediately so missing/failed LimitRange
reconciliation is reported as an error. Locate the block using ensureLimitRange,
limitRangeReady, namespace and obj in projectsettings.go and replace the
non-fatal branch with an immediate return of the error (or wrap and return a
descriptive error) so the reconcile reports failure when ensureLimitRange
returns an error.
- Around line 222-225: The current create-only logic in the LimitRange creation
block (call to config.K8sClient.CoreV1().LimitRanges(namespace).Create with
lrName and namespace) treats AlreadyExists as success and skips reconciliation;
change it to detect errors.IsAlreadyExists(err) and then fetch the existing
LimitRange (using the same LimitRanges(namespace).Get), compare the
spec/labels/ownerReferences against the desired lr, and if they differ perform
an Update (LimitRanges(namespace).Update) to reconcile fields (or Patch as
appropriate) so pre-existing ambient-default-limits with drifted values are
corrected; ensure you preserve resourceVersion when updating and log or return
errors from Get/Update operations.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: b0fa6d5e-4f4b-43e8-8c03-f849cd69ef0b

📥 Commits

Reviewing files that changed from the base of the PR and between f715e39 and 43fb809.

📒 Files selected for processing (5)
  • components/manifests/base/core/kustomization.yaml
  • components/manifests/base/core/limitrange.yaml
  • components/manifests/base/rbac/operator-clusterrole.yaml
  • components/operator/internal/handlers/projectsettings.go
  • components/operator/internal/handlers/projectsettings_test.go

@chambridge chambridge force-pushed the fix/limitrange-default-requests branch from 43fb809 to 5e542eb Compare March 25, 2026 21:42
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@components/operator/internal/handlers/projectsettings.go`:
- Around line 160-165: The ProjectSettings controller writes
statusUpdate["limitRangeReady"] (limitRangeReady) but the CRD schema for
ProjectSettings doesn't declare this status property, so the apiserver prunes
it; update the ProjectSettings CRD schema to include a boolean status property
named limitRangeReady (with an appropriate description) under status.properties
so UpdateStatus will persist this field; ensure the CRD validation type matches
the controller (boolean) and regenerate/apply the CRD manifest so the
controller's statusUpdate map can store limitRangeReady durably.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 881cbd46-7f38-4d02-b09f-006e1594f0da

📥 Commits

Reviewing files that changed from the base of the PR and between 43fb809 and 5e542eb.

📒 Files selected for processing (5)
  • components/manifests/base/core/kustomization.yaml
  • components/manifests/base/core/limitrange.yaml
  • components/manifests/base/rbac/operator-clusterrole.yaml
  • components/operator/internal/handlers/projectsettings.go
  • components/operator/internal/handlers/projectsettings_test.go

@chambridge chambridge force-pushed the fix/limitrange-default-requests branch 2 times, most recently from 5d63dbe to 84ec8ac Compare March 25, 2026 23:43
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@components/manifests/base/core/limitrange.yaml`:
- Around line 11-16: Remove the hard `default` limits from the LimitRange
manifest and the operator code so only `defaultRequest` remains: delete the
`default` block in the YAML snippet (the cpu: "2" and memory: 4Gi entries) and
update the operator code in
components/operator/internal/handlers/projectsettings.go to stop
creating/injecting the `Default` limits (remove or conditionally omit the fields
set around the LimitRange creation at the block that sets Default CPU/Memory—the
code around lines that set Default.Limits/DefaultRequest). Ensure the manifest
and the operator-created LimitRange only include `defaultRequest` to avoid
imposing cluster-wide hard limits.

In `@components/manifests/base/crds/projectsettings-crd.yaml`:
- Around line 80-82: The CRD lacks the status subresource so ProjectSettings
status updates (e.g., via UpdateStatus in
components/operator/internal/handlers/projectsettings.go) will be ignored;
update the CRD version spec in projectsettings-crd.yaml to enable
subresources.status for the relevant version so that .status fields like
limitRangeReady are writable via the /status endpoint, ensuring the status
subresource is declared at the version level (not just the schema).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 974ec258-2f89-4ed9-a99c-40de0278a5af

📥 Commits

Reviewing files that changed from the base of the PR and between 5e542eb and 84ec8ac.

📒 Files selected for processing (6)
  • components/manifests/base/core/kustomization.yaml
  • components/manifests/base/core/limitrange.yaml
  • components/manifests/base/crds/projectsettings-crd.yaml
  • components/manifests/base/rbac/operator-clusterrole.yaml
  • components/operator/internal/handlers/projectsettings.go
  • components/operator/internal/handlers/projectsettings_test.go

…cking

Add LimitRange objects with defaultRequest values to both the platform
namespace (static YAML manifest) and project namespaces (dynamically
created by the operator during ProjectSettings reconciliation). This
ensures containers without explicit resource requests receive a non-zero
scheduling footprint, which is critical for Cluster Autoscaler
bin-packing accuracy on ROSA.

Changes:
- Static LimitRange manifest for the platform namespace (250m CPU,
  256Mi memory defaultRequest; 2 CPU, 4Gi memory default limit)
- ensureLimitRange() in ProjectSettings reconciler for dynamic
  per-project namespace creation with OwnerReference lifecycle
- Extracted buildOwnerRef() helper to reduce duplication between
  ensureLimitRange() and ensureSessionTriggerRBAC()
- RBAC: granted operator limitranges get/create permissions
- Three unit tests: creation, idempotency, multi-namespace isolation

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Chris Hambridge <chambrid@redhat.com>
@chambridge chambridge force-pushed the fix/limitrange-default-requests branch from 84ec8ac to 522f0b3 Compare March 26, 2026 00:12
@ambient-code ambient-code bot added this to the Review Queue milestone Mar 26, 2026
@Gkrumbach07 Gkrumbach07 merged commit bccd8c7 into ambient-code:main Mar 26, 2026
21 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