Files
grafana/pkg/api/cloudwatch/cloudwatch.go
Jari Sukanen 23599814a3 cloudwatch: add support for defining AWS profile for CloudWatch datasource
Add support for defining AWS profile for CloudWatch datasource to support
pulling information from multiple different AWS accounts to single dashboard.

With this change, it is possible to define multiple AWS credentials in
~/.aws/credentials file and connect different data sources to different
AWS accounts.
2015-10-27 17:00:02 +02:00

160 lines
4.5 KiB
Go

package cloudwatch
import (
"encoding/json"
"errors"
"io/ioutil"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
"github.com/aws/aws-sdk-go/service/cloudwatch"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/grafana/grafana/pkg/middleware"
)
type actionHandler func(*cwRequest, *middleware.Context)
var actionHandlers map[string]actionHandler
type cwRequest struct {
Region string `json:"region"`
Profile string `json:"profile"`
Action string `json:"action"`
Body []byte `json:"-"`
}
func init() {
actionHandlers = map[string]actionHandler{
"GetMetricStatistics": handleGetMetricStatistics,
"ListMetrics": handleListMetrics,
"DescribeInstances": handleDescribeInstances,
"__GetRegions": handleGetRegions,
"__GetNamespaces": handleGetNamespaces,
"__GetMetrics": handleGetMetrics,
"__GetDimensions": handleGetDimensions,
}
}
func handleGetMetricStatistics(req *cwRequest, c *middleware.Context) {
creds := credentials.NewChainCredentials(
[]credentials.Provider{
&credentials.EnvProvider{},
&credentials.SharedCredentialsProvider{Filename: "", Profile: req.Profile},
&ec2rolecreds.EC2RoleProvider{ExpiryWindow: 5 * time.Minute},
})
svc := cloudwatch.New(&aws.Config{
Region: aws.String(req.Region),
Credentials: creds,
})
reqParam := &struct {
Parameters struct {
Namespace string `json:"namespace"`
MetricName string `json:"metricName"`
Dimensions []*cloudwatch.Dimension `json:"dimensions"`
Statistics []*string `json:"statistics"`
StartTime int64 `json:"startTime"`
EndTime int64 `json:"endTime"`
Period int64 `json:"period"`
} `json:"parameters"`
}{}
json.Unmarshal(req.Body, reqParam)
params := &cloudwatch.GetMetricStatisticsInput{
Namespace: aws.String(reqParam.Parameters.Namespace),
MetricName: aws.String(reqParam.Parameters.MetricName),
Dimensions: reqParam.Parameters.Dimensions,
Statistics: reqParam.Parameters.Statistics,
StartTime: aws.Time(time.Unix(reqParam.Parameters.StartTime, 0)),
EndTime: aws.Time(time.Unix(reqParam.Parameters.EndTime, 0)),
Period: aws.Int64(reqParam.Parameters.Period),
}
resp, err := svc.GetMetricStatistics(params)
if err != nil {
c.JsonApiErr(500, "Unable to call AWS API", err)
return
}
c.JSON(200, resp)
}
func handleListMetrics(req *cwRequest, c *middleware.Context) {
creds := credentials.NewChainCredentials(
[]credentials.Provider{
&credentials.EnvProvider{},
&credentials.SharedCredentialsProvider{Filename: "", Profile: req.Profile},
&ec2rolecreds.EC2RoleProvider{ExpiryWindow: 5 * time.Minute},
})
svc := cloudwatch.New(&aws.Config{
Region: aws.String(req.Region),
Credentials: creds,
})
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,
}
resp, err := svc.ListMetrics(params)
if err != nil {
c.JsonApiErr(500, "Unable to call AWS API", err)
return
}
c.JSON(200, resp)
}
func handleDescribeInstances(req *cwRequest, c *middleware.Context) {
svc := ec2.New(&aws.Config{Region: aws.String(req.Region)})
reqParam := &struct {
Parameters struct {
Filters []*ec2.Filter `json:"filters"`
InstanceIds []*string `json:"instanceIds"`
} `json:"parameters"`
}{}
json.Unmarshal(req.Body, reqParam)
params := &ec2.DescribeInstancesInput{}
if len(reqParam.Parameters.Filters) > 0 {
params.Filters = reqParam.Parameters.Filters
}
if len(reqParam.Parameters.InstanceIds) > 0 {
params.InstanceIds = reqParam.Parameters.InstanceIds
}
resp, err := svc.DescribeInstances(params)
if err != nil {
c.JsonApiErr(500, "Unable to call AWS API", err)
return
}
c.JSON(200, resp)
}
func HandleRequest(c *middleware.Context) {
var req cwRequest
req.Body, _ = ioutil.ReadAll(c.Req.Request.Body)
json.Unmarshal(req.Body, &req)
if handler, found := actionHandlers[req.Action]; !found {
c.JsonApiErr(500, "Unexpected AWS Action", errors.New(req.Action))
return
} else {
handler(&req, c)
}
}