GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — feat: detect dependent resource API version changes by exijn · Pull Request #3536 · operator-framework/java-operator-sdk

Conversation

@exijn

@exijn exijn commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add an opt-in, experimental detectApiVersionChange option on @KubernetesDependent to detect when a dependent resource's API version has changed since the operator last applied it, and request a one-time update in that case.
  • Record the API version the operator applies in the javaoperatorsdk.io/last-applied-api-version annotation, following the same pattern as the existing javaoperatorsdk.io/previous annotation.
  • Reuse the existing matching machinery (both SSA-based and non-SSA) to compare the marker instead of adding special-case matcher logic, so behavior is consistent across both paths.
  • Default behavior is unchanged: the feature is disabled by default and no marker annotation is ever added or read unless explicitly enabled.

Motivation

When a dependent resource's CRD gains a new API version and the operator is upgraded to target it, comparing actualResource.getApiVersion() with the desired resource's API version is not a reliable way to detect resources that still need to be updated: the Kubernetes API server serves a resource using the requested, served API version regardless of what it is actually stored as, so this comparison would always trivially match. This is why KubernetesDependentResource already ignores apiVersion entirely in both matchers.

Instead of trying to infer the actual stored/storage version (which JOSDK cannot reliably observe, and which tools like StorageVersionMigration exist to address), this PR lets JOSDK track what the operator itself last applied, using a persistent annotation marker, discussed in #2644.

When detectApiVersionChange is enabled:

  • On every create/update/match, the target (desired) resource is marked with the API version the operator is currently using.
  • The existing matcher (SSA or non-SSA) naturally detects a mismatch when the actual resource's recorded marker differs from - or is missing relative to - the desired marker, since it's just another annotation diff.
  • Once updated, the actual resource's marker matches the desired one again, so no further updates are triggered until the API version changes again.
  • This includes resources created before the feature was enabled: a missing marker is treated as a mismatch, causing a one-time update, after which matching succeeds normally.

This is explicitly not a replacement for Kubernetes' StorageVersionMigration and does not attempt to read or infer the actual stored representation of the resource.

Public API

  • New @KubernetesDependent(detectApiVersionChange = true) annotation attribute (default false), marked @Experimental.
  • New KubernetesDependentResourceConfig#detectApiVersionChange() and a new (additive) constructor overload; existing constructors are unchanged.
  • New KubernetesDependentResourceConfigBuilder#withDetectApiVersionChange(boolean).
  • New KubernetesDependentResource.LAST_APPLIED_API_VERSION_ANNOTATION_KEY constant (javaoperatorsdk.io/last-applied-api-version).

No breaking changes.

