github.com/kotalco/kotal@v0.3.0/apis/shared/resources.go (about) 1 package shared 2 3 import ( 4 "fmt" 5 6 "k8s.io/apimachinery/pkg/api/resource" 7 "k8s.io/apimachinery/pkg/util/validation/field" 8 ) 9 10 // Resources is node compute and storage resources 11 // +k8s:deepcopy-gen=true 12 type Resources struct { 13 // CPU is cpu cores the node requires 14 // +kubebuilder:validation:Pattern="^[1-9][0-9]*m?$" 15 CPU string `json:"cpu,omitempty"` 16 // CPULimit is cpu cores the node is limited to 17 // +kubebuilder:validation:Pattern="^[1-9][0-9]*m?$" 18 CPULimit string `json:"cpuLimit,omitempty"` 19 // Memory is memmory requirements 20 // +kubebuilder:validation:Pattern="^[1-9][0-9]*[KMGTPE]i$" 21 Memory string `json:"memory,omitempty"` 22 // MemoryLimit is cpu cores the node is limited to 23 // +kubebuilder:validation:Pattern="^[1-9][0-9]*[KMGTPE]i$" 24 MemoryLimit string `json:"memoryLimit,omitempty"` 25 // Storage is disk space storage requirements 26 // +kubebuilder:validation:Pattern="^[1-9][0-9]*[KMGTPE]i$" 27 Storage string `json:"storage,omitempty"` 28 // StorageClass is the volume storage class 29 StorageClass *string `json:"storageClass,omitempty"` 30 } 31 32 // validate is the shared validation logic 33 func (r *Resources) validate() (errors field.ErrorList) { 34 cpu := r.CPU 35 cpuLimit := r.CPULimit 36 37 if cpu != cpuLimit { 38 // validate cpuLimit can't be less than cpu request 39 cpuQuantity := resource.MustParse(cpu) 40 cpuLimitQuantity := resource.MustParse(cpuLimit) 41 if cpuLimitQuantity.Cmp(cpuQuantity) == -1 { 42 msg := fmt.Sprintf("must be greater than or equal to cpu %s", string(cpu)) 43 err := field.Invalid(field.NewPath("spec").Child("resources").Child("cpuLimit"), cpuLimit, msg) 44 errors = append(errors, err) 45 } 46 } 47 48 memory := r.Memory 49 memoryLimit := r.MemoryLimit 50 memoryQuantity := resource.MustParse(memory) 51 memoryLimitQuantity := resource.MustParse(memoryLimit) 52 53 // validate memory limit must be greater than memory 54 if memoryLimitQuantity.Cmp(memoryQuantity) != 1 { 55 msg := fmt.Sprintf("must be greater than memory %s", string(memory)) 56 err := field.Invalid(field.NewPath("spec").Child("resources").Child("memoryLimit"), memoryLimit, msg) 57 errors = append(errors, err) 58 } 59 60 return 61 } 62 63 // ValidateCreate validates resources during creation 64 func (r *Resources) ValidateCreate() (errors field.ErrorList) { 65 errors = append(errors, r.validate()...) 66 return 67 } 68 69 // ValidateUpdate validates resources during update 70 func (r *Resources) ValidateUpdate(oldResources *Resources) (errors field.ErrorList) { 71 72 oldStorage := oldResources.Storage 73 oldStorageClass := oldResources.StorageClass 74 75 errors = append(errors, r.validate()...) 76 77 // requested storage can't be decreased 78 if oldStorage != r.Storage { 79 80 oldStorageQuantity := resource.MustParse(oldStorage) 81 newStorageQuantity := resource.MustParse(r.Storage) 82 83 if newStorageQuantity.Cmp(oldStorageQuantity) == -1 { 84 msg := fmt.Sprintf("must be greater than or equal to old storage %s", oldStorage) 85 err := field.Invalid(field.NewPath("spec").Child("resources").Child("storage"), r.Storage, msg) 86 errors = append(errors, err) 87 } 88 89 } 90 91 // storage class is immutable 92 if oldStorageClass != nil && r.StorageClass != nil && *oldStorageClass != *r.StorageClass { 93 msg := "field is immutable" 94 err := field.Invalid(field.NewPath("spec").Child("resources").Child("storageClass"), *r.StorageClass, msg) 95 errors = append(errors, err) 96 } 97 98 return 99 }