You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by pc...@apache.org on 2022/12/15 08:17:06 UTC

[camel-k] 01/03: fix: reconciliation loops behaviors

This is an automated email from the ASF dual-hosted git repository.

pcongiusti pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-k.git

commit ff24882004c9645660ae9f5051793f822525144a
Author: Pasquale Congiusti <pa...@gmail.com>
AuthorDate: Mon Dec 12 16:57:43 2022 +0100

    fix: reconciliation loops behaviors
    
    * Expose trait failures into Integration status
    * KameletBinding will report an Error when it cannot create an Integration for any reason
    
    Closes #3389
    Closes #3010
---
 pkg/apis/camel/v1alpha1/kamelet_binding_types.go   |  2 +
 pkg/controller/integration/platform_setup.go       |  6 ++-
 pkg/controller/kameletbinding/initialize.go        |  5 ++-
 .../kameletbinding/kamelet_binding_controller.go   | 47 +++++++++++-----------
 pkg/controller/kameletbinding/monitor.go           |  8 +++-
 5 files changed, 41 insertions(+), 27 deletions(-)

diff --git a/pkg/apis/camel/v1alpha1/kamelet_binding_types.go b/pkg/apis/camel/v1alpha1/kamelet_binding_types.go
index eafd475de..860151824 100644
--- a/pkg/apis/camel/v1alpha1/kamelet_binding_types.go
+++ b/pkg/apis/camel/v1alpha1/kamelet_binding_types.go
@@ -128,6 +128,8 @@ type KameletBindingConditionType string
 const (
 	// KameletBindingConditionReady --
 	KameletBindingConditionReady KameletBindingConditionType = "Ready"
+	// KameletBindingIntegrationConditionError is used to report the error on the generated Integration
+	KameletBindingIntegrationConditionError KameletBindingConditionType = "IntegrationError"
 )
 
 // KameletBindingPhase --
