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 2019/10/01 13:53:47 UTC

[camel-k] 04/08: Fix #952: add Knative 0.8.0 compatibility hack

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 dcff4af821f01b3e37817d58c7bde167ec619a2b
Author: nferraro <ni...@gmail.com>
AuthorDate: Thu Sep 26 16:05:52 2019 +0200

    Fix #952: add Knative 0.8.0 compatibility hack
---
 e2e/test_support.go                                |  4 +-
 ...toscheme_knative_eventing_08_compat_v1alpha1.go | 43 ++++++++++++++++++++++
 pkg/apis/knative08compat/knative08compat.go        | 22 +++++++++++
 pkg/trait/istio_test.go                            |  5 +++
 pkg/trait/knative.go                               | 37 ++++++++++++++++++-
 pkg/trait/knative_service_test.go                  |  6 +++
 pkg/util/knative/knative.go                        | 38 ++++++++++++++-----
 pkg/util/kubernetes/errors.go                      |  9 +++++
 8 files changed, 150 insertions(+), 14 deletions(-)

diff --git a/e2e/test_support.go b/e2e/test_support.go
index fd0b1b0..04a5203 100644
--- a/e2e/test_support.go
+++ b/e2e/test_support.go
@@ -39,7 +39,6 @@ import (
 	"github.com/apache/camel-k/pkg/util/log"
 	"github.com/apache/camel-k/pkg/util/openshift"
 	"github.com/google/uuid"
-	messaging "knative.dev/eventing/pkg/apis/messaging/v1alpha1"
 	"github.com/onsi/gomega"
 	projectv1 "github.com/openshift/api/project/v1"
 	"github.com/spf13/cobra"
@@ -49,6 +48,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/labels"
 	"k8s.io/apimachinery/pkg/runtime"
+	messaging "knative.dev/eventing/pkg/apis/messaging/v1alpha1"
 	k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
 )
 
