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
2 changes: 1 addition & 1 deletion build/components/versions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ firmware:
libvirt: v10.9.0
edk2: stable202411
core:
3p-kubevirt: v1.6.2-v12n.28
3p-kubevirt: v1.6.2-v12n.30
3p-containerized-data-importer: v1.60.3-v12n.18
distribution: 2.8.3
package:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ func (b *KVVM) setCPUHotpluggable(cores int, coreFraction string) error {
domainSpec.CPU = &virtv1.CPU{}
}

fraction, err := GetCPUFraction(coreFraction)
fraction, err := ParseCPUCoreFraction(coreFraction)
if err != nil {
return err
}
Expand Down Expand Up @@ -440,14 +440,14 @@ func shouldKeepMemoryNonHotpluggable(kvvm *virtv1.VirtualMachine) bool {
return false
}

func GetCPUFraction(cpuFraction string) (int, error) {
func ParseCPUCoreFraction(cpuFraction string) (int, error) {
if cpuFraction == "" {
return 100, nil
}
fraction := intstr.FromString(cpuFraction)
value, _, err := getIntOrPercentValueSafely(&fraction)
if err != nil {
return 0, fmt.Errorf("invalid value for cpu fraction: %w", err)
return 0, fmt.Errorf("invalid value for cpu core fraction: %w", err)
}
return value, nil
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ func NewComparatorCPU(featureGate featuregate.FeatureGate) VMSpecFieldComparator
}

// Compare returns changes in the cpu section.
// // It supports CPU hotplug mechanism for cores changes.
// // It requires reboot if cpu fraction is changed or if COU hotplug is disabled.
// It returns "apply immediate" when cpu core fraction is changed or
// CPU cores change is compatible with hotplug.
func (c *comparatorCPU) Compare(current, desired *v1alpha2.VirtualMachineSpec) []FieldChange {
coresRestartMsg := ""

Expand All @@ -50,26 +50,29 @@ func (c *comparatorCPU) Compare(current, desired *v1alpha2.VirtualMachineSpec) [
coresChangedAction = ActionRestart
}

fractionChangedAction := ActionApplyImmediate

// Require reboot if CPU hotplug is not enabled.
if !c.featureGate.Enabled(featuregates.HotplugCPUWithLiveMigration) {
coresChangedAction = ActionRestart
fractionChangedAction = ActionRestart
}

coresChanges := compareInts("cpu.cores", current.CPU.Cores, desired.CPU.Cores, 0, coresChangedAction)
if HasChanges(coresChanges) && coresRestartMsg != "" {
coresChanges[0].RestartMessage = coresRestartMsg
}
fractionChanges := compareStrings("cpu.coreFraction", current.CPU.CoreFraction, desired.CPU.CoreFraction, DefaultCPUCoreFraction, ActionRestart)
fractionChanges := compareStrings("cpu.coreFraction", current.CPU.CoreFraction, desired.CPU.CoreFraction, DefaultCPUCoreFraction, fractionChangedAction)

// Yield full replace if both fields changed.
// Yield a full replace for cpu section if both fields are changed.
if HasChanges(coresChanges) && HasChanges(fractionChanges) {
return []FieldChange{
{
Operation: ChangeReplace,
Path: "cpu",
CurrentValue: current.CPU,
DesiredValue: desired.CPU,
ActionRequired: ActionRestart,
ActionRequired: MostDisruptiveAction(coresChangedAction, fractionChangedAction),
RestartMessage: coresRestartMsg,
},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ cpu:
),
},
{
"restart on cpu section change",
"restart on cpu section change when hotplug is disabled",
`
cpu:
cores: 2
Expand All @@ -88,6 +88,24 @@ cpu:
requirePathOperation("cpu", ChangeReplace),
),
},
{
"immediate apply on cpu section change when hotplug is enabled",
`
cpu:
cores: 2
coreFraction: 60%
`,
`
cpu:
cores: 6
coreFraction: 40%
`,
[]featuregate.Feature{featuregates.HotplugCPUWithLiveMigration},
assertChanges(
actionRequired(ActionApplyImmediate),
requirePathOperation("cpu", ChangeReplace),
),
},
{
"no restart cpu.coreFraction from empty to default value",
`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ limitations under the License.

package vmchange

import "cmp"

type ChangeOperation string

const (
Expand All @@ -33,6 +35,12 @@ const (
ActionApplyImmediate ActionType = "ApplyImmediate"
)

var actionDisruptionOrder = map[ActionType]int{
ActionNone: 0,
ActionApplyImmediate: 1,
ActionRestart: 2,
}

type FieldChange struct {
Operation ChangeOperation `json:"operation,omitempty"`
Path string `json:"path,omitempty"`
Expand All @@ -51,3 +59,31 @@ func HasChanges(changes []FieldChange) bool {
}
return false
}

// MostDisruptiveAction returns a most dangerous action from the list.
func MostDisruptiveAction(actions ...ActionType) ActionType {
result := ActionNone
for _, action := range actions {
// Break immediately if 'action' is the most disruptive action.
if action == ActionRestart {
return action
}
if action.Cmp(result) == 1 {
result = action
}
}
return result
}

// Cmp returns 0 if the action is equal to 'other', -1 if the action is less harmless than 'other',
// or 1 if the action is more disruptive than 'other'.
func (a ActionType) Cmp(other ActionType) int {
aOrder, hasA := actionDisruptionOrder[a]
otherOrder, hasOther := actionDisruptionOrder[other]
if hasA && hasOther {
return cmp.Compare(aOrder, otherOrder)
}

// Should not reach here, but equal is safe.
return 0
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,5 +82,5 @@ func (h *HotplugHandler) Name() string {
}

func getHotplugResourcesSum(vm *v1alpha2.VirtualMachine) string {
return fmt.Sprintf("cpu.cores=%d,memory.size=%s", vm.Spec.CPU.Cores, vm.Spec.Memory.Size.String())
return fmt.Sprintf("cpu.cores=%d,cpu.coreFraction=%s,memory.size=%s", vm.Spec.CPU.Cores, vm.Spec.CPU.CoreFraction, vm.Spec.Memory.Size.String())
}
Loading