controller-runtime: Unable to get an object of a custom resource using the default client outside Reconcile() method

I am trying to get an object of a custom resource that I defined outside of Reconcile() using the default client provided by the manager. I notice that even the object exists in the cluster, the client will return an error saying the object is not found. However, the client works as expected (i.e., can find the object) when I call it in the Reconcile() method. I am wondering what might be the cause for that?

Here is a code example:

type MyReconciler struct {
   client.Client
   Manager ctrl.Manager
}

func (r *MyReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
  ...
  nnm := types.NamespacedName{Namespace: "myNamespace", Name: "myName"
  inst := &api.MyCustomResource{}
  // r.Get will get the object if it exists in the cluster.
  if err := r.Get(ctx, nnm, inst); err != nil {
  ..
  }
   ...
}

If I call r.Get(ctx, nnm, inst) outside Reconcile (e.g., in or after SetupWithManager()), it cannot get the object even it exists.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 19 (11 by maintainers)

Most upvoted comments

@vincepri I am getting errors.IsNotFound() error. The actual error message is something like {“error”: “HNCConfiguration.hnc.x-k8s.io “config” not found”}. I assume that means the client cannot find the object? If the manager/client hasn’t started, am I supposed to get a different error indicating the client hasn’t started.

It would be odd for you to get an errors.IsNotFound() when you are doing an r.client.Create(...). I was suggesting you could handle the error from Create and check for errors.IsAlreadyExists() and move on if that is the case.

Yes, I solved the problem by enforcing the reconciliation via adding a channel to watch.

I remember once trying to create a singleton CR in the case that it doesn’t exist by doing something similar. In the end we ended up doing something like:

	// Create CR if it's not there
	client := mgr.GetClient()
	err = client.Create(context.TODO(), &kniv1alpha1.KNICluster{
		ObjectMeta: metav1.ObjectMeta{
			Name:      kniNamespacedName.Name,
			Namespace: kniNamespacedName.Namespace,
		},
	})
	switch {
	case err == nil:
		log.Info("Created KNICluster resource")
	case errors.IsAlreadyExists(err):
		log.Info("KNICluster resource already exists")
	default:
		log.Error(err, "Failed to create KNICluster resource")
		os.Exit(1)
	}

The big issue that I had with forcing the reconcile by throwing something on the queue was that the semantics for handling when the primary resource was not found was strange.