github.com/galamsiva2020/kubernetes-heapster-monitoring@v0.0.0-20210823134957-3c1baa7c1e70/metrics/api/v1/model_handlers.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 v1 16 17 import ( 18 "errors" 19 "fmt" 20 "net/http" 21 "strings" 22 "time" 23 24 restful "github.com/emicklei/go-restful" 25 26 "k8s.io/heapster/metrics/api/v1/types" 27 "k8s.io/heapster/metrics/core" 28 "k8s.io/heapster/metrics/util/metrics" 29 ) 30 31 // for testing 32 var nowFunc = time.Now 33 34 // errModelNotActivated is the error that is returned by the API handlers 35 // when manager.model has not been initialized. 36 var errModelNotActivated = errors.New("the model is not activated") 37 38 // Deprecated - clients should switch to full metric names ASAP. 39 var deprecatedMetricNamesConversion = map[string]string{ 40 "cpu-usage": "cpu/usage_rate", 41 "cpu-limit": "cpu/limit", 42 "memory-limit": "memory/limit", 43 "memory-usage": "memory/usage", 44 "memory-working": "memory/working_set", 45 } 46 47 type clusterMetricsFetcher interface { 48 availableClusterMetrics(request *restful.Request, response *restful.Response) 49 clusterMetrics(request *restful.Request, response *restful.Response) 50 51 nodeList(request *restful.Request, response *restful.Response) 52 availableNodeMetrics(request *restful.Request, response *restful.Response) 53 nodeMetrics(request *restful.Request, response *restful.Response) 54 55 namespaceList(request *restful.Request, response *restful.Response) 56 availableNamespaceMetrics(request *restful.Request, response *restful.Response) 57 namespaceMetrics(request *restful.Request, response *restful.Response) 58 59 namespacePodList(request *restful.Request, response *restful.Response) 60 availablePodMetrics(request *restful.Request, response *restful.Response) 61 podMetrics(request *restful.Request, response *restful.Response) 62 63 podContainerList(request *restful.Request, response *restful.Response) 64 65 availablePodContainerMetrics(request *restful.Request, response *restful.Response) 66 podContainerMetrics(request *restful.Request, response *restful.Response) 67 68 nodeSystemContainerList(request *restful.Request, response *restful.Response) 69 availableFreeContainerMetrics(request *restful.Request, response *restful.Response) 70 freeContainerMetrics(request *restful.Request, response *restful.Response) 71 72 podListMetrics(request *restful.Request, response *restful.Response) 73 74 isRunningInKubernetes() bool 75 } 76 77 // addClusterMetricsRoutes adds all the standard model routes to a WebService. 78 // It should already have a base path registered. 79 func addClusterMetricsRoutes(a clusterMetricsFetcher, ws *restful.WebService) { 80 // The /metrics/ endpoint returns a list of all available metrics for the Cluster entity of the model. 81 ws.Route(ws.GET("/metrics/"). 82 To(metrics.InstrumentRouteFunc("availableClusterMetrics", a.availableClusterMetrics)). 83 Doc("Get a list of all available metrics for the Cluster entity"). 84 Operation("availableClusterMetrics")) 85 86 // The /metrics/{metric-name} endpoint exposes an aggregated metric for the Cluster entity of the model. 87 ws.Route(ws.GET("/metrics/{metric-name:*}"). 88 To(metrics.InstrumentRouteFunc("clusterMetrics", a.clusterMetrics)). 89 Doc("Export an aggregated cluster-level metric"). 90 Operation("clusterMetrics"). 91 Param(ws.PathParameter("metric-name", "The name of the requested metric").DataType("string")). 92 Param(ws.QueryParameter("start", "Start time for requested metric").DataType("string")). 93 Param(ws.QueryParameter("end", "End time for requested metric").DataType("string")). 94 Param(ws.QueryParameter("labels", "A comma-separated list of key:values pairs to use to search for a labeled metric").DataType("string")). 95 Writes(types.MetricResult{})) 96 97 // The /nodes/{node-name}/metrics endpoint returns a list of all nodes with some metrics. 98 ws.Route(ws.GET("/nodes/"). 99 To(metrics.InstrumentRouteFunc("nodeList", a.nodeList)). 100 Doc("Get a list of all nodes that have some current metrics"). 101 Operation("nodeList")) 102 103 // The /nodes/{node-name}/metrics endpoint returns a list of all available metrics for a Node entity. 104 ws.Route(ws.GET("/nodes/{node-name}/metrics/"). 105 To(metrics.InstrumentRouteFunc("availableNodeMetrics", a.availableNodeMetrics)). 106 Doc("Get a list of all available metrics for a Node entity"). 107 Operation("availableNodeMetrics"). 108 Param(ws.PathParameter("node-name", "The name of the node to lookup").DataType("string"))) 109 110 // The /nodes/{node-name}/metrics/{metric-name} endpoint exposes a metric for a Node entity of the model. 111 // The {node-name} parameter is the hostname of a specific node. 112 ws.Route(ws.GET("/nodes/{node-name}/metrics/{metric-name:*}"). 113 To(metrics.InstrumentRouteFunc("nodeMetrics", a.nodeMetrics)). 114 Doc("Export a node-level metric"). 115 Operation("nodeMetrics"). 116 Param(ws.PathParameter("node-name", "The name of the node to lookup").DataType("string")). 117 Param(ws.PathParameter("metric-name", "The name of the requested metric").DataType("string")). 118 Param(ws.QueryParameter("start", "Start time for requested metric").DataType("string")). 119 Param(ws.QueryParameter("end", "End time for requested metric").DataType("string")). 120 Param(ws.QueryParameter("labels", "A comma-separated list of key:values pairs to use to search for a labeled metric").DataType("string")). 121 Writes(types.MetricResult{})) 122 123 if a.isRunningInKubernetes() { 124 125 ws.Route(ws.GET("/namespaces/"). 126 To(metrics.InstrumentRouteFunc("namespaceList", a.namespaceList)). 127 Doc("Get a list of all namespaces that have some current metrics"). 128 Operation("namespaceList")) 129 130 // The /namespaces/{namespace-name}/metrics endpoint returns a list of all available metrics for a Namespace entity. 131 ws.Route(ws.GET("/namespaces/{namespace-name}/metrics"). 132 To(metrics.InstrumentRouteFunc("availableNamespaceMetrics", a.availableNamespaceMetrics)). 133 Doc("Get a list of all available metrics for a Namespace entity"). 134 Operation("availableNamespaceMetrics"). 135 Param(ws.PathParameter("namespace-name", "The name of the namespace to lookup").DataType("string"))) 136 137 // The /namespaces/{namespace-name}/metrics/{metric-name} endpoint exposes an aggregated metrics 138 // for a Namespace entity of the model. 139 ws.Route(ws.GET("/namespaces/{namespace-name}/metrics/{metric-name:*}"). 140 To(metrics.InstrumentRouteFunc("namespaceMetrics", a.namespaceMetrics)). 141 Doc("Export an aggregated namespace-level metric"). 142 Operation("namespaceMetrics"). 143 Param(ws.PathParameter("namespace-name", "The name of the namespace to lookup").DataType("string")). 144 Param(ws.PathParameter("metric-name", "The name of the requested metric").DataType("string")). 145 Param(ws.QueryParameter("start", "Start time for requested metrics").DataType("string")). 146 Param(ws.QueryParameter("end", "End time for requested metric").DataType("string")). 147 Param(ws.QueryParameter("labels", "A comma-separated list of key:values pairs to use to search for a labeled metric").DataType("string")). 148 Writes(types.MetricResult{})) 149 150 ws.Route(ws.GET("/namespaces/{namespace-name}/pods/"). 151 To(metrics.InstrumentRouteFunc("namespacePodList", a.namespacePodList)). 152 Doc("Get a list of pods from the given namespace that have some metrics"). 153 Operation("namespacePodList"). 154 Param(ws.PathParameter("namespace-name", "The name of the namespace to lookup").DataType("string"))) 155 156 // The /namespaces/{namespace-name}/pods/{pod-name}/metrics endpoint returns a list of all available metrics for a Pod entity. 157 ws.Route(ws.GET("/namespaces/{namespace-name}/pods/{pod-name}/metrics"). 158 To(metrics.InstrumentRouteFunc("availablePodMetrics", a.availablePodMetrics)). 159 Doc("Get a list of all available metrics for a Pod entity"). 160 Operation("availablePodMetrics"). 161 Param(ws.PathParameter("namespace-name", "The name of the namespace to lookup").DataType("string")). 162 Param(ws.PathParameter("pod-name", "The name of the pod to lookup").DataType("string"))) 163 164 // The /namespaces/{namespace-name}/pods/{pod-name}/metrics/{metric-name} endpoint exposes 165 // an aggregated metric for a Pod entity of the model. 166 ws.Route(ws.GET("/namespaces/{namespace-name}/pods/{pod-name}/metrics/{metric-name:*}"). 167 To(metrics.InstrumentRouteFunc("podMetrics", a.podMetrics)). 168 Doc("Export an aggregated pod-level metric"). 169 Operation("podMetrics"). 170 Param(ws.PathParameter("namespace-name", "The name of the namespace to lookup").DataType("string")). 171 Param(ws.PathParameter("pod-name", "The name of the pod to lookup").DataType("string")). 172 Param(ws.PathParameter("metric-name", "The name of the requested metric").DataType("string")). 173 Param(ws.QueryParameter("start", "Start time for requested metrics").DataType("string")). 174 Param(ws.QueryParameter("end", "End time for requested metric").DataType("string")). 175 Param(ws.QueryParameter("labels", "A comma-separated list of key:values pairs to use to search for a labeled metric").DataType("string")). 176 Writes(types.MetricResult{})) 177 178 // The /namespaces/{namespace-name}/pods/{pod-name}/containers endpoint 179 // returns a list of all containers for a Pod entity. 180 ws.Route(ws.GET("/namespaces/{namespace-name}/pods/{pod-name}/containers"). 181 To(metrics.InstrumentRouteFunc("podContainerList", a.podContainerList)). 182 Doc("Get a list of containers for a Pod entity "). 183 Operation("podContainerList"). 184 Param(ws.PathParameter("namespace-name", "The name of the namespace to lookup").DataType("string")). 185 Param(ws.PathParameter("pod-name", "The name of the pod to lookup").DataType("string"))) 186 187 // The /namespaces/{namespace-name}/pods/{pod-name}/containers/metrics/{container-name}/metrics endpoint 188 // returns a list of all available metrics for a Pod Container entity. 189 ws.Route(ws.GET("/namespaces/{namespace-name}/pods/{pod-name}/containers/{container-name}/metrics"). 190 To(metrics.InstrumentRouteFunc("availableContainerMetrics", a.availablePodContainerMetrics)). 191 Doc("Get a list of all available metrics for a Pod entity"). 192 Operation("availableContainerMetrics"). 193 Param(ws.PathParameter("namespace-name", "The name of the namespace to lookup").DataType("string")). 194 Param(ws.PathParameter("pod-name", "The name of the pod to lookup").DataType("string")). 195 Param(ws.PathParameter("container-name", "The name of the namespace to use").DataType("string"))) 196 197 // The /namespaces/{namespace-name}/pods/{pod-name}/containers/{container-name}/metrics/{metric-name} endpoint exposes 198 // a metric for a Container entity of the model. 199 ws.Route(ws.GET("/namespaces/{namespace-name}/pods/{pod-name}/containers/{container-name}/metrics/{metric-name:*}"). 200 To(metrics.InstrumentRouteFunc("podContainerMetrics", a.podContainerMetrics)). 201 Doc("Export an aggregated metric for a Pod Container"). 202 Operation("podContainerMetrics"). 203 Param(ws.PathParameter("namespace-name", "The name of the namespace to use").DataType("string")). 204 Param(ws.PathParameter("pod-name", "The name of the pod to use").DataType("string")). 205 Param(ws.PathParameter("container-name", "The name of the namespace to use").DataType("string")). 206 Param(ws.PathParameter("metric-name", "The name of the requested metric").DataType("string")). 207 Param(ws.QueryParameter("start", "Start time for requested metrics").DataType("string")). 208 Param(ws.QueryParameter("end", "End time for requested metric").DataType("string")). 209 Param(ws.QueryParameter("labels", "A comma-separated list of key:values pairs to use to search for a labeled metric").DataType("string")). 210 Writes(types.MetricResult{})) 211 } 212 213 ws.Route(ws.GET("/nodes/{node-name}/freecontainers/"). 214 To(metrics.InstrumentRouteFunc("systemContainerList", a.nodeSystemContainerList)). 215 Doc("Get a list of all non-pod containers with some metrics"). 216 Operation("systemContainerList"). 217 Param(ws.PathParameter("node-name", "The name of the namespace to lookup").DataType("string"))) 218 219 // The /nodes/{node-name}/freecontainers/{container-name}/metrics endpoint 220 // returns a list of all available metrics for a Free Container entity. 221 ws.Route(ws.GET("/nodes/{node-name}/freecontainers/{container-name}/metrics"). 222 To(metrics.InstrumentRouteFunc("availableMetrics", a.availableFreeContainerMetrics)). 223 Doc("Get a list of all available metrics for a free Container entity"). 224 Operation("availableMetrics"). 225 Param(ws.PathParameter("node-name", "The name of the namespace to lookup").DataType("string")). 226 Param(ws.PathParameter("container-name", "The name of the namespace to use").DataType("string"))) 227 228 // The /nodes/{node-name}/freecontainers/{container-name}/metrics/{metric-name} endpoint exposes 229 // a metric for a free Container entity of the model. 230 ws.Route(ws.GET("/nodes/{node-name}/freecontainers/{container-name}/metrics/{metric-name:*}"). 231 To(metrics.InstrumentRouteFunc("freeContainerMetrics", a.freeContainerMetrics)). 232 Doc("Export a container-level metric for a free container"). 233 Operation("freeContainerMetrics"). 234 Param(ws.PathParameter("node-name", "The name of the node to use").DataType("string")). 235 Param(ws.PathParameter("container-name", "The name of the container to use").DataType("string")). 236 Param(ws.PathParameter("metric-name", "The name of the requested metric").DataType("string")). 237 Param(ws.QueryParameter("start", "Start time for requested metrics").DataType("string")). 238 Param(ws.QueryParameter("end", "End time for requested metric").DataType("string")). 239 Param(ws.QueryParameter("labels", "A comma-separated list of key:values pairs to use to search for a labeled metric").DataType("string")). 240 Writes(types.MetricResult{})) 241 242 if a.isRunningInKubernetes() { 243 // The /namespaces/{namespace-name}/pod-list/{pod-list}/metrics/{metric-name} endpoint exposes 244 // metrics for a list of pods of the model. 245 ws.Route(ws.GET("/namespaces/{namespace-name}/pod-list/{pod-list}/metrics/{metric-name:*}"). 246 To(metrics.InstrumentRouteFunc("podListMetric", a.podListMetrics)). 247 Doc("Export a metric for all pods from the given list"). 248 Operation("podListMetric"). 249 Param(ws.PathParameter("namespace-name", "The name of the namespace to lookup").DataType("string")). 250 Param(ws.PathParameter("pod-list", "Comma separated list of pod names to lookup").DataType("string")). 251 Param(ws.PathParameter("metric-name", "The name of the requested metric").DataType("string")). 252 Param(ws.QueryParameter("start", "Start time for requested metrics").DataType("string")). 253 Param(ws.QueryParameter("end", "End time for requested metric").DataType("string")). 254 Param(ws.QueryParameter("labels", "A comma-separated list of key:values pairs to use to search for a labeled metric").DataType("string")). 255 Writes(types.MetricResult{})) 256 } 257 } 258 259 func (a *Api) isRunningInKubernetes() bool { 260 return a.runningInKubernetes 261 } 262 263 // RegisterModel registers the Model API endpoints. 264 // All endpoints that end with a {metric-name} also receive a start time query parameter. 265 // The start and end times should be specified as a string, formatted according to RFC 3339. 266 func (a *Api) RegisterModel(container *restful.Container) { 267 ws := new(restful.WebService) 268 ws.Path("/api/v1/model"). 269 Doc("Root endpoint of the stats model"). 270 Consumes("*/*"). 271 Produces(restful.MIME_JSON) 272 273 addClusterMetricsRoutes(a, ws) 274 275 ws.Route(ws.GET("/debug/allkeys"). 276 To(metrics.InstrumentRouteFunc("debugAllKeys", a.allKeys)). 277 Doc("Get keys of all metric sets available"). 278 Operation("debugAllKeys")) 279 container.Add(ws) 280 } 281 282 // availableMetrics returns a list of available cluster metric names. 283 func (a *Api) availableClusterMetrics(request *restful.Request, response *restful.Response) { 284 a.processMetricNamesRequest(core.ClusterKey(), response) 285 } 286 287 // availableMetrics returns a list of available node metric names. 288 func (a *Api) availableNodeMetrics(request *restful.Request, response *restful.Response) { 289 a.processMetricNamesRequest(core.NodeKey(request.PathParameter("node-name")), response) 290 } 291 292 // availableMetrics returns a list of available namespace metric names. 293 func (a *Api) availableNamespaceMetrics(request *restful.Request, response *restful.Response) { 294 a.processMetricNamesRequest(core.NamespaceKey(request.PathParameter("namespace-name")), response) 295 } 296 297 // availableMetrics returns a list of available pod metric names. 298 func (a *Api) availablePodMetrics(request *restful.Request, response *restful.Response) { 299 a.processMetricNamesRequest( 300 core.PodKey(request.PathParameter("namespace-name"), 301 request.PathParameter("pod-name")), response) 302 } 303 304 // availableMetrics returns a list of available pod metric names. 305 func (a *Api) availablePodContainerMetrics(request *restful.Request, response *restful.Response) { 306 a.processMetricNamesRequest( 307 core.PodContainerKey(request.PathParameter("namespace-name"), 308 request.PathParameter("pod-name"), 309 request.PathParameter("container-name"), 310 ), response) 311 } 312 313 // availableMetrics returns a list of available pod metric names. 314 func (a *Api) availableFreeContainerMetrics(request *restful.Request, response *restful.Response) { 315 a.processMetricNamesRequest( 316 core.NodeContainerKey(request.PathParameter("node-name"), 317 request.PathParameter("container-name"), 318 ), response) 319 } 320 321 func (a *Api) nodeList(request *restful.Request, response *restful.Response) { 322 response.WriteEntity(a.metricSink.GetNodes()) 323 } 324 325 func (a *Api) namespaceList(request *restful.Request, response *restful.Response) { 326 response.WriteEntity(a.metricSink.GetNamespaces()) 327 } 328 329 func (a *Api) namespacePodList(request *restful.Request, response *restful.Response) { 330 response.WriteEntity(a.metricSink.GetPodsFromNamespace(request.PathParameter("namespace-name"))) 331 } 332 333 func (a *Api) podContainerList(request *restful.Request, response *restful.Response) { 334 response.WriteEntity(a.metricSink.GetContainersForPodFromNamespace(request.PathParameter("namespace-name"), request.PathParameter("pod-name"))) 335 } 336 337 func (a *Api) nodeSystemContainerList(request *restful.Request, response *restful.Response) { 338 response.WriteEntity(a.metricSink.GetSystemContainersFromNode(request.PathParameter("node-name"))) 339 } 340 341 func (a *Api) allKeys(request *restful.Request, response *restful.Response) { 342 response.WriteEntity(a.metricSink.GetMetricSetKeys()) 343 } 344 345 // clusterMetrics returns a metric timeseries for a metric of the Cluster entity. 346 func (a *Api) clusterMetrics(request *restful.Request, response *restful.Response) { 347 a.processMetricRequest(core.ClusterKey(), request, response) 348 } 349 350 // nodeMetrics returns a metric timeseries for a metric of the Node entity. 351 func (a *Api) nodeMetrics(request *restful.Request, response *restful.Response) { 352 a.processMetricRequest(core.NodeKey(request.PathParameter("node-name")), 353 request, response) 354 } 355 356 // namespaceMetrics returns a metric timeseries for a metric of the Namespace entity. 357 func (a *Api) namespaceMetrics(request *restful.Request, response *restful.Response) { 358 a.processMetricRequest(core.NamespaceKey(request.PathParameter("namespace-name")), 359 request, response) 360 } 361 362 // podMetrics returns a metric timeseries for a metric of the Pod entity. 363 func (a *Api) podMetrics(request *restful.Request, response *restful.Response) { 364 a.processMetricRequest( 365 core.PodKey(request.PathParameter("namespace-name"), 366 request.PathParameter("pod-name")), 367 request, response) 368 } 369 370 func (a *Api) podListMetrics(request *restful.Request, response *restful.Response) { 371 start, end, err := getStartEndTime(request) 372 if err != nil { 373 response.WriteError(http.StatusBadRequest, err) 374 return 375 } 376 ns := request.PathParameter("namespace-name") 377 keys := []string{} 378 metricName := request.PathParameter("metric-name") 379 convertedMetricName := convertMetricName(metricName) 380 for _, podName := range strings.Split(request.PathParameter("pod-list"), ",") { 381 keys = append(keys, core.PodKey(ns, podName)) 382 } 383 384 labels, err := getLabels(request) 385 if err != nil { 386 response.WriteError(http.StatusBadRequest, err) 387 return 388 } 389 390 var metrics map[string][]core.TimestampedMetricValue 391 if labels != nil { 392 metrics = a.metricSink.GetLabeledMetric(convertedMetricName, labels, keys, start, end) 393 } else { 394 metrics = a.metricSink.GetMetric(convertedMetricName, keys, start, end) 395 } 396 397 result := types.MetricResultList{ 398 Items: make([]types.MetricResult, 0, len(keys)), 399 } 400 for _, key := range keys { 401 result.Items = append(result.Items, exportTimestampedMetricValue(metrics[key])) 402 } 403 response.PrettyPrint(false) 404 response.WriteEntity(result) 405 } 406 407 // podContainerMetrics returns a metric timeseries for a metric of a Pod Container entity. 408 // podContainerMetrics uses the namespace-name/pod-name/container-name path. 409 func (a *Api) podContainerMetrics(request *restful.Request, response *restful.Response) { 410 a.processMetricRequest( 411 core.PodContainerKey(request.PathParameter("namespace-name"), 412 request.PathParameter("pod-name"), 413 request.PathParameter("container-name"), 414 ), 415 request, response) 416 } 417 418 // freeContainerMetrics returns a metric timeseries for a metric of the Container entity. 419 // freeContainerMetrics addresses only free containers, by using the node-name/container-name path. 420 func (a *Api) freeContainerMetrics(request *restful.Request, response *restful.Response) { 421 a.processMetricRequest( 422 core.NodeContainerKey(request.PathParameter("node-name"), 423 request.PathParameter("container-name"), 424 ), 425 request, response) 426 } 427 428 // parseRequestParam parses a time.Time from a named QueryParam, using the RFC3339 format. 429 func parseTimeParam(queryParam string, defaultValue time.Time) (time.Time, error) { 430 if queryParam != "" { 431 reqStamp, err := time.Parse(time.RFC3339, queryParam) 432 if err != nil { 433 return time.Time{}, fmt.Errorf("timestamp argument cannot be parsed: %s", err) 434 } 435 return reqStamp, nil 436 } 437 return defaultValue, nil 438 } 439 440 func (a *Api) processMetricRequest(key string, request *restful.Request, response *restful.Response) { 441 start, end, err := getStartEndTime(request) 442 if err != nil { 443 response.WriteError(http.StatusBadRequest, err) 444 return 445 } 446 metricName := request.PathParameter("metric-name") 447 convertedMetricName := convertMetricName(metricName) 448 labels, err := getLabels(request) 449 if err != nil { 450 response.WriteError(http.StatusBadRequest, err) 451 return 452 } 453 454 var metrics map[string][]core.TimestampedMetricValue 455 if labels != nil { 456 metrics = a.metricSink.GetLabeledMetric(convertedMetricName, labels, []string{key}, start, end) 457 } else { 458 metrics = a.metricSink.GetMetric(convertedMetricName, []string{key}, start, end) 459 } 460 converted := exportTimestampedMetricValue(metrics[key]) 461 response.WriteEntity(converted) 462 } 463 464 func (a *Api) processMetricNamesRequest(key string, response *restful.Response) { 465 metricNames := a.metricSink.GetMetricNames(key) 466 response.WriteEntity(metricNames) 467 } 468 469 func convertMetricName(metricName string) string { 470 if convertedMetricName, ok := deprecatedMetricNamesConversion[metricName]; ok { 471 return convertedMetricName 472 } 473 return metricName 474 } 475 476 func getStartEndTime(request *restful.Request) (time.Time, time.Time, error) { 477 start, err := parseTimeParam(request.QueryParameter("start"), time.Time{}) 478 if err != nil { 479 return time.Time{}, time.Time{}, err 480 } 481 end, err := parseTimeParam(request.QueryParameter("end"), nowFunc()) 482 if err != nil { 483 return time.Time{}, time.Time{}, err 484 } 485 return start, end, nil 486 } 487 488 func exportTimestampedMetricValue(values []core.TimestampedMetricValue) types.MetricResult { 489 result := types.MetricResult{ 490 Metrics: make([]types.MetricPoint, 0, len(values)), 491 } 492 for _, value := range values { 493 if result.LatestTimestamp.Before(value.Timestamp) { 494 result.LatestTimestamp = value.Timestamp 495 } 496 // TODO: clean up types in model api 497 var intValue int64 498 if value.ValueType == core.ValueInt64 { 499 intValue = value.IntValue 500 } else { 501 intValue = int64(value.FloatValue) 502 } 503 504 result.Metrics = append(result.Metrics, types.MetricPoint{ 505 Timestamp: value.Timestamp, 506 Value: uint64(intValue), 507 }) 508 } 509 return result 510 } 511 512 func getLabels(request *restful.Request) (map[string]string, error) { 513 labelsRaw := request.QueryParameter("labels") 514 if labelsRaw == "" { 515 return nil, nil 516 } 517 518 kvPairs := strings.Split(labelsRaw, ",") 519 labels := make(map[string]string, len(kvPairs)) 520 for _, kvPair := range kvPairs { 521 kvSplit := strings.SplitN(kvPair, ":", 2) 522 if len(kvSplit) != 2 || kvSplit[0] == "" || kvSplit[1] == "" { 523 return nil, fmt.Errorf("invalid label pair %q", kvPair) 524 } 525 labels[kvSplit[0]] = kvSplit[1] 526 } 527 528 return labels, nil 529 }