Skip to content

Typed by-name secondary resource accessors on Context #3372

@afalhambra-hivemq

Description

@afalhambra-hivemq

Summary

Revisit #1410 ("Access secondary resources by ResourceID") now that ResourceDiscriminators are gone. Add typed by-name accessors on Context<P> so reconcilers can look up secondary resources scoped to a specific event source without dropping to eventSourceRetriever().getEventSourceFor(...) and casting.

Motivation

When a reconciler watches external secondary resources via a named event source (e.g. ConfigMaps referenced from a custom resource's spec), today's options on Context<P> are:

  1. getSecondaryResource(Class, String eventSourceName) returns the single linked resource. No by-name lookup.
  2. getSecondaryResourcesAsStream(Class, boolean deduplicate) returns all secondary resources of the type across all event sources. No event-source scoping.
  3. Drop to context.eventSourceRetriever().getEventSourceFor(...), cast to InformerEventSource, then call .get(ResourceID). Works, but ad-hoc.

#1410 acknowledged this back in 2022 and the chosen mechanism (ResourceDiscriminators) was later removed in #2253, leaving the gap unfilled.

With PR #3345 having landed (Cache<T> / ResourceCache<T> interfaces, read-cache-after-write consistent), the natural fix is to expose typed accessors on Context<P> that dispatch to those interfaces.

Proposed API additions on Context<P>

<R> Optional<R> getSecondaryResource(
        Class<R> expectedType, String eventSourceName, String name, String namespace);

default <R> Optional<R> getSecondaryResource(
        Class<R> expectedType, String eventSourceName, String name) {
    return getSecondaryResource(
            expectedType, eventSourceName, name,
            getPrimaryResource().getMetadata().getNamespace());
}

<R> Stream<R> getSecondaryResourcesAsStream(Class<R> expectedType, String eventSourceName);

Semantics:

  • Single-resource by name and namespace: dispatch to Cache<R>.get(ResourceID) when the event source implements Cache<R> (direct cache lookup, read-cache-after-write consistent). Otherwise fall back to EventSource.getSecondaryResources(primary) filtered by ResourceID. ResourceID stays an implementation detail.
  • Single-resource by name (default method): convenience that uses the primary resource's namespace. Documented caveat: for cluster-scoped primaries (no namespace) the lookup is cluster-scoped; use the four-arg overload to target a specific namespace.
  • Stream by event source: dispatch to ResourceCache<R>.list(namespace) when the event source implements ResourceCache<R> (read-cache-after-write consistent). For cluster-scoped primaries (null namespace) falls back to Cache.list() to avoid an NPE in InformerWrapper.list. Otherwise falls back to eventSource.getSecondaryResources(primary).stream().
  • NoEventSourceForClassException handling mirrors the existing getSecondaryResource(Class, String): rethrow unless eventSourceName == null and the type is part of a managed workflow, in which case return an empty result.

Validated end-to-end against a real consumer; PR includes the API + tests, downstream migration verified separately (119 ITs passing).

Status

PR #3373 is open, targeting the next branch for the next minor release. After the first review round (csviri, 2026-05-22) the original (Class, String eventSourceName, ResourceID) signature was replaced with (Class, String eventSourceName, String name, String namespace) to keep ResourceID out of the public Context API surface.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions