github.com/kubewharf/katalyst-core@v0.5.3/pkg/agent/resourcemanager/reporter/manager.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 reporter
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"sort"
    23  
    24  	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    25  	"k8s.io/apimachinery/pkg/util/errors"
    26  
    27  	"github.com/kubewharf/katalyst-api/pkg/protocol/reporterplugin/v1alpha1"
    28  	"github.com/kubewharf/katalyst-core/pkg/client"
    29  	"github.com/kubewharf/katalyst-core/pkg/config"
    30  	"github.com/kubewharf/katalyst-core/pkg/metaserver"
    31  	"github.com/kubewharf/katalyst-core/pkg/metrics"
    32  )
    33  
    34  // Manager indicates the way that resources are updated, and it
    35  // is also responsible for other
    36  type Manager interface {
    37  	// PushContents gets ReportField list from report manager, the reporter implementation
    38  	// should be responsible for assembling and updating the specific object.
    39  	PushContents(ctx context.Context, responses map[string]*v1alpha1.GetReportContentResponse) error
    40  
    41  	// Run starts all the updaters registered in this Manager.
    42  	Run(ctx context.Context)
    43  }
    44  
    45  type managerImpl struct {
    46  	conf *config.Configuration
    47  
    48  	// reporters are the map of gvk to reporter
    49  	reporters map[v1.GroupVersionKind]Reporter
    50  
    51  	// converters are the map of gvk to converter
    52  	// which is registered by RegisterConverterInitializer
    53  	converters map[v1.GroupVersionKind]Converter
    54  }
    55  
    56  // NewReporterManager is to create a reporter manager
    57  func NewReporterManager(genericClient *client.GenericClientSet, metaServer *metaserver.MetaServer,
    58  	emitter metrics.MetricEmitter, conf *config.Configuration,
    59  ) (Manager, error) {
    60  	r := &managerImpl{
    61  		reporters:  make(map[v1.GroupVersionKind]Reporter),
    62  		converters: make(map[v1.GroupVersionKind]Converter),
    63  		conf:       conf,
    64  	}
    65  
    66  	err := r.getReporter(genericClient, metaServer, emitter, conf, getRegisteredInitializers())
    67  	if err != nil {
    68  		return nil, err
    69  	}
    70  
    71  	err = r.getConverter(genericClient, metaServer, emitter, conf, getRegisteredConverterInitializers())
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  
    76  	return r, nil
    77  }
    78  
    79  func (r *managerImpl) PushContents(ctx context.Context, responses map[string]*v1alpha1.GetReportContentResponse) error {
    80  	var (
    81  		err     error
    82  		errList []error
    83  	)
    84  
    85  	// aggregate all plugin response by gvk
    86  	reportFieldsByGVK := aggregateReportFieldsByGVK(responses)
    87  
    88  	// convert report fields to expected version and kind if needed
    89  	reportFieldsByGVK, err = r.convertReportFieldsIfNeeded(ctx, reportFieldsByGVK)
    90  	if err != nil {
    91  		return fmt.Errorf("convert report fields failed: %v", err)
    92  	}
    93  
    94  	// it will update all fields by updater with same gvk
    95  	for gvk, fields := range reportFieldsByGVK {
    96  		u, ok := r.reporters[gvk]
    97  		if !ok || u == nil {
    98  			return fmt.Errorf("reporter of gvk %s not found", gvk)
    99  		}
   100  
   101  		sort.SliceStable(fields, func(i, j int) bool {
   102  			return fields[i].String() < fields[j].String()
   103  		})
   104  
   105  		err = u.Update(ctx, fields)
   106  		if err != nil {
   107  			errList = append(errList, fmt.Errorf("reporter %s report failed with error: %s", gvk, err))
   108  		}
   109  	}
   110  
   111  	return errors.NewAggregate(errList)
   112  }
   113  
   114  func (r *managerImpl) Run(ctx context.Context) {
   115  	for _, u := range r.reporters {
   116  		go u.Run(ctx)
   117  	}
   118  	<-ctx.Done()
   119  }
   120  
   121  func (r *managerImpl) getReporter(genericClient *client.GenericClientSet, metaServer *metaserver.MetaServer,
   122  	emitter metrics.MetricEmitter, conf *config.Configuration, initializers map[v1.GroupVersionKind]InitFunc,
   123  ) error {
   124  	var errList []error
   125  	for gvk, f := range initializers {
   126  		reporter, err := f(genericClient, metaServer, emitter, conf)
   127  		if err != nil {
   128  			errList = append(errList, err)
   129  			continue
   130  		}
   131  		r.reporters[gvk] = reporter
   132  	}
   133  
   134  	if len(errList) > 0 {
   135  		return errors.NewAggregate(errList)
   136  	}
   137  
   138  	return nil
   139  }
   140  
   141  func (r *managerImpl) getConverter(genericClient *client.GenericClientSet, server *metaserver.MetaServer,
   142  	emitter metrics.MetricEmitter, conf *config.Configuration, initializers map[v1.GroupVersionKind]ConverterInitFunc,
   143  ) error {
   144  	var errList []error
   145  	for gvk, f := range initializers {
   146  		converter, err := f(genericClient, server, emitter, conf)
   147  		if err != nil {
   148  			errList = append(errList, err)
   149  			continue
   150  		}
   151  		r.converters[gvk] = converter
   152  	}
   153  
   154  	if len(errList) > 0 {
   155  		return errors.NewAggregate(errList)
   156  	}
   157  
   158  	return nil
   159  }
   160  
   161  // convertReportFieldsIfNeeded converts all plugin's report fields to other gvk or other fields through
   162  // converter registered by RegisterConverterInitializer
   163  func (r *managerImpl) convertReportFieldsIfNeeded(ctx context.Context,
   164  	reportFieldsByGVK map[v1.GroupVersionKind][]*v1alpha1.ReportField,
   165  ) (map[v1.GroupVersionKind][]*v1alpha1.ReportField, error) {
   166  	var errList []error
   167  	convertedFieldsByGVK := make(map[v1.GroupVersionKind][]*v1alpha1.ReportField)
   168  	for gvk, fields := range reportFieldsByGVK {
   169  		c, ok := r.converters[gvk]
   170  		if ok && c != nil {
   171  			convertedContent, err := c.Convert(ctx, fields)
   172  			if err != nil {
   173  				errList = append(errList, err)
   174  				continue
   175  			}
   176  
   177  			if convertedContent.GroupVersionKind == nil {
   178  				continue
   179  			}
   180  
   181  			convertedFieldsByGVK[*convertedContent.GroupVersionKind] = append(convertedFieldsByGVK[*convertedContent.GroupVersionKind], convertedContent.Field...)
   182  		} else {
   183  			convertedFieldsByGVK[gvk] = append(convertedFieldsByGVK[gvk], fields...)
   184  		}
   185  	}
   186  
   187  	if len(errList) > 0 {
   188  		return nil, errors.NewAggregate(errList)
   189  	}
   190  
   191  	return convertedFieldsByGVK, nil
   192  }
   193  
   194  // aggregateReportFieldsByGVK aggregate all report field of plugins' response by its groupVersionKind
   195  // because different plugins may be responsible for one groupVersionKind.
   196  func aggregateReportFieldsByGVK(reportResponses map[string]*v1alpha1.GetReportContentResponse) map[v1.GroupVersionKind][]*v1alpha1.ReportField {
   197  	reportFields := make(map[v1.GroupVersionKind][]*v1alpha1.ReportField)
   198  	for name := range reportResponses {
   199  		response := reportResponses[name]
   200  		if response == nil {
   201  			continue
   202  		}
   203  
   204  		for _, c := range response.GetContent() {
   205  			if c == nil {
   206  				continue
   207  			}
   208  
   209  			gvk := c.GetGroupVersionKind()
   210  			if gvk == nil {
   211  				continue
   212  			}
   213  
   214  			if _, ok := reportFields[*gvk]; !ok {
   215  				reportFields[*gvk] = make([]*v1alpha1.ReportField, 0)
   216  			}
   217  
   218  			reportFields[*gvk] = append(reportFields[*gvk], c.GetField()...)
   219  		}
   220  	}
   221  
   222  	return reportFields
   223  }