-
Notifications
You must be signed in to change notification settings - Fork 243
Comparing changes
Open a pull request
base repository: operator-framework/java-operator-sdk
base: main
head repository: operator-framework/java-operator-sdk
compare: next
- 18 commits
- 159 files changed
- 4 contributors
Commits on Aug 28, 2026
-
chore: set next version to 999-SNAPSHOT (#3469)
Signed-off-by: Attila Mészáros <a_meszaros@apple.com>
Configuration menu - View commit details
-
Copy full SHA for a04024a - Browse repository at this point
Copy the full SHA a04024aView commit details -
improve: integration test to showcase external resource state in stat…
…us (#3480) Add integration tests that showcases handling explicit state in status. Both for simple managed/secondary resources and using a dependent resource. Signed-off-by: Attila Mészáros <a_meszaros@apple.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Configuration menu - View commit details
-
Copy full SHA for cef3be3 - Browse repository at this point
Copy the full SHA cef3be3View commit details -
* feat: pool informers so controllers and event sources can share them Every InformerEventSource used to create its own SharedIndexInformer, so an operator whose controllers all watch the same secondary type - ConfigMap and Secret being the usual suspects - opened one watch connection and kept one cache per controller for the very same resources. Informers are now handed out by an InformerPool obtained from the ConfigurationService, keyed by an InformerClassifier. Event sources whose classifiers are equal are backed by one informer; the pool reference counts its users and stops the informer once the last one releases it. The classifier is made up of everything that decides what an informer watches and how: the KubernetesClient instance (compared by identity, since two clients for the same API server may still differ in credentials, impersonation or TLS material), the resource class or the group/version/kind for generic resources, the namespace, the label, field and shard selectors, and the item store. Two components are deliberately not part of that identity. The informerListLimit is excluded, so event sources that disagree only on it still share an informer, keeping the limit of whichever one created it and logging a warning. Indexers are excluded because they can be added to a running informer: they are registered under a name qualified with the controller and event source that added them, so index names stay private to an event source while callers keep using their own names, and they are removed again when that event source releases the informer. Two strategies ship: DefaultInformerPool shares as described and is the default, NonSharingInformerPool creates a dedicated informer per event source for anyone wanting to opt out. Either is selected with ConfigurationServiceOverrider#withInformerPool, and a custom strategy extends AbstractInformerPool, which already creates the informers from a classifier, starts them and waits for their caches to sync, leaving the subclass only the question of whether and when an informer is shared. Consequently informer creation and startup moved out of InformerWrapper and InformerManager into the pool, InformerManager acquires and releases informers instead of owning them, and it removes its own event handler and indexers from an informer that keeps running for others. An event source registered dynamically against an already running shared informer needs no special handling: the client replays the cache contents to a newly added handler. Also in support of the above: ConfigurationService#informerPool, an InformerEventSource constructor that no longer needs an EventSourceContext (the one taking it is deprecated), the resource group/version/kind on InformerConfiguration, equality and toString on FieldSelector, and equality of GroupVersionKindPlural made consistent with its hashCode so that an unspecified plural no longer splits informers. The pooling itself is production ready; the configuration API around it is marked experimental and may still change. Covered by unit tests for the pools, the classifier, the wrapper and the manager, and by integration tests for sharing, dynamic registration and de-registration that each run against both strategies. Signed-off-by: Attila Mészáros <a_meszaros@apple.com>
Configuration menu - View commit details
-
Copy full SHA for e179410 - Browse repository at this point
Copy the full SHA e179410View commit details -
fix: new kotlin sample parent version
This needed to be fixed after rebase. Signed-off-by: Attila Mészáros <a_meszaros@apple.com>
Configuration menu - View commit details
-
Copy full SHA for aacb3c5 - Browse repository at this point
Copy the full SHA aacb3c5View commit details -
fix: set configuration service for default pool (#3535)
This is expected for a pool to set. Event if the underlying implementation would set it, this is the correct way to handle it. Signed-off-by: Attila Mészáros <a_meszaros@apple.com>
Configuration menu - View commit details
-
Copy full SHA for 05ddbcc - Browse repository at this point
Copy the full SHA 05ddbccView commit details -
perf: size the workflow result map from Workflow#size (#3547)
AbstractWorkflowExecutor called Workflow#getDependentResourcesByName purely to read its size. That allocates a HashMap and walks every node to collect the dependent resources, then discards the map. The executor is constructed on every reconcile and cleanup of a workflow-based reconciler, so use the existing Workflow#size instead.
Configuration menu - View commit details
-
Copy full SHA for 8ab41a3 - Browse repository at this point
Copy the full SHA 8ab41a3View commit details -
refactor: call existing helpers instead of re-implementing them (#3544)
No behavior change; each site is replaced by a helper that already exists. - PrimaryUpdateAndCacheUtils#compareResourceVersions (and its private validateResourceVersion) duplicated the entire algorithm of ReconcilerUtilsInternal#validateAndCompareResourceVersions: the length-first compare, the empty check, the leading-zero check and the same exception messages. It had no production caller, so the copy could silently drift from the version all production paths use. Delegate instead. - addFinalizerWithSSA builds its bare SSA skeleton with HasMetadata#initNameAndNamespaceFrom, which ResourceOperations already uses for the same purpose and which is Namespaced-aware. - AbstractInformerPool formats the informer identifier with ReconcilerUtilsInternal#getResourceTypeNameWithVersion instead of concatenating the resource name and version by hand. - EventFilterWindow uses ExtendedResourceEvent#getResourceVersion, which had no callers even though it is exactly the expression used here. - LocallyRunOperatorExtension instantiates reconcilers with Utils#instantiate, so it also supports non-public no-arg constructors and reports the failing class instead of wrapping in a bare RuntimeException.
Configuration menu - View commit details
-
Copy full SHA for 8bdfe58 - Browse repository at this point
Copy the full SHA 8bdfe58View commit details -
test: fix flaky finalizer removal in TriggerReconcilerOnAllEventIT (#…
…3543) The event count is increased at the beginning of the reconciliation, thus waiting for it released the test into the middle of a reconciliation that was still about to remove the finalizer. The subsequent update then raced with that removal and failed with a conflict. Wait for the finalizer removal to actually land, and retry the (optimistically locked) update with a fresh read on conflict.
Configuration menu - View commit details
-
Copy full SHA for 8a18799 - Browse repository at this point
Copy the full SHA 8a18799View commit details -
feat: detect dependent resource API version changes (#3536)
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 <fc49854985@gmail.com> Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for 2740cf6 - Browse repository at this point
Copy the full SHA 2740cf6View commit details -
refactor: resolve the informer target client without a downcast (#3548)
InformerManager is generic over C extends Informable, but getTargetClient type-tested for InformerEventSourceConfiguration to find out whether a specific (e.g. remote cluster) client was configured. Informable has two implementors and only one could answer the question, so a third configuration type wanting its own client would be ignored silently rather than failing to compile. Move the default getKubernetesClient() up from InformerEventSourceConfiguration to Informable and let InformerManager ask the configuration directly. The default still returns Optional.empty(), so existing implementations are unaffected. As a side effect the ConfigurationService client is now only created when no specific client is configured, instead of being created and then discarded.
Configuration menu - View commit details
-
Copy full SHA for 0f576f2 - Browse repository at this point
Copy the full SHA 0f576f2View commit details -
refactor: clean up the Kubernetes resource matchers (#3546)
- GenericKubernetesResourceMatcher allocated the path-prefix lists (List.of(SPEC), List.of(METADATA), the labels/annotations pair, List.of(STATUS)) once per JSON-diff node while matching, and nodeIsChildOf built a stream per call. Both run for every node of every match, so hoist the lists to constants and use an indexed loop. - SSABasedGenericKubernetesResourceMatcher#sanitizeState nested the StatefulSet volume-claim-template handling four levels deep inside the type ladder; extract it into sanitizeVolumeClaimTemplates so the ladder reads as one dispatch per resource kind.
Configuration menu - View commit details
-
Copy full SHA for 8329795 - Browse repository at this point
Copy the full SHA 8329795View commit details -
improve: followup PR for Informer Pools (#3541)
- addresses deprecations - addresses late PR comments for Informer Pools: #3325 Signed-off-by: Attila Mészáros <a_meszaros@apple.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Signed-off-by: Attila Mészáros <a_meszaros@apple.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Configuration menu - View commit details
-
Copy full SHA for f2a5748 - Browse repository at this point
Copy the full SHA f2a5748View commit details -
refactor: let ResourceState own the trigger-on-all-events flag (#3549)
markEventReceived and unMarkEventReceived took a boolean that only ever selects which IllegalStateException guards apply, and every EventProcessor call site supplied it by re-reading the same controller configuration value. It can never differ between calls for a given processor, but nothing enforced that: a call site passing the wrong value would silently change which state transitions are legal, and the state machine could not be read without also reading its callers. Decide it once at the edge: ResourceStateManager takes the flag at construction (EventProcessor already knows it there) and passes it to each ResourceState, which keeps it as a final field. Both types are package-private, so this is self-contained.
Configuration menu - View commit details
-
Copy full SHA for 7504c22 - Browse repository at this point
Copy the full SHA 7504c22View commit details -
perf: avoid redundant work on informer event paths (#3545)
- Mappers#fromMetadata resolved the primary GroupVersionKind on every secondary event, although it only depends on the primary type. Hoist it out of the lambda and compare the encoded string before falling back to parsing the annotation value. - Mappers.SecondaryToPrimaryFromDefaultAnnotation built a whole new mapper on every invocation; hold a single delegate instead. The primaryResourceType field becomes unused and is dropped. - InformerEventSource#start walked the entire informer cache to seed the primary-to-secondary index even when that index is the no-op implementation (i.e. whenever a primaryToSecondaryMapper is configured), which is pure startup latency proportional to the number of cached secondaries. - ExternalResourceCachingEventSource#getSecondaryResources looked the primary up in the cache a second time although the value was already in a local. - PerResourcePollingEventSource#getAndCacheResource derived the same ResourceID twice in adjacent statements.
Configuration menu - View commit details
-
Copy full SHA for 9065185 - Browse repository at this point
Copy the full SHA 9065185View commit details -
improve: log informer re-use on info level (#3569)
Signed-off-by: Attila Mészáros <a_meszaros@apple.com>
Configuration menu - View commit details
-
Copy full SHA for 9a53fbd - Browse repository at this point
Copy the full SHA 9a53fbdView commit details -
test: cover informer retry after a CR deserialization problem (#3558)
Adds an IT for the situation where the resource that cannot be deserialized is already present when the informer lists on startup, the counterpart of MultiVersionCRDIT, which covers the watch case. With stopOnInformerErrorDuringStartup set to false the operator starts, but the informer is not retried: the exception handler installed by the informer pool declines a retry for deserialization errors and the Reflector of the fabric8 client then completes its stop future, so fixing the problem in the cluster while the operator runs does not bring the informer back. The test asserts that current behavior, so it fails once the informer does get retried; the log of the informer pool no longer promises a periodic retry in this case. * Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Configuration menu - View commit details
-
Copy full SHA for c5c8b16 - Browse repository at this point
Copy the full SHA c5c8b16View commit details -
fix: retain recently written external resources missing from a stale …
…update (#3565) An update of the whole resource set of a primary (a poll result or a received event) might have been created before the reconciler wrote a resource, thus not containing it yet. Since such updates are handled as the full actual state, the write was lost from the cache, and the next reconciliation created a duplicate of an already created resource or repeated an already executed update. Writes are now marked as unconfirmed and retained for the next update if it either does not contain the resource at all - the expected case for a create - or still contains a state that a write replaced. Every state replaced since the last update is kept, since the reconciler might write the same resource multiple times in between, and an update created before any of those writes is stale. Any other state is treated as a change made outside of the reconciler and accepted as actual. Marks are dropped on the first update, so a resource really deleted or changed meanwhile is not retained indefinitely. Also guards handleRecentResourceUpdate against a missing cache entry, and resolves the actual resources from the state resources in the external state bulk dependent integration test, which is the recommended approach for resources that take longer to become visible.
Configuration menu - View commit details
-
Copy full SHA for 5ef9d39 - Browse repository at this point
Copy the full SHA 5ef9d39View commit details -
fix: small issue after rebase on main
Signed-off-by: Attila Mészáros <a_meszaros@apple.com>
Configuration menu - View commit details
-
Copy full SHA for f2e2ef0 - Browse repository at this point
Copy the full SHA f2e2ef0View commit details
This comparison is taking too long to generate.
Unfortunately it looks like we can’t render this comparison for you right now. It might be too big, or there might be something weird with your repository.
You can try running this command locally to see the comparison on your machine:
git diff main...next