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 }