diff --git a/pkg/controller/integration/platform_setup.go b/pkg/controller/integration/platform_setup.go
index 92a90ce80..e18b33823 100644
--- a/pkg/controller/integration/platform_setup.go
+++ b/pkg/controller/integration/platform_setup.go
@@ -20,6 +20,7 @@ package integration
 import (
 	"context"
 
+	corev1 "k8s.io/api/core/v1"
 	k8serrors "k8s.io/apimachinery/pkg/api/errors"
 
 	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
@@ -52,7 +53,10 @@ func (action *platformSetupAction) CanHandle(integration *v1.Integration) bool {
 // Handle handles the integrations.
 func (action *platformSetupAction) Handle(ctx context.Context, integration *v1.Integration) (*v1.Integration, error) {
 	if _, err := trait.Apply(ctx, action.client, integration, nil); err != nil {
-		return nil, err
+		integration.Status.Phase = v1.IntegrationPhaseError
+		integration.SetReadyCondition(corev1.ConditionFalse,
+			v1.IntegrationConditionInitializationFailedReason, err.Error())
+		return integration, err
 	}
 
 	pl, err := platform.GetForResource(ctx, action.client, integration)
diff --git a/pkg/controller/kameletbinding/initialize.go b/pkg/controller/kameletbinding/initialize.go
index 0ff43d881..6ae2827b7 100644
--- a/pkg/controller/kameletbinding/initialize.go
+++ b/pkg/controller/kameletbinding/initialize.go
@@ -52,7 +52,10 @@ func (action *initializeAction) CanHandle(kameletbinding *v1alpha1.KameletBindin
 func (action *initializeAction) Handle(ctx context.Context, kameletbinding *v1alpha1.KameletBinding) (*v1alpha1.KameletBinding, error) {
 	it, err := CreateIntegrationFor(ctx, action.client, kameletbinding)
 	if err != nil {
-		return nil, err
+		kameletbinding.Status.Phase = v1alpha1.KameletBindingPhaseError
+		kameletbinding.Status.SetErrorCondition(v1alpha1.KameletBindingIntegrationConditionError,
+			"Couldn't create an Integration custom resource", err)
+		return kameletbinding, err
 	}
 
 	if _, err := kubernetes.ReplaceResource(ctx, action.client, it); err != nil {
diff --git a/pkg/controller/kameletbinding/kamelet_binding_controller.go b/pkg/controller/kameletbinding/kamelet_binding_controller.go
index b14574217..8709c3e38 100644
--- a/pkg/controller/kameletbinding/kamelet_binding_controller.go
+++ b/pkg/controller/kameletbinding/kamelet_binding_controller.go
@@ -19,7 +19,6 @@ package kameletbinding
 
 import (
 	"context"
-	"time"
 
 	"k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/runtime"
@@ -41,6 +40,7 @@ import (
 
 	camelevent "github.com/apache/camel-k/pkg/event"
 	"github.com/apache/camel-k/pkg/platform"
+	"github.com/apache/camel-k/pkg/util/log"
 	"github.com/apache/camel-k/pkg/util/monitoring"
 )
 
@@ -180,7 +180,6 @@ func (r *ReconcileKameletBinding) Reconcile(ctx context.Context, request reconci
 		NewMonitorAction(),
 	}
 
-	var targetPhase v1alpha1.KameletBindingPhase
 	var err error
 
 	target := instance.DeepCopy()
@@ -193,31 +192,21 @@ func (r *ReconcileKameletBinding) Reconcile(ctx context.Context, request reconci
 		if a.CanHandle(target) {
 			targetLog.Infof("Invoking action %s", a.Name())
 
-			phaseFrom := target.Status.Phase
-
 			target, err = a.Handle(ctx, target)
 			if err != nil {
 				camelevent.NotifyKameletBindingError(ctx, r.client, r.recorder, &instance, target, err)
+				// Update the kameletbinding (mostly just to update its phase) if the new instance is returned
+				if target != nil {
+					_ = r.update(ctx, &instance, target, &targetLog)
+				}
 				return reconcile.Result{}, err
 			}
 
 			if target != nil {
-				target.Status.ObservedGeneration = instance.Generation
-
-				if err := r.client.Status().Patch(ctx, target, ctrl.MergeFrom(&instance)); err != nil {
+				if err := r.update(ctx, &instance, target, &targetLog); err != nil {
 					camelevent.NotifyKameletBindingError(ctx, r.client, r.recorder, &instance, target, err)
 					return reconcile.Result{}, err
 				}
-
-				targetPhase = target.Status.Phase
-
-				if targetPhase != phaseFrom {
-					targetLog.Info(
-						"state transition",
-						"phase-from", phaseFrom,
-						"phase-to", target.Status.Phase,
-					)
-				}
 			}
 
 			// handle one action at time so the resource
@@ -227,12 +216,24 @@ func (r *ReconcileKameletBinding) Reconcile(ctx context.Context, request reconci
 		}
 	}
 
-	if targetPhase == v1alpha1.KameletBindingPhaseReady {
-		return reconcile.Result{}, nil
+	return reconcile.Result{}, nil
+}
+
+func (r *ReconcileKameletBinding) update(ctx context.Context, base *v1alpha1.KameletBinding, target *v1alpha1.KameletBinding, log *log.Logger) error {
+	target.Status.ObservedGeneration = base.Generation
+
+	if err := r.client.Status().Patch(ctx, target, ctrl.MergeFrom(base)); err != nil {
+		camelevent.NotifyKameletBindingError(ctx, r.client, r.recorder, base, target, err)
+		return err
 	}
 
-	// Requeue
-	return reconcile.Result{
-		RequeueAfter: 5 * time.Second,
-	}, nil
+	if target.Status.Phase != base.Status.Phase {
+		log.Info(
+			"state transition",
+			"phase-from", base.Status.Phase,
+			"phase-to", target.Status.Phase,
+		)
+	}
+
+	return nil
 }
diff --git a/pkg/controller/kameletbinding/monitor.go b/pkg/controller/kameletbinding/monitor.go
index 04a4e546c..752342b1f 100644
--- a/pkg/controller/kameletbinding/monitor.go
+++ b/pkg/controller/kameletbinding/monitor.go
@@ -49,7 +49,8 @@ func (action *monitorAction) Name() string {
 
 func (action *monitorAction) CanHandle(kameletbinding *v1alpha1.KameletBinding) bool {
 	return kameletbinding.Status.Phase == v1alpha1.KameletBindingPhaseCreating ||
-		kameletbinding.Status.Phase == v1alpha1.KameletBindingPhaseError ||
+		(kameletbinding.Status.Phase == v1alpha1.KameletBindingPhaseError &&
+			kameletbinding.Status.GetCondition(v1alpha1.KameletBindingIntegrationConditionError) == nil) ||
 		kameletbinding.Status.Phase == v1alpha1.KameletBindingPhaseReady
 }
 
@@ -85,7 +86,10 @@ func (action *monitorAction) Handle(ctx context.Context, kameletbinding *v1alpha
 	// Check if the integration needs to be changed
 	expected, err := CreateIntegrationFor(ctx, action.client, kameletbinding)
 	if err != nil {
-		return nil, err
+		kameletbinding.Status.Phase = v1alpha1.KameletBindingPhaseError
+		kameletbinding.Status.SetErrorCondition(v1alpha1.KameletBindingIntegrationConditionError,
+			"Couldn't create an Integration custom resource", err)
+		return kameletbinding, err
 	}
 
 	semanticEquality := equality.Semantic.DeepDerivative(expected.Spec, it.Spec)