You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by lb...@apache.org on 2019/07/02 12:24:25 UTC

[camel-k] 05/12: refactor(controller): simplify integration kit controller

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

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

commit 87e0bffc248b38648bd34be257ddfd207b994ad1
Author: lburgazzoli <lb...@gmail.com>
AuthorDate: Fri Jun 28 15:58:45 2019 +0200

    refactor(controller): simplify integration kit controller
---
 pkg/controller/integrationkit/action.go            |  6 +-
 pkg/controller/integrationkit/build.go             | 78 +++++++++-------------
 pkg/controller/integrationkit/initialize.go        | 32 +++------
 .../integrationkit/integrationkit_controller.go    | 62 ++++++++++++++---
 pkg/controller/integrationkit/monitor.go           | 15 ++---
 5 files changed, 101 insertions(+), 92 deletions(-)

diff --git a/pkg/controller/integrationkit/action.go b/pkg/controller/integrationkit/action.go
index 69691bf..5dd5ecf 100644
--- a/pkg/controller/integrationkit/action.go
+++ b/pkg/controller/integrationkit/action.go
@@ -28,6 +28,7 @@ import (
 // Action --
 type Action interface {
 	client.Injectable
+	log.Injectable
 
 	// a user friendly name for the action
 	Name() string
@@ -36,10 +37,7 @@ type Action interface {
 	CanHandle(kit *v1alpha1.IntegrationKit) bool
 
 	// executes the handling function
-	Handle(ctx context.Context, kit *v1alpha1.IntegrationKit) error
-
-	// Inject integration logger
-	InjectLogger(log.Logger)
+	Handle(ctx context.Context, kit *v1alpha1.IntegrationKit) (*v1alpha1.IntegrationKit, error)
 }
 
 type baseAction struct {
diff --git a/pkg/controller/integrationkit/build.go b/pkg/controller/integrationkit/build.go
index 97b7caf..4fb448a 100644
--- a/pkg/controller/integrationkit/build.go
+++ b/pkg/controller/integrationkit/build.go
@@ -52,20 +52,20 @@ func (action *buildAction) CanHandle(kit *v1alpha1.IntegrationKit) bool {
 		kit.Status.Phase == v1alpha1.IntegrationKitPhaseBuildRunning
 }
 
-func (action *buildAction) Handle(ctx context.Context, kit *v1alpha1.IntegrationKit) error {
+func (action *buildAction) Handle(ctx context.Context, kit *v1alpha1.IntegrationKit) (*v1alpha1.IntegrationKit, error) {
 	if kit.Status.Phase == v1alpha1.IntegrationKitPhaseBuildSubmitted {
 		return action.handleBuildSubmitted(ctx, kit)
 	} else if kit.Status.Phase == v1alpha1.IntegrationKitPhaseBuildRunning {
 		return action.handleBuildRunning(ctx, kit)
 	}
 
-	return nil
+	return nil, nil
 }
 
-func (action *buildAction) handleBuildSubmitted(ctx context.Context, kit *v1alpha1.IntegrationKit) error {
+func (action *buildAction) handleBuildSubmitted(ctx context.Context, kit *v1alpha1.IntegrationKit) (*v1alpha1.IntegrationKit, error) {
 	build, err := kubernetes.GetBuild(ctx, action.client, kit.Name, kit.Namespace)
 	if err != nil && !k8serrors.IsNotFound(err) {
-		return err
+		return nil, err
 	}
 
 	if err != nil && k8serrors.IsNotFound(err) ||
@@ -75,11 +75,11 @@ func (action *buildAction) handleBuildSubmitted(ctx context.Context, kit *v1alph
 
 		env, err := trait.Apply(ctx, action.client, nil, kit)
 		if err != nil {
-			return err
+			return nil, err
 		}
 
 		if env.CamelCatalog == nil {
-			return errors.New("undefined camel catalog")
+			return nil, errors.New("undefined camel catalog")
 		}
 
 		build = &v1alpha1.Build{
@@ -104,97 +104,81 @@ func (action *buildAction) handleBuildSubmitted(ctx context.Context, kit *v1alph
 
 		// Set the integration kit instance as the owner and controller
 		if err := controllerutil.SetControllerReference(kit, build, action.client.GetScheme()); err != nil {
-			return err
+			return nil, err
 		}
 
 		err = action.client.Delete(ctx, build)
 		if err != nil && !k8serrors.IsNotFound(err) {
-			return errors.Wrap(err, "cannot delete build")
+			return nil, errors.Wrap(err, "cannot delete build")
 		}
 
 		err = action.client.Create(ctx, build)
 		if err != nil {
-			return errors.Wrap(err, "cannot create build")
+			return nil, errors.Wrap(err, "cannot create build")
 		}
 	}
 
 	if build.Status.Phase == v1alpha1.BuildPhaseRunning {
-		target := kit.DeepCopy()
-		target.Status.Phase = v1alpha1.IntegrationKitPhaseBuildRunning
-
-		action.L.Info("IntegrationKit state transition", "phase", target.Status.Phase)
-
-		return action.client.Status().Update(ctx, target)
+		kit.Status.Phase = v1alpha1.IntegrationKitPhaseBuildRunning
+		return kit, nil
 	}
 
-	return nil
+	return nil, nil
 }
 
-func (action *buildAction) handleBuildRunning(ctx context.Context, kit *v1alpha1.IntegrationKit) error {
+func (action *buildAction) handleBuildRunning(ctx context.Context, kit *v1alpha1.IntegrationKit) (*v1alpha1.IntegrationKit, error) {
 	build, err := kubernetes.GetBuild(ctx, action.client, kit.Name, kit.Namespace)
 	if err != nil {
-		return err
+		return nil, err
 	}
 
 	switch build.Status.Phase {
-
 	case v1alpha1.BuildPhaseRunning:
 		action.L.Info("Build running")
-
 	case v1alpha1.BuildPhaseSucceeded:
-		target := kit.DeepCopy()
-
 		// we should ensure that the integration kit is still in the right phase,
 		// if not there is a chance that the kit has been modified by the user
-		if target.Status.Phase != v1alpha1.IntegrationKitPhaseBuildRunning {
-			return fmt.Errorf("found kit %s not in the expected phase (expectd=%s, found=%s)",
+		if kit.Status.Phase != v1alpha1.IntegrationKitPhaseBuildRunning {
+			return nil, fmt.Errorf("found kit %s not in the expected phase (expectd=%s, found=%s)",
 				build.Spec.Meta.Name,
 				string(v1alpha1.IntegrationKitPhaseBuildRunning),
-				string(target.Status.Phase),
+				string(kit.Status.Phase),
 			)
 		}
 
-		target.Status.BaseImage = build.Status.BaseImage
-		target.Status.Image = build.Status.Image
-		target.Status.PublicImage = build.Status.PublicImage
-		target.Status.Phase = v1alpha1.IntegrationKitPhaseReady
-		target.Status.Artifacts = make([]v1alpha1.Artifact, 0, len(build.Status.Artifacts))
+		kit.Status.BaseImage = build.Status.BaseImage
+		kit.Status.Image = build.Status.Image
+		kit.Status.PublicImage = build.Status.PublicImage
+		kit.Status.Phase = v1alpha1.IntegrationKitPhaseReady
+		kit.Status.Artifacts = make([]v1alpha1.Artifact, 0, len(build.Status.Artifacts))
 
 		for _, a := range build.Status.Artifacts {
 			// do not include artifact location
-			target.Status.Artifacts = append(target.Status.Artifacts, v1alpha1.Artifact{
+			kit.Status.Artifacts = append(kit.Status.Artifacts, v1alpha1.Artifact{
 				ID:       a.ID,
 				Location: "",
 				Target:   a.Target,
 			})
 		}
 
-		action.L.Info("IntegrationKit state transition", "phase", target.Status.Phase)
-		if err := action.client.Status().Update(ctx, target); err != nil {
-			return err
-		}
-
+		return kit, err
 	case v1alpha1.BuildPhaseError, v1alpha1.BuildPhaseInterrupted:
-		target := kit.DeepCopy()
-
 		// we should ensure that the integration kit is still in the right phase,
 		// if not there is a chance that the kit has been modified by the user
-		if target.Status.Phase != v1alpha1.IntegrationKitPhaseBuildRunning {
-			return fmt.Errorf("found kit %s not the an expected phase (expectd=%s, found=%s)",
+		if kit.Status.Phase != v1alpha1.IntegrationKitPhaseBuildRunning {
+			return nil, fmt.Errorf("found kit %s not the an expected phase (expectd=%s, found=%s)",
 				build.Spec.Meta.Name,
 				string(v1alpha1.IntegrationKitPhaseBuildRunning),
-				string(target.Status.Phase),
+				string(kit.Status.Phase),
 			)
 		}
 
 		// Let's copy the build failure to the integration kit status
-		target.Status.Failure = build.Status.Failure
-		target.Status.Phase = v1alpha1.IntegrationKitPhaseError
-
-		action.L.Error(fmt.Errorf(build.Status.Error), "IntegrationKit state transition", "phase", target.Status.Phase)
+		kit.Status.Failure = build.Status.Failure
+		kit.Status.Phase = v1alpha1.IntegrationKitPhaseError
 
-		return action.client.Status().Update(ctx, target)
+		return kit, nil
 	}
 
-	return nil
+	return nil, nil
 }
diff --git a/pkg/controller/integrationkit/initialize.go b/pkg/controller/integrationkit/initialize.go
index d90076b..9deb30f 100644
--- a/pkg/controller/integrationkit/initialize.go
+++ b/pkg/controller/integrationkit/initialize.go
@@ -23,7 +23,6 @@ import (
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 	"github.com/apache/camel-k/pkg/platform"
 	"github.com/apache/camel-k/pkg/trait"
-	"github.com/apache/camel-k/pkg/util/digest"
 )
 
 // NewInitializeAction creates a new initialization handling action for the kit
@@ -43,44 +42,35 @@ func (action *initializeAction) CanHandle(kit *v1alpha1.IntegrationKit) bool {
 	return kit.Status.Phase == ""
 }
 
-func (action *initializeAction) Handle(ctx context.Context, kit *v1alpha1.IntegrationKit) error {
+func (action *initializeAction) Handle(ctx context.Context, kit *v1alpha1.IntegrationKit) (*v1alpha1.IntegrationKit, error) {
 	// The integration platform needs to be initialized before starting to create kits
 	if _, err := platform.GetCurrentPlatform(ctx, action.client, kit.Namespace); err != nil {
 		action.L.Info("Waiting for the integration platform to be initialized")
-		return nil
+		return nil, nil
 	}
 
-	target := kit.DeepCopy()
-
-	_, err := trait.Apply(ctx, action.client, nil, target)
+	_, err := trait.Apply(ctx, action.client, nil, kit)
 	if err != nil {
-		return err
+		return nil, err
 	}
 
 	// Updating the whole integration kit as it may have changed
 	action.L.Info("Updating IntegrationKit")
-	if err := action.client.Update(ctx, target); err != nil {
-		return err
+	if err := action.client.Update(ctx, kit); err != nil {
+		return nil, err
 	}
 
-	if target.Spec.Image == "" {
+	if kit.Spec.Image == "" {
 		// by default the kit should be built
-		target.Status.Phase = v1alpha1.IntegrationKitPhaseBuildSubmitted
+		kit.Status.Phase = v1alpha1.IntegrationKitPhaseBuildSubmitted
 	} else {
 		// but in case it has been created from an image, mark the
 		// kit as ready
-		target.Status.Phase = v1alpha1.IntegrationKitPhaseReady
+		kit.Status.Phase = v1alpha1.IntegrationKitPhaseReady
 
 		// and set the image to be used
-		target.Status.Image = target.Spec.Image
-	}
-
-	dgst, err := digest.ComputeForIntegrationKit(target)
-	if err != nil {
-		return err
+		kit.Status.Image = kit.Spec.Image
 	}
-	target.Status.Digest = dgst
 
-	action.L.Info("IntegrationKit state transition", "phase", target.Status.Phase)
-	return action.client.Status().Update(ctx, target)
+	return kit, nil
 }
diff --git a/pkg/controller/integrationkit/integrationkit_controller.go b/pkg/controller/integrationkit/integrationkit_controller.go
index 57d580a..2d02a2d 100644
--- a/pkg/controller/integrationkit/integrationkit_controller.go
+++ b/pkg/controller/integrationkit/integrationkit_controller.go
@@ -19,6 +19,8 @@ package integrationkit
 import (
 	"context"
 
+	"github.com/apache/camel-k/pkg/util/digest"
+
 	"k8s.io/apimachinery/pkg/api/errors"
 	k8serrors "k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/runtime"
@@ -128,8 +130,7 @@ func (r *ReconcileIntegrationKit) Reconcile(request reconcile.Request) (reconcil
 	var instance v1alpha1.IntegrationKit
 
 	// Fetch the IntegrationKit instance
-	err := r.client.Get(ctx, request.NamespacedName, &instance)
-	if err != nil {
+	if err := r.client.Get(ctx, request.NamespacedName, &instance); err != nil {
 		if errors.IsNotFound(err) {
 			// Request object not found, could have been deleted after reconcile request.
 			// Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
@@ -140,26 +141,65 @@ func (r *ReconcileIntegrationKit) Reconcile(request reconcile.Request) (reconcil
 		return reconcile.Result{}, err
 	}
 
-	actionPool := []Action{
+	actions := []Action{
 		NewInitializeAction(),
 		NewBuildAction(),
 		NewMonitorAction(),
 	}
 
-	ilog := rlog.ForIntegrationKit(&instance)
-	for _, a := range actionPool {
+	var targetPhase v1alpha1.IntegrationKitPhase
+
+	target := instance.DeepCopy()
+	targetLog := rlog.ForIntegrationKit(target)
+
+	for _, a := range actions {
 		a.InjectClient(r.client)
-		a.InjectLogger(ilog)
-		if a.CanHandle(&instance) {
-			ilog.Infof("Invoking action %s", a.Name())
-			if err := a.Handle(ctx, &instance); err != nil {
-				if k8serrors.IsConflict(err) {
-					ilog.Error(err, "conflict")
+		a.InjectLogger(targetLog)
+
+		if a.CanHandle(target) {
+			targetLog.Infof("Invoking action %s", a.Name())
+
+			phaseFrom := target.Status.Phase
+			target = target.DeepCopy()
+
+			t, err := a.Handle(ctx, target)
+			if err != nil {
+				return reconcile.Result{
+					Requeue: true,
+				}, nil
+			}
+
+			if t != nil {
+				target = t
+
+				dgst, err := digest.ComputeForIntegrationKit(target)
+				if err != nil {
 					return reconcile.Result{
 						Requeue: true,
 					}, nil
 				}
 
+				target.Status.Digest = dgst
+
+				if err := r.client.Status().Update(ctx, target); err != nil {
+					if k8serrors.IsConflict(err) {
+						targetLog.Error(err, "conflict")
+						return reconcile.Result{
+							Requeue: true,
+						}, nil
+					}
+				}
+
+				targetPhase = target.Status.Phase
+
+				if targetPhase != phaseFrom {
+					targetLog.Info(
+						"state transition",
+						"phase-from", phaseFrom,
+						"phase-to", target.Status.Phase,
+					)
+				}
+
 				return reconcile.Result{}, err
 			}
 		}
diff --git a/pkg/controller/integrationkit/monitor.go b/pkg/controller/integrationkit/monitor.go
index 79671e3..a3910b1 100644
--- a/pkg/controller/integrationkit/monitor.go
+++ b/pkg/controller/integrationkit/monitor.go
@@ -41,22 +41,19 @@ func (action *monitorAction) CanHandle(kit *v1alpha1.IntegrationKit) bool {
 	return kit.Status.Phase == v1alpha1.IntegrationKitPhaseReady || kit.Status.Phase == v1alpha1.IntegrationKitPhaseError
 }
 
-func (action *monitorAction) Handle(ctx context.Context, kit *v1alpha1.IntegrationKit) error {
+func (action *monitorAction) Handle(ctx context.Context, kit *v1alpha1.IntegrationKit) (*v1alpha1.IntegrationKit, error) {
 	hash, err := digest.ComputeForIntegrationKit(kit)
 	if err != nil {
-		return err
+		return nil, err
 	}
 	if hash != kit.Status.Digest {
 		action.L.Info("IntegrationKit needs a rebuild")
 
-		target := kit.DeepCopy()
-		target.Status.Digest = hash
-		target.Status.Phase = v1alpha1.IntegrationKitPhaseBuildSubmitted
+		kit.Status.Digest = hash
+		kit.Status.Phase = v1alpha1.IntegrationKitPhaseBuildSubmitted
 
-		action.L.Info("IntegrationKit state transition", "phase", target.Status.Phase)
-
-		return action.client.Status().Update(ctx, target)
+		return kit, nil
 	}
 
-	return nil
+	return nil, nil
 }