Skip to content

Commit 51ee86c

Browse files
Merge pull request volcano-sh#174 from TommyLike/feature/job_priority_class
Support job level priorityClassName
2 parents 5e56f4e + 9f2ccc0 commit 51ee86c

File tree

5 files changed

+187
-12
lines changed

5 files changed

+187
-12
lines changed

pkg/admission/admit_job_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
/*
2+
Copyright 2019 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+
117
package admission
218

319
import (

pkg/admission/mutate_job.go

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,28 +74,41 @@ func MutateJobs(ar v1beta1.AdmissionReview) *v1beta1.AdmissionResponse {
7474

7575
func createPatch(job v1alpha1.Job) ([]byte, error) {
7676
var patch []patchOperation
77-
patch = append(patch, mutateSpec(job.Spec.Tasks, "/spec/tasks")...)
77+
pathQueue := patchDefaultQueue(job)
78+
if pathQueue != nil {
79+
patch = append(patch, *pathQueue)
80+
}
81+
pathSpec := mutateSpec(job.Spec.Tasks, "/spec/tasks")
82+
if pathSpec != nil {
83+
patch = append(patch, *pathSpec)
84+
}
85+
return json.Marshal(patch)
86+
}
87+
88+
func patchDefaultQueue(job v1alpha1.Job) *patchOperation {
7889
//Add default queue if not specified.
7990
if job.Spec.Queue == "" {
80-
patch = append(patch, patchOperation{Op: "add", Path: "/spec/queue", Value: DefaultQueue})
91+
return &patchOperation{Op: "add", Path: "/spec/queue", Value: DefaultQueue}
8192
}
82-
83-
return json.Marshal(patch)
93+
return nil
8494
}
8595

86-
func mutateSpec(tasks []v1alpha1.TaskSpec, basePath string) (patch []patchOperation) {
96+
func mutateSpec(tasks []v1alpha1.TaskSpec, basePath string) *patchOperation {
97+
patched := false
8798
for index := range tasks {
8899
// add default task name
89100
taskName := tasks[index].Name
90101
if len(taskName) == 0 {
102+
patched = true
91103
tasks[index].Name = v1alpha1.DefaultTaskSpec + strconv.Itoa(index)
92104
}
93105
}
94-
patch = append(patch, patchOperation{
106+
if !patched {
107+
return nil
108+
}
109+
return &patchOperation{
95110
Op: "replace",
96111
Path: basePath,
97112
Value: tasks,
98-
})
99-
100-
return patch
113+
}
101114
}

pkg/admission/mutate_job_test.go

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/*
2+
Copyright 2019 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 admission
18+
19+
import (
20+
"k8s.io/api/core/v1"
21+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
22+
"testing"
23+
"volcano.sh/volcano/pkg/apis/batch/v1alpha1"
24+
)
25+
26+
func TestCreatePatchExecution(t *testing.T) {
27+
28+
namespace := "test"
29+
30+
testCase := struct {
31+
Name string
32+
Job v1alpha1.Job
33+
operation patchOperation
34+
}{
35+
Name: "patch default task name",
36+
Job: v1alpha1.Job{
37+
ObjectMeta: metav1.ObjectMeta{
38+
Name: "path-task-name",
39+
Namespace: namespace,
40+
},
41+
Spec: v1alpha1.JobSpec{
42+
MinAvailable: 1,
43+
Tasks: []v1alpha1.TaskSpec{
44+
{
45+
Replicas: 1,
46+
Template: v1.PodTemplateSpec{
47+
ObjectMeta: metav1.ObjectMeta{
48+
Labels: map[string]string{"name": "test"},
49+
},
50+
Spec: v1.PodSpec{
51+
Containers: []v1.Container{
52+
{
53+
Name: "fake-name",
54+
Image: "busybox:1.24",
55+
},
56+
},
57+
},
58+
},
59+
},
60+
{
61+
Replicas: 1,
62+
Template: v1.PodTemplateSpec{
63+
ObjectMeta: metav1.ObjectMeta{
64+
Labels: map[string]string{"name": "test"},
65+
},
66+
Spec: v1.PodSpec{
67+
Containers: []v1.Container{
68+
{
69+
Name: "fake-name",
70+
Image: "busybox:1.24",
71+
},
72+
},
73+
},
74+
},
75+
},
76+
},
77+
},
78+
},
79+
operation: patchOperation{
80+
Op: "replace",
81+
Path: "/spec/tasks",
82+
Value: []v1alpha1.TaskSpec{
83+
{
84+
Name: v1alpha1.DefaultTaskSpec + "0",
85+
Replicas: 1,
86+
Template: v1.PodTemplateSpec{
87+
ObjectMeta: metav1.ObjectMeta{
88+
Labels: map[string]string{"name": "test"},
89+
},
90+
Spec: v1.PodSpec{
91+
Containers: []v1.Container{
92+
{
93+
Name: "fake-name",
94+
Image: "busybox:1.24",
95+
},
96+
},
97+
},
98+
},
99+
},
100+
{
101+
Name: v1alpha1.DefaultTaskSpec + "1",
102+
Replicas: 1,
103+
Template: v1.PodTemplateSpec{
104+
ObjectMeta: metav1.ObjectMeta{
105+
Labels: map[string]string{"name": "test"},
106+
},
107+
Spec: v1.PodSpec{
108+
Containers: []v1.Container{
109+
{
110+
Name: "fake-name",
111+
Image: "busybox:1.24",
112+
},
113+
},
114+
},
115+
},
116+
},
117+
},
118+
},
119+
}
120+
121+
ret := mutateSpec(testCase.Job.Spec.Tasks, "/spec/tasks")
122+
if ret.Path != testCase.operation.Path || ret.Op != testCase.operation.Op {
123+
t.Errorf("testCase %s's expected patch operation %v, but got %v",
124+
testCase.Name, testCase.operation, *ret)
125+
}
126+
127+
actualTasks, ok := ret.Value.([]v1alpha1.TaskSpec)
128+
if !ok {
129+
t.Errorf("testCase '%s' path value expected to be '[]v1alpha1.TaskSpec', but negative",
130+
testCase.Name)
131+
}
132+
expectedTasks, _ := testCase.operation.Value.([]v1alpha1.TaskSpec)
133+
for index, task := range expectedTasks {
134+
aTask := actualTasks[index]
135+
if aTask.Name != task.Name {
136+
t.Errorf("testCase '%s's expected patch operation with value %v, but got %v",
137+
testCase.Name, testCase.operation.Value, ret.Value)
138+
}
139+
}
140+
141+
}

pkg/apis/batch/v1alpha1/job.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ type JobSpec struct {
7979
// the Job becomes eligible to be deleted immediately after it finishes.
8080
// +optional
8181
TTLSecondsAfterFinished *int32 `json:"ttlSecondsAfterFinished,omitempty" protobuf:"varint,9,opt,name=ttlSecondsAfterFinished"`
82+
83+
// If specified, indicates the job's priority.
84+
// +optional
85+
PriorityClassName string `json:"priorityClassName,omitempty" protobuf:"bytes,10,opt,name=priorityClassName"`
8286
}
8387

8488
// VolumeSpec defines the specification of Volume, e.g. PVC

pkg/controllers/job/job_controller_actions.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -448,9 +448,10 @@ func (cc *Controller) createPodGroupIfNotExist(job *vkv1.Job) error {
448448
},
449449
},
450450
Spec: kbv1.PodGroupSpec{
451-
MinMember: job.Spec.MinAvailable,
452-
Queue: job.Spec.Queue,
453-
MinResources: cc.calcPGMinResources(job),
451+
MinMember: job.Spec.MinAvailable,
452+
Queue: job.Spec.Queue,
453+
MinResources: cc.calcPGMinResources(job),
454+
PriorityClassName: job.Spec.PriorityClassName,
454455
},
455456
}
456457

0 commit comments

Comments
 (0)