Skip to content

Commit 0f36a17

Browse files
committed
UPSTREAM: <carry>: make RESTMapper in client cluster-aware
Signed-off-by: Dr. Stefan Schimanski <stefan.schimanski@gmail.com>
1 parent a3df1ba commit 0f36a17

File tree

9 files changed

+149
-60
lines changed

9 files changed

+149
-60
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ require (
3131
)
3232

3333
require (
34+
github.com/hashicorp/golang-lru/v2 v2.0.7
3435
github.com/kcp-dev/apimachinery/v2 v2.0.0-alpha.0.0.20230926071920-57d168bcbe34
3536
github.com/kcp-dev/logicalcluster/v3 v3.0.5
3637
)

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
6565
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
6666
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
6767
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
68+
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
69+
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
6870
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
6971
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
7072
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=

pkg/client/client.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ type Options struct {
4747
// Mapper, if provided, will be used to map GroupVersionKinds to Resources
4848
Mapper meta.RESTMapper
4949

50+
// MapperWithContext, if provided, will be used to map GroupVersionKinds to Resources.
51+
// This overrides Mapper if set.
52+
MapperWithContext func(context.Context) (meta.RESTMapper, error)
53+
5054
// Cache, if provided, is used to read objects from the cache.
5155
Cache *CacheOptions
5256

@@ -170,11 +174,16 @@ func newClient(config *rest.Config, options Options) (*client, error) {
170174
}
171175
}
172176

