Description
Bug Report
What did you do?
When updating an instance of a Custom Resource
we get an exception in the ReconcilerUtils.setSpec(HasMetadata resource, Object spec):
io.javaoperatorsdk.operator.AggregatedOperatorException: Exception during workflow.
at io.javaoperatorsdk.operator.processing.dependent.workflow.WorkflowReconcileResult.createFinalException(WorkflowReconcileResult.java:54) ~[operator-framework-core-3.2.0.jar:na]
at io.javaoperatorsdk.operator.processing.dependent.workflow.WorkflowReconcileResult.throwAggregateExceptionIfErrorsPresent(WorkflowReconcileResult.java:48) ~[operator-framework-core-3.2.0.jar:na]
at io.javaoperatorsdk.operator.processing.dependent.workflow.Workflow.reconcile(Workflow.java:56) ~[operator-framework-core-3.2.0.jar:na]
at no.fintlabs.FlaisReconiler.reconcile(FlaisReconiler.java:50) ~[flais-operator-starter-1.0.0-rc-4.jar:na]
at no.fintlabs.FlaisReconiler.reconcile(FlaisReconiler.java:20) ~[flais-operator-starter-1.0.0-rc-4.jar:na]
at io.javaoperatorsdk.operator.processing.Controller$1.execute(Controller.java:130) ~[operator-framework-core-3.2.0.jar:na]
at io.javaoperatorsdk.operator.processing.Controller$1.execute(Controller.java:88) ~[operator-framework-core-3.2.0.jar:na]
at io.javaoperatorsdk.operator.api.monitoring.Metrics.timeControllerExecution(Metrics.java:197) ~[operator-framework-core-3.2.0.jar:na]
at io.javaoperatorsdk.operator.processing.Controller.reconcile(Controller.java:87) ~[operator-framework-core-3.2.0.jar:na]
at io.javaoperatorsdk.operator.processing.event.ReconciliationDispatcher.reconcileExecution(ReconciliationDispatcher.java:130) ~[operator-framework-core-3.2.0.jar:na]
at io.javaoperatorsdk.operator.processing.event.ReconciliationDispatcher.handleReconcile(ReconciliationDispatcher.java:110) ~[operator-framework-core-3.2.0.jar:na]
at io.javaoperatorsdk.operator.processing.event.ReconciliationDispatcher.handleDispatch(ReconciliationDispatcher.java:81) ~[operator-framework-core-3.2.0.jar:na]
at io.javaoperatorsdk.operator.processing.event.ReconciliationDispatcher.handleExecution(ReconciliationDispatcher.java:54) ~[operator-framework-core-3.2.0.jar:na]
at io.javaoperatorsdk.operator.processing.event.EventProcessor$ReconcilerExecutor.run(EventProcessor.java:395) ~[operator-framework-core-3.2.0.jar:na]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[na:na]
at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]
Caused by: java.lang.IllegalStateException: No spec found on resource
at io.javaoperatorsdk.operator.ReconcilerUtils.setSpec(ReconcilerUtils.java:112) ~[operator-framework-core-3.2.0.jar:na]
at io.javaoperatorsdk.operator.processing.dependent.kubernetes.GenericResourceUpdatePreProcessor$3.updateClonedActual(GenericResourceUpdatePreProcessor.java:40) ~[operator-framework-core-3.2.0.jar:na]
at io.javaoperatorsdk.operator.processing.dependent.kubernetes.GenericResourceUpdatePreProcessor.replaceSpecOnActual(GenericResourceUpdatePreProcessor.java:48) ~[operator-framework-core-3.2.0.jar:na]
at io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource.update(KubernetesDependentResource.java:132) ~[operator-framework-core-3.2.0.jar:na]
at io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource.update(CRUDKubernetesDependentResource.java:17) ~[operator-framework-core-3.2.0.jar:na]
at io.javaoperatorsdk.operator.processing.dependent.AbstractDependentResource.handleUpdate(AbstractDependentResource.java:111) ~[operator-framework-core-3.2.0.jar:na]
at io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource.handleUpdate(KubernetesDependentResource.java:119) ~[operator-framework-core-3.2.0.jar:na]
at io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource.handleUpdate(KubernetesDependentResource.java:32) ~[operator-framework-core-3.2.0.jar:na]
at io.javaoperatorsdk.operator.processing.dependent.AbstractDependentResource.reconcile(AbstractDependentResource.java:50) ~[operator-framework-core-3.2.0.jar:na]
at io.javaoperatorsdk.operator.processing.dependent.workflow.WorkflowReconcileExecutor$NodeReconcileExecutor.run(WorkflowReconcileExecutor.java:166) ~[operator-framework-core-3.2.0.jar:na]
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) ~[na:na]
at java.base/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264) ~[na:na]
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java) ~[na:na]
... 3 common frames omitted
Caused by: java.lang.NoSuchMethodException: no.fintlabs.onepassword.OnePasswordCrd.setSpec(no.fintlabs.onepassword.OnePasswordSpec)
at java.base/java.lang.Class.getMethod(Class.java:2227) ~[na:na]
at io.javaoperatorsdk.operator.ReconcilerUtils.setSpec(ReconcilerUtils.java:109) ~[operator-framework-core-3.2.0.jar:na]
... 15 common frames omitted
This is only happening when we update, not on create.
This is the desired
method from the dependent resource class. This is how I create the CRD instance.
@Override
protected OnePasswordCrd desired(FlaisApplicationCrd primary, Context<FlaisApplicationCrd> context) {
OnePasswordCrd onePasswordCrd = new OnePasswordCrd();
onePasswordCrd.getMetadata().setLabels(LabelFactory.updateRecommendedLabels(primary));
onePasswordCrd.getMetadata().setName(primary.getMetadata().getName());
onePasswordCrd.getMetadata().setNamespace(primary.getMetadata().getNamespace());
onePasswordCrd.getSpec().setItemPath(primary.getSpec().getOnePassword().getItemPath());
return onePasswordCrd;
}
This is the CRD class.
@Group("onepassword.com")
@Version("v1")
@Kind("OnePasswordItem")
public class OnePasswordCrd extends CustomResource<OnePasswordSpec, Void> implements Namespaced {
@Override
protected OnePasswordSpec initSpec() {
return new OnePasswordSpec();
}
}
This is the spec class.
@Data
public class OnePasswordSpec {
private String itemPath;
}
One can see the source code here
What did you expect to see?
No exception and the resource updated.
What did you see instead? Under which circumstances?
See the description further up.
Environment
Kubernetes cluster type:
Azure Kubernetes Service
io.javaoperatorsdk.operator-framework:3.2.0
openjdk 17.0.2 2022-01-18 LTS
Client Version: v1.24.0
Kustomize Version: v4.5.4
Server Version: v1.22.11
Possible Solution
What happens is that if it is a CustomResource we're not able to get the setSpec() method.
The reason seems to be related to reflection. If I do resource.getClass().getMethod("setSpec", Object.class)
instead of resource.getClass().getMethod("setSpec", spec.getClass()) it seems to work.
It might be a solution to check if the resource
extends CustomResource
and then do
resource.getClass().getMethod("setSpec", Object.class)