Skip to content

Commit d357c36

Browse files
🐛 allow fakeclient to patch CR with no RV
\# Context This PR should fix a bug #2678 where patching a resource would throw a conflict error when the new object doesn't specify any RV. - Because the new RV is an empty string, an error is thrown here: https://github.com/kubernetes-sigs/controller-runtime/blob/01de80b092778fd35abd9e2371d54ce0953d4613/pkg/client/fake/client.go#L429-L430 - The RV is nil, because the computed patch between the old and new accessor doesn't include resourceVersion: - https://github.com/evanphx/json-patch/blob/v5.9.0/v5/merge.go#L253-L273 - Witch is used by `client.MergeFrom()`: https://github.com/kubernetes-sigs/controller-runtime/blob/v0.17.2/pkg/client/patch.go#L150-L152 \# Changes - Fix patch by setting the new accessors' RV to the old accessors' RV. - Add test to ensure the correct behavior
1 parent e08b286 commit d357c36

File tree

2 files changed

+34
-0
lines changed

2 files changed

+34
-0
lines changed

pkg/client/fake/client_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,38 @@ var _ = Describe("Fake client", func() {
550550
Expect(obj.ObjectMeta.ResourceVersion).To(Equal("1000"))
551551
})
552552

553+
It("should allow patch with non-set ResourceVersion for a resource that doesn't allow unconditional updates", func() {
554+
schemeBuilder := &scheme.Builder{GroupVersion: schema.GroupVersion{Group: "test", Version: "v1"}}
555+
schemeBuilder.Register(&WithPointerMeta{}, &WithPointerMetaList{})
556+
557+
scheme := runtime.NewScheme()
558+
Expect(schemeBuilder.AddToScheme(scheme)).NotTo(HaveOccurred())
559+
560+
cl := NewClientBuilder().WithScheme(scheme).Build()
561+
original := &WithPointerMeta{
562+
ObjectMeta: &metav1.ObjectMeta{
563+
Name: "obj",
564+
Namespace: "ns2",
565+
}}
566+
567+
err := cl.Create(context.Background(), original)
568+
Expect(err).ToNot(HaveOccurred())
569+
570+
newObj := &WithPointerMeta{
571+
ObjectMeta: &metav1.ObjectMeta{
572+
Name: original.Name,
573+
Namespace: original.Namespace,
574+
Annotations: map[string]string{
575+
"foo": "bar",
576+
},
577+
}}
578+
Expect(cl.Patch(context.Background(), newObj, client.MergeFrom(original))).To(Succeed())
579+
580+
patched := &WithPointerMeta{}
581+
Expect(cl.Get(context.Background(), client.ObjectKeyFromObject(original), patched)).To(Succeed())
582+
Expect(patched.Annotations).To(Equal(map[string]string{"foo": "bar"}))
583+
})
584+
553585
It("should reject updates with non-set ResourceVersion for a resource that doesn't allow unconditional updates", func() {
554586
By("Creating a new binding")
555587
binding := &corev1.Binding{

pkg/client/patch.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ func (s *mergeFromPatch) Data(obj Object) ([]byte, error) {
112112

113113
modified = modified.DeepCopyObject().(Object)
114114
modified.SetResourceVersion(version)
115+
} else if modified.GetResourceVersion() == "" {
116+
modified.SetResourceVersion(original.GetResourceVersion())
115117
}
116118

117119
originalJSON, err := json.Marshal(original)

0 commit comments

Comments
 (0)