diff --git a/util_test_helper.go b/util_test_helper.go index 8811b93..994633d 100644 --- a/util_test_helper.go +++ b/util_test_helper.go @@ -5,7 +5,7 @@ import ( "fmt" "math/rand" "os" - "strings" + "regexp" "testing" "time" @@ -436,8 +436,10 @@ type testHelper struct { username string } +var resourceNameRe = regexp.MustCompile(`[^a-zA-Z\d_.-]`) + func (t *testHelper) GenerateTestResourceName(test *testing.T) string { - return strings.ReplaceAll(fmt.Sprintf("%s-%s", test.Name(), t.GenerateRandomID(5)), "/", "_") + return resourceNameRe.ReplaceAllString(fmt.Sprintf("%s-%s", test.Name(), t.GenerateRandomID(5)), "_") } func (t *testHelper) GetUsername() string { diff --git a/vm.go b/vm.go index 86d7daf..4612f83 100644 --- a/vm.go +++ b/vm.go @@ -213,9 +213,8 @@ type VMData interface { CPU() VMCPU // Memory return the Memory of a VM in Bytes. Memory() int64 - // MemoryPolicy returns the memory policy set on the VM, if any. The second parameter returned is true if the - // memory policy is set. - MemoryPolicy() (MemoryPolicy, bool) + // MemoryPolicy returns the memory policy set on the VM. + MemoryPolicy() MemoryPolicy // TagIDs returns a list of tags for this VM. TagIDs() []TagID // HugePages returns the hugepage settings for the VM, if any. @@ -1120,6 +1119,7 @@ func (v vmPlacementPolicyParameters) MustWithHostIDs(hostIDs []HostID) Buildable type MemoryPolicyParameters interface { Guaranteed() *int64 Max() *int64 + Ballooning() *bool } // BuildableMemoryPolicyParameters is a buildable version of MemoryPolicyParameters. @@ -1131,6 +1131,9 @@ type BuildableMemoryPolicyParameters interface { WithMax(max int64) (BuildableMemoryPolicyParameters, error) MustWithMax(max int64) BuildableMemoryPolicyParameters + + WithBallooning(ballooning bool) (BuildableMemoryPolicyParameters, error) + MustWithBallooning(ballooning bool) BuildableMemoryPolicyParameters } // NewMemoryPolicyParameters creates a new instance of BuildableMemoryPolicyParameters. @@ -1141,6 +1144,24 @@ func NewMemoryPolicyParameters() BuildableMemoryPolicyParameters { type memoryPolicyParameters struct { guaranteed *int64 max *int64 + ballooning *bool +} + +func (m *memoryPolicyParameters) Ballooning() *bool { + return m.ballooning +} + +func (m *memoryPolicyParameters) WithBallooning(ballooning bool) (BuildableMemoryPolicyParameters, error) { + m.ballooning = &ballooning + return m, nil +} + +func (m *memoryPolicyParameters) MustWithBallooning(ballooning bool) BuildableMemoryPolicyParameters { + builder, err := m.WithBallooning(ballooning) + if err != nil { + panic(err) + } + return builder } func (m *memoryPolicyParameters) MustWithGuaranteed(guaranteed int64) BuildableMemoryPolicyParameters { @@ -1183,11 +1204,18 @@ type MemoryPolicy interface { Guaranteed() *int64 // Max returns the maximum amount of memory given to the VM. Max() *int64 + // Ballooning returns true if the VM can give back the memory it is not using to the host OS. + Ballooning() bool } type memoryPolicy struct { guaranteed *int64 max *int64 + ballooning bool +} + +func (m memoryPolicy) Ballooning() bool { + return m.ballooning } func (m memoryPolicy) Max() *int64 { @@ -1806,8 +1834,8 @@ func (v *vm) PlacementPolicy() (VMPlacementPolicy, bool) { return v.placementPolicy, v.placementPolicy != nil } -func (v *vm) MemoryPolicy() (MemoryPolicy, bool) { - return v.memoryPolicy, v.memoryPolicy != nil +func (v *vm) MemoryPolicy() MemoryPolicy { + return v.memoryPolicy } func (v *vm) WaitForIPAddresses(params VMIPSearchParams, retries ...RetryStrategy) (map[string][]net.IP, error) { @@ -2080,21 +2108,29 @@ func vmInstanceTypeIDConverter(object *ovirtsdk.Vm, v *vm) error { } func vmMemoryPolicyConverter(object *ovirtsdk.Vm, v *vm) error { - if memPolicy, ok := object.MemoryPolicy(); ok { - resultMemPolicy := &memoryPolicy{} - if guaranteed, ok := memPolicy.Guaranteed(); ok { - if guaranteed < -1 { - return newError( - EBug, - "the engine returned a negative guaranteed memory value for VM %s (%d)", - object.MustId(), - guaranteed, - ) - } - resultMemPolicy.guaranteed = &guaranteed + memPolicy, ok := object.MemoryPolicy() + if !ok { + return newFieldNotFound("vm", "memory policy") + } + resultMemPolicy := &memoryPolicy{} + if guaranteed, ok := memPolicy.Guaranteed(); ok { + if guaranteed < -1 { + return newError( + EBug, + "the engine returned a negative guaranteed memory value for VM %s (%d)", + object.MustId(), + guaranteed, + ) } - v.memoryPolicy = resultMemPolicy + resultMemPolicy.guaranteed = &guaranteed + } + if max, ok := memPolicy.Max(); ok { + resultMemPolicy.max = &max + } + if ballooning, ok := memPolicy.Ballooning(); ok { + resultMemPolicy.ballooning = ballooning } + v.memoryPolicy = resultMemPolicy return nil } diff --git a/vm_create.go b/vm_create.go index 78f2675..1f91d10 100644 --- a/vm_create.go +++ b/vm_create.go @@ -226,6 +226,9 @@ func vmBuilderMemoryPolicy(params OptionalVMParameters, builder *ovirtsdk.VmBuil if max := (*memPolicyParams).Max(); max != nil { memoryPolicyBuilder.Max(*max) } + if ballooning := (*memPolicyParams).Ballooning(); ballooning != nil { + memoryPolicyBuilder.Ballooning(*ballooning) + } builder.MemoryPolicyBuilder(memoryPolicyBuilder) } } @@ -412,19 +415,20 @@ func (m *mockClient) createVMMemory(params OptionalVMParameters) int64 { } func (m *mockClient) createVMMemoryPolicy(params OptionalVMParameters) *memoryPolicy { - var memPolicy *memoryPolicy + memPolicy := &memoryPolicy{ + ballooning: true, + } if memoryPolicyParams := params.MemoryPolicy(); memoryPolicyParams != nil { - var guaranteed *int64 if guaranteedMemory := (*memoryPolicyParams).Guaranteed(); guaranteedMemory != nil { - guaranteed = guaranteedMemory + memPolicy.guaranteed = guaranteedMemory } - var max *int64 + if maxMemory := (*memoryPolicyParams).Max(); maxMemory != nil { - max = maxMemory + memPolicy.max = maxMemory } - memPolicy = &memoryPolicy{ - guaranteed, - max, + + if memBallooning := (*memoryPolicyParams).Ballooning(); memBallooning != nil { + memPolicy.ballooning = *memBallooning } } return memPolicy diff --git a/vm_test.go b/vm_test.go index 667070b..41950f5 100644 --- a/vm_test.go +++ b/vm_test.go @@ -471,6 +471,22 @@ func TestVMCreationWithSparseDisks(t *testing.T) { ) } +func TestMemoryPolicyDefaults(t *testing.T) { + helper := getHelper(t) + vm := assertCanCreateVM( + t, + helper, + helper.GenerateTestResourceName(t), + nil, + ) + // Test if memory policy is correctly set + memoryPolicy := vm.MemoryPolicy() + if memoryPolicy == nil { + t.Fatalf("Memory policy was not set.") + } + +} + func TestGuaranteedMemory(t *testing.T) { helper := getHelper(t) expectedGuaranteed := int64(2 * 1024 * 1024 * 1024) @@ -486,10 +502,7 @@ func TestGuaranteedMemory(t *testing.T) { MustWithGuaranteed(expectedGuaranteed), ).MustWithMemory(expectedGuaranteed), ) - memoryPolicy, ok := vm.MemoryPolicy() - if !ok { - t.Fatalf("Memory policy is not set on VM.") - } + memoryPolicy := vm.MemoryPolicy() guaranteed := memoryPolicy.Guaranteed() if guaranteed == nil { t.Fatalf("Guaranteed memory is not set on VM.") @@ -514,10 +527,7 @@ func TestMaxMemory(t *testing.T) { MustWithMax(expectedMax), ).MustWithMemory(expectedMax), ) - memoryPolicy, ok := vm.MemoryPolicy() - if !ok { - t.Fatalf("Memory policy is not set on VM.") - } + memoryPolicy := vm.MemoryPolicy() max := memoryPolicy.Max() if max == nil { t.Fatalf("Guaranteed memory is not set on VM.") @@ -527,6 +537,58 @@ func TestMaxMemory(t *testing.T) { } } +func TestBallooning(t *testing.T) { + truePointer := true + falsePointer := false + testCases := []struct { + name string + set *bool + expected bool + }{ + { + "empty", + nil, + true, + }, + { + "true", + &truePointer, + true, + }, + { + "false", + &falsePointer, + false, + }, + } + + for _, testCase := range testCases { + t.Run(fmt.Sprintf("ballooning=%s", testCase.name), func(t *testing.T) { + helper := getHelper(t) + params := ovirtclient.NewCreateVMParams() + if testCase.set != nil { + params = params.WithMemoryPolicy( + ovirtclient. + NewMemoryPolicyParameters(). + MustWithBallooning(*testCase.set), + ) + } + vm := assertCanCreateVM( + t, + helper, + helper.GenerateTestResourceName(t), + params, + ) + memoryPolicy := vm.MemoryPolicy() + ballooning := memoryPolicy.Ballooning() + if ballooning != testCase.expected { + t.Fatalf("Incorrect ballooning value") + } + }) + } + +} + func checkVMDiskSparseness(t *testing.T, checkVM ovirtclient.VM, sparse bool, message string) { t.Helper() diskAttachments, err := checkVM.ListDiskAttachments()