Logarithmic timestamp comparison for ReplicSet downscaling

Change-Id: I0657ea0ce41b98fdee1a5307b5826a10deaff98c
This commit is contained in:
Aldo Culquicondor
2020-11-26 16:34:21 -05:00
committed by Mike Dame
parent 336bbae82c
commit a8d105ab72
5 changed files with 142 additions and 23 deletions

View File

@@ -437,7 +437,10 @@ func TestSortingActivePods(t *testing.T) {
func TestSortingActivePodsWithRanks(t *testing.T) {
now := metav1.Now()
then := metav1.Time{Time: now.AddDate(0, -1, 0)}
then1Month := metav1.Time{Time: now.AddDate(0, -1, 0)}
then2Hours := metav1.Time{Time: now.Add(-2 * time.Hour)}
then5Hours := metav1.Time{Time: now.Add(-5 * time.Hour)}
then8Hours := metav1.Time{Time: now.Add(-8 * time.Hour)}
zeroTime := metav1.Time{}
pod := func(podName, nodeName string, phase v1.PodPhase, ready bool, restarts int32, readySince metav1.Time, created metav1.Time, annotations map[string]string) *v1.Pod {
var conditions []v1.PodCondition
@@ -467,30 +470,46 @@ func TestSortingActivePodsWithRanks(t *testing.T) {
runningNotReadyPod = pod("not-ready", "node", v1.PodRunning, false, 0, zeroTime, zeroTime, nil)
runningReadyNoLastTransitionTimePod = pod("ready-no-last-transition-time", "node", v1.PodRunning, true, 0, zeroTime, zeroTime, nil)
runningReadyNow = pod("ready-now", "node", v1.PodRunning, true, 0, now, now, nil)
runningReadyThen = pod("ready-then", "node", v1.PodRunning, true, 0, then, then, nil)
runningReadyThen = pod("ready-then", "node", v1.PodRunning, true, 0, then1Month, then1Month, nil)
runningReadyNowHighRestarts = pod("ready-high-restarts", "node", v1.PodRunning, true, 9001, now, now, nil)
runningReadyNowCreatedThen = pod("ready-now-created-then", "node", v1.PodRunning, true, 0, now, then, nil)
lowPodDeletionCost = pod("low-deletion-cost", "node", v1.PodRunning, true, 0, now, then, map[string]string{core.PodDeletionCost: "10"})
highPodDeletionCost = pod("high-deletion-cost", "node", v1.PodRunning, true, 0, now, then, map[string]string{core.PodDeletionCost: "100"})
runningReadyNowCreatedThen = pod("ready-now-created-then", "node", v1.PodRunning, true, 0, now, then1Month, nil)
lowPodDeletionCost = pod("low-deletion-cost", "node", v1.PodRunning, true, 0, now, then1Month, map[string]string{core.PodDeletionCost: "10"})
highPodDeletionCost = pod("high-deletion-cost", "node", v1.PodRunning, true, 0, now, then1Month, map[string]string{core.PodDeletionCost: "100"})
unscheduled5Hours = pod("unscheduled-5-hours", "", v1.PodPending, false, 0, then5Hours, then5Hours, nil)
unscheduled8Hours = pod("unscheduled-10-hours", "", v1.PodPending, false, 0, then8Hours, then8Hours, nil)
ready2Hours = pod("ready-2-hours", "", v1.PodRunning, true, 0, then2Hours, then1Month, nil)
ready5Hours = pod("ready-5-hours", "", v1.PodRunning, true, 0, then5Hours, then1Month, nil)
ready10Hours = pod("ready-10-hours", "", v1.PodRunning, true, 0, then8Hours, then1Month, nil)
)
equalityTests := []*v1.Pod{
unscheduledPod,
scheduledPendingPod,
unknownPhasePod,
runningNotReadyPod,
runningReadyNowCreatedThen,
runningReadyNow,
runningReadyThen,
runningReadyNowHighRestarts,
runningReadyNowCreatedThen,
equalityTests := []struct {
p1 *v1.Pod
p2 *v1.Pod
disableLogarithmicScaleDown bool
}{
{p1: unscheduledPod},
{p1: scheduledPendingPod},
{p1: unknownPhasePod},
{p1: runningNotReadyPod},
{p1: runningReadyNowCreatedThen},
{p1: runningReadyNow},
{p1: runningReadyThen},
{p1: runningReadyNowHighRestarts},
{p1: runningReadyNowCreatedThen},
{p1: unscheduled5Hours, p2: unscheduled8Hours},
{p1: ready5Hours, p2: ready10Hours},
}
for _, pod := range equalityTests {
for _, tc := range equalityTests {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.LogarithmicScaleDown, !tc.disableLogarithmicScaleDown)()
if tc.p2 == nil {
tc.p2 = tc.p1
}
podsWithRanks := ActivePodsWithRanks{
Pods: []*v1.Pod{pod, pod},
Pods: []*v1.Pod{tc.p1, tc.p2},
Rank: []int{1, 1},
Now: now,
}
if podsWithRanks.Less(0, 1) || podsWithRanks.Less(1, 0) {
t.Errorf("expected pod %q not to be less than than itself", pod.Name)
t.Errorf("expected pod %q to be equivalent to %q", tc.p1.Name, tc.p2.Name)
}
}
type podWithRank struct {
@@ -498,8 +517,9 @@ func TestSortingActivePodsWithRanks(t *testing.T) {
rank int
}
inequalityTests := []struct {
lesser, greater podWithRank
disablePodDeletioncost bool
lesser, greater podWithRank
disablePodDeletioncost bool
disableLogarithmicScaleDown bool
}{
{lesser: podWithRank{unscheduledPod, 1}, greater: podWithRank{scheduledPendingPod, 2}},
{lesser: podWithRank{unscheduledPod, 2}, greater: podWithRank{scheduledPendingPod, 1}},
@@ -516,14 +536,17 @@ func TestSortingActivePodsWithRanks(t *testing.T) {
{lesser: podWithRank{runningReadyNowCreatedThen, 2}, greater: podWithRank{runningReadyNow, 1}},
{lesser: podWithRank{lowPodDeletionCost, 2}, greater: podWithRank{highPodDeletionCost, 1}},
{lesser: podWithRank{highPodDeletionCost, 2}, greater: podWithRank{lowPodDeletionCost, 1}, disablePodDeletioncost: true},
{lesser: podWithRank{ready2Hours, 1}, greater: podWithRank{ready5Hours, 1}},
}
for i, test := range inequalityTests {
t.Run(fmt.Sprintf("test%d", i), func(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodDeletionCost, !test.disablePodDeletioncost)()
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.LogarithmicScaleDown, !test.disableLogarithmicScaleDown)()
podsWithRanks := ActivePodsWithRanks{
Pods: []*v1.Pod{test.lesser.pod, test.greater.pod},
Rank: []int{test.lesser.rank, test.greater.rank},
Now: now,
}
if !podsWithRanks.Less(0, 1) {
t.Errorf("expected pod %q with rank %v to be less than %q with rank %v", podsWithRanks.Pods[0].Name, podsWithRanks.Rank[0], podsWithRanks.Pods[1].Name, podsWithRanks.Rank[1])