Skip to content

Error when using multiple dependent resources of the same class #1653

Closed
@derlin

Description

@derlin

Bug Report

What did you do?

I am using the JOSDK through quarkus-operator-sdk. I have a specific use case that I explained in #1437. The code is available at https://github.com/derlin/josdk-operator-dependent-crs/blob/main/src/main/java/ch/derlin/configreconciler/DbReconciler.java .

Now, I am trying to migrate to quarkus-operator-sdk 5.X, which updates JOSDK from 3.X to 4.X. The difficulty comes from the fact that I have two different event sources for the same class Secret.

My event sources are prepared like this. The createInformer method creates its own event source, while the dbSecret is an instance of CRUDKubernetesDependentResource<Secret, Db>:

  @Override
  public Map<String, EventSource> prepareEventSources(EventSourceContext<Db> context) {
    Map<String, EventSource> eventSources = Map.of(
        CONFIG_INFORMER, createInformer(context, Config.class, CONFIG_INFORMER),
        CREDENTIALS_SECRET_INFORMER, createInformer(context, Secret.class, CREDENTIALS_SECRET_INFORMER, CREDENTIALS_SECRET_LABEL),
        DB_SECRET_INFORMER, dbSecret.initEventSource(context)
    );
    dbSecret.useEventSourceWithName(DB_SECRET_INFORMER); // <- added for 4.X migration
    return eventSources;
  }

In my reconciliation, I have the following:

  @Override
  public UpdateControl<Db> reconcile(Db resource, Context<Db> context) {
    // ...

    // ⮕ .getSecondaryResource deprecated, how to do the same in 4.X ?
    var config = context.getSecondaryResource(Config.class).orElseThrow(() ->
        new ValidationException("Missing config"));
    var credentialsSecret = context.getSecondaryResource(Secret.class, CREDENTIALS_SECRET_INFORMER).orElseThrow(() ->
        new ValidationException("Missing credentials secret"));

    dbSecret.reconcile(resource, context);  //  ⮕ THROWING EXCEPTION
    var secret = context.getSecondaryResource(Secret.class, DB_SECRET_INFORMER).orElseThrow();
    
    // ...
  }

This was working fine with the old version but with 4.X I get the following exception when calling dbSecret.reconcile(resource, context):

