Skip to content

Commit ee41a80

Browse files
authored
Merge pull request #528 from vincepri/fixup-gvk
🐛 Preserve GroupVersionKind during Update/Patch
2 parents bfba246 + cea57be commit ee41a80

File tree

2 files changed

+150
-5
lines changed

2 files changed

+150
-5
lines changed

pkg/client/client.go

+15
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"k8s.io/apimachinery/pkg/api/meta"
2525
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2626
"k8s.io/apimachinery/pkg/runtime"
27+
"k8s.io/apimachinery/pkg/runtime/schema"
2728
"k8s.io/apimachinery/pkg/runtime/serializer"
2829
"k8s.io/client-go/dynamic"
2930
"k8s.io/client-go/kubernetes/scheme"
@@ -103,6 +104,16 @@ type client struct {
103104
unstructuredClient unstructuredClient
104105
}
105106

107+
// resetGroupVersionKind is a helper function to restore and preserve GroupVersionKind on an object.
108+
// TODO(vincepri): Remove this function and its calls once controller-runtime dependencies are upgraded to 1.15.
109+
func (c *client) resetGroupVersionKind(obj runtime.Object, gvk schema.GroupVersionKind) {
110+
if gvk != schema.EmptyObjectKind.GroupVersionKind() {
111+
if v, ok := obj.(schema.ObjectKind); ok {
112+
v.SetGroupVersionKind(gvk)
113+
}
114+
}
115+
}
116+
106117
// Create implements client.Client
107118
func (c *client) Create(ctx context.Context, obj runtime.Object, opts ...CreateOption) error {
108119
_, ok := obj.(*unstructured.Unstructured)
@@ -114,6 +125,7 @@ func (c *client) Create(ctx context.Context, obj runtime.Object, opts ...CreateO
114125

115126
// Update implements client.Client
116127
func (c *client) Update(ctx context.Context, obj runtime.Object, opts ...UpdateOption) error {
128+
defer c.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
117129
_, ok := obj.(*unstructured.Unstructured)
118130
if ok {
119131
return c.unstructuredClient.Update(ctx, obj, opts...)
@@ -141,6 +153,7 @@ func (c *client) DeleteAllOf(ctx context.Context, obj runtime.Object, opts ...De
141153

142154
// Patch implements client.Client
143155
func (c *client) Patch(ctx context.Context, obj runtime.Object, patch Patch, opts ...PatchOption) error {
156+
defer c.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
144157
_, ok := obj.(*unstructured.Unstructured)
145158
if ok {
146159
return c.unstructuredClient.Patch(ctx, obj, patch, opts...)
@@ -181,6 +194,7 @@ var _ StatusWriter = &statusWriter{}
181194

182195
// Update implements client.StatusWriter
183196
func (sw *statusWriter) Update(ctx context.Context, obj runtime.Object, opts ...UpdateOption) error {
197+
defer sw.client.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
184198
_, ok := obj.(*unstructured.Unstructured)
185199
if ok {
186200
return sw.client.unstructuredClient.UpdateStatus(ctx, obj, opts...)
@@ -190,6 +204,7 @@ func (sw *statusWriter) Update(ctx context.Context, obj runtime.Object, opts ...
190204

191205
// Patch implements client.Client
192206
func (sw *statusWriter) Patch(ctx context.Context, obj runtime.Object, patch Patch, opts ...PatchOption) error {
207+
defer sw.client.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
193208
_, ok := obj.(*unstructured.Unstructured)
194209
if ok {
195210
return sw.client.unstructuredClient.PatchStatus(ctx, obj, patch, opts...)

pkg/client/client_test.go

+135-5
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ func deleteNamespace(ns *corev1.Namespace) {
5959
var _ = Describe("Client", func() {
6060

6161
var scheme *runtime.Scheme
62+
var depGvk schema.GroupVersionKind
6263
var dep *appsv1.Deployment
6364
var pod *corev1.Pod
6465
var node *corev1.Node
@@ -82,6 +83,11 @@ var _ = Describe("Client", func() {
8283
},
8384
},
8485
}
86+
depGvk = schema.GroupVersionKind{
87+
Group: "apps",
88+
Kind: "Deployment",
89+
Version: "v1",
90+
}
8591
// Pod is invalid without a container field in the PodSpec
8692
pod = &corev1.Pod{
8793
ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("pod-%v", count), Namespace: ns},
@@ -453,6 +459,26 @@ var _ = Describe("Client", func() {
453459
close(done)
454460
})
455461

462+
It("should update and preserve type information", func(done Done) {
463+
cl, err := client.New(cfg, client.Options{})
464+
Expect(err).NotTo(HaveOccurred())
465+
Expect(cl).NotTo(BeNil())
466+
467+
By("initially creating a Deployment")
468+
dep, err := clientset.AppsV1().Deployments(ns).Create(dep)
469+
Expect(err).NotTo(HaveOccurred())
470+
471+
By("updating the Deployment")
472+
dep.SetGroupVersionKind(depGvk)
473+
err = cl.Update(context.TODO(), dep)
474+
Expect(err).NotTo(HaveOccurred())
475+
476+
By("validating updated Deployment has type information")
477+
Expect(dep.GroupVersionKind()).To(Equal(depGvk))
478+
479+
close(done)
480+
})
481+
456482
It("should update an existing object non-namespace object from a go struct", func(done Done) {
457483
cl, err := client.New(cfg, client.Options{})
458484
Expect(err).NotTo(HaveOccurred())
@@ -550,6 +576,29 @@ var _ = Describe("Client", func() {
550576
close(done)
551577
})
552578

579+
It("should update and preserve type information", func(done Done) {
580+
cl, err := client.New(cfg, client.Options{})
581+
Expect(err).NotTo(HaveOccurred())
582+
Expect(cl).NotTo(BeNil())
583+
584+
By("initially creating a Deployment")
585+
dep, err := clientset.AppsV1().Deployments(ns).Create(dep)
586+
Expect(err).NotTo(HaveOccurred())
587+
588+
By("updating the Deployment")
589+
u := &unstructured.Unstructured{}
590+
Expect(scheme.Convert(dep, u, nil)).To(Succeed())
591+
u.SetGroupVersionKind(depGvk)
592+
u.SetAnnotations(map[string]string{"foo": "bar"})
593+
err = cl.Update(context.TODO(), u)
594+
Expect(err).NotTo(HaveOccurred())
595+
596+
By("validating updated Deployment has type information")
597+
Expect(u.GroupVersionKind()).To(Equal(depGvk))
598+
599+
close(done)
600+
})
601+
553602
It("should update an existing object non-namespace object from a go struct", func(done Done) {
554603
cl, err := client.New(cfg, client.Options{})
555604
Expect(err).NotTo(HaveOccurred())
@@ -586,11 +635,7 @@ var _ = Describe("Client", func() {
586635
By("updating non-existent object")
587636
u := &unstructured.Unstructured{}
588637
Expect(scheme.Convert(dep, u, nil)).To(Succeed())
589-
u.SetGroupVersionKind(schema.GroupVersionKind{
590-
Group: "apps",
591-
Kind: "Deployment",
592-
Version: "v1",
593-
})
638+
u.SetGroupVersionKind(depGvk)
594639
err = cl.Update(context.TODO(), dep)
595640
Expect(err).To(HaveOccurred())
596641

@@ -624,6 +669,49 @@ var _ = Describe("Client", func() {
624669
close(done)
625670
})
626671

672+
It("should update status and preserve type information", func(done Done) {
673+
cl, err := client.New(cfg, client.Options{})
674+
Expect(err).NotTo(HaveOccurred())
675+
Expect(cl).NotTo(BeNil())
676+
677+
By("initially creating a Deployment")
678+
dep, err := clientset.AppsV1().Deployments(ns).Create(dep)
679+
Expect(err).NotTo(HaveOccurred())
680+
681+
By("updating the status of Deployment")
682+
dep.SetGroupVersionKind(depGvk)
683+
dep.Status.Replicas = 1
684+
err = cl.Status().Update(context.TODO(), dep)
685+
Expect(err).NotTo(HaveOccurred())
686+
687+
By("validating updated Deployment has type information")
688+
Expect(dep.GroupVersionKind()).To(Equal(depGvk))
689+
690+
close(done)
691+
})
692+
693+
It("should patch status and preserve type information", func(done Done) {
694+
cl, err := client.New(cfg, client.Options{})
695+
Expect(err).NotTo(HaveOccurred())
696+
Expect(cl).NotTo(BeNil())
697+
698+
By("initially creating a Deployment")
699+
dep, err := clientset.AppsV1().Deployments(ns).Create(dep)
700+
Expect(err).NotTo(HaveOccurred())
701+
702+
By("patching the status of Deployment")
703+
dep.SetGroupVersionKind(depGvk)
704+
depPatch := client.MergeFrom(dep.DeepCopy())
705+
dep.Status.Replicas = 1
706+
err = cl.Status().Patch(context.TODO(), dep, depPatch)
707+
Expect(err).NotTo(HaveOccurred())
708+
709+
By("validating updated Deployment has type information")
710+
Expect(dep.GroupVersionKind()).To(Equal(depGvk))
711+
712+
close(done)
713+
})
714+
627715
It("should not update spec of an existing object", func(done Done) {
628716
cl, err := client.New(cfg, client.Options{})
629717
Expect(err).NotTo(HaveOccurred())
@@ -1070,6 +1158,26 @@ var _ = Describe("Client", func() {
10701158
close(done)
10711159
})
10721160

1161+
It("should patch and preserve type information", func(done Done) {
1162+
cl, err := client.New(cfg, client.Options{})
1163+
Expect(err).NotTo(HaveOccurred())
1164+
Expect(cl).NotTo(BeNil())
1165+
1166+
By("initially creating a Deployment")
1167+
dep, err := clientset.AppsV1().Deployments(ns).Create(dep)
1168+
Expect(err).NotTo(HaveOccurred())
1169+
1170+
By("patching the Deployment")
1171+
dep.SetGroupVersionKind(depGvk)
1172+
err = cl.Patch(context.TODO(), dep, client.ConstantPatch(types.MergePatchType, mergePatch))
1173+
Expect(err).NotTo(HaveOccurred())
1174+
1175+
By("validating updated Deployment has type information")
1176+
Expect(dep.GroupVersionKind()).To(Equal(depGvk))
1177+
1178+
close(done)
1179+
})
1180+
10731181
It("should patch an existing object non-namespace object from a go struct", func(done Done) {
10741182
cl, err := client.New(cfg, client.Options{})
10751183
Expect(err).NotTo(HaveOccurred())
@@ -1184,6 +1292,28 @@ var _ = Describe("Client", func() {
11841292
close(done)
11851293
})
11861294

1295+
It("should patch and preserve type information", func(done Done) {
1296+
cl, err := client.New(cfg, client.Options{})
1297+
Expect(err).NotTo(HaveOccurred())
1298+
Expect(cl).NotTo(BeNil())
1299+
1300+
By("initially creating a Deployment")
1301+
dep, err := clientset.AppsV1().Deployments(ns).Create(dep)
1302+
Expect(err).NotTo(HaveOccurred())
1303+
1304+
By("patching the Deployment")
1305+
u := &unstructured.Unstructured{}
1306+
Expect(scheme.Convert(dep, u, nil)).To(Succeed())
1307+
u.SetGroupVersionKind(depGvk)
1308+
err = cl.Patch(context.TODO(), u, client.ConstantPatch(types.MergePatchType, mergePatch))
1309+
Expect(err).NotTo(HaveOccurred())
1310+
1311+
By("validating updated Deployment has type information")
1312+
Expect(u.GroupVersionKind()).To(Equal(depGvk))
1313+
1314+
close(done)
1315+
})
1316+
11871317
It("should patch an existing object non-namespace object from a go struct", func(done Done) {
11881318
cl, err := client.New(cfg, client.Options{})
11891319
Expect(err).NotTo(HaveOccurred())

0 commit comments

Comments
 (0)