diff --git a/pkg/client/fake/client.go b/pkg/client/fake/client.go index 18dd639d1c..0a529175ed 100644 --- a/pkg/client/fake/client.go +++ b/pkg/client/fake/client.go @@ -400,9 +400,10 @@ func (t versionedTracker) update(gvr schema.GroupVersionResource, obj runtime.Ob if t.withStatusSubresource.Has(gvk) { if isStatus { // copy everything but status and metadata.ResourceVersion from original object - if err := copyNonStatusFrom(oldObject, obj); err != nil { + if err := copyStatusFrom(obj, oldObject); err != nil { return fmt.Errorf("failed to copy non-status field for object with status subresouce: %w", err) } + obj = oldObject.DeepCopyObject().(client.Object) } else { // copy status from original object if err := copyStatusFrom(oldObject, obj); err != nil { return fmt.Errorf("failed to copy the status for object with status subresource: %w", err) @@ -949,6 +950,7 @@ func dryPatch(action testing.PatchActionImpl, tracker testing.ObjectTracker) (ru return obj, nil } +//lint:ignore U1000 function is causing errors with status updates func copyNonStatusFrom(old, new runtime.Object) error { newClientObject, ok := new.(client.Object) if !ok { @@ -1108,30 +1110,12 @@ func (sw *fakeSubResourceClient) Create(ctx context.Context, obj client.Object, func (sw *fakeSubResourceClient) Update(ctx context.Context, obj client.Object, opts ...client.SubResourceUpdateOption) error { updateOptions := client.SubResourceUpdateOptions{} updateOptions.ApplyOptions(opts) - gvr, err := getGVRFromObject(obj, sw.client.scheme) - if err != nil { - return err - } - o, err := sw.client.tracker.Get(gvr, obj.GetNamespace(), obj.GetName()) - if err != nil { - return err - } - gvk, err := apiutil.GVKForObject(obj, sw.client.scheme) - if err != nil { - return err - } - body := o - if sw.client.tracker.withStatusSubresource.Has(gvk) { - err := copyStatusFrom(obj, body) - if err != nil { - return err - } - } - bodyObj := body.(client.Object) - if bodyObj.GetResourceVersion() != obj.GetResourceVersion() { - return apierrors.NewConflict(gvr.GroupResource(), obj.GetName(), fmt.Errorf("resource version conflict")) + + body := obj + if updateOptions.SubResourceBody != nil { + body = updateOptions.SubResourceBody } - return sw.client.update(bodyObj, true, &updateOptions.UpdateOptions) + return sw.client.update(body, true, &updateOptions.UpdateOptions) } func (sw *fakeSubResourceClient) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.SubResourcePatchOption) error { diff --git a/pkg/client/fake/client_test.go b/pkg/client/fake/client_test.go index 16eb04efb7..fed59c07dc 100644 --- a/pkg/client/fake/client_test.go +++ b/pkg/client/fake/client_test.go @@ -1479,6 +1479,36 @@ var _ = Describe("Fake client", func() { objOriginal.Status.NodeInfo.MachineID = "machine-id-from-status-update" Expect(cmp.Diff(objOriginal, actual)).To(BeEmpty()) }) + It("should not overwrite status fields of typed objects that have a status subresource on status update", func() { + obj := &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "node", + }, + Spec: corev1.NodeSpec{ + PodCIDR: "old-cidr", + }, + Status: corev1.NodeStatus{ + NodeInfo: corev1.NodeSystemInfo{ + MachineID: "machine-id", + }, + }, + } + cl := NewClientBuilder().WithStatusSubresource(obj).WithObjects(obj).Build() + objOriginal := obj.DeepCopy() + + obj.Status.Phase = corev1.NodeRunning + Expect(cl.Status().Update(context.Background(), obj)).NotTo(HaveOccurred()) + + actual := &corev1.Node{ObjectMeta: metav1.ObjectMeta{Name: obj.Name}} + Expect(cl.Get(context.Background(), client.ObjectKeyFromObject(actual), actual)).NotTo(HaveOccurred()) + + objOriginal.APIVersion = actual.APIVersion + objOriginal.Kind = actual.Kind + objOriginal.ResourceVersion = actual.ResourceVersion + Expect(cmp.Diff(objOriginal, actual)).ToNot(BeEmpty()) + Expect(objOriginal.Status.NodeInfo.MachineID).To(Equal(actual.Status.NodeInfo.MachineID)) + Expect(objOriginal.Status.Phase).ToNot(Equal(actual.Status.Phase)) + }) It("should not change the status of typed objects that have a status subresource on patch", func() { obj := &corev1.Node{