volcano.sh/volcano@v1.9.0/test/e2e/schedulingaction/preempt.go (about) 1 /* 2 Copyright 2021 The Volcano Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package schedulingaction 18 19 import ( 20 "context" 21 22 . "github.com/onsi/ginkgo/v2" 23 . "github.com/onsi/gomega" 24 25 corev1 "k8s.io/api/core/v1" 26 v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 28 schedulingv1beta1 "volcano.sh/apis/pkg/apis/scheduling/v1beta1" 29 30 e2eutil "volcano.sh/volcano/test/e2e/util" 31 ) 32 33 const ( 34 highPriority = "high-priority" 35 middlePriority = "middle-priority" 36 lowPriority = "low-priority" 37 highPriorityValue = 100 38 middlePriorityValue = 50 39 lowPriorityValue = 10 40 ) 41 42 var _ = Describe("Job E2E Test", func() { 43 It("schedule high priority job without preemption when resource is enough", func() { 44 ctx := e2eutil.InitTestContext(e2eutil.Options{ 45 PriorityClasses: map[string]int32{ 46 highPriority: highPriorityValue, 47 lowPriority: lowPriorityValue, 48 }, 49 }) 50 defer e2eutil.CleanupTestContext(ctx) 51 52 slot := e2eutil.OneCPU 53 54 job := &e2eutil.JobSpec{ 55 Tasks: []e2eutil.TaskSpec{ 56 { 57 Img: e2eutil.DefaultNginxImage, 58 Req: slot, 59 Min: 1, 60 Rep: 1, 61 Labels: map[string]string{schedulingv1beta1.PodPreemptable: "true"}, 62 }, 63 }, 64 } 65 66 job.Name = "preemptee" 67 job.Pri = lowPriority 68 preempteeJob := e2eutil.CreateJob(ctx, job) 69 err := e2eutil.WaitTasksReady(ctx, preempteeJob, 1) 70 Expect(err).NotTo(HaveOccurred()) 71 72 job.Name = "preemptor" 73 job.Pri = highPriority 74 preemptorJob := e2eutil.CreateJob(ctx, job) 75 err = e2eutil.WaitTasksReady(ctx, preempteeJob, 1) 76 Expect(err).NotTo(HaveOccurred()) 77 78 err = e2eutil.WaitTasksReady(ctx, preemptorJob, 1) 79 Expect(err).NotTo(HaveOccurred()) 80 }) 81 82 It("schedule high priority job with preemption when idle resource is NOT enough but preemptee resource is enough", func() { 83 ctx := e2eutil.InitTestContext(e2eutil.Options{ 84 PriorityClasses: map[string]int32{ 85 highPriority: highPriorityValue, 86 lowPriority: lowPriorityValue, 87 }, 88 }) 89 defer e2eutil.CleanupTestContext(ctx) 90 91 slot := e2eutil.OneCPU 92 rep := e2eutil.ClusterSize(ctx, slot) 93 94 job := &e2eutil.JobSpec{ 95 Tasks: []e2eutil.TaskSpec{ 96 { 97 Img: e2eutil.DefaultNginxImage, 98 Req: slot, 99 Min: 1, 100 Rep: rep, 101 Labels: map[string]string{schedulingv1beta1.PodPreemptable: "true"}, 102 }, 103 }, 104 } 105 106 job.Name = "preemptee" 107 job.Pri = lowPriority 108 preempteeJob := e2eutil.CreateJob(ctx, job) 109 err := e2eutil.WaitTasksReady(ctx, preempteeJob, int(rep)) 110 Expect(err).NotTo(HaveOccurred()) 111 112 job.Name = "preemptor" 113 job.Pri = highPriority 114 job.Min = rep / 2 115 preemptorJob := e2eutil.CreateJob(ctx, job) 116 err = e2eutil.WaitTasksReady(ctx, preempteeJob, int(rep)/2) 117 Expect(err).NotTo(HaveOccurred()) 118 119 err = e2eutil.WaitTasksReady(ctx, preemptorJob, int(rep)/2) 120 Expect(err).NotTo(HaveOccurred()) 121 }) 122 123 It("preemption doesn't work when podgroup is pending due to insufficient resource", func() { 124 ctx := e2eutil.InitTestContext(e2eutil.Options{ 125 PriorityClasses: map[string]int32{ 126 highPriority: highPriorityValue, 127 lowPriority: lowPriorityValue, 128 }, 129 }) 130 defer e2eutil.CleanupTestContext(ctx) 131 132 pgName := "pending-pg" 133 pg := &schedulingv1beta1.PodGroup{ 134 ObjectMeta: v1.ObjectMeta{ 135 Namespace: ctx.Namespace, 136 Name: pgName, 137 }, 138 Spec: schedulingv1beta1.PodGroupSpec{ 139 MinMember: 1, 140 MinResources: &e2eutil.ThirtyCPU, 141 }, 142 } 143 _, err := ctx.Vcclient.SchedulingV1beta1().PodGroups(ctx.Namespace).Create(context.TODO(), pg, v1.CreateOptions{}) 144 Expect(err).NotTo(HaveOccurred()) 145 146 slot := e2eutil.OneCPU 147 rep := e2eutil.ClusterSize(ctx, slot) 148 job := &e2eutil.JobSpec{ 149 Tasks: []e2eutil.TaskSpec{ 150 { 151 Img: e2eutil.DefaultNginxImage, 152 Req: slot, 153 Min: 1, 154 Rep: rep, 155 }, 156 }, 157 } 158 job.Name = "preemptee" 159 job.Pri = lowPriority 160 preempteeJob := e2eutil.CreateJob(ctx, job) 161 err = e2eutil.WaitTasksReady(ctx, preempteeJob, int(rep)) 162 Expect(err).NotTo(HaveOccurred()) 163 164 pod := &corev1.Pod{ 165 TypeMeta: v1.TypeMeta{ 166 APIVersion: "v1", 167 Kind: "Pod", 168 }, 169 ObjectMeta: v1.ObjectMeta{ 170 Namespace: ctx.Namespace, 171 Name: "preemptor-pod", 172 Annotations: map[string]string{schedulingv1beta1.KubeGroupNameAnnotationKey: pgName}, 173 }, 174 Spec: corev1.PodSpec{ 175 SchedulerName: "volcano", 176 Containers: e2eutil.CreateContainers(e2eutil.DefaultNginxImage, "", "", e2eutil.OneCPU, e2eutil.OneCPU, 0), 177 PriorityClassName: highPriority, 178 }, 179 } 180 // Pod is allowed to be created, preemption does not happen due to PodGroup is in pending state 181 _, err = ctx.Kubeclient.CoreV1().Pods(ctx.Namespace).Create(context.TODO(), pod, v1.CreateOptions{}) 182 Expect(err).NotTo(HaveOccurred()) 183 // Make sure preempteeJob is not preempted as expected 184 err = e2eutil.WaitTasksReady(ctx, preempteeJob, int(rep)) 185 Expect(err).NotTo(HaveOccurred()) 186 }) 187 188 It("preemption only works in the same queue", func() { 189 ctx := e2eutil.InitTestContext(e2eutil.Options{ 190 Queues: []string{"q1-preemption", "q2-reference"}, 191 PriorityClasses: map[string]int32{ 192 highPriority: highPriorityValue, 193 lowPriority: lowPriorityValue, 194 }, 195 }) 196 defer e2eutil.CleanupTestContext(ctx) 197 198 slot := e2eutil.OneCPU 199 rep := e2eutil.ClusterSize(ctx, slot) 200 job := &e2eutil.JobSpec{ 201 Tasks: []e2eutil.TaskSpec{ 202 { 203 Img: e2eutil.DefaultNginxImage, 204 Req: slot, 205 Min: 1, 206 Rep: rep / 2, 207 Labels: map[string]string{schedulingv1beta1.PodPreemptable: "true"}, 208 }, 209 }, 210 } 211 212 job.Name = "j1-q1" 213 job.Pri = lowPriority 214 job.Queue = "q1-preemption" 215 queue1Job := e2eutil.CreateJob(ctx, job) 216 err := e2eutil.WaitTasksReady(ctx, queue1Job, int(rep)/2) 217 Expect(err).NotTo(HaveOccurred()) 218 219 job.Name = "j2-q2" 220 job.Pri = lowPriority 221 job.Queue = "q2-reference" 222 queue2Job := e2eutil.CreateJob(ctx, job) 223 err = e2eutil.WaitTasksReady(ctx, queue2Job, int(rep)/2) 224 Expect(err).NotTo(HaveOccurred()) 225 226 job.Name = "j3-q1" 227 job.Pri = highPriority 228 job.Queue = "q1-preemption" 229 job.Tasks[0].Rep = rep 230 queue1Job3 := e2eutil.CreateJob(ctx, job) 231 err = e2eutil.WaitTasksReady(ctx, queue1Job3, int(rep)/2) 232 Expect(err).NotTo(HaveOccurred()) 233 err = e2eutil.WaitTasksReady(ctx, queue1Job, 0) 234 Expect(err).NotTo(HaveOccurred()) 235 }) 236 237 It("preemption doesn't work when total resource of idle resource and preemptee is NOT enough", func() { 238 ctx := e2eutil.InitTestContext(e2eutil.Options{ 239 Queues: []string{"q1-preemption", "q2-reference"}, 240 PriorityClasses: map[string]int32{ 241 highPriority: highPriorityValue, 242 lowPriority: lowPriorityValue, 243 }, 244 }) 245 defer e2eutil.CleanupTestContext(ctx) 246 247 slot := e2eutil.OneCPU 248 rep := e2eutil.ClusterSize(ctx, slot) 249 job := &e2eutil.JobSpec{ 250 Tasks: []e2eutil.TaskSpec{ 251 { 252 Img: e2eutil.DefaultNginxImage, 253 Req: slot, 254 Min: 1, 255 Rep: 1, 256 Labels: map[string]string{schedulingv1beta1.PodPreemptable: "true"}, 257 }, 258 }, 259 } 260 261 job.Name = "j1-q1" 262 job.Pri = lowPriority 263 job.Queue = "q1-preemption" 264 queue1Job := e2eutil.CreateJob(ctx, job) 265 err := e2eutil.WaitTasksReady(ctx, queue1Job, 1) 266 Expect(err).NotTo(HaveOccurred()) 267 268 job.Name = "j2-q2" 269 job.Pri = lowPriority 270 job.Queue = "q2-reference" 271 job.Tasks[0].Min = rep / 2 272 job.Tasks[0].Rep = rep / 2 273 queue2Job := e2eutil.CreateJob(ctx, job) 274 err = e2eutil.WaitTasksReady(ctx, queue2Job, int(rep)/2) 275 Expect(err).NotTo(HaveOccurred()) 276 277 job.Name = "j3-q1" 278 job.Pri = highPriority 279 job.Queue = "q1-preemption" 280 job.Tasks[0].Min = rep 281 job.Tasks[0].Rep = rep 282 queue1Job3 := e2eutil.CreateJob(ctx, job) 283 err = e2eutil.WaitTasksReady(ctx, queue1Job3, int(rep)) 284 Expect(err).To(HaveOccurred()) 285 err = e2eutil.WaitTasksReady(ctx, queue1Job, 1) 286 Expect(err).NotTo(HaveOccurred()) 287 err = e2eutil.WaitTasksReady(ctx, queue2Job, int(rep)/2) 288 Expect(err).NotTo(HaveOccurred()) 289 }) 290 291 It("multi-preemptor-jobs who are in different priority", func() { 292 Skip("https://github.com/volcano-sh/volcano/issues/911") 293 ctx := e2eutil.InitTestContext(e2eutil.Options{ 294 Queues: []string{"q1-preemption"}, 295 PriorityClasses: map[string]int32{ 296 highPriority: highPriorityValue, 297 middlePriority: middlePriorityValue, 298 lowPriority: lowPriorityValue, 299 }, 300 }) 301 defer e2eutil.CleanupTestContext(ctx) 302 303 slot := e2eutil.OneCPU 304 rep := e2eutil.ClusterSize(ctx, slot) 305 job := &e2eutil.JobSpec{ 306 Tasks: []e2eutil.TaskSpec{ 307 { 308 Img: e2eutil.DefaultNginxImage, 309 Req: slot, 310 Min: 1, 311 Rep: rep, 312 Labels: map[string]string{schedulingv1beta1.PodPreemptable: "true"}, 313 }, 314 }, 315 } 316 317 job.Name = "low-priority-job" 318 job.Pri = lowPriority 319 job.Queue = "q1-preemption" 320 lowPriorityJob := e2eutil.CreateJob(ctx, job) 321 err := e2eutil.WaitTasksReady(ctx, lowPriorityJob, int(rep)) 322 Expect(err).NotTo(HaveOccurred()) 323 324 job.Name = "middle-prority-job" 325 job.Pri = middlePriority 326 job.Queue = "q1-preemption" 327 job.Tasks[0].Rep = rep / 2 328 job.Tasks[0].Min = rep / 2 329 middlePriorityJob := e2eutil.CreateJob(ctx, job) 330 err = e2eutil.WaitTasksReady(ctx, middlePriorityJob, int(rep)/2) 331 Expect(err).NotTo(HaveOccurred()) 332 err = e2eutil.WaitTasksReady(ctx, lowPriorityJob, int(rep)/2) 333 Expect(err).NotTo(HaveOccurred()) 334 335 job.Name = "high-priority-job" 336 job.Pri = highPriority 337 job.Queue = "q1-preemption" 338 job.Tasks[0].Rep = rep 339 job.Tasks[0].Min = rep 340 highPriorityJob := e2eutil.CreateJob(ctx, job) 341 err = e2eutil.WaitTasksReady(ctx, highPriorityJob, int(rep)) 342 Expect(err).NotTo(HaveOccurred()) 343 err = e2eutil.WaitTasksReady(ctx, lowPriorityJob, 0) 344 Expect(err).NotTo(HaveOccurred()) 345 err = e2eutil.WaitTasksReady(ctx, middlePriorityJob, 0) 346 Expect(err).NotTo(HaveOccurred()) 347 }) 348 })