volcano.sh/volcano@v1.9.0/pkg/controllers/job/job_controller_util.go (about) 1 /* 2 Copyright 2017 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 job 18 19 import ( 20 "fmt" 21 "strconv" 22 23 v1 "k8s.io/api/core/v1" 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 "k8s.io/apimachinery/pkg/runtime/schema" 26 "k8s.io/klog/v2" 27 28 batch "volcano.sh/apis/pkg/apis/batch/v1alpha1" 29 "volcano.sh/apis/pkg/apis/bus/v1alpha1" 30 "volcano.sh/apis/pkg/apis/helpers" 31 schedulingv2 "volcano.sh/apis/pkg/apis/scheduling/v1beta1" 32 "volcano.sh/volcano/pkg/controllers/apis" 33 jobhelpers "volcano.sh/volcano/pkg/controllers/job/helpers" 34 ) 35 36 // MakePodName append podname,jobname,taskName and index and returns the string. 37 func MakePodName(jobName string, taskName string, index int) string { 38 return fmt.Sprintf(jobhelpers.PodNameFmt, jobName, taskName, index) 39 } 40 41 func createJobPod(job *batch.Job, template *v1.PodTemplateSpec, topologyPolicy batch.NumaPolicy, ix int, jobForwarding bool) *v1.Pod { 42 templateCopy := template.DeepCopy() 43 44 pod := &v1.Pod{ 45 ObjectMeta: metav1.ObjectMeta{ 46 Name: jobhelpers.MakePodName(job.Name, template.Name, ix), 47 Namespace: job.Namespace, 48 OwnerReferences: []metav1.OwnerReference{ 49 *metav1.NewControllerRef(job, helpers.JobKind), 50 }, 51 Labels: templateCopy.Labels, 52 Annotations: templateCopy.Annotations, 53 }, 54 Spec: templateCopy.Spec, 55 } 56 57 // If no scheduler name in Pod, use scheduler name from Job. 58 if len(pod.Spec.SchedulerName) == 0 { 59 pod.Spec.SchedulerName = job.Spec.SchedulerName 60 } 61 62 volumeMap := make(map[string]string) 63 for _, volume := range job.Spec.Volumes { 64 vcName := volume.VolumeClaimName 65 name := fmt.Sprintf("%s-%s", job.Name, jobhelpers.GenRandomStr(12)) 66 if _, ok := volumeMap[vcName]; !ok { 67 volume := v1.Volume{ 68 Name: name, 69 VolumeSource: v1.VolumeSource{ 70 PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ 71 ClaimName: vcName, 72 }, 73 }, 74 } 75 pod.Spec.Volumes = append(pod.Spec.Volumes, volume) 76 volumeMap[vcName] = name 77 } else { 78 // duplicate volumes, should be prevented 79 continue 80 } 81 82 for i, c := range pod.Spec.Containers { 83 vm := v1.VolumeMount{ 84 MountPath: volume.MountPath, 85 Name: name, 86 } 87 pod.Spec.Containers[i].VolumeMounts = append(c.VolumeMounts, vm) 88 } 89 } 90 91 tsKey := templateCopy.Name 92 if len(tsKey) == 0 { 93 tsKey = batch.DefaultTaskSpec 94 } 95 96 if len(pod.Annotations) == 0 { 97 pod.Annotations = make(map[string]string) 98 } 99 100 index := strconv.Itoa(ix) 101 pod.Annotations[batch.TaskIndex] = index 102 pod.Annotations[batch.TaskSpecKey] = tsKey 103 pgName := job.Name + "-" + string(job.UID) 104 pod.Annotations[schedulingv2.KubeGroupNameAnnotationKey] = pgName 105 pod.Annotations[batch.JobNameKey] = job.Name 106 pod.Annotations[batch.QueueNameKey] = job.Spec.Queue 107 pod.Annotations[batch.JobVersion] = fmt.Sprintf("%d", job.Status.Version) 108 pod.Annotations[batch.PodTemplateKey] = fmt.Sprintf("%s-%s", job.Name, template.Name) 109 110 if topologyPolicy != "" { 111 pod.Annotations[schedulingv2.NumaPolicyKey] = string(topologyPolicy) 112 } 113 114 if len(job.Annotations) > 0 { 115 if value, found := job.Annotations[schedulingv2.PodPreemptable]; found { 116 pod.Annotations[schedulingv2.PodPreemptable] = value 117 } 118 if value, found := job.Annotations[schedulingv2.CooldownTime]; found { 119 pod.Annotations[schedulingv2.CooldownTime] = value 120 } 121 if value, found := job.Annotations[schedulingv2.RevocableZone]; found { 122 pod.Annotations[schedulingv2.RevocableZone] = value 123 } 124 125 if value, found := job.Annotations[schedulingv2.JDBMinAvailable]; found { 126 pod.Annotations[schedulingv2.JDBMinAvailable] = value 127 } else if value, found := job.Annotations[schedulingv2.JDBMaxUnavailable]; found { 128 pod.Annotations[schedulingv2.JDBMaxUnavailable] = value 129 } 130 } 131 132 if len(pod.Labels) == 0 { 133 pod.Labels = make(map[string]string) 134 } 135 136 // Set pod labels for Service. 137 pod.Labels[batch.TaskIndex] = index 138 pod.Labels[batch.JobNameKey] = job.Name 139 pod.Labels[batch.TaskSpecKey] = tsKey 140 pod.Labels[batch.JobNamespaceKey] = job.Namespace 141 pod.Labels[batch.QueueNameKey] = job.Spec.Queue 142 if len(job.Labels) > 0 { 143 if value, found := job.Labels[schedulingv2.PodPreemptable]; found { 144 pod.Labels[schedulingv2.PodPreemptable] = value 145 } 146 if value, found := job.Labels[schedulingv2.CooldownTime]; found { 147 pod.Labels[schedulingv2.CooldownTime] = value 148 } 149 } 150 151 if jobForwarding { 152 pod.Annotations[batch.JobForwardingKey] = "true" 153 pod.Labels[batch.JobForwardingKey] = "true" 154 } 155 156 return pod 157 } 158 159 func applyPolicies(job *batch.Job, req *apis.Request) v1alpha1.Action { 160 if len(req.Action) != 0 { 161 return req.Action 162 } 163 164 if req.Event == v1alpha1.OutOfSyncEvent { 165 return v1alpha1.SyncJobAction 166 } 167 168 // For all the requests triggered from discarded job resources will perform sync action instead 169 if req.JobVersion < job.Status.Version { 170 klog.Infof("Request %s is outdated, will perform sync instead.", req) 171 return v1alpha1.SyncJobAction 172 } 173 174 // Overwrite Job level policies 175 if len(req.TaskName) != 0 { 176 // Parse task level policies 177 for _, task := range job.Spec.Tasks { 178 if task.Name == req.TaskName { 179 for _, policy := range task.Policies { 180 policyEvents := getEventlist(policy) 181 182 if len(policyEvents) > 0 && len(req.Event) > 0 { 183 if checkEventExist(policyEvents, req.Event) || checkEventExist(policyEvents, v1alpha1.AnyEvent) { 184 return policy.Action 185 } 186 } 187 188 // 0 is not an error code, is prevented in validation admission controller 189 if policy.ExitCode != nil && *policy.ExitCode == req.ExitCode { 190 return policy.Action 191 } 192 } 193 break 194 } 195 } 196 } 197 198 // Parse Job level policies 199 for _, policy := range job.Spec.Policies { 200 policyEvents := getEventlist(policy) 201 202 if len(policyEvents) > 0 && len(req.Event) > 0 { 203 if checkEventExist(policyEvents, req.Event) || checkEventExist(policyEvents, v1alpha1.AnyEvent) { 204 return policy.Action 205 } 206 } 207 208 // 0 is not an error code, is prevented in validation admission controller 209 if policy.ExitCode != nil && *policy.ExitCode == req.ExitCode { 210 return policy.Action 211 } 212 } 213 214 return v1alpha1.SyncJobAction 215 } 216 217 func getEventlist(policy batch.LifecyclePolicy) []v1alpha1.Event { 218 policyEventsList := policy.Events 219 if len(policy.Event) > 0 { 220 policyEventsList = append(policyEventsList, policy.Event) 221 } 222 return policyEventsList 223 } 224 225 func checkEventExist(policyEvents []v1alpha1.Event, reqEvent v1alpha1.Event) bool { 226 for _, event := range policyEvents { 227 if event == reqEvent { 228 return true 229 } 230 } 231 return false 232 } 233 234 // TaskPriority structure. 235 type TaskPriority struct { 236 priority int32 237 238 batch.TaskSpec 239 } 240 241 // TasksPriority is a slice of TaskPriority. 242 type TasksPriority []TaskPriority 243 244 func (p TasksPriority) Len() int { return len(p) } 245 246 func (p TasksPriority) Less(i, j int) bool { 247 return p[i].priority > p[j].priority 248 } 249 250 func (p TasksPriority) Swap(i, j int) { p[i], p[j] = p[j], p[i] } 251 252 func isControlledBy(obj metav1.Object, gvk schema.GroupVersionKind) bool { 253 controllerRef := metav1.GetControllerOf(obj) 254 if controllerRef == nil { 255 return false 256 } 257 if controllerRef.APIVersion == gvk.GroupVersion().String() && controllerRef.Kind == gvk.Kind { 258 return true 259 } 260 return false 261 }