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/12/13 08:22:49 UTC

[camel-k] 01/02: Fix #1125: use all known knative types to check if it's enabled

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 e290a1d4185cec7fde0aadf2753b203c10b70604
Author: Nicola Ferraro <ni...@gmail.com>
AuthorDate: Tue Dec 10 11:08:36 2019 +0100

    Fix #1125: use all known knative types to check if it's enabled
---
 .../integrationplatform/initialize_test.go         |  4 +
 pkg/platform/platform.go                           |  3 +-
 pkg/util/knative/apis.go                           | 99 ++++++++++++++--------
 pkg/util/knative/enabled.go                        | 93 ++++++++++++++++++++
 pkg/util/knative/knative.go                        | 37 +-------
 5 files changed, 168 insertions(+), 68 deletions(-)

diff --git a/pkg/controller/integrationplatform/initialize_test.go b/pkg/controller/integrationplatform/initialize_test.go
index 53681e2..9f7a047 100644
--- a/pkg/controller/integrationplatform/initialize_test.go
+++ b/pkg/controller/integrationplatform/initialize_test.go
@@ -39,6 +39,7 @@ func TestTimeouts_Default(t *testing.T) {
 	ip.Namespace = "ns"
 	ip.Name = xid.New().String()
 	ip.Spec.Cluster = v1alpha1.IntegrationPlatformClusterOpenShift
+	ip.Spec.Profile = v1alpha1.TraitProfileOpenShift
 
 	c, err := test.NewFakeClient(&ip)
 	assert.Nil(t, err)
@@ -65,6 +66,7 @@ func TestTimeouts_MavenComputedFromBuild(t *testing.T) {
 	ip.Namespace = "ns"
 	ip.Name = xid.New().String()
 	ip.Spec.Cluster = v1alpha1.IntegrationPlatformClusterOpenShift
+	ip.Spec.Profile = v1alpha1.TraitProfileOpenShift
 
 	timeout, err := time.ParseDuration("1m1ms")
 	assert.Nil(t, err)
@@ -98,6 +100,7 @@ func TestTimeouts_Truncated(t *testing.T) {
 	ip.Namespace = "ns"
 	ip.Name = xid.New().String()
 	ip.Spec.Cluster = v1alpha1.IntegrationPlatformClusterOpenShift
+	ip.Spec.Profile = v1alpha1.TraitProfileOpenShift
 
 	bt, err := time.ParseDuration("5m1ms")
 	assert.Nil(t, err)
@@ -135,6 +138,7 @@ func TestDefaultMavenSettingsApplied(t *testing.T) {
 	ip.Namespace = "ns"
 	ip.Name = "test-platform"
 	ip.Spec.Cluster = v1alpha1.IntegrationPlatformClusterOpenShift
+	ip.Spec.Profile = v1alpha1.TraitProfileOpenShift
 
 	c, err := test.NewFakeClient(&ip)
 	assert.Nil(t, err)
diff --git a/pkg/platform/platform.go b/pkg/platform/platform.go
index bcd92c7..5ecae34 100644
--- a/pkg/platform/platform.go
+++ b/pkg/platform/platform.go
@@ -21,6 +21,7 @@ import (
 	"context"
 
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+	"github.com/apache/camel-k/pkg/client"
 	"github.com/apache/camel-k/pkg/util/knative"
 	"github.com/apache/camel-k/pkg/util/kubernetes"
 	k8serrors "k8s.io/apimachinery/pkg/api/errors"
@@ -98,7 +99,7 @@ func IsActive(p *v1alpha1.IntegrationPlatform) bool {
 }
 
 // DetermineBestProfile tries to detect the best trait profile for the platform
-func DetermineBestProfile(ctx context.Context, c k8sclient.Reader, p *v1alpha1.IntegrationPlatform) v1alpha1.TraitProfile {
+func DetermineBestProfile(ctx context.Context, c client.Client, p *v1alpha1.IntegrationPlatform) v1alpha1.TraitProfile {
 	if p.Status.Profile != "" {
 		return p.Status.Profile
 	}
diff --git a/pkg/util/knative/apis.go b/pkg/util/knative/apis.go
index 43708bc..ccb385b 100644
--- a/pkg/util/knative/apis.go
+++ b/pkg/util/knative/apis.go
@@ -26,63 +26,96 @@ import (
 
 var (
 	// KnownChannelKinds are known channel kinds belonging to Knative
-	KnownChannelKinds = []schema.GroupVersionKind{
+	KnownChannelKinds = []GroupVersionKindResource{
 		{
-			Kind:    "Channel",
-			Group:   "messaging.knative.dev",
-			Version: "v1alpha1",
+			GroupVersionKind: schema.GroupVersionKind{
+				Kind:    "Channel",
+				Group:   "messaging.knative.dev",
+				Version: "v1alpha1",
+			},
+			Resource: "channels",
 		},
 		{
-			Kind:    "Channel",
-			Group:   "eventing.knative.dev",
-			Version: "v1alpha1",
+			GroupVersionKind: schema.GroupVersionKind{
+				Kind:    "Channel",
+				Group:   "eventing.knative.dev",
+				Version: "v1alpha1",
+			},
+			Resource: "channels",
 		},
 		{
-			Kind:    "InMemoryChannel",
-			Group:   "messaging.knative.dev",
-			Version: "v1alpha1",
+			GroupVersionKind: schema.GroupVersionKind{
+				Kind:    "InMemoryChannel",
+				Group:   "messaging.knative.dev",
+				Version: "v1alpha1",
+			},
+			Resource: "inmemorychannels",
 		},
 		{
-			Kind:    "KafkaChannel",
-			Group:   "messaging.knative.dev",
-			Version: "v1alpha1",
+			GroupVersionKind: schema.GroupVersionKind{
+				Kind:    "KafkaChannel",
+				Group:   "messaging.knative.dev",
+				Version: "v1alpha1",
+			},
+			Resource: "kafkachannels",
 		},
 		{
-			Kind:    "NatssChannel",
-			Group:   "messaging.knative.dev",
-			Version: "v1alpha1",
+			GroupVersionKind: schema.GroupVersionKind{
+				Kind:    "NatssChannel",
+				Group:   "messaging.knative.dev",
+				Version: "v1alpha1",
+			},
+			Resource: "natsschannels",
 		},
 	}
 
 	// KnownEndpointKinds are known endpoint kinds belonging to Knative
-	KnownEndpointKinds = []schema.GroupVersionKind{
+	KnownEndpointKinds = []GroupVersionKindResource{
 		{
-			Kind:    "Service",
-			Group:   "serving.knative.dev",
-			Version: "v1",
+			GroupVersionKind: schema.GroupVersionKind{
+				Kind:    "Service",
+				Group:   "serving.knative.dev",
+				Version: "v1",
+			},
+			Resource: "services",
 		},
 		{
-			Kind:    "Service",
-			Group:   "serving.knative.dev",
-			Version: "v1beta1",
+			GroupVersionKind: schema.GroupVersionKind{
+				Kind:    "Service",
+				Group:   "serving.knative.dev",
+				Version: "v1beta1",
+			},
+			Resource: "services",
 		},
 		{
-			Kind:    "Service",
-			Group:   "serving.knative.dev",
-			Version: "v1alpha1",
+			GroupVersionKind: schema.GroupVersionKind{
+				Kind:    "Service",
+				Group:   "serving.knative.dev",
+				Version: "v1alpha1",
+			},
+			Resource: "services",
 		},
 	}
 
 	// KnownBrokerKinds are known broker kinds belonging to Knative
-	KnownBrokerKinds = []schema.GroupVersionKind{
+	KnownBrokerKinds = []GroupVersionKindResource{
 		{
-			Kind:    "Broker",
-			Group:   "eventing.knative.dev",
-			Version: "v1alpha1",
+			GroupVersionKind: schema.GroupVersionKind{
+				Kind:    "Broker",
+				Group:   "eventing.knative.dev",
+				Version: "v1alpha1",
+			},
+			Resource: "brokers",
 		},
 	}
 )
 
+// GroupVersionKindResource --
+type GroupVersionKindResource struct {
+	schema.GroupVersionKind
+	Resource string
+}
+
 func init() {
 	// Channels are also endpoints
 	KnownEndpointKinds = append(KnownEndpointKinds, KnownChannelKinds...)
@@ -107,7 +140,7 @@ func FillMissingReferenceData(serviceType knativev1.CamelServiceType, ref v1.Obj
 }
 
 // nolint: gocritic
-func fillMissingReferenceDataWith(serviceTypes []schema.GroupVersionKind, ref v1.ObjectReference) []v1.ObjectReference {
+func fillMissingReferenceDataWith(serviceTypes []GroupVersionKindResource, ref v1.ObjectReference) []v1.ObjectReference {
 	list := make([]v1.ObjectReference, 0)
 	if ref.APIVersion == "" && ref.Kind == "" {
 		for _, st := range serviceTypes {
@@ -134,7 +167,7 @@ func fillMissingReferenceDataWith(serviceTypes []schema.GroupVersionKind, ref v1
 	return list
 }
 
-func getGroupVersions(serviceTypes []schema.GroupVersionKind, kind string) []string {
+func getGroupVersions(serviceTypes []GroupVersionKindResource, kind string) []string {
 	res := make([]string, 0)
 	for _, st := range serviceTypes {
 		if st.Kind == kind {
@@ -144,7 +177,7 @@ func getGroupVersions(serviceTypes []schema.GroupVersionKind, kind string) []str
 	return res
 }
 
-func getKinds(serviceTypes []schema.GroupVersionKind, apiVersion string) []string {
+func getKinds(serviceTypes []GroupVersionKindResource, apiVersion string) []string {
 	res := make([]string, 0)
 	for _, st := range serviceTypes {
 		if st.GroupVersion().String() == apiVersion {
diff --git a/pkg/util/knative/enabled.go b/pkg/util/knative/enabled.go
new file mode 100644
index 0000000..b3099ec
--- /dev/null
+++ b/pkg/util/knative/enabled.go
@@ -0,0 +1,93 @@
+/*
+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 knative
+
+import (
+	"context"
+
+	"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"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	"k8s.io/client-go/dynamic"
+	"k8s.io/client-go/kubernetes"
+)
+
+// IsEnabledInNamespace returns true if we can list some basic knative objects in the given namespace.
+//
+// This method can be used at operator level to check if knative resources can be accessed.
+func IsEnabledInNamespace(ctx context.Context, c client.Client, namespace string) bool {
+	dyn, err := dynamic.NewForConfig(c.GetConfig())
+	if err != nil {
+		log.Infof("could not create dynamic client to check knative installation in namespace %s, got error: %v", namespace, err)
+		return false
+	}
+	for _, kgv := range KnownEndpointKinds {
+		_, err = dyn.Resource(schema.GroupVersionResource{
+			Group:    kgv.Group,
+			Version:  kgv.Version,
+			Resource: kgv.Resource,
+		}).Namespace(namespace).List(metav1.ListOptions{})
+
+		if err == nil {
+			return true
+		}
+	}
+
+	log.Infof("could not find any knative type in namespace %s, last error was: %v", namespace, err)
+	return false
+}
+
+// IsInstalled returns true if we are connected to a cluster with Knative installed
+//
+// This method should not be called from the operator, as it might require permissions that are not available.
+func IsInstalled(ctx context.Context, c kubernetes.Interface) (bool, error) {
+	// check some Knative APIs
+	for _, api := range getKnativeGroupVersions() {
+		if installed, err := isInstalled(c, api); err != nil {
+			return false, err
+		} else if installed {
+			return true, nil
+		}
+	}
+	return false, nil
+}
+
+func isInstalled(c kubernetes.Interface, api schema.GroupVersion) (bool, error) {
+	_, err := c.Discovery().ServerResourcesForGroupVersion(api.String())
+	if err != nil && (k8serrors.IsNotFound(err) || kubernetesutils.IsUnknownAPIError(err)) {
+		return false, nil
+	} else if err != nil {
+		return false, err
+	}
+	return true, nil
+}
+
+func getKnativeGroupVersions() []schema.GroupVersion {
+	apis := make(map[schema.GroupVersion]bool)
+	res := make([]schema.GroupVersion, 0)
+	for _, gvk := range KnownEndpointKinds {
+		if !apis[gvk.GroupVersion()] {
+			apis[gvk.GroupVersion()] = true
+			res = append(res, gvk.GroupVersion())
+		}
+	}
+	return res
+}
diff --git a/pkg/util/knative/knative.go b/pkg/util/knative/knative.go
index 003912b..ebbb761 100644
--- a/pkg/util/knative/knative.go
+++ b/pkg/util/knative/knative.go
@@ -24,52 +24,21 @@ import (
 
 	"github.com/apache/camel-k/pkg/client"
 	kubernetesutils "github.com/apache/camel-k/pkg/util/kubernetes"
-	"github.com/apache/camel-k/pkg/util/log"
+	corev1 "k8s.io/api/core/v1"
 	k8serrors "k8s.io/apimachinery/pkg/api/errors"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"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"
-
-	corev1 "k8s.io/api/core/v1"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	eventing "knative.dev/eventing/pkg/apis/eventing/v1alpha1"
 	messaging "knative.dev/eventing/pkg/apis/messaging/v1alpha1"
 	"knative.dev/pkg/apis/duck"
 	duckv1 "knative.dev/pkg/apis/duck/v1"
 	apisv1alpha1 "knative.dev/pkg/apis/v1alpha1"
 	serving "knative.dev/serving/pkg/apis/serving/v1"
+	controller "sigs.k8s.io/controller-runtime/pkg/client"
 )
 
-// IsEnabledInNamespace returns true if we can list some basic knative objects in the given namespace
-func IsEnabledInNamespace(ctx context.Context, c k8sclient.Reader, namespace string) bool {
-	channels := messaging.ChannelList{
-		TypeMeta: metav1.TypeMeta{
-			Kind:       "Channel",
-			APIVersion: eventing.SchemeGroupVersion.String(),
-		},
-	}
-	if err := c.List(ctx, &channels, k8sclient.InNamespace(namespace)); err != nil {
-		log.Infof("could not find knative in namespace %s, got error: %v", namespace, err)
-		return false
-	}
-	return true
-}
-
-// IsInstalled returns true if we are connected to a cluster with Knative installed
-func IsInstalled(ctx context.Context, c kubernetes.Interface) (bool, error) {
-	// check knative eventing, since serving may be on v1beta1 in some clusters
-	_, err := c.Discovery().ServerResourcesForGroupVersion("eventing.knative.dev/v1alpha1")
-	if err != nil && k8serrors.IsNotFound(err) {
-		return false, nil
-	} else if err != nil {
-		return false, err
-	}
-	return true, nil
-}
-
 // CreateSubscription ---
 func CreateSubscription(channelReference corev1.ObjectReference, serviceName string) runtime.Object {
 	subs := messaging.Subscription{