From b365eec0f700612580371f1de30201258b69a0e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E5=86=9B10092085?= Date: Wed, 3 Dec 2025 12:39:32 +0800 Subject: [PATCH] When using kubectl to delete multiple sts pods simultaneously, it gets stuck and won't exit Kubernetes-commit: a14f528ffe671da721dfa80ed8774361e1fb6011 --- pkg/cmd/wait/delete.go | 13 +++++++++++-- pkg/cmd/wait/wait_test.go | 40 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/pkg/cmd/wait/delete.go b/pkg/cmd/wait/delete.go index a8ccd2fca..aeb8aa4d7 100644 --- a/pkg/cmd/wait/delete.go +++ b/pkg/cmd/wait/delete.go @@ -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 } diff --git a/pkg/cmd/wait/wait_test.go b/pkg/cmd/wait/wait_test.go index 0f90129cc..0d0087359 100644 --- a/pkg/cmd/wait/wait_test.go +++ b/pkg/cmd/wait/wait_test.go @@ -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 {