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  }