sigs.k8s.io/kueue@v0.6.2/pkg/util/testingjobs/jobset/wrappers.go (about) 1 /* 2 Copyright 2023 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 jobset 18 19 import ( 20 corev1 "k8s.io/api/core/v1" 21 apimeta "k8s.io/apimachinery/pkg/api/meta" 22 "k8s.io/apimachinery/pkg/api/resource" 23 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 "k8s.io/utils/ptr" 25 jobsetapi "sigs.k8s.io/jobset/api/jobset/v1alpha2" 26 jobsetutil "sigs.k8s.io/jobset/pkg/util/testing" 27 28 "sigs.k8s.io/kueue/pkg/controller/constants" 29 ) 30 31 // JobSetWrapper wraps a JobSet. 32 type JobSetWrapper struct{ jobsetapi.JobSet } 33 34 // TestPodSpec is the default pod spec used for testing. 35 var TestPodSpec = corev1.PodSpec{ 36 RestartPolicy: corev1.RestartPolicyNever, 37 Containers: []corev1.Container{ 38 { 39 Name: "test-container", 40 Image: "busybox:latest", 41 }, 42 }, 43 } 44 45 type ReplicatedJobRequirements struct { 46 Name string 47 Replicas int32 48 Parallelism int32 49 Completions int32 50 Annotations map[string]string 51 Image string 52 Args []string 53 } 54 55 // MakeJobSet creates a wrapper for a suspended JobSet 56 func MakeJobSet(name, ns string) *JobSetWrapper { 57 jobSetWrapper := *jobsetutil.MakeJobSet(name, ns) 58 return &JobSetWrapper{*jobSetWrapper.Suspend(true).Obj()} 59 } 60 61 // Obj returns the inner JobSet. 62 func (j *JobSetWrapper) Obj() *jobsetapi.JobSet { 63 return &j.JobSet 64 } 65 66 // DeepCopy returns a DeepCopy of j. 67 func (j *JobSetWrapper) DeepCopy() *JobSetWrapper { 68 return &JobSetWrapper{JobSet: *j.JobSet.DeepCopy()} 69 } 70 71 // ReplicatedJobs sets a new set of ReplicatedJobs in the inner JobSet. 72 func (j *JobSetWrapper) ReplicatedJobs(replicatedJobs ...ReplicatedJobRequirements) *JobSetWrapper { 73 j.Spec.ReplicatedJobs = make([]jobsetapi.ReplicatedJob, len(replicatedJobs)) 74 for index, req := range replicatedJobs { 75 jt := jobsetutil.MakeJobTemplate("", "").PodSpec(TestPodSpec).Obj() 76 jt.Annotations = req.Annotations 77 jt.Spec.Parallelism = ptr.To(req.Parallelism) 78 jt.Spec.Completions = ptr.To(req.Completions) 79 if len(req.Image) > 0 { 80 jt.Spec.BackoffLimit = ptr.To[int32](0) 81 spec := &jt.Spec.Template.Spec 82 spec.RestartPolicy = corev1.RestartPolicyNever 83 spec.TerminationGracePeriodSeconds = ptr.To[int64](0) 84 spec.Containers = []corev1.Container{ 85 { 86 Name: "c", 87 Image: req.Image, 88 Args: req.Args, 89 }, 90 } 91 } 92 j.Spec.ReplicatedJobs[index] = jobsetutil.MakeReplicatedJob(req.Name).Job(jt).Replicas(req.Replicas).Obj() 93 } 94 return j 95 } 96 97 // Suspend updates the suspend status of the JobSet. 98 func (j *JobSetWrapper) Suspend(s bool) *JobSetWrapper { 99 j.Spec.Suspend = ptr.To(s) 100 return j 101 } 102 103 // Label sets a label to the JobSet. 104 func (j *JobSetWrapper) Label(k, v string) *JobSetWrapper { 105 if j.Labels == nil { 106 j.Labels = make(map[string]string) 107 } 108 j.Labels[k] = v 109 return j 110 } 111 112 // Queue updates the queue name of the JobSet. 113 func (j *JobSetWrapper) Queue(queue string) *JobSetWrapper { 114 return j.Label(constants.QueueLabel, queue) 115 } 116 117 // Request adds a resource request to the first container of the target replicatedJob. 118 func (j *JobSetWrapper) Request(replicatedJobName string, r corev1.ResourceName, v string) *JobSetWrapper { 119 for i, replicatedJob := range j.Spec.ReplicatedJobs { 120 if replicatedJob.Name == replicatedJobName { 121 if j.Spec.ReplicatedJobs[i].Template.Spec.Template.Spec.Containers[0].Resources.Requests == nil { 122 j.Spec.ReplicatedJobs[i].Template.Spec.Template.Spec.Containers[0].Resources.Requests = map[corev1.ResourceName]resource.Quantity{} 123 } 124 j.Spec.ReplicatedJobs[i].Template.Spec.Template.Spec.Containers[0].Resources.Requests[r] = resource.MustParse(v) 125 } 126 } 127 return j 128 } 129 130 // PriorityClass updates JobSet priorityclass. 131 func (j *JobSetWrapper) PriorityClass(pc string) *JobSetWrapper { 132 for i := range j.Spec.ReplicatedJobs { 133 j.Spec.ReplicatedJobs[i].Template.Spec.Template.Spec.PriorityClassName = pc 134 } 135 return j 136 } 137 138 // WorkloadPriorityClass updates JobSet workloadpriorityclass. 139 func (j *JobSetWrapper) WorkloadPriorityClass(wpc string) *JobSetWrapper { 140 if j.Labels == nil { 141 j.Labels = make(map[string]string) 142 } 143 j.Labels[constants.WorkloadPriorityClassLabel] = wpc 144 return j 145 } 146 147 // JobsStatus updates JobSet status. 148 func (j *JobSetWrapper) JobsStatus(statuses ...jobsetapi.ReplicatedJobStatus) *JobSetWrapper { 149 j.Status.ReplicatedJobsStatus = statuses 150 return j 151 } 152 153 // Condition adds a condition 154 func (j *JobSetWrapper) Condition(c metav1.Condition) *JobSetWrapper { 155 apimeta.SetStatusCondition(&j.Status.Conditions, c) 156 return j 157 }