...

Source file src/edge-infra.dev/pkg/k8s/runtime/controller/reconcile/result_processor.go

Documentation: edge-infra.dev/pkg/k8s/runtime/controller/reconcile

     1  package reconcile
     2  
     3  import (
     4  	"context"
     5  
     6  	corev1 "k8s.io/api/core/v1"
     7  	"k8s.io/client-go/tools/record"
     8  	ctrl "sigs.k8s.io/controller-runtime"
     9  	"sigs.k8s.io/controller-runtime/pkg/client"
    10  
    11  	"edge-infra.dev/pkg/k8s/meta/status"
    12  	"edge-infra.dev/pkg/k8s/runtime/conditions"
    13  	"edge-infra.dev/pkg/k8s/runtime/controller/reconcile/recerr"
    14  )
    15  
    16  // ResultProcessor processes the results of reconciliation (the object, result
    17  // and error). Any errors during processing need not result in the
    18  // reconciliation failure. The errors can be recorded as logs and events.
    19  type ResultProcessor func(context.Context, record.EventRecorder, conditions.Setter, Result, error)
    20  
    21  // RecordReconcileReq is a ResultProcessor that checks the reconcile
    22  // annotation value and sets it in the object status as
    23  // status.lastHandledReconcileAt.
    24  func RecordReconcileReq(_ context.Context, _ record.EventRecorder, obj conditions.Setter, _ Result, _ error) {
    25  	if v, ok := GetAnnotation(obj.GetAnnotations()); ok {
    26  		_ = SetStatusLastHandledReconcileAt(obj, v)
    27  	}
    28  }
    29  
    30  // RecordResult is a ResultProcessor that handles logging and event recording for
    31  // a reconciled object based on the reconcile error and the object's readiness.
    32  func RecordResult(ctx context.Context, recorder record.EventRecorder, obj conditions.Setter, _ Result, err error) {
    33  	reason := conditions.GetReason(obj, status.ReadyCondition)
    34  	switch e := err.(type) {
    35  	case *recerr.Generic:
    36  		logError(ctx, e.Event, e, e.Error())
    37  		recordEvent(recorder, obj, e.Event, e.Notification, err.Error(), e.Reason)
    38  	case *recerr.Wait:
    39  		logError(ctx, e.Event, e, "reconciliation waiting",
    40  			"reason", e.Err,
    41  			"duration", e.Config.RequeueAfter,
    42  		)
    43  		recordEvent(recorder, obj, e.Event, e.Notification, err.Error(), e.Reason)
    44  	case *recerr.Stalled:
    45  		logError(ctx, e.Event, e, "reconciliation stalled")
    46  		recordEvent(recorder, obj, e.Event, e.Notification, err.Error(), e.Reason)
    47  	case error:
    48  		logError(ctx, corev1.EventTypeWarning, e, e.Error())
    49  		if reason == "" {
    50  			reason = "ReconcileFailed"
    51  		}
    52  		recordEvent(recorder, obj, corev1.EventTypeWarning, true, err.Error(), reason)
    53  	case nil:
    54  		if !conditions.IsReady(obj) {
    55  			return
    56  		}
    57  		// The error is 'nil' and the object is ready, so a 'Normal' event is
    58  		// recorded to report successful reconciliation of the object.
    59  		message := conditions.GetMessage(obj, status.ReadyCondition)
    60  		recordEvent(recorder, obj, corev1.EventTypeNormal, true, message, reason)
    61  	}
    62  }
    63  
    64  // logError logs error based on the passed error configurations.
    65  func logError(ctx context.Context, eventType string, err error, msg string, keysAndValues ...interface{}) {
    66  	log := ctrl.LoggerFrom(ctx)
    67  	switch eventType {
    68  	case corev1.EventTypeNormal, recerr.EventTypeNone:
    69  		log.Info(msg, keysAndValues...)
    70  	case corev1.EventTypeWarning:
    71  		log.Error(err, msg, keysAndValues...)
    72  	}
    73  }
    74  
    75  // recordEvent records events based on the passed error configurations.
    76  func recordEvent(recorder record.EventRecorder, obj client.Object, eventType string, notification bool, message, reason string) {
    77  	if recorder == nil || eventType == recerr.EventTypeNone {
    78  		return
    79  	}
    80  	switch eventType {
    81  	case corev1.EventTypeNormal:
    82  		if notification {
    83  			recorder.Eventf(obj, corev1.EventTypeNormal, reason, message)
    84  		}
    85  		return
    86  	case corev1.EventTypeWarning:
    87  		recorder.Eventf(obj, corev1.EventTypeWarning, reason, message)
    88  		return
    89  	}
    90  }
    91  

View as plain text