Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions pkg/device/quota.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ import (
type Quota struct {
Used int64
Limit int64
// LimitSet distinguishes an explicitly configured limit (including an
// explicit 0, which blocks all usage) from an entry auto-created by usage
// tracking, which carries Limit 0 but means "no limit configured". FitQuota
// gates on this rather than Limit != 0 so that a ResourceQuota of "0" is
// honored as a hard block instead of being read as unlimited.
LimitSet bool
}

type DeviceQuota map[string]*Quota
Expand Down Expand Up @@ -75,13 +81,13 @@ func (q *QuotaManager) FitQuota(ns string, memreq int64, memoryFactor int32, cor
if memoryFactor > 1 {
limit = limit * int64(memoryFactor)
}
if limit != 0 && memQuota.Used+memreq > limit {
if memQuota.LimitSet && memQuota.Used+memreq > limit {
klog.V(4).InfoS("resourceMem quota not fitted", "limit", limit, "used", memQuota.Used, "alloc", memreq)
return false
}
}
coreQuota, ok := (*dq)[coreResourceName]
if ok && coreQuota.Limit != 0 && coreQuota.Used+coresreq > coreQuota.Limit {
if ok && coreQuota.LimitSet && coreQuota.Used+coresreq > coreQuota.Limit {
klog.V(4).InfoS("resourceCores quota not fitted", "limit", coreQuota.Limit, "used", coreQuota.Used, "alloc", coresreq)
return false
}
Expand Down Expand Up @@ -210,6 +216,7 @@ func (q *QuotaManager) AddQuota(quota *corev1.ResourceQuota) {
}
}
(*dp)[dn].Limit = value
(*dp)[dn].LimitSet = true
klog.V(4).InfoS("quota set:", "idx=", idx, "val", value)
}
}
Expand Down Expand Up @@ -239,6 +246,7 @@ func (q *QuotaManager) DelQuota(quota *corev1.ResourceQuota) {
if dq, ok := q.Quotas[quota.Namespace]; ok {
if quotaInfo, ok := (*dq)[dn]; ok {
quotaInfo.Limit = 0
quotaInfo.LimitSet = false
}
}
}
Expand All @@ -261,8 +269,9 @@ func (q *QuotaManager) GetResourceQuota() map[string]*DeviceQuota {
curDQ := &DeviceQuota{}
for name, quota := range *dq {
(*curDQ)[name] = &Quota{
Used: quota.Used,
Limit: quota.Limit,
Used: quota.Used,
Limit: quota.Limit,
LimitSet: quota.LimitSet,
}
}
quotasCopy[ns] = curDQ
Expand Down
24 changes: 22 additions & 2 deletions pkg/device/quota_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ func TestFitQuota(t *testing.T) {
coreName := "nvidia.com/gpucore"

qm.Quotas[ns] = &DeviceQuota{
memName: &Quota{Used: 1000, Limit: 2000},
coreName: &Quota{Used: 200, Limit: 400},
memName: &Quota{Used: 1000, Limit: 2000, LimitSet: true},
coreName: &Quota{Used: 200, Limit: 400, LimitSet: true},
}

// Should fit
Expand Down Expand Up @@ -160,6 +160,26 @@ func TestFitQuota(t *testing.T) {
}
}

func TestFitQuotaExplicitZeroBlocks(t *testing.T) {
initTest()
qm := &QuotaManager{Quotas: make(map[string]*DeviceQuota)}
ns := "team-zero"
memName := "nvidia.com/gpumem"

// An operator sets a ResourceQuota of "0" to block all GPU memory in the namespace.
rq := &corev1.ResourceQuota{}
rq.Namespace = ns
rq.Spec.Hard = corev1.ResourceList{
corev1.ResourceName("limits." + memName): *resource.NewQuantity(0, resource.DecimalSI),
}
qm.AddQuota(rq)

// The explicit zero must block any positive request, not be read as "unlimited".
if qm.FitQuota(ns, 500, 1, 0, "NVIDIA") {
t.Error(`FitQuota admitted a 500 request under limits.nvidia.com/gpumem: "0"; an explicit zero quota must block`)
}
}

func TestAddUsageAndRmUsage(t *testing.T) {
initTest()
qm := NewQuotaManager()
Expand Down
4 changes: 2 additions & 2 deletions pkg/scheduler/webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,8 +269,8 @@ func TestFitResourceQuota(t *testing.T) {
coreName := "nvidia.com/gpucores"

qm.Quotas[ns] = &device.DeviceQuota{
memName: &device.Quota{Used: 1000, Limit: 2000},
coreName: &device.Quota{Used: 200, Limit: 400},
memName: &device.Quota{Used: 1000, Limit: 2000, LimitSet: true},
coreName: &device.Quota{Used: 200, Limit: 400, LimitSet: true},
}

testCases := []struct {
Expand Down
Loading