yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/aws/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 aws
    16  
    17  import (
    18  	"fmt"
    19  	"strings"
    20  	"time"
    21  
    22  	"yunion.io/x/log"
    23  	"yunion.io/x/pkg/errors"
    24  
    25  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    26  )
    27  
    28  func (self *SAwsClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) {
    29  	if len(opts.ResourceId) == 0 {
    30  		return nil, fmt.Errorf("missing resource id")
    31  	}
    32  	switch opts.ResourceType {
    33  	case cloudprovider.METRIC_RESOURCE_TYPE_SERVER:
    34  		return self.GetEcsMetrics(opts)
    35  	case cloudprovider.METRIC_RESOURCE_TYPE_RDS:
    36  		return self.GetRdsMetrics(opts)
    37  	case cloudprovider.METRIC_RESOURCE_TYPE_REDIS:
    38  		return self.GetRedisMetrics(opts)
    39  	default:
    40  		return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.ResourceType)
    41  	}
    42  }
    43  
    44  func (self *SAwsClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) {
    45  	ret := []cloudprovider.MetricValues{}
    46  	for metricType, metricNames := range map[cloudprovider.TMetricType]map[string]string{
    47  		cloudprovider.VM_METRIC_TYPE_CPU_USAGE: {
    48  			"CPUUtilization": "",
    49  		},
    50  		cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS: {
    51  			"DiskReadOps": "",
    52  			"EBSReadOps":  cloudprovider.METRIC_TAG_TYPE_DISK_TYPE + ":" + cloudprovider.METRIC_TAG_TYPE_DISK_TYPE,
    53  		},
    54  		cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS: {
    55  			"DiskWriteOps": "",
    56  			"EBSWriteOps":  cloudprovider.METRIC_TAG_TYPE_DISK_TYPE + ":" + cloudprovider.METRIC_TAG_TYPE_DISK_TYPE,
    57  		},
    58  		cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS: {
    59  			"DiskReadBytes": "",
    60  			"EBSReadBytes":  cloudprovider.METRIC_TAG_TYPE_DISK_TYPE + ":" + cloudprovider.METRIC_TAG_TYPE_DISK_TYPE,
    61  		},
    62  		cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS: {
    63  			"DiskWriteBytes": "",
    64  			"EBSWriteBytes":  cloudprovider.METRIC_TAG_TYPE_DISK_TYPE + ":" + cloudprovider.METRIC_TAG_TYPE_DISK_TYPE,
    65  		},
    66  		cloudprovider.VM_METRIC_TYPE_NET_BPS_RX: {
    67  			"NetworkIn": "",
    68  		},
    69  		cloudprovider.VM_METRIC_TYPE_NET_BPS_TX: {
    70  			"NetworkOut": "",
    71  		},
    72  	} {
    73  		part, err := self.getMetrics(opts.RegionExtId, "AWS/EC2", metricType, metricNames, "InstanceId", opts.ResourceId, opts.StartTime, opts.EndTime)
    74  		if err != nil {
    75  			log.Errorf("getMetrics error: %v", err)
    76  			continue
    77  		}
    78  		ret = append(ret, part...)
    79  	}
    80  	return ret, nil
    81  }
    82  
    83  type Datapoint struct {
    84  	Average            float64 `xml:"Average"`
    85  	ExtendedStatistics struct {
    86  		Key   string `xml:"Key"`
    87  		Value string `xml:"Value"`
    88  	} `xml:"ExtendedStatistics>entry"`
    89  	Maximum     float64   `xml:"Maximum"`
    90  	Minimum     float64   `xml:"Minimum"`
    91  	SampleCount float64   `xml:"SampleCount"`
    92  	Sum         float64   `xml:"Sum"`
    93  	Timestamp   time.Time `xml:"Timestamp"`
    94  	Unit        string    `xml:"Unit"`
    95  }
    96  
    97  func (self Datapoint) GetValue() float64 {
    98  	return self.Average + self.Average + self.Minimum + self.Sum
    99  }
   100  
   101  type Datapoints struct {
   102  	Datapoints []Datapoint `xml:"Datapoints>member"`
   103  	Label      string      `xml:"Label"`
   104  }
   105  
   106  func (self *SAwsClient) getMetrics(regionId, ns string, metricType cloudprovider.TMetricType, metrics map[string]string, dimensionName, dimensionValue string, start, end time.Time) ([]cloudprovider.MetricValues, error) {
   107  	result := []cloudprovider.MetricValues{}
   108  	for metricName, tagValue := range metrics {
   109  		params := map[string]string{
   110  			"EndTime":                   end.Format(time.RFC3339),
   111  			"MetricName":                metricName,
   112  			"Dimensions.member.1.Name":  dimensionName,
   113  			"Dimensions.member.1.Value": dimensionValue,
   114  			"Namespace":                 ns,
   115  			"Period":                    "1",
   116  			"StartTime":                 start.Format(time.RFC3339),
   117  			"Statistics.member.1":       "Average",
   118  		}
   119  		ret := Datapoints{}
   120  		err := self.monitorRequest(regionId, "GetMetricStatistics", params, &ret)
   121  		if err != nil {
   122  			log.Errorf("GetMetricStatistics error: %v", err)
   123  			continue
   124  		}
   125  		metric := cloudprovider.MetricValues{}
   126  		metric.Id = dimensionValue
   127  		metric.MetricType = metricType
   128  		tags := map[string]string{}
   129  		idx := strings.Index(tagValue, ":")
   130  		if idx > 0 {
   131  			tags[tagValue[:idx]] = tagValue[idx+1:]
   132  		}
   133  		for _, data := range ret.Datapoints {
   134  			metricValue := cloudprovider.MetricValue{}
   135  			metricValue.Tags = tags
   136  			metricValue.Timestamp = data.Timestamp
   137  			metricValue.Value = data.GetValue()
   138  			metric.Values = append(metric.Values, metricValue)
   139  		}
   140  		result = append(result, metric)
   141  	}
   142  	return result, nil
   143  }
   144  
   145  func (self *SAwsClient) GetRdsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) {
   146  	ret := []cloudprovider.MetricValues{}
   147  	for metricType, metricNames := range map[cloudprovider.TMetricType]map[string]string{
   148  		cloudprovider.RDS_METRIC_TYPE_CPU_USAGE: {
   149  			"CPUUtilization": "",
   150  		},
   151  		cloudprovider.RDS_METRIC_TYPE_NET_BPS_RX: {
   152  			"NetworkReceiveThroughput": "",
   153  		},
   154  		cloudprovider.RDS_METRIC_TYPE_NET_BPS_TX: {
   155  			"NetworkTransmitThroughput": "",
   156  		},
   157  		cloudprovider.RDS_METRIC_TYPE_CONN_COUNT: {
   158  			"DatabaseConnections": "",
   159  		},
   160  	} {
   161  		part, err := self.getMetrics(opts.RegionExtId, "AWS/RDS", metricType, metricNames, "DBInstanceIdentifier", opts.ResourceId, opts.StartTime, opts.EndTime)
   162  		if err != nil {
   163  			log.Errorf("getMetrics error: %v", err)
   164  			continue
   165  		}
   166  		ret = append(ret, part...)
   167  	}
   168  	return ret, nil
   169  
   170  }
   171  
   172  func (self *SAwsClient) GetRedisMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) {
   173  	ret := []cloudprovider.MetricValues{}
   174  	for metricType, metricNames := range map[cloudprovider.TMetricType]map[string]string{
   175  		cloudprovider.REDIS_METRIC_TYPE_CPU_USAGE: {
   176  			"CPUUtilization": "",
   177  		},
   178  		cloudprovider.REDIS_METRIC_TYPE_USED_CONN: {
   179  			"CurrConnections": "",
   180  		},
   181  		cloudprovider.REDIS_METRIC_TYPE_CACHE_EXP_KEYS: {
   182  			"Reclaimed": "",
   183  		},
   184  	} {
   185  		part, err := self.getMetrics(opts.RegionExtId, "AWS/ElastiCache", metricType, metricNames, "CacheClusterId", opts.ResourceId, opts.StartTime, opts.EndTime)
   186  		if err != nil {
   187  			log.Errorf("getMetrics error: %v", err)
   188  			continue
   189  		}
   190  		ret = append(ret, part...)
   191  	}
   192  	return ret, nil
   193  }