volcano.sh/volcano@v1.9.0/pkg/scheduler/plugins/resourcequota/resourcequota.go (about)

     1  package resourcequota
     2  
     3  import (
     4  	"fmt"
     5  
     6  	v1 "k8s.io/api/core/v1"
     7  	quotav1 "k8s.io/apiserver/pkg/quota/v1"
     8  	"k8s.io/klog/v2"
     9  
    10  	scheduling "volcano.sh/apis/pkg/apis/scheduling"
    11  	"volcano.sh/volcano/pkg/scheduler/api"
    12  	"volcano.sh/volcano/pkg/scheduler/framework"
    13  	"volcano.sh/volcano/pkg/scheduler/plugins/util"
    14  )
    15  
    16  // PluginName indicates name of volcano scheduler plugin.
    17  const PluginName = "resourcequota"
    18  
    19  // resourceQuota scope not supported
    20  type resourceQuotaPlugin struct {
    21  	// Arguments given for the plugin
    22  	pluginArguments framework.Arguments
    23  }
    24  
    25  // New return resourcequota plugin
    26  func New(arguments framework.Arguments) framework.Plugin {
    27  	return &resourceQuotaPlugin{
    28  		pluginArguments: arguments,
    29  	}
    30  }
    31  
    32  func (rq *resourceQuotaPlugin) Name() string {
    33  	return PluginName
    34  }
    35  
    36  func (rq *resourceQuotaPlugin) OnSessionOpen(ssn *framework.Session) {
    37  	pendingResources := make(map[string]v1.ResourceList)
    38  
    39  	ssn.AddJobEnqueueableFn(rq.Name(), func(obj interface{}) int {
    40  		job := obj.(*api.JobInfo)
    41  
    42  		resourcesRequests := job.PodGroup.Spec.MinResources
    43  
    44  		if resourcesRequests == nil {
    45  			return util.Permit
    46  		}
    47  
    48  		if ssn.NamespaceInfo[api.NamespaceName(job.Namespace)] == nil {
    49  			return util.Permit
    50  		}
    51  
    52  		quotas := ssn.NamespaceInfo[api.NamespaceName(job.Namespace)].QuotaStatus
    53  		for _, resourceQuota := range quotas {
    54  			hardResources := quotav1.ResourceNames(resourceQuota.Hard)
    55  			requestedUsage := quotav1.Mask(*resourcesRequests, hardResources)
    56  
    57  			var resourcesUsed = resourceQuota.Used
    58  			if pendingUse, found := pendingResources[job.Namespace]; found {
    59  				resourcesUsed = quotav1.Add(pendingUse, resourcesUsed)
    60  			}
    61  			newUsage := quotav1.Add(resourcesUsed, requestedUsage)
    62  			maskedNewUsage := quotav1.Mask(newUsage, quotav1.ResourceNames(requestedUsage))
    63  
    64  			if allowed, exceeded := quotav1.LessThanOrEqual(maskedNewUsage, resourceQuota.Hard); !allowed {
    65  				failedRequestedUsage := quotav1.Mask(requestedUsage, exceeded)
    66  				failedUsed := quotav1.Mask(resourceQuota.Used, exceeded)
    67  				failedHard := quotav1.Mask(resourceQuota.Hard, exceeded)
    68  				msg := fmt.Sprintf("resource quota insufficient, requested: %v, used: %v, limited: %v",
    69  					failedRequestedUsage,
    70  					failedUsed,
    71  					failedHard,
    72  				)
    73  				klog.V(4).Infof("enqueueable false for job: %s/%s, because :%s", job.Namespace, job.Name, msg)
    74  				ssn.RecordPodGroupEvent(job.PodGroup, v1.EventTypeNormal, string(scheduling.PodGroupUnschedulableType), msg)
    75  				return util.Reject
    76  			}
    77  		}
    78  		if _, found := pendingResources[job.Namespace]; !found {
    79  			pendingResources[job.Namespace] = v1.ResourceList{}
    80  		}
    81  		pendingResources[job.Namespace] = quotav1.Add(pendingResources[job.Namespace], *resourcesRequests)
    82  		return util.Permit
    83  	})
    84  }
    85  
    86  func (rq *resourceQuotaPlugin) OnSessionClose(session *framework.Session) {
    87  }