From dd76e88984888527ac8f45e4aed006707aa67a9f Mon Sep 17 00:00:00 2001
From: Philipp Matthes
Date: Fri, 13 Mar 2026 14:29:39 +0100
Subject: [PATCH 1/5] Add changed crd spec and fix incompatible parts
---
go.mod | 2 +-
go.sum | 2 ++
internal/libvirt/libvirt.go | 32 ++++++++++++++++----------------
3 files changed, 19 insertions(+), 17 deletions(-)
diff --git a/go.mod b/go.mod
index 2d79a67..b8c6387 100644
--- a/go.mod
+++ b/go.mod
@@ -7,7 +7,7 @@ go 1.26
require (
github.com/cert-manager/cert-manager v1.19.4
- github.com/cobaltcore-dev/openstack-hypervisor-operator v0.0.0-20260309144200-9c8ed613a94c
+ github.com/cobaltcore-dev/openstack-hypervisor-operator v0.0.0-20260313120621-e3699e2ccab9
github.com/coreos/go-systemd/v22 v22.7.0
github.com/digitalocean/go-libvirt v0.0.0-20260217163227-273eaa321819
github.com/godbus/dbus/v5 v5.2.2
diff --git a/go.sum b/go.sum
index 7d38453..2d8a494 100644
--- a/go.sum
+++ b/go.sum
@@ -16,6 +16,8 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cobaltcore-dev/openstack-hypervisor-operator v0.0.0-20260309144200-9c8ed613a94c h1:KylfcJikSMWNJnuNfG1Od6fNUw4kQTjseP7khmwVlrM=
github.com/cobaltcore-dev/openstack-hypervisor-operator v0.0.0-20260309144200-9c8ed613a94c/go.mod h1:b0KmJdxvRI8UXlGe8cRm5BD8Tm2WhF7zSKMSIRGyVL4=
+github.com/cobaltcore-dev/openstack-hypervisor-operator v0.0.0-20260313120621-e3699e2ccab9 h1:fIQCfP6HTOMu9XqcRLUYeUCK2mPWcOkSqYVF9HUhQyE=
+github.com/cobaltcore-dev/openstack-hypervisor-operator v0.0.0-20260313120621-e3699e2ccab9/go.mod h1:b0KmJdxvRI8UXlGe8cRm5BD8Tm2WhF7zSKMSIRGyVL4=
github.com/coreos/go-systemd/v22 v22.7.0 h1:LAEzFkke61DFROc7zNLX/WA2i5J8gYqe0rSj9KI28KA=
github.com/coreos/go-systemd/v22 v22.7.0/go.mod h1:xNUYtjHu2EDXbsxz1i41wouACIwT7Ybq9o0BQhMwD0w=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
diff --git a/internal/libvirt/libvirt.go b/internal/libvirt/libvirt.go
index fd2bdeb..90711a6 100644
--- a/internal/libvirt/libvirt.go
+++ b/internal/libvirt/libvirt.go
@@ -458,14 +458,14 @@ func (l *LibVirt) addAllocationCapacity(old v1.Hypervisor) (v1.Hypervisor, error
cellsById[cell.ID] = v1.Cell{
CellID: cell.ID,
- Allocation: map[string]resource.Quantity{
+ Allocation: map[v1.ResourceName]resource.Quantity{
// Will be updated below when we look at the domain infos.
- "memory": *resource.NewQuantity(0, resource.BinarySI),
- "cpu": *resource.NewQuantity(0, resource.DecimalSI),
+ v1.ResourceMemory: *resource.NewQuantity(0, resource.BinarySI),
+ v1.ResourceCPU: *resource.NewQuantity(0, resource.DecimalSI),
},
- Capacity: map[string]resource.Quantity{
- "memory": memoryCapacity,
- "cpu": cpuCapacity,
+ Capacity: map[v1.ResourceName]resource.Quantity{
+ v1.ResourceMemory: memoryCapacity,
+ v1.ResourceCPU: cpuCapacity,
},
}
}
@@ -505,14 +505,14 @@ func (l *LibVirt) addAllocationCapacity(old v1.Hypervisor) (v1.Hypervisor, error
domInfo.Name, memoryNode.CellID,
)
}
- memAllocCell := cell.Allocation["memory"]
+ memAllocCell := cell.Allocation[v1.ResourceMemory]
// If a domain is using multiple memory cells, assume the
// distribution across cells is even.
nCells := int64(len(domInfo.NumaTune.MemNodes)) // is non-zero
memAllocPerCell := *resource.
NewQuantity(memAlloc.Value()/nCells, resource.BinarySI)
memAllocCell.Add(memAllocPerCell)
- cell.Allocation["memory"] = memAllocCell
+ cell.Allocation[v1.ResourceMemory] = memAllocCell
cellsById[memoryNode.CellID] = cell
}
@@ -528,14 +528,14 @@ func (l *LibVirt) addAllocationCapacity(old v1.Hypervisor) (v1.Hypervisor, error
domInfo.Name, cpuCell.ID,
)
}
- cpuAllocCell := cell.Allocation["cpu"]
+ cpuAllocCell := cell.Allocation[v1.ResourceCPU]
// If a domain is using multiple cpu cells, assume the distribution
// across cells is even.
nCells := int64(len(domInfo.CPU.Numa.Cells)) // is non-zero
cpuAllocPerCell := *resource.
NewQuantity(cpuAlloc.Value()/nCells, resource.DecimalSI)
cpuAllocCell.Add(cpuAllocPerCell)
- cell.Allocation["cpu"] = cpuAllocCell
+ cell.Allocation[v1.ResourceCPU] = cpuAllocCell
cellsById[cpuCell.ID] = cell
}
}
@@ -544,12 +544,12 @@ func (l *LibVirt) addAllocationCapacity(old v1.Hypervisor) (v1.Hypervisor, error
cellsAsSlice = append(cellsAsSlice, cell)
}
- newHv.Status.Capacity = make(map[string]resource.Quantity)
- newHv.Status.Capacity["memory"] = *totalMemoryCapacity
- newHv.Status.Capacity["cpu"] = *totalCpuCapacity
- newHv.Status.Allocation = make(map[string]resource.Quantity)
- newHv.Status.Allocation["memory"] = *totalMemoryAlloc
- newHv.Status.Allocation["cpu"] = *totalCpuAlloc
+ newHv.Status.Capacity = make(map[v1.ResourceName]resource.Quantity)
+ newHv.Status.Capacity[v1.ResourceMemory] = *totalMemoryCapacity
+ newHv.Status.Capacity[v1.ResourceCPU] = *totalCpuCapacity
+ newHv.Status.Allocation = make(map[v1.ResourceName]resource.Quantity)
+ newHv.Status.Allocation[v1.ResourceMemory] = *totalMemoryAlloc
+ newHv.Status.Allocation[v1.ResourceCPU] = *totalCpuAlloc
newHv.Status.Cells = cellsAsSlice
return newHv, nil
}
From 59de598a12cf538a1050e0412d852cd0b479084a Mon Sep 17 00:00:00 2001
From: Philipp Matthes
Date: Fri, 13 Mar 2026 14:44:26 +0100
Subject: [PATCH 2/5] Implement addEffectiveAllocationCapacity
---
internal/libvirt/libvirt.go | 41 ++++
internal/libvirt/libvirt_test.go | 344 +++++++++++++++++++++++++++++++
2 files changed, 385 insertions(+)
diff --git a/internal/libvirt/libvirt.go b/internal/libvirt/libvirt.go
index 90711a6..9c28c63 100644
--- a/internal/libvirt/libvirt.go
+++ b/internal/libvirt/libvirt.go
@@ -274,6 +274,7 @@ func (l *LibVirt) Process(hv v1.Hypervisor) (v1.Hypervisor, error) {
l.addCapabilities,
l.addDomainCapabilities,
l.addAllocationCapacity,
+ l.addEffectiveAllocationCapacity,
}
var err error
for _, processor := range processors {
@@ -553,3 +554,43 @@ func (l *LibVirt) addAllocationCapacity(old v1.Hypervisor) (v1.Hypervisor, error
newHv.Status.Cells = cellsAsSlice
return newHv, nil
}
+
+// Add the effective allocation capacity to the hypervisor instance.
+//
+// The effective allocation capacity is calculated as the physical capacity and
+// allocation times the applied overcommit ratio, or 1.0 by default. In case
+// the resulting values are fractional, they are floored.
+func (l *LibVirt) addEffectiveAllocationCapacity(old v1.Hypervisor) (v1.Hypervisor, error) {
+ newHv := *old.DeepCopy()
+ // Initialize the EffectiveCapacity map if it's nil
+ if newHv.Status.EffectiveCapacity == nil {
+ newHv.Status.EffectiveCapacity = make(map[v1.ResourceName]resource.Quantity)
+ }
+ for resourceName, capacity := range newHv.Status.Capacity {
+ overcommit, ok := newHv.Spec.Overcommit[resourceName]
+ if !ok {
+ overcommit = 1.0
+ }
+ flooredValue := int64(float64(capacity.Value()) * overcommit)
+ effectiveCapacity := resource.NewQuantity(flooredValue, capacity.Format)
+ newHv.Status.EffectiveCapacity[resourceName] = *effectiveCapacity
+ }
+ // Also apply this to each cell.
+ for i, cell := range newHv.Status.Cells {
+ // Initialize the cell's EffectiveCapacity map if it's nil
+ if cell.EffectiveCapacity == nil {
+ cell.EffectiveCapacity = make(map[v1.ResourceName]resource.Quantity)
+ }
+ for resourceName, capacity := range cell.Capacity {
+ overcommit, ok := newHv.Spec.Overcommit[resourceName]
+ if !ok {
+ overcommit = 1.0
+ }
+ flooredValue := int64(float64(capacity.Value()) * overcommit)
+ effectiveCapacity := resource.NewQuantity(flooredValue, capacity.Format)
+ cell.EffectiveCapacity[resourceName] = *effectiveCapacity
+ }
+ newHv.Status.Cells[i] = cell
+ }
+ return newHv, nil
+}
diff --git a/internal/libvirt/libvirt_test.go b/internal/libvirt/libvirt_test.go
index e104c58..03589d0 100644
--- a/internal/libvirt/libvirt_test.go
+++ b/internal/libvirt/libvirt_test.go
@@ -1552,3 +1552,347 @@ func TestRunEventLoop_ClosedEventChannel(t *testing.T) {
t.Fatal("Event loop did not handle closed channel within timeout")
}
}
+
+func TestAddEffectiveAllocationCapacity_NoOvercommit(t *testing.T) {
+ // Test that when no overcommit is specified, effective capacity equals capacity
+ l := &LibVirt{}
+
+ hv := v1.Hypervisor{
+ Status: v1.HypervisorStatus{
+ Capacity: map[v1.ResourceName]resource.Quantity{
+ v1.ResourceMemory: *resource.NewQuantity(64*1024*1024*1024, resource.BinarySI),
+ v1.ResourceCPU: *resource.NewQuantity(16, resource.DecimalSI),
+ },
+ EffectiveCapacity: make(map[v1.ResourceName]resource.Quantity),
+ Cells: []v1.Cell{
+ {
+ CellID: 0,
+ Capacity: map[v1.ResourceName]resource.Quantity{
+ v1.ResourceMemory: *resource.NewQuantity(64*1024*1024*1024, resource.BinarySI),
+ v1.ResourceCPU: *resource.NewQuantity(16, resource.DecimalSI),
+ },
+ EffectiveCapacity: make(map[v1.ResourceName]resource.Quantity),
+ },
+ },
+ },
+ }
+
+ result, err := l.addEffectiveAllocationCapacity(hv)
+
+ if err != nil {
+ t.Fatalf("addEffectiveAllocationCapacity() returned unexpected error: %v", err)
+ }
+
+ // With no overcommit, effective capacity should equal physical capacity
+ expectedMemory := resource.NewQuantity(64*1024*1024*1024, resource.BinarySI)
+ memEffective := result.Status.EffectiveCapacity[v1.ResourceMemory]
+ if !memEffective.Equal(*expectedMemory) {
+ t.Errorf("Expected effective memory capacity %s, got %s",
+ expectedMemory.String(), memEffective.String())
+ }
+
+ expectedCPU := resource.NewQuantity(16, resource.DecimalSI)
+ cpuEffective := result.Status.EffectiveCapacity[v1.ResourceCPU]
+ if !cpuEffective.Equal(*expectedCPU) {
+ t.Errorf("Expected effective CPU capacity %s, got %s",
+ expectedCPU.String(), cpuEffective.String())
+ }
+
+ // Check cell effective capacity
+ if len(result.Status.Cells) != 1 {
+ t.Fatalf("Expected 1 cell, got %d", len(result.Status.Cells))
+ }
+ cellMemEffective := result.Status.Cells[0].EffectiveCapacity[v1.ResourceMemory]
+ if !cellMemEffective.Equal(*expectedMemory) {
+ t.Errorf("Cell 0: Expected effective memory capacity %s, got %s",
+ expectedMemory.String(), cellMemEffective.String())
+ }
+ cellCpuEffective := result.Status.Cells[0].EffectiveCapacity[v1.ResourceCPU]
+ if !cellCpuEffective.Equal(*expectedCPU) {
+ t.Errorf("Cell 0: Expected effective CPU capacity %s, got %s",
+ expectedCPU.String(), cellCpuEffective.String())
+ }
+}
+
+func TestAddEffectiveAllocationCapacity_WithMemoryOvercommit(t *testing.T) {
+ // Test memory overcommit ratio of 1.5
+ l := &LibVirt{}
+
+ hv := v1.Hypervisor{
+ Spec: v1.HypervisorSpec{
+ Overcommit: map[v1.ResourceName]float64{
+ v1.ResourceMemory: 1.5,
+ },
+ },
+ Status: v1.HypervisorStatus{
+ Capacity: map[v1.ResourceName]resource.Quantity{
+ v1.ResourceMemory: *resource.NewQuantity(64*1024*1024*1024, resource.BinarySI),
+ v1.ResourceCPU: *resource.NewQuantity(16, resource.DecimalSI),
+ },
+ EffectiveCapacity: make(map[v1.ResourceName]resource.Quantity),
+ Cells: []v1.Cell{},
+ },
+ }
+
+ result, err := l.addEffectiveAllocationCapacity(hv)
+
+ if err != nil {
+ t.Fatalf("addEffectiveAllocationCapacity() returned unexpected error: %v", err)
+ }
+
+ // Memory should be 64 GiB * 1.5 = 96 GiB
+ expectedMemory := resource.NewQuantity(96*1024*1024*1024, resource.BinarySI)
+ memEffective := result.Status.EffectiveCapacity[v1.ResourceMemory]
+ if !memEffective.Equal(*expectedMemory) {
+ t.Errorf("Expected effective memory capacity %s, got %s",
+ expectedMemory.String(), memEffective.String())
+ }
+
+ // CPU should remain unchanged (no overcommit specified, defaults to 1.0)
+ expectedCPU := resource.NewQuantity(16, resource.DecimalSI)
+ cpuEffective := result.Status.EffectiveCapacity[v1.ResourceCPU]
+ if !cpuEffective.Equal(*expectedCPU) {
+ t.Errorf("Expected effective CPU capacity %s, got %s",
+ expectedCPU.String(), cpuEffective.String())
+ }
+}
+
+func TestAddEffectiveAllocationCapacity_WithCPUOvercommit(t *testing.T) {
+ // Test CPU overcommit ratio of 4.0
+ l := &LibVirt{}
+
+ hv := v1.Hypervisor{
+ Spec: v1.HypervisorSpec{
+ Overcommit: map[v1.ResourceName]float64{
+ v1.ResourceCPU: 4.0,
+ },
+ },
+ Status: v1.HypervisorStatus{
+ Capacity: map[v1.ResourceName]resource.Quantity{
+ v1.ResourceMemory: *resource.NewQuantity(64*1024*1024*1024, resource.BinarySI),
+ v1.ResourceCPU: *resource.NewQuantity(16, resource.DecimalSI),
+ },
+ EffectiveCapacity: make(map[v1.ResourceName]resource.Quantity),
+ Cells: []v1.Cell{},
+ },
+ }
+
+ result, err := l.addEffectiveAllocationCapacity(hv)
+
+ if err != nil {
+ t.Fatalf("addEffectiveAllocationCapacity() returned unexpected error: %v", err)
+ }
+
+ // Memory should remain unchanged (no overcommit specified, defaults to 1.0)
+ expectedMemory := resource.NewQuantity(64*1024*1024*1024, resource.BinarySI)
+ memEffective := result.Status.EffectiveCapacity[v1.ResourceMemory]
+ if !memEffective.Equal(*expectedMemory) {
+ t.Errorf("Expected effective memory capacity %s, got %s",
+ expectedMemory.String(), memEffective.String())
+ }
+
+ // CPU should be 16 * 4.0 = 64
+ expectedCPU := resource.NewQuantity(64, resource.DecimalSI)
+ cpuEffective := result.Status.EffectiveCapacity[v1.ResourceCPU]
+ if !cpuEffective.Equal(*expectedCPU) {
+ t.Errorf("Expected effective CPU capacity %s, got %s",
+ expectedCPU.String(), cpuEffective.String())
+ }
+}
+
+func TestAddEffectiveAllocationCapacity_WithBothOvercommit(t *testing.T) {
+ // Test both memory and CPU overcommit
+ l := &LibVirt{}
+
+ hv := v1.Hypervisor{
+ Spec: v1.HypervisorSpec{
+ Overcommit: map[v1.ResourceName]float64{
+ v1.ResourceMemory: 2.0,
+ v1.ResourceCPU: 8.0,
+ },
+ },
+ Status: v1.HypervisorStatus{
+ Capacity: map[v1.ResourceName]resource.Quantity{
+ v1.ResourceMemory: *resource.NewQuantity(32*1024*1024*1024, resource.BinarySI),
+ v1.ResourceCPU: *resource.NewQuantity(8, resource.DecimalSI),
+ },
+ EffectiveCapacity: make(map[v1.ResourceName]resource.Quantity),
+ Cells: []v1.Cell{},
+ },
+ }
+
+ result, err := l.addEffectiveAllocationCapacity(hv)
+
+ if err != nil {
+ t.Fatalf("addEffectiveAllocationCapacity() returned unexpected error: %v", err)
+ }
+
+ // Memory should be 32 GiB * 2.0 = 64 GiB
+ expectedMemory := resource.NewQuantity(64*1024*1024*1024, resource.BinarySI)
+ memEffective := result.Status.EffectiveCapacity[v1.ResourceMemory]
+ if !memEffective.Equal(*expectedMemory) {
+ t.Errorf("Expected effective memory capacity %s, got %s",
+ expectedMemory.String(), memEffective.String())
+ }
+
+ // CPU should be 8 * 8.0 = 64
+ expectedCPU := resource.NewQuantity(64, resource.DecimalSI)
+ cpuEffective := result.Status.EffectiveCapacity[v1.ResourceCPU]
+ if !cpuEffective.Equal(*expectedCPU) {
+ t.Errorf("Expected effective CPU capacity %s, got %s",
+ expectedCPU.String(), cpuEffective.String())
+ }
+}
+
+func TestAddEffectiveAllocationCapacity_FractionalValuesFloored(t *testing.T) {
+ // Test that fractional values are floored
+ l := &LibVirt{}
+
+ hv := v1.Hypervisor{
+ Spec: v1.HypervisorSpec{
+ Overcommit: map[v1.ResourceName]float64{
+ v1.ResourceCPU: 1.5, // 10 * 1.5 = 15
+ },
+ },
+ Status: v1.HypervisorStatus{
+ Capacity: map[v1.ResourceName]resource.Quantity{
+ v1.ResourceCPU: *resource.NewQuantity(10, resource.DecimalSI),
+ },
+ EffectiveCapacity: make(map[v1.ResourceName]resource.Quantity),
+ Cells: []v1.Cell{},
+ },
+ }
+
+ result, err := l.addEffectiveAllocationCapacity(hv)
+
+ if err != nil {
+ t.Fatalf("addEffectiveAllocationCapacity() returned unexpected error: %v", err)
+ }
+
+ // CPU should be floor(10 * 1.5) = floor(15) = 15
+ expectedCPU := resource.NewQuantity(15, resource.DecimalSI)
+ cpuEffective := result.Status.EffectiveCapacity[v1.ResourceCPU]
+ if !cpuEffective.Equal(*expectedCPU) {
+ t.Errorf("Expected effective CPU capacity %s, got %s",
+ expectedCPU.String(), cpuEffective.String())
+ }
+}
+
+func TestAddEffectiveAllocationCapacity_FractionalValuesFlooredDown(t *testing.T) {
+ // Test that fractional values are floored down, not rounded
+ l := &LibVirt{}
+
+ hv := v1.Hypervisor{
+ Spec: v1.HypervisorSpec{
+ Overcommit: map[v1.ResourceName]float64{
+ v1.ResourceCPU: 1.9, // 10 * 1.9 = 19
+ },
+ },
+ Status: v1.HypervisorStatus{
+ Capacity: map[v1.ResourceName]resource.Quantity{
+ v1.ResourceCPU: *resource.NewQuantity(10, resource.DecimalSI),
+ },
+ EffectiveCapacity: make(map[v1.ResourceName]resource.Quantity),
+ Cells: []v1.Cell{},
+ },
+ }
+
+ result, err := l.addEffectiveAllocationCapacity(hv)
+
+ if err != nil {
+ t.Fatalf("addEffectiveAllocationCapacity() returned unexpected error: %v", err)
+ }
+
+ // CPU should be floor(10 * 1.9) = floor(19) = 19
+ expectedCPU := resource.NewQuantity(19, resource.DecimalSI)
+ cpuEffective := result.Status.EffectiveCapacity[v1.ResourceCPU]
+ if !cpuEffective.Equal(*expectedCPU) {
+ t.Errorf("Expected effective CPU capacity %s, got %s",
+ expectedCPU.String(), cpuEffective.String())
+ }
+}
+
+func TestAddEffectiveAllocationCapacity_MultipleCells(t *testing.T) {
+ // Test that overcommit is applied to each cell individually
+ l := &LibVirt{}
+
+ hv := v1.Hypervisor{
+ Spec: v1.HypervisorSpec{
+ Overcommit: map[v1.ResourceName]float64{
+ v1.ResourceMemory: 1.5,
+ v1.ResourceCPU: 2.0,
+ },
+ },
+ Status: v1.HypervisorStatus{
+ Capacity: map[v1.ResourceName]resource.Quantity{
+ v1.ResourceMemory: *resource.NewQuantity(128*1024*1024*1024, resource.BinarySI),
+ v1.ResourceCPU: *resource.NewQuantity(32, resource.DecimalSI),
+ },
+ EffectiveCapacity: make(map[v1.ResourceName]resource.Quantity),
+ Cells: []v1.Cell{
+ {
+ CellID: 0,
+ Capacity: map[v1.ResourceName]resource.Quantity{
+ v1.ResourceMemory: *resource.NewQuantity(64*1024*1024*1024, resource.BinarySI),
+ v1.ResourceCPU: *resource.NewQuantity(16, resource.DecimalSI),
+ },
+ EffectiveCapacity: make(map[v1.ResourceName]resource.Quantity),
+ },
+ {
+ CellID: 1,
+ Capacity: map[v1.ResourceName]resource.Quantity{
+ v1.ResourceMemory: *resource.NewQuantity(64*1024*1024*1024, resource.BinarySI),
+ v1.ResourceCPU: *resource.NewQuantity(16, resource.DecimalSI),
+ },
+ EffectiveCapacity: make(map[v1.ResourceName]resource.Quantity),
+ },
+ },
+ },
+ }
+
+ result, err := l.addEffectiveAllocationCapacity(hv)
+
+ if err != nil {
+ t.Fatalf("addEffectiveAllocationCapacity() returned unexpected error: %v", err)
+ }
+
+ // Check total effective capacity
+ // Memory: 128 GiB * 1.5 = 192 GiB
+ expectedTotalMemory := resource.NewQuantity(192*1024*1024*1024, resource.BinarySI)
+ totalMemEffective := result.Status.EffectiveCapacity[v1.ResourceMemory]
+ if !totalMemEffective.Equal(*expectedTotalMemory) {
+ t.Errorf("Expected total effective memory capacity %s, got %s",
+ expectedTotalMemory.String(), totalMemEffective.String())
+ }
+
+ // CPU: 32 * 2.0 = 64
+ expectedTotalCPU := resource.NewQuantity(64, resource.DecimalSI)
+ totalCpuEffective := result.Status.EffectiveCapacity[v1.ResourceCPU]
+ if !totalCpuEffective.Equal(*expectedTotalCPU) {
+ t.Errorf("Expected total effective CPU capacity %s, got %s",
+ expectedTotalCPU.String(), totalCpuEffective.String())
+ }
+
+ // Check each cell's effective capacity
+ if len(result.Status.Cells) != 2 {
+ t.Fatalf("Expected 2 cells, got %d", len(result.Status.Cells))
+ }
+
+ for i, cell := range result.Status.Cells {
+ // Cell memory: 64 GiB * 1.5 = 96 GiB
+ expectedCellMemory := resource.NewQuantity(96*1024*1024*1024, resource.BinarySI)
+ cellMemEffective := cell.EffectiveCapacity[v1.ResourceMemory]
+ if !cellMemEffective.Equal(*expectedCellMemory) {
+ t.Errorf("Cell %d: Expected effective memory capacity %s, got %s",
+ i, expectedCellMemory.String(), cellMemEffective.String())
+ }
+
+ // Cell CPU: 16 * 2.0 = 32
+ expectedCellCPU := resource.NewQuantity(32, resource.DecimalSI)
+ cellCpuEffective := cell.EffectiveCapacity[v1.ResourceCPU]
+ if !cellCpuEffective.Equal(*expectedCellCPU) {
+ t.Errorf("Cell %d: Expected effective CPU capacity %s, got %s",
+ i, expectedCellCPU.String(), cellCpuEffective.String())
+ }
+ }
+}
From ae02d4bcfd566dd22b18215f0e7d58dc4b2e931d Mon Sep 17 00:00:00 2001
From: Philipp Matthes
Date: Fri, 13 Mar 2026 14:54:20 +0100
Subject: [PATCH 3/5] Actually test flooring
---
internal/libvirt/libvirt_test.go | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)
diff --git a/internal/libvirt/libvirt_test.go b/internal/libvirt/libvirt_test.go
index 03589d0..66e550d 100644
--- a/internal/libvirt/libvirt_test.go
+++ b/internal/libvirt/libvirt_test.go
@@ -1745,18 +1745,19 @@ func TestAddEffectiveAllocationCapacity_WithBothOvercommit(t *testing.T) {
}
func TestAddEffectiveAllocationCapacity_FractionalValuesFloored(t *testing.T) {
- // Test that fractional values are floored
+ // Test that fractional values are floored (not rounded)
+ // 11 * 1.5 = 16.5, which should be floored to 16
l := &LibVirt{}
hv := v1.Hypervisor{
Spec: v1.HypervisorSpec{
Overcommit: map[v1.ResourceName]float64{
- v1.ResourceCPU: 1.5, // 10 * 1.5 = 15
+ v1.ResourceCPU: 1.5, // 11 * 1.5 = 16.5
},
},
Status: v1.HypervisorStatus{
Capacity: map[v1.ResourceName]resource.Quantity{
- v1.ResourceCPU: *resource.NewQuantity(10, resource.DecimalSI),
+ v1.ResourceCPU: *resource.NewQuantity(11, resource.DecimalSI),
},
EffectiveCapacity: make(map[v1.ResourceName]resource.Quantity),
Cells: []v1.Cell{},
@@ -1769,8 +1770,8 @@ func TestAddEffectiveAllocationCapacity_FractionalValuesFloored(t *testing.T) {
t.Fatalf("addEffectiveAllocationCapacity() returned unexpected error: %v", err)
}
- // CPU should be floor(10 * 1.5) = floor(15) = 15
- expectedCPU := resource.NewQuantity(15, resource.DecimalSI)
+ // CPU should be floor(11 * 1.5) = floor(16.5) = 16
+ expectedCPU := resource.NewQuantity(16, resource.DecimalSI)
cpuEffective := result.Status.EffectiveCapacity[v1.ResourceCPU]
if !cpuEffective.Equal(*expectedCPU) {
t.Errorf("Expected effective CPU capacity %s, got %s",
@@ -1779,18 +1780,19 @@ func TestAddEffectiveAllocationCapacity_FractionalValuesFloored(t *testing.T) {
}
func TestAddEffectiveAllocationCapacity_FractionalValuesFlooredDown(t *testing.T) {
- // Test that fractional values are floored down, not rounded
+ // Test that fractional values are floored down, not rounded up
+ // 3 * 1.9 = 5.7, which should be floored to 5 (not rounded to 6)
l := &LibVirt{}
hv := v1.Hypervisor{
Spec: v1.HypervisorSpec{
Overcommit: map[v1.ResourceName]float64{
- v1.ResourceCPU: 1.9, // 10 * 1.9 = 19
+ v1.ResourceCPU: 1.9, // 3 * 1.9 = 5.7
},
},
Status: v1.HypervisorStatus{
Capacity: map[v1.ResourceName]resource.Quantity{
- v1.ResourceCPU: *resource.NewQuantity(10, resource.DecimalSI),
+ v1.ResourceCPU: *resource.NewQuantity(3, resource.DecimalSI),
},
EffectiveCapacity: make(map[v1.ResourceName]resource.Quantity),
Cells: []v1.Cell{},
@@ -1803,8 +1805,8 @@ func TestAddEffectiveAllocationCapacity_FractionalValuesFlooredDown(t *testing.T
t.Fatalf("addEffectiveAllocationCapacity() returned unexpected error: %v", err)
}
- // CPU should be floor(10 * 1.9) = floor(19) = 19
- expectedCPU := resource.NewQuantity(19, resource.DecimalSI)
+ // CPU should be floor(3 * 1.9) = floor(5.7) = 5
+ expectedCPU := resource.NewQuantity(5, resource.DecimalSI)
cpuEffective := result.Status.EffectiveCapacity[v1.ResourceCPU]
if !cpuEffective.Equal(*expectedCPU) {
t.Errorf("Expected effective CPU capacity %s, got %s",
From 6586e8fcf3a4f000056e93d69459c3d56ed84ea6 Mon Sep 17 00:00:00 2001
From: Philipp Matthes
Date: Fri, 13 Mar 2026 14:56:01 +0100
Subject: [PATCH 4/5] Remove stale entries from map
---
internal/libvirt/libvirt.go | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/internal/libvirt/libvirt.go b/internal/libvirt/libvirt.go
index 9c28c63..775f316 100644
--- a/internal/libvirt/libvirt.go
+++ b/internal/libvirt/libvirt.go
@@ -562,10 +562,8 @@ func (l *LibVirt) addAllocationCapacity(old v1.Hypervisor) (v1.Hypervisor, error
// the resulting values are fractional, they are floored.
func (l *LibVirt) addEffectiveAllocationCapacity(old v1.Hypervisor) (v1.Hypervisor, error) {
newHv := *old.DeepCopy()
- // Initialize the EffectiveCapacity map if it's nil
- if newHv.Status.EffectiveCapacity == nil {
- newHv.Status.EffectiveCapacity = make(map[v1.ResourceName]resource.Quantity)
- }
+ // Always recreate the EffectiveCapacity map to remove stale entries
+ newHv.Status.EffectiveCapacity = make(map[v1.ResourceName]resource.Quantity)
for resourceName, capacity := range newHv.Status.Capacity {
overcommit, ok := newHv.Spec.Overcommit[resourceName]
if !ok {
@@ -577,10 +575,8 @@ func (l *LibVirt) addEffectiveAllocationCapacity(old v1.Hypervisor) (v1.Hypervis
}
// Also apply this to each cell.
for i, cell := range newHv.Status.Cells {
- // Initialize the cell's EffectiveCapacity map if it's nil
- if cell.EffectiveCapacity == nil {
- cell.EffectiveCapacity = make(map[v1.ResourceName]resource.Quantity)
- }
+ // Always recreate the cell's EffectiveCapacity map to remove stale entries
+ cell.EffectiveCapacity = make(map[v1.ResourceName]resource.Quantity)
for resourceName, capacity := range cell.Capacity {
overcommit, ok := newHv.Spec.Overcommit[resourceName]
if !ok {
From cd961645dd75bcf008e07496e893043473ffda1a Mon Sep 17 00:00:00 2001
From: Philipp Matthes
Date: Fri, 13 Mar 2026 14:58:51 +0100
Subject: [PATCH 5/5] Rename addEffectiveAllocationCapacity ->
addEffectiveCapacity
---
internal/libvirt/libvirt.go | 12 ++++-----
internal/libvirt/libvirt_test.go | 42 ++++++++++++++++----------------
2 files changed, 27 insertions(+), 27 deletions(-)
diff --git a/internal/libvirt/libvirt.go b/internal/libvirt/libvirt.go
index 775f316..591a18c 100644
--- a/internal/libvirt/libvirt.go
+++ b/internal/libvirt/libvirt.go
@@ -274,7 +274,7 @@ func (l *LibVirt) Process(hv v1.Hypervisor) (v1.Hypervisor, error) {
l.addCapabilities,
l.addDomainCapabilities,
l.addAllocationCapacity,
- l.addEffectiveAllocationCapacity,
+ l.addEffectiveCapacity,
}
var err error
for _, processor := range processors {
@@ -555,12 +555,12 @@ func (l *LibVirt) addAllocationCapacity(old v1.Hypervisor) (v1.Hypervisor, error
return newHv, nil
}
-// Add the effective allocation capacity to the hypervisor instance.
+// Add the effective capacity to the hypervisor instance.
//
-// The effective allocation capacity is calculated as the physical capacity and
-// allocation times the applied overcommit ratio, or 1.0 by default. In case
-// the resulting values are fractional, they are floored.
-func (l *LibVirt) addEffectiveAllocationCapacity(old v1.Hypervisor) (v1.Hypervisor, error) {
+// The effective capacity is calculated as the physical capacity times the
+// applied overcommit ratio, or 1.0 by default. In case the resulting values
+// are fractional, they are floored.
+func (l *LibVirt) addEffectiveCapacity(old v1.Hypervisor) (v1.Hypervisor, error) {
newHv := *old.DeepCopy()
// Always recreate the EffectiveCapacity map to remove stale entries
newHv.Status.EffectiveCapacity = make(map[v1.ResourceName]resource.Quantity)
diff --git a/internal/libvirt/libvirt_test.go b/internal/libvirt/libvirt_test.go
index 66e550d..9e4da3d 100644
--- a/internal/libvirt/libvirt_test.go
+++ b/internal/libvirt/libvirt_test.go
@@ -1553,7 +1553,7 @@ func TestRunEventLoop_ClosedEventChannel(t *testing.T) {
}
}
-func TestAddEffectiveAllocationCapacity_NoOvercommit(t *testing.T) {
+func TestAddEffectiveCapacity_NoOvercommit(t *testing.T) {
// Test that when no overcommit is specified, effective capacity equals capacity
l := &LibVirt{}
@@ -1577,10 +1577,10 @@ func TestAddEffectiveAllocationCapacity_NoOvercommit(t *testing.T) {
},
}
- result, err := l.addEffectiveAllocationCapacity(hv)
+ result, err := l.addEffectiveCapacity(hv)
if err != nil {
- t.Fatalf("addEffectiveAllocationCapacity() returned unexpected error: %v", err)
+ t.Fatalf("addEffectiveCapacity() returned unexpected error: %v", err)
}
// With no overcommit, effective capacity should equal physical capacity
@@ -1614,7 +1614,7 @@ func TestAddEffectiveAllocationCapacity_NoOvercommit(t *testing.T) {
}
}
-func TestAddEffectiveAllocationCapacity_WithMemoryOvercommit(t *testing.T) {
+func TestAddEffectiveCapacity_WithMemoryOvercommit(t *testing.T) {
// Test memory overcommit ratio of 1.5
l := &LibVirt{}
@@ -1634,10 +1634,10 @@ func TestAddEffectiveAllocationCapacity_WithMemoryOvercommit(t *testing.T) {
},
}
- result, err := l.addEffectiveAllocationCapacity(hv)
+ result, err := l.addEffectiveCapacity(hv)
if err != nil {
- t.Fatalf("addEffectiveAllocationCapacity() returned unexpected error: %v", err)
+ t.Fatalf("addEffectiveCapacity() returned unexpected error: %v", err)
}
// Memory should be 64 GiB * 1.5 = 96 GiB
@@ -1657,7 +1657,7 @@ func TestAddEffectiveAllocationCapacity_WithMemoryOvercommit(t *testing.T) {
}
}
-func TestAddEffectiveAllocationCapacity_WithCPUOvercommit(t *testing.T) {
+func TestAddEffectiveCapacity_WithCPUOvercommit(t *testing.T) {
// Test CPU overcommit ratio of 4.0
l := &LibVirt{}
@@ -1677,10 +1677,10 @@ func TestAddEffectiveAllocationCapacity_WithCPUOvercommit(t *testing.T) {
},
}
- result, err := l.addEffectiveAllocationCapacity(hv)
+ result, err := l.addEffectiveCapacity(hv)
if err != nil {
- t.Fatalf("addEffectiveAllocationCapacity() returned unexpected error: %v", err)
+ t.Fatalf("addEffectiveCapacity() returned unexpected error: %v", err)
}
// Memory should remain unchanged (no overcommit specified, defaults to 1.0)
@@ -1700,7 +1700,7 @@ func TestAddEffectiveAllocationCapacity_WithCPUOvercommit(t *testing.T) {
}
}
-func TestAddEffectiveAllocationCapacity_WithBothOvercommit(t *testing.T) {
+func TestAddEffectiveCapacity_WithBothOvercommit(t *testing.T) {
// Test both memory and CPU overcommit
l := &LibVirt{}
@@ -1721,10 +1721,10 @@ func TestAddEffectiveAllocationCapacity_WithBothOvercommit(t *testing.T) {
},
}
- result, err := l.addEffectiveAllocationCapacity(hv)
+ result, err := l.addEffectiveCapacity(hv)
if err != nil {
- t.Fatalf("addEffectiveAllocationCapacity() returned unexpected error: %v", err)
+ t.Fatalf("addEffectiveCapacity() returned unexpected error: %v", err)
}
// Memory should be 32 GiB * 2.0 = 64 GiB
@@ -1744,7 +1744,7 @@ func TestAddEffectiveAllocationCapacity_WithBothOvercommit(t *testing.T) {
}
}
-func TestAddEffectiveAllocationCapacity_FractionalValuesFloored(t *testing.T) {
+func TestAddEffectiveCapacity_FractionalValuesFloored(t *testing.T) {
// Test that fractional values are floored (not rounded)
// 11 * 1.5 = 16.5, which should be floored to 16
l := &LibVirt{}
@@ -1764,10 +1764,10 @@ func TestAddEffectiveAllocationCapacity_FractionalValuesFloored(t *testing.T) {
},
}
- result, err := l.addEffectiveAllocationCapacity(hv)
+ result, err := l.addEffectiveCapacity(hv)
if err != nil {
- t.Fatalf("addEffectiveAllocationCapacity() returned unexpected error: %v", err)
+ t.Fatalf("addEffectiveCapacity() returned unexpected error: %v", err)
}
// CPU should be floor(11 * 1.5) = floor(16.5) = 16
@@ -1779,7 +1779,7 @@ func TestAddEffectiveAllocationCapacity_FractionalValuesFloored(t *testing.T) {
}
}
-func TestAddEffectiveAllocationCapacity_FractionalValuesFlooredDown(t *testing.T) {
+func TestAddEffectiveCapacity_FractionalValuesFlooredDown(t *testing.T) {
// Test that fractional values are floored down, not rounded up
// 3 * 1.9 = 5.7, which should be floored to 5 (not rounded to 6)
l := &LibVirt{}
@@ -1799,10 +1799,10 @@ func TestAddEffectiveAllocationCapacity_FractionalValuesFlooredDown(t *testing.T
},
}
- result, err := l.addEffectiveAllocationCapacity(hv)
+ result, err := l.addEffectiveCapacity(hv)
if err != nil {
- t.Fatalf("addEffectiveAllocationCapacity() returned unexpected error: %v", err)
+ t.Fatalf("addEffectiveCapacity() returned unexpected error: %v", err)
}
// CPU should be floor(3 * 1.9) = floor(5.7) = 5
@@ -1814,7 +1814,7 @@ func TestAddEffectiveAllocationCapacity_FractionalValuesFlooredDown(t *testing.T
}
}
-func TestAddEffectiveAllocationCapacity_MultipleCells(t *testing.T) {
+func TestAddEffectiveCapacity_MultipleCells(t *testing.T) {
// Test that overcommit is applied to each cell individually
l := &LibVirt{}
@@ -1852,10 +1852,10 @@ func TestAddEffectiveAllocationCapacity_MultipleCells(t *testing.T) {
},
}
- result, err := l.addEffectiveAllocationCapacity(hv)
+ result, err := l.addEffectiveCapacity(hv)
if err != nil {
- t.Fatalf("addEffectiveAllocationCapacity() returned unexpected error: %v", err)
+ t.Fatalf("addEffectiveCapacity() returned unexpected error: %v", err)
}
// Check total effective capacity