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  }