diff --git a/pkg/tsdb/cloudwatch/cloudwatch.go b/pkg/tsdb/cloudwatch/cloudwatch.go index 3a3e6801652..d5bdd010269 100644 --- a/pkg/tsdb/cloudwatch/cloudwatch.go +++ b/pkg/tsdb/cloudwatch/cloudwatch.go @@ -17,6 +17,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/service/cloudwatch" + "github.com/aws/aws-sdk-go/service/ec2/ec2iface" "github.com/grafana/grafana/pkg/components/null" "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/metrics" @@ -24,6 +25,7 @@ import ( type CloudWatchExecutor struct { *models.DataSource + ec2Svc ec2iface.EC2API } type DatasourceInfo struct { diff --git a/pkg/tsdb/cloudwatch/metric_find_query.go b/pkg/tsdb/cloudwatch/metric_find_query.go index 1d891a457f5..b9d4d5b6a80 100644 --- a/pkg/tsdb/cloudwatch/metric_find_query.go +++ b/pkg/tsdb/cloudwatch/metric_find_query.go @@ -185,6 +185,18 @@ func (e *CloudWatchExecutor) executeMetricFindQuery(ctx context.Context, queryCo data, err = e.handleGetEbsVolumeIds(ctx, parameters, queryContext) break case "ec2_instance_attribute": + region := parameters.Get("region").MustString() + dsInfo := e.getDsInfo(region) + cfg, err := e.getAwsConfig(dsInfo) + if err != nil { + return nil, errors.New("Failed to call ec2:DescribeInstances") + } + sess, err := session.NewSession(cfg) + if err != nil { + return nil, errors.New("Failed to call ec2:DescribeInstances") + } + e.ec2Svc = ec2.New(sess, cfg) + data, err = e.handleGetEc2InstanceAttribute(ctx, parameters, queryContext) break } @@ -375,14 +387,16 @@ func (e *CloudWatchExecutor) handleGetEc2InstanceAttribute(ctx context.Context, var filters []*ec2.Filter for k, v := range filterJson { - if vv, ok := v.([]string); ok { - var vvvv []*string + if vv, ok := v.([]interface{}); ok { + var vvvvv []*string for _, vvv := range vv { - vvvv = append(vvvv, &vvv) + if vvvv, ok := vvv.(string); ok { + vvvvv = append(vvvvv, &vvvv) + } } filters = append(filters, &ec2.Filter{ Name: aws.String(k), - Values: vvvv, + Values: vvvvv, }) } } @@ -469,24 +483,13 @@ func (e *CloudWatchExecutor) cloudwatchListMetrics(region string, namespace stri } func (e *CloudWatchExecutor) ec2DescribeInstances(region string, filters []*ec2.Filter, instanceIds []*string) (*ec2.DescribeInstancesOutput, error) { - dsInfo := e.getDsInfo(region) - cfg, err := e.getAwsConfig(dsInfo) - if err != nil { - return nil, errors.New("Failed to call ec2:DescribeInstances") - } - sess, err := session.NewSession(cfg) - if err != nil { - return nil, errors.New("Failed to call ec2:DescribeInstances") - } - svc := ec2.New(sess, cfg) - params := &ec2.DescribeInstancesInput{ Filters: filters, InstanceIds: instanceIds, } var resp ec2.DescribeInstancesOutput - err = svc.DescribeInstancesPages(params, + err := e.ec2Svc.DescribeInstancesPages(params, func(page *ec2.DescribeInstancesOutput, lastPage bool) bool { reservations, _ := awsutil.ValuesAtPath(page, "Reservations") for _, reservation := range reservations { diff --git a/pkg/tsdb/cloudwatch/metric_find_query_test.go b/pkg/tsdb/cloudwatch/metric_find_query_test.go index 238e815fac1..255b343a33a 100644 --- a/pkg/tsdb/cloudwatch/metric_find_query_test.go +++ b/pkg/tsdb/cloudwatch/metric_find_query_test.go @@ -1,13 +1,28 @@ package cloudwatch import ( + "context" "testing" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/cloudwatch" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/ec2/ec2iface" + "github.com/grafana/grafana/pkg/components/simplejson" + "github.com/grafana/grafana/pkg/tsdb" . "github.com/smartystreets/goconvey/convey" ) +type mockedEc2 struct { + ec2iface.EC2API + Resp ec2.DescribeInstancesOutput +} + +func (m mockedEc2) DescribeInstancesPages(in *ec2.DescribeInstancesInput, fn func(*ec2.DescribeInstancesOutput, bool) bool) error { + fn(&m.Resp, true) + return nil +} + func TestCloudWatchMetrics(t *testing.T) { Convey("When calling getMetricsForCustomMetrics", t, func() { @@ -66,4 +81,37 @@ func TestCloudWatchMetrics(t *testing.T) { }) }) + Convey("When calling handleGetEc2InstanceAttribute", t, func() { + executor := &CloudWatchExecutor{ + ec2Svc: mockedEc2{Resp: ec2.DescribeInstancesOutput{ + Reservations: []*ec2.Reservation{ + { + Instances: []*ec2.Instance{ + { + InstanceId: aws.String("i-12345678"), + Tags: []*ec2.Tag{ + { + Key: aws.String("Environment"), + Value: aws.String("production"), + }, + }, + }, + }, + }, + }, + }}, + } + + json := simplejson.New() + json.Set("region", "us-east-1") + json.Set("attributeName", "InstanceId") + filters := make(map[string]interface{}) + filters["tag:Environment"] = []string{"production"} + json.Set("filters", filters) + result, _ := executor.handleGetEc2InstanceAttribute(context.Background(), json, &tsdb.TsdbQuery{}) + + Convey("Should equal production InstanceId", func() { + So(result[0].Text, ShouldEqual, "i-12345678") + }) + }) }