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 4390c77a9c9a79e1752dd838a2793f0d247c4f2c
Author: nferraro <ni.ferr...@gmail.com>
AuthorDate: Fri Jan 11 11:41:20 2019 +0100

    Fix #312: refactor platform image lookup into its own package
---
 cmd/util/publisher/publisher.go                    | 20 +++---
 pkg/builder/builder.go                             |  5 --
 pkg/builder/builder_steps.go                       | 49 -------------
 pkg/builder/kaniko/kaniko.go                       |  1 -
 pkg/builder/s2i/s2i.go                             |  1 -
 pkg/controller/integration/build_context.go        | 20 ++++--
 pkg/controller/integration/util.go                 | 44 ++++++++++--
 pkg/{builder/s2i/s2i.go => platform/images/doc.go} | 17 +----
 pkg/platform/images/images.go                      | 82 ++++++++++++++++++++++
 pkg/platform/images/images_test.go                 | 68 ++++++++++++++++++
 pkg/trait/builder_test.go                          |  4 +-
 11 files changed, 219 insertions(+), 92 deletions(-)

diff --git a/cmd/util/publisher/publisher.go b/cmd/util/publisher/publisher.go
index 857bbc0..e4dc8c3 100644
--- a/cmd/util/publisher/publisher.go
+++ b/cmd/util/publisher/publisher.go
@@ -33,6 +33,7 @@ import (
        "github.com/apache/camel-k/pkg/apis"
        "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
        "github.com/apache/camel-k/pkg/builder"
+       "github.com/apache/camel-k/pkg/platform/images"
        "github.com/apache/camel-k/pkg/util/camel"
        "github.com/apache/camel-k/pkg/util/kubernetes"
        "github.com/pkg/errors"
@@ -60,7 +61,7 @@ func main() {
 
        cmd.Flags().StringVar(&options.StartWith, "start-with", "", "The 
component to start with")
        cmd.Flags().StringVar(&options.EndWith, "end-with", "", "The component 
to end with")
-       cmd.Flags().IntVar(&options.BuildAttempts, "attempts", 5, "The maximum 
number of build attempts")
+       cmd.Flags().IntVar(&options.BuildAttempts, "attempts", 5, "The maximum 
number of build attempts for each image")
 
        panicIfErr(cmd.Execute())
 }
@@ -127,6 +128,13 @@ func (options *PublisherOptions) build(component string, 
camelVersion string) er
        }
        defer os.RemoveAll(dir)
 
+       dependencies := make([]string, 0)
+       for d := range images.StandardDependencies {
+               dependencies = append(dependencies, d)
+       }
+       dependencies = append(dependencies, images.BaseDependency)
+       dependencies = append(dependencies, "camel:"+component)
+
        ctx := builder.Context{
                C:    context.TODO(),
                Path: dir,
@@ -136,13 +144,7 @@ func (options *PublisherOptions) build(component string, 
camelVersion string) er
                                        CamelVersion: camelVersion,
                                },
                        },
-                       Dependencies: []string{
-                               "camel-k:knative",
-                               "camel:core",
-                               "runtime:jvm",
-                               "runtime:yaml",
-                               "camel:" + component,
-                       },
+                       Dependencies: dependencies,
                },
        }
 
@@ -170,7 +172,7 @@ func (options *PublisherOptions) build(component string, 
camelVersion string) er
                return err
        }
 
-       image := builder.PredefinedImageNameFor(component)
+       image := images.PredefinedImageNameFor(component)
        buildCmd := exec.Command("docker", "build", "-t", image, archiveDir)
        buildCmd.Stdout = os.Stdout
        buildCmd.Stderr = os.Stderr
diff --git a/pkg/builder/builder.go b/pkg/builder/builder.go
index ae61eaa..9becccb 100644
--- a/pkg/builder/builder.go
+++ b/pkg/builder/builder.go
@@ -168,11 +168,6 @@ func (b *defaultBuilder) submit(request Request) {
                        break
                }
 
