This is an automated email from the ASF dual-hosted git repository. astefanutti pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel-k.git
commit 91fbfa07c3d2c9e34cad37f957a73edd6ab82593 Author: John Poth <poth.j...@gmail.com> AuthorDate: Fri Sep 3 17:33:55 2021 +0200 Fix #2553: Polish --- .github/workflows/kubernetes.yml | 8 - docs/modules/traits/pages/service-binding.adoc | 6 +- pkg/apis/addtoscheme_service_binding.go | 25 --- .../integration/integration_controller.go | 22 -- pkg/trait/service_binding.go | 233 +++++++-------------- pkg/trait/trait_configure_test.go | 6 +- resources/traits.yaml | 10 +- 7 files changed, 92 insertions(+), 218 deletions(-) diff --git a/.github/workflows/kubernetes.yml b/.github/workflows/kubernetes.yml index 57e6f8b..25e4e7e 100644 --- a/.github/workflows/kubernetes.yml +++ b/.github/workflows/kubernetes.yml @@ -99,14 +99,6 @@ jobs: make PACKAGE_ARTIFACTS_STRATEGY=download build package-artifacts images images-push sudo mv ./kamel /usr/local/bin - - name: Install Service Binding - run: | - echo "Installing Service Binding Operator" - - export SERVICE_BINDING_VERSION=v0.9.1 - kubectl apply -f https://github.com/redhat-developer/service-binding-operator/releases/download/$SERVICE_BINDING_VERSION/release.yaml - echo "Waiting for all pods to be ready in service-binding-operator" - kubectl wait --for=condition=Ready pod --all -n service-binding-operator --timeout=60s - name: Run IT # Disable registry tests as not compatible with KinD #env: diff --git a/docs/modules/traits/pages/service-binding.adoc b/docs/modules/traits/pages/service-binding.adoc index 75c755c..79a0b40 100755 --- a/docs/modules/traits/pages/service-binding.adoc +++ b/docs/modules/traits/pages/service-binding.adoc @@ -1,7 +1,7 @@ = Service Binding Trait // Start of autogenerated code - DO NOT EDIT! (description) -The Service Binding trait allows users to connect to Provisioned Services and ServiceBindings in Kubernetes: +The Service Binding trait allows users to connect to Services in Kubernetes: https://github.com/k8s-service-bindings/spec#service-binding As the specification is still evolving this is subject to change @@ -26,9 +26,9 @@ The following configuration options are available: | bool | Can be used to enable or disable a trait. All traits share this common property. -| service-binding.service-bindings +| service-binding.services | []string -| List of Provisioned Services and ServiceBindings in the form [[apigroup/]version:]kind:[namespace/]name +| List of Services in the form [[apigroup/]version:]kind:[namespace/]name |=== diff --git a/pkg/apis/addtoscheme_service_binding.go b/pkg/apis/addtoscheme_service_binding.go deleted file mode 100644 index 3d40973..0000000 --- a/pkg/apis/addtoscheme_service_binding.go +++ /dev/null @@ -1,25 +0,0 @@ -/* -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/api/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/controller/integration/integration_controller.go b/pkg/controller/integration/integration_controller.go index 8b9c745..06f2b48 100644 --- a/pkg/controller/integration/integration_controller.go +++ b/pkg/controller/integration/integration_controller.go @@ -37,14 +37,11 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" "sigs.k8s.io/controller-runtime/pkg/source" - sb "github.com/redhat-developer/service-binding-operator/api/v1alpha1" - v1 "github.com/apache/camel-k/pkg/apis/camel/v1" "github.com/apache/camel-k/pkg/client" camelevent "github.com/apache/camel-k/pkg/event" "github.com/apache/camel-k/pkg/platform" "github.com/apache/camel-k/pkg/util/digest" - "github.com/apache/camel-k/pkg/util/kubernetes" "github.com/apache/camel-k/pkg/util/log" "github.com/apache/camel-k/pkg/util/monitoring" ) @@ -239,25 +236,6 @@ func add(mgr manager.Manager, r reconcile.Reconciler, cl client.Client) error { return err } - // Check the ServiceBinding CRD is present - if ok, err := kubernetes.IsAPIResourceInstalled(cl, sb.GroupVersion.String(), sb.GroupVersionKind.Kind); err != nil { - return err - } else if !ok { - log.Info("Service binding is disabled, install the Service Binding Operator if needed") - } else if ok, err := kubernetes.CheckPermission(context.TODO(), cl, sb.GroupVersion.Group, sb.GroupVersionResource.Resource, platform.GetOperatorWatchNamespace(), "", "create"); err != nil { - return err - } else if !ok { - log.Info("Service binding is disabled, the operator is not granted permission to create ServiceBindings!") - } else { - // Watch ServiceBindings and enqueue owning Integrations - 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/trait/service_binding.go b/pkg/trait/service_binding.go index 3a5db8a..30fb969 100644 --- a/pkg/trait/service_binding.go +++ b/pkg/trait/service_binding.go @@ -18,24 +18,19 @@ limitations under the License. package trait import ( - "fmt" - + "github.com/apache/camel-k/pkg/util/reference" corev1 "k8s.io/api/core/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/dynamic" - ctrl "sigs.k8s.io/controller-runtime/pkg/client" - - sb "github.com/redhat-developer/service-binding-operator/api/v1alpha1" + sb "github.com/redhat-developer/service-binding-operator/apis/binding/v1alpha1" "github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline" - "github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/builder" "github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/context" "github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/handler/collect" "github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/handler/mapping" "github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/handler/naming" v1 "github.com/apache/camel-k/pkg/apis/camel/v1" - "github.com/apache/camel-k/pkg/util/reference" ) // The Service Binding trait allows users to connect to Services in Kubernetes: @@ -63,166 +58,56 @@ func (t *serviceBindingTrait) Configure(e *Environment) (bool, error) { return false, nil } - return e.IntegrationInPhase(v1.IntegrationPhaseInitialization, v1.IntegrationPhaseWaitingForBindings) || - e.IntegrationInRunningPhases(), nil + return e.IntegrationInPhase( + v1.IntegrationPhaseInitialization, + v1.IntegrationPhaseWaitingForBindings, + v1.IntegrationPhaseDeploying, + v1.IntegrationPhaseRunning, + ), nil } func (t *serviceBindingTrait) Apply(e *Environment) error { - services, err := t.parseServices(e) + ctx, err := t.getContext(e) if err != nil { return err } - - serviceBindingCrd := []sb.ServiceBinding{} - - for _, name := range services { - serviceBinding := createServiceBinding(e, services, e.Integration.Name) - append(serviceBindingCrd, serviceBinding) - } - - var camelKFlow = []pipeline.Handler{ - pipeline.HandlerFunc(collect.PreFlight), - pipeline.HandlerFunc(collect.ProvisionedService), - pipeline.HandlerFunc(collect.BindingDefinitions), - pipeline.HandlerFunc(collect.BindingItems), - pipeline.HandlerFunc(collect.OwnedResources), - pipeline.HandlerFunc(mapping.Handle), - pipeline.HandlerFunc(naming.Handle), + // let the retry policy be controlled by Camel-k + err = process(ctx, getHandlers()) + if err != nil { + return err } - p := builder.Builder().WithHandlers(camelKFlow...).WithContextProvider(context.Provider(e.Client, context.ResourceLookup(e.Client.RESTMapper()))).Build() - - p.Process(serviceBindingCrd) // construct Secret - name, secretExist := i.bindingSecretName() - data := i.bindingItemMap() - if len(data) == 0 { - return "", nil - } - secret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: i.bindingMeta.Namespace, - Name: name, - }, - StringData: data, - } - - if e.IntegrationInPhase(v1.IntegrationPhaseInitialization) { - serviceBindingsCollectionReady := true - for _, name := range serviceBindings { - isIntSB := name == e.Integration.Name - 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, e.Integration.Name) - 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.IntegrationPhaseWaitingForBindings - return nil - }) - } - return nil - } else if e.IntegrationInPhase(v1.IntegrationPhaseWaitingForBindings) { - 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 - } - if name == e.Integration.Name { - request := createServiceBinding(e, services, name) - e.Resources.Add(&request) - } - } - } else if e.IntegrationInRunningPhases() { - 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.IntegrationPhaseWaitingForBindings - return nil - }) - return nil - } - e.ServiceBindings[name] = sb.Status.Secret - if name == e.Integration.Name { - request := createServiceBinding(e, services, name) - e.Resources.Add(&request) - } - } + secret := getSecret(ctx, e.Integration.Namespace) + if secret != nil { + e.Resources.Add(secret) e.ApplicationProperties["quarkus.kubernetes-service-binding.enabled"] = "true" e.ApplicationProperties["SERVICE_BINDING_ROOT"] = serviceBindingsMountPath + e.ServiceBindings = make(map[string]string) + e.ServiceBindings[e.Integration.Name] = secret.GetName() } return nil } -func (i *impl) Process(binding interface{}) (bool, error) { - ctx, err := i.ctxProvider.Get(binding) +func (t *serviceBindingTrait) getContext(e *Environment) (pipeline.Context, error) { + services, err := t.parseServices(e.Integration.Namespace) if err != nil { - return false, err - } - var status pipeline.FlowStatus - for _, h := range i.handlers { - h.Handle(ctx) - status = ctx.FlowStatus() - if status.Stop { - break - } + return nil, err } - - return status.Retry, status.Err -} - -func setCollectionReady(e *Environment, serviceBinding string, status corev1.ConditionStatus) { - e.Integration.Status.SetCondition( - v1.IntegrationConditionServiceBindingsCollectionReady, - 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 == metav1.ConditionTrue && sb.Status.Secret != "" - } + serviceBinding := createServiceBinding(e, services, e.Integration.Name) + dyn, err := dynamic.NewForConfig(e.Client.GetConfig()) + if err != nil { + return nil, err } - return false -} - -func (t *serviceBindingTrait) getServiceBinding(e *Environment, name string) (sb.ServiceBinding, error) { - serviceBinding := sb.ServiceBinding{} - key := ctrl.ObjectKey{ - Namespace: e.Integration.Namespace, - Name: name, + ctxProvider := context.Provider(dyn, context.ResourceLookup(e.Client.RESTMapper())) + ctx, err := ctxProvider.Get(serviceBinding) + if err != nil { + return nil, err } - return serviceBinding, t.Client.Get(e.Ctx, key, &serviceBinding) + return ctx, nil } -func (t *serviceBindingTrait) parseServices(e *Environment) ([]sb.Service, error) { +func (t *serviceBindingTrait) parseServices(ns string) ([]sb.Service, error) { services := make([]sb.Service, 0) converter := reference.NewConverter("") for _, s := range t.Services { @@ -230,7 +115,7 @@ func (t *serviceBindingTrait) parseServices(e *Environment) ([]sb.Service, error if err != nil { return services, err } - namespace := e.Integration.Namespace + namespace := ns if ref.Namespace != "" { namespace = ref.Namespace } @@ -250,7 +135,20 @@ func (t *serviceBindingTrait) parseServices(e *Environment) ([]sb.Service, error return services, nil } -func createServiceBinding(e *Environment, services []sb.Service, name string) sb.ServiceBinding { +func process(ctx pipeline.Context, handlers []pipeline.Handler) error { + var status pipeline.FlowStatus + for _, h := range handlers { + h.Handle(ctx) + status = ctx.FlowStatus() + if status.Stop { + break + } + } + + return status.Err +} + +func createServiceBinding(e *Environment, services []sb.Service, name string) *sb.ServiceBinding { spec := sb.ServiceBindingSpec{ NamingStrategy: "none", Services: services, @@ -258,7 +156,7 @@ func createServiceBinding(e *Environment, services []sb.Service, name string) sb labels := map[string]string{ v1.IntegrationLabel: e.Integration.Name, } - serviceBinding := sb.ServiceBinding{ + return &sb.ServiceBinding{ TypeMeta: metav1.TypeMeta{ Kind: "ServiceBinding", APIVersion: "binding.operators.coreos.com/v1alpha1", @@ -270,5 +168,36 @@ func createServiceBinding(e *Environment, services []sb.Service, name string) sb }, Spec: spec, } - return serviceBinding -} \ No newline at end of file +} + +func getHandlers() []pipeline.Handler { + return []pipeline.Handler{ + pipeline.HandlerFunc(collect.PreFlight), + pipeline.HandlerFunc(collect.ProvisionedService), + pipeline.HandlerFunc(collect.BindingDefinitions), + pipeline.HandlerFunc(collect.BindingItems), + pipeline.HandlerFunc(collect.OwnedResources), + pipeline.HandlerFunc(mapping.Handle), + pipeline.HandlerFunc(naming.Handle), + } +} + +func getSecret(ctx pipeline.Context, ns string) *corev1.Secret { + name := ctx.BindingSecretName() + items := ctx.BindingItems() + data := items.AsMap() + if len(data) == 0 { + return nil + } + return &corev1.Secret{ + TypeMeta: metav1.TypeMeta{ + Kind: "Secret", + APIVersion: corev1.SchemeGroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns, + Name: name, + }, + StringData: data, + } +} diff --git a/pkg/trait/trait_configure_test.go b/pkg/trait/trait_configure_test.go index 34b9e3f..e92c498 100644 --- a/pkg/trait/trait_configure_test.go +++ b/pkg/trait/trait_configure_test.go @@ -134,8 +134,8 @@ func TestTraitListConfigurationFromAnnotations(t *testing.T) { Integration: &v1.Integration{ ObjectMeta: metav1.ObjectMeta{ Annotations: map[string]string{ - "trait.camel.apache.org/jolokia.options": `["opt1", "opt2"]`, - "trait.camel.apache.org/service-binding.service-bindings": `Binding:xxx`, // lenient + "trait.camel.apache.org/jolokia.options": `["opt1", "opt2"]`, + "trait.camel.apache.org/service-binding.services": `Binding:xxx`, // lenient }, }, Spec: v1.IntegrationSpec{ @@ -146,7 +146,7 @@ func TestTraitListConfigurationFromAnnotations(t *testing.T) { c := NewCatalog(nil) assert.NoError(t, c.configure(&env)) assert.Equal(t, []string{"opt1", "opt2"}, c.GetTrait("jolokia").(*jolokiaTrait).Options) - assert.Equal(t, []string{"Binding:xxx"}, c.GetTrait("service-binding").(*serviceBindingTrait).ServiceBindings) + assert.Equal(t, []string{"Binding:xxx"}, c.GetTrait("service-binding").(*serviceBindingTrait).Services) } func TestTraitSplitConfiguration(t *testing.T) { diff --git a/resources/traits.yaml b/resources/traits.yaml index cc0d88b..c422f64 100755 --- a/resources/traits.yaml +++ b/resources/traits.yaml @@ -918,17 +918,17 @@ traits: - Kubernetes - Knative - OpenShift - description: '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' + description: 'The Service Binding trait allows users to connect to Services in Kubernetes: + https://github.com/k8s-service-bindings/spec#service-binding As the specification + is still evolving this is subject to change' properties: - name: enabled type: bool description: Can be used to enable or disable a trait. All traits share this common property. - - name: service-bindings + - name: services type: '[]string' - description: List of Provisioned Services and ServiceBindings in the form [[apigroup/]version:]kind:[namespace/]name + description: List of Services in the form [[apigroup/]version:]kind:[namespace/]name - name: service platform: false profiles: