From 48203e64c9ea9e9d7883f1263e747f3249449045 Mon Sep 17 00:00:00 2001 From: Andy Bursavich Date: Sun, 24 Oct 2021 19:38:23 -0700 Subject: [PATCH] source: add gateway client --- go.mod | 5 ++- go.sum | 1 + source/store.go | 102 +++++++++++++++++++------------------------ source/store_test.go | 11 +++++ 4 files changed, 61 insertions(+), 58 deletions(-) diff --git a/go.mod b/go.mod index f7bf2c67e..3984dcd00 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,8 @@ require ( github.com/Azure/go-autorest/autorest/to v0.4.0 github.com/StackExchange/dnscontrol v0.2.8 github.com/akamai/AkamaiOPEN-edgegrid-golang v1.1.1 + github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 // indirect + github.com/alecthomas/colour v0.1.0 // indirect github.com/alecthomas/kingpin v2.2.5+incompatible github.com/aliyun/alibaba-cloud-sdk-go v1.61.1483 github.com/aws/aws-sdk-go v1.42.52 @@ -73,8 +75,6 @@ require ( github.com/Azure/go-autorest/logger v0.2.1 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect github.com/Masterminds/semver v1.4.2 // indirect - github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 // indirect - github.com/alecthomas/colour v0.1.0 // indirect github.com/alecthomas/repr v0.0.0-20200325044227-4184120f674c // indirect github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect @@ -157,6 +157,7 @@ require ( k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect k8s.io/utils v0.0.0-20211116205334-6203023598ed // indirect sigs.k8s.io/controller-runtime v0.11.0 // indirect + sigs.k8s.io/gateway-api v0.4.1 sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect sigs.k8s.io/yaml v1.3.0 // indirect diff --git a/go.sum b/go.sum index 6898f0a01..448da11bb 100644 --- a/go.sum +++ b/go.sum @@ -2086,6 +2086,7 @@ sigs.k8s.io/controller-tools v0.5.0/go.mod h1:JTsstrMpxs+9BUj6eGuAaEb6SDSPTeVtUy sigs.k8s.io/controller-tools v0.6.0/go.mod h1:baRMVPrctU77F+rfAuH2uPqW93k6yQnZA2dhUOr7ihc= sigs.k8s.io/controller-tools v0.6.2/go.mod h1:oaeGpjXn6+ZSEIQkUe/+3I40PNiDYp9aeawbt3xTgJ8= sigs.k8s.io/gateway-api v0.3.0/go.mod h1:Wb8bx7QhGVZxOSEU3i9vw/JqTB5Nlai9MLMYVZeDmRQ= +sigs.k8s.io/gateway-api v0.4.1 h1:Tof9/PNSZXyfDuTTe1XFvaTlvBRE6bKq1kmV6jj6rQE= sigs.k8s.io/gateway-api v0.4.1/go.mod h1:r3eiNP+0el+NTLwaTfOrCNXy8TukC+dIM3ggc+fbNWk= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= diff --git a/source/store.go b/source/store.go index 942400aef..721e8daed 100644 --- a/source/store.go +++ b/source/store.go @@ -35,6 +35,7 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" + gateway "sigs.k8s.io/gateway-api/pkg/client/clientset/gateway/versioned" ) // ErrSourceNotFound is returned when a requested source doesn't exist. @@ -74,6 +75,7 @@ type Config struct { // ClientGenerator provides clients type ClientGenerator interface { KubeClient() (kubernetes.Interface, error) + GatewayClient() (gateway.Interface, error) IstioClient() (istioclient.Interface, error) CloudFoundryClient(cfAPPEndpoint string, cfUsername string, cfPassword string) (*cfclient.Client, error) DynamicKubernetesClient() (dynamic.Interface, error) @@ -87,11 +89,13 @@ type SingletonClientGenerator struct { APIServerURL string RequestTimeout time.Duration kubeClient kubernetes.Interface + gatewayClient gateway.Interface istioClient *istioclient.Clientset cfClient *cfclient.Client dynKubeClient dynamic.Interface openshiftClient openshift.Interface kubeOnce sync.Once + gatewayOnce sync.Once istioOnce sync.Once cfOnce sync.Once dynCliOnce sync.Once @@ -107,6 +111,28 @@ func (p *SingletonClientGenerator) KubeClient() (kubernetes.Interface, error) { return p.kubeClient, err } +// GatewayClient generates a gateway client if it was not created before +func (p *SingletonClientGenerator) GatewayClient() (gateway.Interface, error) { + var err error + p.gatewayOnce.Do(func() { + p.gatewayClient, err = newGatewayClient(p.KubeConfig, p.APIServerURL, p.RequestTimeout) + }) + return p.gatewayClient, err +} + +func newGatewayClient(kubeConfig, apiServerURL string, requestTimeout time.Duration) (gateway.Interface, error) { + config, err := instrumentedRESTConfig(kubeConfig, apiServerURL, requestTimeout) + if err != nil { + return nil, err + } + client, err := gateway.NewForConfig(config) + if err != nil { + return nil, err + } + log.Infof("Created GatewayAPI client %s", config.Host) + return client, nil +} + // IstioClient generates an istio go client if it was not created before func (p *SingletonClientGenerator) IstioClient() (istioclient.Interface, error) { var err error @@ -296,6 +322,23 @@ func BuildWithConfig(ctx context.Context, source string, p ClientGenerator, cfg return nil, ErrSourceNotFound } +func instrumentedRESTConfig(kubeConfig, apiServerURL string, requestTimeout time.Duration) (*rest.Config, error) { + config, err := GetRestConfig(kubeConfig, apiServerURL) + if err != nil { + return nil, err + } + config.WrapTransport = func(rt http.RoundTripper) http.RoundTripper { + return instrumented_http.NewTransport(rt, &instrumented_http.Callbacks{ + PathProcessor: func(path string) string { + parts := strings.Split(path, "/") + return parts[len(parts)-1] + }, + }) + } + config.Timeout = requestTimeout + return config, nil +} + // GetRestConfig returns the rest clients config to get automatically // data if you run inside a cluster or by passing flags. func GetRestConfig(kubeConfig, apiServerURL string) (*rest.Config, error) { @@ -331,28 +374,15 @@ func GetRestConfig(kubeConfig, apiServerURL string) (*rest.Config, error) { // KubeConfig isn't provided it defaults to using the recommended default. func NewKubeClient(kubeConfig, apiServerURL string, requestTimeout time.Duration) (*kubernetes.Clientset, error) { log.Infof("Instantiating new Kubernetes client") - config, err := GetRestConfig(kubeConfig, apiServerURL) + config, err := instrumentedRESTConfig(kubeConfig, apiServerURL, requestTimeout) if err != nil { return nil, err } - - config.Timeout = requestTimeout - config.WrapTransport = func(rt http.RoundTripper) http.RoundTripper { - return instrumented_http.NewTransport(rt, &instrumented_http.Callbacks{ - PathProcessor: func(path string) string { - parts := strings.Split(path, "/") - return parts[len(parts)-1] - }, - }) - } - client, err := kubernetes.NewForConfig(config) if err != nil { return nil, err } - log.Infof("Created Kubernetes client %s", config.Host) - return client, nil } @@ -388,35 +418,15 @@ func NewIstioClient(kubeConfig string, apiServerURL string) (*istioclient.Client // uses APIServerURL and KubeConfig attributes to connect to the cluster. If // KubeConfig isn't provided it defaults to using the recommended default. func NewDynamicKubernetesClient(kubeConfig, apiServerURL string, requestTimeout time.Duration) (dynamic.Interface, error) { - if kubeConfig == "" { - if _, err := os.Stat(clientcmd.RecommendedHomeFile); err == nil { - kubeConfig = clientcmd.RecommendedHomeFile - } - } - - config, err := clientcmd.BuildConfigFromFlags(apiServerURL, kubeConfig) + config, err := instrumentedRESTConfig(kubeConfig, apiServerURL, requestTimeout) if err != nil { return nil, err } - - config.WrapTransport = func(rt http.RoundTripper) http.RoundTripper { - return instrumented_http.NewTransport(rt, &instrumented_http.Callbacks{ - PathProcessor: func(path string) string { - parts := strings.Split(path, "/") - return parts[len(parts)-1] - }, - }) - } - - config.Timeout = requestTimeout - client, err := dynamic.NewForConfig(config) if err != nil { return nil, err } - log.Infof("Created Dynamic Kubernetes client %s", config.Host) - return client, nil } @@ -424,34 +434,14 @@ func NewDynamicKubernetesClient(kubeConfig, apiServerURL string, requestTimeout // uses APIServerURL and KubeConfig attributes to connect to the cluster. If // KubeConfig isn't provided it defaults to using the recommended default. func NewOpenShiftClient(kubeConfig, apiServerURL string, requestTimeout time.Duration) (*openshift.Clientset, error) { - if kubeConfig == "" { - if _, err := os.Stat(clientcmd.RecommendedHomeFile); err == nil { - kubeConfig = clientcmd.RecommendedHomeFile - } - } - - config, err := clientcmd.BuildConfigFromFlags(apiServerURL, kubeConfig) + config, err := instrumentedRESTConfig(kubeConfig, apiServerURL, requestTimeout) if err != nil { return nil, err } - - config.WrapTransport = func(rt http.RoundTripper) http.RoundTripper { - return instrumented_http.NewTransport(rt, &instrumented_http.Callbacks{ - PathProcessor: func(path string) string { - parts := strings.Split(path, "/") - return parts[len(parts)-1] - }, - }) - } - - config.Timeout = requestTimeout - client, err := openshift.NewForConfig(config) if err != nil { return nil, err } - log.Infof("Created OpenShift client %s", config.Host) - return client, nil } diff --git a/source/store_test.go b/source/store_test.go index bd09ed0e7..527478f52 100644 --- a/source/store_test.go +++ b/source/store_test.go @@ -33,11 +33,13 @@ import ( fakeDynamic "k8s.io/client-go/dynamic/fake" "k8s.io/client-go/kubernetes" fakeKube "k8s.io/client-go/kubernetes/fake" + gateway "sigs.k8s.io/gateway-api/pkg/client/clientset/gateway/versioned" ) type MockClientGenerator struct { mock.Mock kubeClient kubernetes.Interface + gatewayClient gateway.Interface istioClient istioclient.Interface cloudFoundryClient *cfclient.Client dynamicKubernetesClient dynamic.Interface @@ -53,6 +55,15 @@ func (m *MockClientGenerator) KubeClient() (kubernetes.Interface, error) { return nil, args.Error(1) } +func (m *MockClientGenerator) GatewayClient() (gateway.Interface, error) { + args := m.Called() + if args.Error(1) != nil { + return nil, args.Error(1) + } + m.gatewayClient = args.Get(0).(gateway.Interface) + return m.gatewayClient, nil +} + func (m *MockClientGenerator) IstioClient() (istioclient.Interface, error) { args := m.Called() if args.Error(1) == nil {