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:
[email protected]
With regards,
Apache Git Services