blob: ecadcc59af76f2332eb4d2a7d60a6a5387905698 [file] [log] [blame]
/*
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 (
"fmt"
"github.com/apache/camel-k/pkg/trait"
"github.com/sirupsen/logrus"
"github.com/apache/camel-k/pkg/util"
"github.com/apache/camel-k/pkg/util/digest"
"github.com/rs/xid"
"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
"github.com/operator-framework/operator-sdk/pkg/sdk"
)
// NewBuildContextAction create an action that handles integration context build
func NewBuildContextAction(namespace string) Action {
return &buildContextAction{
namespace: namespace,
}
}
type buildContextAction struct {
namespace string
}
func (action *buildContextAction) Name() string {
return "build-context"
}
func (action *buildContextAction) CanHandle(integration *v1alpha1.Integration) bool {
return integration.Status.Phase == v1alpha1.IntegrationPhaseBuildingContext
}
func (action *buildContextAction) Handle(integration *v1alpha1.Integration) error {
ctx, err := LookupContextForIntegration(integration)
if err != nil {
//TODO: we may need to add a wait strategy, i.e give up after some time
return err
}
if ctx != nil {
if ctx.Labels["camel.apache.org/context.type"] == v1alpha1.IntegrationContextTypePlatform {
// This is a platform context and as it is auto generated it may get
// out of sync if the integration that has generated it, has been
// amended to add/remove dependencies
//TODO: this is a very simple check, we may need to provide a deps comparison strategy
if !util.StringSliceContains(ctx.Spec.Dependencies, integration.Spec.Dependencies) {
// We need to re-generate a context or search for a new one that
// satisfies integrations needs so let's remove the association
// with a context
target := integration.DeepCopy()
target.Spec.Context = ""
return sdk.Update(target)
}
}
if ctx.Status.Phase == v1alpha1.IntegrationContextPhaseError {
target := integration.DeepCopy()
target.Status.Image = ctx.Status.Image
target.Spec.Context = ctx.Name
target.Status.Phase = v1alpha1.IntegrationPhaseError
target.Status.Digest, err = digest.ComputeForIntegration(target)
if err != nil {
return err
}
logrus.Info("Integration ", target.Name, " transitioning to state ", target.Status.Phase)
return sdk.Update(target)
}
if ctx.Status.Phase == v1alpha1.IntegrationContextPhaseReady {
target := integration.DeepCopy()
target.Status.Image = ctx.Status.Image
target.Spec.Context = ctx.Name
dgst, err := digest.ComputeForIntegration(target)
if err != nil {
return err
}
target.Status.Digest = dgst
if _, err := trait.Apply(target, ctx); err != nil {
return err
}
logrus.Info("Integration ", target.Name, " transitioning to state ", target.Status.Phase)
return sdk.Update(target)
}
if integration.Spec.Context == "" {
// We need to set the context
target := integration.DeepCopy()
target.Spec.Context = ctx.Name
return sdk.Update(target)
}
return nil
}
platformCtxName := fmt.Sprintf("ctx-%s", xid.New())
platformCtx := v1alpha1.NewIntegrationContext(action.namespace, platformCtxName)
// Add some information for post-processing, this may need to be refactored
// to a proper data structure
platformCtx.Labels = map[string]string{
"camel.apache.org/context.type": v1alpha1.IntegrationContextTypePlatform,
"camel.apache.org/context.created.by.kind": v1alpha1.IntegrationKind,
"camel.apache.org/context.created.by.name": integration.Name,
"camel.apache.org/context.created.by.version": integration.ResourceVersion,
}
// Set the context to have the same dependencies as the integrations
platformCtx.Spec = v1alpha1.IntegrationContextSpec{
Dependencies: integration.Spec.Dependencies,
Repositories: integration.Spec.Repositories,
Traits: integration.Spec.Traits,
}
if err := sdk.Create(&platformCtx); err != nil {
return err
}
// Set the context name so the next handle loop, will fall through the
// same path as integration with a user defined context
target := integration.DeepCopy()
target.Spec.Context = platformCtxName
return sdk.Update(target)
}