github.com/kubewharf/katalyst-core@v0.5.3/pkg/webhook/mutating/node/allocatable_mutator.go (about) 1 /* 2 Copyright 2022 The Katalyst Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package node 18 19 import ( 20 "fmt" 21 22 overcommitutil "github.com/kubewharf/katalyst-core/pkg/util/overcommit" 23 24 admissionv1beta1 "k8s.io/api/admission/v1beta1" 25 core "k8s.io/api/core/v1" 26 "k8s.io/apimachinery/pkg/api/resource" 27 "k8s.io/klog/v2" 28 29 "github.com/kubewharf/katalyst-api/pkg/consts" 30 "github.com/kubewharf/katalyst-core/pkg/util/native" 31 ) 32 33 const ( 34 nodeAllocatableMutatorName = "nodeAllocatableMutator" 35 ) 36 37 // WebhookNodeAllocatableMutator mutate node allocatable according to overcommit annotation 38 type WebhookNodeAllocatableMutator struct{} 39 40 func NewWebhookNodeAllocatableMutator() *WebhookNodeAllocatableMutator { 41 return &WebhookNodeAllocatableMutator{} 42 } 43 44 func (na *WebhookNodeAllocatableMutator) MutateNode(node *core.Node, admissionRequest *admissionv1beta1.AdmissionRequest) error { 45 if admissionv1beta1.Update != admissionRequest.Operation || admissionRequest.SubResource != "status" { 46 return nil 47 } 48 49 if node == nil { 50 err := fmt.Errorf("node is nil") 51 klog.Error(err) 52 return err 53 } 54 55 nodeAnnotations := node.Annotations 56 if nodeAnnotations == nil { 57 nodeAnnotations = make(map[string]string) 58 } 59 60 nodeAnnotations[consts.NodeAnnotationOriginalCapacityCPUKey] = node.Status.Capacity.Cpu().String() 61 nodeAnnotations[consts.NodeAnnotationOriginalCapacityMemoryKey] = node.Status.Capacity.Memory().String() 62 nodeAnnotations[consts.NodeAnnotationOriginalAllocatableCPUKey] = node.Status.Allocatable.Cpu().String() 63 nodeAnnotations[consts.NodeAnnotationOriginalAllocatableMemoryKey] = node.Status.Allocatable.Memory().String() 64 node.Annotations = nodeAnnotations 65 66 CPUOvercommitRatioValue, ok := node.Annotations[consts.NodeAnnotationCPUOvercommitRatioKey] 67 if ok { 68 var newAllocatable, newCapacity *resource.Quantity 69 // get overcommit allocatable and capacity from annotation first 70 overcommitCapacity, ok := node.Annotations[consts.NodeAnnotationOvercommitCapacityCPUKey] 71 if ok { 72 quantity, err := resource.ParseQuantity(overcommitCapacity) 73 if err != nil { 74 klog.Error(err) 75 } else { 76 newCapacity = &quantity 77 klog.V(6).Infof("node %s cpu capacity by annotation: %v", node.Name, newCapacity.String()) 78 } 79 } 80 81 overcommitAllocatable, ok := node.Annotations[consts.NodeAnnotationOvercommitAllocatableCPUKey] 82 if ok { 83 quantity, err := resource.ParseQuantity(overcommitAllocatable) 84 if err != nil { 85 klog.Error(err) 86 } else { 87 newAllocatable = &quantity 88 klog.V(6).Infof("node %s cpu allocatable by annotation: %v", node.Name, newAllocatable.String()) 89 } 90 } 91 92 // calculate allocatable and capacity by overcommit ratio 93 if newAllocatable == nil || newCapacity == nil { 94 CPUOvercommitRatio, err := cpuOvercommitRatioValidate(node.Annotations) 95 if err != nil { 96 klog.Errorf("node %s %s validate fail, value: %s, err: %v", node.Name, consts.NodeAnnotationCPUOvercommitRatioKey, CPUOvercommitRatioValue, err) 97 } else { 98 if CPUOvercommitRatio > 1.0 { 99 allocatable := node.Status.Allocatable.Cpu() 100 capacity := node.Status.Capacity.Cpu() 101 allocatableByOvercommit := native.MultiplyResourceQuantity(core.ResourceCPU, *allocatable, CPUOvercommitRatio) 102 capacityByOvercommit := native.MultiplyResourceQuantity(core.ResourceCPU, *capacity, CPUOvercommitRatio) 103 newAllocatable = &allocatableByOvercommit 104 newCapacity = &capacityByOvercommit 105 106 klog.V(6).Infof( 107 "node %s %s capacity: %v, allocatable: %v, newCapacity: %v, newAllocatable: %v", 108 node.Name, core.ResourceCPU, 109 capacity.String(), newCapacity.String(), 110 allocatable.String(), newAllocatable.String()) 111 } 112 } 113 } 114 115 if newAllocatable != nil && newCapacity != nil { 116 node.Status.Allocatable[core.ResourceCPU] = *newAllocatable 117 node.Status.Capacity[core.ResourceCPU] = *newCapacity 118 } 119 } 120 121 memoryOvercommitRatioValue, ok := node.Annotations[consts.NodeAnnotationMemoryOvercommitRatioKey] 122 if ok { 123 var newAllocatable, newCapacity *resource.Quantity 124 // get overcommit allocatable and capacity from annotation first 125 overcommitCapacity, ok := node.Annotations[consts.NodeAnnotationOvercommitCapacityMemoryKey] 126 if ok { 127 quantity, err := resource.ParseQuantity(overcommitCapacity) 128 if err != nil { 129 klog.Error(err) 130 } else { 131 newCapacity = &quantity 132 klog.V(6).Infof("node %s mem capacity by annotation: %v", node.Name, newCapacity.String()) 133 } 134 } 135 136 overcommitAllocatable, ok := node.Annotations[consts.NodeAnnotationOvercommitAllocatableMemoryKey] 137 if ok { 138 quantity, err := resource.ParseQuantity(overcommitAllocatable) 139 if err != nil { 140 klog.Error(err) 141 } else { 142 newAllocatable = &quantity 143 klog.V(6).Infof("node %s mem allocatable by annotation: %v", node.Name, newAllocatable.String()) 144 } 145 } 146 147 if newAllocatable == nil || newCapacity == nil { 148 memoryOvercommitRatio, err := memOvercommitRatioValidate(node.Annotations) 149 if err != nil { 150 klog.Errorf("node %s %s validate fail, value: %s, err: %v", node.Name, consts.NodeAnnotationMemoryOvercommitRatioKey, memoryOvercommitRatioValue, err) 151 } else { 152 if memoryOvercommitRatio > 1.0 { 153 allocatable := node.Status.Allocatable.Memory() 154 capacity := node.Status.Capacity.Memory() 155 allocatableByOvercommit := native.MultiplyResourceQuantity(core.ResourceMemory, *allocatable, memoryOvercommitRatio) 156 capacityByOvercommit := native.MultiplyResourceQuantity(core.ResourceMemory, *capacity, memoryOvercommitRatio) 157 newAllocatable = &allocatableByOvercommit 158 newCapacity = &capacityByOvercommit 159 klog.V(6).Infof("node %s %s capacity: %v, allocatable: %v, newCapacity: %v, newAllocatable: %v", 160 node.Name, core.ResourceMemory, 161 capacity.String(), newCapacity.String(), 162 allocatable.String(), newAllocatable.String()) 163 } 164 } 165 } 166 167 if newAllocatable != nil && newCapacity != nil { 168 node.Status.Allocatable[core.ResourceMemory] = *newAllocatable 169 node.Status.Capacity[core.ResourceMemory] = *newCapacity 170 } 171 } 172 173 return nil 174 } 175 176 func (na *WebhookNodeAllocatableMutator) Name() string { 177 return nodeAllocatableMutatorName 178 } 179 180 func cpuOvercommitRatioValidate(nodeAnnotation map[string]string) (float64, error) { 181 return overcommitutil.OvercommitRatioValidate( 182 nodeAnnotation, 183 consts.NodeAnnotationCPUOvercommitRatioKey, 184 consts.NodeAnnotationRealtimeCPUOvercommitRatioKey, 185 ) 186 } 187 188 func memOvercommitRatioValidate(nodeAnnotation map[string]string) (float64, error) { 189 return overcommitutil.OvercommitRatioValidate( 190 nodeAnnotation, 191 consts.NodeAnnotationMemoryOvercommitRatioKey, 192 consts.NodeAnnotationRealtimeMemoryOvercommitRatioKey, 193 ) 194 }