Skip to content

Commit 8146dfb

Browse files
Calculate effective capacity from overcommit and capacity (#70)
In cobaltcore-dev/openstack-hypervisor-operator#257 we add a spec field that can be used to specify the desired overcommit ratio for each resource name. This change applies the overcommit ratio to the hypervisor to its status, by calculating the effective capacity and exposing it through the hypervisor status.
1 parent 8e5b18e commit 8146dfb

4 files changed

Lines changed: 402 additions & 17 deletions

File tree

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ go 1.26
77

88
require (
99
github.com/cert-manager/cert-manager v1.19.4
10-
github.com/cobaltcore-dev/openstack-hypervisor-operator v0.0.0-20260309144200-9c8ed613a94c
10+
github.com/cobaltcore-dev/openstack-hypervisor-operator v0.0.0-20260313120621-e3699e2ccab9
1111
github.com/coreos/go-systemd/v22 v22.7.0
1212
github.com/digitalocean/go-libvirt v0.0.0-20260217163227-273eaa321819
1313
github.com/godbus/dbus/v5 v5.2.2

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
1616
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
1717
github.com/cobaltcore-dev/openstack-hypervisor-operator v0.0.0-20260309144200-9c8ed613a94c h1:KylfcJikSMWNJnuNfG1Od6fNUw4kQTjseP7khmwVlrM=
1818
github.com/cobaltcore-dev/openstack-hypervisor-operator v0.0.0-20260309144200-9c8ed613a94c/go.mod h1:b0KmJdxvRI8UXlGe8cRm5BD8Tm2WhF7zSKMSIRGyVL4=
19+
github.com/cobaltcore-dev/openstack-hypervisor-operator v0.0.0-20260313120621-e3699e2ccab9 h1:fIQCfP6HTOMu9XqcRLUYeUCK2mPWcOkSqYVF9HUhQyE=
20+
github.com/cobaltcore-dev/openstack-hypervisor-operator v0.0.0-20260313120621-e3699e2ccab9/go.mod h1:b0KmJdxvRI8UXlGe8cRm5BD8Tm2WhF7zSKMSIRGyVL4=
1921
github.com/coreos/go-systemd/v22 v22.7.0 h1:LAEzFkke61DFROc7zNLX/WA2i5J8gYqe0rSj9KI28KA=
2022
github.com/coreos/go-systemd/v22 v22.7.0/go.mod h1:xNUYtjHu2EDXbsxz1i41wouACIwT7Ybq9o0BQhMwD0w=
2123
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=

internal/libvirt/libvirt.go

Lines changed: 53 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ func (l *LibVirt) Process(hv v1.Hypervisor) (v1.Hypervisor, error) {
274274
l.addCapabilities,
275275
l.addDomainCapabilities,
276276
l.addAllocationCapacity,
277+
l.addEffectiveCapacity,
277278
}
278279
var err error
279280
for _, processor := range processors {
@@ -458,14 +459,14 @@ func (l *LibVirt) addAllocationCapacity(old v1.Hypervisor) (v1.Hypervisor, error
458459

459460
cellsById[cell.ID] = v1.Cell{
460461
CellID: cell.ID,
461-
Allocation: map[string]resource.Quantity{
462+
Allocation: map[v1.ResourceName]resource.Quantity{
462463
// Will be updated below when we look at the domain infos.
463-
"memory": *resource.NewQuantity(0, resource.BinarySI),
464-
"cpu": *resource.NewQuantity(0, resource.DecimalSI),
464+
v1.ResourceMemory: *resource.NewQuantity(0, resource.BinarySI),
465+
v1.ResourceCPU: *resource.NewQuantity(0, resource.DecimalSI),
465466
},
466-
Capacity: map[string]resource.Quantity{
467-
"memory": memoryCapacity,
468-
"cpu": cpuCapacity,
467+
Capacity: map[v1.ResourceName]resource.Quantity{
468+
v1.ResourceMemory: memoryCapacity,
469+
v1.ResourceCPU: cpuCapacity,
469470
},
470471
}
471472
}
@@ -505,14 +506,14 @@ func (l *LibVirt) addAllocationCapacity(old v1.Hypervisor) (v1.Hypervisor, error
505506
domInfo.Name, memoryNode.CellID,
506507
)
507508
}
508-
memAllocCell := cell.Allocation["memory"]
509+
memAllocCell := cell.Allocation[v1.ResourceMemory]
509510
// If a domain is using multiple memory cells, assume the
510511
// distribution across cells is even.
511512
nCells := int64(len(domInfo.NumaTune.MemNodes)) // is non-zero
512513
memAllocPerCell := *resource.
513514
NewQuantity(memAlloc.Value()/nCells, resource.BinarySI)
514515
memAllocCell.Add(memAllocPerCell)
515-
cell.Allocation["memory"] = memAllocCell
516+
cell.Allocation[v1.ResourceMemory] = memAllocCell
516517
cellsById[memoryNode.CellID] = cell
517518
}
518519

@@ -528,14 +529,14 @@ func (l *LibVirt) addAllocationCapacity(old v1.Hypervisor) (v1.Hypervisor, error
528529
domInfo.Name, cpuCell.ID,
529530
)
530531
}
531-
cpuAllocCell := cell.Allocation["cpu"]
532+
cpuAllocCell := cell.Allocation[v1.ResourceCPU]
532533
// If a domain is using multiple cpu cells, assume the distribution
533534
// across cells is even.
534535
nCells := int64(len(domInfo.CPU.Numa.Cells)) // is non-zero
535536
cpuAllocPerCell := *resource.
536537
NewQuantity(cpuAlloc.Value()/nCells, resource.DecimalSI)
537538
cpuAllocCell.Add(cpuAllocPerCell)
538-
cell.Allocation["cpu"] = cpuAllocCell
539+
cell.Allocation[v1.ResourceCPU] = cpuAllocCell
539540
cellsById[cpuCell.ID] = cell
540541
}
541542
}
@@ -544,12 +545,48 @@ func (l *LibVirt) addAllocationCapacity(old v1.Hypervisor) (v1.Hypervisor, error
544545
cellsAsSlice = append(cellsAsSlice, cell)
545546
}
546547

