re-implement dimension_values()

pull/8050/head
Mitsuhiro Tanda 8 years ago
parent ec632bb9ed
commit 1dcc51adce
  1. 49
      pkg/api/cloudwatch/cloudwatch.go
  2. 81
      pkg/tsdb/cloudwatch/metric_find_query.go
  3. 46
      public/app/plugins/datasource/cloudwatch/datasource.js

@ -11,7 +11,6 @@ import (
"time" "time"
"github.com/aws/aws-sdk-go/aws" "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"
"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds" "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
"github.com/aws/aws-sdk-go/aws/credentials/endpointcreds" "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/aws/session"
"github.com/aws/aws-sdk-go/service/cloudwatch" "github.com/aws/aws-sdk-go/service/cloudwatch"
"github.com/aws/aws-sdk-go/service/sts" "github.com/aws/aws-sdk-go/service/sts"
"github.com/grafana/grafana/pkg/metrics"
"github.com/grafana/grafana/pkg/middleware" "github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models" m "github.com/grafana/grafana/pkg/models"
) )
@ -73,7 +71,6 @@ func (req *cwRequest) GetDatasourceInfo() *DatasourceInfo {
func init() { func init() {
actionHandlers = map[string]actionHandler{ actionHandlers = map[string]actionHandler{
"ListMetrics": handleListMetrics,
"DescribeAlarms": handleDescribeAlarms, "DescribeAlarms": handleDescribeAlarms,
"DescribeAlarmsForMetric": handleDescribeAlarmsForMetric, "DescribeAlarmsForMetric": handleDescribeAlarmsForMetric,
"DescribeAlarmHistory": handleDescribeAlarmHistory, "DescribeAlarmHistory": handleDescribeAlarmHistory,
@ -216,52 +213,6 @@ func getAwsConfig(req *cwRequest) (*aws.Config, error) {
return cfg, nil 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) { func handleDescribeAlarms(req *cwRequest, c *middleware.Context) {
cfg, err := getAwsConfig(req) cfg, err := getAwsConfig(req)
if err != nil { if err != nil {

@ -176,6 +176,9 @@ func (e *CloudWatchExecutor) executeMetricFindQuery(ctx context.Context, queries
case "dimension_keys": case "dimension_keys":
data, err = e.handleGetDimensions(ctx, parameters, queryContext) data, err = e.handleGetDimensions(ctx, parameters, queryContext)
break break
case "dimension_values":
data, err = e.handleGetDimensionValues(ctx, parameters, queryContext)
break
case "ebs_volume_ids": case "ebs_volume_ids":
data, err = e.handleGetEbsVolumeIds(ctx, parameters, queryContext) data, err = e.handleGetEbsVolumeIds(ctx, parameters, queryContext)
break break
@ -328,6 +331,49 @@ func (e *CloudWatchExecutor) handleGetDimensions(ctx context.Context, parameters
return result, nil 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) { func (e *CloudWatchExecutor) handleGetEbsVolumeIds(ctx context.Context, parameters *simplejson.Json, queryContext *tsdb.QueryContext) ([]suggestData, error) {
region := parameters.Get("region").MustString() region := parameters.Get("region").MustString()
instanceId := parameters.Get("instanceId").MustString() instanceId := parameters.Get("instanceId").MustString()
@ -428,6 +474,41 @@ func getAwsConfig(dsInfo *cwapi.DatasourceInfo) (*aws.Config, error) {
return cfg, nil 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) { func (e *CloudWatchExecutor) ec2DescribeInstances(region string, filters []*ec2.Filter, instanceIds []*string) (*ec2.DescribeInstancesOutput, error) {
dsInfo := e.getDsInfo(region) dsInfo := e.getDsInfo(region)
cfg, err := getAwsConfig(dsInfo) cfg, err := getAwsConfig(dsInfo)

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

Loading…
Cancel
Save