@@ -498,7 +498,7 @@ func createKnativeChannel(ns string, name string) func() error {
 	return func() error {
 		channel := messaging.InMemoryChannel{
 			TypeMeta: metav1.TypeMeta{
-				Kind:       "Channel",
+				Kind:       "InMemoryChannel",
 				APIVersion: messaging.SchemeGroupVersion.String(),
 			},
 			ObjectMeta: metav1.ObjectMeta{
diff --git a/pkg/apis/addtoscheme_knative_eventing_08_compat_v1alpha1.go b/pkg/apis/addtoscheme_knative_eventing_08_compat_v1alpha1.go
new file mode 100644
index 0000000..51734f4
--- /dev/null
+++ b/pkg/apis/addtoscheme_knative_eventing_08_compat_v1alpha1.go
@@ -0,0 +1,43 @@
+/*
+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/apache/camel-k/pkg/apis/knative08compat"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+)
+
+var (
+	compat08SchemeBuilder = runtime.NewSchemeBuilder(eventing08CompatKnownTypes)
+	compat08AddToScheme   = compat08SchemeBuilder.AddToScheme
+)
+
+func init() {
+	AddToSchemes = append(AddToSchemes, compat08AddToScheme)
+}
+
+// eventing08CompatKnownTypes Adds the list of known types to Scheme.
+func eventing08CompatKnownTypes(scheme *runtime.Scheme) error {
+	scheme.AddKnownTypes(knative08compat.CompatSchemeGroupVersion,
+		&knative08compat.Subscription{},
+		&knative08compat.SubscriptionList{},
+	)
+	metav1.AddToGroupVersion(scheme, knative08compat.CompatSchemeGroupVersion)
+	return nil
+}
diff --git a/pkg/apis/knative08compat/knative08compat.go b/pkg/apis/knative08compat/knative08compat.go
new file mode 100644
index 0000000..7939754
--- /dev/null
+++ b/pkg/apis/knative08compat/knative08compat.go
@@ -0,0 +1,22 @@
+package knative08compat
+
+import (
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	messaging "knative.dev/eventing/pkg/apis/messaging/v1alpha1"
+)
+
+// CompatSchemeGroupVersion is the old group version used in Knative 0.8
+var CompatSchemeGroupVersion = schema.GroupVersion{
+	Group:   "eventing.knative.dev",
+	Version: "v1alpha1",
+}
+
+// Subscription is a Knative 0.8 compatibility version for messaging.Subscription
+type Subscription struct {
+	messaging.Subscription
+}
+
+// SubscriptionList is a Knative 0.8 compatibility version for messaging.SubscriptionList
+type SubscriptionList struct {
+	messaging.SubscriptionList
+}
diff --git a/pkg/trait/istio_test.go b/pkg/trait/istio_test.go
index 7f804e4..cd5830f 100644
--- a/pkg/trait/istio_test.go
+++ b/pkg/trait/istio_test.go
@@ -49,6 +49,11 @@ func NewIstioTestEnv(t *testing.T, d *appsv1.Deployment, s *serving.Service, ena
 					"istio": {
 						Configuration: make(map[string]string),
 					},
+					"knative": {
+						Configuration: map[string]string{
+							"knative-08-compat-mode": "false", // disable it so it does not check resources in the cluster
+						},
+					},
 				},
 			},
 		},
diff --git a/pkg/trait/knative.go b/pkg/trait/knative.go
index 14705ad..f64929a 100644
--- a/pkg/trait/knative.go
+++ b/pkg/trait/knative.go
@@ -25,6 +25,7 @@ import (
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 	"github.com/apache/camel-k/pkg/metadata"
 	"github.com/apache/camel-k/pkg/util/envvar"
+	"github.com/apache/camel-k/pkg/util/kubernetes"
 	"github.com/pkg/errors"
 	"github.com/scylladb/go-set/strset"
 	k8serrors "k8s.io/apimachinery/pkg/api/errors"
@@ -32,6 +33,9 @@ import (
 
 	knativeapi "github.com/apache/camel-k/pkg/apis/camel/v1alpha1/knative"
 	knativeutil "github.com/apache/camel-k/pkg/util/knative"
+	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	messaging "knative.dev/eventing/pkg/apis/messaging/v1alpha1"
+	kubeclient "sigs.k8s.io/controller-runtime/pkg/client"
 )
 
 type knativeTrait struct {
@@ -44,6 +48,7 @@ type knativeTrait struct {
 	FilterSourceChannels *bool    `property:"filter-source-channels"`
 	ChannelAPIs          []string `property:"channel-apis"`
 	EndpointAPIs         []string `property:"endpoint-apis"`
+	Knative08CompatMode  *bool    `property:"knative-08-compat-mode"`
 	Auto                 *bool    `property:"auto"`
 }
 
@@ -147,6 +152,14 @@ func (t *knativeTrait) Configure(e *Environment) (bool, error) {
 			filter := true
 			t.FilterSourceChannels = &filter
 		}
+
+		if t.Knative08CompatMode == nil {
+			compat, err := t.shouldUseKnative08CompatMode(e.Integration.Namespace)
+			if err != nil {
+				return false, err
+			}
+			t.Knative08CompatMode = &compat
+		}
 	}
 
 	return true, nil
@@ -194,13 +207,16 @@ func (t *knativeTrait) createSubscriptions(e *Environment) error {
 	if err != nil {
 		return err
 	}
+
+	compat := t.Knative08CompatMode != nil && *t.Knative08CompatMode
+
 	for _, ch := range channels {
 		chRef, err := knativeutil.GetAddressableReference(t.ctx, t.client, types, e.Integration.Namespace, ch)
 		if err != nil {
 			return err
 		}
-		sub := knativeutil.CreateSubscription(*chRef, e.Integration.Name)
-		e.Resources.Add(&sub)
+		sub := knativeutil.CreateSubscription(*chRef, e.Integration.Name, compat)
+		e.Resources.Add(sub)
 	}
 
 	return nil
@@ -347,6 +363,23 @@ func (t *knativeTrait) extractNames(names string) []string {
 	return answer
 }
 
+func (t *knativeTrait) shouldUseKnative08CompatMode(namespace string) (bool, error) {
+	lst := messaging.SubscriptionList{
+		TypeMeta: v1.TypeMeta{
+			Kind:       "Subscription",
+			APIVersion: messaging.SchemeGroupVersion.String(),
+		},
+	}
+	opts := kubeclient.ListOptions{
+		Namespace: namespace,
+	}
+	err := t.client.List(t.ctx, &opts, &lst)
+	if err != nil && kubernetes.IsUnknownAPIError(err) {
+		return true, nil
+	}
+	return false, err
+}
+
 func decodeKindAPIGroupVersions(specs []string) ([]schema.GroupVersionKind, error) {
 	lst := make([]schema.GroupVersionKind, 0, len(specs))
 	for _, spec := range specs {
diff --git a/pkg/trait/knative_service_test.go b/pkg/trait/knative_service_test.go
index 04a21c4..0af56d9 100644
--- a/pkg/trait/knative_service_test.go
+++ b/pkg/trait/knative_service_test.go
@@ -45,6 +45,9 @@ func TestKnativeService(t *testing.T) {
 	assert.Nil(t, err)
 
 	traitCatalog := NewCatalog(context.TODO(), nil)
+	knativeTrait := traitCatalog.GetTrait("knative").(*knativeTrait)
+	falze := false
+	knativeTrait.Knative08CompatMode = &falze
 
 	environment := Environment{
 		CamelCatalog: catalog,
@@ -184,6 +187,9 @@ func TestKnativeServiceWithCustomContainerName(t *testing.T) {
 	assert.Nil(t, err)
 
 	traitCatalog := NewCatalog(context.TODO(), nil)
+	knativeTrait := traitCatalog.GetTrait("knative").(*knativeTrait)
+	falze := false
+	knativeTrait.Knative08CompatMode = &falze
 
 	environment := Environment{
 		CamelCatalog: catalog,
diff --git a/pkg/util/knative/knative.go b/pkg/util/knative/knative.go
index 2653701..874c108 100644
--- a/pkg/util/knative/knative.go
+++ b/pkg/util/knative/knative.go
@@ -20,13 +20,16 @@ package knative
 import (
 	"context"
 	"fmt"
-	"k8s.io/apimachinery/pkg/runtime/schema"
 	"net/url"
 
+	"github.com/apache/camel-k/pkg/apis/knative08compat"
 	"github.com/apache/camel-k/pkg/client"
+	kubernetesutils "github.com/apache/camel-k/pkg/util/kubernetes"
 	"github.com/apache/camel-k/pkg/util/log"
 	k8serrors "k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/runtime/schema"
 	"k8s.io/client-go/kubernetes"
 	controller "sigs.k8s.io/controller-runtime/pkg/client"
 	k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
@@ -68,10 +71,14 @@ func IsInstalled(ctx context.Context, c kubernetes.Interface) (bool, error) {
 }
 
 // CreateSubscription ---
-func CreateSubscription(channelReference corev1.ObjectReference, serviceName string) messaging.Subscription {
-	return messaging.Subscription{
+func CreateSubscription(channelReference corev1.ObjectReference, serviceName string, compat08 bool) runtime.Object {
+	apiVersion := messaging.SchemeGroupVersion.String()
+	if compat08 {
+		apiVersion = knative08compat.CompatSchemeGroupVersion.String()
+	}
+	subs := messaging.Subscription{
 		TypeMeta: metav1.TypeMeta{
-			APIVersion: messaging.SchemeGroupVersion.String(),
+			APIVersion: apiVersion,
 			Kind:       "Subscription",
 		},
 		ObjectMeta: metav1.ObjectMeta{
@@ -93,21 +100,30 @@ func CreateSubscription(channelReference corev1.ObjectReference, serviceName str
 			},
 		},
 	}
+
+	if compat08 {
+		return &knative08compat.Subscription{
+			Subscription: subs,
+		}
+	}
+	return &subs
 }
 
 // GetAnySinkURL looks up the resource among all given types and returns the resource sink URL if present
 func GetAnySinkURL(ctx context.Context, c client.Client, types []schema.GroupVersionKind, namespace string, name string) (*url.URL, error) {
 	for _, gvk := range types {
 		sink := corev1.ObjectReference{
-			Kind: gvk.Kind,
+			Kind:       gvk.Kind,
 			APIVersion: gvk.GroupVersion().String(),
-			Namespace: namespace,
-			Name: name,
+			Namespace:  namespace,
+			Name:       name,
 		}
 
 		res, err := GetSinkURI(ctx, c, &sink, namespace)
 		if err != nil && k8serrors.IsNotFound(err) {
 			continue
+		} else if err != nil && kubernetesutils.IsUnknownAPIError(err) {
+			continue
 		} else if err != nil {
 			return nil, err
 		}
@@ -120,15 +136,17 @@ func GetAnySinkURL(ctx context.Context, c client.Client, types []schema.GroupVer
 func GetAddressableReference(ctx context.Context, c client.Client, types []schema.GroupVersionKind, namespace string, name string) (*corev1.ObjectReference, error) {
 	for _, gvk := range types {
 		sink := corev1.ObjectReference{
-			Kind: gvk.Kind,
+			Kind:       gvk.Kind,
 			APIVersion: gvk.GroupVersion().String(),
-			Namespace: namespace,
-			Name: name,
+			Namespace:  namespace,
+			Name:       name,
 		}
 
 		_, err := GetSinkURI(ctx, c, &sink, namespace)
 		if err != nil && k8serrors.IsNotFound(err) {
 			continue
+		} else if err != nil && kubernetesutils.IsUnknownAPIError(err) {
+			continue
 		} else if err != nil {
 			return nil, err
 		}
diff --git a/pkg/util/kubernetes/errors.go b/pkg/util/kubernetes/errors.go
new file mode 100644
index 0000000..4d8f194
--- /dev/null
+++ b/pkg/util/kubernetes/errors.go
@@ -0,0 +1,9 @@
+package kubernetes
+
+import "strings"
+
+// IsUnknownAPIError checks if the given error is due to some missing APIs in the cluster.
+// Apparently there's no such method in Kubernetes Go API.
+func IsUnknownAPIError(err error) bool {
+	return err != nil && strings.HasPrefix(err.Error(), "no matches for kind")
+}