Testing

  • ./mvnw -pl operator-framework-core -am test -Dtest='KubernetesDependentResourceApiVersionChangeTest,KubernetesDependentConverterTest'
  • ./mvnw -pl operator-framework-core -am test -Dtest='GenericKubernetesResourceMatcherTest,SSABasedGenericKubernetesResourceMatcherTest,KubernetesDependentResourceTest,DependentResourceConfigurationResolverTest'
  • ./mvnw -pl operator-framework-core -am test (full core module, 706 tests)
  • ./mvnw spotless:apply / ./mvnw spotless:check
  • ./mvnw clean install -pl '!migration' (the migration module's OpenRewrite-based tests fail in this environment due to a pre-existing JDK 25 / OpenRewrite javac-internals incompatibility, unrelated to this change and not touched by it)

Fixes #2644

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

csviri reacted with thumbs up emoji csviri reacted with heart emoji
All reactions
  • 👍 1 reaction
  • ❤️ 1 reaction
Copilot AI review requested due to automatic review settings August 3, 2026 17:23
@openshift-ci
openshift-ci Bot requested review from csviri and metacosm August 3, 2026 17:23
@exijn
feat: detect dependent resource API version changes
f0530e1
Add an opt-in, experimental detectApiVersionChange option on
@KubernetesDependent that records the API version the operator applies
in the javaoperatorsdk.io/last-applied-api-version annotation. The
regular matcher then detects a mismatch when that marker differs from
(or is missing relative to) the currently applied API version, causing
a one-time update without triggering repeated reconciliations once the
resource is up-to-date. Disabled by default, so existing behavior and
matching are unaffected unless explicitly enabled.

Fixes operator-framework#2644

Signed-off-by: hej090224 <[email protected]>
@exijn
exijn force-pushed the feat/2644-dependent-api-version-update branch from d322648 to f0530e1 Compare August 3, 2026 17:33
Copilot AI reviewed Aug 3, 2026
View reviewed changes

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Adds an opt-in, experimental mechanism for dependent resources to detect API version changes by persisting the operator-applied API version in an annotation, so the existing matcher logic can trigger a one-time update when that marker changes.

Changes:

  • Introduces detectApiVersionChange on @KubernetesDependent, plus config + builder wiring to propagate the flag.
  • Adds javaoperatorsdk.io/last-applied-api-version marker annotation support in KubernetesDependentResource.
  • Adds focused unit tests and documentation covering both SSA and non-SSA matcher behavior.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java Adds marker annotation constant and writes marker when feature enabled.
operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfig.java Adds config flag, default, constructor overload, and getter.
operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfigBuilder.java Adds builder support for detectApiVersionChange.
operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentConverter.java Wires annotation attribute into config creation.
operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependent.java Adds experimental annotation attribute and documentation.
operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceApiVersionChangeTest.java New tests validating marker-driven mismatch behavior for SSA and non-SSA.
operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentConverterTest.java New focused test for annotation→config wiring for the new flag.
docs/content/en/docs/documentation/dependent-resource-and-workflows/dependent-resources.md Documents the new experimental feature and its behavior/limitations.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread ...io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java
Comment on lines +195 to +207
private void addLastAppliedApiVersion(R target) {
if (kubernetesDependentResourceConfig == null
|| !kubernetesDependentResourceConfig.detectApiVersionChange()) {
return;
}
var apiVersion = target.getApiVersion();
if (apiVersion != null) {
target
.getMetadata()
.getAnnotations()
.put(LAST_APPLIED_API_VERSION_ANNOTATION_KEY, apiVersion);
}
}

@exijn exijn Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Fixed in aacbb4b: the desired resource's annotations map is now defensively copied into a mutable LinkedHashMap (via ensureMutableAnnotations) whenever detectApiVersionChange is enabled, before this method or the pre-existing previous-annotation bookkeeping write to it. This is scoped to the opt-in feature so default behavior for everyone else is unchanged. Added a regression test (nonSSA_preservesExistingAnnotationsWhenMarkingEvenIfImmutable) that sets an immutable Map.of(...) on the desired resource and asserts both the existing entry and the new marker survive.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread ...io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java
Comment on lines +195 to +207
private void addLastAppliedApiVersion(R target) {
if (kubernetesDependentResourceConfig == null
|| !kubernetesDependentResourceConfig.detectApiVersionChange()) {
return;
}
var apiVersion = target.getApiVersion();
if (apiVersion != null) {
target
.getMetadata()
.getAnnotations()
.put(LAST_APPLIED_API_VERSION_ANNOTATION_KEY, apiVersion);
}
}

@exijn exijn Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Added nonSSA_preservesExistingAnnotationsWhenMarkingEvenIfImmutable in aacbb4b, which sets an immutable Map.of("user.example.com/owner", "team-a") as the desired resource's annotations, then asserts the marker is added and the pre-existing entry is preserved. This also caught that the pre-existing previous-annotation handling code had the same latent assumption, which is now fixed alongside it (see the other reply).

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread ...perator/processing/dependent/kubernetes/KubernetesDependentResourceApiVersionChangeTest.java Outdated
Comment on lines +313 to +318
private static class ConfigMapDependentResourceForTest
extends KubernetesDependentResource<GenericKubernetesResource, HasMetadata> {
public ConfigMapDependentResourceForTest() {
super(GenericKubernetesResource.class, null);
}
}

@exijn exijn Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Renamed to WidgetDependentResourceForTest in aacbb4b — good catch, it does manage a GenericKubernetesResource (a synthetic "Widget" test resource), not a ConfigMap.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread ...perator/processing/dependent/kubernetes/KubernetesDependentResourceApiVersionChangeTest.java
Comment on lines +178 to +182
var result = dr.match(actual, desired, primary(), context);

assertThat(result.matched()).isNotNull();
assertThat(desired.getMetadata().getAnnotations())
.doesNotContainKey(KubernetesDependentResource.LAST_APPLIED_API_VERSION_ANNOTATION_KEY);

@exijn exijn Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Fixed in aacbb4b — replaced with assertThat(result.matched()).withFailMessage(...).isTrue(), asserting the concrete expected outcome (a null desired API version just skips marking, and matching proceeds normally) instead of the no-op null check.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread ...in/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependent.java Outdated
Comment on lines +75 to +77
* <p>When enabled, JOSDK records the API version it applies in the {@code
* javaoperatorsdk.io/last-applied-api-version} annotation. On subsequent reconciliations, the
* resource is considered mismatched (and thus updated) if that recorded marker differs from the

@exijn exijn Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Fixed in aacbb4b — the Javadoc now references {@value KubernetesDependentResource#LAST_APPLIED_API_VERSION_ANNOTATION_KEY} instead of duplicating the string literal.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Copilot started reviewing on behalf of exijn August 3, 2026 17:39
View session
@exijn
fix: ensure mutable annotations map when marking API version
aacbb4b
Guard against a null or immutable annotations map (e.g. Map.of(...))
on the desired resource when detectApiVersionChange is enabled, since
writing the last-applied-api-version marker (and the pre-existing
previous-annotation bookkeeping that runs alongside it) requires a
mutable map. Also rename a misleadingly-named test helper and replace
a no-op assertion on a primitive boolean with a concrete expectation.

Addresses Copilot review feedback on PR operator-framework#3536.

Signed-off-by: hej090224 <[email protected]>
@csviri

csviri commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

@xstefank @metacosm could you review this one pls, I'm quite busy next couple of days.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@csviri
csviri requested a review from xstefank August 4, 2026 08:25
xstefank
xstefank approved these changes Aug 5, 2026
View reviewed changes

@xstefank xstefank left a comment

Copy link
Copy Markdown
Collaborator

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

nice idea, thanks

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
csviri
csviri requested changes Aug 7, 2026
View reviewed changes

@csviri csviri left a comment

Copy link
Copy Markdown
Collaborator

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Hi @hej090224 , looks good to me, one additional things that we do for feature is an integration test for the happy flow, could you please add also that?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@csviri csviri linked an issue Aug 7, 2026 that may be closed by this pull request
CRUDKubernetesDependentResource should update dependent resource on API version update #2644
Closed
@exijn @claude
test: add integration test for detectApiVersionChange happy flow
fa58bee
Add DetectApiVersionChangeIT covering the end-to-end scenario: a
ConfigMap dependent resource configured with detectApiVersionChange
is marked with the current API version on creation (without
triggering an update), and a stale marker annotation left on the
actual resource (simulating an older operator/CRD version) is
detected and corrected with exactly one update, after which no
further reconciliation loop occurs.

Addresses review feedback from @csviri on PR operator-framework#3536 requesting an
integration test for the happy flow.

Signed-off-by: hej090224 <[email protected]>

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CZnZDCv3jGtQxWe7LyXPDN
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 29156909-8388-400e-b65f-3c21e591a0eb

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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
  • X
  • Mastodon
  • Reddit
  • LinkedIn

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

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@exijn

exijn commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

@csviri Added an integration test for the happy flow in fa58bee: DetectApiVersionChangeIT.

It covers the end-to-end scenario against a real cluster:

  • On creation, the ConfigMap dependent is marked with the current API version (javaoperatorsdk.io/last-applied-api-version) without triggering an update.
  • A stale marker left on the actual resource (simulating one applied by an older operator/CRD version) is detected and corrected with exactly one update.
  • No further updates/reconciliation loop occur once the marker is up to date again.

Let me know if you'd like additional scenarios covered (e.g. SSA path) as a follow-up.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

csviri
csviri approved these changes Aug 11, 2026
View reviewed changes

@csviri csviri left a comment

Copy link
Copy Markdown
Collaborator

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

LGTM, awesome! thank you @hej090224

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@csviri
csviri merged commit d4bd3da into operator-framework:next Aug 11, 2026
29 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@csviri csviri mentioned this pull request Aug 11, 2026
test: sample for virtual threads #3554
Closed
csviri pushed a commit that referenced this pull request Aug 28, 2026
@exijn @claude @csviri
feat: detect dependent resource API version changes (#3536)
2740cf6
Add an opt-in, experimental detectApiVersionChange option on
@KubernetesDependent that records the API version the operator applies
in the javaoperatorsdk.io/last-applied-api-version annotation. The
regular matcher then detects a mismatch when that marker differs from
(or is missing relative to) the currently applied API version, causing
a one-time update without triggering repeated reconciliations once the
resource is up-to-date. Disabled by default, so existing behavior and
matching are unaffected unless explicitly enabled.

Guard against a null or immutable annotations map (e.g. Map.of(...))
on the desired resource when detectApiVersionChange is enabled, since
writing the last-applied-api-version marker (and the pre-existing
previous-annotation bookkeeping that runs alongside it) requires a
mutable map. Also rename a misleadingly-named test helper and replace
a no-op assertion on a primitive boolean with a concrete expectation.

Addresses Copilot review feedback on PR #3536.

Add DetectApiVersionChangeIT covering the end-to-end scenario: a
ConfigMap dependent resource configured with detectApiVersionChange
is marked with the current API version on creation (without
triggering an update), and a stale marker annotation left on the
actual resource (simulating an older operator/CRD version) is
detected and corrected with exactly one update, after which no
further reconciliation loop occurs.

Signed-off-by: hej090224 <[email protected]>
Co-authored-by: Claude Sonnet 5 <[email protected]>
csviri pushed a commit that referenced this pull request Sep 3, 2026
@exijn @claude @csviri
feat: detect dependent resource API version changes (#3536)
8251ce3
Add an opt-in, experimental detectApiVersionChange option on
@KubernetesDependent that records the API version the operator applies
in the javaoperatorsdk.io/last-applied-api-version annotation. The
regular matcher then detects a mismatch when that marker differs from
(or is missing relative to) the currently applied API version, causing
a one-time update without triggering repeated reconciliations once the
resource is up-to-date. Disabled by default, so existing behavior and
matching are unaffected unless explicitly enabled.

Guard against a null or immutable annotations map (e.g. Map.of(...))
on the desired resource when detectApiVersionChange is enabled, since
writing the last-applied-api-version marker (and the pre-existing
previous-annotation bookkeeping that runs alongside it) requires a
mutable map. Also rename a misleadingly-named test helper and replace
a no-op assertion on a primitive boolean with a concrete expectation.

Addresses Copilot review feedback on PR #3536.

Add DetectApiVersionChangeIT covering the end-to-end scenario: a
ConfigMap dependent resource configured with detectApiVersionChange
is marked with the current API version on creation (without
triggering an update), and a stale marker annotation left on the
actual resource (simulating an older operator/CRD version) is
detected and corrected with exactly one update, after which no
further reconciliation loop occurs.

Signed-off-by: hej090224 <[email protected]>
Co-authored-by: Claude Sonnet 5 <[email protected]>
csviri pushed a commit that referenced this pull request Sep 3, 2026
@exijn @claude @csviri
feat: detect dependent resource API version changes (#3536)
6bb9e39
Add an opt-in, experimental detectApiVersionChange option on
@KubernetesDependent that records the API version the operator applies
in the javaoperatorsdk.io/last-applied-api-version annotation. The
regular matcher then detects a mismatch when that marker differs from
(or is missing relative to) the currently applied API version, causing
a one-time update without triggering repeated reconciliations once the
resource is up-to-date. Disabled by default, so existing behavior and
matching are unaffected unless explicitly enabled.

Guard against a null or immutable annotations map (e.g. Map.of(...))
on the desired resource when detectApiVersionChange is enabled, since
writing the last-applied-api-version marker (and the pre-existing
previous-annotation bookkeeping that runs alongside it) requires a
mutable map. Also rename a misleadingly-named test helper and replace
a no-op assertion on a primitive boolean with a concrete expectation.

Addresses Copilot review feedback on PR #3536.

Add DetectApiVersionChangeIT covering the end-to-end scenario: a
ConfigMap dependent resource configured with detectApiVersionChange
is marked with the current API version on creation (without
triggering an update), and a stale marker annotation left on the
actual resource (simulating an older operator/CRD version) is
detected and corrected with exactly one update, after which no
further reconciliation loop occurs.

Signed-off-by: hej090224 <[email protected]>
Co-authored-by: Claude Sonnet 5 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

Copilot code review Copilot
Copilot review effort
Applies to this pull request for everyone.Learn more about Copilot code review.
Copilot left review comments
@csviri csviri csviri approved these changes
@xstefank xstefank xstefank approved these changes
@metacosm metacosm Awaiting requested review from metacosm

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

CRUDKubernetesDependentResource should update dependent resource on API version update

Uh oh!

There was an error while loading. Please reload this page.

4 participants

@exijn @csviri @xstefank
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.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.