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 2021/02/09 12:32:02 UTC
[camel-k] 01/06: feat: Add ServiceBinding trait (#1445)
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 a000ec5c18b0e504ccd2e424a3ca417e0d50b11a
Author: John Poth <po...@gmail.com>
AuthorDate: Fri Sep 25 14:31:30 2020 +0200
feat: Add ServiceBinding trait (#1445)
---
deploy/operator-role-binding-service-binding.yaml | 30 +++
deploy/operator-role-service-binding.yaml | 37 +++
go.mod | 7 +-
pkg/apis/addtoscheme_service_binding.go | 25 ++
pkg/apis/camel/v1/integration_types.go | 4 +
pkg/cmd/run.go | 9 +-
.../integration/integration_controller.go | 10 +
pkg/controller/integration/platform_setup.go | 3 +-
pkg/trait/deployer.go | 3 +-
pkg/trait/service_binding.go | 266 +++++++++++++++++++++
pkg/trait/trait_register.go | 1 +
pkg/trait/trait_types.go | 33 ++-
12 files changed, 418 insertions(+), 10 deletions(-)
diff --git a/deploy/operator-role-binding-service-binding.yaml b/deploy/operator-role-binding-service-binding.yaml
new file mode 100644
index 0000000..9a2621a
--- /dev/null
+++ b/deploy/operator-role-binding-service-binding.yaml
@@ -0,0 +1,30 @@
+# ---------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ---------------------------------------------------------------------------
+
+kind: RoleBinding
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ name: camel-k-operator-service-binding
+ labels:
+ app: "camel-k"
+subjects:
+- kind: ServiceAccount
+ name: camel-k-operator
+roleRef:
+ kind: Role
+ name: camel-k-operator-service-binding
+ apiGroup: rbac.authorization.k8s.io
diff --git a/deploy/operator-role-service-binding.yaml b/deploy/operator-role-service-binding.yaml
new file mode 100644
index 0000000..68a2774
--- /dev/null
+++ b/deploy/operator-role-service-binding.yaml
@@ -0,0 +1,37 @@
+# ---------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ---------------------------------------------------------------------------
+
+kind: Role
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ name: camel-k-operator-service-binding
+ labels:
+ app: "camel-k"
+rules:
+- apiGroups:
+ - operators.coreos.com
+ resources:
+ - servicebindings
+ verbs:
+ - create
+ - delete
+ - deletecollection
+ - get
+ - list
+ - patch
+ - update
+ - watch
diff --git a/go.mod b/go.mod
index e744805..603cb68 100644
--- a/go.mod
+++ b/go.mod
@@ -28,6 +28,7 @@ require (
github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.42.1
github.com/prometheus/client_golang v1.7.1
github.com/radovskyb/watcher v1.0.6
+ github.com/redhat-developer/service-binding-operator v0.4.0
github.com/rs/xid v1.2.1
github.com/scylladb/go-set v1.0.2
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749
@@ -37,7 +38,7 @@ require (
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.6.2
github.com/stoewer/go-strcase v1.0.2
- github.com/stretchr/testify v1.5.1
+ github.com/stretchr/testify v1.6.1
go.uber.org/multierr v1.5.0
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
gopkg.in/inf.v0 v0.9.1
@@ -57,6 +58,10 @@ replace (
github.com/Azure/go-autorest => github.com/Azure/go-autorest v13.3.2+incompatible // Required by OLM
k8s.io/client-go => k8s.io/client-go v0.18.9
k8s.io/code-generator => k8s.io/code-generator v0.18.9
+ // Required by Service Binding Operator dependency, see https://github.com/redhat-developer/service-binding-operator/pull/798
+ github.com/operator-framework/operator-lifecycle-manager => github.com/operator-framework/operator-lifecycle-manager v0.0.0-20200321030439-57b580e57e88
+ github.com/operator-framework/operator-sdk => github.com/operator-framework/operator-sdk v0.17.1
+ k8s.io/api => k8s.io/api v0.18.9
)
replace github.com/docker/docker => github.com/moby/moby v0.7.3-0.20190826074503-38ab9da00309 // Required by Helm
diff --git a/pkg/apis/addtoscheme_service_binding.go b/pkg/apis/addtoscheme_service_binding.go
new file mode 100644
index 0000000..9fc4a7b
--- /dev/null
+++ b/pkg/apis/addtoscheme_service_binding.go
@@ -0,0 +1,25 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package apis
+
+import "github.com/redhat-developer/service-binding-operator/pkg/apis/operators/v1alpha1"
+
+func init() {
+ // Register the types with the Scheme so the components can map objects to GroupVersionKinds and back
+ AddToSchemes = append(AddToSchemes, v1alpha1.SchemeBuilder.AddToScheme)
+}
diff --git a/pkg/apis/camel/v1/integration_types.go b/pkg/apis/camel/v1/integration_types.go
index 3d103d5..5a9e631 100644
--- a/pkg/apis/camel/v1/integration_types.go
+++ b/pkg/apis/camel/v1/integration_types.go
@@ -112,6 +112,8 @@ const (
IntegrationPhaseBuildingKit IntegrationPhase = "Building Kit"
// IntegrationPhaseResolvingKit --
IntegrationPhaseResolvingKit IntegrationPhase = "Resolving Kit"
+ // IntegrationPhaseWaitingForServiceBindingCollectionReady --
+ IntegrationPhaseWaitingForServiceBindingCollectionReady IntegrationPhase = "Waiting For Service binding Collection Ready Status"
// IntegrationPhaseDeploying --
IntegrationPhaseDeploying IntegrationPhase = "Deploying"
// IntegrationPhaseRunning --
@@ -133,6 +135,8 @@ const (
IntegrationConditionKnativeServiceAvailable IntegrationConditionType = "KnativeServiceAvailable"
// IntegrationConditionCronJobAvailable --
IntegrationConditionCronJobAvailable IntegrationConditionType = "CronJobAvailable"
+ // IntegrationConditionServiceBindingCollectionReady --
+ IntegrationConditionServiceBindingCollectionReady IntegrationConditionType = "ServiceBindingCollectionReady"
// IntegrationConditionExposureAvailable --
IntegrationConditionExposureAvailable IntegrationConditionType = "ExposureAvailable"
// IntegrationConditionPrometheusAvailable --
diff --git a/pkg/cmd/run.go b/pkg/cmd/run.go
index 874c443..6f5f4ce 100644
--- a/pkg/cmd/run.go
+++ b/pkg/cmd/run.go
@@ -72,6 +72,7 @@ func newCmdRun(rootCmdOptions *RootCmdOptions) (*cobra.Command, *runCmdOptions)
}
cmd.Flags().String("name", "", "The integration name")
+ cmd.Flags().StringArrayP("connect", "c", nil, "A ServiceBinding or Provisioned Service that the integration should bind to specified as KIND.VERSION.GROUP/NAME[/NAMESPACE]")
cmd.Flags().StringArrayP("dependency", "d", nil, "An external library that should be included. E.g. for Maven dependencies \"mvn:org.my/app:1.0\"")
cmd.Flags().BoolP("wait", "w", false, "Wait for the integration to be running")
cmd.Flags().StringP("kit", "k", "", "The kit used to run the integration")
@@ -117,6 +118,7 @@ type runCmdOptions struct {
IntegrationName string `mapstructure:"name" yaml:",omitempty"`
Profile string `mapstructure:"profile" yaml:",omitempty"`
OutputFormat string `mapstructure:"output" yaml:",omitempty"`
+ Connects []string `mapstructure:"connects" yaml:",omitempty"`
Resources []string `mapstructure:"resources" yaml:",omitempty"`
OpenAPIs []string `mapstructure:"open-apis" yaml:",omitempty"`
Dependencies []string `mapstructure:"dependencies" yaml:",omitempty"`
@@ -658,7 +660,12 @@ func (o *runCmdOptions) GetIntegrationName(sources []string) string {
return name
}
-func (*runCmdOptions) configureTraits(integration *v1.Integration, options []string, catalog *trait.Catalog) error {
+func (o *runCmdOptions) configureTraits(integration *v1.Integration, options []string, catalog *trait.Catalog) error {
+ // configure ServiceBinding trait
+ for _, sb := range o.Connects {
+ bindings := fmt.Sprintf("service-binding.service-bindings=%s", sb)
+ options = append(options, bindings)
+ }
traits, err := configureTraits(options, catalog)
if err != nil {
return err
diff --git a/pkg/controller/integration/integration_controller.go b/pkg/controller/integration/integration_controller.go
index 5a1b5fe..012a20c 100644
--- a/pkg/controller/integration/integration_controller.go
+++ b/pkg/controller/integration/integration_controller.go
@@ -44,6 +44,7 @@ import (
"github.com/apache/camel-k/pkg/util/digest"
"github.com/apache/camel-k/pkg/util/log"
"github.com/apache/camel-k/pkg/util/monitoring"
+ sb "github.com/redhat-developer/service-binding-operator/pkg/apis/operators/v1alpha1"
)
// Add creates a new Integration Controller and adds it to the Manager. The Manager will set fields on the Controller
@@ -217,6 +218,15 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
return err
}
+ // Watch ServiceBindings created
+ err = c.Watch(&source.Kind{Type: &sb.ServiceBinding{}}, &handler.EnqueueRequestForOwner{
+ OwnerType: &v1.Integration{},
+ IsController: true,
+ })
+ if err != nil {
+ return err
+ }
+
return nil
}
diff --git a/pkg/controller/integration/platform_setup.go b/pkg/controller/integration/platform_setup.go
index 51c5a5b..0bf4127 100644
--- a/pkg/controller/integration/platform_setup.go
+++ b/pkg/controller/integration/platform_setup.go
@@ -46,7 +46,8 @@ func (action *platformSetupAction) Name() string {
// CanHandle tells whether this action can handle the integration
func (action *platformSetupAction) CanHandle(integration *v1.Integration) bool {
return integration.Status.Phase == v1.IntegrationPhaseNone ||
- integration.Status.Phase == v1.IntegrationPhaseWaitingForPlatform
+ integration.Status.Phase == v1.IntegrationPhaseWaitingForPlatform ||
+ integration.Status.Phase == v1.IntegrationPhaseWaitingForServiceBindingCollectionReady
}
// Handle handles the integrations
diff --git a/pkg/trait/deployer.go b/pkg/trait/deployer.go
index 81aaee8..ed11cf4 100644
--- a/pkg/trait/deployer.go
+++ b/pkg/trait/deployer.go
@@ -49,6 +49,7 @@ func newDeployerTrait() Trait {
func (t *deployerTrait) Configure(e *Environment) (bool, error) {
return e.IntegrationInPhase(
v1.IntegrationPhaseNone,
+ v1.IntegrationPhaseWaitingForServiceBindingCollectionReady,
v1.IntegrationPhaseWaitingForPlatform,
v1.IntegrationPhaseInitialization,
v1.IntegrationPhaseBuildingKit,
@@ -79,7 +80,7 @@ func (t *deployerTrait) Apply(e *Environment) error {
})
}
- case v1.IntegrationPhaseRunning:
+ case v1.IntegrationPhaseRunning, v1.IntegrationPhaseWaitingForServiceBindingCollectionReady:
// Register a post action that patches the resources generated by the traits
e.PostActions = append(e.PostActions, func(env *Environment) error {
for _, resource := range env.Resources.Items() {
diff --git a/pkg/trait/service_binding.go b/pkg/trait/service_binding.go
new file mode 100644
index 0000000..131d2c5
--- /dev/null
+++ b/pkg/trait/service_binding.go
@@ -0,0 +1,266 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package trait
+
+import (
+ "fmt"
+ "strings"
+
+ v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+ sb "github.com/redhat-developer/service-binding-operator/pkg/apis/operators/v1alpha1"
+ corev1 "k8s.io/api/core/v1"
+ k8serrors "k8s.io/apimachinery/pkg/api/errors"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+// The Service Binding trait allows users to connect to Provisioned Services and ServiceBindings in Kubernetes:
+// https://github.com/k8s-service-bindings/spec#service-binding
+// As the specification is still evolving this is subject to change
+// +camel-k:trait=service-binding
+type serviceBindingTrait struct {
+ BaseTrait `property:",squash"`
+ // List of Provisioned Services and ServiceBindings in the form KIND.VERSION.GROUP/NAME[/NAMESPACE]
+ ServiceBindings []string `property:"service-bindings" json:"serviceBindings,omitempty"`
+}
+
+func newServiceBindingTrait() Trait {
+ return &serviceBindingTrait{
+ BaseTrait: NewBaseTrait("service-binding", 250),
+ }
+}
+
+// IsAllowedInProfile overrides default
+func (t *serviceBindingTrait) IsAllowedInProfile(profile v1.TraitProfile) bool {
+ return profile == v1.TraitProfileKubernetes ||
+ profile == v1.TraitProfileOpenShift
+}
+
+func (t *serviceBindingTrait) Configure(e *Environment) (bool, error) {
+ if t.Enabled != nil && !*t.Enabled {
+ return false, nil
+ }
+
+ if len(t.ServiceBindings) == 0 {
+ return false, nil
+ }
+
+ return e.IntegrationInPhase(
+ v1.IntegrationPhaseInitialization,
+ v1.IntegrationPhaseWaitingForServiceBindingCollectionReady,
+ v1.IntegrationPhaseDeploying,
+ v1.IntegrationPhaseRunning,
+ ), nil
+}
+
+func (t *serviceBindingTrait) Apply(e *Environment) error {
+ integrationServiceBindingName := e.Integration.Name + "-service-binding-request"
+ services, err := t.parseProvisionedServices(e)
+ if err != nil {
+ return err
+ }
+ serviceBindings, err := t.parseServiceBindings(e)
+ if err != nil {
+ return err
+ }
+ if len(services) > 0 {
+ serviceBindings = append(serviceBindings, integrationServiceBindingName)
+ }
+ if e.IntegrationInPhase(v1.IntegrationPhaseInitialization) {
+ serviceBindingsCollectionReady := true
+ for _, name := range serviceBindings {
+ isIntSB := name == integrationServiceBindingName
+ serviceBinding, err := t.getServiceBinding(e, name)
+ // Do not throw an error if the ServiceBinding is not found and if we are managing it: we will create it
+ if (err != nil && !k8serrors.IsNotFound(err)) || (err != nil && !isIntSB) {
+ return err
+ }
+ if isIntSB {
+ request := createServiceBinding(e, services, integrationServiceBindingName)
+ e.Resources.Add(&request)
+ }
+ if isCollectionReady(serviceBinding) {
+ setCollectionReady(e, name, corev1.ConditionTrue)
+ } else {
+ setCollectionReady(e, name, corev1.ConditionFalse)
+ serviceBindingsCollectionReady = false
+ }
+ }
+ if !serviceBindingsCollectionReady {
+ e.PostProcessors = append(e.PostProcessors, func(environment *Environment) error {
+ e.Integration.Status.Phase = v1.IntegrationPhaseWaitingForServiceBindingCollectionReady
+ return nil
+ })
+ }
+ return nil
+ } else if e.IntegrationInPhase(v1.IntegrationPhaseWaitingForServiceBindingCollectionReady) {
+ for _, name := range serviceBindings {
+ serviceBinding, err := t.getServiceBinding(e, name)
+ if err != nil {
+ return err
+ }
+ if isCollectionReady(serviceBinding) {
+ setCollectionReady(e, name, corev1.ConditionTrue)
+ } else {
+ setCollectionReady(e, name, corev1.ConditionFalse)
+ return nil
+ }
+ }
+ e.PostActions = append(e.PostActions, func(environment *Environment) error {
+ e.Integration.Status.Phase = v1.IntegrationPhaseInitialization
+ return nil
+ })
+ } else if e.IntegrationInPhase(v1.IntegrationPhaseDeploying, v1.IntegrationPhaseRunning) {
+ e.ServiceBindings = make(map[string]string)
+ for _, name := range serviceBindings {
+ sb, err := t.getServiceBinding(e, name)
+ if err != nil {
+ return err
+ }
+ if !isCollectionReady(sb) {
+ setCollectionReady(e, name, corev1.ConditionFalse)
+ e.PostProcessors = append(e.PostProcessors, func(environment *Environment) error {
+ e.Integration.Status.Phase = v1.IntegrationPhaseWaitingForServiceBindingCollectionReady
+ return nil
+ })
+ return nil
+ }
+ e.ServiceBindings[name] = sb.Status.Secret
+ if name == integrationServiceBindingName {
+ request := createServiceBinding(e, services, integrationServiceBindingName)
+ e.Resources.Add(&request)
+ }
+ }
+ e.ApplicationProperties["quarkus.kubernetes-service-binding.enabled"] = "true"
+ e.ApplicationProperties["SERVICE_BINDING_ROOT"] = ServiceBindingsMountPath
+ }
+ return nil
+}
+
+func setCollectionReady(e *Environment, serviceBinding string, status corev1.ConditionStatus) {
+ e.Integration.Status.SetCondition(
+ v1.IntegrationConditionServiceBindingCollectionReady,
+ status,
+ "",
+ fmt.Sprintf("Name=%s", serviceBinding),
+ )
+}
+
+func isCollectionReady(sb sb.ServiceBinding) bool {
+ for _, condition := range sb.Status.Conditions {
+ if condition.Type == "CollectionReady" {
+ return condition.Status == corev1.ConditionTrue && sb.Status.Secret != ""
+ }
+ }
+ return false
+}
+
+func (t *serviceBindingTrait) getServiceBinding(e *Environment, name string) (sb.ServiceBinding, error) {
+ serviceBinding := sb.ServiceBinding{}
+ key := k8sclient.ObjectKey{
+ Namespace: e.Integration.Namespace,
+ Name: name,
+ }
+ return serviceBinding, t.Client.Get(t.Ctx, key, &serviceBinding)
+}
+
+func (t *serviceBindingTrait) parseProvisionedServices(e *Environment) ([]sb.Service, error) {
+ services := make([]sb.Service, 0)
+ for _, s := range t.ServiceBindings {
+ seg := strings.Split(s, "/")
+ if !(len(seg) == 3 || len(seg) == 2) {
+ return nil, fmt.Errorf("ServiceBinding: %s should be specified in the form KIND.VERSION.GROUP/NAME[/NAMESPACE]", s)
+ }
+ gvk := seg[0]
+ index := strings.Index(gvk, ".")
+ kind := seg[0][0:index]
+ if kind == "ServiceBinding" {
+ continue
+ }
+ vg := seg[0][index+1 : len(gvk)]
+ index = strings.Index(vg, ".")
+ version := vg[0:index]
+ group := vg[index+1 : len(vg)]
+ name := seg[1]
+ namespace := e.Integration.Namespace
+ if len(seg) == 3 {
+ namespace = seg[2]
+ }
+ namePrefix := ""
+ service := sb.Service{
+ GroupVersionKind: metav1.GroupVersionKind{
+ Group: group,
+ Version: version,
+ Kind: kind,
+ },
+ EnvVarPrefix: &namePrefix,
+ LocalObjectReference: corev1.LocalObjectReference{
+ Name: name,
+ },
+ Namespace: &namespace,
+ }
+ services = append(services, service)
+ }
+ return services, nil
+}
+
+func (t *serviceBindingTrait) parseServiceBindings(e *Environment) ([]string, error) {
+ serviceBindings := make([]string, 0)
+ for _, s := range t.ServiceBindings {
+ seg := strings.Split(s, "/")
+ if !(len(seg) == 3 || len(seg) == 2) {
+ return nil, fmt.Errorf("ServiceBinding: %s should be specified in the form KIND.VERSION.GROUP/NAME[/NAMESPACE]", s)
+ }
+ gvk := seg[0]
+ index := strings.Index(gvk, ".")
+ kind := seg[0][0:index]
+ if kind == "ServiceBinding" {
+ vg := seg[0][index+1 : len(gvk)]
+ if vg != "v1alpha1.operators.coreos.com" {
+ return nil, fmt.Errorf("ServiceBinding: %s VERSION.GROUP should be v1alpha1.operators.coreos.com", s)
+ }
+ if len(seg) == 3 && seg[2] != e.Integration.Namespace {
+ return nil, fmt.Errorf("ServiceBinding: %s should be in the same namespace %s as the integration", s, e.Integration.Namespace)
+ }
+ serviceBindings = append(serviceBindings, seg[1])
+ }
+ }
+ return serviceBindings, nil
+}
+
+func createServiceBinding(e *Environment, services []sb.Service, name string) sb.ServiceBinding {
+ spec := sb.ServiceBindingSpec{
+ Services: services,
+ }
+ labels := map[string]string{
+ v1.IntegrationLabel: e.Integration.Name,
+ }
+ serviceBinding := sb.ServiceBinding{
+ TypeMeta: metav1.TypeMeta{
+ Kind: "ServiceBinding",
+ APIVersion: "operators.coreos.com/v1alpha1",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: e.Integration.Namespace,
+ Name: name,
+ Labels: labels,
+ },
+ Spec: spec,
+ }
+ return serviceBinding
+}
diff --git a/pkg/trait/trait_register.go b/pkg/trait/trait_register.go
index ef171c7..1ec4e31 100644
--- a/pkg/trait/trait_register.go
+++ b/pkg/trait/trait_register.go
@@ -45,6 +45,7 @@ func init() {
AddToTraits(newRouteTrait)
AddToTraits(newIstioTrait)
AddToTraits(newIngressTrait)
+ AddToTraits(newServiceBindingTrait)
AddToTraits(newOwnerTrait)
AddToTraits(newPdbTrait)
}
diff --git a/pkg/trait/trait_types.go b/pkg/trait/trait_types.go
index 7b60392..ed893e0 100644
--- a/pkg/trait/trait_types.go
+++ b/pkg/trait/trait_types.go
@@ -42,12 +42,13 @@ import (
const True = "true"
var (
- basePath = "/etc/camel"
- confDPath = path.Join(basePath, "conf.d")
- sourcesMountPath = path.Join(basePath, "sources")
- resourcesMountPath = path.Join(basePath, "resources")
- configMapsMountPath = path.Join(confDPath, "_configmaps")
- secretsMountPath = path.Join(confDPath, "_secrets")
+ basePath = "/etc/camel"
+ confDPath = path.Join(basePath, "conf.d")
+ sourcesMountPath = path.Join(basePath, "sources")
+ resourcesMountPath = path.Join(basePath, "resources")
+ configMapsMountPath = path.Join(confDPath, "_configmaps")
+ secretsMountPath = path.Join(confDPath, "_secrets")
+ serviceBindingsMountPath = path.Join(ConfdPath, "_servicebindings")
)
// Identifiable represent an identifiable type
@@ -196,6 +197,7 @@ type Environment struct {
EnvVars []corev1.EnvVar
ApplicationProperties map[string]string
Interceptors []string
+ ServiceBindings map[string]string
}
// ControllerStrategy is used to determine the kind of controller that needs to be created for the integration
@@ -671,6 +673,25 @@ func (e *Environment) configureVolumesAndMounts(vols *[]corev1.Volume, mnts *[]c
//
// Volumes :: Additional Secrets
//
+ // append Service Binding secrets
+ for _, name := range e.ServiceBindings {
+ refName := kubernetes.SanitizeLabel(name)
+
+ *vols = append(*vols, corev1.Volume{
+ Name: refName,
+ VolumeSource: corev1.VolumeSource{
+ Secret: &corev1.SecretVolumeSource{
+ SecretName: name,
+ },
+ },
+ })
+
+ *mnts = append(*mnts, corev1.VolumeMount{
+ Name: refName,
+ MountPath: path.Join(serviceBindingsMountPath, strings.ToLower(name)),
+ })
+ }
+ secrets := e.CollectConfigurationValues("secret")
for _, secretName := range e.collectConfigurationValues("secret") {
refName := kubernetes.SanitizeLabel(secretName)