nicolaferraro closed pull request #76: Context handling improvement
URL: https://github.com/apache/camel-k/pull/76
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/Gopkg.lock b/Gopkg.lock
index c9859df..bc54a02 100644
--- a/Gopkg.lock
+++ b/Gopkg.lock
@@ -317,6 +317,14 @@
   pruneopts = "NUT"
   revision = "05ee40e3a273f7245e8777337fc7b46e533a9a92"
 
+[[projects]]
+  digest = "1:0975c74a2cd70df6c2ae353c6283a25ce759dda7e1e706e5c07458baf3faca22"
+  name = "github.com/rs/xid"
+  packages = ["."]
+  pruneopts = "NUT"
+  revision = "15d26544def341f036c5f8dca987a4cbe575032c"
+  version = "v1.2.1"
+
 [[projects]]
   digest = "1:b2339e83ce9b5c4f79405f949429a7f68a9a904fed903c672aac1e7ceb7f5f02"
   name = "github.com/sirupsen/logrus"
@@ -711,6 +719,7 @@
     "github.com/operator-framework/operator-sdk/pkg/util/k8sutil",
     "github.com/operator-framework/operator-sdk/version",
     "github.com/pkg/errors",
+    "github.com/rs/xid",
     "github.com/sirupsen/logrus",
     "github.com/spf13/cobra",
     "github.com/stoewer/go-strcase",
diff --git a/deploy/platform-integration-context-core.yaml 
b/deploy/platform-integration-context-core.yaml
new file mode 100644
index 0000000..836d195
--- /dev/null
+++ b/deploy/platform-integration-context-core.yaml
@@ -0,0 +1,9 @@
+apiVersion: camel.apache.org/v1alpha1
+kind: IntegrationContext
+metadata:
+  name: root.integrationcontexts.camel.apache.org
+  labels:
+    app: "camel-k"
+    camel.apache.org/context.created.by.kind: Operator
+    camel.apache.org/context.created.by.name: core
+    camel.apache.org/context.type: platform
\ No newline at end of file
diff --git a/deploy/platform-integration-context-groovy.yaml 
b/deploy/platform-integration-context-groovy.yaml
new file mode 100644
index 0000000..5c5cbf4
--- /dev/null
+++ b/deploy/platform-integration-context-groovy.yaml
@@ -0,0 +1,12 @@
+apiVersion: camel.apache.org/v1alpha1
+kind: IntegrationContext
+metadata:
+  name: groovy.integrationcontexts.camel.apache.org
+  labels:
+    app: "camel-k"
+    camel.apache.org/context.created.by.kind: Operator
+    camel.apache.org/context.created.by.name: core
+    camel.apache.org/context.type: platform
+spec:
+  dependencies:
+    - camel:groovy
\ No newline at end of file
diff --git a/deploy/resources.go b/deploy/resources.go
index 77a12cd..189d4ef 100644
--- a/deploy/resources.go
+++ b/deploy/resources.go
@@ -356,6 +356,33 @@ spec:
 status:
   loadBalancer: {}
 
+`
+       Resources["platform-integration-context-core.yaml"] =
+               `
+apiVersion: camel.apache.org/v1alpha1
+kind: IntegrationContext
+metadata:
+  name: root.integrationcontexts.camel.apache.org
+  labels:
+    app: "camel-k"
+    camel.apache.org/context.created.by.kind: Operator
+    camel.apache.org/context.created.by.name: core
+    camel.apache.org/context.type: platform
+`
+       Resources["platform-integration-context-groovy.yaml"] =
+               `
+apiVersion: camel.apache.org/v1alpha1
+kind: IntegrationContext
+metadata:
+  name: groovy.integrationcontexts.camel.apache.org
+  labels:
+    app: "camel-k"
+    camel.apache.org/context.created.by.kind: Operator
+    camel.apache.org/context.created.by.name: core
+    camel.apache.org/context.type: platform
+spec:
+  dependencies:
+    - camel:groovy
 `
        Resources["user-cluster-role.yaml"] =
                `
