Skip to content

chore!: remove interval field from resource CR#2091

Closed
frewilhelm wants to merge 6 commits into
open-component-model:mainfrom
frewilhelm:k8s-api-rm-res-interval
Closed

chore!: remove interval field from resource CR#2091
frewilhelm wants to merge 6 commits into
open-component-model:mainfrom
frewilhelm:k8s-api-rm-res-interval

Conversation

@frewilhelm

Copy link
Copy Markdown
Contributor

Summary

  • Remove the interval field from ResourceSpec and the GetRequeueAfter() method from the Resource type
  • Update the Resource and Deployer controllers to no longer requeue on a timer
  • Remove interval from the Resource CRD schema (base + Helm chart) and drop it from the required list
  • Clean up all tests, samples, examples, and documentation accordingly

Motivation

The interval field on the Resource API is redundant with the existing event-driven
reconciliation model. Unlike Repository and Component, the Resource controller does
not poll an external system directly. Its reconciliation is already triggered by:

  1. Spec changes — via the GenerationChangedPredicate on the Resource itself.
  2. Component updates — via a watch on the referenced Component object, which
    re-enqueues all Resources that reference it.
  3. Resolution completions — via the worker pool event source, which notifies
    the controller when an async resolution finishes.

The Component controller is the one that actually polls the OCM repository on its
own interval. When a new component version is discovered, the Component's status
update propagates through the watch chain: Component → Resource → Deployer. Adding
a separate polling interval on the Resource was therefore unnecessary overhead that
could also mask the true source of updates and make debugging harder.

Removing it makes the Resource controller purely reactive and aligns it with the
principle that only the outermost controllers (Repository, Component) that interact
with external systems should own polling intervals.

@frewilhelm frewilhelm requested a review from a team as a code owner March 27, 2026 15:42
@github-actions github-actions Bot added the kind/chore chore, maintenance, etc. label Mar 27, 2026
@coderabbitai

coderabbitai Bot commented Mar 27, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Removed the interval field from ResourceSpec and deleted the Resource.GetRequeueAfter() method; updated controllers to stop scheduling interval-based requeues and adjusted CRDs, examples, tests, and generated deepcopy code accordingly.

Changes

Cohort / File(s) Summary
API Type Definitions
kubernetes/controller/api/v1alpha1/resource_types.go
Deleted Interval metav1.Duration from ResourceSpec and removed func (in *Resource) GetRequeueAfter() time.Duration; removed unused time import.
Generated Code
kubernetes/controller/api/v1alpha1/zz_generated.deepcopy.go
Removed explicit out.Interval = in.Interval assignment in DeepCopyInto for ResourceSpec (struct copy covers field).
CRD Schemas
kubernetes/controller/chart/templates/crd/resources.delivery.ocm.software.yaml, kubernetes/controller/config/crd/bases/delivery.ocm.software_resources.yaml
Removed spec.interval property and removed interval from spec.required; shortened verificationPolicy.Always description text.
Controller Logic
kubernetes/controller/internal/controller/deployer/deployer_controller.go, kubernetes/controller/internal/controller/resource/resource_controller.go
Replaced interval-based requeue results with immediate ctrl.Result{} / fixed 0 delay; removed reliance on GetRequeueAfter() for follow-up reconciles and deferred status updates.
Tests
kubernetes/controller/internal/controller/deployer/deployer_controller_test.go, kubernetes/controller/internal/controller/resource/resource_controller_test.go
Removed Interval fields from test struct literals and removed time imports used only for those durations.
Samples & Testdata
kubernetes/controller/config/samples/resource.delivery.ocm.software_sample.yaml, kubernetes/controller/test/e2e/testdata/*/*, conformance/scenarios/*, kubernetes/controller/examples/*/*
Removed spec.interval entries from Resource manifests and ResourceGraphDefinition templates across examples, bootstrap files, and e2e/conformance testdata; minor whitespace/newline edits.
Conformance Scenario
conformance/scenarios/sovereign/components/product/deploy/rgd.yaml, conformance/scenarios/sovereign/deploy/bootstrap.yaml
Removed multiple interval entries in RGD templates and a trailing newline removal.

Sequence Diagram(s)

sequenceDiagram
  participant Controller
  participant Resource
  participant Status
  participant Workqueue

  rect rgba(200,200,255,0.5)
    Note over Controller: Old flow (before this PR)
    Controller ->> Resource: Reconcile()
    Controller ->> Resource: GetRequeueAfter()
    Resource -->> Controller: duration
    Controller ->> Status: MarkReady(...)
    Controller ->> Workqueue: RequeueAfter(duration)
  end

  rect rgba(200,255,200,0.5)
    Note over Controller: New flow (after this PR)
    Controller ->> Resource: Reconcile()
    Controller ->> Status: MarkReady(...)
    Controller --x Workqueue: (no interval-based requeue)
    Note over Workqueue: Subsequent reconciles rely on events/predicates
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested reviewers

  • Skarlso
  • fabianburth

