[GitHub] nicolaferraro closed pull request #68: Support for integration configuration

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[GitHub] nicolaferraro closed pull request #68: Support for integration configuration

GitBox
nicolaferraro closed pull request #68: Support for integration configuration
URL: https://github.com/apache/camel-k/pull/68
 
 
   

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/pkg/apis/camel/v1alpha1/types.go b/pkg/apis/camel/v1alpha1/types.go
index 72da35a..fd21328 100644
--- a/pkg/apis/camel/v1alpha1/types.go
+++ b/pkg/apis/camel/v1alpha1/types.go
@@ -21,8 +21,15 @@ import (
  metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
+// ConfigurationSpec --
+type ConfigurationSpec struct {
+ Type  string `json:"type"`
+ Value string `json:"value"`
+}
+
 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 
+// IntegrationList --
 type IntegrationList struct {
  metav1.TypeMeta `json:",inline"`
  metav1.ListMeta `json:"metadata"`
@@ -31,6 +38,7 @@ type IntegrationList struct {
 
 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 
+// Integration --
 type Integration struct {
  metav1.TypeMeta   `json:",inline"`
  metav1.ObjectMeta `json:"metadata"`
@@ -38,36 +46,49 @@ type Integration struct {
  Status            IntegrationStatus `json:"status,omitempty"`
 }
 
+// IntegrationSpec --
 type IntegrationSpec struct {
- Replicas     *int32     `json:"replicas,omitempty"`
- Source       SourceSpec `json:"source,omitempty"`
- Context      string     `json:"context,omitempty"`
- Dependencies []string   `json:"dependencies,omitempty"`
+ Replicas      *int32              `json:"replicas,omitempty"`
+ Source        SourceSpec          `json:"source,omitempty"`
+ Context       string              `json:"context,omitempty"`
+ Dependencies  []string            `json:"dependencies,omitempty"`
+ Configuration []ConfigurationSpec `json:"configuration,omitempty"`
 }
 
+// SourceSpec --
 type SourceSpec struct {
  Name     string `json:"name,omitempty"`
  Content  string `json:"content,omitempty"`
  Language string `json:"language,omitempty"`
 }
 
+// IntegrationStatus --
 type IntegrationStatus struct {
  Phase  IntegrationPhase `json:"phase,omitempty"`
  Digest string           `json:"digest,omitempty"`
  Image  string           `json:"image,omitempty"`
 }
 
+// IntegrationPhase --
 type IntegrationPhase string
 
 const (
- IntegrationPhaseBuilding  IntegrationPhase = "Building"
+ // IntegrationKind --
+ IntegrationKind string = "Integration"
+
+ // IntegrationPhaseBuilding --
+ IntegrationPhaseBuilding IntegrationPhase = "Building"
+ // IntegrationPhaseDeploying --
  IntegrationPhaseDeploying IntegrationPhase = "Deploying"
- IntegrationPhaseRunning   IntegrationPhase = "Running"
- IntegrationPhaseError     IntegrationPhase = "Error"
+ // IntegrationPhaseRunning --
+ IntegrationPhaseRunning IntegrationPhase = "Running"
+ // IntegrationPhaseError --
+ IntegrationPhaseError IntegrationPhase = "Error"
 )
 
 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 
+// IntegrationContextList --
 type IntegrationContextList struct {
  metav1.TypeMeta `json:",inline"`
  metav1.ListMeta `json:"metadata"`
@@ -76,6 +97,7 @@ type IntegrationContextList struct {
 
 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 
+// IntegrationContext --
 type IntegrationContext struct {
  metav1.TypeMeta   `json:",inline"`
  metav1.ObjectMeta `json:"metadata"`
@@ -83,28 +105,20 @@ type IntegrationContext struct {
  Status            IntegrationContextStatus `json:"status,omitempty"`
 }
 
+// IntegrationContextSpec --
 type IntegrationContextSpec struct {
- Dependencies []string          `json:"dependencies,omitempty"`
- Properties   []PropertySpec    `json:"properties,omitempty"`
- Environment  []EnvironmentSpec `json:"environment,omitempty"`
-}
-
-type PropertySpec struct {
- Name  string
- Value string
-}
-
-type EnvironmentSpec struct {
- Name  string
- Value string
+ Dependencies  []string            `json:"dependencies,omitempty"`
+ Configuration []ConfigurationSpec `json:"configuration,omitempty"`
 }
 
+// IntegrationContextStatus --
 type IntegrationContextStatus struct {
  Phase  IntegrationContextPhase `json:"phase,omitempty"`
  Image  string                  `json:"image,omitempty"`
  Digest string                  `json:"digest,omitempty"`
 }
 
+// IntegrationContextPhase --
 type IntegrationContextPhase string
 
 const (
diff --git a/pkg/apis/camel/v1alpha1/types_support.go b/pkg/apis/camel/v1alpha1/types_support.go
index fe93a18..b202aa3 100644
--- a/pkg/apis/camel/v1alpha1/types_support.go
+++ b/pkg/apis/camel/v1alpha1/types_support.go
@@ -29,12 +29,8 @@ import (
 //
 // **********************************
 
-func (spec PropertySpec) String() string {
- return fmt.Sprintf("%s=%s", spec.Name, spec.Value)
-}
-
-func (spec EnvironmentSpec) String() string {
- return fmt.Sprintf("%s=%s", spec.Name, spec.Value)
+func (spec ConfigurationSpec) String() string {
+ return fmt.Sprintf("%s=%s", spec.Type, spec.Value)
 }
 
 // **********************************
@@ -43,6 +39,7 @@ func (spec EnvironmentSpec) String() string {
 //
 // **********************************
 
+// NewIntegrationContext --
 func NewIntegrationContext(namespace string, name string) IntegrationContext {
  return IntegrationContext{
  TypeMeta: metav1.TypeMeta{
@@ -56,6 +53,7 @@ func NewIntegrationContext(namespace string, name string) IntegrationContext {
  }
 }
 
+// NewIntegrationContextList --
 func NewIntegrationContextList() IntegrationContextList {
  return IntegrationContextList{
  TypeMeta: metav1.TypeMeta{
diff --git a/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go
index 826918a..ec6db14 100644
--- a/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go
+++ b/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go
@@ -26,17 +26,17 @@ import (
 )
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *EnvironmentSpec) DeepCopyInto(out *EnvironmentSpec) {
+func (in *ConfigurationSpec) DeepCopyInto(out *ConfigurationSpec) {
  *out = *in
  return
 }
 
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvironmentSpec.
-func (in *EnvironmentSpec) DeepCopy() *EnvironmentSpec {
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigurationSpec.
+func (in *ConfigurationSpec) DeepCopy() *ConfigurationSpec {
  if in == nil {
  return nil
  }
- out := new(EnvironmentSpec)
+ out := new(ConfigurationSpec)
  in.DeepCopyInto(out)
  return out
 }
@@ -138,14 +138,9 @@ func (in *IntegrationContextSpec) DeepCopyInto(out *IntegrationContextSpec) {
  *out = make([]string, len(*in))
  copy(*out, *in)
  }
- if in.Properties != nil {
- in, out := &in.Properties, &out.Properties
- *out = make([]PropertySpec, len(*in))
- copy(*out, *in)
- }
- if in.Environment != nil {
- in, out := &in.Environment, &out.Environment
- *out = make([]EnvironmentSpec, len(*in))
+ if in.Configuration != nil {
+ in, out := &in.Configuration, &out.Configuration
+ *out = make([]ConfigurationSpec, len(*in))
  copy(*out, *in)
  }
  return
@@ -224,6 +219,11 @@ func (in *IntegrationSpec) DeepCopyInto(out *IntegrationSpec) {
  *out = make([]string, len(*in))
  copy(*out, *in)
  }
+ if in.Configuration != nil {
+ in, out := &in.Configuration, &out.Configuration
+ *out = make([]ConfigurationSpec, len(*in))
+ copy(*out, *in)
+ }
  return
 }
 
@@ -253,22 +253,6 @@ func (in *IntegrationStatus) DeepCopy() *IntegrationStatus {
  return out
 }
 
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *PropertySpec) DeepCopyInto(out *PropertySpec) {
- *out = *in
- return
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PropertySpec.
-func (in *PropertySpec) DeepCopy() *PropertySpec {
- if in == nil {
- return nil
- }
- out := new(PropertySpec)
- in.DeepCopyInto(out)
- return out
-}
-
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *SourceSpec) DeepCopyInto(out *SourceSpec) {
  *out = *in
diff --git a/pkg/client/cmd/context_create.go b/pkg/client/cmd/context_create.go
index de2c1a5..49c3950 100644
--- a/pkg/client/cmd/context_create.go
+++ b/pkg/client/cmd/context_create.go
@@ -21,7 +21,6 @@ import (
  "errors"
  "fmt"
  "strconv"
- "strings"
 
  "github.com/operator-framework/operator-sdk/pkg/sdk"
 
@@ -46,9 +45,10 @@ func newContextCreateCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
  RunE:  impl.run,
  }
 
- cmd.Flags().StringSliceVarP(&impl.env, "env", "e", nil, "Add an environment variable")
- cmd.Flags().StringSliceVarP(&impl.properties, "property", "p", nil, "Add a system property")
  cmd.Flags().StringSliceVarP(&impl.dependencies, "dependency", "d", nil, "Add a dependency")
+ cmd.Flags().StringSliceVarP(&impl.properties, "property", "p", nil, "Add a camel property")
+ cmd.Flags().StringSliceVar(&impl.configmaps, "configmap", nil, "Add a ConfigMap")
+ cmd.Flags().StringSliceVar(&impl.secrets, "secret", nil, "Add a Secret")
 
  return &cmd
 }
@@ -56,9 +56,10 @@ func newContextCreateCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
 type contextCreateCommand struct {
  *RootCmdOptions
 
- env          []string
- properties   []string
  dependencies []string
+ properties   []string
+ configmaps   []string
+ secrets      []string
 }
 
 func (command *contextCreateCommand) validateArgs(cmd *cobra.Command, args []string) error {
@@ -75,22 +76,27 @@ func (command *contextCreateCommand) run(cmd *cobra.Command, args []string) erro
 
  ctx := v1alpha1.NewIntegrationContext(namespace, name)
  ctx.Spec = v1alpha1.IntegrationContextSpec{
- Dependencies: command.dependencies,
- Environment:  make([]v1alpha1.EnvironmentSpec, 0),
- Properties:   make([]v1alpha1.PropertySpec, 0),
+ Dependencies:  command.dependencies,
+ Configuration: make([]v1alpha1.ConfigurationSpec, 0),
  }
 
- for _, item := range command.env {
- pair := strings.Split(item, "=")
- if len(pair) == 2 {
- ctx.Spec.Environment = append(ctx.Spec.Environment, v1alpha1.EnvironmentSpec{Name: pair[0], Value: pair[1]})
- }
- }
  for _, item := range command.properties {
- pair := strings.Split(item, "=")
- if len(pair) == 2 {
- ctx.Spec.Environment = append(ctx.Spec.Environment, v1alpha1.EnvironmentSpec{Name: pair[0], Value: pair[1]})
- }
+ ctx.Spec.Configuration = append(ctx.Spec.Configuration, v1alpha1.ConfigurationSpec{
+ Type:  "property",
+ Value: item,
+ })
+ }
+ for _, item := range command.configmaps {
+ ctx.Spec.Configuration = append(ctx.Spec.Configuration, v1alpha1.ConfigurationSpec{
+ Type:  "configmap",
+ Value: item,
+ })
+ }
+ for _, item := range command.secrets {
+ ctx.Spec.Configuration = append(ctx.Spec.Configuration, v1alpha1.ConfigurationSpec{
+ Type:  "secret",
+ Value: item,
+ })
  }
 
  existed := false
diff --git a/pkg/client/cmd/run.go b/pkg/client/cmd/run.go
index 312f49b..c4df815 100644
--- a/pkg/client/cmd/run.go
+++ b/pkg/client/cmd/run.go
@@ -34,17 +34,9 @@ import (
  "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
-type RunCmdOptions struct {
- *RootCmdOptions
- IntegrationContext string
- Language           string
- IntegrationName    string
- Dependencies       []string
- Wait               bool
-}
-
+// NewCmdRun --
 func NewCmdRun(rootCmdOptions *RootCmdOptions) *cobra.Command {
- options := RunCmdOptions{
+ options := runCmdOptions{
  RootCmdOptions: rootCmdOptions,
  }
 
@@ -61,11 +53,26 @@ func NewCmdRun(rootCmdOptions *RootCmdOptions) *cobra.Command {
  cmd.Flags().StringSliceVarP(&options.Dependencies, "dependency", "d", nil, "The integration dependency")
  cmd.Flags().BoolVarP(&options.Wait, "wait", "w", false, "Waits for the integration to be running")
  cmd.Flags().StringVarP(&options.IntegrationContext, "context", "x", "", "The contex used to run the integration")
+ cmd.Flags().StringSliceVarP(&options.Properties, "property", "p", nil, "Add a camel property")
+ cmd.Flags().StringSliceVar(&options.ConfigMaps, "configmap", nil, "Add a ConfigMap")
+ cmd.Flags().StringSliceVar(&options.Secrets, "secret", nil, "Add a Secret")
 
  return &cmd
 }
 
-func (*RunCmdOptions) validateArgs(cmd *cobra.Command, args []string) error {
+type runCmdOptions struct {
+ *RootCmdOptions
+ IntegrationContext string
+ Language           string
+ IntegrationName    string
+ Dependencies       []string
+ Properties         []string
+ ConfigMaps         []string
+ Secrets            []string
+ Wait               bool
+}
+
+func (*runCmdOptions) validateArgs(cmd *cobra.Command, args []string) error {
  if len(args) != 1 {
  return errors.New("accepts 1 arg, received " + strconv.Itoa(len(args)))
  }
@@ -78,7 +85,7 @@ func (*RunCmdOptions) validateArgs(cmd *cobra.Command, args []string) error {
  return nil
 }
 
-func (o *RunCmdOptions) run(cmd *cobra.Command, args []string) error {
+func (o *runCmdOptions) run(cmd *cobra.Command, args []string) error {
  integration, err := o.createIntegration(cmd, args)
  if err != nil {
  return err
@@ -92,7 +99,7 @@ func (o *RunCmdOptions) run(cmd *cobra.Command, args []string) error {
  return nil
 }
 
-func (o *RunCmdOptions) waitForIntegrationReady(integration *v1alpha1.Integration) error {
+func (o *runCmdOptions) waitForIntegrationReady(integration *v1alpha1.Integration) error {
  // Block this goroutine until the integration is in a final status
  changes, err := watch.WatchStateChanges(o.Context, integration)
  if err != nil {
@@ -130,7 +137,7 @@ watcher:
  return nil
 }
 
-func (o *RunCmdOptions) createIntegration(cmd *cobra.Command, args []string) (*v1alpha1.Integration, error) {
+func (o *runCmdOptions) createIntegration(cmd *cobra.Command, args []string) (*v1alpha1.Integration, error) {
  code, err := o.loadCode(args[0])
  if err != nil {
  return nil, err
@@ -157,7 +164,7 @@ func (o *RunCmdOptions) createIntegration(cmd *cobra.Command, args []string) (*v
 
  integration := v1alpha1.Integration{
  TypeMeta: v1.TypeMeta{
- Kind:       "Integration",
+ Kind:       v1alpha1.IntegrationKind,
  APIVersion: v1alpha1.SchemeGroupVersion.String(),
  },
  ObjectMeta: v1.ObjectMeta{
@@ -170,11 +177,31 @@ func (o *RunCmdOptions) createIntegration(cmd *cobra.Command, args []string) (*v
  Content:  code,
  Language: o.Language,
  },
- Dependencies: o.Dependencies,
- Context:      o.IntegrationContext,
+ Dependencies:  o.Dependencies,
+ Context:       o.IntegrationContext,
+ Configuration: make([]v1alpha1.ConfigurationSpec, 0),
  },
  }
 
+ for _, item := range o.Properties {
+ integration.Spec.Configuration = append(integration.Spec.Configuration, v1alpha1.ConfigurationSpec{
+ Type:  "property",
+ Value: item,
+ })
+ }
+ for _, item := range o.ConfigMaps {
+ integration.Spec.Configuration = append(integration.Spec.Configuration, v1alpha1.ConfigurationSpec{
+ Type:  "configmap",
+ Value: item,
+ })
+ }
+ for _, item := range o.Secrets {
+ integration.Spec.Configuration = append(integration.Spec.Configuration, v1alpha1.ConfigurationSpec{
+ Type:  "secret",
+ Value: item,
+ })
+ }
+
  existed := false
  err = sdk.Create(&integration)
  if err != nil && k8serrors.IsAlreadyExists(err) {
@@ -200,7 +227,7 @@ func (o *RunCmdOptions) createIntegration(cmd *cobra.Command, args []string) (*v
  return &integration, nil
 }
 
-func (*RunCmdOptions) loadCode(fileName string) (string, error) {
+func (*runCmdOptions) loadCode(fileName string) (string, error) {
  content, err := ioutil.ReadFile(fileName)
  if err != nil {
  return "", err
diff --git a/pkg/stub/action/integration/build.go b/pkg/stub/action/integration/build.go
index f98930e..ba24358 100644
--- a/pkg/stub/action/integration/build.go
+++ b/pkg/stub/action/integration/build.go
@@ -24,38 +24,37 @@ import (
  "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/pkg/errors"
  "github.com/sirupsen/logrus"
 )
 
-type BuildAction struct {
- buildManager *build.Manager
-}
-
+// NewBuildAction create an action that handles integration build
 func NewBuildAction(ctx context.Context, namespace string) IntegrationAction {
- return &BuildAction{
+ return &buildAction{
  buildManager: build.NewManager(ctx, namespace),
  }
 }
 
-func (b *BuildAction) Name() string {
+type buildAction struct {
+ buildManager *build.Manager
+}
+
+func (action *buildAction) Name() string {
  return "build"
 }
 
-func (b *BuildAction) CanHandle(integration *v1alpha1.Integration) bool {
+func (action *buildAction) CanHandle(integration *v1alpha1.Integration) bool {
  return integration.Status.Phase == v1alpha1.IntegrationPhaseBuilding
 }
 
-func (b *BuildAction) Handle(integration *v1alpha1.Integration) error {
- if integration.Spec.Context != "" {
- name := integration.Spec.Context
- ctx := v1alpha1.NewIntegrationContext(integration.Namespace, name)
+func (action *buildAction) 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 err := sdk.Get(&ctx); err != nil {
- //TODO: we may need to add a wait strategy, i.e give up after some time
- return errors.Wrapf(err, "unable to find integration context %s, %s", ctx.Name, err)
- }
 
+ if ctx != nil {
  if ctx.Status.Phase == v1alpha1.IntegrationContextPhaseReady {
  target := integration.DeepCopy()
  target.Status.Image = ctx.Status.Image
@@ -70,9 +69,9 @@ func (b *BuildAction) Handle(integration *v1alpha1.Integration) error {
  Name:      integration.Name,
  Qualifier: integration.Status.Digest,
  }
- buildResult := b.buildManager.Get(buildIdentifier)
+ buildResult := action.buildManager.Get(buildIdentifier)
  if buildResult.Status == api.BuildStatusNotRequested {
- b.buildManager.Start(api.BuildSource{
+ action.buildManager.Start(api.BuildSource{
  Identifier: buildIdentifier,
  Code: api.Code{
  Name:     integration.Spec.Source.Name,
diff --git a/pkg/stub/action/integration/deploy.go b/pkg/stub/action/integration/deploy.go
index 3403928..8bc4b74 100644
--- a/pkg/stub/action/integration/deploy.go
+++ b/pkg/stub/action/integration/deploy.go
@@ -18,6 +18,7 @@ limitations under the License.
 package action
 
 import (
+ "fmt"
  "strings"
 
  "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
@@ -29,26 +30,31 @@ import (
  metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
-type DeployAction struct {
+// NewDeployAction create an action that handles integration deploy
+func NewDeployAction() IntegrationAction {
+ return &deployAction{}
 }
 
-func NewDeployAction() IntegrationAction {
- return &DeployAction{}
+type deployAction struct {
 }
 
-func (b *DeployAction) Name() string {
+func (action *deployAction) Name() string {
  return "deploy"
 }
 
-func (a *DeployAction) CanHandle(integration *v1alpha1.Integration) bool {
+func (action *deployAction) CanHandle(integration *v1alpha1.Integration) bool {
  return integration.Status.Phase == v1alpha1.IntegrationPhaseDeploying
 }
 
-func (a *DeployAction) Handle(integration *v1alpha1.Integration) error {
- if err := createOrUpdateConfigMap(integration); err != nil {
+func (action *deployAction) Handle(integration *v1alpha1.Integration) error {
+ ctx, err := LookupContextForIntegration(integration)
+ if err != nil {
  return err
  }
- if err := createOrUpdateDeployment(integration); err != nil {
+ if err = createOrUpdateConfigMap(ctx, integration); err != nil {
+ return err
+ }
+ if err = createOrUpdateDeployment(ctx, integration); err != nil {
  return err
  }
 
@@ -61,11 +67,15 @@ func (a *DeployAction) Handle(integration *v1alpha1.Integration) error {
 //
 // **********************************
 
-func getConfigMapFor(integration *v1alpha1.Integration) *corev1.ConfigMap {
+func getConfigMapFor(ctx *v1alpha1.IntegrationContext, integration *v1alpha1.Integration) (*corev1.ConfigMap, error) {
  controller := true
  blockOwnerDeletion := true
 
- return &corev1.ConfigMap{
+ // combine properties of integration with context, integration
+ // properties have the priority
+ properties := CombineConfigurationAsMap("property", ctx, integration)
+
+ cm := corev1.ConfigMap{
  TypeMeta: metav1.TypeMeta{
  Kind:       "ConfigMap",
  APIVersion: "v1",
@@ -91,14 +101,20 @@ func getConfigMapFor(integration *v1alpha1.Integration) *corev1.ConfigMap {
  },
  Data: map[string]string{
  "integration": integration.Spec.Source.Content,
+ "properties":  PropertiesString(properties),
  },
  }
+
+ return &cm, nil
 }
 
-func createOrUpdateConfigMap(integration *v1alpha1.Integration) error {
- cm := getConfigMapFor(integration)
+func createOrUpdateConfigMap(ctx *v1alpha1.IntegrationContext, integration *v1alpha1.Integration) error {
+ cm, err := getConfigMapFor(ctx, integration)
+ if err != nil {
+ return err
+ }
 
- err := sdk.Create(cm)
+ err = sdk.Create(cm)
  if err != nil && k8serrors.IsAlreadyExists(err) {
  err = sdk.Update(cm)
  }
@@ -115,10 +131,21 @@ func createOrUpdateConfigMap(integration *v1alpha1.Integration) error {
 //
 // **********************************
 
-func getDeploymentFor(integration *v1alpha1.Integration) *appsv1.Deployment {
+func getDeploymentFor(ctx *v1alpha1.IntegrationContext, integration *v1alpha1.Integration) (*appsv1.Deployment, error) {
  controller := true
  blockOwnerDeletion := true
- integrationName := strings.TrimPrefix(integration.Spec.Source.Name, "/")
+ sourceName := strings.TrimPrefix(integration.Spec.Source.Name, "/")
+
+ // combine environment of integration with context, integration
+ // environment has the priority
+ environment := CombineConfigurationAsMap("env", ctx, integration)
+
+ // set env vars needed by the runtime
+ environment["JAVA_MAIN_CLASS"] = "org.apache.camel.k.jvm.Application"
+ environment["CAMEL_K_ROUTES_URI"] = "file:/etc/camel/conf/" + sourceName
+ environment["CAMEL_K_ROUTES_LANGUAGE"] = integration.Spec.Source.Language
+ environment["CAMEL_K_CONF"] = "/etc/camel/conf/application.properties"
+ environment["CAMEL_K_CONF_D"] = "/etc/camel/conf.d"
 
  labels := map[string]string{
  "camel.apache.org/integration": integration.Name,
@@ -158,58 +185,116 @@ func getDeploymentFor(integration *v1alpha1.Integration) *appsv1.Deployment {
  {
  Name:  integration.Name,
  Image: integration.Status.Image,
- VolumeMounts: []corev1.VolumeMount{
- {
- Name:      "integration",
- MountPath: "/etc/camel",
- },
- },
- Env: []corev1.EnvVar{
- {
- Name:  "JAVA_MAIN_CLASS",
- Value: "org.apache.camel.k.jvm.Application",
- },
- {
- Name:  "CAMEL_K_ROUTES_URI",
- Value: "file:/etc/camel/" + integrationName,
- },
- {
- Name:  "CAMEL_K_ROUTES_LANGUAGE",
- Value: integration.Spec.Source.Language,
- },
- },
+ Env:   EnvironmentAsEnvVarSlice(environment),
  },
  },
- Volumes: []corev1.Volume{
- {
- Name: "integration",
- VolumeSource: corev1.VolumeSource{
- ConfigMap: &corev1.ConfigMapVolumeSource{
- LocalObjectReference: corev1.LocalObjectReference{
- Name: integration.Name,
- },
- Items: []corev1.KeyToPath{
- {
- Key:  "integration",
- Path: integrationName,
- },
- },
- },
- },
- },
+ },
+ },
+ },
+ }
+
+ //
+ // Volumes :: Setup
+ //
+
+ vols := make([]corev1.Volume, 0)
+ mnts := make([]corev1.VolumeMount, 0)
+ cnt := 0
+
+ //
+ // Volumes :: Defaults
+ //
+
+ vols = append(vols, corev1.Volume{
+ Name: "integration",
+ VolumeSource: corev1.VolumeSource{
+ ConfigMap: &corev1.ConfigMapVolumeSource{
+ LocalObjectReference: corev1.LocalObjectReference{
+ Name: integration.Name,
+ },
+ Items: []corev1.KeyToPath{
+ {
+ Key:  "integration",
+ Path: sourceName,
+ }, {
+ Key:  "properties",
+ Path: "application.properties",
  },
  },
  },
  },
+ })
+
+ mnts = append(mnts, corev1.VolumeMount{
+ Name:      "integration",
+ MountPath: "/etc/camel/conf",
+ })
+
+ //
+ // Volumes :: Additional ConfigMaps
+ //
+
+ cmList := CombineConfigurationAsSlice("configmap", ctx, integration)
+ for _, cmName := range cmList {
+ cnt++
+
+ vols = append(vols, corev1.Volume{
+ Name: "integration-cm-" + cmName,
+ VolumeSource: corev1.VolumeSource{
+ ConfigMap: &corev1.ConfigMapVolumeSource{
+ LocalObjectReference: corev1.LocalObjectReference{
+ Name: cmName,
+ },
+ },
+ },
+ })
+
+ mnts = append(mnts, corev1.VolumeMount{
+ Name:      "integration-cm-" + cmName,
+ MountPath: fmt.Sprintf("/etc/camel/conf.d/%03d_%s", cnt, cmName),
+ })
  }
 
- return &deployment
+ //
+ // Volumes :: Additional Secrets
+ //
+
+ secretList := CombineConfigurationAsSlice("secret", ctx, integration)
+ for _, secretName := range secretList {
+ cnt++
+
+ vols = append(vols, corev1.Volume{
+ Name: "integration-secret-" + secretName,
+ VolumeSource: corev1.VolumeSource{
+ Secret: &corev1.SecretVolumeSource{
+ SecretName: secretName,
+ },
+ },
+ })
+
+ mnts = append(mnts, corev1.VolumeMount{
+ Name:      "integration-secret-" + secretName,
+ MountPath: fmt.Sprintf("/etc/camel/conf.d/%03d_%s", cnt, secretName),
+ })
+ }
+
+ //
+ // Volumes
+ //
+
+ deployment.Spec.Template.Spec.Volumes = vols
+ deployment.Spec.Template.Spec.Containers[0].VolumeMounts = mnts
+
+ return &deployment, nil
 }
 
-func createOrUpdateDeployment(integration *v1alpha1.Integration) error {
- deployment := getDeploymentFor(integration)
+func createOrUpdateDeployment(ctx *v1alpha1.IntegrationContext, integration *v1alpha1.Integration) error {
+ deployment, err := getDeploymentFor(ctx, integration)
+ if err != nil {
+ return err
+ }
 
- err := sdk.Create(deployment)
+ err = sdk.Create(deployment)
  if err != nil && k8serrors.IsAlreadyExists(err) {
  err = sdk.Update(deployment)
  }
diff --git a/pkg/stub/action/integration/util.go b/pkg/stub/action/integration/util.go
new file mode 100644
index 0000000..8021809
--- /dev/null
+++ b/pkg/stub/action/integration/util.go
@@ -0,0 +1,106 @@
+package action
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+ "github.com/operator-framework/operator-sdk/pkg/sdk"
+ "k8s.io/api/core/v1"
+
+ "github.com/pkg/errors"
+)
+
+// LookupContextForIntegration --
+func LookupContextForIntegration(integration *v1alpha1.Integration) (*v1alpha1.IntegrationContext, error) {
+ if integration.Spec.Context != "" {
+ name := integration.Spec.Context
+ ctx := v1alpha1.NewIntegrationContext(integration.Namespace, name)
+
+ if err := sdk.Get(&ctx); err != nil {
+ return nil, errors.Wrapf(err, "unable to find integration context %s, %s", ctx.Name, err)
+ }
+
+ return &ctx, nil
+ }
+
+ return nil, nil
+}
+
+// PropertiesString --
+func PropertiesString(m map[string]string) string {
+ properties := ""
+ for k, v := range m {
+ properties += fmt.Sprintf("%s=%s\n", k, v)
+ }
+
+ return properties
+}
+
+// EnvironmentAsEnvVarSlice --
+func EnvironmentAsEnvVarSlice(m map[string]string) []v1.EnvVar {
+ env := make([]v1.EnvVar, 0, len(m))
+
+ for k, v := range m {
+ env = append(env, v1.EnvVar{Name: k, Value: v})
+ }
+
+ return env
+}
+
+// CombineConfigurationAsMap --
+func CombineConfigurationAsMap(configurationType string, context *v1alpha1.IntegrationContext, integration *v1alpha1.Integration) map[string]string {
+ result := make(map[string]string)
+ if context != nil {
+ // Add context properties first so integrations can
+ // override it
+ for _, c := range context.Spec.Configuration {
+ if c.Type == configurationType {
+ pair := strings.Split(c.Value, "=")
+ if len(pair) == 2 {
+ result[pair[0]] = pair[1]
+ }
+ }
+ }
+ }
+
+ if integration != nil {
+ for _, c := range integration.Spec.Configuration {
+ if c.Type == configurationType {
+ pair := strings.Split(c.Value, "=")
+ if len(pair) == 2 {
+ result[pair[0]] = pair[1]
+ }
+ }
+ }
+ }
+
+ return result
+}
+
+// CombineConfigurationAsSlice --
+func CombineConfigurationAsSlice(configurationType string, context *v1alpha1.IntegrationContext, integration *v1alpha1.Integration) []string {
+ result := make(map[string]bool, 0)
+ if context != nil {
+ // Add context properties first so integrations can
+ // override it
+ for _, c := range context.Spec.Configuration {
+ if c.Type == configurationType {
+ result[c.Value] = true
+ }
+ }
+ }
+
+ for _, c := range integration.Spec.Configuration {
+ if c.Type == configurationType {
+ result[c.Value] = true
+ }
+ }
+
+ keys := make([]string, 0, len(result))
+ for k := range result {
+ keys = append(keys, k)
+ }
+
+ return keys
+}
diff --git a/pkg/util/digest/digest.go b/pkg/util/digest/digest.go
index 103a6f1..265c664 100644
--- a/pkg/util/digest/digest.go
+++ b/pkg/util/digest/digest.go
@@ -44,6 +44,10 @@ func ComputeForIntegration(integration *v1alpha1.Integration) string {
  for _, item := range integration.Spec.Dependencies {
  hash.Write([]byte(item))
  }
+ // Integration configuration
+ for _, item := range integration.Spec.Configuration {
+ hash.Write([]byte(item.String()))
+ }
 
  // Add a letter at the beginning and use URL safe encoding
  return "v" + base64.RawURLEncoding.EncodeToString(hash.Sum(nil))
@@ -51,18 +55,15 @@ func ComputeForIntegration(integration *v1alpha1.Integration) string {
 
 // ComputeForIntegrationContext a digest of the fields that are relevant for the deployment
 // Produces a digest that can be used as docker image tag
-func ComputeForIntegrationContext(integration *v1alpha1.IntegrationContext) string {
+func ComputeForIntegrationContext(context *v1alpha1.IntegrationContext) string {
  hash := sha256.New()
  // Operator version is relevant
  hash.Write([]byte(version.Version))
 
- for _, item := range integration.Spec.Dependencies {
+ for _, item := range context.Spec.Dependencies {
  hash.Write([]byte(item))
  }
- for _, item := range integration.Spec.Environment {
- hash.Write([]byte(item.String()))
- }
- for _, item := range integration.Spec.Properties {
+ for _, item := range context.Spec.Configuration {
  hash.Write([]byte(item.String()))
  }
 
@@ -70,6 +71,7 @@ func ComputeForIntegrationContext(integration *v1alpha1.IntegrationContext) stri
  return "v" + base64.RawURLEncoding.EncodeToString(hash.Sum(nil))
 }
 
+// Random --
 func Random() string {
  return "v" + strconv.FormatInt(rand.Int63(), 10)
 }
diff --git a/pkg/util/maven/types.go b/pkg/util/maven/types.go
index 30a80de..5b1158e 100644
--- a/pkg/util/maven/types.go
+++ b/pkg/util/maven/types.go
@@ -25,7 +25,7 @@ type ProjectDefinition struct {
  Project     Project
  JavaSources map[string]string
  Resources   map[string]string
- Env         map[string]string
+ Env         map[string]string // TODO: should we deprecate it ? env are set on deployment
 }
 
 type Project struct {
diff --git a/runtime/examples/props.js b/runtime/examples/props.js
new file mode 100644
index 0000000..a89b6ae
--- /dev/null
+++ b/runtime/examples/props.js
@@ -0,0 +1,9 @@
+//
+// To run this integrations use:
+//
+//     kamel run -p my.message=test-props runtime/examples/props.js
+//
+
+from('timer:props?period=1s')
+    .routeId('props')
+    .log('{{my.message}}')
\ No newline at end of file
diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Application.java b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Application.java
index bec284f..1575131 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Application.java
+++ b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Application.java
@@ -16,11 +16,27 @@
  */
 package org.apache.camel.k.jvm;
 
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.FileVisitor;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.main.Main;
 import org.apache.camel.util.ObjectHelper;
+import org.apache.commons.io.FilenameUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class Application {
+    private static final Logger LOGGER = LoggerFactory.getLogger(Application.class);
 
     public static void main(String[] args) throws Exception {
         final String resource = System.getenv(Routes.ENV_CAMEL_K_ROUTES_URI);
@@ -30,6 +46,7 @@ public static void main(String[] args) throws Exception {
             throw new IllegalStateException("No valid resource found in " + Routes.ENV_CAMEL_K_ROUTES_URI + " environment variable");
         }
 
+        String locations = computePropertyPlaceholderLocations();
         RoutesLoader loader = Routes.loaderFor(resource, language);
         RouteBuilder routes = loader.load(resource);
 
@@ -37,8 +54,59 @@ public static void main(String[] args) throws Exception {
             throw new IllegalStateException("Unable to load route from: " + resource);
         }
 
+        LOGGER.info("Routes    : {}", resource);
+        LOGGER.info("Language  : {}", language);
+        LOGGER.info("Locations : {}", locations);
+
         Main main = new Main();
+
+        if (ObjectHelper.isNotEmpty(locations)) {
+            main.setPropertyPlaceholderLocations(locations);
+        }
+
         main.addRouteBuilder(routes);
         main.run();
     }
+
+    // *******************************
+    //
+    // helpers
+    //
+    // *******************************
+
+    private static String computePropertyPlaceholderLocations() throws IOException {
+        final String conf = System.getenv(Routes.ENV_CAMEL_K_CONF);
+        final String confd = System.getenv(Routes.ENV_CAMEL_K_CONF_D);
+        final List<String> locations = new ArrayList<>();
+
+        // Main location
+        if (ObjectHelper.isNotEmpty(conf)) {
+            locations.add("file:" + conf);
+        }
+
+        // Additional locations
+        if (ObjectHelper.isNotEmpty(confd)) {
+            Path root = Paths.get(confd);
+            FileVisitor<Path> visitor = new SimpleFileVisitor<Path>() {
+                @Override
+                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                    Objects.requireNonNull(file);
+                    Objects.requireNonNull(attrs);
+
+                    String path = file.toFile().getAbsolutePath();
+                    String ext = FilenameUtils.getExtension(path);
+
+                    if (Objects.equals("properties", ext)) {
+                        locations.add("file:" + path);
+                    }
+
+                    return FileVisitResult.CONTINUE;
+                }
+            };
+
+            Files.walkFileTree(root, visitor);
+        }
+
+        return String.join(",", locations);
+    }
 }
diff --git a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Routes.java b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Routes.java
index b2c87d4..03c91e4 100644
--- a/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Routes.java
+++ b/runtime/jvm/src/main/java/org/apache/camel/k/jvm/Routes.java
@@ -27,6 +27,8 @@
 public final class Routes {
     public static final String ENV_CAMEL_K_ROUTES_URI = "CAMEL_K_ROUTES_URI";
     public static final String ENV_CAMEL_K_ROUTES_LANGUAGE = "CAMEL_K_ROUTES_LANGUAGE";
+    public static final String ENV_CAMEL_K_CONF = "CAMEL_K_CONF";
+    public static final String ENV_CAMEL_K_CONF_D = "CAMEL_K_CONF_D";
     public static final String SCHEME_CLASSPATH = "classpath:";
     public static final String SCHEME_FILE = "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:
[hidden email]


With regards,
Apache Git Services