yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/hcs/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 hcs 16 17 import ( 18 "fmt" 19 "time" 20 21 "yunion.io/x/jsonutils" 22 "yunion.io/x/log" 23 "yunion.io/x/pkg/errors" 24 25 api "yunion.io/x/cloudmux/pkg/apis/compute" 26 "yunion.io/x/cloudmux/pkg/cloudprovider" 27 "yunion.io/x/onecloud/pkg/util/httputils" 28 ) 29 30 type MetricData struct { 31 Namespace string 32 MetricName string 33 Dimensions []struct { 34 Name string 35 Value string 36 } 37 Datapoints []struct { 38 Average float64 39 Timestamp int64 40 } 41 Unit string 42 } 43 44 func (self *SHcsClient) monitorPost(resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { 45 url := self._url("ces", "V1.0", self.defaultRegion, resource) 46 return self.request(httputils.POST, url, nil, params) 47 } 48 49 func (self *SHcsClient) getServerMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { 50 params := map[string]interface{}{ 51 "from": fmt.Sprintf("%d", opts.StartTime.UnixMilli()), 52 "to": fmt.Sprintf("%d", opts.EndTime.UnixMilli()), 53 "period": "1", 54 "filter": "average", 55 } 56 metrics := []interface{}{} 57 namespace, dimesionName, metricNames := "SYS.ECS", "instance_id", []string{ 58 "cpu_util", 59 "network_incoming_bytes_aggregate_rate", 60 "network_outgoing_bytes_aggregate_rate", 61 "disk_read_bytes_rate", 62 "disk_write_bytes_rate", 63 "disk_read_requests_rate", 64 "disk_write_requests_rate", 65 } 66 for _, metricName := range metricNames { 67 metrics = append(metrics, map[string]interface{}{ 68 "namespace": namespace, 69 "metric_name": metricName, 70 "dimensions": []map[string]string{ 71 { 72 "name": dimesionName, 73 "value": opts.ResourceId, 74 }, 75 }, 76 }) 77 } 78 params["metrics"] = metrics 79 resp, err := self.monitorPost("batch-query-metric-data", params) 80 if err != nil { 81 return nil, err 82 } 83 metricData := []MetricData{} 84 err = resp.Unmarshal(&metricData, "metrics") 85 if err != nil { 86 return nil, errors.Wrapf(err, "resp.Unmarshal") 87 } 88 result := []cloudprovider.MetricValues{} 89 for i := range metricData { 90 ret := cloudprovider.MetricValues{ 91 Id: opts.ResourceId, 92 Unit: metricData[i].Unit, 93 Values: []cloudprovider.MetricValue{}, 94 } 95 tags := map[string]string{} 96 switch metricData[i].MetricName { 97 case "cpu_util": 98 ret.MetricType = cloudprovider.VM_METRIC_TYPE_CPU_USAGE 99 case "network_incoming_bytes_aggregate_rate": 100 ret.MetricType = cloudprovider.VM_METRIC_TYPE_NET_BPS_RX 101 tags = map[string]string{"net_type": "internet"} 102 case "network_outgoing_bytes_aggregate_rate": 103 ret.MetricType = cloudprovider.VM_METRIC_TYPE_NET_BPS_TX 104 tags = map[string]string{"net_type": "internet"} 105 case "disk_read_bytes_rate": 106 ret.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS 107 case "disk_write_bytes_rate": 108 ret.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS 109 case "disk_read_requests_rate": 110 ret.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS 111 case "disk_write_requests_rate": 112 ret.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS 113 default: 114 log.Warningf("invalid metricName %s for %s %s", metricData[i].MetricName, opts.ResourceType, opts.ResourceId) 115 continue 116 } 117 for _, value := range metricData[i].Datapoints { 118 metricValue := cloudprovider.MetricValue{ 119 Value: value.Average, 120 Timestamp: time.UnixMilli(value.Timestamp), 121 Tags: tags, 122 } 123 ret.Values = append(ret.Values, metricValue) 124 } 125 result = append(result, ret) 126 } 127 return result, nil 128 } 129 130 func (self *SHcsClient) getRedisMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { 131 params := map[string]interface{}{ 132 "from": fmt.Sprintf("%d", opts.StartTime.UnixMilli()), 133 "to": fmt.Sprintf("%d", opts.EndTime.UnixMilli()), 134 "period": "1", 135 "filter": "average", 136 } 137 metrics := []interface{}{} 138 namespace, dimesionName, metricNames := "SYS.DCS", "dcs_instance_id", []string{ 139 "cpu_usage", 140 "memory_usage", 141 "instantaneous_input_kbps", 142 "instantaneous_output_kbps", 143 "connected_clients", 144 "instantaneous_ops", 145 "keys", 146 "expires", 147 "used_memory_dataset", 148 } 149 for _, metricName := range metricNames { 150 metrics = append(metrics, map[string]interface{}{ 151 "namespace": namespace, 152 "metric_name": metricName, 153 "dimensions": []map[string]string{ 154 { 155 "name": dimesionName, 156 "value": opts.ResourceId, 157 }, 158 }, 159 }) 160 } 161 params["metrics"] = metrics 162 resp, err := self.monitorPost("batch-query-metric-data", params) 163 if err != nil { 164 return nil, err 165 } 166 metricData := []MetricData{} 167 err = resp.Unmarshal(&metricData, "metrics") 168 if err != nil { 169 return nil, errors.Wrapf(err, "resp.Unmarshal") 170 } 171 result := []cloudprovider.MetricValues{} 172 for i := range metricData { 173 ret := cloudprovider.MetricValues{ 174 Id: opts.ResourceId, 175 Unit: metricData[i].Unit, 176 Values: []cloudprovider.MetricValue{}, 177 } 178 tags := map[string]string{} 179 switch metricData[i].MetricName { 180 case "cpu_usage": 181 ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_CPU_USAGE 182 case "memory_usage": 183 ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_MEM_USAGE 184 case "instantaneous_input_kbps": 185 ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_NET_BPS_RX 186 case "instantaneous_output_kbps": 187 ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_NET_BPS_TX 188 case "connected_clients": 189 ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_USED_CONN 190 case "instantaneous_ops": 191 ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_OPT_SES 192 case "keys": 193 ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_CACHE_KEYS 194 case "expires": 195 ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_CACHE_EXP_KEYS 196 case "used_memory_dataset": 197 ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_DATA_MEM_USAGE 198 default: 199 log.Warningf("invalid metricName %s for %s %s", metricData[i].MetricName, opts.ResourceType, opts.ResourceId) 200 continue 201 } 202 for _, value := range metricData[i].Datapoints { 203 metricValue := cloudprovider.MetricValue{ 204 Value: value.Average, 205 Timestamp: time.UnixMilli(value.Timestamp), 206 Tags: tags, 207 } 208 ret.Values = append(ret.Values, metricValue) 209 } 210 result = append(result, ret) 211 } 212 return result, nil 213 } 214 215 func (self *SHcsClient) getRdsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { 216 params := map[string]interface{}{ 217 "from": fmt.Sprintf("%d", opts.StartTime.UnixMilli()), 218 "to": fmt.Sprintf("%d", opts.EndTime.UnixMilli()), 219 "period": "1", 220 "filter": "average", 221 } 222 metrics := []interface{}{} 223 namespace, dimesionName, metricNames := "SYS.RDS", "rds_cluster_id", []string{ 224 "rds001_cpu_util", 225 "rds002_mem_util", 226 "rds004_bytes_in", 227 "rds004_bytes_in", 228 "rds005_bytes_out", 229 "rds039_disk_util", 230 "rds049_disk_read_throughput", 231 "rds050_disk_write_throughput", 232 "rds006_conn_count", 233 "rds008_qps", 234 "rds009_tps", 235 "rds013_innodb_reads", 236 "rds014_innodb_writes", 237 } 238 switch opts.Engine { 239 case api.DBINSTANCE_TYPE_POSTGRESQL: 240 dimesionName = "postgresql_cluster_id" 241 case api.DBINSTANCE_TYPE_SQLSERVER: 242 dimesionName = "rds_cluster_sqlserver_id" 243 } 244 245 for _, metricName := range metricNames { 246 metrics = append(metrics, map[string]interface{}{ 247 "namespace": namespace, 248 "metric_name": metricName, 249 "dimensions": []map[string]string{ 250 { 251 "name": dimesionName, 252 "value": opts.ResourceId, 253 }, 254 }, 255 }) 256 } 257 params["metrics"] = metrics 258 resp, err := self.monitorPost("batch-query-metric-data", params) 259 if err != nil { 260 return nil, err 261 } 262 metricData := []MetricData{} 263 err = resp.Unmarshal(&metricData, "metrics") 264 if err != nil { 265 return nil, errors.Wrapf(err, "resp.Unmarshal") 266 } 267 result := []cloudprovider.MetricValues{} 268 for i := range metricData { 269 ret := cloudprovider.MetricValues{ 270 Id: opts.ResourceId, 271 Unit: metricData[i].Unit, 272 Values: []cloudprovider.MetricValue{}, 273 } 274 tags := map[string]string{} 275 switch metricData[i].MetricName { 276 case "rds001_cpu_util": 277 ret.MetricType = cloudprovider.RDS_METRIC_TYPE_CPU_USAGE 278 case "rds002_mem_util": 279 ret.MetricType = cloudprovider.RDS_METRIC_TYPE_MEM_USAGE 280 case "rds004_bytes_in": 281 ret.MetricType = cloudprovider.RDS_METRIC_TYPE_NET_BPS_RX 282 case "rds005_bytes_out": 283 ret.MetricType = cloudprovider.RDS_METRIC_TYPE_NET_BPS_TX 284 case "rds039_disk_util": 285 ret.MetricType = cloudprovider.RDS_METRIC_TYPE_DISK_USAGE 286 case "rds049_disk_read_throughput": 287 ret.MetricType = cloudprovider.RDS_METRIC_TYPE_DISK_READ_BPS 288 case "rds050_disk_write_throughput": 289 ret.MetricType = cloudprovider.RDS_METRIC_TYPE_DISK_WRITE_BPS 290 case "rds006_conn_count": 291 ret.MetricType = cloudprovider.RDS_METRIC_TYPE_CONN_COUNT 292 case "rds008_qps": 293 ret.MetricType = cloudprovider.RDS_METRIC_TYPE_QPS 294 case "rds009_tps": 295 ret.MetricType = cloudprovider.RDS_METRIC_TYPE_TPS 296 case "rds013_innodb_reads": 297 ret.MetricType = cloudprovider.RDS_METRIC_TYPE_INNODB_READ_BPS 298 case "rds014_innodb_writes": 299 ret.MetricType = cloudprovider.RDS_METRIC_TYPE_INNODB_WRITE_BPS 300 default: 301 log.Warningf("invalid metricName %s for %s %s", metricData[i].MetricName, opts.ResourceType, opts.ResourceId) 302 continue 303 } 304 for _, value := range metricData[i].Datapoints { 305 metricValue := cloudprovider.MetricValue{ 306 Value: value.Average, 307 Timestamp: time.UnixMilli(value.Timestamp), 308 Tags: tags, 309 } 310 ret.Values = append(ret.Values, metricValue) 311 } 312 result = append(result, ret) 313 } 314 return result, nil 315 } 316 317 func (self *SHcsClient) getBucketMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { 318 params := map[string]interface{}{ 319 "from": opts.StartTime.UnixMilli(), 320 "to": opts.EndTime.UnixMilli(), 321 "period": "1", 322 "filter": "average", 323 } 324 metrics := []interface{}{} 325 namespace, dimesionName, metricNames := "SYS.OBS", "bucket_name", []string{ 326 "download_bytes", 327 "upload_bytes", 328 "first_byte_latency", 329 "get_request_count", 330 "request_count_4xx", 331 "request_count_5xx", 332 } 333 334 for _, metricName := range metricNames { 335 metrics = append(metrics, map[string]interface{}{ 336 "namespace": namespace, 337 "metric_name": metricName, 338 "dimensions": []map[string]string{ 339 { 340 "name": dimesionName, 341 "value": opts.ResourceId, 342 }, 343 }, 344 }) 345 } 346 params["metrics"] = metrics 347 resp, err := self.monitorPost("batch-query-metric-data", params) 348 if err != nil { 349 return nil, err 350 } 351 metricData := []MetricData{} 352 err = resp.Unmarshal(&metricData, "metrics") 353 if err != nil { 354 return nil, errors.Wrapf(err, "resp.Unmarshal") 355 } 356 result := []cloudprovider.MetricValues{} 357 for i := range metricData { 358 ret := cloudprovider.MetricValues{ 359 Id: opts.ResourceId, 360 Unit: metricData[i].Unit, 361 Values: []cloudprovider.MetricValue{}, 362 } 363 tags := map[string]string{} 364 switch metricData[i].MetricName { 365 case "download_bytes": 366 ret.MetricType = cloudprovider.BUCKET_METRIC_TYPE_NET_BPS_TX 367 case "upload_bytes": 368 ret.MetricType = cloudprovider.BUCKET_METRIC_TYPE_NET_BPS_RX 369 case "first_byte_latency": 370 ret.MetricType = cloudprovider.BUCKET_METRIC_TYPE_LATECY 371 tags = map[string]string{"request": "get"} 372 case "get_request_count": 373 ret.MetricType = cloudprovider.BUCKET_METRYC_TYPE_REQ_COUNT 374 tags = map[string]string{"request": "get"} 375 case "request_count_4xx": 376 ret.MetricType = cloudprovider.BUCKET_METRYC_TYPE_REQ_COUNT 377 tags = map[string]string{"request": "4xx"} 378 case "request_count_5xx": 379 ret.MetricType = cloudprovider.BUCKET_METRYC_TYPE_REQ_COUNT 380 tags = map[string]string{"request": "5xx"} 381 default: 382 log.Warningf("invalid metricName %s for %s %s", metricData[i].MetricName, opts.ResourceType, opts.ResourceId) 383 continue 384 } 385 for _, value := range metricData[i].Datapoints { 386 metricValue := cloudprovider.MetricValue{ 387 Value: value.Average, 388 Timestamp: time.UnixMilli(value.Timestamp), 389 Tags: tags, 390 } 391 ret.Values = append(ret.Values, metricValue) 392 } 393 result = append(result, ret) 394 } 395 return result, nil 396 } 397 398 func (self *SHcsClient) getLoadbalancerMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { 399 params := map[string]interface{}{ 400 "from": fmt.Sprintf("%d", opts.StartTime.UnixMilli()), 401 "to": fmt.Sprintf("%d", opts.EndTime.UnixMilli()), 402 "period": "1", 403 "filter": "average", 404 } 405 metrics := []interface{}{} 406 namespace, dimesionName, metricNames := "SYS.ELB", "lb_instance_id", []string{ 407 "m7_in_Bps", 408 "m8_out_Bps", 409 "mc_l7_http_2xx", 410 "md_l7_http_3xx", 411 "me_l7_http_4xx", 412 "mf_l7_http_5xx", 413 } 414 415 for _, metricName := range metricNames { 416 metrics = append(metrics, map[string]interface{}{ 417 "namespace": namespace, 418 "metric_name": metricName, 419 "dimensions": []map[string]string{ 420 { 421 "name": dimesionName, 422 "value": opts.ResourceId, 423 }, 424 }, 425 }) 426 } 427 params["metrics"] = metrics 428 resp, err := self.monitorPost("batch-query-metric-data", params) 429 if err != nil { 430 return nil, err 431 } 432 metricData := []MetricData{} 433 err = resp.Unmarshal(&metricData, "metrics") 434 if err != nil { 435 return nil, errors.Wrapf(err, "resp.Unmarshal") 436 } 437 result := []cloudprovider.MetricValues{} 438 for i := range metricData { 439 ret := cloudprovider.MetricValues{ 440 Id: opts.ResourceId, 441 Unit: metricData[i].Unit, 442 Values: []cloudprovider.MetricValue{}, 443 } 444 tags := map[string]string{} 445 switch metricData[i].MetricName { 446 case "m7_in_Bps": 447 ret.MetricType = cloudprovider.LB_METRIC_TYPE_NET_BPS_RX 448 case "m8_out_Bps": 449 ret.MetricType = cloudprovider.LB_METRIC_TYPE_NET_BPS_TX 450 case "mc_l7_http_2xx": 451 ret.MetricType = cloudprovider.LB_METRIC_TYPE_HRSP_COUNT 452 tags = map[string]string{"request": "2xx"} 453 case "md_l7_http_3xx": 454 ret.MetricType = cloudprovider.LB_METRIC_TYPE_HRSP_COUNT 455 tags = map[string]string{"request": "3xx"} 456 case "md_l7_http_4xx": 457 ret.MetricType = cloudprovider.LB_METRIC_TYPE_HRSP_COUNT 458 tags = map[string]string{"request": "4xx"} 459 case "md_l7_http_5xx": 460 ret.MetricType = cloudprovider.LB_METRIC_TYPE_HRSP_COUNT 461 tags = map[string]string{"request": "5xx"} 462 default: 463 log.Warningf("invalid metricName %s for %s %s", metricData[i].MetricName, opts.ResourceType, opts.ResourceId) 464 continue 465 } 466 for _, value := range metricData[i].Datapoints { 467 metricValue := cloudprovider.MetricValue{ 468 Value: value.Average, 469 Timestamp: time.UnixMilli(value.Timestamp), 470 Tags: tags, 471 } 472 ret.Values = append(ret.Values, metricValue) 473 } 474 result = append(result, ret) 475 } 476 return result, nil 477 } 478 479 func (self *SHcsClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { 480 switch opts.ResourceType { 481 case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: 482 return self.getServerMetrics(opts) 483 case cloudprovider.METRIC_RESOURCE_TYPE_REDIS: 484 return self.getRedisMetrics(opts) 485 case cloudprovider.METRIC_RESOURCE_TYPE_RDS: 486 return self.getRdsMetrics(opts) 487 case cloudprovider.METRIC_RESOURCE_TYPE_BUCKET: 488 return self.getBucketMetrics(opts) 489 case cloudprovider.METRIC_RESOURCE_TYPE_LB: 490 return self.getLoadbalancerMetrics(opts) 491 default: 492 return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "%s", opts.ResourceType) 493 } 494 }