What happened?
The fake client's Create method generates a single random name when
GenerateName is set and does not retry on collision. If the generated
name matches an existing object in the tracker (including previously
deleted ones that the tracker still retains), it returns AlreadyExists
to the caller.
This causes flaky tests when many objects are created and deleted with
the same GenerateName prefix. With only a 5-character random suffix
(27^5 ≈ 14.3M possibilities), the birthday paradox makes collisions
likely at scale.
What did you expect to happen?
The fake client should match the real Kubernetes API server behavior.
Since Kubernetes 1.32, the RetryGenerateName feature gate is GA and
the API server retries up to 7 times on GenerateName collisions:
kubernetes/kubernetes#115489
The fake client should do the same — retry with a new random suffix
on AlreadyExists when GenerateName was used.
Relevant code
The current single-attempt logic is in pkg/client/fake/client.go
in the Create method:
https://github.com/kubernetes-sigs/controller-runtime/blob/main/pkg/client/fake/client.go#L877-L882
The real API server's retry implementation is in:
https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/apiserver/pkg/registry/generic/registry/store.go
(search for generateName / retryCount)
Proposed fix
Wrap the name generation + tracker.Create call in a retry loop
(up to 7 attempts, matching the real API server). On AlreadyExists,
regenerate the random suffix and retry. Only retry when GenerateName
is set — explicit Name collisions should still return an error
immediately.
I'm happy to submit a PR for this.
What happened?
The fake client's
Createmethod generates a single random name whenGenerateNameis set and does not retry on collision. If the generatedname matches an existing object in the tracker (including previously
deleted ones that the tracker still retains), it returns
AlreadyExiststo the caller.
This causes flaky tests when many objects are created and deleted with
the same
GenerateNameprefix. With only a 5-character random suffix(27^5 ≈ 14.3M possibilities), the birthday paradox makes collisions
likely at scale.
What did you expect to happen?
The fake client should match the real Kubernetes API server behavior.
Since Kubernetes 1.32, the
RetryGenerateNamefeature gate is GA andthe API server retries up to 7 times on
GenerateNamecollisions:kubernetes/kubernetes#115489
The fake client should do the same — retry with a new random suffix
on
AlreadyExistswhenGenerateNamewas used.Relevant code
The current single-attempt logic is in
pkg/client/fake/client.goin the
Createmethod:https://github.com/kubernetes-sigs/controller-runtime/blob/main/pkg/client/fake/client.go#L877-L882
The real API server's retry implementation is in:
https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/apiserver/pkg/registry/generic/registry/store.go
(search for
generateName/retryCount)Proposed fix
Wrap the name generation +
tracker.Createcall in a retry loop(up to 7 attempts, matching the real API server). On
AlreadyExists,regenerate the random suffix and retry. Only retry when
GenerateNameis set — explicit
Namecollisions should still return an errorimmediately.
I'm happy to submit a PR for this.