sigs.k8s.io/kueue@v0.6.2/pkg/util/testingjobs/pod/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 pod
    18  
    19  import (
    20  	"fmt"
    21  	"strconv"
    22  	"time"
    23  
    24  	corev1 "k8s.io/api/core/v1"
    25  	"k8s.io/apimachinery/pkg/api/resource"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/apimachinery/pkg/runtime/schema"
    28  	"k8s.io/apimachinery/pkg/types"
    29  	"k8s.io/utils/ptr"
    30  
    31  	"sigs.k8s.io/kueue/pkg/controller/constants"
    32  )
    33  
    34  // PodWrapper wraps a Pod.
    35  type PodWrapper struct {
    36  	corev1.Pod
    37  }
    38  
    39  // MakePod creates a wrapper for a pod with a single container.
    40  func MakePod(name, ns string) *PodWrapper {
    41  	return &PodWrapper{corev1.Pod{
    42  		ObjectMeta: metav1.ObjectMeta{
    43  			Name:        name,
    44  			Namespace:   ns,
    45  			Annotations: make(map[string]string, 1),
    46  		},
    47  		Spec: corev1.PodSpec{
    48  			RestartPolicy: corev1.RestartPolicyNever,
    49  			Containers: []corev1.Container{
    50  				{
    51  					Name:      "c",
    52  					Image:     "pause",
    53  					Resources: corev1.ResourceRequirements{Requests: corev1.ResourceList{}},
    54  				},
    55  			},
    56  			SchedulingGates: make([]corev1.PodSchedulingGate, 0),
    57  		},
    58  	}}
    59  }
    60  
    61  // Obj returns the inner Pod.
    62  func (p *PodWrapper) Obj() *corev1.Pod {
    63  	return &p.Pod
    64  }
    65  
    66  // Group returns multiple pods that form a pod group, based on the original wrapper.
    67  func (p *PodWrapper) MakeGroup(count int) []*corev1.Pod {
    68  	var pods []*corev1.Pod
    69  	for i := 0; i < count; i++ {
    70  		pod := p.Clone().Group(p.Pod.Name).GroupTotalCount(strconv.Itoa(count))
    71  		pod.Pod.Name += fmt.Sprintf("-%d", i)
    72  		pods = append(pods, pod.Obj())
    73  	}
    74  	return pods
    75  }
    76  
    77  // Clone returns deep copy of the Pod.
    78  func (p *PodWrapper) Clone() *PodWrapper {
    79  	return &PodWrapper{Pod: *p.DeepCopy()}
    80  }
    81  
    82  // Queue updates the queue name of the Pod
    83  func (p *PodWrapper) Queue(q string) *PodWrapper {
    84  	return p.Label(constants.QueueLabel, q)
    85  }
    86  
    87  // Queue updates the queue name of the Pod
    88  func (p *PodWrapper) PriorityClass(pc string) *PodWrapper {
    89  	p.Spec.PriorityClassName = pc
    90  	return p
    91  }
    92  
    93  // Name updated the name of the pod
    94  func (p *PodWrapper) Name(n string) *PodWrapper {
    95  	p.ObjectMeta.Name = n
    96  	return p
    97  }
    98  
    99  // Group updates the pod.GroupNameLabel of the Pod
   100  func (p *PodWrapper) Group(g string) *PodWrapper {
   101  	return p.Label("kueue.x-k8s.io/pod-group-name", g)
   102  }
   103  
   104  // GroupTotalCount updates the pod.GroupTotalCountAnnotation of the Pod
   105  func (p *PodWrapper) GroupTotalCount(gtc string) *PodWrapper {
   106  	return p.Annotation("kueue.x-k8s.io/pod-group-total-count", gtc)
   107  }
   108  
   109  // Label sets the label of the Pod
   110  func (p *PodWrapper) Label(k, v string) *PodWrapper {
   111  	if p.Labels == nil {
   112  		p.Labels = make(map[string]string)
   113  	}
   114  	p.Labels[k] = v
   115  	return p
   116  }
   117  
   118  func (p *PodWrapper) Annotation(key, content string) *PodWrapper {
   119  	p.Annotations[key] = content
   120  	return p
   121  }
   122  
   123  // RoleHash updates the pod.RoleHashAnnotation of the pod
   124  func (p *PodWrapper) RoleHash(h string) *PodWrapper {
   125  	return p.Annotation("kueue.x-k8s.io/role-hash", h)
   126  }
   127  
   128  // ParentWorkload sets the parent-workload annotation
   129  func (p *PodWrapper) ParentWorkload(parentWorkload string) *PodWrapper {
   130  	p.Annotations[constants.ParentWorkloadAnnotation] = parentWorkload
   131  	return p
   132  }
   133  
   134  // KueueSchedulingGate adds kueue scheduling gate to the Pod
   135  func (p *PodWrapper) KueueSchedulingGate() *PodWrapper {
   136  	if p.Spec.SchedulingGates == nil {
   137  		p.Spec.SchedulingGates = make([]corev1.PodSchedulingGate, 0)
   138  	}
   139  	p.Spec.SchedulingGates = append(p.Spec.SchedulingGates, corev1.PodSchedulingGate{Name: "kueue.x-k8s.io/admission"})
   140  	return p
   141  }
   142  
   143  // Finalizer adds a finalizer to the Pod
   144  func (p *PodWrapper) Finalizer(f string) *PodWrapper {
   145  	if p.ObjectMeta.Finalizers == nil {
   146  		p.ObjectMeta.Finalizers = make([]string, 0)
   147  	}
   148  	p.ObjectMeta.Finalizers = append(p.ObjectMeta.Finalizers, f)
   149  	return p
   150  }
   151  
   152  // KueueFinalizer adds kueue finalizer to the Pod
   153  func (p *PodWrapper) KueueFinalizer() *PodWrapper {
   154  	return p.Finalizer("kueue.x-k8s.io/managed")
   155  }
   156  
   157  // NodeSelector adds a node selector to the Pod.
   158  func (p *PodWrapper) NodeSelector(k, v string) *PodWrapper {
   159  	if p.Spec.NodeSelector == nil {
   160  		p.Spec.NodeSelector = make(map[string]string, 1)
   161  	}
   162  
   163  	p.Spec.NodeSelector[k] = v
   164  	return p
   165  }
   166  
   167  // Request adds a resource request to the default container.
   168  func (p *PodWrapper) Request(r corev1.ResourceName, v string) *PodWrapper {
   169  	p.Spec.Containers[0].Resources.Requests[r] = resource.MustParse(v)
   170  	return p
   171  }
   172  
   173  func (p *PodWrapper) Image(image string, args []string) *PodWrapper {
   174  	p.Spec.Containers[0].Image = image
   175  	p.Spec.Containers[0].Args = args
   176  	return p
   177  }
   178  
   179  // OwnerReference adds a ownerReference to the default container.
   180  func (p *PodWrapper) OwnerReference(ownerName string, ownerGVK schema.GroupVersionKind) *PodWrapper {
   181  	p.ObjectMeta.OwnerReferences = append(
   182  		p.ObjectMeta.OwnerReferences,
   183  		metav1.OwnerReference{
   184  			APIVersion: ownerGVK.GroupVersion().String(),
   185  			Kind:       ownerGVK.Kind,
   186  			Name:       ownerName,
   187  			UID:        types.UID(ownerName),
   188  			Controller: ptr.To(true),
   189  		},
   190  	)
   191  
   192  	return p
   193  }
   194  
   195  // UID updates the uid of the Pod.
   196  func (p *PodWrapper) UID(uid string) *PodWrapper {
   197  	p.ObjectMeta.UID = types.UID(uid)
   198  	return p
   199  }
   200  
   201  // StatusConditions updates status conditions of the Pod.
   202  func (p *PodWrapper) StatusConditions(conditions ...corev1.PodCondition) *PodWrapper {
   203  	p.Pod.Status.Conditions = conditions
   204  	return p
   205  }
   206  
   207  // StatusPhase updates status phase of the Pod.
   208  func (p *PodWrapper) StatusPhase(ph corev1.PodPhase) *PodWrapper {
   209  	p.Pod.Status.Phase = ph
   210  	return p
   211  }
   212  
   213  // CreationTimestamp sets a creation timestamp for the pod object
   214  func (p *PodWrapper) CreationTimestamp(t time.Time) *PodWrapper {
   215  	timestamp := metav1.NewTime(t).Rfc3339Copy()
   216  	p.Pod.CreationTimestamp = timestamp
   217  	return p
   218  }
   219  
   220  // DeletionTimestamp sets a creation timestamp for the pod object
   221  func (p *PodWrapper) DeletionTimestamp(t time.Time) *PodWrapper {
   222  	timestamp := metav1.NewTime(t).Rfc3339Copy()
   223  	p.Pod.DeletionTimestamp = &timestamp
   224  	return p
   225  }
   226  
   227  // Delete sets a deletion timestamp for the pod object
   228  func (p *PodWrapper) Delete() *PodWrapper {
   229  	t := metav1.NewTime(time.Now())
   230  	p.Pod.DeletionTimestamp = &t
   231  	return p
   232  }
   233  
   234  // Volume adds a new volume for the pod object
   235  func (p *PodWrapper) Volume(v corev1.Volume) *PodWrapper {
   236  	p.Pod.Spec.Volumes = append(p.Pod.Spec.Volumes, v)
   237  	return p
   238  }