Poem

🐰 I nibbled the interval, quiet and neat,
No more timed hops on the reconcile beat,
Controllers pause, events now call,
A hop, a sniff, and that’s all —
Carrots for tests and manifests complete.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'chore!: remove interval field from resource CR' clearly and specifically describes the main change: removing the interval field from the Resource custom resource.
Description check ✅ Passed The description comprehensively explains the removal of the interval field, the motivation, and the impact on controller behavior, directly relating to the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ 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.

@piotrjanik piotrjanik left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM, but isn't that a breaking change?

@github-actions github-actions Bot added the size/s Small label Mar 27, 2026
@frewilhelm frewilhelm changed the title chore: remove interval field from resource CR chore!: remove interval field from resource CR Mar 27, 2026
@github-actions github-actions Bot added the !BREAKING-CHANGE! Breaking change in API or ocm-cli or spec label Mar 27, 2026
@frewilhelm frewilhelm force-pushed the k8s-api-rm-res-interval branch from a22d401 to 590c923 Compare March 27, 2026 17:01

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
kubernetes/controller/internal/controller/deployer/deployer_controller.go (1)

373-377: ⚠️ Potential issue | 🟠 Major

Config and credential rotations lose their last enqueue path.

After this returns without requeueing, the controller is only driven by Deployer, Resource, worker-pool, and dynamic resource events. It still reloads effective OCM config during DownloadResourceWithOCM(), but none of the referenced Secret/ConfigMap/OCM config objects are watched here, so config or credential changes can leave the applied state stale until some unrelated event happens. Please add watches for those refs before removing the fallback requeue.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@kubernetes/controller/internal/controller/deployer/deployer_controller.go`
around lines 373 - 377, The controller currently returns without requeueing
after status.MarkReady(...) which removes the fall-back requeue and leaves
config/credential rotations un-watched; update the controller setup to add
watches for any Secret, ConfigMap and OCM config objects referenced by resources
so changes trigger reconciles before removing the fallback requeue—specifically
ensure the reconciler that calls DownloadResourceWithOCM() has Informers/Watch
registrations for the Secret and ConfigMap refs (and the OCM config resource)
and tie those watches to enqueue the corresponding Deployer/Resource reconcile
(or use EnqueueRequestForOwner) so rotations of credentials or config will
requeue the affected resource prior to deleting the existing requeue behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@kubernetes/controller/internal/controller/resource/resource_controller.go`:
- Around line 453-455: The controller removed periodic requeues but
SetupWithManager() still only watches Resource, Component, Deployer deletions
and the worker-pool source, so rotations/changes to referenced config/credential
objects (Secrets, ConfigMaps, OCM objects) won't enqueue Resources and Deployers
remain stale; update SetupWithManager() to add Watches (or field/index-based
event handlers) for the Resource's config/credential references and the
referenced Secret / ConfigMap / OCM types and create indices (e.g., via
mgr.GetFieldIndexer().IndexField) so changes to those objects map back to
affected Resource objects and enqueue reconcile requests for Resource (and
thereby Deployer) reconciliations, ensuring functions like SetupWithManager(),
and the controller's event handlers and indexing code for
Resource/Component/Deployer reflect these extra watches/indices.
- Around line 178-183: The deferred call currently hardcodes
status.UpdateBeforePatch(..., 0, err) which hides real retry intent; introduce a
local variable (e.g., requeueInt := 0) captured by the defer and set requeueInt
= 1 (or the appropriate positive value) in any retry branches (such as the
Requeue: true after finalizer installation and the "effective ocm config
changed" retry branches) before returning so status.UpdateBeforePatch(resource,
r.EventRecorder, requeueInt, err) reflects the real intent; alternatively, if
you prefer to suppress success events on retry, set a flag (e.g.,
suppressSuccessEvent) and pass that information to UpdateBeforePatch, but the
simplest fix is to thread and update a captured requeue integer and use it in
the deferred status.UpdateBeforePatch call.

---

Outside diff comments:
In `@kubernetes/controller/internal/controller/deployer/deployer_controller.go`:
- Around line 373-377: The controller currently returns without requeueing after
status.MarkReady(...) which removes the fall-back requeue and leaves
config/credential rotations un-watched; update the controller setup to add
watches for any Secret, ConfigMap and OCM config objects referenced by resources
so changes trigger reconciles before removing the fallback requeue—specifically
ensure the reconciler that calls DownloadResourceWithOCM() has Informers/Watch
registrations for the Secret and ConfigMap refs (and the OCM config resource)
and tie those watches to enqueue the corresponding Deployer/Resource reconcile
(or use EnqueueRequestForOwner) so rotations of credentials or config will
requeue the affected resource prior to deleting the existing requeue behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 29afa583-a1f1-452b-acd5-df9aa156c179

