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  }