Skip to content

NullPointerException when reconciling Namespace #1897

Closed
@coltmcnealy-lh

Description

@coltmcnealy-lh

Bug Report

What did you do?

I created a Dependent Resource class that extends KubernetesCRUDDependentResource<Namespace, MyCustomResource>. The goal of this class was to be able to create a Namespace dynamically upon the provisioning of a MyCustomResource.

What did you see instead? Under which circumstances?

When I created a MyCustomResource, I got a NullPointerException because the Namespace::getSpec() method always returns null, since a Kubernetes Namespace object has no spec. The stacktrace can be found here:

 - io.littlehorse.operator.lhcluster.dependents.TenantNamespaceDR -> java.lang.NullPointerException: Cannot invoke "Object.getClass()" because "spec" is null
	at io.javaoperatorsdk.operator.ReconcilerUtils.getSpecClass(ReconcilerUtils.java:178)
	at io.javaoperatorsdk.operator.ReconcilerUtils.setSpec(ReconcilerUtils.java:109)
	at io.javaoperatorsdk.operator.processing.dependent.kubernetes.GenericResourceUpdatePreProcessor$3.updateClonedActual(GenericResourceUpdatePreProcessor.java:40)
	at io.javaoperatorsdk.operator.processing.dependent.kubernetes.GenericResourceUpdatePreProcessor.replaceSpecOnActual(GenericResourceUpdatePreProcessor.java:48)
	at io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource.update(KubernetesDependentResource.java:138)
	at io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource.update(CRUDKubernetesDependentResource.java:16)
	at io.javaoperatorsdk.operator.processing.dependent.AbstractDependentResource.handleUpdate(AbstractDependentResource.java:144)
	at io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource.handleUpdate(KubernetesDependentResource.java:125)
	at io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource.handleUpdate(KubernetesDependentResource.java:32)
	at io.javaoperatorsdk.operator.processing.dependent.AbstractDependentResource.reconcile(AbstractDependentResource.java:72)
	at io.javaoperatorsdk.operator.processing.dependent.SingleDependentResourceReconciler.reconcile(SingleDependentResourceReconciler.java:19)
	at io.javaoperatorsdk.operator.processing.dependent.AbstractDependentResource.reconcile(AbstractDependentResource.java:52)
	at io.javaoperatorsdk.operator.processing.dependent.workflow.WorkflowReconcileExecutor$NodeReconcileExecutor.doRun(WorkflowReconcileExecutor.java:124)
	at io.javaoperatorsdk.operator.processing.dependent.workflow.NodeExecutor.run(NodeExecutor.java:22)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:833)

	at io.javaoperatorsdk.operator.processing.dependent.workflow.WorkflowResult.throwAggregateExceptionIfErrorsPresent(WorkflowResult.java:40)
	at io.javaoperatorsdk.operator.processing.dependent.workflow.WorkflowReconcileResult.throwAggregateExceptionIfErrorsPresent(WorkflowReconcileResult.java:9)
	at io.javaoperatorsdk.operator.processing.dependent.workflow.DefaultWorkflow.reconcile(DefaultWorkflow.java:92)
	at io.javaoperatorsdk.operator.processing.Controller$1.execute(Controller.java:133)
	at io.javaoperatorsdk.operator.processing.Controller$1.execute(Controller.java:96)
	at io.javaoperatorsdk.operator.api.monitoring.Metrics.timeControllerExecution(Metrics.java:209)
	at io.javaoperatorsdk.operator.processing.Controller.reconcile(Controller.java:95)
	at io.javaoperatorsdk.operator.processing.event.ReconciliationDispatcher.reconcileExecution(ReconciliationDispatcher.java:139)
	at io.javaoperatorsdk.operator.processing.event.ReconciliationDispatcher.handleReconcile(ReconciliationDispatcher.java:119)
	at io.javaoperatorsdk.operator.processing.event.ReconciliationDispatcher.handleDispatch(ReconciliationDispatcher.java:89)
	at io.javaoperatorsdk.operator.processing.event.ReconciliationDispatcher.handleExecution(ReconciliationDispatcher.java:62)
	at io.javaoperatorsdk.operator.processing.event.EventProcessor$ReconcilerExecutor.run(EventProcessor.java:414)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:833)

Environment

Running the Java Operator SDK 4.3.0. I was running the Operator locally on my own terminal, pointed at a KIND cluster. Java version 17.

Possible Solution

Often, people do not use custom resources to create a Namespace (and some would consider it to be bad practice). Therefore, you could just say "too bad, you're out of luck, Colt!" and leave it as-is.

Alternatively, we could guard for Namespace objects (which don't have a Spec) in the implementations of the Updater interfaces.

Metadata

Metadata

Assignees

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