You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by as...@apache.org on 2019/09/18 18:47:57 UTC

[camel-k] 01/04: Fix #792: making CLI super-fast

This is an automated email from the ASF dual-hosted git repository.

astefanutti pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel-k.git

commit 53ab079c38eeb2c58706fe4715ee74c381a3ebd8
Author: nferraro <ni...@gmail.com>
AuthorDate: Wed Sep 18 13:20:36 2019 +0200

    Fix #792: making CLI super-fast
---
 cmd/builder/main.go      |  2 +-
 pkg/client/client.go     | 12 +++++++--
 pkg/client/fastmapper.go | 70 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 81 insertions(+), 3 deletions(-)

diff --git a/cmd/builder/main.go b/cmd/builder/main.go
index 2a20e0e..e526aed 100644
--- a/cmd/builder/main.go
+++ b/cmd/builder/main.go
@@ -54,7 +54,7 @@ func main() {
 	rand.Seed(time.Now().UTC().UnixNano())
 	printVersion()
 
-	c, err := client.NewClient()
+	c, err := client.NewClient(false)
 	exitOnError(err)
 
 	ctx := cancellable.NewContext()
diff --git a/pkg/client/client.go b/pkg/client/client.go
index f800fb6..ddb8332 100644
--- a/pkg/client/client.go
+++ b/pkg/client/client.go
@@ -23,6 +23,7 @@ import (
 	"os/user"
 	"path/filepath"
 
+	"k8s.io/apimachinery/pkg/api/meta"
 	"github.com/apache/camel-k/pkg/apis"
 	"github.com/operator-framework/operator-sdk/pkg/k8sutil"
 	"github.com/pkg/errors"
@@ -68,11 +69,12 @@ func (c *defaultClient) GetScheme() *runtime.Scheme {
 // NewOutOfClusterClient creates a new k8s client that can be used from outside the cluster
 func NewOutOfClusterClient(kubeconfig string) (Client, error) {
 	initialize(kubeconfig)
-	return NewClient()
+	// using fast discovery from outside the cluster
+	return NewClient(true)
 }
 
 // NewClient creates a new k8s client that can be used from outside or in the cluster
-func NewClient() (Client, error) {
+func NewClient(fastDiscovery bool) (Client, error) {
 	// Get a config to talk to the apiserver
 	cfg, err := config.GetConfig()
 	if err != nil {
@@ -91,9 +93,15 @@ func NewClient() (Client, error) {
 		return nil, err
 	}
 
+	var mapper meta.RESTMapper
+	if fastDiscovery {
+		mapper = newFastDiscoveryRESTMapper(cfg)
+	}
+
 	// Create a new client to avoid using cache (enabled by default on operator-sdk client)
 	clientOptions := controller.Options{
 		Scheme: scheme,
+		Mapper: mapper,
 	}
 	dynClient, err := controller.New(cfg, clientOptions)
 	if err != nil {
diff --git a/pkg/client/fastmapper.go b/pkg/client/fastmapper.go
new file mode 100644
index 0000000..2752953
--- /dev/null
+++ b/pkg/client/fastmapper.go
@@ -0,0 +1,70 @@
+package client
+
+import (
+	"github.com/sirupsen/logrus"
+	"k8s.io/apimachinery/pkg/api/meta"
+	"k8s.io/apimachinery/pkg/util/wait"
+	"k8s.io/client-go/discovery"
+	"k8s.io/client-go/rest"
+	"k8s.io/client-go/restmapper"
+
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// allowedAPIGroups contains a set of API groups that are allowed when using the fastmapper.
+// Those must correspond to all groups used by the "kamel" binary tool when running out-of-cluster.
+var allowedAPIGroups = map[string]bool{
+	"":                          true, // core APIs
+	"apiextensions.k8s.io":      true,
+	"apps":                      true,
+	"camel.apache.org":          true,
+	"rbac.authorization.k8s.io": true,
+}
+
+func newFastDiscoveryRESTMapper(config *rest.Config) meta.RESTMapper {
+	return meta.NewLazyRESTMapperLoader(func() (meta.RESTMapper, error) {
+		return newFastDiscoveryRESTMapperWithFilter(config, func(g *metav1.APIGroup) bool {
+			return allowedAPIGroups[g.Name]
+		})
+	})
+}
+
+func newFastDiscoveryRESTMapperWithFilter(config *rest.Config, filter func(*metav1.APIGroup) bool) (meta.RESTMapper, error) {
+	dc := discovery.NewDiscoveryClientForConfigOrDie(config)
+	groups, err := dc.ServerGroups()
+	if err != nil {
+		return nil, err
+	}
+	wg := wait.Group{}
+	totalCount := 0
+	pickedCount := 0
+	var grs []*restmapper.APIGroupResources
+	for _, group := range groups.Groups {
+		pick := filter(&group)
+		logrus.Debugf("Group: %s %v", group.Name, pick)
+		totalCount++
+		if !pick {
+			continue
+		}
+		pickedCount++
+		gr := &restmapper.APIGroupResources{
+			Group:              group,
+			VersionedResources: make(map[string][]metav1.APIResource),
+		}
+		grs = append(grs, gr)
+		wg.Start(func() { discoverGroupResources(dc, gr) })
+	}
+	wg.Wait()
+	logrus.Debugf("Picked %d/%d", pickedCount, totalCount)
+	return restmapper.NewDiscoveryRESTMapper(grs), nil
+}
+
+func discoverGroupResources(dc discovery.DiscoveryInterface, gr *restmapper.APIGroupResources) {
+	for _, version := range gr.Group.Versions {
+		resources, err := dc.ServerResourcesForGroupVersion(version.GroupVersion)
+		if err != nil {
+			logrus.Fatal(err, version.GroupVersion)
+		}
+		gr.VersionedResources[version.Version] = resources.APIResources
+	}
+}