diff --git a/pkg/cmd/operator/operator.go b/pkg/cmd/operator/operator.go index 2280b75e45..9c1d3eba33 100644 --- a/pkg/cmd/operator/operator.go +++ b/pkg/cmd/operator/operator.go @@ -258,6 +258,7 @@ func findOrCreateIntegrationPlatform(ctx context.Context, c client.Client, opera if defaultPlatform.Labels == nil { defaultPlatform.Labels = make(map[string]string) } + defaultPlatform.Labels["app"] = "camel-k" defaultPlatform.Labels["camel.apache.org/platform.generated"] = "true" if operatorID != "" { diff --git a/pkg/trait/platform.go b/pkg/trait/platform.go index b6ed793cdf..75ea89fea7 100644 --- a/pkg/trait/platform.go +++ b/pkg/trait/platform.go @@ -132,6 +132,7 @@ func (t *platformTrait) getOrCreatePlatform(e *Environment) (*v1.IntegrationPlat if defaultPlatform.Labels == nil { defaultPlatform.Labels = make(map[string]string) } + defaultPlatform.Labels["app"] = "camel-k" defaultPlatform.Labels["camel.apache.org/platform.generated"] = True // Cascade the operator id in charge to reconcile the Integration if v1.GetOperatorIDAnnotation(e.Integration) != "" { diff --git a/pkg/trait/platform_test.go b/pkg/trait/platform_test.go index 488cbb7392..67ab402640 100644 --- a/pkg/trait/platform_test.go +++ b/pkg/trait/platform_test.go @@ -109,7 +109,7 @@ func TestPlatformTraitCreatesDefaultPlatform(t *testing.T) { assert.Equal(t, v1.IntegrationPhaseWaitingForPlatform, e.Integration.Status.Phase) assert.Equal(t, 1, len(e.Resources.Items())) defPlatform := v1.NewIntegrationPlatform("ns1", platform.DefaultPlatformName) - defPlatform.Labels = map[string]string{"camel.apache.org/platform.generated": True} + defPlatform.Labels = map[string]string{"app": "camel-k", "camel.apache.org/platform.generated": True} assert.Contains(t, e.Resources.Items(), &defPlatform) } diff --git a/pkg/util/bindings/knative_ref.go b/pkg/util/bindings/knative_ref.go index a7ba2accdb..5382c69d67 100644 --- a/pkg/util/bindings/knative_ref.go +++ b/pkg/util/bindings/knative_ref.go @@ -26,6 +26,8 @@ import ( "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" "github.com/apache/camel-k/pkg/util/knative" "github.com/apache/camel-k/pkg/util/uri" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime/schema" ) // KnativeRefBindingProvider converts a reference to a Kubernetes object into a Camel URI. @@ -42,6 +44,17 @@ func (k KnativeRefBindingProvider) Translate(ctx BindingContext, endpointCtx End return nil, nil } + if ok, err := isKnownKnativeResource(e.Ref); !ok { + // only operates on known Knative endpoint resources (e.g. channels, brokers) + return nil, err + } + + if knativeInstalled, _ := knative.IsInstalled(ctx.Client); !knativeInstalled { + // works only when Knative is installed + return nil, fmt.Errorf("integration referencing Knative endpoint '%s' that cannot run, "+ + "because Knative is not installed on the cluster", e.Ref.Name) + } + serviceType, err := knative.GetServiceType(*e.Ref) if err != nil { return nil, err @@ -93,6 +106,21 @@ func (k KnativeRefBindingProvider) Translate(ctx BindingContext, endpointCtx End }, nil } +func isKnownKnativeResource(ref *corev1.ObjectReference) (bool, error) { + gv, err := schema.ParseGroupVersion(ref.APIVersion) + if err != nil { + return false, err + } + + for _, endpoint := range knative.KnownEndpointKinds { + if endpoint.Group == gv.Group && endpoint.Kind == ref.Kind { + return true, nil + } + } + + return false, nil +} + func (k KnativeRefBindingProvider) Order() int { // Executes as last, as it can be used as fallback for all unknown object references return OrderLast diff --git a/pkg/util/bindings/knative_ref_test.go b/pkg/util/bindings/knative_ref_test.go new file mode 100644 index 0000000000..1933cf5f6d --- /dev/null +++ b/pkg/util/bindings/knative_ref_test.go @@ -0,0 +1,156 @@ +/* +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 bindings + +import ( + "context" + "fmt" + "testing" + + "github.com/apache/camel-k/pkg/util/test" + "github.com/stretchr/testify/assert" + v1 "k8s.io/api/core/v1" + + camelv1 "github.com/apache/camel-k/pkg/apis/camel/v1" + "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" +) + +func TestKnativeRefBinding(t *testing.T) { + testcases := []struct { + endpoint v1alpha1.Endpoint + uri string + }{ + { + endpoint: v1alpha1.Endpoint{ + Ref: &v1.ObjectReference{ + Kind: "Broker", + Name: "default", + APIVersion: "eventing.knative.dev/v1", + }, + }, + uri: "knative:event?apiVersion=eventing.knative.dev%2Fv1&kind=Broker&name=default", + }, + { + endpoint: v1alpha1.Endpoint{ + Ref: &v1.ObjectReference{ + Kind: "Channel", + Name: "mychannel", + APIVersion: "messaging.knative.dev/v1", + }, + }, + uri: "knative:channel/mychannel?apiVersion=messaging.knative.dev%2Fv1&kind=Channel", + }, + { + endpoint: v1alpha1.Endpoint{ + Ref: &v1.ObjectReference{ + Kind: "Service", + Name: "myservice", + APIVersion: "serving.knative.dev/v1", + }, + }, + uri: "knative:endpoint/myservice?apiVersion=serving.knative.dev%2Fv1&kind=Service", + }, + } + + for i, tc := range testcases { + t.Run(fmt.Sprintf("test-%d-%s", i, tc.endpoint.Ref.Kind), func(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + client, err := test.NewFakeClient() + assert.NoError(t, err) + + bindingContext := BindingContext{ + Ctx: ctx, + Client: client, + Namespace: "test", + Profile: camelv1.TraitProfileKnative, + } + + binding, err := KnativeRefBindingProvider{}.Translate(bindingContext, EndpointContext{ + Type: v1alpha1.EndpointTypeSink, + }, tc.endpoint) + assert.NoError(t, err) + assert.NotNil(t, binding) + assert.Equal(t, tc.uri, binding.URI) + assert.Equal(t, camelv1.Traits{}, binding.Traits) + }) + } +} + +func TestUnsupportedKnativeResource(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + client, err := test.NewFakeClient() + assert.NoError(t, err) + + bindingContext := BindingContext{ + Ctx: ctx, + Client: client, + Namespace: "test", + Profile: camelv1.TraitProfileKnative, + } + + endpoint := v1alpha1.Endpoint{ + Ref: &v1.ObjectReference{ + Kind: "Unknown", + Name: "default", + APIVersion: "eventing.knative.dev/v1", + }, + } + + binding, err := KnativeRefBindingProvider{}.Translate(bindingContext, EndpointContext{ + Type: v1alpha1.EndpointTypeSink, + }, endpoint) + assert.NoError(t, err) + assert.Nil(t, binding) +} + +func TestKnativeNotInstalled(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + client, err := test.NewFakeClient() + assert.NoError(t, err) + + // disable the knative service api + fakeClient := client.(*test.FakeClient) //nolint + fakeClient.DisableAPIGroupDiscovery("serving.knative.dev/v1") + + bindingContext := BindingContext{ + Ctx: ctx, + Client: client, + Namespace: "test", + Profile: camelv1.TraitProfileKnative, + } + + endpoint := v1alpha1.Endpoint{ + Ref: &v1.ObjectReference{ + Kind: "Broker", + Name: "default", + APIVersion: "eventing.knative.dev/v1", + }, + } + + binding, err := KnativeRefBindingProvider{}.Translate(bindingContext, EndpointContext{ + Type: v1alpha1.EndpointTypeSink, + }, endpoint) + assert.Error(t, err, "integration referencing Knative endpoint 'default' that cannot run, because Knative is not installed on the cluster") + assert.Nil(t, binding) +}