Repository navigation
ReconcilerUtils.setSpec() cannot find the spec if it is a Custom Resource #1589
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 omittedThis 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)
Activity
fix: fix setSpec NoSuchMethodException for custom resource (operator-…
fix: fix setSpec NoSuchMethodException for custom resource (operator-…
fix: fix setSpec NoSuchMethodException for custom resource (operator-…
fix: setSpec NoSuchMethodException for custom resource (#1589) (#1591)
csviri commentedon Nov 8, 2022
thx @fsjovatsen and @scrocquesel for the fix.
Will release v4.1.1 with this fix soon. @fsjovatsen from 3.2.0 is should be trivial to update to that version