Merge pull request #135563 from yangjunmyfm192085/fixkubectl

When using kubectl to delete multiple sts pods simultaneously, it gets stuck and won't exit

Kubernetes-commit: 2c677fe0345d510f48e2fe2863deaa502f73d2a6
This commit is contained in:
Kubernetes Publisher 2026-01-15 20:15:35 +05:30
commit 3a767404cb
4 changed files with 56 additions and 5 deletions

4
go.mod
View file

@ -33,7 +33,7 @@ require (
k8s.io/api v0.0.0-20260114012703-c51ea733cfc5
k8s.io/apimachinery v0.0.0-20260114012332-8931c298fc6d
k8s.io/cli-runtime v0.0.0-20260114021257-dff199191c95
k8s.io/client-go v0.0.0-20260114013155-d8ad3ab106f8
k8s.io/client-go v0.0.0-20260115013208-14e71d285024
k8s.io/component-base v0.0.0-20260114014353-b07a9541dc84
k8s.io/component-helpers v0.0.0-20260114014538-c52e34b7fb41
k8s.io/klog/v2 v2.130.1
@ -92,3 +92,5 @@ require (
gopkg.in/yaml.v3 v3.0.1 // indirect
sigs.k8s.io/kustomize/api v0.20.1 // indirect
)
replace k8s.io/code-generator => k8s.io/code-generator v0.0.0-20260114213448-138c280a7fed

4
go.sum
View file

@ -198,8 +198,8 @@ k8s.io/apimachinery v0.0.0-20260114012332-8931c298fc6d h1:lbzMtYUrm8byD8FkOTpBww
k8s.io/apimachinery v0.0.0-20260114012332-8931c298fc6d/go.mod h1:zpNwej4sm5trmv4IunJBZUKUdbsrjs+lz/cgK1B8Dew=
k8s.io/cli-runtime v0.0.0-20260114021257-dff199191c95 h1:z+8PwCtVn9Vy/K9ycDSubhg8EzzEeXoV293DoTpYJ0M=
k8s.io/cli-runtime v0.0.0-20260114021257-dff199191c95/go.mod h1:StMv4CBSJ8C+aETOp8T5xAwhl8EfugDmhnxhKJRz3aM=
k8s.io/client-go v0.0.0-20260114013155-d8ad3ab106f8 h1:eRON2KmcEv2o100zcpO5LjsrF9kFhyuXUfOmQlb3ZGI=
k8s.io/client-go v0.0.0-20260114013155-d8ad3ab106f8/go.mod h1:WH/2COL4UX2ClV8Y0ExNDUL0yecAqB7x0M5NVROCRYw=
k8s.io/client-go v0.0.0-20260115013208-14e71d285024 h1:QXRqHoBnPI7otK+y4Pxqs8MK1sUMWIKqP7adHte3t9s=
k8s.io/client-go v0.0.0-20260115013208-14e71d285024/go.mod h1:WH/2COL4UX2ClV8Y0ExNDUL0yecAqB7x0M5NVROCRYw=
k8s.io/component-base v0.0.0-20260114014353-b07a9541dc84 h1:WLmvlHlKw1hiKNw1v2iILCWEPvtn8NClDxFr/+eMuig=
k8s.io/component-base v0.0.0-20260114014353-b07a9541dc84/go.mod h1:Di8MCxUlKVRBDtxfcS5WXJHIYBWhB2D/3ojxiaxI1So=
k8s.io/component-helpers v0.0.0-20260114014538-c52e34b7fb41 h1:U8bKHIMsJ2+KVsY9pAYaI7Ue00lMKnUbi9u1P4rIQzM=

View file

@ -24,6 +24,7 @@ import (
"time"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/fields"
@ -90,7 +91,7 @@ func IsDeleted(ctx context.Context, info *resource.Info, o *WaitOptions) (runtim
// this function is used to refresh the cache to prevent timeout waits on resources that have disappeared
preconditionFunc := func(store cache.Store) (bool, error) {
_, exists, err := store.Get(&metav1.ObjectMeta{Namespace: info.Namespace, Name: info.Name})
obj, exists, err := store.Get(&metav1.ObjectMeta{Namespace: info.Namespace, Name: info.Name})
if err != nil {
return true, err
}
@ -98,7 +99,15 @@ func IsDeleted(ctx context.Context, info *resource.Info, o *WaitOptions) (runtim
// since we're looking for it to disappear we just return here if it no longer exists
return true, nil
}
acc, err := meta.Accessor(obj)
if err != nil {
return true, err
}
if uid, ok := o.UIDMap[resourceLocation]; ok {
if acc.GetUID() != uid {
return true, nil
}
}
return false, nil
}

View file

@ -180,6 +180,20 @@ func newUnstructured(apiVersion, kind, namespace, name string) *unstructured.Uns
}
}
func newUnstructuredWithNewID(apiVersion, kind, namespace, name string) *unstructured.Unstructured {
return &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": apiVersion,
"kind": kind,
"metadata": map[string]interface{}{
"namespace": namespace,
"name": name,
"uid": "some-UID-value-new",
},
},
}
}
func newUnstructuredWithGeneration(apiVersion, kind, namespace, name string, generation int64) *unstructured.Unstructured {
return &unstructured.Unstructured{
Object: map[string]interface{}{
@ -544,6 +558,32 @@ func TestWaitForDeletion(t *testing.T) {
},
timeout: 10 * time.Second,
},
{
name: "when list watch, receives a new pod",
infos: []*resource.Info{
{
Mapping: &meta.RESTMapping{
Resource: schema.GroupVersionResource{Group: "group", Version: "version", Resource: "theresource"},
},
Name: "name-foo",
Namespace: "ns-foo",
},
},
fakeClient: func() *dynamicfakeclient.FakeDynamicClient {
fakeClient := dynamicfakeclient.NewSimpleDynamicClientWithCustomListKinds(scheme, listMapping)
fakeClient.PrependReactor("get", "theresource", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
return true, newUnstructured("group/version", "TheKind", "ns-foo", "name-foo"), nil
})
fakeClient.PrependReactor("list", "theresource", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
return true, newUnstructuredList(newUnstructuredWithNewID("group/version", "TheKind", "ns-foo", "name-foo")), nil
})
return fakeClient
},
timeout: 10 * time.Second,
uidMap: UIDMap{
ResourceLocation{GroupResource: schema.GroupResource{Group: "group", Resource: "theresource"}, Namespace: "ns-foo", Name: "name-foo"}: types.UID("some-UID-value"),
},
},
}
for _, test := range tests {