github.com/kubewharf/katalyst-core@v0.5.3/pkg/controller/spd/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 spd
    18  
    19  import (
    20  	"time"
    21  
    22  	apiequality "k8s.io/apimachinery/pkg/api/equality"
    23  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    24  	"k8s.io/apimachinery/pkg/types"
    25  	"k8s.io/client-go/util/retry"
    26  	"k8s.io/klog/v2"
    27  
    28  	apiworkload "github.com/kubewharf/katalyst-api/pkg/apis/workload/v1alpha1"
    29  	"github.com/kubewharf/katalyst-core/pkg/metrics"
    30  	"github.com/kubewharf/katalyst-core/pkg/util"
    31  )
    32  
    33  const (
    34  	metricsNameSyncIndicatorSpec         = "sync_indicator_spec"
    35  	metricsNameSyncIndicatorStatus       = "sync_indicator_status"
    36  	metricsNameSyncIndicatorSpecCost     = "sync_indicator_spec_cost"
    37  	metricsNameSyncIndicatorStatusCost   = "sync_indicator_status_cost"
    38  	metricsNameIndicatorSpecChanLength   = "indicator_spec_chan_length"
    39  	metricsNameIndicatorStatusChanLength = "indicator_status_chan_length"
    40  )
    41  
    42  func (sc *SPDController) syncIndicatorSpec() {
    43  	c := sc.indicatorManager.GetIndicatorSpecChan()
    44  	for {
    45  		select {
    46  		case nn, ok := <-c:
    47  			if !ok {
    48  				klog.Infof("[syncIndicatorSpec] indicator spec chan is closed")
    49  				return
    50  			}
    51  
    52  			sc.syncSpec(nn)
    53  			_ = sc.metricsEmitter.StoreInt64(metricsNameIndicatorSpecChanLength, int64(len(c)), metrics.MetricTypeNameRaw)
    54  		case <-sc.ctx.Done():
    55  			klog.Infoln("[syncIndicatorSpec] stop spd vpa queue worker.")
    56  			return
    57  		}
    58  	}
    59  }
    60  
    61  func (sc *SPDController) syncSpec(nn types.NamespacedName) {
    62  	begin := time.Now()
    63  	defer func() {
    64  		costs := time.Since(begin)
    65  		klog.V(5).Infof("[spd] finished syncing indicator spec %q (%v)", nn, costs)
    66  		_ = sc.metricsEmitter.StoreInt64(metricsNameSyncIndicatorSpecCost, costs.Microseconds(),
    67  			metrics.MetricTypeNameRaw, metrics.MetricTag{Key: "name", Val: nn.String()})
    68  	}()
    69  
    70  	klog.V(5).Infof("[syncIndicatorSpec] get %v", nn.String())
    71  
    72  	spec := sc.indicatorManager.GetIndicatorSpec(nn)
    73  	if spec == nil {
    74  		klog.Warningf("[syncIndicatorSpec] spd %v is nil", nn.String())
    75  		return
    76  	}
    77  
    78  	err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
    79  		spd, err := sc.spdLister.ServiceProfileDescriptors(nn.Namespace).Get(nn.Name)
    80  		if err != nil {
    81  			klog.Errorf("[syncIndicatorSpec] failed to get spd [%v], err: %v", nn.String(), err)
    82  			return err
    83  		}
    84  
    85  		spdCopy := spd.DeepCopy()
    86  		sc.mergeIndicatorSpec(spdCopy, *spec)
    87  		if apiequality.Semantic.DeepEqual(spd.Spec, spdCopy.Spec) {
    88  			return nil
    89  		}
    90  
    91  		if _, err := sc.spdControl.UpdateSPD(sc.ctx, spdCopy, metav1.UpdateOptions{}); err != nil {
    92  			klog.Errorf("[syncIndicatorSpec] failed to update spd for %s: %v", nn.String(), err)
    93  			return err
    94  		}
    95  
    96  		_ = sc.metricsEmitter.StoreInt64(metricsNameSyncIndicatorSpec, 1, metrics.MetricTypeNameCount, metrics.MetricTag{
    97  			Key: "status", Val: "success",
    98  		})
    99  
   100  		klog.V(4).Infof("[syncIndicatorSpec] successfully updated spd %s to %+v", nn.String(), spdCopy.Spec)
   101  		return nil
   102  	})
   103  	if err != nil {
   104  		// todo if failed to get spd, re-enqueue to update next time
   105  		klog.Errorf("[syncIndicatorSpec] failed to retry on conflict update spd for %s: %v", nn.String(), err)
   106  		_ = sc.metricsEmitter.StoreInt64(metricsNameSyncIndicatorSpec, 1, metrics.MetricTypeNameCount, metrics.MetricTag{
   107  			Key: "status", Val: "failed",
   108  		})
   109  	}
   110  }
   111  
   112  func (sc *SPDController) syncIndicatorStatus() {
   113  	c := sc.indicatorManager.GetIndicatorStatusChan()
   114  	for {
   115  		select {
   116  		case nn, ok := <-c:
   117  			if !ok {
   118  				klog.Infof("[syncIndicatorStatus] indicator status chan is closed")
   119  				return
   120  			}
   121  
   122  			sc.syncStatus(nn)
   123  			_ = sc.metricsEmitter.StoreInt64(metricsNameIndicatorStatusChanLength, int64(len(c)), metrics.MetricTypeNameRaw)
   124  		case <-sc.ctx.Done():
   125  			klog.Infoln("[syncIndicatorStatus] stop spd vpa status queue worker.")
   126  			return
   127  		}
   128  	}
   129  }
   130  
   131  func (sc *SPDController) syncStatus(nn types.NamespacedName) {
   132  	begin := time.Now()
   133  	defer func() {
   134  		costs := time.Since(begin)
   135  		klog.V(5).Infof("[spd] finished syncing indicator status %q (%v)", nn, costs)
   136  		_ = sc.metricsEmitter.StoreInt64(metricsNameSyncIndicatorStatusCost, costs.Microseconds(),
   137  			metrics.MetricTypeNameRaw, metrics.MetricTag{Key: "name", Val: nn.String()})
   138  	}()
   139  
   140  	klog.V(5).Infof("[syncIndicatorStatus] get %v", nn.String())
   141  
   142  	status := sc.indicatorManager.GetIndicatorStatus(nn)
   143  	if status == nil {
   144  		klog.Warningf("[syncIndicatorStatus] spd status %v is nil", nn.String())
   145  		return
   146  	}
   147  
   148  	err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
   149  		spd, err := sc.spdLister.ServiceProfileDescriptors(nn.Namespace).Get(nn.Name)
   150  		if err != nil {
   151  			klog.Errorf("[syncIndicatorStatus] failed to get spd [%v], err: %v", nn.String(), err)
   152  			return err
   153  		}
   154  
   155  		spdCopy := spd.DeepCopy()
   156  		sc.mergeIndicatorStatus(spdCopy, *status)
   157  		if apiequality.Semantic.DeepEqual(spd.Status, spdCopy.Status) {
   158  			return nil
   159  		}
   160  
   161  		if _, err := sc.spdControl.UpdateSPDStatus(sc.ctx, spdCopy, metav1.UpdateOptions{}); err != nil {
   162  			klog.Errorf("[syncIndicatorStatus] failed to update spd status for %s: %v", nn.String(), err)
   163  			return err
   164  		}
   165  
   166  		_ = sc.metricsEmitter.StoreInt64(metricsNameSyncIndicatorStatus, 1, metrics.MetricTypeNameCount, metrics.MetricTag{
   167  			Key: "status", Val: "success",
   168  		})
   169  
   170  		klog.V(4).Infof("[syncIndicatorStatus] successfully updated spd status %s to %+v", nn.String(), spdCopy.Status)
   171  		return nil
   172  	})
   173  	if err != nil {
   174  		// todo if failed to get spd, re-enqueue to update next time
   175  		klog.Errorf("[syncIndicatorStatus] failed to retry on conflict update spd status for %s: %v", nn.String(), err)
   176  		_ = sc.metricsEmitter.StoreInt64(metricsNameSyncIndicatorStatus, 1, metrics.MetricTypeNameCount, metrics.MetricTag{
   177  			Key: "status", Val: "failed",
   178  		})
   179  	}
   180  }
   181  
   182  func (sc *SPDController) mergeIndicatorSpec(spd *apiworkload.ServiceProfileDescriptor, expected apiworkload.ServiceProfileDescriptorSpec) {
   183  	for _, indicator := range expected.BusinessIndicator {
   184  		util.InsertSPDBusinessIndicatorSpec(&spd.Spec, &indicator)
   185  	}
   186  	for _, indicator := range expected.SystemIndicator {
   187  		util.InsertSPDSystemIndicatorSpec(&spd.Spec, &indicator)
   188  	}
   189  	for _, indicator := range expected.ExtendedIndicator {
   190  		util.InsertSPDExtendedIndicatorSpec(&spd.Spec, &indicator)
   191  	}
   192  
   193  	for i := 0; i < len(spd.Spec.BusinessIndicator); i++ {
   194  		if _, ok := sc.indicatorsSpecBusiness[spd.Spec.BusinessIndicator[i].Name]; !ok {
   195  			klog.Infof("skip spec business %v for spd %v", spd.Spec.BusinessIndicator[i].Name, spd.Name)
   196  			spd.Spec.BusinessIndicator = append(spd.Spec.BusinessIndicator[:i], spd.Spec.BusinessIndicator[i+1:]...)
   197  		}
   198  	}
   199  
   200  	for i := 0; i < len(spd.Spec.SystemIndicator); i++ {
   201  		if _, ok := sc.indicatorsSpecSystem[spd.Spec.SystemIndicator[i].Name]; !ok {
   202  			klog.Infof("skip spec system %v for spd %v", spd.Spec.SystemIndicator[i].Name, spd.Name)
   203  			spd.Spec.SystemIndicator = append(spd.Spec.SystemIndicator[:i], spd.Spec.SystemIndicator[i+1:]...)
   204  		}
   205  	}
   206  
   207  	for i := 0; i < len(spd.Spec.ExtendedIndicator); i++ {
   208  		if _, ok := sc.indicatorsSpecExtended[spd.Spec.ExtendedIndicator[i].Name]; !ok {
   209  			klog.Infof("skip spec extended %v for spd %v", spd.Spec.ExtendedIndicator[i].Name, spd.Name)
   210  			spd.Spec.ExtendedIndicator = append(spd.Spec.ExtendedIndicator[:i], spd.Spec.ExtendedIndicator[i+1:]...)
   211  		}
   212  	}
   213  }
   214  
   215  func (sc *SPDController) mergeIndicatorStatus(spd *apiworkload.ServiceProfileDescriptor, expected apiworkload.ServiceProfileDescriptorStatus) {
   216  	for _, indicator := range expected.BusinessStatus {
   217  		util.InsertSPDBusinessIndicatorStatus(&spd.Status, &indicator)
   218  	}
   219  
   220  	for i := 0; i < len(spd.Status.BusinessStatus); i++ {
   221  		if _, ok := sc.indicatorsStatusBusiness[spd.Status.BusinessStatus[i].Name]; !ok {
   222  			klog.Infof("skip status business %v for spd %v", spd.Status.BusinessStatus[i].Name, spd.Name)
   223  			spd.Status.BusinessStatus = append(spd.Status.BusinessStatus[:i], spd.Status.BusinessStatus[i+1:]...)
   224  		}
   225  	}
   226  }