Skip to content

Commit 9155fb5

Browse files
smarterclaytonk8s-publishing-bot
authored andcommitted
dynamic: The dynamic client no longer needs a special cased watch
By correctly handling content type negotiation, we can avoid the need for a special version of watch and use the same code path as typed clients. Kubernetes-commit: 3f94f80b0a79293e54d7080aaf7a64d7df8b1d4a
1 parent f1f7f7d commit 9155fb5

File tree

3 files changed

+45
-60
lines changed

3 files changed

+45
-60
lines changed

dynamic/client_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,8 @@ func TestWatch(t *testing.T) {
537537
t.Errorf("Watch(%q) got query %s. wanted %s", tc.name, r.URL.RawQuery, tc.query)
538538
}
539539

540+
w.Header().Set("Content-Type", "application/json")
541+
540542
enc := restclientwatch.NewEncoder(streaming.NewEncoder(w, unstructured.UnstructuredJSONScheme), unstructured.UnstructuredJSONScheme)
541543
for _, e := range tc.events {
542544
enc.Encode(&e)

dynamic/scheme.go

Lines changed: 42 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ package dynamic
1818

1919
import (
2020
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2122
"k8s.io/apimachinery/pkg/runtime"
2223
"k8s.io/apimachinery/pkg/runtime/schema"
2324
"k8s.io/apimachinery/pkg/runtime/serializer"
2425
"k8s.io/apimachinery/pkg/runtime/serializer/json"
25-
"k8s.io/apimachinery/pkg/runtime/serializer/versioning"
2626
)
2727

2828
var watchScheme = runtime.NewScheme()
@@ -41,37 +41,6 @@ func init() {
4141
metav1.AddToGroupVersion(deleteScheme, versionV1)
4242
}
4343

44-
var watchJsonSerializerInfo = runtime.SerializerInfo{
45-
MediaType: "application/json",
46-
MediaTypeType: "application",
47-
MediaTypeSubType: "json",
48-
EncodesAsText: true,
49-
Serializer: json.NewSerializer(json.DefaultMetaFactory, watchScheme, watchScheme, false),
50-
PrettySerializer: json.NewSerializer(json.DefaultMetaFactory, watchScheme, watchScheme, true),
51-
StreamSerializer: &runtime.StreamSerializerInfo{
52-
EncodesAsText: true,
53-
Serializer: json.NewSerializer(json.DefaultMetaFactory, watchScheme, watchScheme, false),
54-
Framer: json.Framer,
55-
},
56-
}
57-
58-
// watchNegotiatedSerializer is used to read the wrapper of the watch stream
59-
type watchNegotiatedSerializer struct{}
60-
61-
var watchNegotiatedSerializerInstance = watchNegotiatedSerializer{}
62-
63-
func (s watchNegotiatedSerializer) SupportedMediaTypes() []runtime.SerializerInfo {
64-
return []runtime.SerializerInfo{watchJsonSerializerInfo}
65-
}
66-
67-
func (s watchNegotiatedSerializer) EncoderForVersion(encoder runtime.Encoder, gv runtime.GroupVersioner) runtime.Encoder {
68-
return versioning.NewDefaultingCodecForScheme(watchScheme, encoder, nil, gv, nil)
69-
}
70-
71-
func (s watchNegotiatedSerializer) DecoderToVersion(decoder runtime.Decoder, gv runtime.GroupVersioner) runtime.Decoder {
72-
return versioning.NewDefaultingCodecForScheme(watchScheme, nil, decoder, nil, gv)
73-
}
74-
7544
// basicNegotiatedSerializer is used to handle discovery and error handling serialization
7645
type basicNegotiatedSerializer struct{}
7746

@@ -82,8 +51,8 @@ func (s basicNegotiatedSerializer) SupportedMediaTypes() []runtime.SerializerInf
8251
MediaTypeType: "application",
8352
MediaTypeSubType: "json",
8453
EncodesAsText: true,
85-
Serializer: json.NewSerializer(json.DefaultMetaFactory, basicScheme, basicScheme, false),
86-
PrettySerializer: json.NewSerializer(json.DefaultMetaFactory, basicScheme, basicScheme, true),
54+
Serializer: json.NewSerializer(json.DefaultMetaFactory, unstructuredCreater{basicScheme}, unstructuredTyper{basicScheme}, false),
55+
PrettySerializer: json.NewSerializer(json.DefaultMetaFactory, unstructuredCreater{basicScheme}, unstructuredTyper{basicScheme}, true),
8756
StreamSerializer: &runtime.StreamSerializerInfo{
8857
EncodesAsText: true,
8958
Serializer: json.NewSerializer(json.DefaultMetaFactory, basicScheme, basicScheme, false),
@@ -94,9 +63,46 @@ func (s basicNegotiatedSerializer) SupportedMediaTypes() []runtime.SerializerInf
9463
}
9564

9665
func (s basicNegotiatedSerializer) EncoderForVersion(encoder runtime.Encoder, gv runtime.GroupVersioner) runtime.Encoder {
97-
return versioning.NewDefaultingCodecForScheme(watchScheme, encoder, nil, gv, nil)
66+
return runtime.WithVersionEncoder{
67+
Version: gv,
68+
Encoder: encoder,
69+
ObjectTyper: unstructuredTyper{basicScheme},
70+
}
9871
}
9972

10073
func (s basicNegotiatedSerializer) DecoderToVersion(decoder runtime.Decoder, gv runtime.GroupVersioner) runtime.Decoder {
101-
return versioning.NewDefaultingCodecForScheme(watchScheme, nil, decoder, nil, gv)
74+
return decoder
75+
}
76+
77+
type unstructuredCreater struct {
78+
nested runtime.ObjectCreater
79+
}
80+
81+
func (c unstructuredCreater) New(kind schema.GroupVersionKind) (runtime.Object, error) {
82+
out, err := c.nested.New(kind)
83+
if err == nil {
84+
return out, nil
85+
}
86+
out = &unstructured.Unstructured{}
87+
out.GetObjectKind().SetGroupVersionKind(kind)
88+
return out, nil
89+
}
90+
91+
type unstructuredTyper struct {
92+
nested runtime.ObjectTyper
93+
}
94+
95+
func (t unstructuredTyper) ObjectKinds(obj runtime.Object) ([]schema.GroupVersionKind, bool, error) {
96+
kinds, unversioned, err := t.nested.ObjectKinds(obj)
97+
if err == nil {
98+
return kinds, unversioned, nil
99+
}
100+
if _, ok := obj.(runtime.Unstructured); ok && !obj.GetObjectKind().GroupVersionKind().Empty() {
101+
return []schema.GroupVersionKind{obj.GetObjectKind().GroupVersionKind()}, false, nil
102+
}
103+
return nil, false, err
104+
}
105+
106+
func (t unstructuredTyper) Recognizes(gvk schema.GroupVersionKind) bool {
107+
return true
102108
}

dynamic/simple.go

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,12 @@ package dynamic
1818

1919
import (
2020
"fmt"
21-
"io"
2221

2322
"k8s.io/apimachinery/pkg/api/meta"
2423
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2524
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2625
"k8s.io/apimachinery/pkg/runtime"
2726
"k8s.io/apimachinery/pkg/runtime/schema"
28-
"k8s.io/apimachinery/pkg/runtime/serializer/streaming"
2927
"k8s.io/apimachinery/pkg/types"
3028
"k8s.io/apimachinery/pkg/watch"
3129
"k8s.io/client-go/rest"
@@ -282,31 +280,10 @@ func (c *dynamicResourceClient) List(opts metav1.ListOptions) (*unstructured.Uns
282280
}
283281

284282
func (c *dynamicResourceClient) Watch(opts metav1.ListOptions) (watch.Interface, error) {
285-
internalGV := schema.GroupVersions{
286-
{Group: c.resource.Group, Version: runtime.APIVersionInternal},
287-
// always include the legacy group as a decoding target to handle non-error `Status` return types
288-
{Group: "", Version: runtime.APIVersionInternal},
289-
}
290-
s := &rest.Serializers{
291-
Encoder: watchNegotiatedSerializerInstance.EncoderForVersion(watchJsonSerializerInfo.Serializer, c.resource.GroupVersion()),
292-
Decoder: watchNegotiatedSerializerInstance.DecoderToVersion(watchJsonSerializerInfo.Serializer, internalGV),
293-
294-
RenegotiatedDecoder: func(contentType string, params map[string]string) (runtime.Decoder, error) {
295-
return watchNegotiatedSerializerInstance.DecoderToVersion(watchJsonSerializerInfo.Serializer, internalGV), nil
296-
},
297-
StreamingSerializer: watchJsonSerializerInfo.StreamSerializer.Serializer,
298-
Framer: watchJsonSerializerInfo.StreamSerializer.Framer,
299-
}
300-
301-
wrappedDecoderFn := func(body io.ReadCloser) streaming.Decoder {
302-
framer := s.Framer.NewFrameReader(body)
303-
return streaming.NewDecoder(framer, s.StreamingSerializer)
304-
}
305-
306283
opts.Watch = true
307284
return c.client.client.Get().AbsPath(c.makeURLSegments("")...).
308285
SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
309-
WatchWithSpecificDecoders(wrappedDecoderFn, unstructured.UnstructuredJSONScheme)
286+
Watch()
310287
}
311288

312289
func (c *dynamicResourceClient) Patch(name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (*unstructured.Unstructured, error) {

0 commit comments

Comments
 (0)