programming-kubernetes/cnat

"error": "ats.cnat.programming-kubernetes.info \"example-at\" not found"

ishankhare07 opened this issue · 1 comments

I'm getting the following error

2020-09-19T13:16:17.164+0530    INFO    controller-runtime.controller   Starting EventSource    {"controller": "at", "source": "kind source: /, Kind="}
2020-09-19T13:16:17.164+0530    INFO    controller-runtime.manager      starting metrics server {"path": "/metrics"}
2020-09-19T13:16:17.365+0530    INFO    controller-runtime.controller   Starting Controller     {"controller": "at"}
2020-09-19T13:16:17.365+0530    INFO    controller-runtime.controller   Starting workers        {"controller": "at", "worker count": 1}
2020-09-19T13:16:17.366+0530    INFO    controllers.At  === Reconciling At      {"namespace": "cnat", "at": "example-at"}
2020-09-19T13:16:17.366+0530    INFO    controllers.At  Phase: PENDING  {"namespace": "cnat", "at": "example-at"}
2020-09-19T13:16:17.366+0530    INFO    controllers.At  Checking schedule       {"namespace": "cnat", "at": "example-at", "Target": "2019-04-12T10:12:00Z"}
2020-09-19T13:16:17.366+0530    INFO    controllers.At  It's time!      {"namespace": "cnat", "at": "example-at", "ready to execute": "echo YAY!"}
2020-09-19T13:16:17.366+0530    INFO    controllers.At  === Updating status     {"namespace": "cnat", "at": "example-at"}
2020-09-19T13:16:17.682+0530    ERROR   controller-runtime.controller   Reconciler error        {"controller": "at", "request": "cnat/example-at", "error": "ats.cnat.programming-kubernetes.info \"example-at\" not found"}
github.com/go-logr/zapr.(*zapLogger).Error
        /Users/ishankhare/godev/pkg/mod/github.com/go-logr/zapr@v0.1.0/zapr.go:128
sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).reconcileHandler
        /Users/ishankhare/godev/pkg/mod/sigs.k8s.io/controller-runtime@v0.5.0/pkg/internal/controller/controller.go:258
sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).processNextWorkItem
        /Users/ishankhare/godev/pkg/mod/sigs.k8s.io/controller-runtime@v0.5.0/pkg/internal/controller/controller.go:232
sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).worker
        /Users/ishankhare/godev/pkg/mod/sigs.k8s.io/controller-runtime@v0.5.0/pkg/internal/controller/controller.go:211
k8s.io/apimachinery/pkg/util/wait.JitterUntil.func1
        /Users/ishankhare/godev/pkg/mod/k8s.io/apimachinery@v0.17.2/pkg/util/wait/wait.go:152
k8s.io/apimachinery/pkg/util/wait.JitterUntil
        /Users/ishankhare/godev/pkg/mod/k8s.io/apimachinery@v0.17.2/pkg/util/wait/wait.go:153
k8s.io/apimachinery/pkg/util/wait.Until
        /Users/ishankhare/godev/pkg/mod/k8s.io/apimachinery@v0.17.2/pkg/util/wait/wait.go:88
^Cmake: *** [run] Error 1

I can find the said cr if i run kubectl get at example-at . But controller reports not found .

The specific line causing the error in my opinion is err = r.Status().Update(context.TODO(), instance)

Below is my whole code for at_controllers.go

package controllers

import (
	"context"

	"github.com/go-logr/logr"
	"k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/types"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
	"sigs.k8s.io/controller-runtime/pkg/reconcile"

	cnatv1alpha1 "cnat-controller/api/v1alpha1"
	"cnat-controller/pkg/scheduler"
	"cnat-controller/pkg/spawn"

	corev1 "k8s.io/api/core/v1"
)

// AtReconciler reconciles a At object
type AtReconciler struct {
	client.Client
	Log    logr.Logger
	Scheme *runtime.Scheme
}

// +kubebuilder:rbac:groups=cnat.programming-kubernetes.info,resources=ats,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=cnat.programming-kubernetes.info,resources=ats/status,verbs=get;update;patch

