diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/wait/delete.go b/staging/src/k8s.io/kubectl/pkg/cmd/wait/delete.go index a8ccd2fca7c..aeb8aa4d702 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/wait/delete.go +++ b/staging/src/k8s.io/kubectl/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/staging/src/k8s.io/kubectl/pkg/cmd/wait/wait_test.go b/staging/src/k8s.io/kubectl/pkg/cmd/wait/wait_test.go index 0f90129ccfd..0d0087359f5 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/wait/wait_test.go +++ b/staging/src/k8s.io/kubectl/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 {