Skip to content

Commit 97958d9

Browse files
committed
Use content negotiation in the dynamic client.
1 parent 7f55109 commit 97958d9

File tree

2 files changed

+64
-123
lines changed

2 files changed

+64
-123
lines changed

staging/src/k8s.io/client-go/dynamic/scheme.go

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,18 @@ import (
2121
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2222
"k8s.io/apimachinery/pkg/runtime"
2323
"k8s.io/apimachinery/pkg/runtime/schema"
24-
"k8s.io/apimachinery/pkg/runtime/serializer"
2524
"k8s.io/apimachinery/pkg/runtime/serializer/json"
2625
)
2726

28-
var watchScheme = runtime.NewScheme()
2927
var basicScheme = runtime.NewScheme()
30-
var deleteScheme = runtime.NewScheme()
3128
var parameterScheme = runtime.NewScheme()
32-
var deleteOptionsCodec = serializer.NewCodecFactory(deleteScheme)
3329
var dynamicParameterCodec = runtime.NewParameterCodec(parameterScheme)
3430

3531
var versionV1 = schema.GroupVersion{Version: "v1"}
3632

3733
func init() {
38-
metav1.AddToGroupVersion(watchScheme, versionV1)
3934
metav1.AddToGroupVersion(basicScheme, versionV1)
4035
metav1.AddToGroupVersion(parameterScheme, versionV1)
41-
metav1.AddToGroupVersion(deleteScheme, versionV1)
4236
}
4337

4438
// basicNegotiatedSerializer is used to handle discovery and error handling serialization
@@ -66,7 +60,7 @@ func (s basicNegotiatedSerializer) EncoderForVersion(encoder runtime.Encoder, gv
6660
return runtime.WithVersionEncoder{
6761
Version: gv,
6862
Encoder: encoder,
69-
ObjectTyper: unstructuredTyper{basicScheme},
63+
ObjectTyper: permissiveTyper{basicScheme},
7064
}
7165
}
7266

