From 53ab9dc96576546381460aeb84f079c459710b1f Mon Sep 17 00:00:00 2001 From: Piotr Kliczewski Date: Wed, 30 Sep 2020 16:40:11 +0200 Subject: [PATCH] Use template validation rules In previous implementation we used resource.memory which was not correct. Now let's base our validation logic on the rules. Bug-Url: https://bugzilla.redhat.com/1871433 Signed-off-by: Piotr Kliczewski --- .../validation/validators/vm-validator.go | 57 +++++++++++++++---- .../validators/vm-validator_test.go | 21 +++++-- 2 files changed, 63 insertions(+), 15 deletions(-) diff --git a/pkg/providers/ovirt/validation/validators/vm-validator.go b/pkg/providers/ovirt/validation/validators/vm-validator.go index 893ac3bb7..1d3259246 100644 --- a/pkg/providers/ovirt/validation/validators/vm-validator.go +++ b/pkg/providers/ovirt/validation/validators/vm-validator.go @@ -3,6 +3,7 @@ package validators import ( "encoding/json" "fmt" + "math" kvConfig "github.com/kubevirt/vm-import-operator/pkg/config/kubevirt" @@ -12,9 +13,13 @@ import ( otemplates "github.com/kubevirt/vm-import-operator/pkg/providers/ovirt/templates" outils "github.com/kubevirt/vm-import-operator/pkg/providers/ovirt/utils" ovirtsdk "github.com/ovirt/go-ovirt" - kubevirtv1 "kubevirt.io/client-go/api/v1" ) +type rule struct { + Name string `json:"name"` + Min interface{} `json:"min,omitempty"` +} + // ValidateVM validates given VM func ValidateVM(vm *ovirtsdk.Vm, config kvConfig.KubeVirtConfig, finder *otemplates.TemplateFinder) []ValidationFailure { var results = isValidBios(vm) @@ -125,23 +130,53 @@ func isMemoryAboveRequests(vm *ovirtsdk.Vm, finder *otemplates.TemplateFinder) ( // missing template is verified later return ValidationFailure{}, true } - tempVM := kubevirtv1.VirtualMachine{} - err = json.Unmarshal(template.Objects[0].Raw, &tempVM) + validations := template.Annotations["validations"] + var rules []rule + err = json.Unmarshal([]byte(validations), &rules) if err != nil { - // template processed later + // ignoring, issue with template validation rules return ValidationFailure{}, true } - tempMem, tok := tempVM.Spec.Template.Spec.Domain.Resources.Requests.Memory().AsInt64() - sourceMem, sok := vm.Memory() - if tok && sok && tempMem > sourceMem { - return ValidationFailure{ - ID: VMMemoryTemplateLimitID, - Message: fmt.Sprintf("Source VM memory is lower than enforced by template."), - }, false + + for i := range rules { + r := &rules[i] + if r.Name == "minimal-required-memory" { + sourceMem, sok := vm.Memory() + tempMem, ok := toInt64(r.Min) + if ok && sok && tempMem > sourceMem { + return ValidationFailure{ + ID: VMMemoryTemplateLimitID, + Message: fmt.Sprintf("Source VM memory %d is lower than %d enforced by %s template.", sourceMem, tempMem, template.Name), + }, false + } + } } + return ValidationFailure{}, true } +func toInt64(obj interface{}) (int64, bool) { + switch val := obj.(type) { + case int: + return int64(val), true + case int32: + return int64(val), true + case int64: + return int64(val), true + case uint: + return int64(val), true + case uint32: + return int64(val), true + case uint64: + return int64(val), true + case float32: + return int64(math.Round(float64(val))), true + case float64: + return int64(math.Round(val)), true + } + return 0, false +} + func isValidStatus(vm *ovirtsdk.Vm) (ValidationFailure, bool) { if status, ok := vm.Status(); ok { if status != ovirtsdk.VMSTATUS_UP && status != ovirtsdk.VMSTATUS_DOWN { diff --git a/pkg/providers/ovirt/validation/validators/vm-validator_test.go b/pkg/providers/ovirt/validation/validators/vm-validator_test.go index d414e9cf7..e81f1e3c1 100644 --- a/pkg/providers/ovirt/validation/validators/vm-validator_test.go +++ b/pkg/providers/ovirt/validation/validators/vm-validator_test.go @@ -525,7 +525,7 @@ func newVMWithStatusControl(withStatus bool) *ovirtsdk.Vm { cpu.SetCpuTune(&cpuTune) vm.SetCpu(&cpu) - vm.SetMemory(536870912) + vm.SetMemory(2147483648) ha := ovirtsdk.HighAvailability{} ha.SetEnabled(true) @@ -613,9 +613,10 @@ func (t *mockTemplateProvider) Find(name *string, os *string, workload *string, Items: []templatev1.Template{ { ObjectMeta: metav1.ObjectMeta{ - Name: *name, - Namespace: "default", - Labels: templates.OSLabelBuilder(os, workload, flavor), + Name: *name, + Namespace: "default", + Labels: templates.OSLabelBuilder(os, workload, flavor), + Annotations: getAnnotations(), }, Objects: []runtime.RawExtension{ { @@ -627,6 +628,18 @@ func (t *mockTemplateProvider) Find(name *string, os *string, workload *string, }, nil } +func getAnnotations() map[string]string { + annons := make(map[string]string) + annons["validations"] = `[{ + "name": "minimal-required-memory", + "path": "jsonpath::.spec.domain.resources.requests.memory", + "rule": "integer", + "message": "This VM requires more memory.", + "min": 1610612736 + }]` + return annons +} + // Process mocks the behavior of the client for calling process API func (t *mockTemplateProvider) Process(namespace string, vmName *string, template *templatev1.Template) (*templatev1.Template, error) { return nil, nil