diff --git a/pkg/controller/garbagecollector/garbagecollector.go b/pkg/controller/garbagecollector/garbagecollector.go index 643c0b1476f..f43578073e8 100644 --- a/pkg/controller/garbagecollector/garbagecollector.go +++ b/pkg/controller/garbagecollector/garbagecollector.go @@ -627,7 +627,6 @@ func (gc *GarbageCollector) attemptToDeleteItem(ctx context.Context, item *node) policy := metav1.DeletePropagationForeground err := gc.deleteObject(item.identity, latest.ResourceVersion, latest.OwnerReferences, &policy) if errors.IsNotFound(err) { - // the item was deleted externally, enqueue a virtual delete event gc.dependencyGraphBuilder.enqueueVirtualDeleteEvent(item.identity) return enqueuedVirtualDeleteEventErr } @@ -654,7 +653,6 @@ func (gc *GarbageCollector) attemptToDeleteItem(ctx context.Context, item *node) ) err := gc.deleteObject(item.identity, latest.ResourceVersion, latest.OwnerReferences, &policy) if errors.IsNotFound(err) { - // the item was deleted externally, enqueue a virtual delete event gc.dependencyGraphBuilder.enqueueVirtualDeleteEvent(item.identity) return enqueuedVirtualDeleteEventErr } diff --git a/pkg/controller/garbagecollector/garbagecollector_test.go b/pkg/controller/garbagecollector/garbagecollector_test.go index 8663e6c24a8..2b164fd17cf 100644 --- a/pkg/controller/garbagecollector/garbagecollector_test.go +++ b/pkg/controller/garbagecollector/garbagecollector_test.go @@ -18,6 +18,7 @@ package garbagecollector import ( "context" + goerrors "errors" "fmt" "net/http" "net/http/httptest" @@ -255,6 +256,126 @@ func serilizeOrDie(t *testing.T, object interface{}) []byte { return data } +func TestAttemptToDeleteItemDeleteObjectNotFound(t *testing.T) { + pod := getPod("ExternallyDeletedPod", []metav1.OwnerReference{ + { + Kind: "ReplicationController", + Name: "owner1", + UID: "123", + APIVersion: "v1", + }, + }) + testHandler := &fakeActionHandler{ + response: map[string]FakeResponse{ + "GET" + "/api/v1/namespaces/ns1/replicationcontrollers/owner1": { + 404, + []byte{}, + }, + "GET" + "/api/v1/namespaces/ns1/pods/ExternallyDeletedPod": { + 200, + serilizeOrDie(t, pod), + }, + "DELETE" + "/api/v1/namespaces/ns1/pods/ExternallyDeletedPod": { + 404, + []byte{}, + }, + }, + } + srv, clientConfig := testServerAndClientConfig(testHandler.ServeHTTP) + defer srv.Close() + + gc := setupGC(t, clientConfig) + defer close(gc.stop) + + item := &node{ + identity: objectReference{ + OwnerReference: metav1.OwnerReference{ + Kind: pod.Kind, + APIVersion: pod.APIVersion, + Name: pod.Name, + UID: pod.UID, + }, + Namespace: pod.Namespace, + }, + owners: nil, + } + + err := gc.attemptToDeleteItem(context.TODO(), item) + if !goerrors.Is(err, enqueuedVirtualDeleteEventErr) { + t.Errorf("expected enqueuedVirtualDeleteEventErr, got: %v", err) + } + if gc.dependencyGraphBuilder.graphChanges.Len() == 0 { + t.Errorf("expected a virtual delete event to be enqueued in graphChanges, but the queue is empty") + } +} + +func TestAttemptToDeleteItemDeleteObjectNotFoundWaitingForDependents(t *testing.T) { + pod := getPod("ExternallyDeletedPodFG", []metav1.OwnerReference{ + { + Kind: "ReplicationController", + Name: "owner1", + UID: "123", + APIVersion: "v1", + BlockOwnerDeletion: func() *bool { b := true; return &b }(), + }, + }) + owner := &v1.ReplicationController{ + TypeMeta: metav1.TypeMeta{ + Kind: "ReplicationController", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "owner1", + Namespace: "ns1", + UID: "123", + DeletionTimestamp: func() *metav1.Time { t := metav1.Now(); return &t }(), + Finalizers: []string{metav1.FinalizerDeleteDependents}, + }, + } + testHandler := &fakeActionHandler{ + response: map[string]FakeResponse{ + "GET" + "/api/v1/namespaces/ns1/replicationcontrollers/owner1": { + 200, + serilizeOrDie(t, owner), + }, + "GET" + "/api/v1/namespaces/ns1/pods/ExternallyDeletedPodFG": { + 200, + serilizeOrDie(t, pod), + }, + "DELETE" + "/api/v1/namespaces/ns1/pods/ExternallyDeletedPodFG": { + 404, + []byte{}, + }, + }, + } + srv, clientConfig := testServerAndClientConfig(testHandler.ServeHTTP) + defer srv.Close() + + gc := setupGC(t, clientConfig) + defer close(gc.stop) + + item := &node{ + identity: objectReference{ + OwnerReference: metav1.OwnerReference{ + Kind: pod.Kind, + APIVersion: pod.APIVersion, + Name: pod.Name, + UID: pod.UID, + }, + Namespace: pod.Namespace, + }, + owners: nil, + } + + err := gc.attemptToDeleteItem(context.TODO(), item) + if !goerrors.Is(err, enqueuedVirtualDeleteEventErr) { + t.Errorf("expected enqueuedVirtualDeleteEventErr, got: %v", err) + } + if gc.dependencyGraphBuilder.graphChanges.Len() == 0 { + t.Errorf("expected a virtual delete event to be enqueued in graphChanges, but the queue is empty") + } +} + // test the attemptToDeleteItem function making the expected actions. func TestAttemptToDeleteItem(t *testing.T) { pod := getPod("ToBeDeletedPod", []metav1.OwnerReference{