github.com/timstclair/heapster@v0.20.0-alpha1/metrics/api/v1/api.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 restful "github.com/emicklei/go-restful" 19 20 "k8s.io/heapster/metrics/api/v1/types" 21 "k8s.io/heapster/metrics/core" 22 "k8s.io/heapster/metrics/sinks/metric" 23 ) 24 25 type Api struct { 26 runningInKubernetes bool 27 metricSink *metricsink.MetricSink 28 gkeMetrics map[string]core.MetricDescriptor 29 gkeLabels map[string]core.LabelDescriptor 30 } 31 32 // Create a new Api to serve from the specified cache. 33 func NewApi(runningInKubernetes bool, metricSink *metricsink.MetricSink) *Api { 34 gkeMetrics := make(map[string]core.MetricDescriptor) 35 gkeLabels := make(map[string]core.LabelDescriptor) 36 for _, val := range core.StandardMetrics { 37 gkeMetrics[val.Name] = val.MetricDescriptor 38 } 39 for _, val := range core.CommonLabels() { 40 gkeLabels[val.Key] = val 41 } 42 for _, val := range core.ContainerLabels() { 43 gkeLabels[val.Key] = val 44 } 45 for _, val := range core.PodLabels() { 46 gkeLabels[val.Key] = val 47 } 48 49 return &Api{ 50 runningInKubernetes: runningInKubernetes, 51 metricSink: metricSink, 52 gkeMetrics: gkeMetrics, 53 gkeLabels: gkeLabels, 54 } 55 } 56 57 // Register the mainApi on the specified endpoint. 58 func (a *Api) Register(container *restful.Container) { 59 ws := new(restful.WebService) 60 ws.Path("/api/v1/metric-export"). 61 Doc("Exports the latest point for all Heapster metrics"). 62 Produces(restful.MIME_JSON) 63 ws.Route(ws.GET(""). 64 To(a.exportMetrics). 65 Doc("export the latest data point for all metrics"). 66 Operation("exportMetrics"). 67 Writes([]*types.Timeseries{})) 68 container.Add(ws) 69 ws = new(restful.WebService) 70 ws.Path("/api/v1/metric-export-schema"). 71 Doc("Schema for metrics exported by heapster"). 72 Produces(restful.MIME_JSON) 73 ws.Route(ws.GET(""). 74 To(a.exportMetricsSchema). 75 Doc("export the schema for all metrics"). 76 Operation("exportmetricsSchema"). 77 Writes(types.TimeseriesSchema{})) 78 container.Add(ws) 79 80 if a.metricSink != nil { 81 a.RegisterModel(container) 82 } 83 } 84 85 func convertLabelDescriptor(ld core.LabelDescriptor) types.LabelDescriptor { 86 return types.LabelDescriptor{ 87 Key: ld.Key, 88 Description: ld.Description, 89 } 90 } 91 92 func convertMetricDescriptor(md core.MetricDescriptor) types.MetricDescriptor { 93 result := types.MetricDescriptor{ 94 Name: md.Name, 95 Description: md.Description, 96 Labels: make([]types.LabelDescriptor, 0, len(md.Labels)), 97 } 98 for _, label := range md.Labels { 99 result.Labels = append(result.Labels, convertLabelDescriptor(label)) 100 } 101 102 switch md.Type { 103 case core.MetricCumulative: 104 result.Type = "cumulative" 105 case core.MetricGauge: 106 result.Type = "gauge" 107 } 108 109 switch md.ValueType { 110 case core.ValueInt64: 111 result.ValueType = "int64" 112 case core.ValueFloat: 113 result.ValueType = "double" 114 } 115 116 switch md.Units { 117 case core.UnitsBytes: 118 result.Units = "bytes" 119 case core.UnitsMilliseconds: 120 result.Units = "ms" 121 case core.UnitsNanoseconds: 122 result.Units = "ns" 123 case core.UnitsMillicores: 124 result.Units = "millicores" 125 } 126 return result 127 } 128 129 func (a *Api) exportMetricsSchema(request *restful.Request, response *restful.Response) { 130 result := types.TimeseriesSchema{ 131 Metrics: make([]types.MetricDescriptor, 0), 132 CommonLabels: make([]types.LabelDescriptor, 0), 133 PodLabels: make([]types.LabelDescriptor, 0), 134 } 135 for _, metric := range core.StandardMetrics { 136 if _, found := a.gkeMetrics[metric.Name]; found { 137 result.Metrics = append(result.Metrics, convertMetricDescriptor(metric.MetricDescriptor)) 138 } 139 } 140 for _, label := range core.CommonLabels() { 141 if _, found := a.gkeLabels[label.Key]; found { 142 result.PodLabels = append(result.PodLabels, convertLabelDescriptor(label)) 143 } 144 } 145 for _, label := range core.PodLabels() { 146 if _, found := a.gkeLabels[label.Key]; found { 147 result.PodLabels = append(result.PodLabels, convertLabelDescriptor(label)) 148 } 149 } 150 response.WriteEntity(result) 151 } 152 153 func (a *Api) exportMetrics(request *restful.Request, response *restful.Response) { 154 shortStorage := a.metricSink.GetShortStore() 155 tsmap := make(map[string]*types.Timeseries) 156 157 for _, batch := range shortStorage { 158 for key, ms := range batch.MetricSets { 159 ts := tsmap[key] 160 161 msType := ms.Labels[core.LabelMetricSetType.Key] 162 163 if msType != core.MetricSetTypeNode && 164 msType != core.MetricSetTypePod && 165 msType != core.MetricSetTypePodContainer && 166 msType != core.MetricSetTypeSystemContainer { 167 continue 168 } 169 170 if ts == nil { 171 ts = &types.Timeseries{ 172 Metrics: make(map[string][]types.Point), 173 Labels: make(map[string]string), 174 } 175 for labelName, labelValue := range ms.Labels { 176 if _, ok := a.gkeLabels[labelName]; ok { 177 ts.Labels[labelName] = labelValue 178 } 179 } 180 if msType == core.MetricSetTypeNode { 181 ts.Labels[core.LabelContainerName.Key] = "machine" 182 } 183 tsmap[key] = ts 184 } 185 for metricName, metricVal := range ms.MetricValues { 186 if _, ok := a.gkeMetrics[metricName]; ok { 187 points := ts.Metrics[metricName] 188 if points == nil { 189 points = make([]types.Point, 0, len(shortStorage)) 190 } 191 point := types.Point{ 192 Start: batch.Timestamp, 193 End: batch.Timestamp, 194 } 195 if metricVal.ValueType == core.ValueInt64 { 196 point.Value = &metricVal.IntValue 197 } else if metricVal.ValueType == core.ValueFloat { 198 point.Value = &metricVal.FloatValue 199 } else { 200 continue 201 } 202 points = append(points, point) 203 ts.Metrics[metricName] = points 204 } 205 } 206 } 207 } 208 timeseries := make([]*types.Timeseries, 0, len(tsmap)) 209 for _, ts := range tsmap { 210 timeseries = append(timeseries, ts) 211 } 212 213 response.WriteEntity(timeseries) 214 }