sigs.k8s.io/kueue@v0.6.2/pkg/util/testingjobs/job/wrappers.go (about) 1 /* 2 Copyright 2022 The Kubernetes 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 testing 18 19 import ( 20 "time" 21 22 batchv1 "k8s.io/api/batch/v1" 23 corev1 "k8s.io/api/core/v1" 24 "k8s.io/apimachinery/pkg/api/resource" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/apimachinery/pkg/runtime/schema" 27 "k8s.io/apimachinery/pkg/types" 28 "k8s.io/utils/ptr" 29 30 "sigs.k8s.io/kueue/pkg/controller/constants" 31 ) 32 33 // JobWrapper wraps a Job. 34 type JobWrapper struct{ batchv1.Job } 35 36 // MakeJob creates a wrapper for a suspended job with a single container and parallelism=1. 37 func MakeJob(name, ns string) *JobWrapper { 38 return &JobWrapper{batchv1.Job{ 39 ObjectMeta: metav1.ObjectMeta{ 40 Name: name, 41 Namespace: ns, 42 Annotations: make(map[string]string, 1), 43 }, 44 Spec: batchv1.JobSpec{ 45 Parallelism: ptr.To[int32](1), 46 Suspend: ptr.To(true), 47 Template: corev1.PodTemplateSpec{ 48 Spec: corev1.PodSpec{ 49 RestartPolicy: corev1.RestartPolicyNever, 50 Containers: []corev1.Container{ 51 { 52 Name: "c", 53 Image: "pause", 54 Resources: corev1.ResourceRequirements{Requests: corev1.ResourceList{}}, 55 }, 56 }, 57 NodeSelector: map[string]string{}, 58 }, 59 }, 60 }, 61 }} 62 } 63 64 // Obj returns the inner Job. 65 func (j *JobWrapper) Obj() *batchv1.Job { 66 return &j.Job 67 } 68 69 // Clone returns deep copy of the Job. 70 func (j *JobWrapper) Clone() *JobWrapper { 71 return &JobWrapper{Job: *j.DeepCopy()} 72 } 73 74 func (j *JobWrapper) BackoffLimit(limit int32) *JobWrapper { 75 j.Spec.BackoffLimit = ptr.To(limit) 76 return j 77 } 78 79 func (j *JobWrapper) TerminationGracePeriod(seconds int64) *JobWrapper { 80 j.Spec.Template.Spec.TerminationGracePeriodSeconds = ptr.To(seconds) 81 return j 82 } 83 84 // Suspend updates the suspend status of the job 85 func (j *JobWrapper) Suspend(s bool) *JobWrapper { 86 j.Spec.Suspend = ptr.To(s) 87 return j 88 } 89 90 // Parallelism updates job parallelism. 91 func (j *JobWrapper) Parallelism(p int32) *JobWrapper { 92 j.Spec.Parallelism = ptr.To(p) 93 return j 94 } 95 96 // Completions updates job completions. 97 func (j *JobWrapper) Completions(p int32) *JobWrapper { 98 j.Spec.Completions = ptr.To(p) 99 return j 100 } 101 102 // Indexed sets the job's completion to Indexed of NonIndexed 103 func (j *JobWrapper) Indexed(indexed bool) *JobWrapper { 104 mode := batchv1.NonIndexedCompletion 105 if indexed { 106 mode = batchv1.IndexedCompletion 107 } 108 j.Spec.CompletionMode = &mode 109 return j 110 } 111 112 // PriorityClass updates job priorityclass. 113 func (j *JobWrapper) PriorityClass(pc string) *JobWrapper { 114 j.Spec.Template.Spec.PriorityClassName = pc 115 return j 116 } 117 118 // WorkloadPriorityClass updates job workloadpriorityclass. 119 func (j *JobWrapper) WorkloadPriorityClass(wpc string) *JobWrapper { 120 return j.Label(constants.WorkloadPriorityClassLabel, wpc) 121 } 122 123 // Queue updates the queue name of the job 124 func (j *JobWrapper) Queue(queue string) *JobWrapper { 125 return j.Label(constants.QueueLabel, queue) 126 } 127 128 // Label sets the label key and value 129 func (j *JobWrapper) Label(key, value string) *JobWrapper { 130 if j.Labels == nil { 131 j.Labels = make(map[string]string) 132 } 133 j.Labels[key] = value 134 return j 135 } 136 137 // QueueNameAnnotation updates the queue name of the job by annotation (deprecated) 138 func (j *JobWrapper) QueueNameAnnotation(queue string) *JobWrapper { 139 return j.SetAnnotation(constants.QueueAnnotation, queue) 140 } 141 142 // ParentWorkload sets the parent-workload annotation 143 func (j *JobWrapper) ParentWorkload(parentWorkload string) *JobWrapper { 144 j.Annotations[constants.ParentWorkloadAnnotation] = parentWorkload 145 return j 146 } 147 148 func (j *JobWrapper) SetAnnotation(key, content string) *JobWrapper { 149 j.Annotations[key] = content 150 return j 151 } 152 153 // Toleration adds a toleration to the job. 154 func (j *JobWrapper) Toleration(t corev1.Toleration) *JobWrapper { 155 j.Spec.Template.Spec.Tolerations = append(j.Spec.Template.Spec.Tolerations, t) 156 return j 157 } 158 159 // NodeSelector adds a node selector to the job. 160 func (j *JobWrapper) NodeSelector(k, v string) *JobWrapper { 161 j.Spec.Template.Spec.NodeSelector[k] = v 162 return j 163 } 164 165 // PodAnnotation sets annotation at the pod template level 166 func (j *JobWrapper) PodAnnotation(k, v string) *JobWrapper { 167 if j.Spec.Template.Annotations == nil { 168 j.Spec.Template.Annotations = make(map[string]string) 169 } 170 j.Spec.Template.Annotations[k] = v 171 return j 172 } 173 174 // PodLabel sets label at the pod template level 175 func (j *JobWrapper) PodLabel(k, v string) *JobWrapper { 176 if j.Spec.Template.Labels == nil { 177 j.Spec.Template.Labels = make(map[string]string) 178 } 179 j.Spec.Template.Labels[k] = v 180 return j 181 } 182 183 // Request adds a resource request to the default container. 184 func (j *JobWrapper) Request(r corev1.ResourceName, v string) *JobWrapper { 185 j.Spec.Template.Spec.Containers[0].Resources.Requests[r] = resource.MustParse(v) 186 return j 187 } 188 189 func (j *JobWrapper) Image(image string, args []string) *JobWrapper { 190 j.Spec.Template.Spec.Containers[0].Image = image 191 j.Spec.Template.Spec.Containers[0].Args = args 192 return j 193 } 194 195 // OwnerReference adds a ownerReference to the default container. 196 func (j *JobWrapper) OwnerReference(ownerName string, ownerGVK schema.GroupVersionKind) *JobWrapper { 197 j.ObjectMeta.OwnerReferences = []metav1.OwnerReference{ 198 { 199 APIVersion: ownerGVK.GroupVersion().String(), 200 Kind: ownerGVK.Kind, 201 Name: ownerName, 202 UID: types.UID(ownerName), 203 Controller: ptr.To(true), 204 }, 205 } 206 return j 207 } 208 209 func (j *JobWrapper) Containers(containers ...corev1.Container) *JobWrapper { 210 j.Spec.Template.Spec.Containers = containers 211 return j 212 } 213 214 // UID updates the uid of the job. 215 func (j *JobWrapper) UID(uid string) *JobWrapper { 216 j.ObjectMeta.UID = types.UID(uid) 217 return j 218 } 219 220 // StartTime sets the .status.startTime 221 func (j *JobWrapper) StartTime(t time.Time) *JobWrapper { 222 j.Status.StartTime = &metav1.Time{Time: t} 223 return j 224 } 225 226 // Active sets the .status.active 227 func (j *JobWrapper) Active(c int32) *JobWrapper { 228 j.Status.Active = c 229 return j 230 } 231 232 // Condition adds a condition 233 func (j *JobWrapper) Condition(c batchv1.JobCondition) *JobWrapper { 234 j.Status.Conditions = append(j.Status.Conditions, c) 235 return j 236 } 237 238 func SetContainerDefaults(c *corev1.Container) { 239 if c.TerminationMessagePath == "" { 240 c.TerminationMessagePath = "/dev/termination-log" 241 } 242 243 if c.TerminationMessagePolicy == "" { 244 c.TerminationMessagePolicy = corev1.TerminationMessageReadFile 245 } 246 247 if c.ImagePullPolicy == "" { 248 c.ImagePullPolicy = corev1.PullIfNotPresent 249 } 250 }