added podgc orphaned pod unit tests
This commit is contained in:
		@@ -18,14 +18,18 @@ package podgc
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/google/go-cmp/cmp"
 | 
						"github.com/google/go-cmp/cmp"
 | 
				
			||||||
 | 
						"github.com/google/go-cmp/cmp/cmpopts"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	v1 "k8s.io/api/core/v1"
 | 
						v1 "k8s.io/api/core/v1"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/labels"
 | 
						"k8s.io/apimachinery/pkg/labels"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
						"k8s.io/apimachinery/pkg/util/sets"
 | 
				
			||||||
 | 
						"k8s.io/apimachinery/pkg/util/strategicpatch"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/wait"
 | 
						"k8s.io/apimachinery/pkg/util/wait"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
						utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
				
			||||||
	"k8s.io/client-go/informers"
 | 
						"k8s.io/client-go/informers"
 | 
				
			||||||
@@ -43,6 +47,7 @@ import (
 | 
				
			|||||||
	"k8s.io/kubernetes/pkg/features"
 | 
						"k8s.io/kubernetes/pkg/features"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/kubelet/eviction"
 | 
						"k8s.io/kubernetes/pkg/kubelet/eviction"
 | 
				
			||||||
	testingclock "k8s.io/utils/clock/testing"
 | 
						testingclock "k8s.io/utils/clock/testing"
 | 
				
			||||||
 | 
						"k8s.io/utils/pointer"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func alwaysReady() bool { return true }
 | 
					func alwaysReady() bool { return true }
 | 
				
			||||||
@@ -671,6 +676,128 @@ func TestGCTerminating(t *testing.T) {
 | 
				
			|||||||
	testDeletingPodsMetrics(t, 7, metrics.PodGCReasonTerminatingOutOfService)
 | 
						testDeletingPodsMetrics(t, 7, metrics.PodGCReasonTerminatingOutOfService)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestGCInspectingPatchedPodBeforeDeletion(t *testing.T) {
 | 
				
			||||||
 | 
						testCases := []struct {
 | 
				
			||||||
 | 
							name                 string
 | 
				
			||||||
 | 
							pod                  *v1.Pod
 | 
				
			||||||
 | 
							expectedPatchedPod   *v1.Pod
 | 
				
			||||||
 | 
							expectedDeleteAction *clienttesting.DeleteActionImpl
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "orphaned pod should have DisruptionTarget condition added before deletion",
 | 
				
			||||||
 | 
								pod: &v1.Pod{
 | 
				
			||||||
 | 
									ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
										Namespace: "default",
 | 
				
			||||||
 | 
										Name:      "testPod",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Spec: v1.PodSpec{
 | 
				
			||||||
 | 
										NodeName: "deletedNode",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Status: v1.PodStatus{
 | 
				
			||||||
 | 
										Phase: v1.PodRunning,
 | 
				
			||||||
 | 
										Conditions: []v1.PodCondition{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Type:   v1.PodReady,
 | 
				
			||||||
 | 
												Status: v1.ConditionTrue,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedPatchedPod: &v1.Pod{
 | 
				
			||||||
 | 
									ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
										Namespace: "default",
 | 
				
			||||||
 | 
										Name:      "testPod",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Spec: v1.PodSpec{
 | 
				
			||||||
 | 
										NodeName: "deletedNode",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Status: v1.PodStatus{
 | 
				
			||||||
 | 
										Phase: v1.PodFailed,
 | 
				
			||||||
 | 
										Conditions: []v1.PodCondition{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Type:    v1.DisruptionTarget,
 | 
				
			||||||
 | 
												Status:  v1.ConditionTrue,
 | 
				
			||||||
 | 
												Reason:  "DeletionByPodGC",
 | 
				
			||||||
 | 
												Message: "PodGC: node no longer exists",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Type:   v1.PodReady,
 | 
				
			||||||
 | 
												Status: v1.ConditionTrue,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedDeleteAction: &clienttesting.DeleteActionImpl{
 | 
				
			||||||
 | 
									Name:          "testPod",
 | 
				
			||||||
 | 
									DeleteOptions: metav1.DeleteOptions{GracePeriodSeconds: pointer.Int64(0)},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, test := range testCases {
 | 
				
			||||||
 | 
							t.Run(test.name, func(t *testing.T) {
 | 
				
			||||||
 | 
								_, ctx := ktesting.NewTestContext(t)
 | 
				
			||||||
 | 
								defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodDisruptionConditions, true)()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								pods := []*v1.Pod{test.pod}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								client := setupNewSimpleClient(nil, pods)
 | 
				
			||||||
 | 
								gcc, podInformer, _ := NewFromClient(ctx, client, -1)
 | 
				
			||||||
 | 
								gcc.quarantineTime = time.Duration(-1)
 | 
				
			||||||
 | 
								podInformer.Informer().GetStore().Add(test.pod)
 | 
				
			||||||
 | 
								gcc.gc(ctx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								actions := client.Actions()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var patchAction clienttesting.PatchAction
 | 
				
			||||||
 | 
								var deleteAction clienttesting.DeleteAction
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for _, action := range actions {
 | 
				
			||||||
 | 
									if action.GetVerb() == "patch" {
 | 
				
			||||||
 | 
										patchAction = action.(clienttesting.PatchAction)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if action.GetVerb() == "delete" {
 | 
				
			||||||
 | 
										deleteAction = action.(clienttesting.DeleteAction)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if patchAction != nil && test.expectedPatchedPod == nil {
 | 
				
			||||||
 | 
									t.Fatalf("Pod was pactched but expectedPatchedPod is nil")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if test.expectedPatchedPod != nil {
 | 
				
			||||||
 | 
									patchedPodBytes := patchAction.GetPatch()
 | 
				
			||||||
 | 
									originalPod, err := json.Marshal(test.pod)
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										t.Fatalf("Failed to marshal original pod %#v: %v", originalPod, err)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									updated, err := strategicpatch.StrategicMergePatch(originalPod, patchedPodBytes, v1.Pod{})
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										t.Fatalf("Failed to apply strategic merge patch %q on pod %#v: %v", patchedPodBytes, originalPod, err)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									updatedPod := &v1.Pod{}
 | 
				
			||||||
 | 
									if err := json.Unmarshal(updated, updatedPod); err != nil {
 | 
				
			||||||
 | 
										t.Fatalf("Failed to unmarshal updated pod %q: %v", updated, err)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if diff := cmp.Diff(test.expectedPatchedPod, updatedPod, cmpopts.IgnoreFields(v1.Pod{}, "TypeMeta"), cmpopts.IgnoreFields(v1.PodCondition{}, "LastTransitionTime")); diff != "" {
 | 
				
			||||||
 | 
										t.Fatalf("Unexpected diff on pod (-want,+got):\n%s", diff)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if deleteAction != nil && test.expectedDeleteAction == nil {
 | 
				
			||||||
 | 
									t.Fatalf("Pod was deleted but expectedDeleteAction is nil")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if test.expectedDeleteAction != nil {
 | 
				
			||||||
 | 
									if diff := cmp.Diff(*test.expectedDeleteAction, deleteAction, cmpopts.IgnoreFields(clienttesting.DeleteActionImpl{}, "ActionImpl")); diff != "" {
 | 
				
			||||||
 | 
										t.Fatalf("Unexpected diff on deleteAction (-want,+got):\n%s", diff)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func verifyDeletedAndPatchedPods(t *testing.T, client *fake.Clientset, wantDeletedPodNames, wantPatchedPodNames sets.String) {
 | 
					func verifyDeletedAndPatchedPods(t *testing.T, client *fake.Clientset, wantDeletedPodNames, wantPatchedPodNames sets.String) {
 | 
				
			||||||
	t.Helper()
 | 
						t.Helper()
 | 
				
			||||||
	deletedPodNames := getDeletedPodNames(client)
 | 
						deletedPodNames := getDeletedPodNames(client)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user