547-
newHv.Status.Capacity = make(map[string]resource.Quantity)
548-
newHv.Status.Capacity["memory"] = *totalMemoryCapacity
549-
newHv.Status.Capacity["cpu"] = *totalCpuCapacity
550-
newHv.Status.Allocation = make(map[string]resource.Quantity)
551-
newHv.Status.Allocation["memory"] = *totalMemoryAlloc
552-
newHv.Status.Allocation["cpu"] = *totalCpuAlloc
548+
newHv.Status.Capacity = make(map[v1.ResourceName]resource.Quantity)
549+
newHv.Status.Capacity[v1.ResourceMemory] = *totalMemoryCapacity
550+
newHv.Status.Capacity[v1.ResourceCPU] = *totalCpuCapacity
551+
newHv.Status.Allocation = make(map[v1.ResourceName]resource.Quantity)
552+
newHv.Status.Allocation[v1.ResourceMemory] = *totalMemoryAlloc
553+
newHv.Status.Allocation[v1.ResourceCPU] = *totalCpuAlloc
553554
newHv.Status.Cells = cellsAsSlice
554555
return newHv, nil
555556
}
557+
558+
// Add the effective capacity to the hypervisor instance.
559+
//
560+
// The effective capacity is calculated as the physical capacity times the
561+
// applied overcommit ratio, or 1.0 by default. In case the resulting values
562+
// are fractional, they are floored.
563+
func (l *LibVirt) addEffectiveCapacity(old v1.Hypervisor) (v1.Hypervisor, error) {
564+
newHv := *old.DeepCopy()
565+
// Always recreate the EffectiveCapacity map to remove stale entries
566+
newHv.Status.EffectiveCapacity = make(map[v1.ResourceName]resource.Quantity)
567+
for resourceName, capacity := range newHv.Status.Capacity {
568+
overcommit, ok := newHv.Spec.Overcommit[resourceName]
569+
if !ok {
570+
overcommit = 1.0
571+
}
572+
flooredValue := int64(float64(capacity.Value()) * overcommit)
573+
effectiveCapacity := resource.NewQuantity(flooredValue, capacity.Format)
574+
newHv.Status.EffectiveCapacity[resourceName] = *effectiveCapacity
575+
}
576+
// Also apply this to each cell.
577+
for i, cell := range newHv.Status.Cells {
578+
// Always recreate the cell's EffectiveCapacity map to remove stale entries
579+
cell.EffectiveCapacity = make(map[v1.ResourceName]resource.Quantity)
580+
for resourceName, capacity := range cell.Capacity {
581+
overcommit, ok := newHv.Spec.Overcommit[resourceName]
582+
if !ok {
583+
overcommit = 1.0
584+
}
585+
flooredValue := int64(float64(capacity.Value()) * overcommit)
586+
effectiveCapacity := resource.NewQuantity(flooredValue, capacity.Format)
587+
cell.EffectiveCapacity[resourceName] = *effectiveCapacity
588+
}
589+
newHv.Status.Cells[i] = cell
590+
}
591+
return newHv, nil
592+
}

0 commit comments

Comments
 (0)