github.com/kubewharf/katalyst-core@v0.5.3/pkg/controller/vpa/util/api.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  	"context"
    21  	"fmt"
    22  	"reflect"
    23  	"time"
    24  
    25  	core "k8s.io/api/core/v1"
    26  	apiequality "k8s.io/apimachinery/pkg/api/equality"
    27  	"k8s.io/apimachinery/pkg/api/meta"
    28  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    29  	"k8s.io/apimachinery/pkg/runtime"
    30  
    31  	apis "github.com/kubewharf/katalyst-api/pkg/apis/autoscaling/v1alpha1"
    32  	"github.com/kubewharf/katalyst-core/pkg/client/control"
    33  )
    34  
    35  const (
    36  	VPARecConditionReasonUpdated = "Updated"
    37  	VPARecConditionReasonIllegal = "Illegal"
    38  )
    39  
    40  const (
    41  	VPAConditionReasonUpdated           = "Updated"
    42  	VPAConditionReasonCalculatedIllegal = "Illegal"
    43  	VPAConditionReasonPodSpecUpdated    = "PodSpecUpdated"
    44  	VPAConditionReasonPodSpecNoUpdate   = "PodSpecNoUpdate"
    45  )
    46  
    47  // SetVPAConditions is used to set conditions for vpa in local vpa
    48  func SetVPAConditions(
    49  	vpa *apis.KatalystVerticalPodAutoscaler,
    50  	conditionType apis.VerticalPodAutoscalerConditionType,
    51  	conditionStatus core.ConditionStatus,
    52  	reason, message string,
    53  ) error {
    54  	if vpa == nil {
    55  		return fmt.Errorf("can't update condition of a nil vpa")
    56  	}
    57  	conditions := vpa.Status.Conditions
    58  
    59  	var conditionIndex int
    60  	for conditionIndex = 0; conditionIndex < len(conditions); conditionIndex++ {
    61  		if conditions[conditionIndex].Type == conditionType {
    62  			break
    63  		}
    64  	}
    65  	if conditionIndex == len(conditions) {
    66  		conditions = append(conditions, apis.VerticalPodAutoscalerCondition{
    67  			Type: conditionType,
    68  		})
    69  	}
    70  
    71  	condition := &conditions[conditionIndex]
    72  	if condition.Status != conditionStatus || condition.Message != message ||
    73  		condition.Reason != reason {
    74  		condition.LastTransitionTime = metav1.NewTime(time.Now())
    75  	}
    76  
    77  	condition.Status = conditionStatus
    78  	condition.Reason = reason
    79  	condition.Message = message
    80  	vpa.Status.Conditions = conditions
    81  	return nil
    82  }
    83  
    84  // SetVPARecConditions is used to set conditions for vpaRec in local vpa
    85  func SetVPARecConditions(
    86  	vpaRec *apis.VerticalPodAutoscalerRecommendation,
    87  	conditionType apis.VerticalPodAutoscalerRecommendationConditionType,
    88  	conditionStatus core.ConditionStatus,
    89  	reason, message string,
    90  ) error {
    91  	if vpaRec == nil {
    92  		return fmt.Errorf("can't update condition of a nil vpa")
    93  	}
    94  	conditions := vpaRec.Status.Conditions
    95  
    96  	var conditionIndex int
    97  	for conditionIndex = 0; conditionIndex < len(conditions); conditionIndex++ {
    98  		if conditions[conditionIndex].Type == conditionType {
    99  			break
   100  		}
   101  	}
   102  	if conditionIndex == len(conditions) {
   103  		conditions = append(conditions, apis.VerticalPodAutoscalerRecommendationCondition{
   104  			Type: conditionType,
   105  		})
   106  	}
   107  
   108  	condition := &conditions[conditionIndex]
   109  	if condition.Status != conditionStatus || condition.Message != message ||
   110  		condition.Reason != reason {
   111  		condition.LastTransitionTime = metav1.NewTime(time.Now())
   112  	}
   113  
   114  	condition.Status = conditionStatus
   115  	condition.Reason = reason
   116  	condition.Message = message
   117  	vpaRec.Status.Conditions = conditions
   118  	return nil
   119  }
   120  
   121  // PatchVPAConditions is used to update conditions for vpa to APIServer
   122  func PatchVPAConditions(
   123  	ctx context.Context,
   124  	vpaUpdater control.VPAUpdater,
   125  	vpa *apis.KatalystVerticalPodAutoscaler,
   126  	conditionType apis.VerticalPodAutoscalerConditionType,
   127  	conditionStatus core.ConditionStatus,
   128  	reason,
   129  	message string,
   130  ) error {
   131  	vpaNew := vpa.DeepCopy()
   132  	if err := SetVPAConditions(vpaNew, conditionType, conditionStatus, reason, message); err != nil {
   133  		return err
   134  	}
   135  
   136  	if apiequality.Semantic.DeepEqual(vpa.Status, vpaNew.Status) {
   137  		return nil
   138  	}
   139  
   140  	if _, err := vpaUpdater.PatchVPAStatus(ctx, vpa, vpaNew); err != nil {
   141  		return err
   142  	}
   143  
   144  	return nil
   145  }
   146  
   147  func UpdateVPAConditions(
   148  	ctx context.Context,
   149  	vpaUpdater control.VPAUpdater,
   150  	vpa *apis.KatalystVerticalPodAutoscaler,
   151  	conditionType apis.VerticalPodAutoscalerConditionType,
   152  	conditionStatus core.ConditionStatus,
   153  	reason,
   154  	message string,
   155  ) error {
   156  	vpaNew := vpa.DeepCopy()
   157  	if err := SetVPAConditions(vpaNew, conditionType, conditionStatus, reason, message); err != nil {
   158  		return err
   159  	}
   160  
   161  	if apiequality.Semantic.DeepEqual(vpa.Status, vpaNew.Status) {
   162  		return nil
   163  	}
   164  
   165  	if _, err := vpaUpdater.UpdateVPAStatus(ctx, vpaNew, metav1.UpdateOptions{}); err != nil {
   166  		return err
   167  	}
   168  
   169  	return nil
   170  }
   171  
   172  // PatchVPARecConditions is used to update conditions for vpaRec to APIServer
   173  func PatchVPARecConditions(
   174  	ctx context.Context,
   175  	vpaRecUpdater control.VPARecommendationUpdater,
   176  	vpaRec *apis.VerticalPodAutoscalerRecommendation,
   177  	conditionType apis.VerticalPodAutoscalerRecommendationConditionType,
   178  	conditionStatus core.ConditionStatus,
   179  	reason,
   180  	message string,
   181  ) error {
   182  	vpaRecCopy := vpaRec.DeepCopy()
   183  	if err := SetVPARecConditions(vpaRecCopy, conditionType, conditionStatus, reason, message); err != nil {
   184  		return err
   185  	}
   186  	if apiequality.Semantic.DeepEqual(vpaRec.Status, vpaRecCopy.Status) {
   187  		return nil
   188  	}
   189  
   190  	return vpaRecUpdater.PatchVPARecommendationStatus(ctx, vpaRec, vpaRecCopy)
   191  }
   192  
   193  // SetOwnerReferencesForVPA is used to parse from workload list, and set the
   194  // runtime information into OwnerReference fields for vpa CR
   195  func SetOwnerReferencesForVPA(vpa *apis.KatalystVerticalPodAutoscaler, workload runtime.Object) error {
   196  	metadata, err := meta.Accessor(workload)
   197  	if err != nil {
   198  		return err
   199  	}
   200  
   201  	ownerRef := metav1.OwnerReference{
   202  		Name:       metadata.GetName(),
   203  		Kind:       workload.GetObjectKind().GroupVersionKind().Kind,
   204  		APIVersion: workload.GetObjectKind().GroupVersionKind().GroupVersion().String(),
   205  		UID:        metadata.GetUID(),
   206  	}
   207  	for _, ow := range vpa.GetOwnerReferences() {
   208  		if reflect.DeepEqual(ow, ownerRef) {
   209  			return nil
   210  		}
   211  	}
   212  
   213  	vpa.OwnerReferences = append(vpa.OwnerReferences, ownerRef)
   214  	return nil
   215  }
   216  
   217  // DeleteOwnerReferencesForVPA is used to parse from workload list, and clean up the
   218  // runtime information from OwnerReference fields for vpa CR
   219  func DeleteOwnerReferencesForVPA(vpa *apis.KatalystVerticalPodAutoscaler, workload runtime.Object) error {
   220  	metadata, err := meta.Accessor(workload)
   221  	if err != nil {
   222  		return err
   223  	}
   224  
   225  	ownerRef := metav1.OwnerReference{
   226  		Name:       metadata.GetName(),
   227  		Kind:       workload.GetObjectKind().GroupVersionKind().Kind,
   228  		APIVersion: workload.GetObjectKind().GroupVersionKind().GroupVersion().String(),
   229  		UID:        metadata.GetUID(),
   230  	}
   231  
   232  	for i, ow := range vpa.GetOwnerReferences() {
   233  		if reflect.DeepEqual(ow, ownerRef) {
   234  			vpa.OwnerReferences = append(vpa.OwnerReferences[:i], vpa.OwnerReferences[i+1:]...)
   235  			return nil
   236  		}
   237  	}
   238  
   239  	return nil
   240  }