From add5bb47d5a84a620abfe599e04c749b1901c1de Mon Sep 17 00:00:00 2001 From: Mitsuhiro Tanda Date: Sat, 14 Nov 2015 19:54:24 +0900 Subject: [PATCH] add dimensions() to CloudWatch templating query --- .../datasource/cloudwatch/datasource.js | 64 ++++++++++++++----- .../datasource/cloudwatch/query_ctrl.js | 20 +----- .../cloudwatch/specs/datasource_specs.ts | 26 +++++++- 3 files changed, 77 insertions(+), 33 deletions(-) diff --git a/public/app/plugins/datasource/cloudwatch/datasource.js b/public/app/plugins/datasource/cloudwatch/datasource.js index d4c622eac55..4512aed972b 100644 --- a/public/app/plugins/datasource/cloudwatch/datasource.js +++ b/public/app/plugins/datasource/cloudwatch/datasource.js @@ -112,14 +112,14 @@ function (angular, _) { }); }; - CloudWatchDatasource.prototype.getDimensionValues = function(region, namespace, metricName, dimensions) { + CloudWatchDatasource.prototype.getDimensions = function(region, namespace, metricName, filterDimensions) { var request = { region: templateSrv.replace(region), action: 'ListMetrics', parameters: { namespace: templateSrv.replace(namespace), metricName: templateSrv.replace(metricName), - dimensions: convertDimensionFormat(dimensions, {}), + dimensions: convertDimensionFormat(filterDimensions, {}), } }; @@ -128,6 +128,17 @@ function (angular, _) { }); }; + CloudWatchDatasource.prototype.getDimensionValues = function(region, namespace, metricName, dimensionKey, filterDimensions) { + return this.getDimensions(region, namespace, metricName, filterDimensions).then(function(dimensions) { + return _.chain(dimensions) + .flatten() + .filter(function(dimension) { + return dimension.Name === dimensionKey; + }) + .pluck('Value').uniq().sortBy().value(); + }); + }; + CloudWatchDatasource.prototype.performEC2DescribeInstances = function(region, filters, instanceIds) { return this.awsRequest({ region: region, @@ -140,6 +151,8 @@ function (angular, _) { var region; var namespace; var metricName; + var dimensionPart; + var dimensions; var transformSuggestData = function(suggestData) { return _.map(suggestData, function(v) { @@ -147,6 +160,21 @@ function (angular, _) { }); }; + var parseDimensions = function(dimensionPart) { + if (_.isEmpty(dimensionPart)) { + return {}; + } + var dimensions = {}; + _.each(dimensionPart.split(','), function(v) { + var t = v.split('='); + if (t.length !== 2) { + throw new Error('Invalid query format'); + } + dimensions[t[0]] = t[1]; + }); + return dimensions; + }; + var regionQuery = query.match(/^regions\(\)/); if (regionQuery) { return this.getRegions(); @@ -167,25 +195,31 @@ function (angular, _) { return this.getDimensionKeys(dimensionKeysQuery[1]); } - var dimensionValuesQuery = query.match(/^dimension_values\(([^,]+?),\s?([^,]+?),\s?([^,]+?)(,\s?([^)]*))?\)/); + var dimensionValuesQuery = query.match(/^dimension_values\(([^,]+?),\s?([^,]+?),\s?([^,]+?),\s?([^,]+?)(,\s?([^)]*))?\)/); if (dimensionValuesQuery) { region = templateSrv.replace(dimensionValuesQuery[1]); namespace = templateSrv.replace(dimensionValuesQuery[2]); metricName = templateSrv.replace(dimensionValuesQuery[3]); - var dimensionPart = templateSrv.replace(dimensionValuesQuery[5]); + var dimensionKey = templateSrv.replace(dimensionValuesQuery[4]); + dimensionPart = templateSrv.replace(dimensionValuesQuery[6]); - var dimensions = {}; - if (!_.isEmpty(dimensionPart)) { - _.each(dimensionPart.split(','), function(v) { - var t = v.split('='); - if (t.length !== 2) { - throw new Error('Invalid query format'); - } - dimensions[t[0]] = t[1]; + dimensions = parseDimensions(dimensionPart); + return this.getDimensionValues(region, namespace, metricName, dimensionKey, dimensions).then(function(result) { + return _.map(result, function(dimension_value) { + return { text: dimension_value }; }); - } + }); + } - return this.getDimensionValues(region, namespace, metricName, dimensions).then(function(result) { + var dimensionsQuery = query.match(/^dimensions\(([^,]+?),\s?([^,]+?),\s?([^,]+?)(,\s?([^)]*))?\)/); + if (dimensionsQuery) { + region = templateSrv.replace(dimensionsQuery[1]); + namespace = templateSrv.replace(dimensionsQuery[2]); + metricName = templateSrv.replace(dimensionsQuery[3]); + dimensionPart = templateSrv.replace(dimensionsQuery[5]); + + dimensions = parseDimensions(dimensionPart); + return this.getDimensions(region, namespace, metricName, dimensions).then(function(result) { return _.map(result, function(dimensions) { var values = _.chain(dimensions) .sortBy(function(dimension) { @@ -228,7 +262,7 @@ function (angular, _) { var metricName = 'EstimatedCharges'; var dimensions = {}; - return this.getDimensionValues(region, namespace, metricName, dimensions).then(function () { + return this.getDimensions(region, namespace, metricName, dimensions).then(function () { return { status: 'success', message: 'Data source is working', title: 'Success' }; }); }; diff --git a/public/app/plugins/datasource/cloudwatch/query_ctrl.js b/public/app/plugins/datasource/cloudwatch/query_ctrl.js index 7bcc73b4323..d0f6fe5b52a 100644 --- a/public/app/plugins/datasource/cloudwatch/query_ctrl.js +++ b/public/app/plugins/datasource/cloudwatch/query_ctrl.js @@ -85,25 +85,11 @@ function (angular, _) { if (segment.type === 'key' || segment.type === 'plus-button') { query = $scope.datasource.getDimensionKeys($scope.target.namespace); } else if (segment.type === 'value') { - query = $scope.datasource.getDimensionValues(target.region, target.namespace, target.metricName, {}); + var dimensionKey = $scope.dimSegments[$index-2].value; + query = $scope.datasource.getDimensionValues(target.region, target.namespace, target.metricName, dimensionKey, {}); } - return query.then(function(results) { - if (segment.type === 'value') { - results = _.chain(results) - .flatten(true) - .filter(function(dimension) { - return dimension.Name === templateSrv.replace($scope.dimSegments[$index-2].value); - }) - .pluck('Value') - .uniq() - .map(function(value) { - return {value: value, text: value}; - }) - .value(); - } - return $scope.transformToSegments(true)(results); - }).then(function(results) { + return query.then($scope.transformToSegments(true)).then(function(results) { if (segment.type === 'key') { results.splice(0, 0, angular.copy($scope.removeDimSegment)); } diff --git a/public/app/plugins/datasource/cloudwatch/specs/datasource_specs.ts b/public/app/plugins/datasource/cloudwatch/specs/datasource_specs.ts index a6d4330a37e..6c55eab55ca 100644 --- a/public/app/plugins/datasource/cloudwatch/specs/datasource_specs.ts +++ b/public/app/plugins/datasource/cloudwatch/specs/datasource_specs.ts @@ -146,7 +146,7 @@ describe('CloudWatchDatasource', function() { }); }); - describeMetricFindQuery('dimension_values(us-east-1,AWS/EC2,CPUUtilization)', scenario => { + describeMetricFindQuery('dimensions(us-east-1,AWS/EC2,CPUUtilization)', scenario => { scenario.setup(() => { scenario.requestResponse = { Metrics: [ @@ -170,4 +170,28 @@ describe('CloudWatchDatasource', function() { }); }); + describeMetricFindQuery('dimension_values(us-east-1,AWS/EC2,CPUUtilization,InstanceId)', scenario => { + scenario.setup(() => { + scenario.requestResponse = { + Metrics: [ + { + Namespace: 'AWS/EC2', + MetricName: 'CPUUtilization', + Dimensions: [ + { + Name: 'InstanceId', + Value: 'i-12345678' + } + ] + } + ] + }; + }); + + it('should call __ListMetrics and return result', () => { + expect(scenario.result[0].text).to.be('i-12345678'); + expect(scenario.request.data.action).to.be('ListMetrics'); + }); + }); + });