Error during event processing ExecutionScope{ resource id: ResourceID{name='example-db', namespace='upgrade'}, version: 340777} failed.: io.javaoperatorsdk.operator.OperatorException: java.lang.IllegalArgumentException: There are multiple EventSources registered for type io.fabric8.kubernetes.api.model.Secret, you need to provide a name to specify which EventSource you want to query. Known names: dependent_db_secret,dependent_credentials_secret
	at io.javaoperatorsdk.operator.monitoring.micrometer.MicrometerMetrics.lambda$timeControllerExecution$0(MicrometerMetrics.java:58)
	at io.micrometer.core.instrument.composite.CompositeTimer.record(CompositeTimer.java:65)
	at io.javaoperatorsdk.operator.monitoring.micrometer.MicrometerMetrics.timeControllerExecution(MicrometerMetrics.java:54)
	at io.javaoperatorsdk.operator.processing.Controller.reconcile(Controller.java:93)
	at io.javaoperatorsdk.operator.processing.event.ReconciliationDispatcher.reconcileExecution(ReconciliationDispatcher.java:130)
	at io.javaoperatorsdk.operator.processing.event.ReconciliationDispatcher.handleReconcile(ReconciliationDispatcher.java:110)
	at io.javaoperatorsdk.operator.processing.event.ReconciliationDispatcher.handleDispatch(ReconciliationDispatcher.java:81)
	at io.javaoperatorsdk.operator.processing.event.ReconciliationDispatcher.handleExecution(ReconciliationDispatcher.java:54)
	at io.javaoperatorsdk.operator.processing.event.EventProcessor$ReconcilerExecutor.run(EventProcessor.java:406)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: java.lang.IllegalArgumentException: There are multiple EventSources registered for type io.fabric8.kubernetes.api.model.Secret, you need to provide a name to specify which EventSource you want to query. Known names: dependent_db_secret,dependent_credentials_secret
	at io.javaoperatorsdk.operator.processing.event.EventSources.get(EventSources.java:118)
	at io.javaoperatorsdk.operator.processing.event.EventSourceManager.getResourceEventSourceFor(EventSourceManager.java:199)
	at io.javaoperatorsdk.operator.api.reconciler.DefaultContext.getSecondaryResource(DefaultContext.java:47)
	at io.javaoperatorsdk.operator.api.reconciler.Context.getSecondaryResource(Context.java:16)
	at io.javaoperatorsdk.operator.processing.dependent.AbstractDependentResource.getSecondaryResource(AbstractDependentResource.java:92)
	at io.javaoperatorsdk.operator.processing.dependent.SingleDependentResourceReconciler.reconcile(SingleDependentResourceReconciler.java:18)
	at io.javaoperatorsdk.operator.processing.dependent.AbstractDependentResource.reconcile(AbstractDependentResource.java:50)
	at ch.derlin.configreconciler.DbReconciler.reconcile(DbReconciler.java:77)
	at ch.derlin.configreconciler.DbReconciler.reconcile(DbReconciler.java:34)
	at ch.derlin.configreconciler.DbReconciler_ClientProxy.reconcile(Unknown Source)
	at io.javaoperatorsdk.operator.processing.Controller$1.execute(Controller.java:136)
	at io.javaoperatorsdk.operator.processing.Controller$1.execute(Controller.java:94)
	at io.javaoperatorsdk.operator.monitoring.micrometer.MicrometerMetrics.lambda$timeControllerExecution$0(MicrometerMetrics.java:56)
	... 11 more

I added the line dbSecret.useEventSourceWithName() (see first code snippet) to try to avoid this error, to no avail.

SIDE NOTE: I also have no idea how to do the getSecondaryResource with the new implementation, any hint ?

What did you expect to see?

I would expect the code to keep working, meaning I am able to reconcile my dbSecret (and also fetch my secondary resources) as before.

What did you see instead? Under which circumstances?

I see the exception (see above):

java.lang.IllegalArgumentException: There are multiple EventSources registered for type io.fabric8.kubernetes.api.model.Secret, you need to provide a name to specify which EventSource you want to query. Known names: custom_secret,dependent_secret

Environment

I am using K3D for testing (vanilla kubernetes).

$ Mention java-operator-sdk version from pom.xml file

    <dependency>
      <groupId>io.quarkiverse.operatorsdk</groupId>
      <artifactId>quarkus-operator-sdk</artifactId>
     <version>5.0.0.Beta2</version>
    </dependency>
    <dependency>
      <groupId>io.javaoperatorsdk</groupId>
      <artifactId>operator-framework-core</artifactId>
      <version>4.1.1</version>
   </dependency>

$ java -version

java -version
openjdk version "11.0.16.1" 2022-08-12
OpenJDK Runtime Environment Homebrew (build 11.0.16.1+0)
OpenJDK 64-Bit Server VM Homebrew (build 11.0.16.1+0, mixed mode)

$ kubectl version

kubectl version --short
Flag --short has been deprecated, and will be removed in the future. The --short output will become the default.
Client Version: v1.25.4
Kustomize Version: v4.5.7
Server Version: v1.24.4+k3s1

Possible Solution

I think the problem comes from https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/SingleDependentResourceReconciler.java#L18 where the .getSecondaryResource() doesn't use any discriminator / doesn't look for the event source name.

Additional context

I already shared my use case in this issue #1437. A minimal reproducible example is available at https://github.com/derlin/josdk-operator-dependent-crs/tree/quarkus-operator-5.X :

  • branch main ⮕ working version with 3.X
  • branch quarkus-operator-5.X ⮕ failing version with 4.X

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions