yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/ecloud/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 ecloud
    16  
    17  import (
    18  	"context"
    19  	"strconv"
    20  	"time"
    21  
    22  	"yunion.io/x/jsonutils"
    23  	"yunion.io/x/pkg/errors"
    24  	"yunion.io/x/pkg/util/timeutils"
    25  	"yunion.io/x/pkg/utils"
    26  
    27  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    28  	"yunion.io/x/onecloud/pkg/httperrors"
    29  )
    30  
    31  const (
    32  	MONITOR_FETCH_REQUEST_ACTION   = "v1.dawn.monitor.fetch"
    33  	MONITOR_PRODUCT_REQUEST_ACTION = "v1.dawn.monitor.products"
    34  
    35  	MONITOR_FETCH_SERVER_PATH = "/api/edw/edw/api"
    36  
    37  	REQUEST_SUCCESS_CODE = "000000"
    38  )
    39  
    40  var (
    41  	noMetricRegion = []string{"guangzhou-2", "beijing-1", "hunan-1"}
    42  
    43  	portRegionMap = map[string][]string{
    44  		"8443": {"wuxi-1", "dongguan-1", "yaan-1", "zhengzhou-1", "beijing-2", "zhuzhou-1", "jinan-1",
    45  			"xian-1", "shanghai-1", "chongqing-1", "ningbo-1"},
    46  		"18080": {"tianjin-1", "jilin-1", "hubei-1", "jiangxi-1", "gansu-1", "shanxi-1", "liaoning-1",
    47  			"yunnan-2", "hebei-1", "fujian-1", "guangxi-1", "anhui-1", "huhehaote-1", "guiyang-1"},
    48  	}
    49  )
    50  
    51  type Metric struct {
    52  	Name string `json:"MetricName"`
    53  }
    54  
    55  type MetricData struct {
    56  	Entitys []Entity `json:"entity"`
    57  }
    58  
    59  type Entity struct {
    60  	ResourceID         string      `json:"resourceId"`
    61  	MetricName         string      `json:"metricName"`
    62  	MetricNameCN       string      `json:"metricNameCn"`
    63  	Unit               string      `json:"unit"`
    64  	MaxValue           int64       `json:"maxValue"`
    65  	AvgValue           int64       `json:"avgValue"`
    66  	MinValue           int64       `json:"minValue"`
    67  	Granularity        string      `json:"granularity"`
    68  	PolymerizeType     string      `json:"polymerizeType"`
    69  	SelectedMetricItem interface{} `json:"selectedMetricItem"`
    70  	MetricItems        interface{} `json:"metricItems"`
    71  	IsChildnode        bool        `json:"isChildnode"`
    72  	Datapoints         []Datapoint `json:"datapoints"`
    73  }
    74  
    75  type Datapoint []string
    76  
    77  type SMonitorRequest struct {
    78  	SApiRequest
    79  }
    80  
    81  func NewMonitorRequest(regionId string, serverPath string, query map[string]string, data jsonutils.JSONObject) *SMonitorRequest {
    82  	apiRequest := NewApiRequest(regionId, serverPath, query, data)
    83  	return &SMonitorRequest{*apiRequest}
    84  }
    85  
    86  func (rr *SMonitorRequest) GetPort() string {
    87  	for port, regions := range portRegionMap {
    88  		if utils.IsInStringArray(rr.GetRegionId(), regions) {
    89  			return port
    90  		}
    91  	}
    92  	return "8443"
    93  }
    94  
    95  func (br *SMonitorRequest) ForMateResponseBody(jrbody jsonutils.JSONObject) (jsonutils.JSONObject, error) {
    96  	code, _ := jrbody.GetString("code")
    97  	if code != REQUEST_SUCCESS_CODE {
    98  		message, _ := jrbody.(*jsonutils.JSONDict).GetString("message")
    99  		return nil, httperrors.NewBadRequestError("rep body code is :%s, message:%s,body:%v", code, message, jrbody)
   100  	}
   101  	if jrbody == nil || !jrbody.Contains("entity") {
   102  		return nil, ErrMissKey{
   103  			Key: "entity",
   104  			Jo:  jrbody,
   105  		}
   106  	}
   107  	return jrbody, nil
   108  }
   109  
   110  func (self *SEcloudClient) DescribeMetricList(regionId, productType string, metrics []Metric, resourceId string,
   111  	since time.Time, until time.Time) (MetricData, error) {
   112  	metricData := MetricData{
   113  		Entitys: make([]Entity, 0),
   114  	}
   115  	params := map[string]string{
   116  		"eAction": MONITOR_FETCH_REQUEST_ACTION,
   117  	}
   118  	getBody := jsonutils.NewDict()
   119  	getBody.Set("startTime", jsonutils.NewString(since.Format(timeutils.MysqlTimeFormat)))
   120  	getBody.Set("endTime", jsonutils.NewString(until.Format(timeutils.MysqlTimeFormat)))
   121  	getBody.Set("productType", jsonutils.NewString(productType))
   122  	getBody.Set("resourceId", jsonutils.NewString(resourceId))
   123  	getBody.Set("metrics", jsonutils.Marshal(&metrics))
   124  	request := NewMonitorRequest(regionId, MONITOR_FETCH_SERVER_PATH, params, getBody)
   125  	err := self.doGet(context.Background(), request, &metricData)
   126  	if err != nil {
   127  		return metricData, errors.Wrap(err, "client doGet error")
   128  	}
   129  	return metricData, nil
   130  }
   131  
   132  func (r *SRegion) GetProductTypes() (jsonutils.JSONObject, error) {
   133  	params := map[string]string{
   134  		"eAction": MONITOR_PRODUCT_REQUEST_ACTION,
   135  	}
   136  	request := NewMonitorRequest(r.ID, MONITOR_FETCH_SERVER_PATH, params, nil)
   137  	rtn := jsonutils.NewDict()
   138  	err := r.client.doGet(context.Background(), request, rtn)
   139  	if err != nil {
   140  		return nil, errors.Wrap(err, "client doGet error")
   141  	}
   142  	return rtn, nil
   143  }
   144  
   145  func (self *SEcloudClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) {
   146  	switch opts.ResourceType {
   147  	case cloudprovider.METRIC_RESOURCE_TYPE_SERVER:
   148  		return self.GetEcsMetrics(opts)
   149  	default:
   150  		return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.ResourceType)
   151  	}
   152  }
   153  
   154  func (self *SEcloudClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) {
   155  	metrics := map[string]cloudprovider.TMetricType{
   156  		"cpu_util":                        cloudprovider.VM_METRIC_TYPE_CPU_USAGE,
   157  		"memory.util":                     cloudprovider.VM_METRIC_TYPE_MEM_USAGE,
   158  		"disk.device.read.requests.rate":  cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS,
   159  		"disk.device.write.requests.rate": cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS,
   160  		"disk.device.read.bytes.rate":     cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS,
   161  		"disk.device.write.bytes.rate":    cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS,
   162  		"network.incoming.bytes":          cloudprovider.VM_METRIC_TYPE_NET_BPS_RX,
   163  		"network.outgoing.bytes":          cloudprovider.VM_METRIC_TYPE_NET_BPS_TX,
   164  	}
   165  	metricNames := []Metric{}
   166  	for metric := range metrics {
   167  		metricNames = append(metricNames, Metric{
   168  			Name: metric,
   169  		})
   170  	}
   171  	if utils.IsInStringArray(opts.RegionExtId, noMetricRegion) {
   172  		return []cloudprovider.MetricValues{}, nil
   173  	}
   174  	data, err := self.DescribeMetricList(opts.RegionExtId, "vm", metricNames, opts.ResourceId, opts.StartTime, opts.EndTime)
   175  	if err != nil {
   176  		return nil, errors.Wrapf(err, "DescribeMetricList")
   177  	}
   178  	ret := []cloudprovider.MetricValues{}
   179  	for _, value := range data.Entitys {
   180  		metric := cloudprovider.MetricValues{}
   181  		metric.Id = opts.ResourceId
   182  		metricType, ok := metrics[value.MetricName]
   183  		if !ok {
   184  			continue
   185  		}
   186  		metric.MetricType = metricType
   187  		for _, points := range value.Datapoints {
   188  			if len(points) != 2 {
   189  				continue
   190  			}
   191  			metricValue := cloudprovider.MetricValue{}
   192  			pointTime, err := strconv.ParseInt(points[1], 10, 64)
   193  			if err != nil {
   194  				continue
   195  			}
   196  			metricValue.Timestamp = time.Unix(pointTime, 0)
   197  			metricValue.Value, err = strconv.ParseFloat(points[0], 64)
   198  			if err != nil {
   199  				continue
   200  			}
   201  			metric.Values = append(metric.Values, metricValue)
   202  		}
   203  		ret = append(ret, metric)
   204  	}
   205  	return ret, nil
   206  }