github.com/kubewharf/katalyst-core@v0.5.3/pkg/util/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 util
    18  
    19  import (
    20  	"fmt"
    21  
    22  	"github.com/pkg/errors"
    23  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    24  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    25  	"k8s.io/apimachinery/pkg/labels"
    26  	"k8s.io/client-go/tools/cache"
    27  	"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
    28  
    29  	apis "github.com/kubewharf/katalyst-api/pkg/apis/autoscaling/v1alpha1"
    30  	"github.com/kubewharf/katalyst-api/pkg/client/clientset/versioned/scheme"
    31  	autoscalelister "github.com/kubewharf/katalyst-api/pkg/client/listers/autoscaling/v1alpha1"
    32  	apiconsts "github.com/kubewharf/katalyst-api/pkg/consts"
    33  	"github.com/kubewharf/katalyst-core/pkg/consts"
    34  	"github.com/kubewharf/katalyst-core/pkg/util/native"
    35  )
    36  
    37  /*
    38   helper functions to get vpa-rec-related objects with indexed informer
    39  */
    40  
    41  // GetVPARecForVPA is used to get vpaRec that should be managed the given vpa
    42  func getVPARecFroVPAWithIndex(vpa *apis.KatalystVerticalPodAutoscaler, vpaRecIndexer cache.Indexer) (*apis.VerticalPodAutoscalerRecommendation, error) {
    43  	gvk, err := apiutil.GVKForObject(vpa, scheme.Scheme)
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  	ownerRef := metav1.OwnerReference{
    48  		Name:       vpa.GetName(),
    49  		Kind:       gvk.Kind,
    50  		APIVersion: gvk.GroupVersion().String(),
    51  		UID:        vpa.GetUID(),
    52  	}
    53  
    54  	objs, err := vpaRecIndexer.ByIndex(consts.OwnerReferenceIndex, native.GenerateObjectOwnerReferenceKey(ownerRef))
    55  	if err != nil {
    56  		return nil, errors.Wrapf(err, "vpaRec for vpa %s not exist", vpa.Name)
    57  	} else if len(objs) > 1 || len(objs) == 0 {
    58  		return nil, fmt.Errorf("vpaRec for vpa %s invalid", vpa.Name)
    59  	}
    60  
    61  	vpaRec, ok := objs[0].(*apis.VerticalPodAutoscalerRecommendation)
    62  	if !ok {
    63  		return nil, fmt.Errorf("invalid vpaRec")
    64  	}
    65  	return vpaRec, nil
    66  }
    67  
    68  /*
    69   helper functions to build indexed informer for vpa-rec-related objects
    70  */
    71  
    72  // GetVPAForVPARec is used to get vpa that should manage the given vpaRec
    73  func GetVPAForVPARec(vpaRec *apis.VerticalPodAutoscalerRecommendation,
    74  	vpaLister autoscalelister.KatalystVerticalPodAutoscalerLister,
    75  ) (*apis.KatalystVerticalPodAutoscaler, error) {
    76  	ownerReferences := vpaRec.GetOwnerReferences()
    77  	if len(ownerReferences) == 0 {
    78  		return nil, fmt.Errorf(" vpaRec %v has no owner", vpaRec.Name)
    79  	} else if len(ownerReferences) > 1 {
    80  		return nil, fmt.Errorf(" vpaRec %v has more than one owner", vpaRec.Name)
    81  	}
    82  
    83  	vpa, err := vpaLister.KatalystVerticalPodAutoscalers(vpaRec.Namespace).Get(ownerReferences[0].Name)
    84  	if err != nil {
    85  		return nil, fmt.Errorf("failed to get vpa %v : %v", ownerReferences[0].Name, err)
    86  	}
    87  
    88  	if !CheckVPARecommendationMatchVPA(vpaRec, vpa) {
    89  		return nil, fmt.Errorf("VPA UID mismatch, VPA %s may be deleted", vpa.Name)
    90  	}
    91  
    92  	return vpa, nil
    93  }
    94  
    95  // GetVPARecForVPA is used to get vpaRec that should be managed the given vpa
    96  func GetVPARecForVPA(vpa *apis.KatalystVerticalPodAutoscaler, vpaRecIndexer cache.Indexer,
    97  	recLister autoscalelister.VerticalPodAutoscalerRecommendationLister,
    98  ) (*apis.VerticalPodAutoscalerRecommendation, error) {
    99  	if recName, ok := vpa.GetAnnotations()[apiconsts.VPAAnnotationVPARecNameKey]; ok {
   100  		vpaRec, err := recLister.VerticalPodAutoscalerRecommendations(vpa.Namespace).Get(recName)
   101  		if err == nil && CheckVPARecommendationMatchVPA(vpaRec, vpa) {
   102  			return vpaRec, nil
   103  		}
   104  	}
   105  
   106  	if vpaRecIndexer != nil {
   107  		if vpaRec, err := getVPARecFroVPAWithIndex(vpa, vpaRecIndexer); err == nil {
   108  			return vpaRec, nil
   109  		}
   110  	}
   111  
   112  	recList, err := recLister.List(labels.Everything())
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  
   117  	for _, vpaRec := range recList {
   118  		if CheckVPARecommendationMatchVPA(vpaRec, vpa) {
   119  			return vpaRec, nil
   120  		}
   121  	}
   122  	return nil, apierrors.NewNotFound(apis.Resource(apis.ResourceNameVPARecommendation), "vparec for vpa")
   123  }