177+
// Init a MapperWithContext if none provided
178+
if options.MapperWithContext == nil {
179+
options.MapperWithContext = func(context.Context) (meta.RESTMapper, error) { return options.Mapper, nil }
180+
}
181+
173182
resources := &clientRestResources{
174183
httpClient: options.HTTPClient,
175184
config: config,
176185
scheme: options.Scheme,
177-
mapper: options.Mapper,
186+
mapper: options.MapperWithContext,
178187
codecs: serializer.NewCodecFactory(options.Scheme),
179188

180189
structuredResourceByType: make(map[schema.GroupVersionKind]*resourceMeta),
@@ -197,7 +206,7 @@ func newClient(config *rest.Config, options Options) (*client, error) {
197206
},
198207
metadataClient: metadataClient{
199208
client: rawMetaClient,
200-
restMapper: options.Mapper,
209+
restMapper: options.MapperWithContext,
201210
},
202211
scheme: options.Scheme,
203212
mapper: options.Mapper,

pkg/client/client_rest_resources.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package client
1818

1919
import (
20+
"context"
2021
"net/http"
2122
"strings"
2223
"sync"
@@ -42,7 +43,7 @@ type clientRestResources struct {
4243
scheme *runtime.Scheme
4344

4445
// mapper maps GroupVersionKinds to Resources
45-
mapper meta.RESTMapper
46+
mapper func(ctx context.Context) (meta.RESTMapper, error)
4647

4748
// codecs are used to create a REST client for a gvk
4849
codecs serializer.CodecFactory
@@ -56,7 +57,7 @@ type clientRestResources struct {
5657

5758
// newResource maps obj to a Kubernetes Resource and constructs a client for that Resource.
5859
// If the object is a list, the resource represents the item's type instead.
59-
func (c *clientRestResources) newResource(gvk schema.GroupVersionKind, isList, isUnstructured bool) (*resourceMeta, error) {
60+
func (c *clientRestResources) newResource(ctx context.Context, gvk schema.GroupVersionKind, isList, isUnstructured bool) (*resourceMeta, error) {
6061
if strings.HasSuffix(gvk.Kind, "List") && isList {
6162
// if this was a list, treat it as a request for the item's resource
6263
gvk.Kind = gvk.Kind[:len(gvk.Kind)-4]
@@ -66,7 +67,11 @@ func (c *clientRestResources) newResource(gvk schema.GroupVersionKind, isList, i
6667
if err != nil {
6768
return nil, err
6869
}
69-
mapping, err := c.mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
70+
mapper, err := c.mapper(ctx)
71+
if err != nil {
72+
return nil, err
73+
}
74+
mapping, err := mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
7075
if err != nil {
7176
return nil, err
7277
}
@@ -75,7 +80,7 @@ func (c *clientRestResources) newResource(gvk schema.GroupVersionKind, isList, i
7580

7681
// getResource returns the resource meta information for the given type of object.
7782
// If the object is a list, the resource represents the item's type instead.
78-
func (c *clientRestResources) getResource(obj runtime.Object) (*resourceMeta, error) {
83+
func (c *clientRestResources) getResource(ctx context.Context, obj runtime.Object) (*resourceMeta, error) {
7984
gvk, err := apiutil.GVKForObject(obj, c.scheme)
8085
if err != nil {
8186
return nil, err
@@ -100,7 +105,7 @@ func (c *clientRestResources) getResource(obj runtime.Object) (*resourceMeta, er
100105
// Initialize a new Client
101106
c.mu.Lock()
102107
defer c.mu.Unlock()
103-
r, err = c.newResource(gvk, meta.IsListType(obj), isUnstructured)
108+
r, err = c.newResource(ctx, gvk, meta.IsListType(obj), isUnstructured)
104109
if err != nil {
105110
return nil, err
106111
}
@@ -109,8 +114,8 @@ func (c *clientRestResources) getResource(obj runtime.Object) (*resourceMeta, er
109114
}
110115

111116
// getObjMeta returns objMeta containing both type and object metadata and state.
112-
func (c *clientRestResources) getObjMeta(obj runtime.Object) (*objMeta, error) {
113-
r, err := c.getResource(obj)
117+
func (c *clientRestResources) getObjMeta(ctx context.Context, obj runtime.Object) (*objMeta, error) {
118+
r, err := c.getResource(ctx, obj)
114119
if err != nil {
115120
return nil, err
116121
}

pkg/client/metadata_client.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,15 @@ import (
3535
// metadataClient is a client that reads & writes metadata-only requests to/from the API server.
3636
type metadataClient struct {
3737
client metadata.Interface
38-
restMapper meta.RESTMapper
38+
restMapper func(ctx context.Context) (meta.RESTMapper, error)
3939
}
4040

41-
func (mc *metadataClient) getResourceInterface(gvk schema.GroupVersionKind, ns string) (metadata.ResourceInterface, error) {
42-
mapping, err := mc.restMapper.RESTMapping(gvk.GroupKind(), gvk.Version)
41+
func (mc *metadataClient) getResourceInterface(ctx context.Context, gvk schema.GroupVersionKind, ns string) (metadata.ResourceInterface, error) {
42+
mapper, err := mc.restMapper(ctx)
43+
if err != nil {
44+
return nil, err
45+
}
46+
mapping, err := mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
4347
if err != nil {
4448
return nil, err
4549
}
@@ -56,7 +60,7 @@ func (mc *metadataClient) Delete(ctx context.Context, obj Object, opts ...Delete
5660
return fmt.Errorf("metadata client did not understand object: %T", obj)
5761
}
5862

59-
resInt, err := mc.getResourceInterface(metadata.GroupVersionKind(), metadata.Namespace)
63+
resInt, err := mc.getResourceInterface(ctx, metadata.GroupVersionKind(), metadata.Namespace)
6064
if err != nil {
6165
return err
6266
}
@@ -77,7 +81,7 @@ func (mc *metadataClient) DeleteAllOf(ctx context.Context, obj Object, opts ...D
7781
deleteAllOfOpts := DeleteAllOfOptions{}
7882
deleteAllOfOpts.ApplyOptions(opts)
7983

80-
resInt, err := mc.getResourceInterface(metadata.GroupVersionKind(), deleteAllOfOpts.ListOptions.Namespace)
84+
resInt, err := mc.getResourceInterface(ctx, metadata.GroupVersionKind(), deleteAllOfOpts.ListOptions.Namespace)
8185
if err != nil {
8286
return err
8387
}
@@ -93,7 +97,7 @@ func (mc *metadataClient) Patch(ctx context.Context, obj Object, patch Patch, op
9397
}
9498

9599
gvk := metadata.GroupVersionKind()
96-
resInt, err := mc.getResourceInterface(gvk, metadata.Namespace)
100+
resInt, err := mc.getResourceInterface(ctx, gvk, metadata.Namespace)
97101
if err != nil {
98102
return err
99103
}
@@ -127,7 +131,7 @@ func (mc *metadataClient) Get(ctx context.Context, key ObjectKey, obj Object, op
127131
getOpts := GetOptions{}
128132
getOpts.ApplyOptions(opts)
129133

130-
resInt, err := mc.getResourceInterface(gvk, key.Namespace)
134+
resInt, err := mc.getResourceInterface(ctx, gvk, key.Namespace)
131135
if err != nil {
132136
return err
133137
}
@@ -154,7 +158,7 @@ func (mc *metadataClient) List(ctx context.Context, obj ObjectList, opts ...List
154158
listOpts := ListOptions{}
155159
listOpts.ApplyOptions(opts)
156160

157-
resInt, err := mc.getResourceInterface(gvk, listOpts.Namespace)
161+
resInt, err := mc.getResourceInterface(ctx, gvk, listOpts.Namespace)
158162
if err != nil {
159163
return err
160164
}
@@ -175,7 +179,7 @@ func (mc *metadataClient) PatchSubResource(ctx context.Context, obj Object, subR
175179
}
176180

177181
gvk := metadata.GroupVersionKind()
178-
resInt, err := mc.getResourceInterface(gvk, metadata.Namespace)
182+
resInt, err := mc.getResourceInterface(ctx, gvk, metadata.Namespace)
179183
if err != nil {
180184
return err
181185
}

pkg/client/typed_client.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ type typedClient struct {
3232

3333
// Create implements client.Client.
3434
func (c *typedClient) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
35-
o, err := c.resources.getObjMeta(obj)
35+
o, err := c.resources.getObjMeta(ctx, obj)
3636
if err != nil {
3737
return err
3838
}
@@ -51,7 +51,7 @@ func (c *typedClient) Create(ctx context.Context, obj Object, opts ...CreateOpti
5151

5252
// Update implements client.Client.
5353
func (c *typedClient) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
54-
o, err := c.resources.getObjMeta(obj)
54+
o, err := c.resources.getObjMeta(ctx, obj)
5555
if err != nil {
5656
return err
5757
}
@@ -71,7 +71,7 @@ func (c *typedClient) Update(ctx context.Context, obj Object, opts ...UpdateOpti
7171

7272
// Delete implements client.Client.
7373
func (c *typedClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
74-
o, err := c.resources.getObjMeta(obj)
74+
o, err := c.resources.getObjMeta(ctx, obj)
7575
if err != nil {
7676
return err
7777
}
@@ -90,7 +90,7 @@ func (c *typedClient) Delete(ctx context.Context, obj Object, opts ...DeleteOpti
9090

9191
// DeleteAllOf implements client.Client.
9292
func (c *typedClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
93-
o, err := c.resources.getObjMeta(obj)
93+
o, err := c.resources.getObjMeta(ctx, obj)
9494
if err != nil {
9595
return err
9696
}
@@ -109,7 +109,7 @@ func (c *typedClient) DeleteAllOf(ctx context.Context, obj Object, opts ...Delet
109109

110110
// Patch implements client.Client.
111111
func (c *typedClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
112-
o, err := c.resources.getObjMeta(obj)
112+
o, err := c.resources.getObjMeta(ctx, obj)
113113
if err != nil {
114114
return err
115115
}
@@ -134,7 +134,7 @@ func (c *typedClient) Patch(ctx context.Context, obj Object, patch Patch, opts .
134134

135135
// Get implements client.Client.
136136
func (c *typedClient) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error {
137-
r, err := c.resources.getResource(obj)
137+
r, err := c.resources.getResource(ctx, obj)
138138
if err != nil {
139139
return err
140140
}
@@ -149,7 +149,7 @@ func (c *typedClient) Get(ctx context.Context, key ObjectKey, obj Object, opts .
149149

150150
// List implements client.Client.
151151
func (c *typedClient) List(ctx context.Context, obj ObjectList, opts ...ListOption) error {
152-
r, err := c.resources.getResource(obj)
152+
r, err := c.resources.getResource(ctx, obj)
153153
if err != nil {
154154
return err
155155
}
@@ -166,7 +166,7 @@ func (c *typedClient) List(ctx context.Context, obj ObjectList, opts ...ListOpti
166166
}
167167

168168
func (c *typedClient) GetSubResource(ctx context.Context, obj, subResourceObj Object, subResource string, opts ...SubResourceGetOption) error {
169-
o, err := c.resources.getObjMeta(obj)
169+
o, err := c.resources.getObjMeta(ctx, obj)
170170
if err != nil {
171171
return err
172172
}
@@ -189,7 +189,7 @@ func (c *typedClient) GetSubResource(ctx context.Context, obj, subResourceObj Ob
189189
}
190190

191191
func (c *typedClient) CreateSubResource(ctx context.Context, obj Object, subResourceObj Object, subResource string, opts ...SubResourceCreateOption) error {
192-
o, err := c.resources.getObjMeta(obj)
192+
o, err := c.resources.getObjMeta(ctx, obj)
193193
if err != nil {
194194
return err
195195
}
@@ -214,7 +214,7 @@ func (c *typedClient) CreateSubResource(ctx context.Context, obj Object, subReso
214214

215215
// UpdateSubResource used by SubResourceWriter to write status.
216216
func (c *typedClient) UpdateSubResource(ctx context.Context, obj Object, subResource string, opts ...SubResourceUpdateOption) error {
217-
o, err := c.resources.getObjMeta(obj)
217+
o, err := c.resources.getObjMeta(ctx, obj)
218218
if err != nil {
219219
return err
220220
}
@@ -249,7 +249,7 @@ func (c *typedClient) UpdateSubResource(ctx context.Context, obj Object, subReso
249249

250250
// PatchSubResource used by SubResourceWriter to write subresource.
251251
func (c *typedClient) PatchSubResource(ctx context.Context, obj Object, subResource string, patch Patch, opts ...SubResourcePatchOption) error {
252-
o, err := c.resources.getObjMeta(obj)
252+
o, err := c.resources.getObjMeta(ctx, obj)
253253
if err != nil {
254254
return err
255255
}

pkg/client/unstructured_client.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func (uc *unstructuredClient) Create(ctx context.Context, obj Object, opts ...Cr
4141

4242
gvk := u.GetObjectKind().GroupVersionKind()
4343

44-
o, err := uc.resources.getObjMeta(obj)
44+
o, err := uc.resources.getObjMeta(ctx, obj)
4545
if err != nil {
4646
return err
4747
}
@@ -70,7 +70,7 @@ func (uc *unstructuredClient) Update(ctx context.Context, obj Object, opts ...Up
7070

7171
gvk := u.GetObjectKind().GroupVersionKind()
7272

73-
o, err := uc.resources.getObjMeta(obj)
73+
o, err := uc.resources.getObjMeta(ctx, obj)
7474
if err != nil {
7575
return err
7676
}
@@ -97,7 +97,7 @@ func (uc *unstructuredClient) Delete(ctx context.Context, obj Object, opts ...De
9797
return fmt.Errorf("unstructured client did not understand object: %T", obj)
9898
}
9999

100-
o, err := uc.resources.getObjMeta(obj)
100+
o, err := uc.resources.getObjMeta(ctx, obj)
101101
if err != nil {
102102
return err
103103
}
@@ -120,7 +120,7 @@ func (uc *unstructuredClient) DeleteAllOf(ctx context.Context, obj Object, opts
120120
return fmt.Errorf("unstructured client did not understand object: %T", obj)
121121
}
122122

123-
o, err := uc.resources.getObjMeta(obj)
123+
o, err := uc.resources.getObjMeta(ctx, obj)
124124
if err != nil {
125125
return err
126126
}
@@ -143,7 +143,7 @@ func (uc *unstructuredClient) Patch(ctx context.Context, obj Object, patch Patch
143143
return fmt.Errorf("unstructured client did not understand object: %T", obj)
144144
}
145145

146-
o, err := uc.resources.getObjMeta(obj)
146+
o, err := uc.resources.getObjMeta(ctx, obj)
147147
if err != nil {
148148
return err
149149
}
@@ -178,7 +178,7 @@ func (uc *unstructuredClient) Get(ctx context.Context, key ObjectKey, obj Object
178178
getOpts := GetOptions{}
179179
getOpts.ApplyOptions(opts)
180180

181-
r, err := uc.resources.getResource(obj)
181+
r, err := uc.resources.getResource(ctx, obj)
182182
if err != nil {
183183
return err
184184
}
@@ -206,7 +206,7 @@ func (uc *unstructuredClient) List(ctx context.Context, obj ObjectList, opts ...
206206
gvk := u.GetObjectKind().GroupVersionKind()
207207
gvk.Kind = strings.TrimSuffix(gvk.Kind, "List")
208208

209-
r, err := uc.resources.getResource(obj)
209+
r, err := uc.resources.getResource(ctx, obj)
210210
if err != nil {
211211
return err
212212
}
@@ -235,7 +235,7 @@ func (uc *unstructuredClient) GetSubResource(ctx context.Context, obj, subResour
235235
subResourceObj.SetName(obj.GetName())
236236
}
237237

238-
o, err := uc.resources.getObjMeta(obj)
238+
o, err := uc.resources.getObjMeta(ctx, obj)
239239
if err != nil {
240240
return err
241241
}
@@ -266,7 +266,7 @@ func (uc *unstructuredClient) CreateSubResource(ctx context.Context, obj, subRes
266266
subResourceObj.SetName(obj.GetName())
267267
}
268268

269-
o, err := uc.resources.getObjMeta(obj)
269+
o, err := uc.resources.getObjMeta(ctx, obj)
270270
if err != nil {
271271
return err
272272
}
@@ -290,7 +290,7 @@ func (uc *unstructuredClient) UpdateSubResource(ctx context.Context, obj Object,
290290
return fmt.Errorf("unstructured client did not understand object: %T", obj)
291291
}
292292

293-
o, err := uc.resources.getObjMeta(obj)
293+
o, err := uc.resources.getObjMeta(ctx, obj)
294294
if err != nil {
295295
return err
296296
}
@@ -328,7 +328,7 @@ func (uc *unstructuredClient) PatchSubResource(ctx context.Context, obj Object,
328328

329329
gvk := u.GetObjectKind().GroupVersionKind()
330330

331-
o, err := uc.resources.getObjMeta(obj)
331+
o, err := uc.resources.getObjMeta(ctx, obj)
332332
if err != nil {
333333
return err
334334
}

0 commit comments

Comments
 (0)