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 }