diff --git a/pkg/api/cloudwatch/cloudwatch.go b/pkg/api/cloudwatch/cloudwatch.go index 0fb7b09f3cb..1b796be874e 100644 --- a/pkg/api/cloudwatch/cloudwatch.go +++ b/pkg/api/cloudwatch/cloudwatch.go @@ -17,7 +17,6 @@ import ( "github.com/aws/aws-sdk-go/service/cloudwatch" "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/sts" - "github.com/grafana/grafana/pkg/log" "github.com/grafana/grafana/pkg/metrics" "github.com/grafana/grafana/pkg/middleware" m "github.com/grafana/grafana/pkg/models" @@ -90,7 +89,7 @@ type cache struct { var awsCredentialCache map[string]cache = make(map[string]cache) var credentialCacheLock sync.RWMutex -func getCredentials(dsInfo *datasourceInfo) *credentials.Credentials { +func getCredentials(dsInfo *datasourceInfo) (*credentials.Credentials, error) { cacheKey := dsInfo.Profile + ":" + dsInfo.AssumeRoleArn credentialCacheLock.RLock() if _, ok := awsCredentialCache[cacheKey]; ok { @@ -98,7 +97,7 @@ func getCredentials(dsInfo *datasourceInfo) *credentials.Credentials { (*awsCredentialCache[cacheKey].expiration).After(time.Now().UTC()) { result := awsCredentialCache[cacheKey].credential credentialCacheLock.RUnlock() - return result + return result, nil } } credentialCacheLock.RUnlock() @@ -130,8 +129,7 @@ func getCredentials(dsInfo *datasourceInfo) *credentials.Credentials { svc := sts.New(session.New(stsConfig), stsConfig) resp, err := svc.AssumeRole(params) if err != nil { - // ignore - log.Error(3, "CloudWatch: Failed to assume role", err) + return nil, err } if resp.Credentials != nil { accessKeyId = *resp.Credentials.AccessKeyId @@ -165,19 +163,28 @@ func getCredentials(dsInfo *datasourceInfo) *credentials.Credentials { } credentialCacheLock.Unlock() - return creds + return creds, nil } -func getAwsConfig(req *cwRequest) *aws.Config { +func getAwsConfig(req *cwRequest) (*aws.Config, error) { + creds, err := getCredentials(req.GetDatasourceInfo()) + if err != nil { + return nil, err + } + cfg := &aws.Config{ Region: aws.String(req.Region), - Credentials: getCredentials(req.GetDatasourceInfo()), + Credentials: creds, } - return cfg + return cfg, nil } func handleGetMetricStatistics(req *cwRequest, c *middleware.Context) { - cfg := getAwsConfig(req) + cfg, err := getAwsConfig(req) + if err != nil { + c.JsonApiErr(500, "Unable to call AWS API", err) + return + } svc := cloudwatch.New(session.New(cfg), cfg) reqParam := &struct { @@ -220,7 +227,11 @@ func handleGetMetricStatistics(req *cwRequest, c *middleware.Context) { } func handleListMetrics(req *cwRequest, c *middleware.Context) { - cfg := getAwsConfig(req) + cfg, err := getAwsConfig(req) + if err != nil { + c.JsonApiErr(500, "Unable to call AWS API", err) + return + } svc := cloudwatch.New(session.New(cfg), cfg) reqParam := &struct { @@ -239,7 +250,7 @@ func handleListMetrics(req *cwRequest, c *middleware.Context) { } var resp cloudwatch.ListMetricsOutput - err := svc.ListMetricsPages(params, + err = svc.ListMetricsPages(params, func(page *cloudwatch.ListMetricsOutput, lastPage bool) bool { metrics.M_Aws_CloudWatch_ListMetrics.Inc(1) metrics, _ := awsutil.ValuesAtPath(page, "Metrics") @@ -257,7 +268,11 @@ func handleListMetrics(req *cwRequest, c *middleware.Context) { } func handleDescribeAlarms(req *cwRequest, c *middleware.Context) { - cfg := getAwsConfig(req) + cfg, err := getAwsConfig(req) + if err != nil { + c.JsonApiErr(500, "Unable to call AWS API", err) + return + } svc := cloudwatch.New(session.New(cfg), cfg) reqParam := &struct { @@ -296,7 +311,11 @@ func handleDescribeAlarms(req *cwRequest, c *middleware.Context) { } func handleDescribeAlarmsForMetric(req *cwRequest, c *middleware.Context) { - cfg := getAwsConfig(req) + cfg, err := getAwsConfig(req) + if err != nil { + c.JsonApiErr(500, "Unable to call AWS API", err) + return + } svc := cloudwatch.New(session.New(cfg), cfg) reqParam := &struct { @@ -336,7 +355,11 @@ func handleDescribeAlarmsForMetric(req *cwRequest, c *middleware.Context) { } func handleDescribeAlarmHistory(req *cwRequest, c *middleware.Context) { - cfg := getAwsConfig(req) + cfg, err := getAwsConfig(req) + if err != nil { + c.JsonApiErr(500, "Unable to call AWS API", err) + return + } svc := cloudwatch.New(session.New(cfg), cfg) reqParam := &struct { @@ -368,7 +391,11 @@ func handleDescribeAlarmHistory(req *cwRequest, c *middleware.Context) { } func handleDescribeInstances(req *cwRequest, c *middleware.Context) { - cfg := getAwsConfig(req) + cfg, err := getAwsConfig(req) + if err != nil { + c.JsonApiErr(500, "Unable to call AWS API", err) + return + } svc := ec2.New(session.New(cfg), cfg) reqParam := &struct { @@ -388,7 +415,7 @@ func handleDescribeInstances(req *cwRequest, c *middleware.Context) { } var resp ec2.DescribeInstancesOutput - err := svc.DescribeInstancesPages(params, + err = svc.DescribeInstancesPages(params, func(page *ec2.DescribeInstancesOutput, lastPage bool) bool { reservations, _ := awsutil.ValuesAtPath(page, "Reservations") for _, reservation := range reservations { diff --git a/pkg/api/cloudwatch/metrics.go b/pkg/api/cloudwatch/metrics.go index 28fc9a11df6..6013e7f30c2 100644 --- a/pkg/api/cloudwatch/metrics.go +++ b/pkg/api/cloudwatch/metrics.go @@ -248,9 +248,13 @@ func handleGetDimensions(req *cwRequest, c *middleware.Context) { } func getAllMetrics(cwData *datasourceInfo) (cloudwatch.ListMetricsOutput, error) { + creds, err := getCredentials(cwData) + if err != nil { + return cloudwatch.ListMetricsOutput{}, err + } cfg := &aws.Config{ Region: aws.String(cwData.Region), - Credentials: getCredentials(cwData), + Credentials: creds, } svc := cloudwatch.New(session.New(cfg), cfg) @@ -260,7 +264,7 @@ func getAllMetrics(cwData *datasourceInfo) (cloudwatch.ListMetricsOutput, error) } var resp cloudwatch.ListMetricsOutput - err := svc.ListMetricsPages(params, + err = svc.ListMetricsPages(params, func(page *cloudwatch.ListMetricsOutput, lastPage bool) bool { metrics.M_Aws_CloudWatch_ListMetrics.Inc(1) metrics, _ := awsutil.ValuesAtPath(page, "Metrics")