@@ -106,3 +100,25 @@ func (t unstructuredTyper) ObjectKinds(obj runtime.Object) ([]schema.GroupVersio
106100
func (t unstructuredTyper) Recognizes(gvk schema.GroupVersionKind) bool {
107101
return true
108102
}
103+
104+
// The dynamic client has historically accepted Unstructured objects with missing or empty
105+
// apiVersion and/or kind as arguments to its write request methods. This typer will return the type
106+
// of a runtime.Unstructured with no error, even if the type is missing or empty.
107+
type permissiveTyper struct {
108+
nested runtime.ObjectTyper
109+
}
110+
111+
func (t permissiveTyper) ObjectKinds(obj runtime.Object) ([]schema.GroupVersionKind, bool, error) {
112+
kinds, unversioned, err := t.nested.ObjectKinds(obj)
113+
if err == nil {
114+
return kinds, unversioned, nil
115+
}
116+
if _, ok := obj.(runtime.Unstructured); ok {
117+
return []schema.GroupVersionKind{obj.GetObjectKind().GroupVersionKind()}, false, nil
118+
}
119+
return nil, false, err
120+
}
121+
122+
func (t permissiveTyper) Recognizes(gvk schema.GroupVersionKind) bool {
123+
return true
124+
}

staging/src/k8s.io/client-go/dynamic/simple.go

Lines changed: 41 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,10 @@ func NewForConfig(inConfig *rest.Config) (*DynamicClient, error) {
8686
// Note the http client provided takes precedence over the configured transport values.
8787
func NewForConfigAndClient(inConfig *rest.Config, h *http.Client) (*DynamicClient, error) {
8888
config := ConfigFor(inConfig)
89-
// for serializing the options
90-
config.GroupVersion = &schema.GroupVersion{}
89+
config.GroupVersion = nil
9190
config.APIPath = "/if-you-see-this-search-for-the-break"
9291

93-
restClient, err := rest.RESTClientForConfigAndClient(config, h)
92+
restClient, err := rest.UnversionedRESTClientForConfigAndClient(config, h)
9493
if err != nil {
9594
return nil, err
9695
}
@@ -114,10 +113,6 @@ func (c *dynamicResourceClient) Namespace(ns string) ResourceInterface {
114113
}
115114

116115
func (c *dynamicResourceClient) Create(ctx context.Context, obj *unstructured.Unstructured, opts metav1.CreateOptions, subresources ...string) (*unstructured.Unstructured, error) {
117-
outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
118-
if err != nil {
119-
return nil, err
120-
}
121116
name := ""
122117
if len(subresources) > 0 {
123118
accessor, err := meta.Accessor(obj)
@@ -133,26 +128,17 @@ func (c *dynamicResourceClient) Create(ctx context.Context, obj *unstructured.Un
133128
return nil, err
134129
}
135130

136-
result := c.client.client.
131+
var out unstructured.Unstructured
132+
if err := c.client.client.
137133
Post().
138134
AbsPath(append(c.makeURLSegments(name), subresources...)...).
139-
SetHeader("Content-Type", runtime.ContentTypeJSON).
140-
Body(outBytes).
135+
Body(obj).
141136
SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
142-
Do(ctx)
143-
if err := result.Error(); err != nil {
137+
Do(ctx).Into(&out); err != nil {
144138
return nil, err
145139
}
146140

147-
retBytes, err := result.Raw()
148-
if err != nil {
149-
return nil, err
150-
}
151-
uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
152-
if err != nil {
153-
return nil, err
154-
}
155-
return uncastObj.(*unstructured.Unstructured), nil
141+
return &out, nil
156142
}
157143

158144
func (c *dynamicResourceClient) Update(ctx context.Context, obj *unstructured.Unstructured, opts metav1.UpdateOptions, subresources ...string) (*unstructured.Unstructured, error) {
@@ -167,31 +153,18 @@ func (c *dynamicResourceClient) Update(ctx context.Context, obj *unstructured.Un
167153
if err := validateNamespaceWithOptionalName(c.namespace, name); err != nil {
168154
return nil, err
169155
}
170-
outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
171-
if err != nil {
172-
return nil, err
173-
}
174156

175-
result := c.client.client.
157+
var out unstructured.Unstructured
158+
if err := c.client.client.
176159
Put().
177160
AbsPath(append(c.makeURLSegments(name), subresources...)...).
178-
SetHeader("Content-Type", runtime.ContentTypeJSON).
179-
Body(outBytes).
161+
Body(obj).
180162
SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
181-
Do(ctx)
182-
if err := result.Error(); err != nil {
163+
Do(ctx).Into(&out); err != nil {
183164
return nil, err
184165
}
185166

186-
retBytes, err := result.Raw()
187-
if err != nil {
188-
return nil, err
189-
}
190-
uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
191-
if err != nil {
192-
return nil, err
193-
}
194-
return uncastObj.(*unstructured.Unstructured), nil
167+
return &out, nil
195168
}
196169

197170
func (c *dynamicResourceClient) UpdateStatus(ctx context.Context, obj *unstructured.Unstructured, opts metav1.UpdateOptions) (*unstructured.Unstructured, error) {
@@ -206,31 +179,18 @@ func (c *dynamicResourceClient) UpdateStatus(ctx context.Context, obj *unstructu
206179
if err := validateNamespaceWithOptionalName(c.namespace, name); err != nil {
207180
return nil, err
208181
}
209-
outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
210-
if err != nil {
211-
return nil, err
212-
}
213182

214-
result := c.client.client.
183+
var out unstructured.Unstructured
184+
if err := c.client.client.
215185
Put().
216186
AbsPath(append(c.makeURLSegments(name), "status")...).
217-
SetHeader("Content-Type", runtime.ContentTypeJSON).
218-
Body(outBytes).
187+
Body(obj).
219188
SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
220-
Do(ctx)
221-
if err := result.Error(); err != nil {
189+
Do(ctx).Into(&out); err != nil {
222190
return nil, err
223191
}
224192

225-
retBytes, err := result.Raw()
226-
if err != nil {
227-
return nil, err
228-
}
229-
uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
230-
if err != nil {
231-
return nil, err
232-
}
233-
return uncastObj.(*unstructured.Unstructured), nil
193+
return &out, nil
234194
}
235195

236196
func (c *dynamicResourceClient) Delete(ctx context.Context, name string, opts metav1.DeleteOptions, subresources ...string) error {
@@ -240,16 +200,11 @@ func (c *dynamicResourceClient) Delete(ctx context.Context, name string, opts me
240200
if err := validateNamespaceWithOptionalName(c.namespace, name); err != nil {
241201
return err
242202
}
243-
deleteOptionsByte, err := runtime.Encode(deleteOptionsCodec.LegacyCodec(schema.GroupVersion{Version: "v1"}), &opts)
244-
if err != nil {
245-
return err
246-
}
247203

248204
result := c.client.client.
249205
Delete().
250206
AbsPath(append(c.makeURLSegments(name), subresources...)...).
251-
SetHeader("Content-Type", runtime.ContentTypeJSON).
252-
Body(deleteOptionsByte).
207+
Body(&opts).
253208
Do(ctx)
254209
return result.Error()
255210
}
@@ -259,16 +214,10 @@ func (c *dynamicResourceClient) DeleteCollection(ctx context.Context, opts metav
259214
return err
260215
}
261216

262-
deleteOptionsByte, err := runtime.Encode(deleteOptionsCodec.LegacyCodec(schema.GroupVersion{Version: "v1"}), &opts)
263-
if err != nil {
264-
return err
265-
}
266-
267217
result := c.client.client.
268218
Delete().
269219
AbsPath(c.makeURLSegments("")...).
270-
SetHeader("Content-Type", runtime.ContentTypeJSON).
271-
Body(deleteOptionsByte).
220+
Body(&opts).
272221
SpecificallyVersionedParams(&listOptions, dynamicParameterCodec, versionV1).
273222
Do(ctx)
274223
return result.Error()
@@ -281,20 +230,15 @@ func (c *dynamicResourceClient) Get(ctx context.Context, name string, opts metav
281230
if err := validateNamespaceWithOptionalName(c.namespace, name); err != nil {
282231
return nil, err
283232
}
284-
result := c.client.client.Get().AbsPath(append(c.makeURLSegments(name), subresources...)...).SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).Do(ctx)
285-
if err := result.Error(); err != nil {
286-
return nil, err
287-
}
288-
retBytes, err := result.Raw()
289-
if err != nil {
290-
return nil, err
291-
}
292-
obj := &unstructured.Unstructured{}
293-
err = runtime.DecodeInto(unstructured.UnstructuredJSONScheme, retBytes, obj)
294-
if err != nil {
233+
var out unstructured.Unstructured
234+
if err := c.client.client.
235+
Get().
236+
AbsPath(append(c.makeURLSegments(name), subresources...)...).
237+
SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
238+
Do(ctx).Into(&out); err != nil {
295239
return nil, err
296240
}
297-
return obj, nil
241+
return &out, nil
298242
}
299243

300244
func (c *dynamicResourceClient) List(ctx context.Context, opts metav1.ListOptions) (*unstructured.UnstructuredList, error) {
@@ -319,27 +263,15 @@ func (c *dynamicResourceClient) list(ctx context.Context, opts metav1.ListOption
319263
if err := validateNamespaceWithOptionalName(c.namespace); err != nil {
320264
return nil, err
321265
}
322-
result := c.client.client.Get().AbsPath(c.makeURLSegments("")...).SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).Do(ctx)
323-
if err := result.Error(); err != nil {
324-
return nil, err
325-
}
326-
retBytes, err := result.Raw()
327-
if err != nil {
328-
return nil, err
329-
}
330-
uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
331-
if err != nil {
332-
return nil, err
333-
}
334-
if list, ok := uncastObj.(*unstructured.UnstructuredList); ok {
335-
return list, nil
336-
}
337-
338-
list, err := uncastObj.(*unstructured.Unstructured).ToList()
339-
if err != nil {
266+
var out unstructured.UnstructuredList
267+
if err := c.client.client.
268+
Get().
269+
AbsPath(c.makeURLSegments("")...).
270+
SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
271+
Do(ctx).Into(&out); err != nil {
340272
return nil, err
341273
}
342-
return list, nil
274+
return &out, nil
343275
}
344276

345277
// watchList establishes a watch stream with the server and returns an unstructured list.
@@ -380,24 +312,16 @@ func (c *dynamicResourceClient) Patch(ctx context.Context, name string, pt types
380312
if err := validateNamespaceWithOptionalName(c.namespace, name); err != nil {
381313
return nil, err
382314
}
383-
result := c.client.client.
315+
var out unstructured.Unstructured
316+
if err := c.client.client.
384317
Patch(pt).
385318
AbsPath(append(c.makeURLSegments(name), subresources...)...).
386319
Body(data).
387320
SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
388-
Do(ctx)
389-
if err := result.Error(); err != nil {
390-
return nil, err
391-
}
392-
retBytes, err := result.Raw()
393-
if err != nil {
321+
Do(ctx).Into(&out); err != nil {
394322
return nil, err
395323
}
396-
uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
397-
if err != nil {
398-
return nil, err
399-
}
400-
return uncastObj.(*unstructured.Unstructured), nil
324+
return &out, nil
401325
}
402326

403327
func (c *dynamicResourceClient) Apply(ctx context.Context, name string, obj *unstructured.Unstructured, opts metav1.ApplyOptions, subresources ...string) (*unstructured.Unstructured, error) {
@@ -435,12 +359,13 @@ func (c *dynamicResourceClient) Apply(ctx context.Context, name string, obj *uns
435359
if err != nil {
436360
return nil, err
437361
}
438-
uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
439-
if err != nil {
362+
var out unstructured.Unstructured
363+
if err := runtime.DecodeInto(unstructured.UnstructuredJSONScheme, retBytes, &out); err != nil {
440364
return nil, err
441365
}
442-
return uncastObj.(*unstructured.Unstructured), nil
366+
return &out, nil
443367
}
368+
444369
func (c *dynamicResourceClient) ApplyStatus(ctx context.Context, name string, obj *unstructured.Unstructured, opts metav1.ApplyOptions) (*unstructured.Unstructured, error) {
445370
return c.Apply(ctx, name, obj, opts, "status")
446371
}

0 commit comments

Comments
 (0)