From fea67065db56aafc6c7794b84edaa5605958ca5a Mon Sep 17 00:00:00 2001 From: CMC <476479827@qq.com> Date: Thu, 4 Nov 2021 13:36:13 +0800 Subject: [PATCH 1/9] feat: support k8s version less than 1.16 --- pkg/client/factory.go | 6 +++--- pkg/resources/common/dynamiccolumns.go | 2 +- pkg/stores/proxy/proxy_store.go | 6 ++++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/pkg/client/factory.go b/pkg/client/factory.go index 98b7270..064d2b1 100644 --- a/pkg/client/factory.go +++ b/pkg/client/factory.go @@ -35,7 +35,7 @@ func (a *addQuery) RoundTrip(req *http.Request) (*http.Response, error) { for k, v := range a.values { q.Set(k, v) } - req.Header.Set("Accept", "application/json;as=Table;v=v1;g=meta.k8s.io") + req.Header.Set("Accept", "application/json;as=Table;v=v1;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io") req.URL.RawQuery = q.Encode() return a.next.RoundTrip(req) } @@ -59,10 +59,10 @@ func NewFactory(cfg *rest.Config, impersonate bool) (*Factory, error) { tableClientCfg := rest.CopyConfig(clientCfg) tableClientCfg.Wrap(setTable) - tableClientCfg.AcceptContentTypes = "application/json;as=Table;v=v1;g=meta.k8s.io" + tableClientCfg.AcceptContentTypes = "application/json;as=Table;v=v1;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io" tableWatchClientCfg := rest.CopyConfig(watchClientCfg) tableWatchClientCfg.Wrap(setTable) - tableWatchClientCfg.AcceptContentTypes = "application/json;as=Table;v=v1;g=meta.k8s.io" + tableWatchClientCfg.AcceptContentTypes = "application/json;as=Table;v=v1;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io" md, err := metadata.NewForConfig(cfg) if err != nil { diff --git a/pkg/resources/common/dynamiccolumns.go b/pkg/resources/common/dynamiccolumns.go index 42c507f..dfe3af1 100644 --- a/pkg/resources/common/dynamiccolumns.go +++ b/pkg/resources/common/dynamiccolumns.go @@ -96,7 +96,7 @@ func newClient(config *rest.Config) (*rest.RESTClient, error) { config = rest.CopyConfig(config) config.RateLimiter = ratelimit.None config.UserAgent = rest.DefaultKubernetesUserAgent() - config.AcceptContentTypes = "application/json;as=Table;v=v1;g=meta.k8s.io" + config.AcceptContentTypes = "application/json;as=Table;v=v1;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io" config.GroupVersion = &schema.GroupVersion{} config.NegotiatedSerializer = serializer.NewCodecFactory(scheme) config.APIPath = "/" diff --git a/pkg/stores/proxy/proxy_store.go b/pkg/stores/proxy/proxy_store.go index 80e8aa5..7978377 100644 --- a/pkg/stores/proxy/proxy_store.go +++ b/pkg/stores/proxy/proxy_store.go @@ -169,7 +169,8 @@ func rowToObject(obj *unstructured.Unstructured) { return } if obj.Object["kind"] != "Table" || - obj.Object["apiVersion"] != "meta.k8s.io/v1" { + (obj.Object["apiVersion"] != "meta.k8s.io/v1" && + obj.Object["apiVersion"] != "meta.k8s.io/v1beta1") { return } @@ -181,7 +182,8 @@ func rowToObject(obj *unstructured.Unstructured) { func tableToList(obj *unstructured.UnstructuredList) { if obj.Object["kind"] != "Table" || - obj.Object["apiVersion"] != "meta.k8s.io/v1" { + (obj.Object["apiVersion"] != "meta.k8s.io/v1" && + obj.Object["apiVersion"] != "meta.k8s.io/v1beta1") { return } From 5ababa38249c682b1e218a067b4e55d7068bfb10 Mon Sep 17 00:00:00 2001 From: Donnie Adams Date: Tue, 4 Jan 2022 12:45:17 -0700 Subject: [PATCH 2/9] Bump remotedialer to add pause/resume functionality --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index dd7f74a..5757673 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/rancher/dynamiclistener v0.2.1-0.20200714201033-9c1939da3af9 github.com/rancher/kubernetes-provider-detector v0.1.2 github.com/rancher/norman v0.0.0-20210423002317-8e6ffc77a819 - github.com/rancher/remotedialer v0.2.6-0.20210318171128-d1ebd5202be4 + github.com/rancher/remotedialer v0.2.6-0.20220104192242-f3837f8d649a github.com/rancher/wrangler v0.8.1-0.20210423003607-f71a90542852 github.com/sirupsen/logrus v1.6.0 github.com/urfave/cli v1.22.2 diff --git a/go.sum b/go.sum index 9f47f9e..2b396b7 100644 --- a/go.sum +++ b/go.sum @@ -459,8 +459,8 @@ github.com/rancher/lasso v0.0.0-20210408231703-9ddd9378d08d/go.mod h1:OhBBBO1pBw github.com/rancher/moq v0.0.0-20190404221404-ee5226d43009/go.mod h1:wpITyDPTi/Na5h73XkbuEf2AP9fbgrIGqqxVzFhYD6U= github.com/rancher/norman v0.0.0-20210423002317-8e6ffc77a819 h1:K3pICsdBbzOHoOyWdEjCxd8vApLpk8qwBI5VNCQQsM0= github.com/rancher/norman v0.0.0-20210423002317-8e6ffc77a819/go.mod h1:hhnf77V2lmZD7cvUqi4vTBpIs3KpHNL/AmuN0MqEClI= -github.com/rancher/remotedialer v0.2.6-0.20210318171128-d1ebd5202be4 h1:wo4G9nT0YUdHMQe6g++ojYMUvNtHoybhLJ2Ckr/L1N8= -github.com/rancher/remotedialer v0.2.6-0.20210318171128-d1ebd5202be4/go.mod h1:dbzn9NF1JWbGEHL6Q/1KG4KFROILiY/j6wmfF1Np3fk= +github.com/rancher/remotedialer v0.2.6-0.20220104192242-f3837f8d649a h1:Go8MpBEeZCR0yV1ylu2/KjJBvpYomIezU58pejYCtgk= +github.com/rancher/remotedialer v0.2.6-0.20220104192242-f3837f8d649a/go.mod h1:vq3LvyOFnLcwMiCE1KdW3foPd6g5kAjZOtOb7JqGHck= github.com/rancher/wrangler v0.6.1/go.mod h1:L4HtjPeX8iqLgsxfJgz+JjKMcX2q3qbRXSeTlC/CSd4= github.com/rancher/wrangler v0.6.2-0.20200714200521-c61fae623942/go.mod h1:8LdIqAQPHysxNlHqmKbUiDIx9ULt9IHUauh9aOnr67k= github.com/rancher/wrangler v0.6.2-0.20200820173016-2068de651106/go.mod h1:iKqQcYs4YSDjsme52OZtQU4jHPmLlIiM93aj2c8c/W8= From e7119828b8f9a9ca2cb2620ba650bd0508ca463e Mon Sep 17 00:00:00 2001 From: Darren Shepherd Date: Fri, 7 Jan 2022 14:29:46 -0700 Subject: [PATCH 3/9] Update wrangler --- go.mod | 3 +-- go.sum | 13 ++++++++----- main.go | 3 +-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 5757673..037a6ad 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,6 @@ require ( github.com/adrg/xdg v0.3.1 github.com/gorilla/mux v1.7.3 github.com/gorilla/websocket v1.4.2 - github.com/hashicorp/golang-lru v0.5.3 // indirect github.com/imdario/mergo v0.3.8 // indirect github.com/pborman/uuid v1.2.0 github.com/pkg/errors v0.9.1 @@ -23,7 +22,7 @@ require ( github.com/rancher/kubernetes-provider-detector v0.1.2 github.com/rancher/norman v0.0.0-20210423002317-8e6ffc77a819 github.com/rancher/remotedialer v0.2.6-0.20220104192242-f3837f8d649a - github.com/rancher/wrangler v0.8.1-0.20210423003607-f71a90542852 + github.com/rancher/wrangler v0.8.11-0.20211214201934-f5aa5d9f2e81 github.com/sirupsen/logrus v1.6.0 github.com/urfave/cli v1.22.2 github.com/urfave/cli/v2 v2.1.1 diff --git a/go.sum b/go.sum index 2b396b7..80a376d 100644 --- a/go.sum +++ b/go.sum @@ -330,6 +330,7 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -454,8 +455,8 @@ github.com/rancher/kubernetes-provider-detector v0.1.2 h1:iFfmmcZiGya6s3cS4Qxksy github.com/rancher/kubernetes-provider-detector v0.1.2/go.mod h1:ypuJS7kP7rUiAn330xG46mj+Nhvym05GM8NqMVekpH0= github.com/rancher/lasso v0.0.0-20200515155337-a34e1e26ad91/go.mod h1:G6Vv2aj6xB2YjTVagmu4NkhBvbE8nBcGykHRENH6arI= github.com/rancher/lasso v0.0.0-20200820172840-0e4cc0ef5cb0/go.mod h1:OhBBBO1pBwYp0hacWdnvSGOj+XE9yMLOLnaypIlic18= -github.com/rancher/lasso v0.0.0-20210408231703-9ddd9378d08d h1:vfjPEF6M7Jf1/zK1xF7z2drLfniooKcgDQdoXO5+U7w= -github.com/rancher/lasso v0.0.0-20210408231703-9ddd9378d08d/go.mod h1:OhBBBO1pBwYp0hacWdnvSGOj+XE9yMLOLnaypIlic18= +github.com/rancher/lasso v0.0.0-20210616224652-fc3ebd901c08 h1:NxR8Fh0eE7/5/5Zvlog9B5NVjWKqBSb1WYMUF7/IE5c= +github.com/rancher/lasso v0.0.0-20210616224652-fc3ebd901c08/go.mod h1:9qZd/S8DqWzfKtjKGgSoHqGEByYmUE3qRaBaaAHwfEM= github.com/rancher/moq v0.0.0-20190404221404-ee5226d43009/go.mod h1:wpITyDPTi/Na5h73XkbuEf2AP9fbgrIGqqxVzFhYD6U= github.com/rancher/norman v0.0.0-20210423002317-8e6ffc77a819 h1:K3pICsdBbzOHoOyWdEjCxd8vApLpk8qwBI5VNCQQsM0= github.com/rancher/norman v0.0.0-20210423002317-8e6ffc77a819/go.mod h1:hhnf77V2lmZD7cvUqi4vTBpIs3KpHNL/AmuN0MqEClI= @@ -464,8 +465,8 @@ github.com/rancher/remotedialer v0.2.6-0.20220104192242-f3837f8d649a/go.mod h1:v github.com/rancher/wrangler v0.6.1/go.mod h1:L4HtjPeX8iqLgsxfJgz+JjKMcX2q3qbRXSeTlC/CSd4= github.com/rancher/wrangler v0.6.2-0.20200714200521-c61fae623942/go.mod h1:8LdIqAQPHysxNlHqmKbUiDIx9ULt9IHUauh9aOnr67k= github.com/rancher/wrangler v0.6.2-0.20200820173016-2068de651106/go.mod h1:iKqQcYs4YSDjsme52OZtQU4jHPmLlIiM93aj2c8c/W8= -github.com/rancher/wrangler v0.8.1-0.20210423003607-f71a90542852 h1:HMvBxqM0edSRzRZSWg0uDPaKy0NJhIoePmkln4ta4bs= -github.com/rancher/wrangler v0.8.1-0.20210423003607-f71a90542852/go.mod h1:zSV5oh3+YZboilwcJmFHO3J6FZba82BTQft1b6ijx2I= +github.com/rancher/wrangler v0.8.11-0.20211214201934-f5aa5d9f2e81 h1:V6K7b1xEclCmDwfZFYhXHubtTLVpkvYFN+CGOIgIT1M= +github.com/rancher/wrangler v0.8.11-0.20211214201934-f5aa5d9f2e81/go.mod h1:Lte9WjPtGYxYacIWeiS9qawvu2R4NujFU9xuXWJvc/0= github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -513,8 +514,9 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.2.3-0.20181224173747-660f15d67dbb/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -737,6 +739,7 @@ golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191017205301-920acffc3e65/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= diff --git a/main.go b/main.go index 1dc94a7..29b7de6 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,6 @@ package main import ( - "context" "os" "github.com/rancher/steve/pkg/debug" @@ -33,7 +32,7 @@ func main() { } func run(_ *cli.Context) error { - ctx := signals.SetupSignalHandler(context.Background()) + ctx := signals.SetupSignalContext() debugconfig.MustSetupDebug() s, err := config.ToServer(ctx) if err != nil { From 42c575a0090eb5f327f420ea12f0d8381b950345 Mon Sep 17 00:00:00 2001 From: michelia Date: Wed, 26 Jan 2022 19:31:03 +0800 Subject: [PATCH 4/9] Fixed errors in obtaining object relationships Issue: https://github.com/harvester/harvester/issues/1857 --- pkg/stores/proxy/proxy_store.go | 10 +++++----- pkg/summarycache/summarycache.go | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pkg/stores/proxy/proxy_store.go b/pkg/stores/proxy/proxy_store.go index 7978377..368f687 100644 --- a/pkg/stores/proxy/proxy_store.go +++ b/pkg/stores/proxy/proxy_store.go @@ -80,7 +80,7 @@ func NewProxyStore(clientGetter ClientGetter, notifier RelationshipNotifier, loo } func (s *Store) ByID(apiOp *types.APIRequest, schema *types.APISchema, id string) (types.APIObject, error) { - result, err := s.byID(apiOp, schema, id) + result, err := s.byID(apiOp, schema, apiOp.Namespace, id) return toAPI(schema, result), err } @@ -117,8 +117,8 @@ func toAPI(schema *types.APISchema, obj runtime.Object) types.APIObject { return apiObject } -func (s *Store) byID(apiOp *types.APIRequest, schema *types.APISchema, id string) (*unstructured.Unstructured, error) { - k8sClient, err := s.clientGetter.TableClient(apiOp, schema, apiOp.Namespace) +func (s *Store) byID(apiOp *types.APIRequest, schema *types.APISchema, namespace, id string) (*unstructured.Unstructured, error) { + k8sClient, err := s.clientGetter.TableClient(apiOp, schema, namespace) if err != nil { return nil, err } @@ -312,7 +312,7 @@ func (s *Store) listAndWatch(apiOp *types.APIRequest, k8sClient dynamic.Resource if s.notifier != nil { eg.Go(func() error { for rel := range s.notifier.OnInboundRelationshipChange(ctx, schema, apiOp.Namespace) { - obj, err := s.byID(apiOp, schema, rel.Name) + obj, err := s.byID(apiOp, schema, rel.Namespace, rel.Name) if err == nil { result <- s.toAPIEvent(apiOp, schema, watch.Modified, obj) } @@ -524,7 +524,7 @@ func (s *Store) Delete(apiOp *types.APIRequest, schema *types.APISchema, id stri return types.APIObject{}, err } - obj, err := s.byID(apiOp, schema, id) + obj, err := s.byID(apiOp, schema, apiOp.Namespace, id) if err != nil { // ignore lookup error return types.APIObject{}, validation.ErrorCode{ diff --git a/pkg/summarycache/summarycache.go b/pkg/summarycache/summarycache.go index 89f9fc8..5c53069 100644 --- a/pkg/summarycache/summarycache.go +++ b/pkg/summarycache/summarycache.go @@ -80,11 +80,10 @@ func (s *SummaryCache) OnInboundRelationshipChange(ctx context.Context, schema * s.cbs[id] = cb go func() { - defer close(ret) for rel := range cb { if rel.Kind == kind && rel.APIVersion == apiVersion && - rel.Namespace == namespace { + (namespace == "" || namespace == rel.Namespace) { ret <- rel } } @@ -95,10 +94,11 @@ func (s *SummaryCache) OnInboundRelationshipChange(ctx context.Context, schema * s.Lock() defer s.Unlock() close(cb) + defer close(ret) delete(s.cbs, id) }() - return cb + return ret } func (s *SummaryCache) SummaryAndRelationship(obj runtime.Object) (*summary.SummarizedObject, []Relationship) { From e9472ecc341084da5d1ba999b73d216c8ed97a53 Mon Sep 17 00:00:00 2001 From: Ricardo Weir Date: Wed, 2 Feb 2022 17:54:08 -0700 Subject: [PATCH 5/9] Add metrics --- go.mod | 1 + pkg/metrics/metrics.go | 100 +++++++++++++++++++++++++++ pkg/metrics/register.go | 18 +++++ pkg/resources/common/formatter.go | 3 +- pkg/stores/metrics/metrics_client.go | 82 ++++++++++++++++++++++ pkg/stores/metrics/metrics_store.go | 66 ++++++++++++++++++ pkg/stores/proxy/proxy_store.go | 30 ++++---- 7 files changed, 286 insertions(+), 14 deletions(-) create mode 100644 pkg/metrics/metrics.go create mode 100644 pkg/metrics/register.go create mode 100644 pkg/stores/metrics/metrics_client.go create mode 100644 pkg/stores/metrics/metrics_store.go diff --git a/go.mod b/go.mod index 037a6ad..8db8af0 100644 --- a/go.mod +++ b/go.mod @@ -17,6 +17,7 @@ require ( github.com/imdario/mergo v0.3.8 // indirect github.com/pborman/uuid v1.2.0 github.com/pkg/errors v0.9.1 + github.com/prometheus/client_golang v1.7.1 github.com/rancher/apiserver v0.0.0-20210922180056-297b6df8d714 github.com/rancher/dynamiclistener v0.2.1-0.20200714201033-9c1939da3af9 github.com/rancher/kubernetes-provider-detector v0.1.2 diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go new file mode 100644 index 0000000..353e8e9 --- /dev/null +++ b/pkg/metrics/metrics.go @@ -0,0 +1,100 @@ +package metrics + +import ( + "net/http" + "strconv" + + "github.com/prometheus/client_golang/prometheus" + "github.com/rancher/apiserver/pkg/apierror" +) + +type MetricLogger struct { + Resource string + Method string +} + +var prometheusMetrics = false + +const ( + resourceLabel = "resource" + methodLabel = "method" + codeLabel = "code" +) + +var ( + // https://prometheus.io/docs/practices/instrumentation/#use-labels explains logic of having 1 total_requests + // counter with code label vs a counter for each code + + ProxyTotalResponses = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Subsystem: "k8s_proxy", + Name: "total_requests", + Help: "Total count API requests", + }, + []string{resourceLabel, methodLabel, codeLabel}, + ) + K8sClientResponseTime = prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Subsystem: "k8s_proxy", + Name: "client_request_time", + Help: "Request times in ms for k8s client from proxy store", + }, + []string{resourceLabel, methodLabel, codeLabel}) + ProxyStoreResponseTime = prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Subsystem: "k8s_proxy", + Name: "store_request_time", + Help: "Request times in ms for k8s proxy store", + }, + []string{resourceLabel, methodLabel, codeLabel}) +) + +func (m MetricLogger) IncTotalResponses(err error) { + if prometheusMetrics { + ProxyTotalResponses.With( + prometheus.Labels{ + resourceLabel: m.Resource, + methodLabel: m.Method, + codeLabel: m.getAPIErrorCode(err), + }, + ).Inc() + } +} + +func (m MetricLogger) RecordK8sClientResponseTime(err error, val float64) { + if prometheusMetrics { + K8sClientResponseTime.With( + prometheus.Labels{ + resourceLabel: m.Resource, + methodLabel: m.Method, + codeLabel: m.getAPIErrorCode(err), + }, + ).Observe(val) + } +} + +func (m MetricLogger) RecordProxyStoreResponseTime(err error, val float64) { + if prometheusMetrics { + ProxyStoreResponseTime.With( + prometheus.Labels{ + resourceLabel: m.Resource, + methodLabel: m.Method, + codeLabel: m.getAPIErrorCode(err), + }, + ).Observe(val) + } +} + +func (m MetricLogger) getAPIErrorCode(err error) string { + successCode := "200" + if m.Method == http.MethodPost { + successCode = "201" + } + if err == nil { + return successCode + } + if apiError, ok := err.(*apierror.APIError); ok { + return strconv.Itoa(apiError.Code.Status) + } + return "500" +} diff --git a/pkg/metrics/register.go b/pkg/metrics/register.go new file mode 100644 index 0000000..e9ef95e --- /dev/null +++ b/pkg/metrics/register.go @@ -0,0 +1,18 @@ +package metrics + +import ( + "os" + + "github.com/prometheus/client_golang/prometheus" +) + +const metricsEnv = "CATTLE_PROMETHEUS_METRICS" + +func init() { + if os.Getenv(metricsEnv) == "true" { + prometheusMetrics = true + prometheus.MustRegister(ProxyTotalResponses) + prometheus.MustRegister(K8sClientResponseTime) + prometheus.MustRegister(ProxyStoreResponseTime) + } +} diff --git a/pkg/resources/common/formatter.go b/pkg/resources/common/formatter.go index 7ea90b2..cc28616 100644 --- a/pkg/resources/common/formatter.go +++ b/pkg/resources/common/formatter.go @@ -7,6 +7,7 @@ import ( "github.com/rancher/steve/pkg/accesscontrol" "github.com/rancher/steve/pkg/attributes" "github.com/rancher/steve/pkg/schema" + metricsStore "github.com/rancher/steve/pkg/stores/metrics" "github.com/rancher/steve/pkg/stores/proxy" "github.com/rancher/steve/pkg/summarycache" "github.com/rancher/wrangler/pkg/data" @@ -22,7 +23,7 @@ func DefaultTemplate(clientGetter proxy.ClientGetter, summaryCache *summarycache.SummaryCache, asl accesscontrol.AccessSetLookup) schema.Template { return schema.Template{ - Store: proxy.NewProxyStore(clientGetter, summaryCache, asl), + Store: metricsStore.NewMetricsStore(proxy.NewProxyStore(clientGetter, summaryCache, asl)), Formatter: formatter(summaryCache), } } diff --git a/pkg/stores/metrics/metrics_client.go b/pkg/stores/metrics/metrics_client.go new file mode 100644 index 0000000..6fe79d0 --- /dev/null +++ b/pkg/stores/metrics/metrics_client.go @@ -0,0 +1,82 @@ +package metrics + +import ( + "time" + + "github.com/rancher/apiserver/pkg/types" + "github.com/rancher/steve/pkg/metrics" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + k8stypes "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/dynamic" +) + +type ResourceClientWithMetrics struct { + dynamic.ResourceInterface +} + +func Wrap(resourceInterface dynamic.ResourceInterface, err error) (ResourceClientWithMetrics, error) { + client := ResourceClientWithMetrics{} + if err != nil { + return client, err + } + client.ResourceInterface = resourceInterface + return client, err +} + +func (r ResourceClientWithMetrics) Create(apiOp *types.APIRequest, obj *unstructured.Unstructured, options metav1.CreateOptions, subresources ...string) (*unstructured.Unstructured, error) { + m := metrics.MetricLogger{Resource: apiOp.Schema.ID, Method: apiOp.Method} + start := time.Now() + obj, err := r.ResourceInterface.Create(apiOp.Context(), obj, options, subresources...) + m.RecordK8sClientResponseTime(err, float64(time.Since(start).Milliseconds())) + return obj, err +} + +func (r ResourceClientWithMetrics) Update(apiOp *types.APIRequest, obj *unstructured.Unstructured, options metav1.UpdateOptions, subresources ...string) (*unstructured.Unstructured, error) { + m := metrics.MetricLogger{Resource: apiOp.Schema.ID, Method: apiOp.Method} + start := time.Now() + obj, err := r.ResourceInterface.Update(apiOp.Context(), obj, options, subresources...) + m.RecordK8sClientResponseTime(err, float64(time.Since(start).Milliseconds())) + return obj, err +} + +func (r ResourceClientWithMetrics) Delete(apiOp *types.APIRequest, name string, options metav1.DeleteOptions, subresources ...string) error { + m := metrics.MetricLogger{Resource: apiOp.Schema.ID, Method: apiOp.Method} + start := time.Now() + err := r.ResourceInterface.Delete(apiOp.Context(), name, options, subresources...) + m.RecordK8sClientResponseTime(err, float64(time.Since(start).Milliseconds())) + return err +} + +func (r ResourceClientWithMetrics) Get(apiOp *types.APIRequest, name string, options metav1.GetOptions, subresources ...string) (*unstructured.Unstructured, error) { + m := metrics.MetricLogger{Resource: apiOp.Schema.ID, Method: apiOp.Method} + start := time.Now() + obj, err := r.ResourceInterface.Get(apiOp.Context(), name, options, subresources...) + m.RecordK8sClientResponseTime(err, float64(time.Since(start).Milliseconds())) + return obj, err +} + +func (r ResourceClientWithMetrics) List(apiOp *types.APIRequest, opts metav1.ListOptions) (*unstructured.UnstructuredList, error) { + m := metrics.MetricLogger{Resource: apiOp.Schema.ID, Method: apiOp.Method} + start := time.Now() + obj, err := r.ResourceInterface.List(apiOp.Context(), opts) + m.RecordK8sClientResponseTime(err, float64(time.Since(start).Milliseconds())) + return obj, err +} + +func (r ResourceClientWithMetrics) Watch(apiOp *types.APIRequest, opts metav1.ListOptions) (watch.Interface, error) { + m := metrics.MetricLogger{Resource: apiOp.Schema.ID, Method: apiOp.Method} + start := time.Now() + watchInterface, err := r.ResourceInterface.Watch(apiOp.Context(), opts) + m.RecordK8sClientResponseTime(err, float64(time.Since(start).Milliseconds())) + return watchInterface, err +} + +func (r ResourceClientWithMetrics) Patch(apiOp *types.APIRequest, name string, pt k8stypes.PatchType, data []byte, options metav1.PatchOptions, subresources ...string) (*unstructured.Unstructured, error) { + m := metrics.MetricLogger{Resource: apiOp.Schema.ID, Method: apiOp.Method} + start := time.Now() + obj, err := r.ResourceInterface.Patch(apiOp.Context(), name, pt, data, options, subresources...) + m.RecordK8sClientResponseTime(err, float64(time.Since(start).Milliseconds())) + return obj, err +} diff --git a/pkg/stores/metrics/metrics_store.go b/pkg/stores/metrics/metrics_store.go new file mode 100644 index 0000000..1e316a1 --- /dev/null +++ b/pkg/stores/metrics/metrics_store.go @@ -0,0 +1,66 @@ +package metrics + +import ( + "time" + + "github.com/rancher/apiserver/pkg/types" + "github.com/rancher/steve/pkg/metrics" +) + +type Store struct { + Store types.Store +} + +func NewMetricsStore(store types.Store) *Store { + return &Store{ + Store: store, + } +} + +func (s *Store) ByID(apiOp *types.APIRequest, schema *types.APISchema, id string) (types.APIObject, error) { + m := metrics.MetricLogger{Resource: apiOp.Schema.ID, Method: apiOp.Method} + storeStart := time.Now() + apiObject, err := s.Store.ByID(apiOp, schema, id) + m.RecordProxyStoreResponseTime(err, float64(time.Since(storeStart).Milliseconds())) + return apiObject, err +} + +func (s *Store) List(apiOp *types.APIRequest, schema *types.APISchema) (types.APIObjectList, error) { + m := metrics.MetricLogger{Resource: apiOp.Schema.ID, Method: apiOp.Method} + storeStart := time.Now() + apiObjectList, err := s.Store.List(apiOp, schema) + m.RecordProxyStoreResponseTime(err, float64(time.Since(storeStart).Milliseconds())) + return apiObjectList, err +} + +func (s *Store) Create(apiOp *types.APIRequest, schema *types.APISchema, data types.APIObject) (types.APIObject, error) { + m := metrics.MetricLogger{Resource: apiOp.Schema.ID, Method: apiOp.Method} + storeStart := time.Now() + apiObject, err := s.Store.Create(apiOp, schema, data) + m.RecordProxyStoreResponseTime(err, float64(time.Since(storeStart).Milliseconds())) + return apiObject, err +} + +func (s *Store) Update(apiOp *types.APIRequest, schema *types.APISchema, data types.APIObject, id string) (types.APIObject, error) { + m := metrics.MetricLogger{Resource: apiOp.Schema.ID, Method: apiOp.Method} + storeStart := time.Now() + apiObject, err := s.Store.Update(apiOp, schema, data, id) + m.RecordProxyStoreResponseTime(err, float64(time.Since(storeStart).Milliseconds())) + return apiObject, err +} + +func (s *Store) Delete(apiOp *types.APIRequest, schema *types.APISchema, id string) (types.APIObject, error) { + m := metrics.MetricLogger{Resource: apiOp.Schema.ID, Method: apiOp.Method} + storeStart := time.Now() + apiObject, err := s.Store.Delete(apiOp, schema, id) + m.RecordProxyStoreResponseTime(err, float64(time.Since(storeStart).Milliseconds())) + return apiObject, err +} + +func (s *Store) Watch(apiOp *types.APIRequest, schema *types.APISchema, w types.WatchRequest) (chan types.APIEvent, error) { + m := metrics.MetricLogger{Resource: apiOp.Schema.ID, Method: apiOp.Method} + storeStart := time.Now() + apiEvent, err := s.Store.Watch(apiOp, schema, w) + m.RecordProxyStoreResponseTime(err, float64(time.Since(storeStart).Milliseconds())) + return apiEvent, err +} \ No newline at end of file diff --git a/pkg/stores/proxy/proxy_store.go b/pkg/stores/proxy/proxy_store.go index 368f687..b707923 100644 --- a/pkg/stores/proxy/proxy_store.go +++ b/pkg/stores/proxy/proxy_store.go @@ -14,6 +14,7 @@ import ( "github.com/rancher/apiserver/pkg/types" "github.com/rancher/steve/pkg/accesscontrol" "github.com/rancher/steve/pkg/attributes" + metricsStore "github.com/rancher/steve/pkg/stores/metrics" "github.com/rancher/steve/pkg/stores/partition" "github.com/rancher/wrangler/pkg/data" "github.com/rancher/wrangler/pkg/schemas/validation" @@ -118,7 +119,7 @@ func toAPI(schema *types.APISchema, obj runtime.Object) types.APIObject { } func (s *Store) byID(apiOp *types.APIRequest, schema *types.APISchema, namespace, id string) (*unstructured.Unstructured, error) { - k8sClient, err := s.clientGetter.TableClient(apiOp, schema, namespace) + k8sClient, err := metricsStore.Wrap(s.clientGetter.TableClient(apiOp, schema, namespace)) if err != nil { return nil, err } @@ -128,7 +129,7 @@ func (s *Store) byID(apiOp *types.APIRequest, schema *types.APISchema, namespace return nil, err } - obj, err := k8sClient.Get(apiOp.Context(), id, opts) + obj, err := k8sClient.Get(apiOp, id, opts) rowToObject(obj) return obj, err } @@ -256,7 +257,8 @@ func (s *Store) list(apiOp *types.APIRequest, schema *types.APISchema, client dy return types.APIObjectList{}, nil } - resultList, err := client.List(apiOp.Context(), opts) + k8sClient, _ := metricsStore.Wrap(client, nil) + resultList, err := k8sClient.List(apiOp, opts) if err != nil { return types.APIObjectList{}, err } @@ -282,14 +284,15 @@ func returnErr(err error, c chan types.APIEvent) { } } -func (s *Store) listAndWatch(apiOp *types.APIRequest, k8sClient dynamic.ResourceInterface, schema *types.APISchema, w types.WatchRequest, result chan types.APIEvent) { +func (s *Store) listAndWatch(apiOp *types.APIRequest, client dynamic.ResourceInterface, schema *types.APISchema, w types.WatchRequest, result chan types.APIEvent) { rev := w.Revision if rev == "-1" || rev == "0" { rev = "" } timeout := int64(60 * 30) - watcher, err := k8sClient.Watch(apiOp.Context(), metav1.ListOptions{ + k8sClient, _ := metricsStore.Wrap(client, nil) + watcher, err := k8sClient.Watch(apiOp, metav1.ListOptions{ Watch: true, TimeoutSeconds: &timeout, ResourceVersion: rev, @@ -427,7 +430,7 @@ func (s *Store) Create(apiOp *types.APIRequest, schema *types.APISchema, params gvk := attributes.GVK(schema) input["apiVersion"], input["kind"] = gvk.ToAPIVersionAndKind() - k8sClient, err := s.clientGetter.TableClient(apiOp, schema, ns) + k8sClient, err := metricsStore.Wrap(s.clientGetter.TableClient(apiOp, schema, ns)) if err != nil { return types.APIObject{}, err } @@ -437,9 +440,10 @@ func (s *Store) Create(apiOp *types.APIRequest, schema *types.APISchema, params return types.APIObject{}, err } - resp, err = k8sClient.Create(apiOp.Context(), &unstructured.Unstructured{Object: input}, opts) + resp, err = k8sClient.Create(apiOp, &unstructured.Unstructured{Object: input}, opts) rowToObject(resp) - return toAPI(schema, resp), err + apiObject := toAPI(schema, resp) + return apiObject, err } func (s *Store) Update(apiOp *types.APIRequest, schema *types.APISchema, params types.APIObject, id string) (types.APIObject, error) { @@ -449,7 +453,7 @@ func (s *Store) Update(apiOp *types.APIRequest, schema *types.APISchema, params ) ns := types.Namespace(input) - k8sClient, err := s.clientGetter.TableClient(apiOp, schema, ns) + k8sClient, err := metricsStore.Wrap(s.clientGetter.TableClient(apiOp, schema, ns)) if err != nil { return types.APIObject{}, err } @@ -482,7 +486,7 @@ func (s *Store) Update(apiOp *types.APIRequest, schema *types.APISchema, params } } - resp, err := k8sClient.Patch(apiOp.Context(), id, pType, bytes, opts) + resp, err := k8sClient.Patch(apiOp, id, pType, bytes, opts) if err != nil { return types.APIObject{}, err } @@ -500,7 +504,7 @@ func (s *Store) Update(apiOp *types.APIRequest, schema *types.APISchema, params return types.APIObject{}, err } - resp, err := k8sClient.Update(apiOp.Context(), &unstructured.Unstructured{Object: moveFromUnderscore(input)}, metav1.UpdateOptions{}) + resp, err := k8sClient.Update(apiOp, &unstructured.Unstructured{Object: moveFromUnderscore(input)}, metav1.UpdateOptions{}) if err != nil { return types.APIObject{}, err } @@ -515,12 +519,12 @@ func (s *Store) Delete(apiOp *types.APIRequest, schema *types.APISchema, id stri return types.APIObject{}, nil } - k8sClient, err := s.clientGetter.TableClient(apiOp, schema, apiOp.Namespace) + k8sClient, err := metricsStore.Wrap(s.clientGetter.TableClient(apiOp, schema, apiOp.Namespace)) if err != nil { return types.APIObject{}, err } - if err := k8sClient.Delete(apiOp.Context(), id, opts); err != nil { + if err := k8sClient.Delete(apiOp, id, opts); err != nil { return types.APIObject{}, err } From 6bb3915906eac4bf2490df8735529b32ecc3e97a Mon Sep 17 00:00:00 2001 From: Jake Hyde Date: Wed, 2 Mar 2022 19:19:02 -0500 Subject: [PATCH 6/9] Prevent write on closed channel --- pkg/summarycache/summarycache.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/summarycache/summarycache.go b/pkg/summarycache/summarycache.go index 5c53069..326bacd 100644 --- a/pkg/summarycache/summarycache.go +++ b/pkg/summarycache/summarycache.go @@ -80,6 +80,7 @@ func (s *SummaryCache) OnInboundRelationshipChange(ctx context.Context, schema * s.cbs[id] = cb go func() { + defer close(ret) for rel := range cb { if rel.Kind == kind && rel.APIVersion == apiVersion && @@ -94,7 +95,6 @@ func (s *SummaryCache) OnInboundRelationshipChange(ctx context.Context, schema * s.Lock() defer s.Unlock() close(cb) - defer close(ret) delete(s.cbs, id) }() From 974c0a7f91cc10109a3277559c429b8a96708641 Mon Sep 17 00:00:00 2001 From: Nelson Roberts Date: Thu, 31 Mar 2022 14:32:46 -0700 Subject: [PATCH 7/9] enable fossa scanning request: https://github.com/rancherlabs/eio/issues/772 --- .drone.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .drone.yml diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..4420ccb --- /dev/null +++ b/.drone.yml @@ -0,0 +1,13 @@ +--- +kind: pipeline +name: fossa + +steps: +- name: fossa + image: rancher/drone-fossa:latest + settings: + api_key: + from_secret: FOSSA_API_KEY + when: + instance: + - drone-publish.rancher.io From 87f7f70d0d8cd3c8c94366eca0fdffb63eb888a5 Mon Sep 17 00:00:00 2001 From: Guilherme Macedo Date: Tue, 5 Apr 2022 17:15:14 +0200 Subject: [PATCH 8/9] Dependencies bumps Signed-off-by: Guilherme Macedo --- .gitignore | 1 + go.mod | 8 ++++---- go.sum | 55 +++++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 47 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index 0ee2ac6..b4b9df1 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ /dist *.swp .idea +steve diff --git a/go.mod b/go.mod index 8db8af0..d9cdd9d 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/imdario/mergo v0.3.8 // indirect github.com/pborman/uuid v1.2.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.7.1 + github.com/prometheus/client_golang v1.11.1 github.com/rancher/apiserver v0.0.0-20210922180056-297b6df8d714 github.com/rancher/dynamiclistener v0.2.1-0.20200714201033-9c1939da3af9 github.com/rancher/kubernetes-provider-detector v0.1.2 @@ -27,13 +27,13 @@ require ( github.com/sirupsen/logrus v1.6.0 github.com/urfave/cli v1.22.2 github.com/urfave/cli/v2 v2.1.1 - golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 + golang.org/x/sync v0.0.0-20201207232520-09787c993a3a k8s.io/api v0.20.0 k8s.io/apiextensions-apiserver v0.20.0 - k8s.io/apimachinery v0.20.0 + k8s.io/apimachinery v0.20.15 k8s.io/apiserver v0.20.0 k8s.io/client-go v12.0.0+incompatible k8s.io/klog v1.0.0 k8s.io/kube-aggregator v0.20.0 - k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd + k8s.io/kube-openapi v0.0.0-20211110013926-83f114cd0513 ) diff --git a/go.sum b/go.sum index 80a376d..ff8818e 100644 --- a/go.sum +++ b/go.sum @@ -51,6 +51,7 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= @@ -144,8 +145,10 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0 h1:QvGt2nLcHH0WK9orKa+ppBPAxREcH364nPUedEpK0TY= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= @@ -200,8 +203,9 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -242,8 +246,10 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= @@ -315,19 +321,23 @@ github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -383,6 +393,7 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwd github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= @@ -421,8 +432,9 @@ github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4 github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= -github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.1 h1:+4eQaD7vAZ6DsfsxB15hbE0odUjGI5ARs9yskGu1v4s= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -433,16 +445,18 @@ github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7q github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/qri-io/starlib v0.4.2-0.20200213133954-ff2e8cd5ef8d/go.mod h1:7DPO4domFU579Ga6E61sB9VFNaniPVwJP5C4bBCu3wA= github.com/rancher/apiserver v0.0.0-20210922180056-297b6df8d714 h1:DJPC3bY+yy8Ne4ge2FYs7k6J0CWERTL47hlKXTCgPYs= @@ -535,6 +549,7 @@ github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSf github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= @@ -639,6 +654,8 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -654,8 +671,10 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180117170059-2c42eef0765b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -693,10 +712,13 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40 h1:JWgyZ1qgdTaF3N3oxC+MdTV7qvEEgHo3otj+HB5CM7Q= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -706,8 +728,9 @@ golang.org/x/text v0.3.1-0.20171227012246-e19ae1496984/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -758,6 +781,8 @@ golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -823,8 +848,9 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1 h1:7QnIQpGRHE5RnLKnESfDoxm2dTapTZua5a0kS0A+VXQ= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -885,8 +911,9 @@ k8s.io/apimachinery v0.0.0-20201118005411-2456ebdaba22/go.mod h1:WlLqWAHZGg07Ael k8s.io/apimachinery v0.17.2/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= k8s.io/apimachinery v0.18.0/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= k8s.io/apimachinery v0.18.8/go.mod h1:6sQd+iHEqmOtALqOFjSWp2KZ9F0wlU/nWm0ZgsYWMig= -k8s.io/apimachinery v0.20.0 h1:jjzbTJRXk0unNS71L7h3lxGDH/2HPxMPaQY+MjECKL8= k8s.io/apimachinery v0.20.0/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.20.15 h1:tZW9jhDILQJq0fYXq7/t0xulj+73HzxLVBUGLCNg9uM= +k8s.io/apimachinery v0.20.15/go.mod h1:4KFiDSxCoGviCiRk9kTXIROsIf4VSGkVYjVJjJln3pg= k8s.io/apiserver v0.0.0-20190918160949-bfa5e2e684ad/go.mod h1:XPCXEwhjaFN29a8NldXA901ElnKeKLrLtREO9ZhFyhg= k8s.io/apiserver v0.17.2/go.mod h1:lBmw/TtQdtxvrTk0e2cgtOxHizXI+d0mmGQURIHQZlo= k8s.io/apiserver v0.18.0/go.mod h1:3S2O6FeBBd6XTo0njUrLxiqk8GNy6wWOftjhJcXYnjw= @@ -926,8 +953,9 @@ k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKf k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= -k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd h1:sOHNzJIkytDF6qadMNKhhDRpc6ODik8lVC6nOur7B2c= k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/kube-openapi v0.0.0-20211110013926-83f114cd0513 h1:pbudjNtv90nOgR0/DUhPwKHnQ55Khz8+sNhJBIK7A5M= +k8s.io/kube-openapi v0.0.0-20211110013926-83f114cd0513/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= k8s.io/kubectl v0.0.0-20191219154910-1528d4eea6dd/go.mod h1:9ehGcuUGjXVZh0qbYSB0vvofQw2JQe6c6cO0k4wu/Oo= k8s.io/metrics v0.0.0-20191214191643-6b1944c9f765/go.mod h1:5V7rewilItwK0cz4nomU0b3XCcees2Ka5EBYWS1HBeM= k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= @@ -957,8 +985,9 @@ sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2Iem sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= -sigs.k8s.io/structured-merge-diff/v4 v4.0.2 h1:YHQV7Dajm86OuqnIR6zAelnDWBRjo+YhYV9PmGrh1s8= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/testing_frameworks v0.1.2/go.mod h1:ToQrwSC3s8Xf/lADdZp3Mktcql9CG0UAmdJG9th5i0w= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= From d4cfe78364788943a31bc7b55427688b71174fa9 Mon Sep 17 00:00:00 2001 From: Colleen Murphy Date: Tue, 12 Apr 2022 16:17:28 -0700 Subject: [PATCH 9/9] Add field filtering for resources This change enables steve to work with three new query parameters: "include": only include the named fields from the kubernetes object. Subfields are denoted with ".". Subfields within arrays are ignored. Multiple fields can be included by repeating the parameter. Example: GET /v1/configmaps?include=kind&include=apiVersion => { "type": "collection", "links": { "self": "http://server/v1/configmaps" }, "createTypes": { "configmap": "http://server/v1/configmaps" }, "actions": {}, "resourceType": "configmap", "revision": "327238", "data": [ { "id": "c-m-w466b2vg/kube-root-ca.crt", "type": "configmap", "links": { "remove": "http://server/v1/configmaps/c-m-w466b2vg/kube-root-ca.crt", "self": "http://server/v1/configmaps/c-m-w466b2vg/kube-root-ca.crt", "update": "http://server/v1/configmaps/c-m-w466b2vg/kube-root-ca.crt", "view": "http://server/api/v1/namespaces/c-m-w466b2vg/configmaps/kube-root-ca.crt" }, "apiVersion": "v1", "kind": "ConfigMap" }, } ... } "exclude": exclude the named fields from the kubernetes object. Subfields are denoted with ".". Subfields within arrays are ignored. Multiple fields can be excluded by repeating the parameter. Example: GET /v1/configmaps?exclude=data&exclude=metadata.managedFields => { "type": "collection", "links": { "self": "http://server/v1/configmaps" }, "createTypes": { "configmap": "http://server/v1/configmaps" }, "actions": {}, "resourceType": "configmap", "revision": "328086", "data": [ { "id": "c-m-w466b2vg/kube-root-ca.crt", "type": "configmap", "links": { "remove": "http://server/v1/configmaps/c-m-w466b2vg/kube-root-ca.crt", "self": "http://server/v1/configmaps/c-m-w466b2vg/kube-root-ca.crt", "update": "http://server/v1/configmaps/c-m-w466b2vg/kube-root-ca.crt", "view": "http://server/api/v1/namespaces/c-m-w466b2vg/configmaps/kube-root-ca.crt" }, "apiVersion": "v1", "kind": "ConfigMap", "metadata": { "creationTimestamp": "2022-04-11T22:05:27Z", "fields": [ "kube-root-ca.crt", 1, "25h" ], "name": "kube-root-ca.crt", "namespace": "c-m-w466b2vg", "relationships": null, "resourceVersion": "36948", "state": { "error": false, "message": "Resource is always ready", "name": "active", "transitioning": false }, "uid": "1c497934-52cb-42ab-a613-dedfd5fb207b" } }, ... } "excludeValues": replace the values of an object with empty strings, leaving the keys in place. Useful for showing a summary of an object with large values, such as the data in a ConfigMap. Only works on fields that are object. Multiple fields can have values excluded by repeating the parameter. Example: GET /v1/configmaps?excludeValues=data => { "type": "collection", ... "data": [ { ... "data": { "ca.crt": "" }, ... }, ... ] } --- pkg/resources/common/formatter.go | 41 ++ pkg/resources/common/formatter_test.go | 543 +++++++++++++++++++++++++ 2 files changed, 584 insertions(+) create mode 100644 pkg/resources/common/formatter_test.go diff --git a/pkg/resources/common/formatter.go b/pkg/resources/common/formatter.go index cc28616..06dd345 100644 --- a/pkg/resources/common/formatter.go +++ b/pkg/resources/common/formatter.go @@ -93,6 +93,47 @@ func formatter(summarycache *summarycache.SummaryCache) types.Formatter { data.PutValue(unstr.Object, rel, "metadata", "relationships") summary.NormalizeConditions(unstr) + + includeFields(request, unstr) + excludeFields(request, unstr) + excludeValues(request, unstr) + } + + } +} + +func includeFields(request *types.APIRequest, unstr *unstructured.Unstructured) { + if fields, ok := request.Query["include"]; ok { + newObj := map[string]interface{}{} + for _, f := range fields { + fieldParts := strings.Split(f, ".") + if val, ok := data.GetValue(unstr.Object, fieldParts...); ok { + data.PutValue(newObj, val, fieldParts...) + } + } + unstr.Object = newObj + } +} + +func excludeFields(request *types.APIRequest, unstr *unstructured.Unstructured) { + if fields, ok := request.Query["exclude"]; ok { + for _, f := range fields { + fieldParts := strings.Split(f, ".") + data.RemoveValue(unstr.Object, fieldParts...) + } + } +} + +func excludeValues(request *types.APIRequest, unstr *unstructured.Unstructured) { + if values, ok := request.Query["excludeValues"]; ok { + for _, f := range values { + fieldParts := strings.Split(f, ".") + fieldValues := data.GetValueN(unstr.Object, fieldParts...) + if obj, ok := fieldValues.(map[string]interface{}); ok { + for k := range obj { + data.PutValue(unstr.Object, "", append(fieldParts, k)...) + } + } } } } diff --git a/pkg/resources/common/formatter_test.go b/pkg/resources/common/formatter_test.go new file mode 100644 index 0000000..635fec5 --- /dev/null +++ b/pkg/resources/common/formatter_test.go @@ -0,0 +1,543 @@ +package common + +import ( + "net/url" + "testing" + + "github.com/rancher/apiserver/pkg/types" + "github.com/stretchr/testify/assert" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" +) + +func Test_includeFields(t *testing.T) { + tests := []struct { + name string + request *types.APIRequest + unstr *unstructured.Unstructured + want *unstructured.Unstructured + }{ + { + name: "include top level field", + request: &types.APIRequest{ + Query: url.Values{ + "include": []string{"metadata"}, + }, + }, + unstr: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "creationTimestamp": "2022-04-11T22:05:27Z", + "name": "kube-root-ca.crt", + "namespace": "c-m-w466b2vg", + "resourceVersion": "36948", + "uid": "1c497934-52cb-42ab-a613-dedfd5fb207b", + }, + "data": map[string]interface{}{ + "ca.crt": "-----BEGIN CERTIFICATE-----\nMIIC5zCCAc+gAwIBAg\n-----END CERTIFICATE-----\n", + }, + }, + }, + want: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "creationTimestamp": "2022-04-11T22:05:27Z", + "name": "kube-root-ca.crt", + "namespace": "c-m-w466b2vg", + "resourceVersion": "36948", + "uid": "1c497934-52cb-42ab-a613-dedfd5fb207b", + }, + }, + }, + }, + { + name: "include sub field", + request: &types.APIRequest{ + Query: url.Values{ + "include": []string{"metadata.managedFields"}, + }, + }, + unstr: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "creationTimestamp": "2022-04-11T22:05:27Z", + "name": "kube-root-ca.crt", + "namespace": "c-m-w466b2vg", + "resourceVersion": "36948", + "uid": "1c497934-52cb-42ab-a613-dedfd5fb207b", + "managedFields": []map[string]interface{}{ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": map[string]interface{}{ + "f:data": map[string]interface{}{ + ".": map[string]interface{}{}, + "f:ca.crt": map[string]interface{}{}, + }, + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2022-04-11T22:05:27Z", + }, + }, + }, + "data": map[string]interface{}{ + "ca.crt": "-----BEGIN CERTIFICATE-----\nMIIC5zCCAc+gAwIBAg\n-----END CERTIFICATE-----\n", + }, + }, + }, + want: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "managedFields": []map[string]interface{}{ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": map[string]interface{}{ + "f:data": map[string]interface{}{ + ".": map[string]interface{}{}, + "f:ca.crt": map[string]interface{}{}, + }, + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2022-04-11T22:05:27Z", + }, + }, + }, + }, + }, + }, + { + name: "include invalid field", + request: &types.APIRequest{ + Query: url.Values{ + "include": []string{"foo.bar"}, + }, + }, + unstr: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "creationTimestamp": "2022-04-11T22:05:27Z", + "name": "kube-root-ca.crt", + "namespace": "c-m-w466b2vg", + "resourceVersion": "36948", + "uid": "1c497934-52cb-42ab-a613-dedfd5fb207b", + }, + "data": map[string]interface{}{ + "ca.crt": "-----BEGIN CERTIFICATE-----\nMIIC5zCCAc+gAwIBAg\n-----END CERTIFICATE-----\n", + }, + }, + }, + want: &unstructured.Unstructured{ + Object: map[string]interface{}{}, + }, + }, + { + name: "include multiple fields", + request: &types.APIRequest{ + Query: url.Values{ + "include": []string{"kind", "apiVersion", "metadata.name"}, + }, + }, + unstr: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "v1", + "kind": "ConfigMap", + "metadata": map[string]interface{}{ + "creationTimestamp": "2022-04-11T22:05:27Z", + "name": "kube-root-ca.crt", + "namespace": "c-m-w466b2vg", + "resourceVersion": "36948", + "uid": "1c497934-52cb-42ab-a613-dedfd5fb207b", + }, + "data": map[string]interface{}{ + "ca.crt": "-----BEGIN CERTIFICATE-----\nMIIC5zCCAc+gAwIBAg\n-----END CERTIFICATE-----\n", + }, + }, + }, + want: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "v1", + "kind": "ConfigMap", + "metadata": map[string]interface{}{ + "name": "kube-root-ca.crt", + }, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + includeFields(tt.request, tt.unstr) + assert.Equal(t, tt.want, tt.unstr) + }) + } +} + +func Test_excludeFields(t *testing.T) { + tests := []struct { + name string + request *types.APIRequest + unstr *unstructured.Unstructured + want *unstructured.Unstructured + }{ + { + name: "exclude top level field", + request: &types.APIRequest{ + Query: url.Values{ + "exclude": []string{"metadata"}, + }, + }, + unstr: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "creationTimestamp": "2022-04-11T22:05:27Z", + "name": "kube-root-ca.crt", + "namespace": "c-m-w466b2vg", + "resourceVersion": "36948", + "uid": "1c497934-52cb-42ab-a613-dedfd5fb207b", + }, + "data": map[string]interface{}{ + "ca.crt": "-----BEGIN CERTIFICATE-----\nMIIC5zCCAc+gAwIBAg\n-----END CERTIFICATE-----\n", + }, + }, + }, + want: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "data": map[string]interface{}{ + "ca.crt": "-----BEGIN CERTIFICATE-----\nMIIC5zCCAc+gAwIBAg\n-----END CERTIFICATE-----\n", + }, + }, + }, + }, + { + name: "exclude sub field", + request: &types.APIRequest{ + Query: url.Values{ + "exclude": []string{"metadata.managedFields"}, + }, + }, + unstr: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "creationTimestamp": "2022-04-11T22:05:27Z", + "name": "kube-root-ca.crt", + "namespace": "c-m-w466b2vg", + "resourceVersion": "36948", + "uid": "1c497934-52cb-42ab-a613-dedfd5fb207b", + "managedFields": []map[string]interface{}{ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": map[string]interface{}{ + "f:data": map[string]interface{}{ + ".": map[string]interface{}{}, + "f:ca.crt": map[string]interface{}{}, + }, + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2022-04-11T22:05:27Z", + }, + }, + }, + "data": map[string]interface{}{ + "ca.crt": "-----BEGIN CERTIFICATE-----\nMIIC5zCCAc+gAwIBAg\n-----END CERTIFICATE-----\n", + }, + }, + }, + want: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "creationTimestamp": "2022-04-11T22:05:27Z", + "name": "kube-root-ca.crt", + "namespace": "c-m-w466b2vg", + "resourceVersion": "36948", + "uid": "1c497934-52cb-42ab-a613-dedfd5fb207b", + }, + "data": map[string]interface{}{ + "ca.crt": "-----BEGIN CERTIFICATE-----\nMIIC5zCCAc+gAwIBAg\n-----END CERTIFICATE-----\n", + }, + }, + }, + }, + { + name: "exclude invalid field", + request: &types.APIRequest{ + Query: url.Values{ + "exclude": []string{"foo.bar"}, + }, + }, + unstr: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "creationTimestamp": "2022-04-11T22:05:27Z", + "name": "kube-root-ca.crt", + "namespace": "c-m-w466b2vg", + "resourceVersion": "36948", + "uid": "1c497934-52cb-42ab-a613-dedfd5fb207b", + }, + "data": map[string]interface{}{ + "ca.crt": "-----BEGIN CERTIFICATE-----\nMIIC5zCCAc+gAwIBAg\n-----END CERTIFICATE-----\n", + }, + }, + }, + want: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "creationTimestamp": "2022-04-11T22:05:27Z", + "name": "kube-root-ca.crt", + "namespace": "c-m-w466b2vg", + "resourceVersion": "36948", + "uid": "1c497934-52cb-42ab-a613-dedfd5fb207b", + }, + "data": map[string]interface{}{ + "ca.crt": "-----BEGIN CERTIFICATE-----\nMIIC5zCCAc+gAwIBAg\n-----END CERTIFICATE-----\n", + }, + }, + }, + }, + { + name: "exclude multiple fields", + request: &types.APIRequest{ + Query: url.Values{ + "exclude": []string{"kind", "apiVersion", "metadata.name"}, + }, + }, + unstr: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "v1", + "kind": "ConfigMap", + "metadata": map[string]interface{}{ + "creationTimestamp": "2022-04-11T22:05:27Z", + "name": "kube-root-ca.crt", + "namespace": "c-m-w466b2vg", + "resourceVersion": "36948", + "uid": "1c497934-52cb-42ab-a613-dedfd5fb207b", + }, + "data": map[string]interface{}{ + "ca.crt": "-----BEGIN CERTIFICATE-----\nMIIC5zCCAc+gAwIBAg\n-----END CERTIFICATE-----\n", + }, + }, + }, + want: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "creationTimestamp": "2022-04-11T22:05:27Z", + "namespace": "c-m-w466b2vg", + "resourceVersion": "36948", + "uid": "1c497934-52cb-42ab-a613-dedfd5fb207b", + }, + "data": map[string]interface{}{ + "ca.crt": "-----BEGIN CERTIFICATE-----\nMIIC5zCCAc+gAwIBAg\n-----END CERTIFICATE-----\n", + }, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + excludeFields(tt.request, tt.unstr) + assert.Equal(t, tt.want, tt.unstr) + }) + } +} + +func Test_excludeValues(t *testing.T) { + tests := []struct { + name string + request *types.APIRequest + unstr *unstructured.Unstructured + want *unstructured.Unstructured + }{ + { + name: "exclude top level value", + request: &types.APIRequest{ + Query: url.Values{ + "excludeValues": []string{"data"}, + }, + }, + unstr: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "creationTimestamp": "2022-04-11T22:05:27Z", + "name": "kube-root-ca.crt", + "namespace": "c-m-w466b2vg", + "resourceVersion": "36948", + "uid": "1c497934-52cb-42ab-a613-dedfd5fb207b", + }, + "data": map[string]interface{}{ + "ca.crt": "-----BEGIN CERTIFICATE-----\nMIIC5zCCAc+gAwIBAg\n-----END CERTIFICATE-----\n", + }, + }, + }, + want: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "creationTimestamp": "2022-04-11T22:05:27Z", + "name": "kube-root-ca.crt", + "namespace": "c-m-w466b2vg", + "resourceVersion": "36948", + "uid": "1c497934-52cb-42ab-a613-dedfd5fb207b", + }, + "data": map[string]interface{}{ + "ca.crt": "", + }, + }, + }, + }, + { + name: "exclude sub field value", + request: &types.APIRequest{ + Query: url.Values{ + "excludeValues": []string{"metadata.annotations"}, + }, + }, + unstr: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "annotations": map[string]interface{}{ + "deployment.kubernetes.io/revision": "2", + "meta.helm.sh/release-name": "fleet-agent-local", + "meta.helm.sh/release-namespace": "cattle-fleet-local-system", + }, + "creationTimestamp": "2022-04-11T22:05:27Z", + "name": "fleet-agent", + "namespace": "cattle-fleet-local-system", + "resourceVersion": "36948", + "uid": "1c497934-52cb-42ab-a613-dedfd5fb207b", + }, + "spec": map[string]interface{}{ + "replicas": 1, + }, + }, + }, + want: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "annotations": map[string]interface{}{ + "deployment.kubernetes.io/revision": "", + "meta.helm.sh/release-name": "", + "meta.helm.sh/release-namespace": "", + }, + "creationTimestamp": "2022-04-11T22:05:27Z", + "name": "fleet-agent", + "namespace": "cattle-fleet-local-system", + "resourceVersion": "36948", + "uid": "1c497934-52cb-42ab-a613-dedfd5fb207b", + }, + "spec": map[string]interface{}{ + "replicas": 1, + }, + }, + }, + }, + { + name: "exclude invalid value", + request: &types.APIRequest{ + Query: url.Values{ + "excludeValues": []string{"foo.bar"}, + }, + }, + unstr: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "creationTimestamp": "2022-04-11T22:05:27Z", + "name": "kube-root-ca.crt", + "namespace": "c-m-w466b2vg", + "resourceVersion": "36948", + "uid": "1c497934-52cb-42ab-a613-dedfd5fb207b", + }, + "data": map[string]interface{}{ + "ca.crt": "-----BEGIN CERTIFICATE-----\nMIIC5zCCAc+gAwIBAg\n-----END CERTIFICATE-----\n", + }, + }, + }, + want: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "creationTimestamp": "2022-04-11T22:05:27Z", + "name": "kube-root-ca.crt", + "namespace": "c-m-w466b2vg", + "resourceVersion": "36948", + "uid": "1c497934-52cb-42ab-a613-dedfd5fb207b", + }, + "data": map[string]interface{}{ + "ca.crt": "-----BEGIN CERTIFICATE-----\nMIIC5zCCAc+gAwIBAg\n-----END CERTIFICATE-----\n", + }, + }, + }, + }, + { + name: "exclude multiple values", + request: &types.APIRequest{ + Query: url.Values{ + "excludeValues": []string{"metadata.annotations", "metadata.labels"}, + }, + }, + unstr: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "annotations": map[string]interface{}{ + "deployment.kubernetes.io/revision": "2", + "meta.helm.sh/release-name": "fleet-agent-local", + "meta.helm.sh/release-namespace": "cattle-fleet-local-system", + }, + "labels": map[string]interface{}{ + "app.kubernetes.io/managed-by": "Helm", + "objectset.rio.cattle.io/hash": "362023f752e7f1989d8b652e029bd2c658ae7c44", + }, + "creationTimestamp": "2022-04-11T22:05:27Z", + "name": "fleet-agent", + "namespace": "cattle-fleet-local-system", + "resourceVersion": "36948", + "uid": "1c497934-52cb-42ab-a613-dedfd5fb207b", + }, + "spec": map[string]interface{}{ + "replicas": 1, + }, + }, + }, + want: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "annotations": map[string]interface{}{ + "deployment.kubernetes.io/revision": "", + "meta.helm.sh/release-name": "", + "meta.helm.sh/release-namespace": "", + }, + "labels": map[string]interface{}{ + "app.kubernetes.io/managed-by": "", + "objectset.rio.cattle.io/hash": "", + }, + "creationTimestamp": "2022-04-11T22:05:27Z", + "name": "fleet-agent", + "namespace": "cattle-fleet-local-system", + "resourceVersion": "36948", + "uid": "1c497934-52cb-42ab-a613-dedfd5fb207b", + }, + "spec": map[string]interface{}{ + "replicas": 1, + }, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + excludeValues(tt.request, tt.unstr) + assert.Equal(t, tt.want, tt.unstr) + }) + } +}