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 }