diff --git a/pkg/apis/camel/v1alpha1/build_types.go b/pkg/apis/camel/v1alpha1/build_types.go index 1c516617b8..b70ffd0f3e 100644 --- a/pkg/apis/camel/v1alpha1/build_types.go +++ b/pkg/apis/camel/v1alpha1/build_types.go @@ -64,8 +64,12 @@ const ( // BuildKind -- BuildKind string = "Build" - // BuildPhaseInitial -- - BuildPhaseInitial BuildPhase = "" + // BuildPhaseNone -- + BuildPhaseNone BuildPhase = "" + // BuildPhaseInitialization -- + BuildPhaseInitialization BuildPhase = "initialization" + // BuildPhaseWaitingForPlatform -- + BuildPhaseWaitingForPlatform BuildPhase = "Waiting For Platform" // BuildPhaseScheduling -- BuildPhaseScheduling BuildPhase = "Scheduling" // BuildPhasePending -- diff --git a/pkg/apis/camel/v1alpha1/common_types_support.go b/pkg/apis/camel/v1alpha1/common_types_support.go index 09cf835b6e..b09ee3f5aa 100644 --- a/pkg/apis/camel/v1alpha1/common_types_support.go +++ b/pkg/apis/camel/v1alpha1/common_types_support.go @@ -19,12 +19,22 @@ package v1alpha1 import ( "fmt" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) func (in *Artifact) String() string { return in.ID } -func (spec ConfigurationSpec) String() string { - return fmt.Sprintf("%s=%s", spec.Type, spec.Value) +func (in *ConfigurationSpec) String() string { + return fmt.Sprintf("%s=%s", in.Type, in.Value) +} + +// NewErrorFailure -- +func NewErrorFailure(err error) *Failure { + return &Failure{ + Reason: err.Error(), + Time: metav1.Now(), + } } diff --git a/pkg/apis/camel/v1alpha1/integration_types.go b/pkg/apis/camel/v1alpha1/integration_types.go index 9127432920..86ab6f35f8 100644 --- a/pkg/apis/camel/v1alpha1/integration_types.go +++ b/pkg/apis/camel/v1alpha1/integration_types.go @@ -142,8 +142,10 @@ const ( // IntegrationKind -- IntegrationKind string = "Integration" - // IntegrationPhaseInitial -- - IntegrationPhaseInitial IntegrationPhase = "" + // IntegrationPhaseNone -- + IntegrationPhaseNone IntegrationPhase = "" + // IntegrationPhaseInitialization -- + IntegrationPhaseInitialization IntegrationPhase = "initialization" // IntegrationPhaseWaitingForPlatform -- IntegrationPhaseWaitingForPlatform IntegrationPhase = "Waiting For Platform" // IntegrationPhaseBuildingKit -- diff --git a/pkg/apis/camel/v1alpha1/integrationkit_types.go b/pkg/apis/camel/v1alpha1/integrationkit_types.go index 2d199ae5c8..a00cc861ec 100644 --- a/pkg/apis/camel/v1alpha1/integrationkit_types.go +++ b/pkg/apis/camel/v1alpha1/integrationkit_types.go @@ -82,8 +82,10 @@ const ( // IntegrationKitTypeExternal -- IntegrationKitTypeExternal = "external" - // IntegrationKitPhaseInitial -- - IntegrationKitPhaseInitial IntegrationKitPhase = "" + // IntegrationKitPhaseNone -- + IntegrationKitPhaseNone IntegrationKitPhase = "" + // IntegrationKitPhaseInitialization -- + IntegrationKitPhaseInitialization IntegrationKitPhase = "initialization" // IntegrationKitPhaseWaitingForPlatform -- IntegrationKitPhaseWaitingForPlatform IntegrationKitPhase = "Waiting For Platform" // IntegrationKitPhaseBuildSubmitted -- diff --git a/pkg/controller/build/build_controller.go b/pkg/controller/build/build_controller.go index fd85160468..b88d0cb992 100644 --- a/pkg/controller/build/build_controller.go +++ b/pkg/controller/build/build_controller.go @@ -21,6 +21,7 @@ import ( "sync" "time" + "github.com/apache/camel-k/pkg/platform" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" k8serrors "k8s.io/apimachinery/pkg/api/errors" @@ -161,6 +162,34 @@ func (r *ReconcileBuild) Reconcile(request reconcile.Request) (reconcile.Result, return reconcile.Result{}, err } + target := instance.DeepCopy() + targetLog := rlog.ForBuild(target) + + if target.Status.Phase == v1alpha1.BuildPhaseNone || target.Status.Phase == v1alpha1.BuildPhaseWaitingForPlatform { + pl, err := platform.GetCurrentPlatform(ctx, r.client, target.Namespace) + switch { + case err != nil: + target.Status.Phase = v1alpha1.BuildPhaseError + target.Status.Failure = v1alpha1.NewErrorFailure(err) + case pl.Status.Phase != v1alpha1.IntegrationPlatformPhaseReady: + target.Status.Phase = v1alpha1.BuildPhaseWaitingForPlatform + default: + target.Status.Phase = v1alpha1.BuildPhaseInitialization + } + + if instance.Status.Phase != target.Status.Phase { + err = r.update(ctx, target) + if err != nil { + if k8serrors.IsConflict(err) { + targetLog.Error(err, "conflict") + err = nil + } + } + } + + return reconcile.Result{}, err + } + actions := []Action{ NewInitializeAction(), NewScheduleRoutineAction(r.reader, r.builder, &r.routines), @@ -168,14 +197,9 @@ func (r *ReconcileBuild) Reconcile(request reconcile.Request) (reconcile.Result, NewMonitorRoutineAction(&r.routines), NewMonitorPodAction(), NewErrorRecoveryAction(), + NewErrorAction(), } - var err error - - target := instance.DeepCopy() - targetPhase := target.Status.Phase - targetLog := rlog.ForBuild(target) - for _, a := range actions { a.InjectClient(r.client) a.InjectLogger(targetLog) @@ -183,15 +207,13 @@ func (r *ReconcileBuild) Reconcile(request reconcile.Request) (reconcile.Result, if a.CanHandle(target) { targetLog.Infof("Invoking action %s", a.Name()) - phaseFrom := target.Status.Phase - - target, err = a.Handle(ctx, target) + newTarget, err := a.Handle(ctx, target) if err != nil { return reconcile.Result{}, err } - if target != nil { - if err := r.client.Status().Update(ctx, target); err != nil { + if newTarget != nil { + if err := r.update(ctx, newTarget); err != nil { if k8serrors.IsConflict(err) { targetLog.Error(err, "conflict") return reconcile.Result{ @@ -202,15 +224,15 @@ func (r *ReconcileBuild) Reconcile(request reconcile.Request) (reconcile.Result, return reconcile.Result{}, err } - targetPhase = target.Status.Phase - - if targetPhase != phaseFrom { + if newTarget.Status.Phase != target.Status.Phase { targetLog.Info( "state transition", - "phase-from", phaseFrom, - "phase-to", target.Status.Phase, + "phase-from", target.Status.Phase, + "phase-to", newTarget.Status.Phase, ) } + + target = newTarget } // handle one action at time so the resource @@ -220,7 +242,7 @@ func (r *ReconcileBuild) Reconcile(request reconcile.Request) (reconcile.Result, } // Requeue scheduling build so that it re-enters the build working queue - if targetPhase == v1alpha1.BuildPhaseScheduling || targetPhase == v1alpha1.BuildPhaseFailed { + if target.Status.Phase == v1alpha1.BuildPhaseScheduling || target.Status.Phase == v1alpha1.BuildPhaseFailed { return reconcile.Result{ RequeueAfter: 5 * time.Second, }, nil @@ -228,3 +250,8 @@ func (r *ReconcileBuild) Reconcile(request reconcile.Request) (reconcile.Result, return reconcile.Result{}, nil } + +// Update -- +func (r *ReconcileBuild) update(ctx context.Context, target *v1alpha1.Build) error { + return r.client.Status().Update(ctx, target) +} diff --git a/pkg/controller/build/error.go b/pkg/controller/build/error.go new file mode 100644 index 0000000000..62d42b88a3 --- /dev/null +++ b/pkg/controller/build/error.go @@ -0,0 +1,48 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package build + +import ( + "context" + + "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" +) + +// NewErrorAction creates a new error action for scheduled routine +func NewErrorAction() Action { + return &errorAction{} +} + +type errorAction struct { + baseAction +} + +// Name returns a common name of the action +func (action *errorAction) Name() string { + return "error" +} + +// CanHandle tells whether this action can handle the build +func (action *errorAction) CanHandle(build *v1alpha1.Build) bool { + return build.Status.Phase == v1alpha1.BuildPhaseError +} + +// Handle handles the builds +func (action *errorAction) Handle(ctx context.Context, build *v1alpha1.Build) (*v1alpha1.Build, error) { + return nil, nil +} diff --git a/pkg/controller/build/initialize.go b/pkg/controller/build/initialize.go index a6fba9cc17..a3c0674601 100644 --- a/pkg/controller/build/initialize.go +++ b/pkg/controller/build/initialize.go @@ -39,7 +39,7 @@ func (action *initializeAction) Name() string { // CanHandle tells whether this action can handle the build func (action *initializeAction) CanHandle(build *v1alpha1.Build) bool { - return build.Status.Phase == v1alpha1.BuildPhaseInitial + return build.Status.Phase == v1alpha1.BuildPhaseInitialization } // Handle handles the builds diff --git a/pkg/controller/build/recovery.go b/pkg/controller/build/recovery.go index 4492c87b80..f7abc9726c 100644 --- a/pkg/controller/build/recovery.go +++ b/pkg/controller/build/recovery.go @@ -24,8 +24,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" - "github.com/apache/camel-k/pkg/platform" - "github.com/jpillora/backoff" ) @@ -56,12 +54,6 @@ func (action *errorRecoveryAction) CanHandle(build *v1alpha1.Build) bool { } func (action *errorRecoveryAction) Handle(ctx context.Context, build *v1alpha1.Build) (*v1alpha1.Build, error) { - // The integration platform must be initialized before handling the error recovery - if _, err := platform.GetCurrentPlatform(ctx, action.client, build.Namespace); err != nil { - action.L.Info("Waiting for an integration platform to be initialized") - return nil, nil - } - if build.Status.Failure == nil { build.Status.Failure = &v1alpha1.Failure{ Reason: build.Status.Error, @@ -96,7 +88,7 @@ func (action *errorRecoveryAction) Handle(ctx context.Context, build *v1alpha1.B } build.Status = v1alpha1.BuildStatus{} - build.Status.Phase = v1alpha1.BuildPhaseInitial + build.Status.Phase = v1alpha1.BuildPhaseInitialization build.Status.Failure.Recovery.Attempt++ build.Status.Failure.Recovery.AttemptTime = metav1.Now() diff --git a/pkg/controller/integration/deploy.go b/pkg/controller/integration/deploy.go index 36c43ec46a..d61e5ec806 100644 --- a/pkg/controller/integration/deploy.go +++ b/pkg/controller/integration/deploy.go @@ -57,8 +57,7 @@ func (action *deployAction) Handle(ctx context.Context, integration *v1alpha1.In return nil, err } - target := integration.DeepCopy() - target.Status.Phase = v1alpha1.IntegrationPhaseRunning + integration.Status.Phase = v1alpha1.IntegrationPhaseRunning return integration, nil } diff --git a/pkg/controller/integration/error.go b/pkg/controller/integration/error.go new file mode 100644 index 0000000000..262e86638a --- /dev/null +++ b/pkg/controller/integration/error.go @@ -0,0 +1,61 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package integration + +import ( + "context" + + "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" + "github.com/apache/camel-k/pkg/util/digest" +) + +// NewErrorAction creates a new error action for an integration +func NewErrorAction() Action { + return &errorAction{} +} + +type errorAction struct { + baseAction +} + +func (action *errorAction) Name() string { + return "error" +} + +func (action *errorAction) CanHandle(integration *v1alpha1.Integration) bool { + return integration.Status.Phase == v1alpha1.IntegrationPhaseError +} + +func (action *errorAction) Handle(ctx context.Context, integration *v1alpha1.Integration) (*v1alpha1.Integration, error) { + hash, err := digest.ComputeForIntegration(integration) + if err != nil { + return nil, err + } + + if hash != integration.Status.Digest { + action.L.Info("Integration needs a rebuild") + + integration.Status.Digest = hash + integration.Status.Phase = v1alpha1.IntegrationPhaseInitialization + + return integration, nil + } + + // TODO check also if deployment matches (e.g. replicas) + return nil, nil +} diff --git a/pkg/controller/integration/initialize.go b/pkg/controller/integration/initialize.go index 8fed1e8ca2..53be34d68b 100644 --- a/pkg/controller/integration/initialize.go +++ b/pkg/controller/integration/initialize.go @@ -21,7 +21,6 @@ import ( "context" "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" - "github.com/apache/camel-k/pkg/platform" "github.com/apache/camel-k/pkg/trait" ) @@ -41,42 +40,11 @@ func (action *initializeAction) Name() string { // CanHandle tells whether this action can handle the integration func (action *initializeAction) CanHandle(integration *v1alpha1.Integration) bool { - return integration.Status.Phase == v1alpha1.IntegrationPhaseInitial || integration.Status.Phase == v1alpha1.IntegrationPhaseWaitingForPlatform + return integration.Status.Phase == v1alpha1.IntegrationPhaseInitialization } // Handle handles the integrations func (action *initializeAction) Handle(ctx context.Context, integration *v1alpha1.Integration) (*v1alpha1.Integration, error) { - pl, err := platform.GetCurrentPlatform(ctx, action.client, integration.Namespace) - if err != nil { - return nil, err - } - - // The integration platform needs to be ready before starting to create integrations - if pl.Status.Phase != v1alpha1.IntegrationPlatformPhaseReady { - action.L.Info("Waiting for the integration platform to be initialized") - - if integration.Status.Phase != v1alpha1.IntegrationPhaseWaitingForPlatform { - integration.Status.Phase = v1alpha1.IntegrationPhaseWaitingForPlatform - return integration, nil - } - - return nil, nil - } - - // - // restore phase to initial phase as traits are not aware of - // WaitingForPlatform phase - // - if integration.Status.Phase == v1alpha1.IntegrationPhaseWaitingForPlatform { - integration.Status.Phase = v1alpha1.IntegrationPhaseInitial - - return integration, nil - } - - // better not changing the spec section of the target because it may be used for comparison by a - // higher level controller (e.g. Knative source controller) - - // execute custom initialization if _, err := trait.Apply(ctx, action.client, integration, nil); err != nil { return nil, err } diff --git a/pkg/controller/integration/integration_controller.go b/pkg/controller/integration/integration_controller.go index e6042525b4..2bdfb96efc 100644 --- a/pkg/controller/integration/integration_controller.go +++ b/pkg/controller/integration/integration_controller.go @@ -19,6 +19,8 @@ package integration import ( "context" + "github.com/apache/camel-k/pkg/platform" + "github.com/apache/camel-k/pkg/util/digest" "k8s.io/apimachinery/pkg/api/errors" @@ -224,25 +226,48 @@ func (r *ReconcileIntegration) Reconcile(request reconcile.Request) (reconcile.R return reconcile.Result{}, err } - actions := []Action{ - NewInitializeAction(), - NewBuildKitAction(), - NewDeployAction(), - NewMonitorAction(), - NewDeleteAction(), - } - // Delete phase if instance.GetDeletionTimestamp() != nil { instance.Status.Phase = v1alpha1.IntegrationPhaseDeleting } - var targetPhase v1alpha1.IntegrationPhase - var err error - target := instance.DeepCopy() targetLog := rlog.ForIntegration(target) + if target.Status.Phase == v1alpha1.IntegrationPhaseNone || target.Status.Phase == v1alpha1.IntegrationPhaseWaitingForPlatform { + pl, err := platform.GetCurrentPlatform(ctx, r.client, target.Namespace) + switch { + case err != nil: + target.Status.Phase = v1alpha1.IntegrationPhaseError + target.Status.Failure = v1alpha1.NewErrorFailure(err) + case pl.Status.Phase != v1alpha1.IntegrationPlatformPhaseReady: + target.Status.Phase = v1alpha1.IntegrationPhaseWaitingForPlatform + default: + target.Status.Phase = v1alpha1.IntegrationPhaseInitialization + } + + if instance.Status.Phase != target.Status.Phase { + err = r.update(ctx, target) + if err != nil { + if k8serrors.IsConflict(err) { + targetLog.Error(err, "conflict") + err = nil + } + } + } + + return reconcile.Result{}, err + } + + actions := []Action{ + NewInitializeAction(), + NewBuildKitAction(), + NewDeployAction(), + NewMonitorAction(), + NewErrorAction(), + NewDeleteAction(), + } + for _, a := range actions { a.InjectClient(r.client) a.InjectLogger(targetLog) @@ -250,22 +275,13 @@ func (r *ReconcileIntegration) Reconcile(request reconcile.Request) (reconcile.R if a.CanHandle(target) { targetLog.Infof("Invoking action %s", a.Name()) - phaseFrom := target.Status.Phase - - target, err = a.Handle(ctx, target) + newTarget, err := a.Handle(ctx, target) if err != nil { return reconcile.Result{}, err } - if target != nil { - dgst, err := digest.ComputeForIntegration(target) - if err != nil { - return reconcile.Result{}, err - } - - target.Status.Digest = dgst - - if err := r.client.Status().Update(ctx, target); err != nil { + if newTarget != nil { + if err := r.update(ctx, newTarget); err != nil { if k8serrors.IsConflict(err) { targetLog.Error(err, "conflict") return reconcile.Result{ @@ -276,13 +292,11 @@ func (r *ReconcileIntegration) Reconcile(request reconcile.Request) (reconcile.R return reconcile.Result{}, err } - targetPhase = target.Status.Phase - - if targetPhase != phaseFrom { + if newTarget.Status.Phase != target.Status.Phase { targetLog.Info( "state transition", - "phase-from", phaseFrom, - "phase-to", target.Status.Phase, + "phase-from", target.Status.Phase, + "phase-to", newTarget.Status.Phase, ) } } @@ -295,3 +309,15 @@ func (r *ReconcileIntegration) Reconcile(request reconcile.Request) (reconcile.R return reconcile.Result{}, nil } + +// Update -- +func (r *ReconcileIntegration) update(ctx context.Context, target *v1alpha1.Integration) error { + dgst, err := digest.ComputeForIntegration(target) + if err != nil { + return err + } + + target.Status.Digest = dgst + + return r.client.Status().Update(ctx, target) +} diff --git a/pkg/controller/integration/monitor.go b/pkg/controller/integration/monitor.go index b5c99cb235..f4ff480703 100644 --- a/pkg/controller/integration/monitor.go +++ b/pkg/controller/integration/monitor.go @@ -38,8 +38,7 @@ func (action *monitorAction) Name() string { } func (action *monitorAction) CanHandle(integration *v1alpha1.Integration) bool { - return integration.Status.Phase == v1alpha1.IntegrationPhaseRunning || - integration.Status.Phase == v1alpha1.IntegrationPhaseError + return integration.Status.Phase == v1alpha1.IntegrationPhaseRunning } func (action *monitorAction) Handle(ctx context.Context, integration *v1alpha1.Integration) (*v1alpha1.Integration, error) { @@ -52,7 +51,7 @@ func (action *monitorAction) Handle(ctx context.Context, integration *v1alpha1.I action.L.Info("Integration needs a rebuild") integration.Status.Digest = hash - integration.Status.Phase = "" + integration.Status.Phase = v1alpha1.IntegrationPhaseInitialization return integration, nil } diff --git a/pkg/controller/integrationkit/error.go b/pkg/controller/integrationkit/error.go new file mode 100644 index 0000000000..ac63e4641b --- /dev/null +++ b/pkg/controller/integrationkit/error.go @@ -0,0 +1,59 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package integrationkit + +import ( + "context" + + "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" + "github.com/apache/camel-k/pkg/util/digest" +) + +// NewErrorAction creates a new error handling action for the kit +func NewErrorAction() Action { + return &errorAction{} +} + +type errorAction struct { + baseAction +} + +func (action *errorAction) Name() string { + return "error" +} + +func (action *errorAction) CanHandle(kit *v1alpha1.IntegrationKit) bool { + return kit.Status.Phase == v1alpha1.IntegrationKitPhaseError +} + +func (action *errorAction) Handle(ctx context.Context, kit *v1alpha1.IntegrationKit) (*v1alpha1.IntegrationKit, error) { + hash, err := digest.ComputeForIntegrationKit(kit) + if err != nil { + return nil, err + } + if hash != kit.Status.Digest { + action.L.Info("IntegrationKit needs a rebuild") + + kit.Status.Digest = hash + kit.Status.Phase = v1alpha1.IntegrationKitPhaseInitialization + + return kit, nil + } + + return nil, nil +} diff --git a/pkg/controller/integrationkit/initialize.go b/pkg/controller/integrationkit/initialize.go index 405797f136..cfdb138e78 100644 --- a/pkg/controller/integrationkit/initialize.go +++ b/pkg/controller/integrationkit/initialize.go @@ -21,7 +21,6 @@ import ( "context" "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" - "github.com/apache/camel-k/pkg/platform" "github.com/apache/camel-k/pkg/trait" ) @@ -39,18 +38,11 @@ func (action *initializeAction) Name() string { } func (action *initializeAction) CanHandle(kit *v1alpha1.IntegrationKit) bool { - return kit.Status.Phase == v1alpha1.IntegrationKitPhaseInitial || kit.Status.Phase == v1alpha1.IntegrationKitPhaseWaitingForPlatform + return kit.Status.Phase == v1alpha1.IntegrationKitPhaseInitialization } 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 - _, err := platform.GetCurrentPlatform(ctx, action.client, kit.Namespace) - if err != nil { - action.L.Info("Waiting for the integration platform to be initialized") - return nil, nil - } - - _, err = trait.Apply(ctx, action.client, nil, kit) + _, err := trait.Apply(ctx, action.client, nil, kit) if err != nil { return nil, err } diff --git a/pkg/controller/integrationkit/integrationkit_controller.go b/pkg/controller/integrationkit/integrationkit_controller.go index bca22e2f7f..ff401d523f 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/platform" + "github.com/apache/camel-k/pkg/util/digest" "k8s.io/apimachinery/pkg/api/errors" @@ -141,18 +143,41 @@ func (r *ReconcileIntegrationKit) Reconcile(request reconcile.Request) (reconcil return reconcile.Result{}, err } + target := instance.DeepCopy() + targetLog := rlog.ForIntegrationKit(target) + + if target.Status.Phase == v1alpha1.IntegrationKitPhaseNone || target.Status.Phase == v1alpha1.IntegrationKitPhaseWaitingForPlatform { + pl, err := platform.GetCurrentPlatform(ctx, r.client, target.Namespace) + switch { + case err != nil: + target.Status.Phase = v1alpha1.IntegrationKitPhaseError + target.Status.Failure = v1alpha1.NewErrorFailure(err) + case pl.Status.Phase != v1alpha1.IntegrationPlatformPhaseReady: + target.Status.Phase = v1alpha1.IntegrationKitPhaseWaitingForPlatform + default: + target.Status.Phase = v1alpha1.IntegrationKitPhaseInitialization + } + + if instance.Status.Phase != target.Status.Phase { + err = r.update(ctx, target) + if err != nil { + if k8serrors.IsConflict(err) { + targetLog.Error(err, "conflict") + err = nil + } + } + } + + return reconcile.Result{}, err + } + actions := []Action{ NewInitializeAction(), NewBuildAction(), NewMonitorAction(), + NewErrorAction(), } - var targetPhase v1alpha1.IntegrationKitPhase - var err error - - target := instance.DeepCopy() - targetLog := rlog.ForIntegrationKit(target) - for _, a := range actions { a.InjectClient(r.client) a.InjectLogger(targetLog) @@ -160,23 +185,13 @@ func (r *ReconcileIntegrationKit) Reconcile(request reconcile.Request) (reconcil if a.CanHandle(target) { targetLog.Infof("Invoking action %s", a.Name()) - phaseFrom := target.Status.Phase - - target, err = a.Handle(ctx, target) + newTarget, err := a.Handle(ctx, target) if err != nil { return reconcile.Result{}, err } - if target != nil { - dgst, err := digest.ComputeForIntegrationKit(target) - if err != nil { - return reconcile.Result{}, err - } - - target.Status.Digest = dgst - - err = r.client.Status().Update(ctx, target) - if err != nil { + if newTarget != nil { + if err := r.update(ctx, newTarget); err != nil { if k8serrors.IsConflict(err) { targetLog.Error(err, "conflict") return reconcile.Result{ @@ -187,13 +202,11 @@ func (r *ReconcileIntegrationKit) Reconcile(request reconcile.Request) (reconcil return reconcile.Result{}, err } - targetPhase = target.Status.Phase - - if targetPhase != phaseFrom { + if newTarget.Status.Phase != target.Status.Phase { targetLog.Info( "state transition", - "phase-from", phaseFrom, - "phase-to", target.Status.Phase, + "phase-from", target.Status.Phase, + "phase-to", newTarget.Status.Phase, ) } } @@ -206,3 +219,15 @@ func (r *ReconcileIntegrationKit) Reconcile(request reconcile.Request) (reconcil return reconcile.Result{}, nil } + +// Update -- +func (r *ReconcileIntegrationKit) update(ctx context.Context, target *v1alpha1.IntegrationKit) error { + dgst, err := digest.ComputeForIntegrationKit(target) + if err != nil { + return err + } + + target.Status.Digest = dgst + + return r.client.Status().Update(ctx, target) +} diff --git a/pkg/controller/integrationkit/monitor.go b/pkg/controller/integrationkit/monitor.go index a3910b1ef5..fdcfcbcf5f 100644 --- a/pkg/controller/integrationkit/monitor.go +++ b/pkg/controller/integrationkit/monitor.go @@ -38,7 +38,7 @@ func (action *monitorAction) Name() string { } func (action *monitorAction) CanHandle(kit *v1alpha1.IntegrationKit) bool { - return kit.Status.Phase == v1alpha1.IntegrationKitPhaseReady || kit.Status.Phase == v1alpha1.IntegrationKitPhaseError + return kit.Status.Phase == v1alpha1.IntegrationKitPhaseReady } func (action *monitorAction) Handle(ctx context.Context, kit *v1alpha1.IntegrationKit) (*v1alpha1.IntegrationKit, error) { @@ -50,7 +50,7 @@ func (action *monitorAction) Handle(ctx context.Context, kit *v1alpha1.Integrati action.L.Info("IntegrationKit needs a rebuild") kit.Status.Digest = hash - kit.Status.Phase = v1alpha1.IntegrationKitPhaseBuildSubmitted + kit.Status.Phase = v1alpha1.IntegrationKitPhaseInitialization return kit, nil } diff --git a/pkg/trait/builder_test.go b/pkg/trait/builder_test.go index a921cc8b0f..f1153d358f 100644 --- a/pkg/trait/builder_test.go +++ b/pkg/trait/builder_test.go @@ -66,7 +66,7 @@ func TestBuilderTraitNotAppliedBecauseOfNilPhase(t *testing.T) { for _, e := range environments { e := e // pin - e.IntegrationKit.Status.Phase = "" + e.IntegrationKit.Status.Phase = v1alpha1.IntegrationKitPhaseInitialization t.Run(string(e.Platform.Spec.Cluster), func(t *testing.T) { err := NewBuilderTestCatalog().apply(e) diff --git a/pkg/trait/gc.go b/pkg/trait/gc.go index 68da326e79..d104db1fba 100644 --- a/pkg/trait/gc.go +++ b/pkg/trait/gc.go @@ -46,7 +46,7 @@ func (t *garbageCollectorTrait) Configure(e *Environment) (bool, error) { return false, nil } - return e.IntegrationInPhase(v1alpha1.IntegrationPhaseInitial) || + return e.IntegrationInPhase(v1alpha1.IntegrationPhaseInitialization) || e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying), nil } diff --git a/pkg/trait/probes.go b/pkg/trait/probes.go index 7d76132118..1cfb46aad4 100644 --- a/pkg/trait/probes.go +++ b/pkg/trait/probes.go @@ -58,14 +58,14 @@ func newProbesTrait() *probesTrait { func (t *probesTrait) Configure(e *Environment) (bool, error) { if t.Enabled != nil && *t.Enabled { - return e.IntegrationInPhase(v1alpha1.IntegrationPhaseInitial) || e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying), nil + return e.IntegrationInPhase(v1alpha1.IntegrationPhaseInitialization) || e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying), nil } return false, nil } func (t *probesTrait) Apply(e *Environment) error { - if e.IntegrationInPhase(v1alpha1.IntegrationPhaseInitial) { + if e.IntegrationInPhase(v1alpha1.IntegrationPhaseInitialization) { util.StringSliceUniqueAdd(&e.Integration.Status.Dependencies, "runtime:health") // sort the dependencies to get always the same list if they don't change diff --git a/pkg/trait/probes_test.go b/pkg/trait/probes_test.go index 82c95cf609..90b6b56d83 100644 --- a/pkg/trait/probes_test.go +++ b/pkg/trait/probes_test.go @@ -34,7 +34,7 @@ func TestProbesDeps(t *testing.T) { e := Environment{ Integration: &v1alpha1.Integration{ Status: v1alpha1.IntegrationStatus{ - Phase: v1alpha1.IntegrationPhaseInitial, + Phase: v1alpha1.IntegrationPhaseInitialization, }, }, }