diff --git a/internal/scheduling/nova/integration_test.go b/internal/scheduling/nova/integration_test.go index 596d9f2ed..a1267c9c0 100644 --- a/internal/scheduling/nova/integration_test.go +++ b/internal/scheduling/nova/integration_test.go @@ -48,7 +48,7 @@ func newHypervisor(name, cpuCap, cpuAlloc, memCap, memAlloc string) *hv1.Hypervi Name: name, }, Status: hv1.HypervisorStatus{ - Capacity: map[hv1.ResourceName]resource.Quantity{ + EffectiveCapacity: map[hv1.ResourceName]resource.Quantity{ hv1.ResourceCPU: resource.MustParse(cpuCap), hv1.ResourceMemory: resource.MustParse(memCap), }, diff --git a/internal/scheduling/nova/plugins/filters/filter_has_enough_capacity.go b/internal/scheduling/nova/plugins/filters/filter_has_enough_capacity.go index 8852f6151..198f1a28f 100644 --- a/internal/scheduling/nova/plugins/filters/filter_has_enough_capacity.go +++ b/internal/scheduling/nova/plugins/filters/filter_has_enough_capacity.go @@ -56,8 +56,14 @@ func (s *FilterHasEnoughCapacity) Run(traceLog *slog.Logger, request api.Externa return nil, err } for _, hv := range hvs.Items { - // Start with the total capacity. - freeResourcesByHost[hv.Name] = hv.Status.Capacity + // This case would be caught below, but we want to log this explicitly. + if hv.Status.EffectiveCapacity == nil { + traceLog.Warn("hypervisor with nil effective capacity, skipping", "host", hv.Name) + continue + } + + // Start with the total effective capacity which is capacity * overcommit ratio. + freeResourcesByHost[hv.Name] = hv.Status.EffectiveCapacity // Subtract allocated resources. for resourceName, allocated := range hv.Status.Allocation { diff --git a/internal/scheduling/nova/plugins/filters/filter_has_enough_capacity_test.go b/internal/scheduling/nova/plugins/filters/filter_has_enough_capacity_test.go index 504bbb523..4068cf900 100644 --- a/internal/scheduling/nova/plugins/filters/filter_has_enough_capacity_test.go +++ b/internal/scheduling/nova/plugins/filters/filter_has_enough_capacity_test.go @@ -39,7 +39,7 @@ func newHypervisor(name, cpuCap, cpuAlloc, memCap, memAlloc string) *hv1.Hypervi Name: name, }, Status: hv1.HypervisorStatus{ - Capacity: map[hv1.ResourceName]resource.Quantity{ + EffectiveCapacity: map[hv1.ResourceName]resource.Quantity{ hv1.ResourceCPU: resource.MustParse(cpuCap), hv1.ResourceMemory: resource.MustParse(memCap), }, diff --git a/internal/scheduling/nova/plugins/weighers/kvm_binpack.go b/internal/scheduling/nova/plugins/weighers/kvm_binpack.go index 3bed165f4..e1509a4cc 100644 --- a/internal/scheduling/nova/plugins/weighers/kvm_binpack.go +++ b/internal/scheduling/nova/plugins/weighers/kvm_binpack.go @@ -93,14 +93,15 @@ func (s *KVMBinpackStep) Run(traceLog *slog.Logger, request api.ExternalSchedule var totalWeightedUtilization, totalWeight float64 for resourceName, weight := range s.Options.ResourceWeights { - capacity, ok := hv.Status.Capacity[resourceName] + // Effective capacity = capacity * overcommit ratio. + capacity, ok := hv.Status.EffectiveCapacity[resourceName] if !ok { - traceLog.Warn("no capacity in status, skipping", + traceLog.Warn("no effective capacity in status, skipping", "host", host, "resource", resourceName) continue } if capacity.IsZero() { - traceLog.Warn("capacity is zero, skipping", + traceLog.Warn("effective capacity is zero, skipping", "host", host, "resource", resourceName) continue } diff --git a/internal/scheduling/nova/plugins/weighers/kvm_binpack_test.go b/internal/scheduling/nova/plugins/weighers/kvm_binpack_test.go index e867c5bf7..69e1aa9f6 100644 --- a/internal/scheduling/nova/plugins/weighers/kvm_binpack_test.go +++ b/internal/scheduling/nova/plugins/weighers/kvm_binpack_test.go @@ -22,7 +22,7 @@ func newHypervisor(name, capacityCPU, capacityMem, allocationCPU, allocationMem Name: name, }, Status: hv1.HypervisorStatus{ - Capacity: map[hv1.ResourceName]resource.Quantity{ + EffectiveCapacity: map[hv1.ResourceName]resource.Quantity{ hv1.ResourceCPU: resource.MustParse(capacityCPU), hv1.ResourceMemory: resource.MustParse(capacityMem), }, @@ -343,7 +343,7 @@ func TestKVMBinpackStep_Run(t *testing.T) { { ObjectMeta: metav1.ObjectMeta{Name: "host1"}, Status: hv1.HypervisorStatus{ - Capacity: map[hv1.ResourceName]resource.Quantity{ + EffectiveCapacity: map[hv1.ResourceName]resource.Quantity{ hv1.ResourceCPU: resource.MustParse("0"), hv1.ResourceMemory: resource.MustParse("100Gi"), }, @@ -371,7 +371,7 @@ func TestKVMBinpackStep_Run(t *testing.T) { { ObjectMeta: metav1.ObjectMeta{Name: "host1"}, Status: hv1.HypervisorStatus{ - Capacity: map[hv1.ResourceName]resource.Quantity{ + EffectiveCapacity: map[hv1.ResourceName]resource.Quantity{ hv1.ResourceCPU: resource.MustParse("100"), }, Allocation: map[hv1.ResourceName]resource.Quantity{ @@ -397,7 +397,7 @@ func TestKVMBinpackStep_Run(t *testing.T) { { ObjectMeta: metav1.ObjectMeta{Name: "host1"}, Status: hv1.HypervisorStatus{ - Capacity: map[hv1.ResourceName]resource.Quantity{ + EffectiveCapacity: map[hv1.ResourceName]resource.Quantity{ // No CPU capacity }, Allocation: map[hv1.ResourceName]resource.Quantity{ diff --git a/internal/scheduling/nova/plugins/weighers/kvm_prefer_smaller_hosts.go b/internal/scheduling/nova/plugins/weighers/kvm_prefer_smaller_hosts.go index 8bb5928ee..b65a5f75f 100644 --- a/internal/scheduling/nova/plugins/weighers/kvm_prefer_smaller_hosts.go +++ b/internal/scheduling/nova/plugins/weighers/kvm_prefer_smaller_hosts.go @@ -81,9 +81,10 @@ func (s *KVMPreferSmallerHostsStep) Run(traceLog *slog.Logger, request api.Exter if _, ok := result.Activations[hv.Name]; !ok { continue } - capacity, ok := hv.Status.Capacity[resourceName] + // Effective capacity = capacity * overcommit ratio. + capacity, ok := hv.Status.EffectiveCapacity[resourceName] if !ok { - traceLog.Warn("hypervisor has no capacity for resource, skipping", + traceLog.Warn("hypervisor has no effective capacity for resource, skipping", "host", hv.Name, "resource", resourceName) continue } @@ -106,9 +107,9 @@ func (s *KVMPreferSmallerHostsStep) Run(traceLog *slog.Logger, request api.Exter var totalWeightedScore, totalWeight float64 for resourceName, weight := range s.Options.ResourceWeights { - capacity, ok := hv.Status.Capacity[resourceName] + capacity, ok := hv.Status.EffectiveCapacity[resourceName] if !ok { - traceLog.Warn("hypervisor has no capacity for resource, skipping", + traceLog.Warn("hypervisor has no effective capacity for resource, skipping", "host", hv.Name, "resource", resourceName) continue } @@ -117,14 +118,14 @@ func (s *KVMPreferSmallerHostsStep) Run(traceLog *slog.Logger, request api.Exter largestCap := largest[resourceName] if smallestCap == nil || largestCap == nil { - traceLog.Warn("no capacity range found for resource, skipping", + traceLog.Warn("no effective capacity range found for resource, skipping", "resource", resourceName) continue } - // If all hosts have the same capacity for this resource, skip it + // If all hosts have the same effective capacity for this resource, skip it if smallestCap.Cmp(*largestCap) == 0 { - traceLog.Info("all hypervisors have the same capacity for resource, skipping", + traceLog.Info("all hypervisors have the same effective capacity for resource, skipping", "resource", resourceName) continue } diff --git a/internal/scheduling/nova/plugins/weighers/kvm_prefer_smaller_hosts_test.go b/internal/scheduling/nova/plugins/weighers/kvm_prefer_smaller_hosts_test.go index 4a1b70e20..2ab2deb89 100644 --- a/internal/scheduling/nova/plugins/weighers/kvm_prefer_smaller_hosts_test.go +++ b/internal/scheduling/nova/plugins/weighers/kvm_prefer_smaller_hosts_test.go @@ -22,7 +22,7 @@ func newHypervisorWithCapacity(name, capacityCPU, capacityMem string) *hv1.Hyper Name: name, }, Status: hv1.HypervisorStatus{ - Capacity: map[hv1.ResourceName]resource.Quantity{ + EffectiveCapacity: map[hv1.ResourceName]resource.Quantity{ hv1.ResourceCPU: resource.MustParse(capacityCPU), hv1.ResourceMemory: resource.MustParse(capacityMem), }, @@ -376,7 +376,7 @@ func TestKVMPreferSmallerHostsStep_Run(t *testing.T) { { ObjectMeta: metav1.ObjectMeta{Name: "host3"}, Status: hv1.HypervisorStatus{ - Capacity: map[hv1.ResourceName]resource.Quantity{ + EffectiveCapacity: map[hv1.ResourceName]resource.Quantity{ hv1.ResourceCPU: resource.MustParse("100"), // No memory capacity }, @@ -466,13 +466,13 @@ func TestKVMPreferSmallerHostsStep_Run(t *testing.T) { { ObjectMeta: metav1.ObjectMeta{Name: "host1"}, Status: hv1.HypervisorStatus{ - Capacity: map[hv1.ResourceName]resource.Quantity{}, + EffectiveCapacity: map[hv1.ResourceName]resource.Quantity{}, }, }, { ObjectMeta: metav1.ObjectMeta{Name: "host2"}, Status: hv1.HypervisorStatus{ - Capacity: map[hv1.ResourceName]resource.Quantity{}, + EffectiveCapacity: map[hv1.ResourceName]resource.Quantity{}, }, }, }, @@ -534,7 +534,7 @@ func TestKVMPreferSmallerHostsStep_Run(t *testing.T) { { ObjectMeta: metav1.ObjectMeta{Name: "host1"}, Status: hv1.HypervisorStatus{ - Capacity: map[hv1.ResourceName]resource.Quantity{ + EffectiveCapacity: map[hv1.ResourceName]resource.Quantity{ hv1.ResourceMemory: resource.MustParse("64Gi"), // No CPU }, @@ -543,7 +543,7 @@ func TestKVMPreferSmallerHostsStep_Run(t *testing.T) { { ObjectMeta: metav1.ObjectMeta{Name: "host2"}, Status: hv1.HypervisorStatus{ - Capacity: map[hv1.ResourceName]resource.Quantity{ + EffectiveCapacity: map[hv1.ResourceName]resource.Quantity{ hv1.ResourceMemory: resource.MustParse("128Gi"), // No CPU },