func (r *AtReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
	_ = context.Background()
	reqLogger := r.Log.WithValues("namespace", req.Namespace, "at", req.Name)
	reqLogger.Info("=== Reconciling At")

	// your logic here

	// fetch the At instance
	instance := &cnatv1alpha1.At{}
	err := r.Get(context.TODO(), req.NamespacedName, instance)
	if err != nil {
		if errors.IsNotFound(err) {
			return reconcile.Result{}, nil
		}

		return reconcile.Result{}, err
	}

	// if no phase set, default to pending (the initial phase):
	if instance.Status.Phase == "" {
		instance.Status.Phase = cnatv1alpha1.PhasePending
	}

	// the state diagram PENDING -> RUNNING -> DONE
	switch instance.Status.Phase {
	case cnatv1alpha1.PhasePending:
		reqLogger.Info("Phase: PENDING")
		reqLogger.Info("Checking schedule", "Target", instance.Spec.Schedule)

		// check with a tolerance of 2 seconds
		d, err := scheduler.TimeUntilSchedule(instance.Spec.Schedule)
		if err != nil {
			reqLogger.Error(err, "Schedule parsing failure")
			return reconcile.Result{}, err
		}

		// reqLogger.Info("Schedule parsing done", "Result", "diff", fmt.Sprintf("%v", d))

		if d > 0 {
			// Not yet time to execute, wait until scheduled time
			return reconcile.Result{RequeueAfter: d}, nil
		}

		reqLogger.Info("It's time!", "ready to execute", instance.Spec.Command)
		instance.Status.Phase = cnatv1alpha1.PhaseRunning
	case cnatv1alpha1.PhaseRunning:
		reqLogger.Info("Phase: RUNNING")
		pod := spawn.NewPodForCR(instance)

		// set At instance as owner and controller
		err := controllerutil.SetControllerReference(instance, pod, r.Scheme)
		if err != nil {
			return reconcile.Result{}, err
		}

		query := &corev1.Pod{}
		nsName := types.NamespacedName{Name: pod.Name, Namespace: pod.Namespace}
		err = r.Get(context.TODO(), nsName, query)

		if err != nil && errors.IsNotFound(err) {
			// create the pod
			err = r.Create(context.TODO(), pod)
			if err != nil {
				return reconcile.Result{}, err
			}
			reqLogger.Info("Pod Launched", "name", pod.Name)
		} else if err != nil {
			return reconcile.Result{}, err
		} else if query.Status.Phase == corev1.PodFailed ||
			query.Status.Phase == corev1.PodSucceeded {
			reqLogger.Info("Container terminated", "reason",
				query.Status.Reason, "message", query.Status.Message)
			instance.Status.Phase = cnatv1alpha1.PhaseDone
		} else {
			// don't requeue, it will happen automatically when pod status changes
			return reconcile.Result{}, nil
		}
	case cnatv1alpha1.PhaseDone:
		reqLogger.Info("Phase: DONE")
		return reconcile.Result{}, nil
	default:
		reqLogger.Info("NOP")
		return reconcile.Result{}, nil
	}

	// update the At instance
	reqLogger.Info("=== Updating status")
	err = r.Status().Update(context.TODO(), instance)
	if err != nil {
		reqLogger.Info("Unable to update status")
		return reconcile.Result{}, err
	}

	return reconcile.Result{}, nil
}

func (r *AtReconciler) SetupWithManager(mgr ctrl.Manager) error {
	return ctrl.NewControllerManagedBy(mgr).
		For(&cnatv1alpha1.At{}).
		Complete(r)
}

@ishankhare07 In your, at_types.go file, add
// +kubebuilder:subresource:status
above the At struct. For example,

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status

// At is the Schema for the cnats API
type At struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   AtSpec   `json:"spec,omitempty"`
	Status AtStatus `json:"status,omitempty"`
}

make sure to delete the existing crd, then make manifests to generate crd again and the usual commands after that.