package utils import ( "fmt" "regexp" "k8s.io/apimachinery/pkg/api/resource" "edge-infra.dev/pkg/edge/api/graph/model" ) func CreateVirtualMachineModel(virtualMachineID string, namespace string, clusterEdgeID string, clusterName string, hostname string, targetPowerState bool, cpus int, memory string, machineType model.MachineType) model.VirtualMachine { return model.VirtualMachine{ VirtualMachineID: virtualMachineID, Namespace: namespace, ClusterEdgeID: clusterEdgeID, ClusterName: clusterName, Hostname: hostname, TargetPowerState: targetPowerState, Cpus: cpus, Memory: memory, MachineType: machineType, } } func CreateVirtualMachineDiskModel(diskID string, virtualMachineID string, diskType model.DiskType, bus model.BusType, bootOrder int, size string, containerImageURL string) model.VirtualMachineDisk { return model.VirtualMachineDisk{ DiskID: diskID, VirtualMachineID: virtualMachineID, Type: diskType, Bus: bus, BootOrder: bootOrder, Size: size, ContainerImageURL: containerImageURL, } } // Validate a VirtualMachine func ValidateVirtualMachine(virtualMachine *model.VirtualMachine) error { if !virtualMachine.MachineType.IsValid() { return fmt.Errorf("invalid VirtualMachine machine type: %s", virtualMachine.MachineType.String()) } if !validateVirtualMachineMemory(virtualMachine.Memory) { return fmt.Errorf("invalid memory format (SI notation (K,M,G,T,P,E) and Binary notation (Ki,Mi,Gi,Ti,Pi,Ei) are accepted): %s", virtualMachine.Memory) } return nil } func validateVirtualMachineMemory(memory string) bool { _, err := resource.ParseQuantity(memory) // use kubernetes quantity parsing to check for valid memory string return err == nil } func ValidateVirtualMachineDisk(disk *model.VirtualMachineDisk) error { if !disk.Type.IsValid() { return fmt.Errorf("invalid VirtualMachineDisk disk type: %s", disk.Type.String()) } if !disk.Bus.IsValid() { return fmt.Errorf("invalid VirtualMachineDisk bus type: %s", disk.Bus.String()) } if !validateVirtualMachineContainerImageURL(disk.ContainerImageURL) { return fmt.Errorf("invalid container image url format: %s", disk.ContainerImageURL) } if !validateVirtualMachineMemory(disk.Size) { return fmt.Errorf("invalid size format (SI notation (K,M,G,T,P,E) and Binary notation (Ki,Mi,Gi,Ti,Pi,Ei) are accepted): %s", disk.Size) } return nil } func HasDuplicateDiskBootOrders(disks []*model.VirtualMachineDisk) bool { visited := make(map[int]bool, 0) for _, disk := range disks { bootOrder := disk.BootOrder if visited[bootOrder] { return true } visited[bootOrder] = true } return false } func validateVirtualMachineContainerImageURL(containerImageURL string) bool { if containerImageURL == "" { return true // can't validate something that's empty } const pattern = `^docker://us-east1-docker.pkg.dev/ret-edge-pltf-infra/workloads/([^:]+):([^:]+)$|^docker://us-east1-docker.pkg.dev/ret-edge-pltf-infra/thirdparty/quay.io/kubevirt/virtio-container-disk([^:]+):([^:]+)$` re := regexp.MustCompile(pattern) return re.MatchString(containerImageURL) } // Set the VirtualMachine values that aren't being updated to the current values in the db. func UpdateVirtualMachine(currentVM *model.VirtualMachine, updateVM *model.VirtualMachineIDInput) *model.VirtualMachine { currentVM.TargetPowerState = *AssignNotNil[bool](¤tVM.TargetPowerState, updateVM.VirtualMachineValues.TargetPowerState) currentVM.Memory = *AssignNotNil[string](¤tVM.Memory, updateVM.VirtualMachineValues.Memory) currentVM.MachineType = *AssignNotNil[model.MachineType](¤tVM.MachineType, updateVM.VirtualMachineValues.MachineType) currentVM.Cpus = *AssignNotNil[int](¤tVM.Cpus, updateVM.VirtualMachineValues.Cpus) return currentVM } func UpdateVirtualMachineDisk(currentDisk *model.VirtualMachineDisk, updateDisk *model.VirtualMachineDiskUpdateInput) *model.VirtualMachineDisk { currentDisk.Type = *AssignNotNil[model.DiskType](¤tDisk.Type, updateDisk.Type) currentDisk.Bus = *AssignNotNil[model.BusType](¤tDisk.Bus, updateDisk.Bus) currentDisk.BootOrder = *AssignNotNil[int](¤tDisk.BootOrder, updateDisk.BootOrder) currentDisk.Size = *AssignNotNil[string](¤tDisk.Size, updateDisk.Size) currentDisk.ContainerImageURL = *AssignNotNil[string](¤tDisk.ContainerImageURL, updateDisk.ContainerImageURL) return currentDisk } func AssignNotNil[T any](currentValue, newValue *T) *T { if newValue != nil { return newValue } return currentValue }