github.com/kubewharf/katalyst-core@v0.5.3/pkg/webhook/mutating/node/node.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 "context" 21 "fmt" 22 "time" 23 24 kubewebhook "github.com/slok/kubewebhook/pkg/webhook" 25 whcontext "github.com/slok/kubewebhook/pkg/webhook/context" 26 "github.com/slok/kubewebhook/pkg/webhook/mutating" 27 admissionv1beta1 "k8s.io/api/admission/v1beta1" 28 core "k8s.io/api/core/v1" 29 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 30 "k8s.io/klog/v2" 31 32 katalystbase "github.com/kubewharf/katalyst-core/cmd/base" 33 webhookconsts "github.com/kubewharf/katalyst-core/cmd/katalyst-webhook/app/webhook" 34 "github.com/kubewharf/katalyst-core/pkg/config/generic" 35 webhookconfig "github.com/kubewharf/katalyst-core/pkg/config/webhook" 36 "github.com/kubewharf/katalyst-core/pkg/metrics" 37 ) 38 39 type WebhookNodeMutator interface { 40 MutateNode(node *core.Node, admissionRequest *admissionv1beta1.AdmissionRequest) error 41 Name() string 42 } 43 44 // WebhookNode is the implementation of Kubernetes Webhook 45 // any implementation should at least implement the interface of mutating.Mutator of validating.Validator 46 type WebhookNode struct { 47 ctx context.Context 48 49 metricEmitter metrics.MetricEmitter 50 51 mutators []WebhookNodeMutator 52 } 53 54 func NewWebhookNode( 55 ctx context.Context, 56 webhookCtx *katalystbase.GenericContext, 57 _ *generic.GenericConfiguration, 58 _ *webhookconfig.GenericWebhookConfiguration, 59 _ *webhookconfig.WebhooksConfiguration, 60 ) (kubewebhook.Webhook, webhookconsts.GenericStartFunc, error) { 61 metricEmitter := webhookCtx.EmitterPool.GetDefaultMetricsEmitter() 62 if metricEmitter == nil { 63 metricEmitter = metrics.DummyMetrics{} 64 } 65 66 wn := &WebhookNode{ 67 ctx: ctx, 68 metricEmitter: metricEmitter, 69 mutators: []WebhookNodeMutator{}, 70 } 71 72 wn.mutators = append( 73 wn.mutators, 74 NewWebhookNodeAllocatableMutator(), 75 ) 76 77 cfg := mutating.WebhookConfig{ 78 Name: "nodeMutator", 79 Obj: &core.Node{}, 80 } 81 webhook, err := mutating.NewWebhook(cfg, wn, nil, nil, nil) 82 if err != nil { 83 return nil, nil, err 84 } 85 86 return webhook, wn.Run, nil 87 } 88 89 func (wn *WebhookNode) Run() bool { 90 klog.Infof("node webhook run") 91 92 return true 93 } 94 95 func (wn *WebhookNode) Mutate(ctx context.Context, obj metav1.Object) (bool, error) { 96 klog.V(5).Info("webhookNode notice an obj to be mutated") 97 98 node, ok := obj.(*core.Node) 99 if !ok { 100 err := fmt.Errorf("failed to convert obj to node: %v", obj) 101 klog.Error(err) 102 return false, err 103 } 104 if node == nil { 105 err := fmt.Errorf("node can't be nil") 106 klog.Error(err) 107 return false, err 108 } 109 110 admissionRequest := whcontext.GetAdmissionRequest(ctx) 111 if admissionRequest == nil { 112 err := fmt.Errorf("failed to get admission request from ctx") 113 klog.Error(err) 114 return false, err 115 } 116 117 klog.V(5).Infof("begin to mutate node %s", node.Name) 118 for _, mutator := range wn.mutators { 119 start := time.Now() 120 err := mutator.MutateNode(node, admissionRequest) 121 if err != nil { 122 klog.Errorf("failed to mutate node %s: %v", node.Name, err) 123 wn.emitMetrics(false, start, mutator) 124 return false, err 125 } 126 wn.emitMetrics(true, start, mutator) 127 } 128 klog.Infof("node %s was mutated", node.Name) 129 return true, nil 130 } 131 132 func (wn *WebhookNode) emitMetrics(success bool, start time.Time, mutator WebhookNodeMutator) { 133 _ = wn.metricEmitter.StoreInt64("node_mutator_request_total", 1, metrics.MetricTypeNameCount, metrics.MetricTag{Key: "type", Val: mutator.Name()}) 134 _ = wn.metricEmitter.StoreFloat64("node_mutator_latency", time.Since(start).Seconds(), metrics.MetricTypeNameCount, metrics.MetricTag{Key: "type", Val: mutator.Name()}) 135 if !success { 136 _ = wn.metricEmitter.StoreInt64("node_mutator_request_fail", 1, metrics.MetricTypeNameCount, metrics.MetricTag{Key: "type", Val: mutator.Name()}) 137 } 138 }