yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/apsara/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 apsara
    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  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    26  )
    27  
    28  const (
    29  	APSARA_API_VERSION_METRICS = "2019-01-01"
    30  )
    31  
    32  func (self *SApsaraClient) metricsRequest(action string, params map[string]string) (jsonutils.JSONObject, error) {
    33  	client, err := self.getDefaultClient("")
    34  	if err != nil {
    35  		return nil, errors.Wrap(err, "getDefaultClient")
    36  	}
    37  	domain := self.getDomain(APSARA_PRODUCT_METRICS)
    38  	return productRequest(client, APSARA_PRODUCT_METRICS, domain, APSARA_API_VERSION_METRICS, action, params, self.debug)
    39  }
    40  
    41  type MetricData struct {
    42  	Timestamp  int64
    43  	BucketName string
    44  	InstanceId string
    45  	UserId     string
    46  	Value      float64
    47  	Average    float64
    48  	Minimum    float64
    49  	Maximum    float64
    50  	Diskname   string
    51  	Device     string
    52  }
    53  
    54  func (d MetricData) GetValue() float64 {
    55  	if d.Average > 0 {
    56  		return d.Average
    57  	}
    58  	if d.Maximum > 0 {
    59  		return d.Maximum
    60  	}
    61  	if d.Minimum > 0 {
    62  		return d.Minimum
    63  	}
    64  	if d.Value > 0 {
    65  		return d.Value
    66  	}
    67  	return 0.0
    68  }
    69  
    70  func (d MetricData) GetTags() map[string]string {
    71  	ret := map[string]string{}
    72  	if len(d.Device) > 0 {
    73  		ret[cloudprovider.METRIC_TAG_DEVICE] = fmt.Sprintf("%s(%s)", d.Device, d.Diskname)
    74  	}
    75  	return ret
    76  }
    77  
    78  func (self *SApsaraClient) ListMetrics(ns, metricName string, start, end time.Time) ([]MetricData, error) {
    79  	result := []MetricData{}
    80  	nextToken := ""
    81  	for {
    82  		part, next, err := self.listMetrics(ns, metricName, nextToken, start, end)
    83  		if err != nil {
    84  			return nil, errors.Wrap(err, "listMetrics")
    85  		}
    86  		result = append(result, part...)
    87  		if len(next) == 0 {
    88  			break
    89  		}
    90  		nextToken = next
    91  	}
    92  	return result, nil
    93  }
    94  
    95  func (self *SApsaraClient) listMetrics(ns, metricName, nextToken string, start, end time.Time) ([]MetricData, string, error) {
    96  	params := make(map[string]string)
    97  	params["MetricName"] = metricName
    98  	params["Namespace"] = ns
    99  	params["Length"] = "2000"
   100  	if len(nextToken) > 0 {
   101  		params["NextToken"] = nextToken
   102  	}
   103  	if len(self.organizationId) > 0 {
   104  		params["Department"] = self.organizationId
   105  	}
   106  	params["StartTime"] = fmt.Sprintf("%d", start.UnixMilli())
   107  	params["EndTime"] = fmt.Sprintf("%d", end.UnixMilli())
   108  	resp, err := self.metricsRequest("DescribeMetricList", params)
   109  	if err != nil {
   110  		return nil, "", errors.Wrap(err, "DescribeMetricList")
   111  	}
   112  	ret := struct {
   113  		NextToken  string
   114  		Datapoints string
   115  	}{}
   116  	err = resp.Unmarshal(&ret)
   117  	if err != nil {
   118  		return nil, "", errors.Wrapf(err, "resp.Unmarshal")
   119  	}
   120  	obj, err := jsonutils.ParseString(ret.Datapoints)
   121  	if err != nil {
   122  		return nil, "", errors.Wrap(err, "jsonutils.ParseString")
   123  	}
   124  	result := []MetricData{}
   125  	err = obj.Unmarshal(&result)
   126  	if err != nil {
   127  		return nil, "", errors.Wrapf(err, "obj.Unmarshal")
   128  	}
   129  	return result, ret.NextToken, nil
   130  }
   131  
   132  func (self *SApsaraClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) {
   133  	switch opts.ResourceType {
   134  	case cloudprovider.METRIC_RESOURCE_TYPE_SERVER:
   135  		return self.GetEcsMetrics(opts)
   136  	case cloudprovider.METRIC_RESOURCE_TYPE_BUCKET:
   137  		return self.GetOssMetrics(opts)
   138  	case cloudprovider.METRIC_RESOURCE_TYPE_REDIS:
   139  		return self.GetRedisMetrics(opts)
   140  	case cloudprovider.METRIC_RESOURCE_TYPE_RDS:
   141  		return self.GetRdsMetrics(opts)
   142  	case cloudprovider.METRIC_RESOURCE_TYPE_LB:
   143  		return self.GetElbMetrics(opts)
   144  	default:
   145  		return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.ResourceType)
   146  	}
   147  }
   148  
   149  func (self *SApsaraClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) {
   150  	metricTags, tagKey := map[string]string{}, ""
   151  	switch opts.MetricType {
   152  	case cloudprovider.VM_METRIC_TYPE_CPU_USAGE:
   153  		metricTags = map[string]string{
   154  			"CPUUtilization": "",
   155  		}
   156  	case cloudprovider.VM_METRIC_TYPE_NET_BPS_RX:
   157  		metricTags = map[string]string{
   158  			"InternetInRate": cloudprovider.METRIC_TAG_NET_TYPE_INTERNET,
   159  			"IntranetInRate": cloudprovider.METRIC_TAG_NET_TYPE_INTRANET,
   160  		}
   161  		tagKey = cloudprovider.METRIC_TAG_NET_TYPE
   162  	case cloudprovider.VM_METRIC_TYPE_NET_BPS_TX:
   163  		metricTags = map[string]string{
   164  			"InternetOutRate": cloudprovider.METRIC_TAG_NET_TYPE_INTERNET,
   165  			"IntranetOutRate": cloudprovider.METRIC_TAG_NET_TYPE_INTRANET,
   166  		}
   167  		tagKey = cloudprovider.METRIC_TAG_NET_TYPE
   168  	case cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS:
   169  		metricTags = map[string]string{
   170  			"DiskReadBPS": "",
   171  		}
   172  	case cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS:
   173  		metricTags = map[string]string{
   174  			"DiskWriteBPS": "",
   175  		}
   176  	case cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS:
   177  		metricTags = map[string]string{
   178  			"DiskReadIOPS": "",
   179  		}
   180  	case cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS:
   181  		metricTags = map[string]string{
   182  			"DiskWriteIOPS": "",
   183  		}
   184  	case cloudprovider.VM_METRIC_TYPE_MEM_USAGE:
   185  		metricTags = map[string]string{
   186  			"memory_usedutilization": "",
   187  		}
   188  	case cloudprovider.VM_METRIC_TYPE_DISK_USAGE:
   189  		metricTags = map[string]string{
   190  			"diskusage_utilization": "",
   191  		}
   192  	default:
   193  		return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType)
   194  	}
   195  	ret := []cloudprovider.MetricValues{}
   196  	for metric, tag := range metricTags {
   197  		result, err := self.ListMetrics("acs_ecs_dashboard", metric, opts.StartTime, opts.EndTime)
   198  		if err != nil {
   199  			log.Errorf("ListMetric(%s) error: %v", metric, err)
   200  			continue
   201  		}
   202  		tags := map[string]string{}
   203  		if len(tag) > 0 && len(tagKey) > 0 {
   204  			tags[tagKey] = tag
   205  		}
   206  		for i := range result {
   207  			dataTag := result[i].GetTags()
   208  			for k, v := range tags {
   209  				dataTag[k] = v
   210  			}
   211  			ret = append(ret, cloudprovider.MetricValues{
   212  				Id:         result[i].InstanceId,
   213  				MetricType: opts.MetricType,
   214  				Values: []cloudprovider.MetricValue{
   215  					{
   216  						Timestamp: time.UnixMilli(result[i].Timestamp),
   217  						Value:     result[i].GetValue(),
   218  						Tags:      dataTag,
   219  					},
   220  				},
   221  			})
   222  		}
   223  	}
   224  	return ret, nil
   225  }
   226  
   227  func (self *SApsaraClient) GetOssMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) {
   228  	metricTags, tagKey := map[string]string{}, ""
   229  	switch opts.MetricType {
   230  	case cloudprovider.BUCKET_METRIC_TYPE_LATECY:
   231  		metricTags = map[string]string{
   232  			"GetObjectE2eLatency":  cloudprovider.METRIC_TAG_REQUST_GET,
   233  			"PostObjectE2eLatency": cloudprovider.METRIC_TAG_REQUST_GET,
   234  		}
   235  		tagKey = cloudprovider.METRIC_TAG_REQUST
   236  	case cloudprovider.BUCKET_METRIC_TYPE_NET_BPS_TX:
   237  		metricTags = map[string]string{
   238  			"InternetSend": cloudprovider.METRIC_TAG_NET_TYPE_INTERNET,
   239  			"IntranetSend": cloudprovider.METRIC_TAG_NET_TYPE_INTRANET,
   240  		}
   241  		tagKey = cloudprovider.METRIC_TAG_REQUST
   242  	case cloudprovider.BUCKET_METRIC_TYPE_NET_BPS_RX:
   243  		metricTags = map[string]string{
   244  			"InternetRecv": cloudprovider.METRIC_TAG_NET_TYPE_INTERNET,
   245  			"IntranetRecv": cloudprovider.METRIC_TAG_NET_TYPE_INTRANET,
   246  		}
   247  		tagKey = cloudprovider.METRIC_TAG_NET_TYPE
   248  	case cloudprovider.BUCKET_METRYC_TYPE_REQ_COUNT:
   249  		metricTags = map[string]string{
   250  			"GetObjectCount":   cloudprovider.METRIC_TAG_REQUST_GET,
   251  			"PostObjectCount":  cloudprovider.METRIC_TAG_REQUST_POST,
   252  			"ServerErrorCount": cloudprovider.METRIC_TAG_REQUST_5XX,
   253  		}
   254  		tagKey = cloudprovider.METRIC_TAG_REQUST
   255  	default:
   256  		return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType)
   257  	}
   258  	ret := []cloudprovider.MetricValues{}
   259  	for metric, tag := range metricTags {
   260  		result, err := self.ListMetrics("acs_oss_dashboard", metric, opts.StartTime, opts.EndTime)
   261  		if err != nil {
   262  			log.Errorf("ListMetric(%s) error: %v", metric, err)
   263  			continue
   264  		}
   265  		for i := range result {
   266  			ret = append(ret, cloudprovider.MetricValues{
   267  				Id:         result[i].BucketName,
   268  				MetricType: opts.MetricType,
   269  				Values: []cloudprovider.MetricValue{
   270  					{
   271  						Timestamp: time.UnixMilli(result[i].Timestamp),
   272  						Value:     result[i].GetValue(),
   273  						Tags: map[string]string{
   274  							tagKey: tag,
   275  						},
   276  					},
   277  				},
   278  			})
   279  		}
   280  	}
   281  	return ret, nil
   282  }
   283  
   284  func (self *SApsaraClient) GetRedisMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) {
   285  	metricTags, tagKey := map[string]string{}, ""
   286  	switch opts.MetricType {
   287  	case cloudprovider.REDIS_METRIC_TYPE_CPU_USAGE:
   288  		metricTags = map[string]string{
   289  			"CpuUsage": "",
   290  		}
   291  	case cloudprovider.REDIS_METRIC_TYPE_MEM_USAGE:
   292  		metricTags = map[string]string{
   293  			"MemoryUsage": "",
   294  		}
   295  	case cloudprovider.REDIS_METRIC_TYPE_NET_BPS_RX:
   296  		metricTags = map[string]string{
   297  			"IntranetIn": "",
   298  		}
   299  	case cloudprovider.REDIS_METRIC_TYPE_NET_BPS_TX:
   300  		metricTags = map[string]string{
   301  			"IntranetOut": "",
   302  		}
   303  	case cloudprovider.REDIS_METRIC_TYPE_USED_CONN:
   304  		metricTags = map[string]string{
   305  			"UsedConnection": "",
   306  		}
   307  	case cloudprovider.REDIS_METRIC_TYPE_OPT_SES:
   308  		metricTags = map[string]string{
   309  			"UsedQPS": "",
   310  		}
   311  	case cloudprovider.REDIS_METRIC_TYPE_CACHE_KEYS:
   312  		metricTags = map[string]string{
   313  			"Keys": "",
   314  		}
   315  	case cloudprovider.REDIS_METRIC_TYPE_CACHE_EXP_KEYS:
   316  		metricTags = map[string]string{
   317  			"ExpiredKeys": "",
   318  		}
   319  	case cloudprovider.REDIS_METRIC_TYPE_DATA_MEM_USAGE:
   320  		metricTags = map[string]string{
   321  			"UsedMemory": "",
   322  		}
   323  	default:
   324  		return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType)
   325  	}
   326  	ret := []cloudprovider.MetricValues{}
   327  	for metric, tag := range metricTags {
   328  		result, err := self.ListMetrics("acs_kvstore", metric, opts.StartTime, opts.EndTime)
   329  		if err != nil {
   330  			log.Errorf("ListMetric(%s) error: %v", metric, err)
   331  			continue
   332  		}
   333  		tags := map[string]string{}
   334  		if len(tag) > 0 && len(tagKey) > 0 {
   335  			tags[tagKey] = tag
   336  		}
   337  		for i := range result {
   338  			ret = append(ret, cloudprovider.MetricValues{
   339  				Id:         result[i].InstanceId,
   340  				MetricType: opts.MetricType,
   341  				Values: []cloudprovider.MetricValue{
   342  					{
   343  						Timestamp: time.UnixMilli(result[i].Timestamp),
   344  						Value:     result[i].GetValue(),
   345  						Tags:      tags,
   346  					},
   347  				},
   348  			})
   349  		}
   350  	}
   351  	return ret, nil
   352  }
   353  
   354  func (self *SApsaraClient) GetRdsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) {
   355  	metrics := map[string]string{}
   356  	switch opts.MetricType {
   357  	case cloudprovider.RDS_METRIC_TYPE_CPU_USAGE:
   358  		metrics = map[string]string{
   359  			"CpuUsage": "",
   360  		}
   361  	case cloudprovider.RDS_METRIC_TYPE_MEM_USAGE:
   362  		metrics = map[string]string{
   363  			"MemoryUsage": "",
   364  		}
   365  	case cloudprovider.RDS_METRIC_TYPE_NET_BPS_RX:
   366  		metrics = map[string]string{
   367  			"MySQL_NetworkInNew":     "",
   368  			"SQLServer_NetworkInNew": "",
   369  		}
   370  	case cloudprovider.RDS_METRIC_TYPE_NET_BPS_TX:
   371  		metrics = map[string]string{
   372  			"MySQL_NetworkOutNew":     "",
   373  			"SQLServer_NetworkOutNew": "",
   374  		}
   375  	case cloudprovider.RDS_METRIC_TYPE_DISK_USAGE:
   376  		metrics = map[string]string{
   377  			"DiskUsage": "",
   378  		}
   379  	case cloudprovider.RDS_METRIC_TYPE_CONN_USAGE:
   380  		metrics = map[string]string{
   381  			"ConnectionUsage": "",
   382  		}
   383  	default:
   384  		return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType)
   385  	}
   386  	ret := []cloudprovider.MetricValues{}
   387  	for metric := range metrics {
   388  		result, err := self.ListMetrics("acs_rds_dashboard", metric, opts.StartTime, opts.EndTime)
   389  		if err != nil {
   390  			log.Errorf("ListMetric(%s) error: %v", metric, err)
   391  			continue
   392  		}
   393  		for i := range result {
   394  			ret = append(ret, cloudprovider.MetricValues{
   395  				Id:         result[i].InstanceId,
   396  				MetricType: opts.MetricType,
   397  				Values: []cloudprovider.MetricValue{
   398  					{
   399  						Timestamp: time.UnixMilli(result[i].Timestamp),
   400  						Value:     result[i].GetValue(),
   401  					},
   402  				},
   403  			})
   404  		}
   405  	}
   406  	return ret, nil
   407  }
   408  
   409  func (self *SApsaraClient) GetElbMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) {
   410  	metricTags, tagKey := map[string]string{}, ""
   411  	switch opts.MetricType {
   412  	case cloudprovider.LB_METRIC_TYPE_NET_BPS_RX:
   413  		metricTags = map[string]string{
   414  			"InstanceTrafficRX": "",
   415  		}
   416  	case cloudprovider.LB_METRIC_TYPE_NET_BPS_TX:
   417  		metricTags = map[string]string{
   418  			"InstanceTrafficTX": "",
   419  		}
   420  	case cloudprovider.LB_METRIC_TYPE_HRSP_COUNT:
   421  		metricTags = map[string]string{
   422  			"InstanceStatusCode2xx": cloudprovider.METRIC_TAG_REQUST_2XX,
   423  			"InstanceStatusCode3xx": cloudprovider.METRIC_TAG_REQUST_3XX,
   424  			"InstanceStatusCode4xx": cloudprovider.METRIC_TAG_REQUST_4XX,
   425  			"InstanceStatusCode5xx": cloudprovider.METRIC_TAG_REQUST_5XX,
   426  		}
   427  		tagKey = cloudprovider.METRIC_TAG_REQUST
   428  	default:
   429  		return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType)
   430  	}
   431  	ret := []cloudprovider.MetricValues{}
   432  	for metric, tag := range metricTags {
   433  		result, err := self.ListMetrics("acs_slb_dashboard", metric, opts.StartTime, opts.EndTime)
   434  		if err != nil {
   435  			log.Errorf("ListMetric(%s) error: %v", metric, err)
   436  			continue
   437  		}
   438  		tags := map[string]string{}
   439  		if len(tag) > 0 && len(tagKey) > 0 {
   440  			tags[tagKey] = tag
   441  		}
   442  		for i := range result {
   443  			ret = append(ret, cloudprovider.MetricValues{
   444  				Id:         result[i].InstanceId,
   445  				MetricType: opts.MetricType,
   446  				Values: []cloudprovider.MetricValue{
   447  					{
   448  						Timestamp: time.UnixMilli(result[i].Timestamp),
   449  						Value:     result[i].GetValue(),
   450  						Tags:      tags,
   451  					},
   452  				},
   453  			})
   454  		}
   455  	}
   456  	return ret, nil
   457  }