Skip to content

FakeClient update on status subresource not returning error despite conflicting resource version since v0.15.0 #2362

Closed

Description

@nbam-e

After upgrading to controller-runtime 0.15.0 one of our unit tests started failing.
The tested controller performs a client.Status().Update(...) on Pod resources. The now failing unit test aims to test the controller behavior in case of a resource conflict (i.e. The fake client has a pod object, the controller performs a status update on the same pod object, but with a different resource version -> expected behavior: Conflict error, actual behavior since upgrading to 0.15.0: no error).

This can be reproduced with the following testcase: (controller-runtime 0.15.0, k8s api 0.27.2)

func Test_FakeStatusUpdate(t *testing.T) {
	pod := &corev1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Namespace:       "test",
			Name:            "test",
			ResourceVersion: "1",
		},
	}

	c := fake.NewClientBuilder().
		WithRuntimeObjects(pod).
		Build()

	pod.Status.Phase = "testphase"
	pod.ResourceVersion = "2"
	err := c.Status().Update(context.Background(), pod)
	if err == nil {
		t.Fatal("Expected conflict error, but got nil")
	}
}

I think it happens because the result of SetResourceVersion is immediately overwritten again by fromMapStringAny.

There appears to be a unit test for this case, but it doesn't fail because it uses client.Update(...) instead of client.Status().Update(...). https://github.com/kubernetes-sigs/controller-runtime/blob/30eae58f1b984c1b8139dd9b9f68dd2d530ed429/pkg/client/fake/client_test.go#LL1441C2-L1441C2

Related PR: #2259

Activity

  1. changed the title [-]FakeClient update on status subresource not returning error despite conflicting resource version[/-] [+]FakeClient update on status subresource not returning error despite conflicting resource version since 0.15.0[/+] on May 30, 2023
  2. changed the title [-]FakeClient update on status subresource not returning error despite conflicting resource version since 0.15.0[/-] [+]FakeClient update on status subresource not returning error despite conflicting resource version since v0.15.0[/+] on May 30, 2023
  3. sbueringer commented on May 31, 2023

    @sbueringer
    Member

    Agree, sounds like a bug

  4. added a commit that references this issue on May 31, 2023
    c9a6761
  5. iiiceoo commented on May 31, 2023

    @iiiceoo
    Contributor

    /assign

  6. added 2 commits that reference this issue on May 31, 2023
    1f5ad49
    d505e4b
  7. AmFlint commented on Jun 23, 2023

    @AmFlint

    Hello, I encountered the exact same issue.

    While I'm waiting for a fix to be released, I rolled back my controller-runtime to use 0.14.6 (with all k8s go libs using 0.26.1) and it works for now...

  8. sbueringer commented on Jul 1, 2023

    @sbueringer
    Member

    @AmFlint Did the fix implemented in #2365 work for you?

  9. RealAnna commented on Jul 12, 2023

    @RealAnna

    @sbueringer this did not work entirely for us. With the new changes we still had to explicitly add our crds as Statussubresurce to be able to use status updates.
    https://github.com/keptn/lifecycle-toolkit/pull/1701/files#diff-a1bebf6a5efdcbe0c8bd59ac1387c9d1f80f42781e1dc463cdc121222dafa089R17

    Generating the client and adding a resource with client.Create() does not work as before.
    All tests return a status not found since the object is not added to the StatusSubresource.

  10. austincunningham commented on Jul 14, 2023

    @austincunningham

    Same issue using #2365 didn't fix the issue

    replace sigs.k8s.io/controller-runtime => github.com/kubernetes-sigs/controller-runtime v0.15.1-0.20230602030726-6c1419808849
    
  11. troy0820 commented on Aug 25, 2023

    @troy0820
    Member

    /kind bug

    With the release of v0.16.0 did this not work? I see above that the #2365 wasn't successful but wanted to know if anything else in that release fixed this issue.

  12. troy0820 commented on Aug 29, 2023

    @troy0820
    Member

    Re-doing this test like this:

     func Test_FakeStatusUpdate(t *testing.T) {
        pod := &corev1.Pod{
          ObjectMeta: metav1.ObjectMeta{
            Namespace:       "test",
            Name:            "test",
            ResourceVersion: "1",
          },
        }
     
        c := fake.NewClientBuilder().
          WithRuntimeObjects(pod).WithStatusSubresource(pod).
          Build()
     
        pod.Status.Phase = "testphase"
        pod.ResourceVersion = "2"
        err := c.Status().Update(context.Background(), pod)
        if err == nil {
          t.Fatal("Expected conflict error, but got nil")
        }
      }

    now passes with the intended error as before.

    The snippet was updated here

    Doing a subsequent Get of the pod will show that the pod is not updated with no status.Phase and resourceVersion of 1.

    This test is running against controller-runtime v0.16.0 and go1.20

    Does this help @nbam-e ?

  13. 3 remaining items

  14. ericabramov commented on Nov 16, 2023

    @ericabramov

    I've came up with a hacky workaround that solved the gap for me
    A POC code is posted in this stackoverflow thread

    https://stackoverflow.com/questions/77489441/go-k8s-controller-runtime-upgrade-fake-client-lacks-functionality

  15. filanov commented on Nov 19, 2023

    @filanov

    Is there another workaround for this? my test is trying to check a status change on a reconcile, meaning i cannot provide WithStatusSubresource when creating the client because this is what the test need to validate.
    I saw that update just update everything including the status but it's a bad solution because a real client doesn't behave that way.

    Is there a workaround? or another client that i can use?
    I was thinking maybe wrap the client and override the Status().Update() function to call Update in the tests but it sounds like a fix to the fake client would be better.

    In older versions (0.13.x) it worked as expected why did that flow changed?

  16. alvaroaleman commented on Dec 2, 2023

    @alvaroaleman
    Member

    The original issue was fixed and the latter discussion seems to evolve around the question of how to configure a CRD to have a status subresource in the fake client. The tl,dr on how to configure the fakeclient to provide a status subresource for a given resource is to do the following:

    fake.NewClientBuilder().WithStatusSubresource(&MyType{}).Build()
    

    If this is needed or not can not be automatically inferred, refer to #2386 (comment) as for why.

    As the original issue was fixed, I am going to close this. Please limit discussions on this issue to the bug it was created for and that was since fixed.

  17. added a commit that references this issue on Jan 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

kind/bugCategorizes issue or PR as related to a bug.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions