Skip to content

Commit 595f569

Browse files
authored
Merge pull request #2147 from inteon/watch
✨ Improve unstructured serialisation
2 parents dd6bafd + fa6aa54 commit 595f569

File tree

3 files changed

+22
-34
lines changed

3 files changed

+22
-34
lines changed

pkg/client/apiutil/apimachinery.go

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
"k8s.io/apimachinery/pkg/runtime/schema"
3232
"k8s.io/apimachinery/pkg/runtime/serializer"
3333
"k8s.io/client-go/discovery"
34+
"k8s.io/client-go/dynamic"
3435
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
3536
"k8s.io/client-go/rest"
3637
"k8s.io/client-go/restmapper"
@@ -153,19 +154,6 @@ func RESTClientForGVK(gvk schema.GroupVersionKind, isUnstructured bool, baseConf
153154
return rest.RESTClientFor(createRestConfig(gvk, isUnstructured, baseConfig, codecs))
154155
}
155156

156-
// serializerWithDecodedGVK is a CodecFactory that overrides the DecoderToVersion of a WithoutConversionCodecFactory
157-
// in order to avoid clearing the GVK from the decoded object.
158-
//
159-
// See https://github.com/kubernetes/kubernetes/issues/80609.
160-
type serializerWithDecodedGVK struct {
161-
serializer.WithoutConversionCodecFactory
162-
}
163-
164-
// DecoderToVersion returns an decoder that does not do conversion.
165-
func (f serializerWithDecodedGVK) DecoderToVersion(serializer runtime.Decoder, _ runtime.GroupVersioner) runtime.Decoder {
166-
return serializer
167-
}
168-
169157
// createRestConfig copies the base config and updates needed fields for a new rest config.
170158
func createRestConfig(gvk schema.GroupVersionKind, isUnstructured bool, baseConfig *rest.Config, codecs serializer.CodecFactory) *rest.Config {
171159
gv := gvk.GroupVersion()
@@ -190,9 +178,8 @@ func createRestConfig(gvk schema.GroupVersionKind, isUnstructured bool, baseConf
190178
}
191179

192180
if isUnstructured {
193-
// If the object is unstructured, we need to preserve the GVK information.
194-
// Use our own custom serializer.
195-
cfg.NegotiatedSerializer = serializerWithDecodedGVK{serializer.WithoutConversionCodecFactory{CodecFactory: codecs}}
181+
// If the object is unstructured, we use the client-go dynamic serializer.
182+
cfg = dynamic.ConfigFor(cfg)
196183
} else {
197184
cfg.NegotiatedSerializer = serializerWithTargetZeroingDecode{NegotiatedSerializer: serializer.WithoutConversionCodecFactory{CodecFactory: codecs}}
198185
}

pkg/client/watch.go

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2424
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2525
"k8s.io/apimachinery/pkg/watch"
26-
"k8s.io/client-go/dynamic"
2726
"k8s.io/client-go/rest"
2827
)
2928

@@ -33,16 +32,11 @@ func NewWithWatch(config *rest.Config, options Options) (WithWatch, error) {
3332
if err != nil {
3433
return nil, err
3534
}
36-
dynamicClient, err := dynamic.NewForConfig(config)
37-
if err != nil {
38-
return nil, err
39-
}
40-
return &watchingClient{client: client, dynamic: dynamicClient}, nil
35+
return &watchingClient{client: client}, nil
4136
}
4237

4338
type watchingClient struct {
4439
*client
45-
dynamic dynamic.Interface
4640
}
4741

4842
func (w *watchingClient) Watch(ctx context.Context, list ObjectList, opts ...ListOption) (watch.Interface, error) {
@@ -82,20 +76,18 @@ func (w *watchingClient) metadataWatch(ctx context.Context, obj *metav1.PartialO
8276
}
8377

8478
func (w *watchingClient) unstructuredWatch(ctx context.Context, obj *unstructured.UnstructuredList, opts ...ListOption) (watch.Interface, error) {
85-
gvk := obj.GroupVersionKind()
86-
gvk.Kind = strings.TrimSuffix(gvk.Kind, "List")
87-
8879
r, err := w.client.unstructuredClient.resources.getResource(obj)
8980
if err != nil {
9081
return nil, err
9182
}
9283

9384
listOpts := w.listOpts(opts...)
9485

95-
if listOpts.Namespace != "" && r.isNamespaced() {
96-
return w.dynamic.Resource(r.mapping.Resource).Namespace(listOpts.Namespace).Watch(ctx, *listOpts.AsListOptions())
97-
}
98-
return w.dynamic.Resource(r.mapping.Resource).Watch(ctx, *listOpts.AsListOptions())
86+
return r.Get().
87+
NamespaceIfScoped(listOpts.Namespace, r.isNamespaced()).
88+
Resource(r.resource()).
89+
VersionedParams(listOpts.AsListOptions(), w.client.unstructuredClient.paramCodec).
90+
Watch(ctx)
9991
}
10092

10193
func (w *watchingClient) typedWatch(ctx context.Context, obj ObjectList, opts ...ListOption) (watch.Interface, error) {

pkg/client/watch_test.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ var _ = Describe("ClientWithWatch", func() {
7272
Expect(cl).NotTo(BeNil())
7373
})
7474

75-
watchSuite := func(through client.ObjectList, expectedType client.Object) {
75+
watchSuite := func(through client.ObjectList, expectedType client.Object, checkGvk bool) {
7676
cl, err := client.NewWithWatch(cfg, client.Options{})
7777
Expect(err).NotTo(HaveOccurred())
7878
Expect(cl).NotTo(BeNil())
@@ -99,10 +99,19 @@ var _ = Describe("ClientWithWatch", func() {
9999
Expect(metaObject.GetName()).To(Equal(dep.Name))
100100
Expect(metaObject.GetUID()).To(Equal(dep.UID))
101101

102+
if checkGvk {
103+
runtimeObject := event.Object
104+
gvk := runtimeObject.GetObjectKind().GroupVersionKind()
105+
Expect(gvk).To(Equal(schema.GroupVersionKind{
106+
Group: "apps",
107+
Kind: "Deployment",
108+
Version: "v1",
109+
}))
110+
}
102111
}
103112

104113
It("should receive a create event when watching the typed object", func() {
105-
watchSuite(&appsv1.DeploymentList{}, &appsv1.Deployment{})
114+
watchSuite(&appsv1.DeploymentList{}, &appsv1.Deployment{}, false)
106115
})
107116

108117
It("should receive a create event when watching the unstructured object", func() {
@@ -112,12 +121,12 @@ var _ = Describe("ClientWithWatch", func() {
112121
Kind: "Deployment",
113122
Version: "v1",
114123
})
115-
watchSuite(u, &unstructured.Unstructured{})
124+
watchSuite(u, &unstructured.Unstructured{}, true)
116125
})
117126

118127
It("should receive a create event when watching the metadata object", func() {
119128
m := &metav1.PartialObjectMetadataList{TypeMeta: metav1.TypeMeta{Kind: "Deployment", APIVersion: "apps/v1"}}
120-
watchSuite(m, &metav1.PartialObjectMetadata{})
129+
watchSuite(m, &metav1.PartialObjectMetadata{}, false)
121130
})
122131
})
123132

0 commit comments

Comments
 (0)