瀏覽代碼

re-implement dimension_values()

Mitsuhiro Tanda 8 年之前
父節點
當前提交
1dcc51adce

+ 0 - 49
pkg/api/cloudwatch/cloudwatch.go

@@ -11,7 +11,6 @@ import (
 	"time"
 
 	"github.com/aws/aws-sdk-go/aws"
-	"github.com/aws/aws-sdk-go/aws/awsutil"
 	"github.com/aws/aws-sdk-go/aws/credentials"
 	"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
 	"github.com/aws/aws-sdk-go/aws/credentials/endpointcreds"
@@ -19,7 +18,6 @@ import (
 	"github.com/aws/aws-sdk-go/aws/session"
 	"github.com/aws/aws-sdk-go/service/cloudwatch"
 	"github.com/aws/aws-sdk-go/service/sts"
-	"github.com/grafana/grafana/pkg/metrics"
 	"github.com/grafana/grafana/pkg/middleware"
 	m "github.com/grafana/grafana/pkg/models"
 )
@@ -73,7 +71,6 @@ func (req *cwRequest) GetDatasourceInfo() *DatasourceInfo {
 
 func init() {
 	actionHandlers = map[string]actionHandler{
-		"ListMetrics":             handleListMetrics,
 		"DescribeAlarms":          handleDescribeAlarms,
 		"DescribeAlarmsForMetric": handleDescribeAlarmsForMetric,
 		"DescribeAlarmHistory":    handleDescribeAlarmHistory,
@@ -216,52 +213,6 @@ func getAwsConfig(req *cwRequest) (*aws.Config, error) {
 	return cfg, nil
 }
 
-func handleListMetrics(req *cwRequest, c *middleware.Context) {
-	cfg, err := getAwsConfig(req)
-	if err != nil {
-		c.JsonApiErr(500, "Unable to call AWS API", err)
-		return
-	}
-	sess, err := session.NewSession(cfg)
-	if err != nil {
-		c.JsonApiErr(500, "Unable to call AWS API", err)
-		return
-	}
-	svc := cloudwatch.New(sess, cfg)
-
-	reqParam := &struct {
-		Parameters struct {
-			Namespace  string                        `json:"namespace"`
-			MetricName string                        `json:"metricName"`
-			Dimensions []*cloudwatch.DimensionFilter `json:"dimensions"`
-		} `json:"parameters"`
-	}{}
-	json.Unmarshal(req.Body, reqParam)
-
-	params := &cloudwatch.ListMetricsInput{
-		Namespace:  aws.String(reqParam.Parameters.Namespace),
-		MetricName: aws.String(reqParam.Parameters.MetricName),
-		Dimensions: reqParam.Parameters.Dimensions,
-	}
-
-	var resp cloudwatch.ListMetricsOutput
-	err = svc.ListMetricsPages(params,
-		func(page *cloudwatch.ListMetricsOutput, lastPage bool) bool {
-			metrics.M_Aws_CloudWatch_ListMetrics.Inc()
-			metrics, _ := awsutil.ValuesAtPath(page, "Metrics")
-			for _, metric := range metrics {
-				resp.Metrics = append(resp.Metrics, metric.(*cloudwatch.Metric))
-			}
-			return !lastPage
-		})
-	if err != nil {
-		c.JsonApiErr(500, "Unable to call AWS API", err)
-		return
-	}
-
-	c.JSON(200, resp)
-}
-
 func handleDescribeAlarms(req *cwRequest, c *middleware.Context) {
 	cfg, err := getAwsConfig(req)
 	if err != nil {

+ 81 - 0
pkg/tsdb/cloudwatch/metric_find_query.go

@@ -176,6 +176,9 @@ func (e *CloudWatchExecutor) executeMetricFindQuery(ctx context.Context, queries
 	case "dimension_keys":
 		data, err = e.handleGetDimensions(ctx, parameters, queryContext)
 		break
+	case "dimension_values":
+		data, err = e.handleGetDimensionValues(ctx, parameters, queryContext)
+		break
 	case "ebs_volume_ids":
 		data, err = e.handleGetEbsVolumeIds(ctx, parameters, queryContext)
 		break
@@ -328,6 +331,49 @@ func (e *CloudWatchExecutor) handleGetDimensions(ctx context.Context, parameters
 	return result, nil
 }
 
+func (e *CloudWatchExecutor) handleGetDimensionValues(ctx context.Context, parameters *simplejson.Json, queryContext *tsdb.QueryContext) ([]suggestData, error) {
+	region := parameters.Get("region").MustString()
+	namespace := parameters.Get("namespace").MustString()
+	metricName := parameters.Get("metricName").MustString()
+	dimensionKey := parameters.Get("dimensionKey").MustString()
+	dimensionsJson := parameters.Get("dimensionKey").MustMap()
+
+	var dimensions []*cloudwatch.DimensionFilter
+	for _, d := range dimensionsJson {
+		if dd, ok := d.(map[string]string); ok {
+			dimensions = append(dimensions, &cloudwatch.DimensionFilter{
+				Name:  aws.String(dd["Name"]),
+				Value: aws.String(dd["Value"]),
+			})
+		}
+	}
+
+	metrics, err := e.cloudwatchListMetrics(region, namespace, metricName, dimensions)
+	if err != nil {
+		return nil, err
+	}
+
+	result := make([]suggestData, 0)
+	dupCheck := make(map[string]bool)
+	for _, metric := range metrics.Metrics {
+		for _, dim := range metric.Dimensions {
+			if *dim.Name == dimensionKey {
+				if _, exists := dupCheck[*dim.Value]; exists {
+					continue
+				}
+				dupCheck[*dim.Value] = true
+				result = append(result, suggestData{Text: *dim.Value, Value: *dim.Value})
+			}
+		}
+	}
+
+	sort.Slice(result, func(i, j int) bool {
+		return result[i].Text < result[j].Text
+	})
+
+	return result, nil
+}
+
 func (e *CloudWatchExecutor) handleGetEbsVolumeIds(ctx context.Context, parameters *simplejson.Json, queryContext *tsdb.QueryContext) ([]suggestData, error) {
 	region := parameters.Get("region").MustString()
 	instanceId := parameters.Get("instanceId").MustString()
@@ -428,6 +474,41 @@ func getAwsConfig(dsInfo *cwapi.DatasourceInfo) (*aws.Config, error) {
 	return cfg, nil
 }
 
+func (e *CloudWatchExecutor) cloudwatchListMetrics(region string, namespace string, metricName string, dimensions []*cloudwatch.DimensionFilter) (*cloudwatch.ListMetricsOutput, error) {
+	dsInfo := e.getDsInfo(region)
+	cfg, err := getAwsConfig(dsInfo)
+	if err != nil {
+		return nil, errors.New("Failed to call cloudwatch:ListMetrics")
+	}
+	sess, err := session.NewSession(cfg)
+	if err != nil {
+		return nil, errors.New("Failed to call cloudwatch:ListMetrics")
+	}
+	svc := cloudwatch.New(sess, cfg)
+
+	params := &cloudwatch.ListMetricsInput{
+		Namespace:  aws.String(namespace),
+		MetricName: aws.String(metricName),
+		Dimensions: dimensions,
+	}
+
+	var resp cloudwatch.ListMetricsOutput
+	err = svc.ListMetricsPages(params,
+		func(page *cloudwatch.ListMetricsOutput, lastPage bool) bool {
+			metrics.M_Aws_CloudWatch_ListMetrics.Inc()
+			metrics, _ := awsutil.ValuesAtPath(page, "Metrics")
+			for _, metric := range metrics {
+				resp.Metrics = append(resp.Metrics, metric.(*cloudwatch.Metric))
+			}
+			return !lastPage
+		})
+	if err != nil {
+		return nil, errors.New("Failed to call cloudwatch:ListMetrics")
+	}
+
+	return &resp, nil
+}
+
 func (e *CloudWatchExecutor) ec2DescribeInstances(region string, filters []*ec2.Filter, instanceIds []*string) (*ec2.DescribeInstancesOutput, error) {
 	dsInfo := e.getDsInfo(region)
 	cfg, err := getAwsConfig(dsInfo)

+ 22 - 24
public/app/plugins/datasource/cloudwatch/datasource.js

@@ -222,30 +222,28 @@ function (angular, _, moment, dateMath, kbn, templatingVariable, CloudWatchAnnot
     };
 
     this.getDimensionValues = function(region, namespace, metricName, dimensionKey, filterDimensions) {
-      var request = {
-        region: templateSrv.replace(region),
-        action: 'ListMetrics',
-        parameters: {
-          namespace: templateSrv.replace(namespace),
-          metricName: templateSrv.replace(metricName),
-          dimensions: this.convertDimensionFormat(filterDimensions, {}),
-        }
-      };
-
-      return this.awsRequest(request).then(function(result) {
-        return _.chain(result.Metrics)
-        .map('Dimensions')
-        .flatten()
-        .filter(function(dimension) {
-          return dimension !== null && dimension.Name === dimensionKey;
-        })
-        .map('Value')
-        .uniq()
-        .sortBy()
-        .map(function(value) {
-          return {value: value, text: value};
-        }).value();
-      });
+      var range = timeSrv.timeRange();
+      return backendSrv.post('/api/tsdb/query', {
+        from: range.from,
+        to: range.to,
+        queries: [
+          {
+            refId: 'metricFindQuery',
+            intervalMs: 1, // dummy
+            maxDataPoints: 1, // dummy
+            datasourceId: this.instanceSettings.id,
+            type: 'metricFindQuery',
+            subtype: 'dimension_values',
+            parameters: {
+              region: region,
+              namespace: templateSrv.replace(namespace),
+              metricName: templateSrv.replace(metricName),
+              dimensionKey: templateSrv.replace(dimensionKey),
+              dimensions: this.convertDimensionFormat(filterDimensions, {}),
+            }
+          }
+        ]
+      }).then(function (r) { return transformSuggestDataFromTable(r); });
     };
 
     this.getEbsVolumeIds = function(region, instanceId) {