-               if c.Image != "" && c.PublicImage != "" {
-                       logrus.Info("image already computed: skipping following 
steps")
-                       break
-               }
-
                select {
                case <-b.interrupt:
                        c.Error = errors.New("build canceled")
diff --git a/pkg/builder/builder_steps.go b/pkg/builder/builder_steps.go
index b5db1ca..79d98d8 100644
--- a/pkg/builder/builder_steps.go
+++ b/pkg/builder/builder_steps.go
@@ -152,55 +152,6 @@ func ComputeDependencies(ctx *Context) error {
        return nil
 }
 
-// LookupPredefinedImage is used to find a suitable predefined image if 
available
-func LookupPredefinedImage(ctx *Context) error {
-       if !ctx.Request.Platform.Build.PredefinedImages {
-               // Usage of predefined images not enabled
-               return nil
-       }
-
-       standardDependencies := map[string]bool{
-               "camel:core":   true,
-               "runtime:jvm":  true,
-               "runtime:yaml": true,
-       }
-
-       realDependencies := make(map[string]bool)
-       for _, d := range ctx.Request.Dependencies {
-               if _, std := standardDependencies[d]; !std {
-                       realDependencies[d] = true
-               }
-       }
-
-       knativeDep := "camel-k:knative"
-       if len(realDependencies) != 2 || !realDependencies[knativeDep] {
-               return nil
-       }
-
-       var otherDep string
-       for d := range realDependencies {
-               if d != knativeDep {
-                       otherDep = d
-                       break
-               }
-       }
-
-       camelPrefix := "camel:"
-       if !strings.HasPrefix(otherDep, camelPrefix) {
-               return nil
-       }
-
-       comp := strings.TrimPrefix(otherDep, camelPrefix)
-       ctx.Image = PredefinedImageNameFor(comp)
-       ctx.PublicImage = ctx.Image
-       return nil
-}
-
-// PredefinedImageNameFor --
-func PredefinedImageNameFor(comp string) string {
-       return fmt.Sprintf("camelk/camel-base-knative-%s:%s", comp, 
version.Version)
-}
-
 // ArtifactsSelector --
 type ArtifactsSelector func(ctx *Context) error
 
diff --git a/pkg/builder/kaniko/kaniko.go b/pkg/builder/kaniko/kaniko.go
index 0d80075..4b2d826 100644
--- a/pkg/builder/kaniko/kaniko.go
+++ b/pkg/builder/kaniko/kaniko.go
@@ -25,7 +25,6 @@ import (
 var DefaultSteps = []builder.Step{
        builder.NewStep("generate", builder.ProjectGenerationPhase, 
builder.GenerateProject),
        builder.NewStep("build/compute-dependencies", 
builder.ProjectBuildPhase, builder.ComputeDependencies),
-       builder.NewStep("lookup/predefined-image", builder.ProjectBuildPhase + 
1, builder.LookupPredefinedImage),
        builder.NewStep("packager", builder.ApplicationPackagePhase, 
builder.StandardPackager),
        builder.NewStep("publisher/kaniko", builder.ApplicationPublishPhase, 
Publisher),
        builder.NewStep("notify/context", builder.NotifyPhase, 
builder.NotifyIntegrationContext),
diff --git a/pkg/builder/s2i/s2i.go b/pkg/builder/s2i/s2i.go
index 9e105a0..8824e5d 100644
--- a/pkg/builder/s2i/s2i.go
+++ b/pkg/builder/s2i/s2i.go
@@ -25,7 +25,6 @@ import (
 var DefaultSteps = []builder.Step{
        builder.NewStep("generate", builder.ProjectGenerationPhase, 
builder.GenerateProject),
        builder.NewStep("build/compute-dependencies", 
builder.ProjectBuildPhase, builder.ComputeDependencies),
-       builder.NewStep("lookup/predefined-image", builder.ProjectBuildPhase + 
1, builder.LookupPredefinedImage),
        builder.NewStep("packager/incremental", 
builder.ApplicationPackagePhase, builder.IncrementalPackager),
        builder.NewStep("publisher/s2i", builder.ApplicationPublishPhase, 
Publisher),
        builder.NewStep("notify/context", builder.NotifyPhase, 
builder.NotifyIntegrationContext),
diff --git a/pkg/controller/integration/build_context.go 
b/pkg/controller/integration/build_context.go
index 427794c..3bbb4a9 100644
--- a/pkg/controller/integration/build_context.go
+++ b/pkg/controller/integration/build_context.go
@@ -21,16 +21,13 @@ import (
        "context"
        "fmt"
 
+       "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/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/sirupsen/logrus"
 )
 
 // NewBuildContextAction create an action that handles integration context 
build
@@ -60,6 +57,17 @@ func (action *buildContextAction) Handle(ctx 
context.Context, integration *v1alp
                return err
        }
 
+       if ictx == nil {
+               // Try to create an external context if possible
+               pl, err := platform.GetCurrentPlatform(ctx, action.client, 
integration.Namespace)
+               if err != nil {
+                       return nil
+               }
+               if pl.Spec.Build.PredefinedImages {
+                       ictx, err = ImportPredefinedContextIfPresent(ctx, 
action.client, integration)
+               }
+       }
+
        if ictx != nil {
                if ictx.Labels["camel.apache.org/context.type"] == 
v1alpha1.IntegrationContextTypePlatform {
                        // This is a platform context and as it is auto 
generated it may get
diff --git a/pkg/controller/integration/util.go 
b/pkg/controller/integration/util.go
index 9c31ec8..9eecf11 100644
--- a/pkg/controller/integration/util.go
+++ b/pkg/controller/integration/util.go
@@ -19,14 +19,22 @@ package integration
 
 import (
        "context"
-
-       "github.com/apache/camel-k/pkg/util"
-       k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
+       "fmt"
 
        "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+       "github.com/apache/camel-k/pkg/client"
+       "github.com/apache/camel-k/pkg/platform/images"
+       "github.com/apache/camel-k/pkg/util"
        "github.com/pkg/errors"
+       "github.com/rs/xid"
+       k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
 )
 
+var allowedLookupLabels = map[string]bool{
+       v1alpha1.IntegrationContextTypePlatform: true,
+       v1alpha1.IntegrationContextTypeExternal: true,
+}
+
 // LookupContextForIntegration --
 func LookupContextForIntegration(ctx context.Context, c k8sclient.Reader, 
integration *v1alpha1.Integration) (*v1alpha1.IntegrationContext, error) {
        if integration.Status.Context != "" {
@@ -50,7 +58,7 @@ func LookupContextForIntegration(ctx context.Context, c 
k8sclient.Reader, integr
 
        for _, ctx := range ctxList.Items {
                ctx := ctx // pin
-               if ctx.Labels["camel.apache.org/context.type"] == 
v1alpha1.IntegrationContextTypePlatform {
+               if allowed, ok := 
allowedLookupLabels[ctx.Labels["camel.apache.org/context.type"]]; ok && allowed 
{
                        ideps := len(integration.Status.Dependencies)
                        cdeps := len(ctx.Spec.Dependencies)
 
@@ -66,3 +74,31 @@ func LookupContextForIntegration(ctx context.Context, c 
k8sclient.Reader, integr
 
        return nil, nil
 }
+
+// ImportPredefinedContextIfPresent tries to create an external context from a 
predefined image
+func ImportPredefinedContextIfPresent(ctx context.Context, c client.Client, 
integration *v1alpha1.Integration) (*v1alpha1.IntegrationContext, error) {
+       image := images.LookupPredefinedImage(integration.Status.Dependencies)
+       if image == "" {
+               return nil, nil
+       }
+
+       externalCtxName := fmt.Sprintf("ctx-base-%s", xid.New())
+       externalCtx := v1alpha1.NewIntegrationContext(integration.Namespace, 
externalCtxName)
+
+       externalCtx.Labels = map[string]string{
+               "camel.apache.org/context.type":               
v1alpha1.IntegrationContextTypeExternal,
+               "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,
+       }
+
+       externalCtx.Spec = v1alpha1.IntegrationContextSpec{
+               Dependencies: integration.Status.Dependencies,
+               Image:        image,
+       }
+
+       if err := c.Create(ctx, &externalCtx); err != nil {
+               return nil, err
+       }
+       return &externalCtx, nil
+}
diff --git a/pkg/builder/s2i/s2i.go b/pkg/platform/images/doc.go
similarity index 52%
copy from pkg/builder/s2i/s2i.go
copy to pkg/platform/images/doc.go
index 9e105a0..cdf53c0 100644
--- a/pkg/builder/s2i/s2i.go
+++ b/pkg/platform/images/doc.go
@@ -15,18 +15,5 @@ See the License for the specific language governing 
permissions and
 limitations under the License.
 */
 
-package s2i
-
-import (
-       "github.com/apache/camel-k/pkg/builder"
-)
-
-// DefaultSteps --
-var DefaultSteps = []builder.Step{
-       builder.NewStep("generate", builder.ProjectGenerationPhase, 
builder.GenerateProject),
-       builder.NewStep("build/compute-dependencies", 
builder.ProjectBuildPhase, builder.ComputeDependencies),
-       builder.NewStep("lookup/predefined-image", builder.ProjectBuildPhase + 
1, builder.LookupPredefinedImage),
-       builder.NewStep("packager/incremental", 
builder.ApplicationPackagePhase, builder.IncrementalPackager),
-       builder.NewStep("publisher/s2i", builder.ApplicationPublishPhase, 
Publisher),
-       builder.NewStep("notify/context", builder.NotifyPhase, 
builder.NotifyIntegrationContext),
-}
+// Package images contains information for retrieval of platform predefined 
images
+package images
diff --git a/pkg/platform/images/images.go b/pkg/platform/images/images.go
new file mode 100644
index 0000000..ab98a21
--- /dev/null
+++ b/pkg/platform/images/images.go
@@ -0,0 +1,82 @@
+/*
+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 images
+
+import (
+       "fmt"
+       "strings"
+
+       "github.com/apache/camel-k/version"
+)
+
+// BaseRepository is the docker repository that contains images
+const (
+       BaseRepository = "camelk"
+       ImagePrefix    = "camel-base-knative-"
+)
+
+// BaseDependency is a required dependency that must be found in the list
+var BaseDependency = "camel-k:knative"
+
+// StandardDependencies are common dependencies included in the image
+var StandardDependencies = map[string]bool{
+       "camel:core":   true,
+       "runtime:jvm":  true,
+       "runtime:yaml": true,
+}
+
+// LookupPredefinedImage is used to find a suitable predefined image if 
available
+func LookupPredefinedImage(dependencies []string) string {
+
+       realDependencies := make([]string, 0)
+       baseDependencyFound := false
+       for _, d := range dependencies {
+               if _, std := StandardDependencies[d]; std {
+                       continue
+               }
+               if d == BaseDependency {
+                       baseDependencyFound = true
+                       continue
+               }
+               realDependencies = append(realDependencies, d)
+       }
+
+       if !baseDependencyFound {
+               return ""
+       }
+       if len(realDependencies) == 0 {
+               return PredefinedImageNameFor("core")
+       }
+       if len(realDependencies) != 1 {
+               return ""
+       }
+
+       otherDep := realDependencies[0]
+       camelPrefix := "camel:"
+       if !strings.HasPrefix(otherDep, camelPrefix) {
+               return ""
+       }
+
+       comp := strings.TrimPrefix(otherDep, camelPrefix)
+       return PredefinedImageNameFor(comp)
+}
+
+// PredefinedImageNameFor --
+func PredefinedImageNameFor(comp string) string {
+       return fmt.Sprintf("%s/%s%s:%s", BaseRepository, ImagePrefix, comp, 
version.Version)
+}
diff --git a/pkg/platform/images/images_test.go 
b/pkg/platform/images/images_test.go
new file mode 100644
index 0000000..53441e1
--- /dev/null
+++ b/pkg/platform/images/images_test.go
@@ -0,0 +1,68 @@
+/*
+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 images
+
+import (
+       "github.com/apache/camel-k/version"
+       "github.com/stretchr/testify/assert"
+       "strconv"
+       "testing"
+)
+
+func TestImageLookup(t *testing.T) {
+       cases := []struct {
+               dependencies []string
+               image        string
+       }{
+               {
+                       dependencies: []string{"camel:telegram"},
+               },
+               {
+                       dependencies: []string{"camel:telegram", "camel:core"},
+               },
+               {
+                       dependencies: []string{"camel:telegram", "camel:core", 
"camel-k:knative"},
+                       image:        BaseRepository + "/" + ImagePrefix + 
"telegram:" + version.Version,
+               },
+               {
+                       dependencies: []string{"camel:core", "camel-k:knative"},
+                       image:        BaseRepository + "/" + ImagePrefix + 
"core:" + version.Version,
+               },
+               {
+                       dependencies: []string{"camel:dropbox", "camel:core", 
"camel-k:knative", "runtime:jvm"},
+                       image:        BaseRepository + "/" + ImagePrefix + 
"dropbox:" + version.Version,
+               },
+               {
+                       dependencies: []string{"camel:dropbox", "camel:core", 
"camel-k:knative", "runtime:jvm", "runtime:yaml"},
+                       image:        BaseRepository + "/" + ImagePrefix + 
"dropbox:" + version.Version,
+               },
+               {
+                       dependencies: []string{"camel:dropbox", "camel:core", 
"runtime:jvm", "runtime:yaml"},
+               },
+               {
+                       dependencies: []string{"camel:dropbox", "camel:core", 
"camel-k:knative", "runtime:jvm", "runtime:groovy"},
+               },
+       }
+
+       for i, tc := range cases {
+               t.Run("case-"+strconv.Itoa(i), func(t *testing.T) {
+                       assert.Equal(t, tc.image, 
LookupPredefinedImage(tc.dependencies))
+               })
+       }
+
+}
diff --git a/pkg/trait/builder_test.go b/pkg/trait/builder_test.go
index f67fad0..1afefab 100644
--- a/pkg/trait/builder_test.go
+++ b/pkg/trait/builder_test.go
@@ -82,7 +82,7 @@ func TestS2IBuilderTrait(t *testing.T) {
        assert.NotEmpty(t, env.ExecutedTraits)
        assert.NotNil(t, env.GetTrait(ID("builder")))
        assert.NotEmpty(t, env.Steps)
-       assert.Len(t, env.Steps, 6)
+       assert.Len(t, env.Steps, 5)
        assert.Condition(t, func() bool {
                for _, s := range env.Steps {
                        if s.ID() == "publisher/s2i" && s.Phase() == 
builder.ApplicationPublishPhase {
@@ -102,7 +102,7 @@ func TestKanikoBuilderTrait(t *testing.T) {
        assert.NotEmpty(t, env.ExecutedTraits)
        assert.NotNil(t, env.GetTrait(ID("builder")))
        assert.NotEmpty(t, env.Steps)
-       assert.Len(t, env.Steps, 6)
+       assert.Len(t, env.Steps, 5)
        assert.Condition(t, func() bool {
                for _, s := range env.Steps {
                        if s.ID() == "publisher/kaniko" && s.Phase() == 
builder.ApplicationPublishPhase {

Reply via email to