github.com/kubewharf/katalyst-core@v0.5.3/pkg/client/control/vparec.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 control 18 19 import ( 20 "context" 21 "encoding/json" 22 "fmt" 23 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 "k8s.io/apimachinery/pkg/types" 26 "k8s.io/apimachinery/pkg/util/jsonmergepatch" 27 "k8s.io/klog/v2" 28 29 apis "github.com/kubewharf/katalyst-api/pkg/apis/autoscaling/v1alpha1" 30 clientset "github.com/kubewharf/katalyst-api/pkg/client/clientset/versioned" 31 "github.com/kubewharf/katalyst-core/pkg/util/general" 32 ) 33 34 // VPARecommendationUpdater is used to update VPARecommendation CR 35 type VPARecommendationUpdater interface { 36 UpdateVPARecommendation(ctx context.Context, vpaRec *apis.VerticalPodAutoscalerRecommendation, 37 opts metav1.UpdateOptions) (*apis.VerticalPodAutoscalerRecommendation, error) 38 UpdateVPARecommendationStatus(ctx context.Context, vpaRec *apis.VerticalPodAutoscalerRecommendation, 39 opts metav1.UpdateOptions) (*apis.VerticalPodAutoscalerRecommendation, error) 40 41 PatchVPARecommendation(ctx context.Context, oldVpaRec, newVpaRec *apis.VerticalPodAutoscalerRecommendation) error 42 PatchVPARecommendationStatus(ctx context.Context, oldVpaRec, newVpaRec *apis.VerticalPodAutoscalerRecommendation) error 43 44 CreateVPARecommendation(ctx context.Context, vpaRec *apis.VerticalPodAutoscalerRecommendation, 45 opts metav1.CreateOptions) (*apis.VerticalPodAutoscalerRecommendation, error) 46 DeleteVPARecommendation(ctx context.Context, vpaRec *apis.VerticalPodAutoscalerRecommendation, opts metav1.DeleteOptions) error 47 } 48 49 type DummyVPARecommendationUpdater struct{} 50 51 func (d *DummyVPARecommendationUpdater) UpdateVPARecommendation(_ context.Context, _ *apis.VerticalPodAutoscalerRecommendation, _ metav1.UpdateOptions) (*apis.VerticalPodAutoscalerRecommendation, error) { 52 return nil, nil 53 } 54 55 func (d *DummyVPARecommendationUpdater) UpdateVPARecommendationStatus(_ context.Context, _ *apis.VerticalPodAutoscalerRecommendation, _ metav1.UpdateOptions) (*apis.VerticalPodAutoscalerRecommendation, error) { 56 return nil, nil 57 } 58 59 func (d *DummyVPARecommendationUpdater) PatchVPARecommendation(ctx context.Context, oldVparec, newVparec *apis.VerticalPodAutoscalerRecommendation) error { 60 return nil 61 } 62 63 func (d *DummyVPARecommendationUpdater) PatchVPARecommendationStatus(ctx context.Context, oldVparec, newVparec *apis.VerticalPodAutoscalerRecommendation) error { 64 return nil 65 } 66 67 func (d *DummyVPARecommendationUpdater) CreateVPARecommendation(_ context.Context, _ *apis.VerticalPodAutoscalerRecommendation, _ metav1.CreateOptions) (*apis.VerticalPodAutoscalerRecommendation, error) { 68 return nil, nil 69 } 70 71 func (d *DummyVPARecommendationUpdater) DeleteVPARecommendation(_ context.Context, _ *apis.VerticalPodAutoscalerRecommendation, _ metav1.DeleteOptions) error { 72 return nil 73 } 74 75 type RealVPARecommendationUpdater struct { 76 client clientset.Interface 77 } 78 79 func NewRealVPARecommendationUpdater(client clientset.Interface) *RealVPARecommendationUpdater { 80 return &RealVPARecommendationUpdater{ 81 client: client, 82 } 83 } 84 85 func (r *RealVPARecommendationUpdater) UpdateVPARecommendation(ctx context.Context, vpaRec *apis.VerticalPodAutoscalerRecommendation, opts metav1.UpdateOptions) (*apis.VerticalPodAutoscalerRecommendation, error) { 86 if vpaRec == nil { 87 return nil, fmt.Errorf("can't update a nil verticalPodAutoscalerRecommendation") 88 } 89 90 return r.client.AutoscalingV1alpha1().VerticalPodAutoscalerRecommendations(vpaRec.Namespace).Update(ctx, vpaRec, opts) 91 } 92 93 func (r *RealVPARecommendationUpdater) UpdateVPARecommendationStatus(ctx context.Context, vpaRec *apis.VerticalPodAutoscalerRecommendation, opts metav1.UpdateOptions) (*apis.VerticalPodAutoscalerRecommendation, error) { 94 if vpaRec == nil { 95 return nil, fmt.Errorf("can't update a nil verticalPodAutoscalerRecommendation's status") 96 } 97 98 return r.client.AutoscalingV1alpha1().VerticalPodAutoscalerRecommendations(vpaRec.Namespace).UpdateStatus(ctx, vpaRec, opts) 99 } 100 101 func (r *RealVPARecommendationUpdater) PatchVPARecommendation(ctx context.Context, oldVpaRec, newVpaRec *apis.VerticalPodAutoscalerRecommendation) error { 102 if oldVpaRec == nil || newVpaRec == nil { 103 return fmt.Errorf("can't update a nil VPARec") 104 } 105 106 oldData, err := json.Marshal(oldVpaRec) 107 if err != nil { 108 return err 109 } 110 111 newData, err := json.Marshal(newVpaRec) 112 if err != nil { 113 return err 114 } 115 patchBytes, err := jsonmergepatch.CreateThreeWayJSONMergePatch(oldData, newData, oldData) 116 117 if err != nil { 118 return fmt.Errorf("failed to create merge patch for VPARec %q/%q: %v", oldVpaRec.Namespace, oldVpaRec.Name, err) 119 } else if general.JsonPathEmpty(patchBytes) { 120 return nil 121 } 122 123 _, err = r.client.AutoscalingV1alpha1().VerticalPodAutoscalerRecommendations(oldVpaRec.Namespace).Patch(ctx, oldVpaRec.Name, types.MergePatchType, patchBytes, metav1.PatchOptions{}) 124 return err 125 } 126 127 func (r *RealVPARecommendationUpdater) PatchVPARecommendationStatus(ctx context.Context, oldVpaRec, newVpaRec *apis.VerticalPodAutoscalerRecommendation) error { 128 if oldVpaRec == nil || newVpaRec == nil { 129 return fmt.Errorf("can't update a nil VPARec") 130 } 131 132 oldData, err := json.Marshal(apis.VerticalPodAutoscalerRecommendation{Status: oldVpaRec.Status}) 133 if err != nil { 134 return err 135 } 136 137 newData, err := json.Marshal(apis.VerticalPodAutoscalerRecommendation{Status: newVpaRec.Status}) 138 if err != nil { 139 return err 140 } 141 142 if klog.V(5).Enabled() { 143 d, _ := json.Marshal(&oldVpaRec.Status) 144 dn, _ := json.Marshal(&newVpaRec.Status) 145 klog.Infof("vparec %s status updated: %v => %v", oldVpaRec.Name, string(d), string(dn)) 146 } 147 148 patchBytes, err := jsonmergepatch.CreateThreeWayJSONMergePatch(oldData, newData, oldData) 149 if err != nil { 150 return fmt.Errorf("failed to create merge patch for VPARec %q/%q: %v", oldVpaRec.Namespace, oldVpaRec.Name, err) 151 } else if general.JsonPathEmpty(patchBytes) { 152 return nil 153 } 154 155 _, err = r.client.AutoscalingV1alpha1().VerticalPodAutoscalerRecommendations(oldVpaRec.Namespace).Patch(ctx, oldVpaRec.Name, types.MergePatchType, patchBytes, metav1.PatchOptions{}, "status") 156 return err 157 } 158 159 func (r *RealVPARecommendationUpdater) CreateVPARecommendation(ctx context.Context, vpaRec *apis.VerticalPodAutoscalerRecommendation, 160 opts metav1.CreateOptions, 161 ) (*apis.VerticalPodAutoscalerRecommendation, error) { 162 return r.client.AutoscalingV1alpha1().VerticalPodAutoscalerRecommendations(vpaRec.Namespace).Create(ctx, vpaRec, opts) 163 } 164 165 func (r *RealVPARecommendationUpdater) DeleteVPARecommendation(ctx context.Context, vpaRec *apis.VerticalPodAutoscalerRecommendation, opts metav1.DeleteOptions) error { 166 return r.client.AutoscalingV1alpha1().VerticalPodAutoscalerRecommendations(vpaRec.Namespace).Delete(ctx, vpaRec.Name, opts) 167 } 168 169 // RealVPARecommendationUpdaterWithMetric todo: implement with emitting metrics on updating 170 type RealVPARecommendationUpdaterWithMetric struct { 171 client clientset.Interface 172 RealVPARecommendationUpdater 173 }