yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/aliyun/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 aliyun
    16  
    17  import (
    18  	"fmt"
    19  	"strconv"
    20  	"strings"
    21  	"time"
    22  
    23  	"yunion.io/x/jsonutils"
    24  	"yunion.io/x/log"
    25  	"yunion.io/x/pkg/errors"
    26  
    27  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    28  )
    29  
    30  const (
    31  	ALIYUN_API_VERSION_METRICS = "2019-01-01"
    32  )
    33  
    34  func (r *SRegion) metricsRequest(action string, params map[string]string) (jsonutils.JSONObject, error) {
    35  	return r.client.metricsRequest(action, params)
    36  }
    37  
    38  func (self *SAliyunClient) metricsRequest(action string, params map[string]string) (jsonutils.JSONObject, error) {
    39  	client, err := self.getSdkClient("")
    40  	if err != nil {
    41  		return nil, errors.Wrap(err, "self.getSdkClient")
    42  	}
    43  	return jsonRequest(client, "metrics.aliyuncs.com", ALIYUN_API_VERSION_METRICS, action, params, self.debug)
    44  }
    45  
    46  type SResourceLabel struct {
    47  	Name  string `json:"name"`
    48  	Value string `json:"value"`
    49  }
    50  
    51  type SResource struct {
    52  	Description string `json:"Description"`
    53  	Labels      string `json:"Labels"`
    54  	Namespace   string `json:"Namespace"`
    55  }
    56  
    57  func (r *SRegion) DescribeProjectMeta(limit, offset int) (int, []SResource, error) {
    58  	params := make(map[string]string)
    59  	if limit <= 0 {
    60  		limit = 30
    61  	}
    62  	params["PageSize"] = strconv.FormatInt(int64(limit), 10)
    63  	if offset > 0 {
    64  		pageNum := (offset / limit) + 1
    65  		params["PageNumber"] = strconv.FormatInt(int64(pageNum), 10)
    66  	}
    67  	body, err := r.metricsRequest("DescribeProjectMeta", params)
    68  	if err != nil {
    69  		return 0, nil, errors.Wrap(err, "r.metricsRequest DescribeProjectMeta")
    70  	}
    71  	total, _ := body.Int("Total")
    72  	res := make([]SResource, 0)
    73  	err = body.Unmarshal(&res, "Resources", "Resource")
    74  	if err != nil {
    75  		return 0, nil, errors.Wrap(err, "body.Unmarshal Resources Resource")
    76  	}
    77  	return int(total), res, nil
    78  }
    79  
    80  func (r *SRegion) FetchNamespaces() ([]SResource, error) {
    81  	resources := make([]SResource, 0)
    82  	total := -1
    83  	for total < 0 || len(resources) < total {
    84  		ntotal, res, err := r.DescribeProjectMeta(1000, len(resources))
    85  		if err != nil {
    86  			return nil, errors.Wrap(err, "r.DescribeProjectMeta")
    87  		}
    88  		if len(res) == 0 {
    89  			break
    90  		}
    91  		resources = append(resources, res...)
    92  		total = ntotal
    93  	}
    94  	return resources, nil
    95  }
    96  
    97  type SMetricMeta struct {
    98  	Description string `json:"Description"`
    99  	MetricName  string `json:"MetricName"`
   100  	Statistics  string `json:"Statistics"`
   101  	Labels      string `json:"Labels"`
   102  	Dimensions  string `json:"Dimensions"`
   103  	Namespace   string `json:"Namespace"`
   104  	Periods     string `json:"Periods"`
   105  	Unit        string `json:"Unit"`
   106  }
   107  
   108  func (r *SRegion) DescribeMetricMetaList(ns string, limit, offset int) (int, []SMetricMeta, error) {
   109  	params := make(map[string]string)
   110  	if limit <= 0 {
   111  		limit = 30
   112  	}
   113  	params["Namespace"] = ns
   114  	params["PageSize"] = strconv.FormatInt(int64(limit), 10)
   115  	if offset > 0 {
   116  		pageNum := (offset / limit) + 1
   117  		params["PageNumber"] = strconv.FormatInt(int64(pageNum), 10)
   118  	}
   119  	body, err := r.metricsRequest("DescribeMetricMetaList", params)
   120  	if err != nil {
   121  		return 0, nil, errors.Wrap(err, "r.metricsRequest DescribeMetricMetaList")
   122  	}
   123  	total, _ := body.Int("TotalCount")
   124  	res := make([]SMetricMeta, 0)
   125  	err = body.Unmarshal(&res, "Resources", "Resource")
   126  	if err != nil {
   127  		return 0, nil, errors.Wrap(err, "body.Unmarshal Resources Resource")
   128  	}
   129  	return int(total), res, nil
   130  }
   131  
   132  func (r *SRegion) FetchMetrics(ns string) ([]SMetricMeta, error) {
   133  	metrics := make([]SMetricMeta, 0)
   134  	total := -1
   135  	for total < 0 || len(metrics) < total {
   136  		ntotal, res, err := r.DescribeMetricMetaList(ns, 1000, len(metrics))
   137  		if err != nil {
   138  			return nil, errors.Wrap(err, "r.DescribeMetricMetaList")
   139  		}
   140  		if len(res) == 0 {
   141  			break
   142  		}
   143  		metrics = append(metrics, res...)
   144  		total = ntotal
   145  	}
   146  	return metrics, nil
   147  }
   148  
   149  func (r *SRegion) DescribeMetricList(name string, ns string, since time.Time, until time.Time, nextToken string, dimensions []SResourceLabel) ([]jsonutils.JSONObject, string, error) {
   150  	params := make(map[string]string)
   151  	params["MetricName"] = name
   152  	params["Namespace"] = ns
   153  	params["Length"] = "2000"
   154  	if len(nextToken) > 0 {
   155  		params["NextToken"] = nextToken
   156  	}
   157  	if !since.IsZero() {
   158  		params["StartTime"] = strconv.FormatInt(since.Unix()*1000, 10)
   159  	}
   160  	if !until.IsZero() {
   161  		params["EndTime"] = strconv.FormatInt(until.Unix()*1000, 10)
   162  	}
   163  	if len(dimensions) > 0 {
   164  		for _, dimension := range dimensions {
   165  			params[dimension.Name] = dimension.Value
   166  		}
   167  	}
   168  	body, err := r.metricsRequest("DescribeMetricList", params)
   169  	if err != nil {
   170  		return nil, "", errors.Wrap(err, "region.MetricRequest")
   171  	}
   172  	nToken, _ := body.GetString("NextToken")
   173  	dataStr, _ := body.GetString("Datapoints")
   174  	if len(dataStr) == 0 {
   175  		return nil, "", nil
   176  	}
   177  	dataJson, err := jsonutils.ParseString(dataStr)
   178  	if err != nil {
   179  		return nil, "", errors.Wrap(err, "jsonutils.ParseString")
   180  	}
   181  	dataArray, err := dataJson.GetArray()
   182  	if err != nil {
   183  		return nil, "", errors.Wrap(err, "dataJson.GetArray")
   184  	}
   185  	return dataArray, nToken, nil
   186  }
   187  
   188  type MetricData struct {
   189  	Timestamp  int64
   190  	BucketName string
   191  	InstanceId string
   192  	UserId     string
   193  	Value      float64
   194  	Average    float64
   195  	Minimum    float64
   196  	Maximum    float64
   197  
   198  	Diskname string
   199  	Device   string
   200  
   201  	// k8s
   202  	Cluster string
   203  	Node    string
   204  	Pod     string
   205  }
   206  
   207  func (d MetricData) GetValue() float64 {
   208  	if d.Average > 0 {
   209  		return d.Average
   210  	}
   211  	if d.Maximum > 0 {
   212  		return d.Maximum
   213  	}
   214  	if d.Minimum > 0 {
   215  		return d.Minimum
   216  	}
   217  	if d.Value > 0 {
   218  		return d.Value
   219  	}
   220  	return 0.0
   221  }
   222  
   223  func (d MetricData) GetTags() map[string]string {
   224  	ret := map[string]string{}
   225  	if len(d.Device) > 0 {
   226  		ret[cloudprovider.METRIC_TAG_DEVICE] = fmt.Sprintf("%s(%s)", d.Device, d.Diskname)
   227  	}
   228  	return ret
   229  }
   230  
   231  func (self *SAliyunClient) ListMetrics(ns, metricName string, start, end time.Time) ([]MetricData, error) {
   232  	result := []MetricData{}
   233  	nextToken := ""
   234  	for {
   235  		part, next, err := self.listMetrics(ns, metricName, nextToken, start, end)
   236  		if err != nil {
   237  			return nil, errors.Wrap(err, "listMetrics")
   238  		}
   239  		result = append(result, part...)
   240  		if len(next) == 0 {
   241  			break
   242  		}
   243  		nextToken = next
   244  	}
   245  	return result, nil
   246  }
   247  
   248  func (self *SAliyunClient) listMetrics(ns, metricName, nextToken string, start, end time.Time) ([]MetricData, string, error) {
   249  	params := make(map[string]string)
   250  	params["MetricName"] = metricName
   251  	params["Namespace"] = ns
   252  	params["Length"] = "2000"
   253  	if len(nextToken) > 0 {
   254  		params["NextToken"] = nextToken
   255  	}
   256  	params["StartTime"] = fmt.Sprintf("%d", start.UnixMilli())
   257  	params["EndTime"] = fmt.Sprintf("%d", end.UnixMilli())
   258  	resp, err := self.metricsRequest("DescribeMetricList", params)
   259  	if err != nil {
   260  		return nil, "", errors.Wrap(err, "DescribeMetricList")
   261  	}
   262  	ret := struct {
   263  		NextToken  string
   264  		Datapoints string
   265  	}{}
   266  	err = resp.Unmarshal(&ret)
   267  	if err != nil {
   268  		return nil, "", errors.Wrapf(err, "resp.Unmarshal")
   269  	}
   270  	obj, err := jsonutils.ParseString(ret.Datapoints)
   271  	if err != nil {
   272  		return nil, "", errors.Wrap(err, "jsonutils.ParseString")
   273  	}
   274  	result := []MetricData{}
   275  	err = obj.Unmarshal(&result)
   276  	if err != nil {
   277  		return nil, "", errors.Wrapf(err, "obj.Unmarshal")
   278  	}
   279  	return result, ret.NextToken, nil
   280  }
   281  
   282  func (r *SRegion) FetchMetricData(name string, ns string, since time.Time, until time.Time) ([]jsonutils.JSONObject, error) {
   283  	data := make([]jsonutils.JSONObject, 0)
   284  	nextToken := ""
   285  	for {
   286  		datArray, next, err := r.DescribeMetricList(name, ns, since, until, nextToken, nil)
   287  		if err != nil {
   288  			return nil, errors.Wrap(err, "r.DescribeMetricList")
   289  		}
   290  		data = append(data, datArray...)
   291  		if len(next) == 0 {
   292  			break
   293  		}
   294  		nextToken = next
   295  	}
   296  	return data, nil
   297  }
   298  
   299  func (self *SAliyunClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) {
   300  	switch opts.ResourceType {
   301  	case cloudprovider.METRIC_RESOURCE_TYPE_SERVER:
   302  		return self.GetEcsMetrics(opts)
   303  	case cloudprovider.METRIC_RESOURCE_TYPE_BUCKET:
   304  		return self.GetOssMetrics(opts)
   305  	case cloudprovider.METRIC_RESOURCE_TYPE_REDIS:
   306  		return self.GetRedisMetrics(opts)
   307  	case cloudprovider.METRIC_RESOURCE_TYPE_RDS:
   308  		return self.GetRdsMetrics(opts)
   309  	case cloudprovider.METRIC_RESOURCE_TYPE_LB:
   310  		return self.GetElbMetrics(opts)
   311  	case cloudprovider.METRIC_RESOURCE_TYPE_K8S:
   312  		return self.GetK8sMetrics(opts)
   313  	default:
   314  		return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.ResourceType)
   315  	}
   316  }
   317  
   318  func (self *SAliyunClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) {
   319  	metricTags, tagKey := map[string]string{}, ""
   320  	switch opts.MetricType {
   321  	case cloudprovider.VM_METRIC_TYPE_CPU_USAGE:
   322  		metricTags = map[string]string{
   323  			"CPUUtilization": "",
   324  		}
   325  	case cloudprovider.VM_METRIC_TYPE_NET_BPS_RX:
   326  		metricTags = map[string]string{
   327  			"InternetInRate": cloudprovider.METRIC_TAG_NET_TYPE_INTERNET,
   328  			"IntranetInRate": cloudprovider.METRIC_TAG_NET_TYPE_INTRANET,
   329  		}
   330  		tagKey = cloudprovider.METRIC_TAG_NET_TYPE
   331  	case cloudprovider.VM_METRIC_TYPE_NET_BPS_TX:
   332  		metricTags = map[string]string{
   333  			"InternetOutRate": cloudprovider.METRIC_TAG_NET_TYPE_INTERNET,
   334  			"IntranetOutRate": cloudprovider.METRIC_TAG_NET_TYPE_INTRANET,
   335  		}
   336  		tagKey = cloudprovider.METRIC_TAG_NET_TYPE
   337  	case cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS:
   338  		metricTags = map[string]string{
   339  			"DiskReadBPS": "",
   340  		}
   341  	case cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS:
   342  		metricTags = map[string]string{
   343  			"DiskWriteBPS": "",
   344  		}
   345  	case cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS:
   346  		metricTags = map[string]string{
   347  			"DiskReadIOPS": "",
   348  		}
   349  	case cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS:
   350  		metricTags = map[string]string{
   351  			"DiskWriteIOPS": "",
   352  		}
   353  	case cloudprovider.VM_METRIC_TYPE_MEM_USAGE:
   354  		metricTags = map[string]string{
   355  			"memory_usedutilization": "",
   356  		}
   357  	case cloudprovider.VM_METRIC_TYPE_DISK_USAGE:
   358  		metricTags = map[string]string{
   359  			"diskusage_utilization": "",
   360  		}
   361  	default:
   362  		return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType)
   363  	}
   364  	ret := []cloudprovider.MetricValues{}
   365  	for metric, tag := range metricTags {
   366  		result, err := self.ListMetrics("acs_ecs_dashboard", metric, opts.StartTime, opts.EndTime)
   367  		if err != nil {
   368  			log.Errorf("ListMetric(%s) error: %v", metric, err)
   369  			continue
   370  		}
   371  		tags := map[string]string{}
   372  		if len(tag) > 0 && len(tagKey) > 0 {
   373  			tags[tagKey] = tag
   374  		}
   375  		for i := range result {
   376  			dataTag := result[i].GetTags()
   377  			for k, v := range tags {
   378  				dataTag[k] = v
   379  			}
   380  			ret = append(ret, cloudprovider.MetricValues{
   381  				Id:         result[i].InstanceId,
   382  				MetricType: opts.MetricType,
   383  				Values: []cloudprovider.MetricValue{
   384  					{
   385  						Timestamp: time.UnixMilli(result[i].Timestamp),
   386  						Value:     result[i].GetValue(),
   387  						Tags:      dataTag,
   388  					},
   389  				},
   390  			})
   391  		}
   392  	}
   393  	return ret, nil
   394  }
   395  
   396  func (self *SAliyunClient) GetOssMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) {
   397  	metricTags, tagKey := map[string]string{}, ""
   398  	switch opts.MetricType {
   399  	case cloudprovider.BUCKET_METRIC_TYPE_LATECY:
   400  		metricTags = map[string]string{
   401  			"GetObjectE2eLatency":  cloudprovider.METRIC_TAG_REQUST_GET,
   402  			"PostObjectE2eLatency": cloudprovider.METRIC_TAG_REQUST_GET,
   403  		}
   404  		tagKey = cloudprovider.METRIC_TAG_REQUST
   405  	case cloudprovider.BUCKET_METRIC_TYPE_NET_BPS_TX:
   406  		metricTags = map[string]string{
   407  			"InternetSend": cloudprovider.METRIC_TAG_NET_TYPE_INTERNET,
   408  			"IntranetSend": cloudprovider.METRIC_TAG_NET_TYPE_INTRANET,
   409  		}
   410  		tagKey = cloudprovider.METRIC_TAG_REQUST
   411  	case cloudprovider.BUCKET_METRIC_TYPE_NET_BPS_RX:
   412  		metricTags = map[string]string{
   413  			"InternetRecv": cloudprovider.METRIC_TAG_NET_TYPE_INTERNET,
   414  			"IntranetRecv": cloudprovider.METRIC_TAG_NET_TYPE_INTRANET,
   415  		}
   416  		tagKey = cloudprovider.METRIC_TAG_NET_TYPE
   417  	case cloudprovider.BUCKET_METRYC_TYPE_REQ_COUNT:
   418  		metricTags = map[string]string{
   419  			"GetObjectCount":   cloudprovider.METRIC_TAG_REQUST_GET,
   420  			"PostObjectCount":  cloudprovider.METRIC_TAG_REQUST_POST,
   421  			"ServerErrorCount": cloudprovider.METRIC_TAG_REQUST_5XX,
   422  		}
   423  		tagKey = cloudprovider.METRIC_TAG_REQUST
   424  	default:
   425  		return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType)
   426  	}
   427  	ret := []cloudprovider.MetricValues{}
   428  	for metric, tag := range metricTags {
   429  		result, err := self.ListMetrics("acs_oss_dashboard", metric, opts.StartTime, opts.EndTime)
   430  		if err != nil {
   431  			log.Errorf("ListMetric(%s) error: %v", metric, err)
   432  			continue
   433  		}
   434  		for i := range result {
   435  			ret = append(ret, cloudprovider.MetricValues{
   436  				Id:         result[i].BucketName,
   437  				MetricType: opts.MetricType,
   438  				Values: []cloudprovider.MetricValue{
   439  					{
   440  						Timestamp: time.UnixMilli(result[i].Timestamp),
   441  						Value:     result[i].GetValue(),
   442  						Tags: map[string]string{
   443  							tagKey: tag,
   444  						},
   445  					},
   446  				},
   447  			})
   448  		}
   449  	}
   450  	return ret, nil
   451  }
   452  
   453  func (self *SAliyunClient) GetRedisMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) {
   454  	metrics := map[cloudprovider.TMetricType]string{
   455  		cloudprovider.REDIS_METRIC_TYPE_CPU_USAGE:      "CpuUsage",
   456  		cloudprovider.REDIS_METRIC_TYPE_MEM_USAGE:      "MemoryUsage",
   457  		cloudprovider.REDIS_METRIC_TYPE_NET_BPS_RX:     "IntranetIn",
   458  		cloudprovider.REDIS_METRIC_TYPE_NET_BPS_TX:     "IntranetOut",
   459  		cloudprovider.REDIS_METRIC_TYPE_USED_CONN:      "UsedConnection",
   460  		cloudprovider.REDIS_METRIC_TYPE_OPT_SES:        "UsedQPS",
   461  		cloudprovider.REDIS_METRIC_TYPE_CACHE_KEYS:     "StandardKeys",
   462  		cloudprovider.REDIS_METRIC_TYPE_DATA_MEM_USAGE: "UsedMemory",
   463  	}
   464  	metric, ok := metrics[opts.MetricType]
   465  	if !ok {
   466  		return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType)
   467  	}
   468  	ret := []cloudprovider.MetricValues{}
   469  	result, err := self.ListMetrics("acs_kvstore", metric, opts.StartTime, opts.EndTime)
   470  	if err != nil {
   471  		return nil, errors.Wrapf(err, "ListMetric(%s)", metric)
   472  	}
   473  	for i := range result {
   474  		tags := map[string]string{}
   475  		if strings.Contains(result[i].InstanceId, "-db-") {
   476  			tags[cloudprovider.METRIC_TAG_NODE] = result[i].InstanceId
   477  			idx := strings.Index(result[i].InstanceId, "-db-")
   478  			result[i].InstanceId = result[i].InstanceId[:idx]
   479  		}
   480  		value := cloudprovider.MetricValues{
   481  			Id:         result[i].InstanceId,
   482  			MetricType: opts.MetricType,
   483  			Values: []cloudprovider.MetricValue{
   484  				{
   485  					Timestamp: time.UnixMilli(result[i].Timestamp),
   486  					Value:     result[i].GetValue(),
   487  					Tags:      tags,
   488  				},
   489  			},
   490  		}
   491  		ret = append(ret, value)
   492  	}
   493  	return ret, nil
   494  }
   495  
   496  func (self *SAliyunClient) GetRdsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) {
   497  	metricTags := map[string]string{}
   498  	switch opts.MetricType {
   499  	case cloudprovider.RDS_METRIC_TYPE_CPU_USAGE:
   500  		metricTags = map[string]string{
   501  			"CpuUsage": "",
   502  		}
   503  	case cloudprovider.RDS_METRIC_TYPE_MEM_USAGE:
   504  		metricTags = map[string]string{
   505  			"MemoryUsage": "",
   506  		}
   507  	case cloudprovider.RDS_METRIC_TYPE_NET_BPS_RX:
   508  		metricTags = map[string]string{
   509  			"MySQL_NetworkInNew":     "",
   510  			"SQLServer_NetworkInNew": "",
   511  		}
   512  	case cloudprovider.RDS_METRIC_TYPE_NET_BPS_TX:
   513  		metricTags = map[string]string{
   514  			"MySQL_NetworkOutNew":     "",
   515  			"SQLServer_NetworkOutNew": "",
   516  		}
   517  	case cloudprovider.RDS_METRIC_TYPE_DISK_USAGE:
   518  		metricTags = map[string]string{
   519  			"DiskUsage": "",
   520  		}
   521  	case cloudprovider.RDS_METRIC_TYPE_CONN_USAGE:
   522  		metricTags = map[string]string{
   523  			"ConnectionUsage": "",
   524  		}
   525  	default:
   526  		return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType)
   527  	}
   528  	ret := []cloudprovider.MetricValues{}
   529  	for metric := range metricTags {
   530  		result, err := self.ListMetrics("acs_rds_dashboard", metric, opts.StartTime, opts.EndTime)
   531  		if err != nil {
   532  			log.Errorf("ListMetric(%s) error: %v", metric, err)
   533  			continue
   534  		}
   535  		for i := range result {
   536  			ret = append(ret, cloudprovider.MetricValues{
   537  				Id:         result[i].InstanceId,
   538  				MetricType: opts.MetricType,
   539  				Values: []cloudprovider.MetricValue{
   540  					{
   541  						Timestamp: time.UnixMilli(result[i].Timestamp),
   542  						Value:     result[i].GetValue(),
   543  					},
   544  				},
   545  			})
   546  		}
   547  	}
   548  	return ret, nil
   549  }
   550  
   551  func (self *SAliyunClient) GetElbMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) {
   552  	metricTags, tagKey := map[string]string{}, ""
   553  	switch opts.MetricType {
   554  	case cloudprovider.LB_METRIC_TYPE_NET_BPS_RX:
   555  		metricTags = map[string]string{
   556  			"InstanceTrafficRX": "",
   557  		}
   558  	case cloudprovider.LB_METRIC_TYPE_NET_BPS_TX:
   559  		metricTags = map[string]string{
   560  			"InstanceTrafficTX": "",
   561  		}
   562  	case cloudprovider.LB_METRIC_TYPE_HRSP_COUNT:
   563  		metricTags = map[string]string{
   564  			"InstanceStatusCode2xx": cloudprovider.METRIC_TAG_REQUST_2XX,
   565  			"InstanceStatusCode3xx": cloudprovider.METRIC_TAG_REQUST_3XX,
   566  			"InstanceStatusCode4xx": cloudprovider.METRIC_TAG_REQUST_4XX,
   567  			"InstanceStatusCode5xx": cloudprovider.METRIC_TAG_REQUST_5XX,
   568  		}
   569  		tagKey = cloudprovider.METRIC_TAG_REQUST
   570  	default:
   571  		return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType)
   572  	}
   573  	ret := []cloudprovider.MetricValues{}
   574  	for metric, tag := range metricTags {
   575  		result, err := self.ListMetrics("acs_slb_dashboard", metric, opts.StartTime, opts.EndTime)
   576  		if err != nil {
   577  			log.Errorf("ListMetric(%s) error: %v", metric, err)
   578  			continue
   579  		}
   580  		tags := map[string]string{}
   581  		if len(tag) > 0 && len(tagKey) > 0 {
   582  			tags[tagKey] = tag
   583  		}
   584  		for i := range result {
   585  			ret = append(ret, cloudprovider.MetricValues{
   586  				Id:         result[i].InstanceId,
   587  				MetricType: opts.MetricType,
   588  				Values: []cloudprovider.MetricValue{
   589  					{
   590  						Timestamp: time.UnixMilli(result[i].Timestamp),
   591  						Value:     result[i].GetValue(),
   592  						Tags:      tags,
   593  					},
   594  				},
   595  			})
   596  		}
   597  	}
   598  	return ret, nil
   599  }
   600  
   601  func (self *SAliyunClient) GetK8sMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) {
   602  	metricName := ""
   603  	switch opts.MetricType {
   604  	case cloudprovider.K8S_NODE_METRIC_TYPE_CPU_USAGE:
   605  		metricName = "node.cpu.utilization"
   606  	case cloudprovider.K8S_NODE_METRIC_TYPE_MEM_USAGE:
   607  		metricName = "node.memory.utilization"
   608  	default:
   609  		return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType)
   610  	}
   611  	result, err := self.ListMetrics("acs_k8s", metricName, opts.StartTime, opts.EndTime)
   612  	if err != nil {
   613  		return nil, errors.Wrapf(err, "ListMetrics(%s)", metricName)
   614  	}
   615  	ret := []cloudprovider.MetricValues{}
   616  	for i := range result {
   617  		tags := map[string]string{}
   618  		if len(result[i].Node) > 0 {
   619  			tags[cloudprovider.METRIC_TAG_NODE] = result[i].Node
   620  		}
   621  		ret = append(ret, cloudprovider.MetricValues{
   622  			Id:         result[i].Cluster,
   623  			MetricType: opts.MetricType,
   624  			Values: []cloudprovider.MetricValue{
   625  				{
   626  					Timestamp: time.UnixMilli(result[i].Timestamp),
   627  					Value:     result[i].GetValue(),
   628  					Tags:      tags,
   629  				},
   630  			},
   631  		})
   632  	}
   633  	return ret, nil
   634  }