github.com/galamsiva2020/kubernetes-heapster-monitoring@v0.0.0-20210823134957-3c1baa7c1e70/metrics/sinks/hawkular/driver.go (about) 1 // Copyright 2015 Google Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package hawkular 16 17 import ( 18 "crypto/tls" 19 "crypto/x509" 20 "fmt" 21 "io/ioutil" 22 "net/http" 23 "net/url" 24 "strconv" 25 "sync" 26 27 "github.com/golang/glog" 28 "github.com/hawkular/hawkular-client-go/metrics" 29 30 kube_client "k8s.io/client-go/rest" 31 kubeClientCmd "k8s.io/client-go/tools/clientcmd" 32 "k8s.io/heapster/metrics/core" 33 ) 34 35 const ( 36 unitsTag = "units" 37 descriptionTag = "_description" 38 descriptorTag = "descriptor_name" 39 groupTag = "group_id" 40 separator = "/" 41 batchSizeDefault = 1000 42 concurrencyDefault = 5 43 44 nodeId string = "labelNodeId" 45 46 labelTagPrefixOpts = "labelTagPrefix" 47 labelTagPrefixDefault = "labels." 48 49 defaultServiceAccountFile = "/var/run/secrets/kubernetes.io/serviceaccount/token" 50 ) 51 52 // START: ExternalSink interface implementations 53 54 func (h *hawkularSink) Register(mds []core.MetricDescriptor) error { 55 // Create model definitions based on the MetricDescriptors 56 for _, md := range mds { 57 hmd := h.descriptorToDefinition(&md) 58 h.models[md.Name] = &hmd 59 } 60 61 if !h.disablePreCaching { 62 // Fetch currently known metrics from Hawkular-Metrics and cache them 63 err := h.cacheDefinitions() 64 if err != nil { 65 return err 66 } 67 } 68 69 return nil 70 } 71 72 func (h *hawkularSink) Stop() { 73 h.regLock.Lock() 74 defer h.regLock.Unlock() 75 h.init() 76 } 77 78 func (h *hawkularSink) ExportData(db *core.DataBatch) { 79 totalCount := 0 80 h.runId++ 81 for _, ms := range db.MetricSets { 82 totalCount += len(ms.MetricValues) 83 totalCount += len(ms.LabeledMetrics) 84 } 85 86 if len(db.MetricSets) > 0 { 87 tmhs := make(map[string][]metrics.MetricHeader) 88 89 if len(h.labelTenant) == 0 { 90 tmhs[h.client.Tenant] = make([]metrics.MetricHeader, 0, totalCount) 91 } 92 93 wg := &sync.WaitGroup{} 94 95 for _, ms := range db.MetricSets { 96 97 // Transform ms.MetricValues to LabeledMetrics first 98 mvlms := metricValueToLabeledMetric(ms.MetricValues) 99 lms := make([]core.LabeledMetric, 0, len(mvlms)+len(ms.LabeledMetrics)) 100 101 lms = append(lms, mvlms...) 102 lms = append(lms, ms.LabeledMetrics...) 103 104 Store: 105 for _, labeledMetric := range lms { 106 107 for _, filter := range h.filters { 108 if !filter(ms, labeledMetric.Name) { 109 continue Store 110 } 111 } 112 113 tenant := h.client.Tenant 114 115 if len(h.labelTenant) > 0 { 116 if v, found := ms.Labels[h.labelTenant]; found { 117 tenant = v 118 } 119 } 120 121 h.registerLabeledIfNecessaryInline(ms, labeledMetric, wg, metrics.Tenant(tenant)) 122 mH, err := h.pointToLabeledMetricHeader(ms, labeledMetric, db.Timestamp) 123 if err != nil { 124 // One transformation error should not prevent the whole process 125 glog.Errorf(err.Error()) 126 continue 127 } 128 129 if _, found := tmhs[tenant]; !found { 130 tmhs[tenant] = make([]metrics.MetricHeader, 0) 131 } 132 133 tmhs[tenant] = append(tmhs[tenant], *mH) 134 } 135 } 136 h.sendData(tmhs, wg) // Send to a limited channel? Only batches.. egg. 137 wg.Wait() 138 // glog.V(4).Infof("ExportData updated %d tags, total size of cached tags is %d\n", updatedTags, len(h.reg)) 139 } 140 h.expireCache(h.runId) 141 } 142 143 func metricValueToLabeledMetric(msValues map[string]core.MetricValue) []core.LabeledMetric { 144 lms := make([]core.LabeledMetric, 0, len(msValues)) 145 for metricName, metricValue := range msValues { 146 lm := core.LabeledMetric{ 147 Name: metricName, 148 MetricValue: metricValue, 149 Labels: make(map[string]string, 0), 150 } 151 lms = append(lms, lm) 152 } 153 return lms 154 } 155 156 func (h *hawkularSink) DebugInfo() string { 157 info := fmt.Sprintf("%s\n", h.Name()) 158 159 h.regLock.Lock() 160 defer h.regLock.Unlock() 161 info += fmt.Sprintf("Cached metrics: %d\n", len(h.expReg)) 162 if len(h.labelTenant) > 0 { 163 info += fmt.Sprintf("Using label '%s' as tenant information\n", h.labelTenant) 164 } 165 if len(h.labelNodeId) > 0 { 166 info += fmt.Sprintf("Using label '%s' as node identified in resourceid\n", h.labelNodeId) 167 } 168 169 // TODO Add here statistics from the Hawkular-Metrics client instance 170 return info 171 } 172 173 func (h *hawkularSink) Name() string { 174 return "Hawkular-Metrics Sink" 175 } 176 177 // NewHawkularSink Creates and returns a new hawkularSink instance 178 func NewHawkularSink(u *url.URL) (core.DataSink, error) { 179 sink := &hawkularSink{ 180 uri: u, 181 batchSize: 1000, 182 } 183 if err := sink.init(); err != nil { 184 return nil, err 185 } 186 187 metrics := make([]core.MetricDescriptor, 0, len(core.AllMetrics)) 188 for _, metric := range core.AllMetrics { 189 metrics = append(metrics, metric.MetricDescriptor) 190 } 191 sink.Register(metrics) 192 return sink, nil 193 } 194 195 func (h *hawkularSink) init() error { 196 h.models = make(map[string]*metrics.MetricDefinition) 197 h.modifiers = make([]metrics.Modifier, 0) 198 h.filters = make([]Filter, 0) 199 h.batchSize = batchSizeDefault 200 h.expReg = make(map[string]*expiringItem) 201 h.cacheAge = 2 202 h.runId = 0 203 204 p := metrics.Parameters{ 205 Tenant: "heapster", 206 Url: h.uri.String(), 207 Concurrency: concurrencyDefault, 208 } 209 210 opts := h.uri.Query() 211 212 if v, found := opts["tenant"]; found { 213 p.Tenant = v[0] 214 } 215 216 if v, found := opts["labelToTenant"]; found { 217 h.labelTenant = v[0] 218 } 219 220 if v, found := opts[labelTagPrefixOpts]; found { 221 h.labelTagPrefix = v[0] 222 } else { 223 h.labelTagPrefix = labelTagPrefixDefault 224 } 225 226 if v, found := opts[nodeId]; found { 227 h.labelNodeId = v[0] 228 } 229 230 if v, found := opts["useServiceAccount"]; found { 231 if b, _ := strconv.ParseBool(v[0]); b { 232 // If a readable service account token exists, then use it 233 if contents, err := ioutil.ReadFile(defaultServiceAccountFile); err == nil { 234 p.Token = string(contents) 235 } 236 } 237 } 238 239 // Authentication / Authorization parameters 240 tC := &tls.Config{} 241 242 if v, found := opts["auth"]; found { 243 if _, f := opts["caCert"]; f { 244 return fmt.Errorf("Both auth and caCert files provided, combination is not supported") 245 } 246 if len(v[0]) > 0 { 247 // Authfile 248 kubeConfig, err := kubeClientCmd.NewNonInteractiveDeferredLoadingClientConfig(&kubeClientCmd.ClientConfigLoadingRules{ 249 ExplicitPath: v[0]}, 250 &kubeClientCmd.ConfigOverrides{}).ClientConfig() 251 if err != nil { 252 return err 253 } 254 tC, err = kube_client.TLSConfigFor(kubeConfig) 255 if err != nil { 256 return err 257 } 258 } 259 } 260 261 if u, found := opts["user"]; found { 262 if _, wrong := opts["useServiceAccount"]; wrong { 263 return fmt.Errorf("If user and password are used, serviceAccount cannot be used") 264 } 265 if p, f := opts["pass"]; f { 266 h.modifiers = append(h.modifiers, func(req *http.Request) error { 267 req.SetBasicAuth(u[0], p[0]) 268 return nil 269 }) 270 } 271 } 272 273 if v, found := opts["caCert"]; found { 274 caCert, err := ioutil.ReadFile(v[0]) 275 if err != nil { 276 return err 277 } 278 279 caCertPool := x509.NewCertPool() 280 caCertPool.AppendCertsFromPEM(caCert) 281 282 tC.RootCAs = caCertPool 283 } 284 285 if v, found := opts["insecure"]; found { 286 _, f := opts["caCert"] 287 _, f2 := opts["auth"] 288 if f || f2 { 289 return fmt.Errorf("Insecure can't be defined with auth or caCert") 290 } 291 insecure, err := strconv.ParseBool(v[0]) 292 if err != nil { 293 return err 294 } 295 tC.InsecureSkipVerify = insecure 296 } 297 298 p.TLSConfig = tC 299 300 // Filters 301 if v, found := opts["filter"]; found { 302 filters, err := parseFilters(v) 303 if err != nil { 304 return err 305 } 306 h.filters = filters 307 } 308 309 // Concurrency limitations 310 if v, found := opts["concurrencyLimit"]; found { 311 cs, err := strconv.Atoi(v[0]) 312 if err != nil || cs < 0 { 313 return fmt.Errorf("Supplied concurrency value of %s is invalid", v[0]) 314 } 315 p.Concurrency = cs 316 } 317 318 if v, found := opts["batchSize"]; found { 319 bs, err := strconv.Atoi(v[0]) 320 if err != nil || bs < 0 { 321 return fmt.Errorf("Supplied batchSize value of %s is invalid", v[0]) 322 } 323 h.batchSize = bs 324 } 325 326 if v, found := opts["disablePreCache"]; found { 327 dpc, err := strconv.ParseBool(v[0]) 328 if err != nil { 329 return fmt.Errorf("disablePreCache parameter value %s is invalid", v[0]) 330 } 331 h.disablePreCaching = dpc 332 } 333 334 c, err := metrics.NewHawkularClient(p) 335 if err != nil { 336 return err 337 } 338 339 h.client = c 340 341 glog.Infof("Initialised Hawkular Sink with parameters %v", p) 342 return nil 343 }