Skip to content

Commit 042fef7

Browse files
authored
Merge pull request #1521 from fanhaouu/e2e-failedpods
[FailedPods] e2e: build a descheduler image and run the descheduler as a pod
2 parents 2c033a1 + 05ce561 commit 042fef7

File tree

1 file changed

+151
-64
lines changed

1 file changed

+151
-64
lines changed

test/e2e/e2e_failedpods_test.go

Lines changed: 151 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -11,122 +11,209 @@ import (
1111
v1 "k8s.io/api/core/v1"
1212
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1313
"k8s.io/apimachinery/pkg/labels"
14+
"k8s.io/apimachinery/pkg/runtime"
15+
"k8s.io/apimachinery/pkg/util/sets"
1416
"k8s.io/apimachinery/pkg/util/wait"
1517
clientset "k8s.io/client-go/kubernetes"
1618
componentbaseconfig "k8s.io/component-base/config"
1719
utilptr "k8s.io/utils/ptr"
1820

21+
"sigs.k8s.io/descheduler/pkg/api"
22+
apiv1alpha2 "sigs.k8s.io/descheduler/pkg/api/v1alpha2"
1923
"sigs.k8s.io/descheduler/pkg/descheduler/client"
20-
"sigs.k8s.io/descheduler/pkg/descheduler/evictions"
21-
eutils "sigs.k8s.io/descheduler/pkg/descheduler/evictions/utils"
2224
"sigs.k8s.io/descheduler/pkg/framework/plugins/defaultevictor"
2325
"sigs.k8s.io/descheduler/pkg/framework/plugins/removefailedpods"
24-
frameworktesting "sigs.k8s.io/descheduler/pkg/framework/testing"
25-
frameworktypes "sigs.k8s.io/descheduler/pkg/framework/types"
2626
)
2727

28-
var oneHourPodLifetimeSeconds uint = 3600
28+
var (
29+
oneHourPodLifetimeSeconds uint = 3600
30+
oneSecondPodLifetimeSeconds uint = 1
31+
)
32+
33+
func removeFailedPodsPolicy(removeFailedPodsArgs *removefailedpods.RemoveFailedPodsArgs, evictorArgs *defaultevictor.DefaultEvictorArgs) *apiv1alpha2.DeschedulerPolicy {
34+
return &apiv1alpha2.DeschedulerPolicy{
35+
Profiles: []apiv1alpha2.DeschedulerProfile{
36+
{
37+
Name: removefailedpods.PluginName + "Profile",
38+
PluginConfigs: []apiv1alpha2.PluginConfig{
39+
{
40+
Name: removefailedpods.PluginName,
41+
Args: runtime.RawExtension{
42+
Object: removeFailedPodsArgs,
43+
},
44+
},
45+
{
46+
Name: defaultevictor.PluginName,
47+
Args: runtime.RawExtension{
48+
Object: evictorArgs,
49+
},
50+
},
51+
},
52+
Plugins: apiv1alpha2.Plugins{
53+
Filter: apiv1alpha2.PluginSet{
54+
Enabled: []string{
55+
defaultevictor.PluginName,
56+
},
57+
},
58+
Deschedule: apiv1alpha2.PluginSet{
59+
Enabled: []string{
60+
removefailedpods.PluginName,
61+
},
62+
},
63+
},
64+
},
65+
},
66+
}
67+
}
2968