diff --git a/pkg/client/cmd/completion.go b/pkg/client/cmd/completion.go
index 3429dad..f86bd0b 100644
--- a/pkg/client/cmd/completion.go
+++ b/pkg/client/cmd/completion.go
@@ -34,13 +34,14 @@ To configure your bash shell to load completions for each 
session add to your ba
 . <(kamel completion)
 `
 
-func NewCmdCompletion() *cobra.Command {
+// NewCmdCompletion --
+func NewCmdCompletion(root *cobra.Command) *cobra.Command {
        return &cobra.Command{
                Use:   "completion",
                Short: "Generates bash completion scripts",
                Long:  completionCmdLongDescription,
                Run: func(cmd *cobra.Command, args []string) {
-                       cmd.GenBashCompletion(os.Stdout)
+                       root.GenBashCompletion(os.Stdout)
                },
        }
 }
diff --git a/pkg/client/cmd/install.go b/pkg/client/cmd/install.go
index 0693b36..15a4de0 100644
--- a/pkg/client/cmd/install.go
+++ b/pkg/client/cmd/install.go
@@ -20,19 +20,16 @@ package cmd
 import (
        "fmt"
 
+       "os"
+
        "github.com/apache/camel-k/pkg/install"
        "github.com/spf13/cobra"
        "k8s.io/apimachinery/pkg/api/errors"
-       "os"
 )
 
-type InstallCmdOptions struct {
-       *RootCmdOptions
-       ClusterSetupOnly bool
-}
-
+// NewCmdInstall --
 func NewCmdInstall(rootCmdOptions *RootCmdOptions) *cobra.Command {
-       options := InstallCmdOptions{
+       options := installCmdOptions{
                RootCmdOptions: rootCmdOptions,
        }
        cmd := cobra.Command{
@@ -42,13 +39,18 @@ func NewCmdInstall(rootCmdOptions *RootCmdOptions) 
*cobra.Command {
                RunE:  options.install,
        }
 
-       cmd.Flags().BoolVar(&options.ClusterSetupOnly, "cluster-setup", false, 
"Execute cluster-wide operations only (may require admin rights)")
+       cmd.Flags().BoolVar(&options.clusterSetupOnly, "cluster-setup", false, 
"Execute cluster-wide operations only (may require admin rights)")
        cmd.ParseFlags(os.Args)
 
        return &cmd
 }
 
-func (o *InstallCmdOptions) install(cmd *cobra.Command, args []string) error {
+type installCmdOptions struct {
+       *RootCmdOptions
+       clusterSetupOnly bool
+}
+
+func (o *installCmdOptions) install(cmd *cobra.Command, args []string) error {
        err := install.SetupClusterwideResources()
        if err != nil && errors.IsForbidden(err) {
                // TODO explain that this is a one time operation and add a 
flag to do cluster-level operations only when logged as admin
@@ -57,15 +59,21 @@ func (o *InstallCmdOptions) install(cmd *cobra.Command, 
args []string) error {
                return nil // TODO better error handling: if here we return err 
the help page is shown
        }
 
-       if o.ClusterSetupOnly {
+       if o.clusterSetupOnly {
                fmt.Println("Camel K cluster setup completed successfully")
        } else {
                namespace := o.Namespace
 
-               err = install.InstallOperator(namespace)
+               err = install.Operator(namespace)
                if err != nil {
                        return err
                }
+
+               err = install.PlatformContexts(namespace)
+               if err != nil {
+                       return err
+               }
+
                fmt.Println("Camel K installed in namespace", namespace)
        }
 
diff --git a/pkg/client/cmd/root.go b/pkg/client/cmd/root.go
index 50cfb40..3168cc2 100644
--- a/pkg/client/cmd/root.go
+++ b/pkg/client/cmd/root.go
@@ -20,10 +20,11 @@ package cmd
 import (
        "os"
 
+       "context"
+
        "github.com/apache/camel-k/pkg/util/kubernetes"
        "github.com/pkg/errors"
        "github.com/spf13/cobra"
-       "context"
 )
 
 type RootCmdOptions struct {
@@ -62,7 +63,7 @@ func NewKamelCommand(ctx context.Context) (*cobra.Command, 
error) {
                return nil, err
        }
 
-       cmd.AddCommand(NewCmdCompletion())
+       cmd.AddCommand(NewCmdCompletion(&cmd))
        cmd.AddCommand(NewCmdVersion())
        cmd.AddCommand(NewCmdRun(&options))
        cmd.AddCommand(NewCmdGet(&options))
diff --git a/pkg/install/operator.go b/pkg/install/operator.go
index a7044f9..528424a 100644
--- a/pkg/install/operator.go
+++ b/pkg/install/operator.go
@@ -19,13 +19,15 @@ package install
 
 import (
        "github.com/apache/camel-k/deploy"
+       "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
        "github.com/apache/camel-k/pkg/util/kubernetes"
        "github.com/operator-framework/operator-sdk/pkg/sdk"
        "k8s.io/apimachinery/pkg/api/errors"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
-func InstallOperator(namespace string) error {
+// Operator --
+func Operator(namespace string) error {
        return installResources(namespace,
                "operator-service-account.yaml",
                "operator-role-openshift.yaml", // TODO distinguish between 
Openshift and Kubernetes
@@ -35,6 +37,14 @@ func InstallOperator(namespace string) error {
        )
 }
 
+// PlatformContexts --
+func PlatformContexts(namespace string) error {
+       return installResources(namespace,
+               "platform-integration-context-core.yaml",
+               "platform-integration-context-groovy.yaml",
+       )
+}
+
 func installResources(namespace string, names ...string) error {
        for _, name := range names {
                if err := installResource(namespace, name); err != nil {
@@ -50,8 +60,8 @@ func installResource(namespace string, name string) error {
                return err
        }
 
-       if kObj, ok := obj.(metav1.Object); ok {
-               kObj.SetNamespace(namespace)
+       if metaObject, ok := obj.(metav1.Object); ok {
+               metaObject.SetNamespace(namespace)
        }
 
        err = sdk.Create(obj)
@@ -60,6 +70,10 @@ func installResource(namespace string, name string) error {
                if obj.GetObjectKind().GroupVersionKind().Kind == "Service" {
                        return nil
                }
+               // Don't recreate integration contexts
+               if obj.GetObjectKind().GroupVersionKind().Kind == 
v1alpha1.IntegrationContextKind {
+                       return nil
+               }
                return sdk.Update(obj)
        }
        return err
diff --git a/pkg/stub/action/integration/build.go 
b/pkg/stub/action/integration/build.go
index ba24358..b99ab4e 100644
--- a/pkg/stub/action/integration/build.go
+++ b/pkg/stub/action/integration/build.go
@@ -18,24 +18,23 @@ limitations under the License.
 package action
 
 import (
-       "context"
+       "fmt"
+
+       "github.com/rs/xid"
 
        "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
-       "github.com/apache/camel-k/pkg/build"
-       "github.com/apache/camel-k/pkg/build/api"
        "github.com/operator-framework/operator-sdk/pkg/sdk"
-       "github.com/sirupsen/logrus"
 )
 
 // NewBuildAction create an action that handles integration build
-func NewBuildAction(ctx context.Context, namespace string) IntegrationAction {
+func NewBuildAction(namespace string) IntegrationAction {
        return &buildAction{
-               buildManager: build.NewManager(ctx, namespace),
+               namespace: namespace,
        }
 }
 
 type buildAction struct {
-       buildManager *build.Manager
+       namespace string
 }
 
 func (action *buildAction) Name() string {
@@ -53,44 +52,65 @@ func (action *buildAction) Handle(integration 
*v1alpha1.Integration) error {
                return err
        }
 
-
        if ctx != nil {
+               if ctx.Labels["camel.apache.org/context.type"] == "platform" {
+                       // 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 !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.IntegrationContextPhaseReady {
                        target := integration.DeepCopy()
                        target.Status.Image = ctx.Status.Image
+                       target.Spec.Context = ctx.Name
                        target.Status.Phase = v1alpha1.IntegrationPhaseDeploying
                        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
        }
 
-       buildIdentifier := api.BuildIdentifier{
-               Name:      integration.Name,
-               Qualifier: integration.Status.Digest,
+       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":               "platform",
+               "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,
        }
-       buildResult := action.buildManager.Get(buildIdentifier)
-       if buildResult.Status == api.BuildStatusNotRequested {
-               action.buildManager.Start(api.BuildSource{
-                       Identifier: buildIdentifier,
-                       Code: api.Code{
-                               Name:     integration.Spec.Source.Name,
-                               Content:  integration.Spec.Source.Content,
-                               Language: integration.Spec.Source.Language,
-                       },
-                       Dependencies: integration.Spec.Dependencies,
-               })
-               logrus.Info("Build started")
-       } else if buildResult.Status == api.BuildStatusError {
-               target := integration.DeepCopy()
-               target.Status.Phase = v1alpha1.IntegrationPhaseError
-               return sdk.Update(target)
-       } else if buildResult.Status == api.BuildStatusCompleted {
-               target := integration.DeepCopy()
-               target.Status.Image = buildResult.Image
-               target.Status.Phase = v1alpha1.IntegrationPhaseDeploying
-               return sdk.Update(target)
+
+       // Set the context to have the same dependencies as the integrations
+       platformCtx.Spec = v1alpha1.IntegrationContextSpec{
+               Dependencies: integration.Spec.Dependencies,
+       }
+
+       if err := sdk.Create(&platformCtx); err != nil {
+               return err
        }
 
-       return nil
+       // 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)
 }
diff --git a/pkg/stub/action/integration/deploy.go 
b/pkg/stub/action/integration/deploy.go
index 8bc4b74..b8adb43 100644
--- a/pkg/stub/action/integration/deploy.go
+++ b/pkg/stub/action/integration/deploy.go
@@ -147,6 +147,10 @@ func getDeploymentFor(ctx *v1alpha1.IntegrationContext, 
integration *v1alpha1.In
        environment["CAMEL_K_CONF"] = "/etc/camel/conf/application.properties"
        environment["CAMEL_K_CONF_D"] = "/etc/camel/conf.d"
 
+       // add a dummy env var to trigger deployment if everything but the code
+       // has been changed
+       environment["CAMEL_K_DIGEST"] = integration.Status.Digest
+
        labels := map[string]string{
                "camel.apache.org/integration": integration.Name,
        }
diff --git a/pkg/stub/action/integration/util.go 
b/pkg/stub/action/integration/util.go
index 8021809..8c69f69 100644
--- a/pkg/stub/action/integration/util.go
+++ b/pkg/stub/action/integration/util.go
@@ -24,9 +24,51 @@ func LookupContextForIntegration(integration 
*v1alpha1.Integration) (*v1alpha1.I
                return &ctx, nil
        }
 
+       ctxList := v1alpha1.NewIntegrationContextList()
+       if err := sdk.List(integration.Namespace, &ctxList); err != nil {
+               return nil, err
+       }
+
+       for _, ctx := range ctxList.Items {
+               if ctx.Labels["camel.apache.org/context.type"] == "platform" {
+                       ideps := len(integration.Spec.Dependencies)
+                       cdeps := len(ctx.Spec.Dependencies)
+
+                       if ideps != cdeps {
+                               continue
+                       }
+
+                       if StringSliceContains(ctx.Spec.Dependencies, 
integration.Spec.Dependencies) {
+                               return &ctx, nil
+                       }
+               }
+       }
+
        return nil, nil
 }
 
+// StringSliceContains --
+func StringSliceContains(slice []string, items []string) bool {
+       for i := 0; i < len(items); i++ {
+               if !StringSliceExists(slice, items[i]) {
+                       return false
+               }
+       }
+
+       return true
+}
+
+// StringSliceExists --
+func StringSliceExists(slice []string, item string) bool {
+       for i := 0; i < len(slice); i++ {
+               if slice[i] == item {
+                       return true
+               }
+       }
+
+       return false
+}
+
 // PropertiesString --
 func PropertiesString(m map[string]string) string {
        properties := ""
diff --git a/pkg/stub/handler.go b/pkg/stub/handler.go
index d90d776..cb78d7b 100644
--- a/pkg/stub/handler.go
+++ b/pkg/stub/handler.go
@@ -28,11 +28,12 @@ import (
        "github.com/sirupsen/logrus"
 )
 
+// NewHandler --
 func NewHandler(ctx context.Context, namespace string) sdk.Handler {
-       return &Handler{
+       return &handler{
                integrationActionPool: []iaction.IntegrationAction{
                        iaction.NewInitializeAction(),
-                       iaction.NewBuildAction(ctx, namespace),
+                       iaction.NewBuildAction(namespace),
                        iaction.NewDeployAction(),
                        iaction.NewMonitorAction(),
                },
@@ -44,12 +45,12 @@ func NewHandler(ctx context.Context, namespace string) 
sdk.Handler {
        }
 }
 
-type Handler struct {
+type handler struct {
        integrationActionPool        []iaction.IntegrationAction
        integrationContextActionPool []caction.IntegrationContextAction
 }
 
-func (h *Handler) Handle(ctx context.Context, event sdk.Event) error {
+func (h *handler) Handle(ctx context.Context, event sdk.Event) error {
        switch o := event.Object.(type) {
        case *v1alpha1.Integration:
                for _, a := range h.integrationActionPool {
diff --git a/runtime/examples/routes.groovy b/runtime/examples/routes.groovy
new file mode 100644
index 0000000..7ce04bb
--- /dev/null
+++ b/runtime/examples/routes.groovy
@@ -0,0 +1,16 @@
+//
+// To run this integrations use:
+//
+//     kamel run -d camel:groovy runtime/examples/routes.groovy
+//
+
+rnd = new Random()
+
+from('timer:groovy?period=1s')
+    .routeId('groovy')
+    .setBody()
+        .constant('Hello Camel K!')
+    .process {
+        it.in.headers['RandomValue'] = rnd.nextInt()
+    }
+    .to('log:info?showHeaders=true')
\ No newline at end of file
diff --git a/test/testing_env.go b/test/testing_env.go
index 13b0ed8..3b1e215 100644
--- a/test/testing_env.go
+++ b/test/testing_env.go
@@ -22,8 +22,8 @@ limitations under the License.
 package test
 
 import (
-       "github.com/apache/camel-k/pkg/util/kubernetes"
        "github.com/apache/camel-k/pkg/install"
+       "github.com/apache/camel-k/pkg/util/kubernetes"
 )
 
 func init() {
@@ -35,7 +35,7 @@ func init() {
                panic(err)
        }
 
-       err = install.InstallOperator(GetTargetNamespace())
+       err = install.Operator(GetTargetNamespace())
        if err != nil {
                panic(err)
        }
@@ -63,4 +63,4 @@ public class Routes extends RouteBuilder {
 
 }
 `
-}
\ No newline at end of file
+}


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services

Reply via email to