github.com/kubeflow/training-operator@v1.7.0/pkg/controller.v1/common/util.go (about)

     1  // Copyright 2019 The Kubeflow Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package common
    16  
    17  import (
    18  	"fmt"
    19  	"sort"
    20  	"strings"
    21  
    22  	apiv1 "github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1"
    23  	log "github.com/sirupsen/logrus"
    24  	v1 "k8s.io/api/core/v1"
    25  	schedulingv1 "k8s.io/api/scheduling/v1"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  )
    28  
    29  // ReplicasPriority is a slice of ReplicaPriority.
    30  type ReplicasPriority []ReplicaPriority
    31  
    32  type ReplicaPriority struct {
    33  	priority int32
    34  
    35  	apiv1.ReplicaSpec
    36  }
    37  
    38  func (p ReplicasPriority) Len() int {
    39  	return len(p)
    40  }
    41  
    42  func (p ReplicasPriority) Less(i, j int) bool {
    43  	return p[i].priority > p[j].priority
    44  }
    45  
    46  func (p ReplicasPriority) Swap(i, j int) {
    47  	p[i], p[j] = p[j], p[i]
    48  }
    49  
    50  func GenGeneralName(jobName string, rtype string, index string) string {
    51  	n := jobName + "-" + strings.ToLower(rtype) + "-" + index
    52  	return strings.Replace(n, "/", "-", -1)
    53  }
    54  
    55  // RecheckDeletionTimestamp returns a CanAdopt() function to recheck deletion.
    56  //
    57  // The CanAdopt() function calls getObject() to fetch the latest value,
    58  // and denies adoption attempts if that object has a non-nil DeletionTimestamp.
    59  func RecheckDeletionTimestamp(getObject func() (metav1.Object, error)) func() error {
    60  	return func() error {
    61  		obj, err := getObject()
    62  		if err != nil {
    63  			return fmt.Errorf("can't recheck DeletionTimestamp: %v", err)
    64  		}
    65  		if obj.GetDeletionTimestamp() != nil {
    66  			return fmt.Errorf("%v/%v has just been deleted at %v", obj.GetNamespace(), obj.GetName(), obj.GetDeletionTimestamp())
    67  		}
    68  		return nil
    69  	}
    70  }
    71  
    72  func MaxInt(x, y int) int {
    73  	if x < y {
    74  		return y
    75  	}
    76  	return x
    77  }
    78  
    79  func AddResourceList(list, req, limit v1.ResourceList) {
    80  	for name, quantity := range req {
    81  
    82  		if value, ok := list[name]; !ok {
    83  			list[name] = quantity.DeepCopy()
    84  		} else {
    85  			value.Add(quantity)
    86  			list[name] = value
    87  		}
    88  	}
    89  
    90  	if req != nil {
    91  		return
    92  	}
    93  
    94  	// If Requests is omitted for a container,
    95  	// it defaults to Limits if that is explicitly specified.
    96  	for name, quantity := range limit {
    97  		if value, ok := list[name]; !ok {
    98  			list[name] = quantity.DeepCopy()
    99  		} else {
   100  			value.Add(quantity)
   101  			list[name] = value
   102  		}
   103  	}
   104  }
   105  
   106  type PriorityClassGetFunc func(string) (*schedulingv1.PriorityClass, error)
   107  
   108  func CalcPGMinResources(minMember int32, replicas map[apiv1.ReplicaType]*apiv1.ReplicaSpec, pcGetFunc PriorityClassGetFunc) *v1.ResourceList {
   109  	var replicasPriority ReplicasPriority
   110  	for t, replica := range replicas {
   111  		rp := ReplicaPriority{0, *replica}
   112  		pc := replica.Template.Spec.PriorityClassName
   113  
   114  		priorityClass, err := pcGetFunc(pc)
   115  		if err != nil || priorityClass == nil {
   116  			log.Warnf("Ignore task %s priority class %s: %v", t, pc, err)
   117  		} else {
   118  			rp.priority = priorityClass.Value
   119  		}
   120  
   121  		replicasPriority = append(replicasPriority, rp)
   122  	}
   123  
   124  	sort.Sort(replicasPriority)
   125  
   126  	minAvailableTasksRes := v1.ResourceList{}
   127  	podCnt := int32(0)
   128  	for _, task := range replicasPriority {
   129  		if task.Replicas == nil {
   130  			continue
   131  		}
   132  
   133  		for i := int32(0); i < *task.Replicas; i++ {
   134  			if podCnt >= minMember {
   135  				break
   136  			}
   137  			podCnt++
   138  			for _, c := range task.Template.Spec.Containers {
   139  				AddResourceList(minAvailableTasksRes, c.Resources.Requests, c.Resources.Limits)
   140  			}
   141  		}
   142  	}
   143  
   144  	return &minAvailableTasksRes
   145  }