📥 Commits

Reviewing files that changed from the base of the PR and between a22d401 and 590c923.

📒 Files selected for processing (31)
  • kubernetes/controller/api/v1alpha1/resource_types.go
  • kubernetes/controller/api/v1alpha1/zz_generated.deepcopy.go
  • kubernetes/controller/chart/templates/crd/resources.delivery.ocm.software.yaml
  • kubernetes/controller/config/crd/bases/delivery.ocm.software_resources.yaml
  • kubernetes/controller/config/samples/resource.delivery.ocm.software_sample.yaml
  • kubernetes/controller/examples/applyset-pruning/bootstrap.yaml
  • kubernetes/controller/examples/helm-configuration-localization/bootstrap.yaml
  • kubernetes/controller/examples/helm-configuration-localization/rgd.yaml
  • kubernetes/controller/examples/helm-nested-signed/bootstrap.yaml
  • kubernetes/controller/examples/helm-nested-signed/rgd.yaml
  • kubernetes/controller/examples/helm-nested/bootstrap.yaml
  • kubernetes/controller/examples/helm-nested/rgd.yaml
  • kubernetes/controller/examples/helm-signing/bootstrap.yaml
  • kubernetes/controller/examples/helm-signing/rgd.yaml
  • kubernetes/controller/examples/helm-simple-nested-status/bootstrap.yaml
  • kubernetes/controller/examples/helm-simple-nested-status/rgd.yaml
  • kubernetes/controller/examples/helm-simple/bootstrap.yaml
  • kubernetes/controller/examples/helm-simple/rgd.yaml
  • kubernetes/controller/examples/k8s-manifest-simple/bootstrap.yaml
  • kubernetes/controller/examples/kustomize-configuration-localization/bootstrap.yaml
  • kubernetes/controller/examples/kustomize-configuration-localization/rgd.yaml
  • kubernetes/controller/examples/kustomize-simple/bootstrap.yaml
  • kubernetes/controller/examples/kustomize-simple/rgd.yaml
  • kubernetes/controller/internal/controller/deployer/deployer_controller.go
  • kubernetes/controller/internal/controller/deployer/deployer_controller_test.go
  • kubernetes/controller/internal/controller/resource/resource_controller.go
  • kubernetes/controller/internal/controller/resource/resource_controller_test.go
  • kubernetes/controller/test/e2e/testdata/basic-auth/bootstrap.yaml
  • kubernetes/controller/test/e2e/testdata/basic-auth/rgd.yaml
  • kubernetes/controller/test/e2e/testdata/docker-config-json/bootstrap.yaml
  • kubernetes/controller/test/e2e/testdata/docker-config-json/rgd.yaml
💤 Files with no reviewable changes (28)
  • kubernetes/controller/examples/helm-nested-signed/rgd.yaml
  • kubernetes/controller/examples/helm-signing/bootstrap.yaml
  • kubernetes/controller/examples/helm-simple-nested-status/bootstrap.yaml
  • kubernetes/controller/examples/helm-nested-signed/bootstrap.yaml
  • kubernetes/controller/examples/helm-simple/bootstrap.yaml
  • kubernetes/controller/examples/helm-signing/rgd.yaml
  • kubernetes/controller/examples/helm-configuration-localization/bootstrap.yaml
  • kubernetes/controller/config/crd/bases/delivery.ocm.software_resources.yaml
  • kubernetes/controller/examples/helm-nested/bootstrap.yaml
  • kubernetes/controller/examples/applyset-pruning/bootstrap.yaml
  • kubernetes/controller/examples/k8s-manifest-simple/bootstrap.yaml
  • kubernetes/controller/examples/helm-nested/rgd.yaml
  • kubernetes/controller/examples/helm-simple/rgd.yaml
  • kubernetes/controller/test/e2e/testdata/docker-config-json/bootstrap.yaml
  • kubernetes/controller/test/e2e/testdata/basic-auth/bootstrap.yaml
  • kubernetes/controller/examples/kustomize-configuration-localization/rgd.yaml
  • kubernetes/controller/config/samples/resource.delivery.ocm.software_sample.yaml
  • kubernetes/controller/examples/kustomize-simple/bootstrap.yaml
  • kubernetes/controller/internal/controller/deployer/deployer_controller_test.go
  • kubernetes/controller/test/e2e/testdata/docker-config-json/rgd.yaml
  • kubernetes/controller/examples/kustomize-configuration-localization/bootstrap.yaml
  • kubernetes/controller/examples/kustomize-simple/rgd.yaml
  • kubernetes/controller/api/v1alpha1/resource_types.go
  • kubernetes/controller/examples/helm-simple-nested-status/rgd.yaml
  • kubernetes/controller/internal/controller/resource/resource_controller_test.go
  • kubernetes/controller/test/e2e/testdata/basic-auth/rgd.yaml
  • kubernetes/controller/examples/helm-configuration-localization/rgd.yaml
  • kubernetes/controller/api/v1alpha1/zz_generated.deepcopy.go

