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 <[email protected]>
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
+       }
+}

Reply via email to