github.com/kubewharf/katalyst-core@v0.5.3/pkg/util/spd_indicator.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  	"k8s.io/apimachinery/pkg/util/errors"
    23  	"k8s.io/utils/pointer"
    24  
    25  	workloadapis "github.com/kubewharf/katalyst-api/pkg/apis/workload/v1alpha1"
    26  )
    27  
    28  type IndicatorTarget struct {
    29  	UpperBound *float64
    30  	LowerBound *float64
    31  }
    32  
    33  // GetServiceBusinessIndicatorTarget get service business indicator target from spd
    34  // if there are duplicate upper bound or lower bound, return error
    35  func GetServiceBusinessIndicatorTarget(spd *workloadapis.ServiceProfileDescriptor) (map[string]IndicatorTarget, error) {
    36  	var errList []error
    37  	indicators := make(map[string]IndicatorTarget)
    38  	for _, indicator := range spd.Spec.BusinessIndicator {
    39  		_, ok := indicators[string(indicator.Name)]
    40  		if ok {
    41  			errList = append(errList, fmt.Errorf("duplicate indicator %s", indicator.Name))
    42  			continue
    43  		}
    44  
    45  		targetIndicator, err := getIndicatorTarget(indicator.Indicators)
    46  		if err != nil {
    47  			errList = append(errList, fmt.Errorf("get indicator %s failed: %v", indicator.Name, err))
    48  		}
    49  
    50  		indicators[string(indicator.Name)] = *targetIndicator
    51  	}
    52  
    53  	if len(errList) > 0 {
    54  		return nil, fmt.Errorf("failed to get service business indicators: %v", errors.NewAggregate(errList))
    55  	}
    56  
    57  	return indicators, nil
    58  }
    59  
    60  // GetServiceSystemIndicatorTarget get service system indicator target from spd
    61  // if there are duplicate upper bound or lower bound, return error
    62  func GetServiceSystemIndicatorTarget(spd *workloadapis.ServiceProfileDescriptor) (map[string]IndicatorTarget, error) {
    63  	var errList []error
    64  	indicators := make(map[string]IndicatorTarget)
    65  	for _, indicator := range spd.Spec.SystemIndicator {
    66  		_, ok := indicators[string(indicator.Name)]
    67  		if ok {
    68  			errList = append(errList, fmt.Errorf("duplicate indicator %s", indicator.Name))
    69  			continue
    70  		}
    71  
    72  		targetIndicator, err := getIndicatorTarget(indicator.Indicators)
    73  		if err != nil {
    74  			errList = append(errList, fmt.Errorf("get indicator %s failed: %v", indicator.Name, err))
    75  		}
    76  
    77  		indicators[string(indicator.Name)] = *targetIndicator
    78  	}
    79  
    80  	if len(errList) > 0 {
    81  		return nil, fmt.Errorf("failed to get service system indicators: %v", errors.NewAggregate(errList))
    82  	}
    83  
    84  	return indicators, nil
    85  }
    86  
    87  // GetServiceBusinessIndicatorValue returns the current value of business indicators
    88  // The returned map is a map from indicator name to its current value, and if duplicate
    89  // indicators are found, the first one is used
    90  func GetServiceBusinessIndicatorValue(spd *workloadapis.ServiceProfileDescriptor) (map[string]float64, error) {
    91  	indicatorValues := make(map[string]float64)
    92  	for _, indicator := range spd.Status.BusinessStatus {
    93  		if indicator.Current == nil {
    94  			continue
    95  		}
    96  
    97  		_, ok := indicatorValues[string(indicator.Name)]
    98  		if ok {
    99  			continue
   100  		}
   101  
   102  		indicatorValues[string(indicator.Name)] = float64(*indicator.Current)
   103  	}
   104  
   105  	return indicatorValues, nil
   106  }
   107  
   108  func getIndicatorTarget(indicators []workloadapis.Indicator) (*IndicatorTarget, error) {
   109  	targetIndicator := &IndicatorTarget{}
   110  	for _, target := range indicators {
   111  		switch target.IndicatorLevel {
   112  		case workloadapis.IndicatorLevelUpperBound:
   113  			if targetIndicator.UpperBound != nil {
   114  				return nil, fmt.Errorf("duplicate upper bound for indicator")
   115  			}
   116  			targetIndicator.UpperBound = pointer.Float64(float64(target.Value))
   117  		case workloadapis.IndicatorLevelLowerBound:
   118  			if targetIndicator.LowerBound != nil {
   119  				return nil, fmt.Errorf("duplicate lower bound for indicator")
   120  			}
   121  			targetIndicator.LowerBound = pointer.Float64(float64(target.Value))
   122  		default:
   123  			return nil, fmt.Errorf("invalid indicator level %s", target.IndicatorLevel)
   124  		}
   125  	}
   126  
   127  	// check whether target indicator is validated
   128  	if targetIndicator.LowerBound != nil && targetIndicator.UpperBound != nil &&
   129  		*targetIndicator.LowerBound > *targetIndicator.UpperBound {
   130  		return nil, fmt.Errorf("lower bound %v is higher than uppoer bound %v for indicator",
   131  			*targetIndicator.LowerBound, *targetIndicator.UpperBound)
   132  	}
   133  
   134  	return targetIndicator, nil
   135  }