Signed-off-by: Frederic Wilhelm <frederic.wilhelm@sap.com>
@frewilhelm frewilhelm force-pushed the k8s-api-rm-res-interval branch from 590c923 to 0e16c2a Compare March 27, 2026 17:29
@frewilhelm

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Mar 27, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Signed-off-by: Frederic Wilhelm <frederic.wilhelm@sap.com>
@frewilhelm

Copy link
Copy Markdown
Contributor Author

Currently, the Conformance test is failing but it is also passing. I believe the failure is because it does not use the Helm Chart build previously:
image

In comparison to the successful one where it downloads the chart artifact that was built previously (with the adjusted CRDs):
image

@matthiasbruns

Copy link
Copy Markdown
Contributor

do we need to update the conformance test with omit() ?
kubernetes-sigs/kro#1139

frewilhelm and others added 2 commits March 30, 2026 09:05
Signed-off-by: Frederic Wilhelm <frederic.wilhelm@sap.com>
@frewilhelm

Copy link
Copy Markdown
Contributor Author

do we need to update the conformance test with omit() ? kubernetes-sigs/kro#1139

I don't think so. The problem of the Conformance Test that ran without the "Kubernetes Controller" context is missing the adjusted CRDs. It take the default Helm Chart from our registry that does not have the changes yet.

The Conformance Test that is ran in the context of "Kubernetes Controller" is successful because it takes the Helm Chart that was build previously and is available as workflow artifact.

So, the problem is not the rgd. It is the Helm Chart that is taken for tests.

But when I think about this, we will always have a problem when we change the CRDs.

The Conformance test workflow triggered by the "Kubernetes Controller" workflow will expect the changed CRDs.

The Conformance test workflow triggered by changes in conformance/** will expect the version-pinned CRDs

@frewilhelm

Copy link
Copy Markdown
Contributor Author

After thinking about this, the single Conformance Test workflow should only run with the pinned versions. I probably broke the tests by changing something in conformance/** and now the workflow is in a failed state. I will recreate this PR without any changes in conformance/**, so the Conformance Test workflow is not run.

@frewilhelm frewilhelm closed this Mar 30, 2026
morri-son pushed a commit that referenced this pull request Mar 30, 2026
## Summary

- Remove the `interval` field from `ResourceSpec` and the
`GetRequeueAfter()` method from the `Resource` type
- Update the Resource and Deployer controllers to no longer requeue on a
timer
- Remove `interval` from the Resource CRD schema (base + Helm chart) and
drop it from the `required` list
- Clean up all tests, samples, examples, and documentation accordingly

## Motivation

The `interval` field on the Resource API is redundant with the existing
event-driven
reconciliation model. Unlike Repository and Component, the Resource
controller does
not poll an external system directly. Its reconciliation is already
triggered by:

1. **Spec changes** — via the `GenerationChangedPredicate` on the
Resource itself.
2. **Component updates** — via a watch on the referenced Component
object, which
   re-enqueues all Resources that reference it.
3. **Resolution completions** — via the worker pool event source, which
notifies
   the controller when an async resolution finishes.

The Component controller is the one that actually polls the OCM
repository on its
own interval. When a new component version is discovered, the
Component's status
update propagates through the watch chain: Component → Resource →
Deployer. Adding
a separate polling interval on the Resource was therefore unnecessary
overhead that
could also mask the true source of updates and make debugging harder.

Removing it makes the Resource controller purely reactive and aligns it
with the
principle that only the outermost controllers (Repository, Component)
that interact
with external systems should own polling intervals.

---

This is a replacement for
#2091
(see
[comment](#2091 (comment)))

Signed-off-by: Frederic Wilhelm <frederic.wilhelm@sap.com>
Co-authored-by: Fabian Burth <fabian.burth@sap.com>
@frewilhelm frewilhelm deleted the k8s-api-rm-res-interval branch March 30, 2026 11:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

!BREAKING-CHANGE! Breaking change in API or ocm-cli or spec kind/chore chore, maintenance, etc. size/s Small

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants