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