Skip to content

Commit 7beb556

Browse files
committed
🐛 Preserve GroupVersionKind during Update/Patch
Signed-off-by: Vince Prignano <[email protected]>
1 parent 8f633b1 commit 7beb556

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 ...CreateOptionFunc) 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 ...UpdateOptionFunc) 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...)
@@ -132,6 +144,7 @@ func (c *client) Delete(ctx context.Context, obj runtime.Object, opts ...DeleteO
132144

133145
// Patch implements client.Client
134146
func (c *client) Patch(ctx context.Context, obj runtime.Object, patch Patch, opts ...PatchOptionFunc) error {
147+
defer c.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
135148
_, ok := obj.(*unstructured.Unstructured)
136149
if ok {
137150
return c.unstructuredClient.Patch(ctx, obj, patch, opts...)
@@ -172,6 +185,7 @@ var _ StatusWriter = &statusWriter{}
172185

173186
// Update implements client.StatusWriter
174187
func (sw *statusWriter) Update(ctx context.Context, obj runtime.Object, opts ...UpdateOptionFunc) error {
188+
defer sw.client.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
175189
_, ok := obj.(*unstructured.Unstructured)
176190
if ok {
177191
return sw.client.unstructuredClient.UpdateStatus(ctx, obj, opts...)
@@ -181,6 +195,7 @@ func (sw *statusWriter) Update(ctx context.Context, obj runtime.Object, opts ...
181195

182196
// Patch implements client.Client
183197
func (sw *statusWriter) Patch(ctx context.Context, obj runtime.Object, patch Patch, opts ...PatchOptionFunc) error {
198+
defer sw.client.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
184199
_, ok := obj.(*unstructured.Unstructured)
185200
if ok {
186201
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())
@@ -1001,6 +1089,26 @@ var _ = Describe("Client", func() {
10011089
close(done)
10021090
})
10031091

1092+
It("should patch and preserve type information", func(done Done) {
1093+
cl, err := client.New(cfg, client.Options{})
1094+
Expect(err).NotTo(HaveOccurred())
1095+
Expect(cl).NotTo(BeNil())
1096+
1097+
By("initially creating a Deployment")
1098+
dep, err := clientset.AppsV1().Deployments(ns).Create(dep)
1099+
Expect(err).NotTo(HaveOccurred())
1100+
1101+
By("patching the Deployment")
1102+
dep.SetGroupVersionKind(depGvk)
1103+
err = cl.Patch(context.TODO(), dep, client.ConstantPatch(types.MergePatchType, mergePatch))
1104+
Expect(err).NotTo(HaveOccurred())
1105+
1106+
By("validating updated Deployment has type information")
1107+
Expect(dep.GroupVersionKind()).To(Equal(depGvk))
1108+
1109+
close(done)
1110+
})
1111+
10041112
It("should patch an existing object non-namespace object from a go struct", func(done Done) {
10051113
cl, err := client.New(cfg, client.Options{})
10061114
Expect(err).NotTo(HaveOccurred())
@@ -1115,6 +1223,28 @@ var _ = Describe("Client", func() {
11151223
close(done)
11161224
})
11171225

1226+
It("should patch and preserve type information", func(done Done) {
1227+
cl, err := client.New(cfg, client.Options{})
1228+
Expect(err).NotTo(HaveOccurred())
1229+
Expect(cl).NotTo(BeNil())
1230+
1231+
By("initially creating a Deployment")
1232+
dep, err := clientset.AppsV1().Deployments(ns).Create(dep)
1233+
Expect(err).NotTo(HaveOccurred())
1234+
1235+
By("patching the Deployment")
1236+
u := &unstructured.Unstructured{}
1237+
Expect(scheme.Convert(dep, u, nil)).To(Succeed())
1238+
u.SetGroupVersionKind(depGvk)
1239+
err = cl.Patch(context.TODO(), u, client.ConstantPatch(types.MergePatchType, mergePatch))
1240+
Expect(err).NotTo(HaveOccurred())
1241+
1242+
By("validating updated Deployment has type information")
1243+
Expect(u.GroupVersionKind()).To(Equal(depGvk))
1244+
1245+
close(done)
1246+
})
1247+
11181248
It("should patch an existing object non-namespace object from a go struct", func(done Done) {
11191249
cl, err := client.New(cfg, client.Options{})
11201250
Expect(err).NotTo(HaveOccurred())

0 commit comments

Comments
 (0)