3069
func TestFailedPods(t *testing.T) {
3170
ctx := context.Background()
3271

3372
clientSet, err := client.CreateClient(componentbaseconfig.ClientConnectionConfiguration{Kubeconfig: os.Getenv("KUBECONFIG")}, "")
3473
if err != nil {
35-
t.Errorf("Error during client creation with %v", err)
74+
t.Errorf("Error during kubernetes client creation with %v", err)
3675
}
3776

38-
nodeList, err := clientSet.CoreV1().Nodes().List(ctx, metav1.ListOptions{})
39-
if err != nil {
40-
t.Errorf("Error listing node with %v", err)
41-
}
42-
nodes, _ := splitNodesAndWorkerNodes(nodeList.Items)
4377
t.Log("Creating testing namespace")
4478
testNamespace := &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "e2e-" + strings.ToLower(t.Name())}}
4579
if _, err := clientSet.CoreV1().Namespaces().Create(ctx, testNamespace, metav1.CreateOptions{}); err != nil {
4680
t.Fatalf("Unable to create ns %v", testNamespace.Name)
4781
}
4882
defer clientSet.CoreV1().Namespaces().Delete(ctx, testNamespace.Name, metav1.DeleteOptions{})
49-
testCases := map[string]struct {
50-
expectedEvictedCount uint
51-
args *removefailedpods.RemoveFailedPodsArgs
83+
84+
tests := []struct {
85+
name string
86+
expectedEvictedPodCount int
87+
removeFailedPodsArgs *removefailedpods.RemoveFailedPodsArgs
5288
}{
53-
"test-failed-pods-default-args": {
54-
expectedEvictedCount: 1,
55-
args: &removefailedpods.RemoveFailedPodsArgs{},
89+
{
90+
name: "test-failed-pods-default-args",
91+
expectedEvictedPodCount: 1,
92+
removeFailedPodsArgs: &removefailedpods.RemoveFailedPodsArgs{
93+
MinPodLifetimeSeconds: &oneSecondPodLifetimeSeconds,
94+
},
5695
},
57-
"test-failed-pods-reason-unmatched": {
58-
expectedEvictedCount: 0,
59-
args: &removefailedpods.RemoveFailedPodsArgs{
60-
Reasons: []string{"ReasonDoesNotMatch"},
96+
{
97+
name: "test-failed-pods-reason-unmatched",
98+
expectedEvictedPodCount: 0,
99+
removeFailedPodsArgs: &removefailedpods.RemoveFailedPodsArgs{
100+
Reasons: []string{"ReasonDoesNotMatch"},
101+
MinPodLifetimeSeconds: &oneSecondPodLifetimeSeconds,
61102
},
62103
},
63-
"test-failed-pods-min-age-unmet": {
64-
expectedEvictedCount: 0,
65-
args: &removefailedpods.RemoveFailedPodsArgs{
104+
{
105+
name: "test-failed-pods-min-age-unmet",
106+
expectedEvictedPodCount: 0,
107+
removeFailedPodsArgs: &removefailedpods.RemoveFailedPodsArgs{
66108
MinPodLifetimeSeconds: &oneHourPodLifetimeSeconds,
67109
},
68110
},
69-
"test-failed-pods-exclude-job-kind": {
70-
expectedEvictedCount: 0,
71-
args: &removefailedpods.RemoveFailedPodsArgs{
72-
ExcludeOwnerKinds: []string{"Job"},
111+
{
112+
name: "test-failed-pods-exclude-job-kind",
113+
expectedEvictedPodCount: 0,
114+
removeFailedPodsArgs: &removefailedpods.RemoveFailedPodsArgs{
115+
ExcludeOwnerKinds: []string{"Job"},
116+
MinPodLifetimeSeconds: &oneSecondPodLifetimeSeconds,
73117
},
74118
},
75119
}
76-
for name, tc := range testCases {
77-
t.Run(name, func(t *testing.T) {
78-
job := initFailedJob(name, testNamespace.Namespace)
120+
for _, tc := range tests {
121+
t.Run(tc.name, func(t *testing.T) {
122+
job := initFailedJob(tc.name, testNamespace.Namespace)
79123
t.Logf("Creating job %s in %s namespace", job.Name, job.Namespace)
80124
jobClient := clientSet.BatchV1().Jobs(testNamespace.Name)
81125
if _, err := jobClient.Create(ctx, job, metav1.CreateOptions{}); err != nil {
82-
t.Fatalf("Error creating Job %s: %v", name, err)
126+
t.Fatalf("Error creating Job %s: %v", tc.name, err)
83127
}
84128
deletePropagationPolicy := metav1.DeletePropagationForeground
85-
defer jobClient.Delete(ctx, job.Name, metav1.DeleteOptions{PropagationPolicy: &deletePropagationPolicy})
129+
defer func() {
130+
jobClient.Delete(ctx, job.Name, metav1.DeleteOptions{PropagationPolicy: &deletePropagationPolicy})
131+
waitForPodsToDisappear(ctx, t, clientSet, job.Labels, job.Namespace)
132+
}()
86133
waitForJobPodPhase(ctx, t, clientSet, job, v1.PodFailed)
87134

88-
evictionPolicyGroupVersion, err := eutils.SupportEviction(clientSet)
89-
if err != nil || len(evictionPolicyGroupVersion) == 0 {
90-
t.Fatalf("Error detecting eviction policy group: %v", err)
135+
preRunNames := sets.NewString(getCurrentPodNames(ctx, clientSet, testNamespace.Name, t)...)
136+
137+
// Deploy the descheduler with the configured policy
138+
evictorArgs := &defaultevictor.DefaultEvictorArgs{
139+
EvictLocalStoragePods: true,
140+
EvictSystemCriticalPods: false,
141+
IgnorePvcPods: false,
142+
EvictFailedBarePods: false,
143+
}
144+
tc.removeFailedPodsArgs.Namespaces = &api.Namespaces{
145+
Include: []string{testNamespace.Name},
91146
}
92147

93-
handle, podEvictor, err := frameworktesting.InitFrameworkHandle(
94-
ctx,
95-
clientSet,
96-
evictions.NewOptions().
97-
WithPolicyGroupVersion(evictionPolicyGroupVersion),
98-
defaultevictor.DefaultEvictorArgs{
99-
EvictLocalStoragePods: true,
100-
},
101-
nil,
102-
)
148+
deschedulerPolicyConfigMapObj, err := deschedulerPolicyConfigMap(removeFailedPodsPolicy(tc.removeFailedPodsArgs, evictorArgs))
103149
if err != nil {
104-
t.Fatalf("Unable to initialize a framework handle: %v", err)
150+
t.Fatalf("Error creating %q CM: %v", deschedulerPolicyConfigMapObj.Name, err)
105151
}
106152

107-
t.Logf("Running RemoveFailedPods strategy for %s", name)
153+
t.Logf("Creating %q policy CM with RemoveDuplicates configured...", deschedulerPolicyConfigMapObj.Name)
154+
_, err = clientSet.CoreV1().ConfigMaps(deschedulerPolicyConfigMapObj.Namespace).Create(ctx, deschedulerPolicyConfigMapObj, metav1.CreateOptions{})
155+
if err != nil {
156+
t.Fatalf("Error creating %q CM: %v", deschedulerPolicyConfigMapObj.Name, err)
157+
}
108158

109-
plugin, err := removefailedpods.New(&removefailedpods.RemoveFailedPodsArgs{
110-
Reasons: tc.args.Reasons,
111-
MinPodLifetimeSeconds: tc.args.MinPodLifetimeSeconds,
112-
IncludingInitContainers: tc.args.IncludingInitContainers,
113-
ExcludeOwnerKinds: tc.args.ExcludeOwnerKinds,
114-
LabelSelector: tc.args.LabelSelector,
115-
Namespaces: tc.args.Namespaces,
116-
},
117-
handle,
118-
)
159+
defer func() {
160+
t.Logf("Deleting %q CM...", deschedulerPolicyConfigMapObj.Name)
161+
err = clientSet.CoreV1().ConfigMaps(deschedulerPolicyConfigMapObj.Namespace).Delete(ctx, deschedulerPolicyConfigMapObj.Name, metav1.DeleteOptions{})
162+
if err != nil {
163+
t.Fatalf("Unable to delete %q CM: %v", deschedulerPolicyConfigMapObj.Name, err)
164+
}
165+
}()
166+
167+
deschedulerDeploymentObj := deschedulerDeployment(testNamespace.Name)
168+
t.Logf("Creating descheduler deployment %v", deschedulerDeploymentObj.Name)
169+
_, err = clientSet.AppsV1().Deployments(deschedulerDeploymentObj.Namespace).Create(ctx, deschedulerDeploymentObj, metav1.CreateOptions{})
119170
if err != nil {
120-
t.Fatalf("Unable to initialize the plugin: %v", err)
171+
t.Fatalf("Error creating %q deployment: %v", deschedulerDeploymentObj.Name, err)
121172
}
122173

123-
plugin.(frameworktypes.DeschedulePlugin).Deschedule(ctx, nodes)
124-
t.Logf("Finished RemoveFailedPods strategy for %s", name)
174+
deschedulerPodName := ""
175+
defer func() {
176+
if deschedulerPodName != "" {
177+
printPodLogs(ctx, t, clientSet, deschedulerPodName)
178+
}
179+
180+
t.Logf("Deleting %q deployment...", deschedulerDeploymentObj.Name)
181+
err = clientSet.AppsV1().Deployments(deschedulerDeploymentObj.Namespace).Delete(ctx, deschedulerDeploymentObj.Name, metav1.DeleteOptions{})
182+
if err != nil {
183+
t.Fatalf("Unable to delete %q deployment: %v", deschedulerDeploymentObj.Name, err)
184+
}
185+
186+
waitForPodsToDisappear(ctx, t, clientSet, deschedulerDeploymentObj.Labels, deschedulerDeploymentObj.Namespace)
187+
}()
188+
189+
t.Logf("Waiting for the descheduler pod running")
190+
deschedulerPods := waitForPodsRunning(ctx, t, clientSet, deschedulerDeploymentObj.Labels, 1, deschedulerDeploymentObj.Namespace)
191+
if len(deschedulerPods) != 0 {
192+
deschedulerPodName = deschedulerPods[0].Name
193+
}
194+
195+
// Run RemoveDuplicates strategy
196+
var meetsExpectations bool
197+
var actualEvictedPodCount int
198+
if err := wait.PollUntilContextTimeout(ctx, 5*time.Second, 60*time.Second, true, func(ctx context.Context) (bool, error) {
199+
currentRunNames := sets.NewString(getCurrentPodNames(ctx, clientSet, testNamespace.Name, t)...)
200+
actualEvictedPod := preRunNames.Difference(currentRunNames)
201+
actualEvictedPodCount = actualEvictedPod.Len()
202+
t.Logf("preRunNames: %v, currentRunNames: %v, actualEvictedPodCount: %v\n", preRunNames.List(), currentRunNames.List(), actualEvictedPodCount)
203+
if actualEvictedPodCount != tc.expectedEvictedPodCount {
204+
t.Logf("Expecting %v number of pods evicted, got %v instead", tc.expectedEvictedPodCount, actualEvictedPodCount)
205+
return false, nil
206+
}
207+
meetsExpectations = true
208+
return true, nil
209+
}); err != nil {
210+
t.Errorf("Error waiting for descheduler running: %v", err)
211+
}
125212

126-
if actualEvictedCount := podEvictor.TotalEvicted(); actualEvictedCount == tc.expectedEvictedCount {
127-
t.Logf("Total of %d Pods were evicted for %s", actualEvictedCount, name)
213+
if !meetsExpectations {
214+
t.Errorf("Unexpected number of pods have been evicted, got %v, expected %v", actualEvictedPodCount, tc.expectedEvictedPodCount)
128215
} else {
129-
t.Errorf("Unexpected number of pods have been evicted, got %v, expected %v", actualEvictedCount, tc.expectedEvictedCount)
216+
t.Logf("Total of %d Pods were evicted for %s", actualEvictedPodCount, tc.name)
130217
}
131218
})
132219
}

0 commit comments

Comments
 (0)