You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by nf...@apache.org on 2018/09/15 14:25:05 UTC
[camel-k] 01/03: Context handling improvement
This is an automated email from the ASF dual-hosted git repository.
nferraro pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel-k.git
commit f2717d01c315f47df0962154c566fd1498b55e46
Author: lburgazzoli <lb...@gmail.com>
AuthorDate: Fri Sep 14 14:25:18 2018 +0200
Context handling improvement
---
deploy/platform-integration-context-core.yaml | 9 +++
deploy/platform-integration-context-groovy.yaml | 12 ++++
deploy/resources.go | 27 ++++++++
pkg/client/cmd/install.go | 30 +++++----
pkg/install/operator.go | 20 +++++-
pkg/stub/action/integration/build.go | 84 +++++++++++++++----------
pkg/stub/action/integration/deploy.go | 4 ++
pkg/stub/action/integration/util.go | 77 ++++++++++++++++++++++-
pkg/stub/handler.go | 9 +--
runtime/examples/routes.groovy | 16 +++++
test/testing_env.go | 6 +-
11 files changed, 239 insertions(+), 55 deletions(-)
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
@@ -357,6 +357,33 @@ 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"] =
`
kind: ClusterRole
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/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..ce953db 100644
--- a/pkg/stub/action/integration/build.go
+++ b/pkg/stub/action/integration/build.go
@@ -18,24 +18,21 @@ limitations under the License.
package action
import (
- "context"
+ "fmt"
"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 +50,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-%s", integration.Name, integration.ResourceVersion)
+ 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,
+ }
+
+ // Set the context to have the same dependencies as the integrations
+ platformCtx.Spec = v1alpha1.IntegrationContextSpec{
+ Dependencies: integration.Spec.Dependencies,
}
- 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)
+
+ 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..7ddbbab 100644
--- a/pkg/stub/action/integration/util.go
+++ b/pkg/stub/action/integration/util.go
@@ -2,6 +2,7 @@ package action
import (
"fmt"
+ "math"
"strings"
"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
@@ -24,7 +25,81 @@ func LookupContextForIntegration(integration *v1alpha1.Integration) (*v1alpha1.I
return &ctx, nil
}
- return nil, nil
+ ctxList := v1alpha1.NewIntegrationContextList()
+ if err := sdk.List(integration.Namespace, &ctxList); err != nil {
+ return nil, err
+ }
+
+ var c *v1alpha1.IntegrationContext
+
+ if len(integration.Spec.Dependencies) == 0 {
+ // The integration has no dependencies, try to find the one that
+ // has minimum dependencies requirement.
+
+ ndeps := math.MaxUint16
+
+ for _, ctx := range ctxList.Items {
+ cdeps := len(ctx.Spec.Dependencies)
+ if cdeps < ndeps {
+ ndeps = cdeps
+ c = &ctx
+ }
+ if ndeps == 0 {
+ break
+ }
+ }
+ } else {
+ ndeps := math.MaxUint16
+
+ for _, ctx := range ctxList.Items {
+ // The integration has some dependencies, try to find the one that matches
+ // the required dependencies with minimum "dependency overhead"
+
+ if ctx.Labels["camel.apache.org/context.type"] == "platform" {
+ if StringSliceContains(ctx.Spec.Dependencies, integration.Spec.Dependencies) {
+ ideps := len(integration.Spec.Dependencies)
+ cdeps := len(ctx.Spec.Dependencies)
+
+ if cdeps < ndeps || ideps == cdeps {
+ c = &ctx
+ ndeps = cdeps
+ }
+
+ if ideps == ndeps {
+ break
+ }
+ }
+ }
+ }
+ }
+
+ if c == nil {
+ // TODO: generate a new platform context
+ }
+
+ return c, 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 --
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
+}