volcano.sh/volcano@v1.9.0/pkg/scheduler/api/pod_info.go (about)

     1  /*
     2  Copyright 2019 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 api
    18  
    19  import (
    20  	"encoding/json"
    21  	"strconv"
    22  
    23  	v1 "k8s.io/api/core/v1"
    24  	"k8s.io/klog/v2"
    25  
    26  	"volcano.sh/apis/pkg/apis/scheduling/v1beta1"
    27  )
    28  
    29  // Refer k8s.io/kubernetes/pkg/scheduler/algorithm/predicates/predicates.go#GetResourceRequest.
    30  //
    31  // GetResourceRequest returns a *Resource that covers the largest width in each resource dimension.
    32  // Because init-containers run sequentially, we collect the max in each dimension iteratively.
    33  // In contrast, we sum the resource vectors for regular containers since they run simultaneously.
    34  //
    35  // To be consistent with kubernetes default scheduler, it is only used for predicates of actions(e.g.
    36  // allocate, backfill, preempt, reclaim), please use GetPodResourceWithoutInitContainers for other cases.
    37  //
    38  // Example:
    39  //
    40  // Pod:
    41  //   InitContainers
    42  //     IC1:
    43  //       CPU: 2
    44  //       Memory: 1G
    45  //     IC2:
    46  //       CPU: 2
    47  //       Memory: 3G
    48  //   Containers
    49  //     C1:
    50  //       CPU: 2
    51  //       Memory: 1G
    52  //     C2:
    53  //       CPU: 1
    54  //       Memory: 1G
    55  //
    56  // Result: CPU: 3, Memory: 3G
    57  
    58  // GetPodResourceRequest returns all the resource required for that pod
    59  func GetPodResourceRequest(pod *v1.Pod) *Resource {
    60  	result := GetPodResourceWithoutInitContainers(pod)
    61  
    62  	// take max_resource(sum_pod, any_init_container)
    63  	for _, container := range pod.Spec.InitContainers {
    64  		result.SetMaxResource(NewResource(container.Resources.Requests))
    65  	}
    66  	result.AddScalar(v1.ResourcePods, 1)
    67  
    68  	return result
    69  }
    70  
    71  // GetPodPreemptable return volcano.sh/preemptable value for pod
    72  func GetPodPreemptable(pod *v1.Pod) bool {
    73  	// check annotaion first
    74  	if len(pod.Annotations) > 0 {
    75  		if value, found := pod.Annotations[v1beta1.PodPreemptable]; found {
    76  			b, err := strconv.ParseBool(value)
    77  			if err != nil {
    78  				klog.Warningf("invalid %s=%s", v1beta1.PodPreemptable, value)
    79  				return false
    80  			}
    81  			return b
    82  		}
    83  	}
    84  
    85  	// it annotation does not exit, check label
    86  	if len(pod.Labels) > 0 {
    87  		if value, found := pod.Labels[v1beta1.PodPreemptable]; found {
    88  			b, err := strconv.ParseBool(value)
    89  			if err != nil {
    90  				klog.Warningf("invalid %s=%s", v1beta1.PodPreemptable, value)
    91  				return false
    92  			}
    93  			return b
    94  		}
    95  	}
    96  
    97  	return true
    98  }
    99  
   100  // GetPodRevocableZone return volcano.sh/revocable-zone value for pod/podgroup
   101  func GetPodRevocableZone(pod *v1.Pod) string {
   102  	if len(pod.Annotations) > 0 {
   103  		if value, found := pod.Annotations[v1beta1.RevocableZone]; found {
   104  			if value != "*" {
   105  				return ""
   106  			}
   107  			return value
   108  		}
   109  
   110  		if value, found := pod.Annotations[v1beta1.PodPreemptable]; found {
   111  			if b, err := strconv.ParseBool(value); err == nil && b {
   112  				return "*"
   113  			}
   114  		}
   115  	}
   116  	return ""
   117  }
   118  
   119  // GetPodTopologyInfo return volcano.sh/numa-topology-policy value for pod
   120  func GetPodTopologyInfo(pod *v1.Pod) *TopologyInfo {
   121  	info := TopologyInfo{
   122  		ResMap: make(map[int]v1.ResourceList),
   123  	}
   124  
   125  	if len(pod.Annotations) > 0 {
   126  		if value, found := pod.Annotations[v1beta1.NumaPolicyKey]; found {
   127  			info.Policy = value
   128  		}
   129  
   130  		if value, found := pod.Annotations[topologyDecisionAnnotation]; found {
   131  			decision := PodResourceDecision{}
   132  			err := json.Unmarshal([]byte(value), &decision)
   133  			if err == nil {
   134  				info.ResMap = decision.NUMAResources
   135  			}
   136  		}
   137  	}
   138  
   139  	return &info
   140  }
   141  
   142  // GetPodResourceWithoutInitContainers returns Pod's resource request, it does not contain
   143  // init containers' resource request.
   144  func GetPodResourceWithoutInitContainers(pod *v1.Pod) *Resource {
   145  	result := EmptyResource()
   146  	for _, container := range pod.Spec.Containers {
   147  		result.Add(NewResource(container.Resources.Requests))
   148  	}
   149  
   150  	// if PodOverhead feature is supported, add overhead for running a pod
   151  	if pod.Spec.Overhead != nil {
   152  		result.Add(NewResource(pod.Spec.Overhead))
   153  	}
   154  
   155  	return result
   156  }