mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
feat(cloudwatch): refactoring and cleanup of backend code, started moving hard coded stuff in the frontend to the backend, changed name of metricFind queries region() -> regions() , and namespace() -> namespaces() to be more consistent with the others, #684
This commit is contained in:
parent
04f4454974
commit
180ba33ac8
150
pkg/api/cloudwatch/cloudwatch.go
Normal file
150
pkg/api/cloudwatch/cloudwatch.go
Normal file
@ -0,0 +1,150 @@
|
||||
package cloudwatch
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"time"
|
||||
|
||||
"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/grafana/grafana/pkg/middleware"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
|
||||
type actionHandler func(*cwRequest, *middleware.Context)
|
||||
|
||||
var actionHandlers map[string]actionHandler
|
||||
|
||||
type cwRequest struct {
|
||||
Region string `json:"region"`
|
||||
Action string `json:"action"`
|
||||
Body []byte `json:"-"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
actionHandlers = map[string]actionHandler{
|
||||
"GetMetricStatistics": handleGetMetricStatistics,
|
||||
"ListMetrics": handleListMetrics,
|
||||
"DescribeInstances": handleDescribeInstances,
|
||||
"__GetRegions": handleGetRegions,
|
||||
}
|
||||
}
|
||||
|
||||
func handleGetMetricStatistics(req *cwRequest, c *middleware.Context) {
|
||||
svc := cloudwatch.New(&aws.Config{Region: aws.String(req.Region)})
|
||||
|
||||
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) {
|
||||
svc := cloudwatch.New(&aws.Config{Region: aws.String(req.Region)})
|
||||
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 handleGetRegions(req *cwRequest, c *middleware.Context) {
|
||||
regions := []string{
|
||||
"us-west-2", "us-west-1", "eu-west-1", "eu-central-1", "ap-southeast-1",
|
||||
"ap-southeast-2", "ap-northeast-1", "sa-east-1",
|
||||
}
|
||||
|
||||
result := []interface{}{}
|
||||
for _, region := range regions {
|
||||
result = append(result, util.DynMap{"text": region, "value": region})
|
||||
}
|
||||
|
||||
c.JSON(200, result)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ import (
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/cloudwatch"
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/middleware"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
@ -83,7 +84,7 @@ func ProxyDataSourceRequest(c *middleware.Context) {
|
||||
}
|
||||
|
||||
if query.Result.Type == m.DS_CLOUDWATCH {
|
||||
ProxyCloudWatchDataSourceRequest(c)
|
||||
cloudwatch.HandleRequest(c)
|
||||
} else {
|
||||
proxyPath := c.Params("*")
|
||||
proxy := NewReverseProxy(&ds, proxyPath, targetUrl)
|
||||
|
@ -1,125 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"time"
|
||||
|
||||
"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/grafana/grafana/pkg/middleware"
|
||||
)
|
||||
|
||||
func ProxyCloudWatchDataSourceRequest(c *middleware.Context) {
|
||||
body, _ := ioutil.ReadAll(c.Req.Request.Body)
|
||||
|
||||
reqInfo := &struct {
|
||||
Region string `json:"region"`
|
||||
Service string `json:"service"`
|
||||
Action string `json:"action"`
|
||||
}{}
|
||||
json.Unmarshal([]byte(body), reqInfo)
|
||||
|
||||
switch reqInfo.Service {
|
||||
case "CloudWatch":
|
||||
svc := cloudwatch.New(&aws.Config{Region: aws.String(reqInfo.Region)})
|
||||
|
||||
switch reqInfo.Action {
|
||||
case "GetMetricStatistics":
|
||||
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([]byte(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
|
||||
}
|
||||
|
||||
respJson, _ := json.Marshal(resp)
|
||||
fmt.Fprint(c.RW(), string(respJson))
|
||||
case "ListMetrics":
|
||||
reqParam := &struct {
|
||||
Parameters struct {
|
||||
Namespace string `json:"namespace"`
|
||||
MetricName string `json:"metricName"`
|
||||
Dimensions []*cloudwatch.DimensionFilter `json:"dimensions"`
|
||||
} `json:"parameters"`
|
||||
}{}
|
||||
json.Unmarshal([]byte(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
|
||||
}
|
||||
|
||||
respJson, _ := json.Marshal(resp)
|
||||
fmt.Fprint(c.RW(), string(respJson))
|
||||
default:
|
||||
c.JsonApiErr(500, "Unexpected CloudWatch action", errors.New(reqInfo.Action))
|
||||
}
|
||||
case "EC2":
|
||||
svc := ec2.New(&aws.Config{Region: aws.String(reqInfo.Region)})
|
||||
|
||||
switch reqInfo.Action {
|
||||
case "DescribeInstances":
|
||||
reqParam := &struct {
|
||||
Parameters struct {
|
||||
Filters []*ec2.Filter `json:"filters"`
|
||||
InstanceIds []*string `json:"instanceIds"`
|
||||
} `json:"parameters"`
|
||||
}{}
|
||||
json.Unmarshal([]byte(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
|
||||
}
|
||||
|
||||
respJson, _ := json.Marshal(resp)
|
||||
fmt.Fprint(c.RW(), string(respJson))
|
||||
default:
|
||||
c.JsonApiErr(500, "Unexpected EC2 action", errors.New(reqInfo.Action))
|
||||
}
|
||||
default:
|
||||
c.JsonApiErr(500, "Unexpected service", errors.New(reqInfo.Service))
|
||||
}
|
||||
}
|
@ -20,9 +20,6 @@ function (angular, _) {
|
||||
this.defaultRegion = datasource.jsonData.defaultRegion;
|
||||
|
||||
/* jshint -W101 */
|
||||
this.supportedRegion = [
|
||||
'us-east-1', 'us-west-2', 'us-west-1', 'eu-west-1', 'eu-central-1', 'ap-southeast-1', 'ap-southeast-2', 'ap-northeast-1', 'sa-east-1'
|
||||
];
|
||||
|
||||
this.supportedMetrics = {
|
||||
'AWS/AutoScaling': [
|
||||
@ -265,7 +262,6 @@ function (angular, _) {
|
||||
CloudWatchDatasource.prototype.performTimeSeriesQuery = function(query, start, end) {
|
||||
return this.awsRequest({
|
||||
region: query.region,
|
||||
service: 'CloudWatch',
|
||||
action: 'GetMetricStatistics',
|
||||
parameters: {
|
||||
namespace: query.namespace,
|
||||
@ -280,7 +276,7 @@ function (angular, _) {
|
||||
};
|
||||
|
||||
CloudWatchDatasource.prototype.getRegions = function() {
|
||||
return $q.when(this.supportedRegion);
|
||||
return this.awsRequest({action: '__GetRegions'});
|
||||
};
|
||||
|
||||
CloudWatchDatasource.prototype.getNamespaces = function() {
|
||||
@ -300,7 +296,6 @@ function (angular, _) {
|
||||
CloudWatchDatasource.prototype.getDimensionValues = function(region, namespace, metricName, dimensions) {
|
||||
var request = {
|
||||
region: templateSrv.replace(region),
|
||||
service: 'CloudWatch',
|
||||
action: 'ListMetrics',
|
||||
parameters: {
|
||||
namespace: templateSrv.replace(namespace),
|
||||
@ -321,7 +316,6 @@ function (angular, _) {
|
||||
CloudWatchDatasource.prototype.performEC2DescribeInstances = function(region, filters, instanceIds) {
|
||||
return this.awsRequest({
|
||||
region: region,
|
||||
service: 'EC2',
|
||||
action: 'DescribeInstances',
|
||||
parameters: {
|
||||
filter: filters,
|
||||
@ -341,12 +335,12 @@ function (angular, _) {
|
||||
});
|
||||
};
|
||||
|
||||
var regionQuery = query.match(/^region\(\)/);
|
||||
var regionQuery = query.match(/^regions\(\)/);
|
||||
if (regionQuery) {
|
||||
return this.getRegions().then(transformSuggestData);
|
||||
return this.getRegions();
|
||||
}
|
||||
|
||||
var namespaceQuery = query.match(/^namespace\(\)/);
|
||||
var namespaceQuery = query.match(/^namespaces\(\)/);
|
||||
if (namespaceQuery) {
|
||||
return this.getNamespaces().then(transformSuggestData);
|
||||
}
|
||||
|
@ -25,12 +25,12 @@ function (angular, _) {
|
||||
};
|
||||
|
||||
$scope.getRegions = function() {
|
||||
return $scope.datasource.metricFindQuery('region()')
|
||||
return $scope.datasource.metricFindQuery('regions()')
|
||||
.then($scope.transformToSegments(true));
|
||||
};
|
||||
|
||||
$scope.getNamespaces = function() {
|
||||
return $scope.datasource.metricFindQuery('namespace()')
|
||||
return $scope.datasource.metricFindQuery('namespaces()')
|
||||
.then($scope.transformToSegments(true));
|
||||
};
|
||||
|
||||
|
@ -108,17 +108,27 @@ describe('CloudWatchDatasource', function() {
|
||||
};
|
||||
});
|
||||
|
||||
it('should return suggest list for region()', function(done) {
|
||||
var query = 'region()';
|
||||
ctx.ds.metricFindQuery(query).then(function(result) {
|
||||
expect(result[0].text).to.contain('us-east-1');
|
||||
done();
|
||||
describe('regions()', () => {
|
||||
let params, result;
|
||||
beforeEach(() => {
|
||||
ctx.backendSrv.datasourceRequest = args => {
|
||||
params = args;
|
||||
return ctx.$q.when({data: [{text: 'us-east-1'}]});
|
||||
};
|
||||
ctx.ds.metricFindQuery("regions()").then(args => {
|
||||
result = args;
|
||||
});
|
||||
ctx.$rootScope.$apply();
|
||||
});
|
||||
|
||||
it('should issue __GetRegions request', () => {
|
||||
expect(result[0].text).to.contain('us-east-1');
|
||||
expect(params.data.action).to.be('__GetRegions');
|
||||
});
|
||||
ctx.$rootScope.$apply();
|
||||
});
|
||||
|
||||
it('should return suggest list for namespace()', function(done) {
|
||||
var query = 'namespace()';
|
||||
var query = 'namespaces()';
|
||||
ctx.ds.metricFindQuery(query).then(function(result) {
|
||||
result = result.map(function(v) { return v.text; });
|
||||
expect(result).to.contain('AWS/EC2');
|
||||
|
Loading…
Reference in New Issue
Block a user