yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/qcloud/monitor.go (about) 1 // Copyright 2019 Yunion 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 qcloud 16 17 import ( 18 "fmt" 19 "strings" 20 "time" 21 22 "yunion.io/x/jsonutils" 23 "yunion.io/x/log" 24 "yunion.io/x/pkg/errors" 25 "yunion.io/x/pkg/util/timeutils" 26 27 "yunion.io/x/cloudmux/pkg/cloudprovider" 28 ) 29 30 const ( 31 QCLOUD_API_VERSION_METRICS = "2018-07-24" 32 ) 33 34 type SQcMetricDimension struct { 35 Name string `json:"Name"` 36 Value string `json:"Value"` 37 } 38 39 type SQcMetricConditionDimension struct { 40 Key string `json:"Key"` 41 Value string `json:"Value"` 42 Operator string `json:"Operator"` 43 } 44 45 type SQcInstanceMetricDimension struct { 46 Dimensions []SQcMetricDimension 47 } 48 49 type SDataPoint struct { 50 Dimensions []SQcMetricDimension `json:"Dimensions"` 51 Timestamps []float64 `json:"Timestamps"` 52 Values []float64 `json:"Values"` 53 } 54 55 type SK8SDataPoint struct { 56 MetricName string `json:"MetricName"` 57 Points []SK8sPoint `json:"Points"` 58 } 59 60 type SK8sPoint struct { 61 Dimensions []SQcMetricDimension `json:"Dimensions"` 62 Values []SK8sPointValue `json:"Values"` 63 } 64 65 type SK8sPointValue struct { 66 Timestamp float64 `json:"Timestamp"` 67 Value float64 `json:"Value"` 68 } 69 70 type SBatchQueryMetricDataInput struct { 71 MetricName string `json:"MetricName"` 72 Namespace string `json:"Namespace"` 73 Metrics []SQcMetricDimension `json:"Metrics"` 74 StartTime int64 `json:"StartTime"` 75 EndTime int64 `json:"EndTime"` 76 Period string `json:"Period"` 77 } 78 79 func (self *SQcloudClient) metricsRequest(action string, params map[string]string) (jsonutils.JSONObject, error) { 80 cli, err := self.getDefaultClient(params) 81 if err != nil { 82 return nil, err 83 } 84 return monitorRequest(cli, action, params, self.cpcfg.UpdatePermission, self.debug) 85 } 86 87 func (self *SQcloudClient) GetMonitorData(ns string, name string, since time.Time, until time.Time, regionId string, dimensionName string, resIds []string) ([]SDataPoint, error) { 88 params := make(map[string]string) 89 params["Region"] = regionId 90 params["MetricName"] = name 91 params["Namespace"] = ns 92 params["StartTime"] = since.Format(timeutils.IsoTimeFormat) 93 params["EndTime"] = until.Format(timeutils.IsoTimeFormat) 94 for idx, resId := range resIds { 95 params[fmt.Sprintf("Instances.%d.Dimensions.0.Name", idx)] = dimensionName 96 params[fmt.Sprintf("Instances.%d.Dimensions.0.Value", idx)] = resId 97 } 98 body, err := self.metricsRequest("GetMonitorData", params) 99 if err != nil { 100 return nil, errors.Wrapf(err, "MetricRequest for %s", resIds) 101 } 102 ret := []SDataPoint{} 103 err = body.Unmarshal(&ret, "DataPoints") 104 if err != nil { 105 return nil, errors.Wrap(err, "resp.Unmarshal") 106 } 107 return ret, nil 108 } 109 110 func (self *SQcloudClient) GetK8sMonitorData(ns, name, resourceId string, since time.Time, until time.Time, regionId string) ([]SK8SDataPoint, error) { 111 params := make(map[string]string) 112 params["Module"] = "monitor" 113 params["Region"] = regionId 114 params["MetricNames.0"] = name 115 params["Namespace"] = ns 116 params["Period"] = "60" 117 params["StartTime"] = since.Format(timeutils.IsoTimeFormat) 118 params["EndTime"] = until.Format(timeutils.IsoTimeFormat) 119 params["Conditions.0.Key"] = "tke_cluster_instance_id" 120 params["Conditions.0.Operator"] = "in" 121 params["Conditions.0.Value.0"] = resourceId 122 body, err := self.metricsRequest("DescribeStatisticData", params) 123 if err != nil { 124 return nil, errors.Wrap(err, "region.MetricRequest") 125 } 126 ret := []SK8SDataPoint{} 127 return ret, body.Unmarshal(&ret, "Data") 128 } 129 130 func (self *SQcloudClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { 131 switch opts.ResourceType { 132 case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: 133 return self.GetEcsMetrics(opts) 134 case cloudprovider.METRIC_RESOURCE_TYPE_REDIS: 135 return self.GetRedisMetrics(opts) 136 case cloudprovider.METRIC_RESOURCE_TYPE_RDS: 137 return self.GetRdsMetrics(opts) 138 case cloudprovider.METRIC_RESOURCE_TYPE_K8S: 139 return self.GetK8sMetrics(opts) 140 default: 141 return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.ResourceType) 142 } 143 } 144 145 func (self *SQcloudClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { 146 ret := []cloudprovider.MetricValues{} 147 for metricType, metricNames := range map[cloudprovider.TMetricType]map[string]string{ 148 cloudprovider.VM_METRIC_TYPE_CPU_USAGE: { 149 "CPUUsage": "", 150 }, 151 cloudprovider.VM_METRIC_TYPE_MEM_USAGE: { 152 "MemUsage": "", 153 }, 154 cloudprovider.VM_METRIC_TYPE_NET_BPS_TX: { 155 "lanOuttraffic": cloudprovider.METRIC_TAG_NET_TYPE + ":" + cloudprovider.METRIC_TAG_NET_TYPE_INTRANET, 156 "WanOuttraffic": cloudprovider.METRIC_TAG_NET_TYPE + ":" + cloudprovider.METRIC_TAG_NET_TYPE_INTERNET, 157 }, 158 cloudprovider.VM_METRIC_TYPE_NET_BPS_RX: { 159 "lanIntraffic": cloudprovider.METRIC_TAG_NET_TYPE + ":" + cloudprovider.METRIC_TAG_NET_TYPE_INTRANET, 160 "WanIntraffic": cloudprovider.METRIC_TAG_NET_TYPE + ":" + cloudprovider.METRIC_TAG_NET_TYPE_INTERNET, 161 }, 162 } { 163 for metricName, tag := range metricNames { 164 metrics, err := self.GetMonitorData("QCE/CVM", metricName, opts.StartTime, opts.EndTime, opts.RegionExtId, "InstanceId", opts.ResourceIds) 165 if err != nil { 166 log.Errorf("GetMonitorData error: %v", err) 167 continue 168 } 169 for i := range metrics { 170 metric := cloudprovider.MetricValues{} 171 if len(metrics[i].Dimensions) < 1 || metrics[i].Dimensions[0].Name != "InstanceId" { 172 continue 173 } 174 metric.Id = metrics[i].Dimensions[0].Value 175 metric.MetricType = metricType 176 metricValue := cloudprovider.MetricValue{} 177 metricValue.Tags = map[string]string{} 178 idx := strings.Index(tag, ":") 179 if idx > 0 { 180 metricValue.Tags[tag[:idx]] = tag[idx+1:] 181 } 182 if len(metrics[i].Timestamps) == 0 { 183 continue 184 } 185 for j := range metrics[i].Timestamps { 186 metricValue.Value = metrics[i].Values[j] 187 if strings.Contains(metricName, "traffic") { //Mbps 188 metricValue.Value *= 1024 * 1024 189 } 190 metricValue.Timestamp = time.Unix(int64(metrics[i].Timestamps[j]), 0) 191 metric.Values = append(metric.Values, metricValue) 192 } 193 ret = append(ret, metric) 194 } 195 } 196 } 197 return ret, nil 198 } 199 200 func (self *SQcloudClient) GetRedisMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { 201 ret := []cloudprovider.MetricValues{} 202 for metricType, metricNames := range map[cloudprovider.TMetricType]map[string]string{ 203 cloudprovider.REDIS_METRIC_TYPE_CPU_USAGE: { 204 "CpuUsMin": "", 205 }, 206 cloudprovider.REDIS_METRIC_TYPE_MEM_USAGE: { 207 "StorageUsMin": "", 208 }, 209 cloudprovider.REDIS_METRIC_TYPE_NET_BPS_RX: { 210 "InFlowMin": "", 211 }, 212 cloudprovider.REDIS_METRIC_TYPE_NET_BPS_TX: { 213 "OutFlowMin": "", 214 }, 215 cloudprovider.REDIS_METRIC_TYPE_USED_CONN: { 216 "ConnectionsMin": "", 217 }, 218 cloudprovider.REDIS_METRIC_TYPE_OPT_SES: { 219 "QpsMin": "", 220 }, 221 cloudprovider.REDIS_METRIC_TYPE_CACHE_KEYS: { 222 "KeysMin": "", 223 }, 224 cloudprovider.REDIS_METRIC_TYPE_CACHE_EXP_KEYS: { 225 "ExpiredKeysMin": "", 226 }, 227 cloudprovider.REDIS_METRIC_TYPE_DATA_MEM_USAGE: { 228 "StorageMin": "", 229 }, 230 } { 231 for metricName, tag := range metricNames { 232 metrics, err := self.GetMonitorData("QCE/REDIS", metricName, opts.StartTime, opts.EndTime, opts.RegionExtId, "instanceid", opts.ResourceIds) 233 if err != nil { 234 log.Errorf("GetMonitorData error: %v", err) 235 continue 236 } 237 for i := range metrics { 238 metric := cloudprovider.MetricValues{} 239 if len(metrics[i].Dimensions) < 1 || metrics[i].Dimensions[0].Name != "instanceid" { 240 continue 241 } 242 metric.Id = metrics[i].Dimensions[0].Value 243 metric.MetricType = metricType 244 metricValue := cloudprovider.MetricValue{} 245 metricValue.Tags = map[string]string{} 246 idx := strings.Index(tag, ":") 247 if idx > 0 { 248 metricValue.Tags[tag[:idx]] = tag[idx+1:] 249 } 250 if len(metrics[i].Timestamps) == 0 { 251 continue 252 } 253 for j := range metrics[i].Timestamps { 254 metricValue.Value = metrics[i].Values[j] 255 metricValue.Timestamp = time.Unix(int64(metrics[i].Timestamps[j]), 0) 256 metric.Values = append(metric.Values, metricValue) 257 } 258 ret = append(ret, metric) 259 } 260 } 261 } 262 return ret, nil 263 } 264 265 func (self *SQcloudClient) GetRdsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { 266 ret := []cloudprovider.MetricValues{} 267 for metricType, metricNames := range map[cloudprovider.TMetricType]map[string]string{ 268 cloudprovider.RDS_METRIC_TYPE_CPU_USAGE: { 269 "CPUUseRate": "", 270 }, 271 cloudprovider.RDS_METRIC_TYPE_MEM_USAGE: { 272 "MemoryUseRate": "", 273 }, 274 cloudprovider.RDS_METRIC_TYPE_NET_BPS_TX: { 275 "BytesSent": cloudprovider.METRIC_TAG_NET_TYPE + ":" + cloudprovider.METRIC_TAG_NET_TYPE_INTRANET, 276 }, 277 cloudprovider.RDS_METRIC_TYPE_NET_BPS_RX: { 278 "BytesReceived": cloudprovider.METRIC_TAG_NET_TYPE + ":" + cloudprovider.METRIC_TAG_NET_TYPE_INTRANET, 279 }, 280 cloudprovider.RDS_METRIC_TYPE_DISK_USAGE: { 281 "VolumeRate": "", 282 }, 283 cloudprovider.RDS_METRIC_TYPE_CONN_COUNT: { 284 "ThreadsConnected": "", 285 }, 286 cloudprovider.RDS_METRIC_TYPE_CONN_USAGE: { 287 "ConnectionUseRate": "", 288 }, 289 cloudprovider.RDS_METRIC_TYPE_QPS: { 290 "QPS": "", 291 }, 292 cloudprovider.RDS_METRIC_TYPE_TPS: { 293 "TPS": "", 294 }, 295 cloudprovider.RDS_METRIC_TYPE_INNODB_READ_BPS: { 296 "InnodbDataRead": "", 297 }, 298 cloudprovider.RDS_METRIC_TYPE_INNODB_WRITE_BPS: { 299 "InnodbDataWritten": "", 300 }, 301 } { 302 for metricName, tag := range metricNames { 303 metrics, err := self.GetMonitorData("QCE/CDB", metricName, opts.StartTime, opts.EndTime, opts.RegionExtId, "InstanceId", opts.ResourceIds) 304 if err != nil { 305 log.Errorf("GetMonitorData error: %v", err) 306 continue 307 } 308 for i := range metrics { 309 metric := cloudprovider.MetricValues{} 310 if len(metrics[i].Dimensions) < 1 || metrics[i].Dimensions[0].Name != "InstanceId" { 311 continue 312 } 313 metric.Id = metrics[i].Dimensions[0].Value 314 metric.MetricType = metricType 315 metricValue := cloudprovider.MetricValue{} 316 metricValue.Tags = map[string]string{} 317 idx := strings.Index(tag, ":") 318 if idx > 0 { 319 metricValue.Tags[tag[:idx]] = tag[idx+1:] 320 } 321 if len(metrics[i].Timestamps) == 0 { 322 continue 323 } 324 for j := range metrics[i].Timestamps { 325 metricValue.Value = metrics[i].Values[j] 326 metricValue.Timestamp = time.Unix(int64(metrics[i].Timestamps[j]), 0) 327 metric.Values = append(metric.Values, metricValue) 328 } 329 ret = append(ret, metric) 330 } 331 } 332 } 333 return ret, nil 334 } 335 336 func (self *SQcloudClient) GetK8sMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { 337 ret := []cloudprovider.MetricValues{} 338 for metricType, metricName := range map[cloudprovider.TMetricType]string{ 339 cloudprovider.K8S_NODE_METRIC_TYPE_CPU_USAGE: "K8sNodeCpuUsage", 340 cloudprovider.K8S_NODE_METRIC_TYPE_MEM_USAGE: "K8sNodeMemUsage", 341 } { 342 metrics, err := self.GetK8sMonitorData("QCE/TKE2", metricName, opts.ResourceId, opts.StartTime, opts.EndTime, opts.RegionExtId) 343 if err != nil { 344 log.Errorf("GetMonitorData error: %v", err) 345 continue 346 } 347 for i := range metrics { 348 for _, point := range metrics[i].Points { 349 tags := map[string]string{} 350 for _, dim := range point.Dimensions { 351 if dim.Name == "node" { 352 tags[cloudprovider.METRIC_TAG_NODE] = dim.Value 353 } 354 } 355 metric := cloudprovider.MetricValues{} 356 metric.Id = opts.ResourceId 357 metric.MetricType = metricType 358 for _, value := range point.Values { 359 metric.Values = append(metric.Values, cloudprovider.MetricValue{ 360 Value: value.Value, 361 Timestamp: time.Unix(int64(value.Timestamp), 0), 362 Tags: tags, 363 }) 364 } 365 if len(metric.Values) > 0 { 366 ret = append(ret, metric) 367 } 368 } 369 } 370 } 371 return ret, nil 372 }