diff --git a/public/app/plugins/datasource/cloudwatch/datasource.js b/public/app/plugins/datasource/cloudwatch/datasource.js index 2b152131bc2..f606b6e3dc8 100644 --- a/public/app/plugins/datasource/cloudwatch/datasource.js +++ b/public/app/plugins/datasource/cloudwatch/datasource.js @@ -231,33 +231,32 @@ function (angular, _, moment, dateMath) { var region = templateSrv.replace(annotation.region); var namespace = templateSrv.replace(annotation.namespace); var metricName = templateSrv.replace(annotation.metricName); - var dimensionPart = templateSrv.replace(annotation.dimensions); - var statistic = templateSrv.replace(annotation.statistic) || ''; + var dimensions = convertDimensionFormat(annotation.dimensions); + var statistics = _.map(annotation.statistics, function(s) { return templateSrv.replace(s); }); var period = annotation.period || '300'; - - if (!region || !namespace || !metricName) { return $q.when([]); } - - 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 = convertDimensionFormat(dimensions); - } period = parseInt(period, 10); + if (!region || !namespace || !metricName || _.isEmpty(statistics)) { return $q.when([]); } + var d = $q.defer(); var self = this; - this.performDescribeAlarmsForMetric(region, namespace, metricName, dimensions, statistic, period).then(function(alarms) { + var allQueryPromise = _.map(statistics, function(statistic) { + return self.performDescribeAlarmsForMetric(region, namespace, metricName, dimensions, statistic, period); + }); + $q.all(allQueryPromise).then(function(alarms) { var eventList = []; var start = convertToCloudWatchTime(options.range.from, false); var end = convertToCloudWatchTime(options.range.to, true); - _.each(alarms.MetricAlarms, function(alarm) { + _.chain(alarms) + .pluck('MetricAlarms') + .flatten() + .each(function(alarm) { + if (!alarm) { + d.resolve(eventList); + return; + } + self.performDescribeAlarmHistory(region, alarm.AlarmName, start, end).then(function(history) { _.each(history.AlarmHistoryItems, function(h) { var event = { diff --git a/public/app/plugins/datasource/cloudwatch/directives.js b/public/app/plugins/datasource/cloudwatch/directives.js index 22a98e036e4..a08d4fc8d9a 100644 --- a/public/app/plugins/datasource/cloudwatch/directives.js +++ b/public/app/plugins/datasource/cloudwatch/directives.js @@ -1,5 +1,6 @@ define([ 'angular', + './query_parameter_ctrl', ], function (angular) { 'use strict'; @@ -14,4 +15,17 @@ function (angular) { return {templateUrl: 'app/plugins/datasource/cloudwatch/partials/annotations.editor.html'}; }); + module.directive('cloudwatchQueryParameter', function() { + return { + templateUrl: 'app/plugins/datasource/cloudwatch/partials/query.parameter.html', + controller: 'CloudWatchQueryParameterCtrl', + restrict: 'E', + scope: { + target: "=", + datasourceName: "@", + onChange: "&", + } + }; + }); + }); diff --git a/public/app/plugins/datasource/cloudwatch/partials/annotations.editor.html b/public/app/plugins/datasource/cloudwatch/partials/annotations.editor.html index ff545b7bf01..dfecb80032d 100644 --- a/public/app/plugins/datasource/cloudwatch/partials/annotations.editor.html +++ b/public/app/plugins/datasource/cloudwatch/partials/annotations.editor.html @@ -1,41 +1 @@ -
-
-
- - -
- -
- - -
- -
- - -
-
-
- -
-
-
- - -
-
-
- -
-
-
- - -
- -
- - -
-
-
+ diff --git a/public/app/plugins/datasource/cloudwatch/partials/query.editor.html b/public/app/plugins/datasource/cloudwatch/partials/query.editor.html index 0984bc521e2..cc2dfa3a601 100644 --- a/public/app/plugins/datasource/cloudwatch/partials/query.editor.html +++ b/public/app/plugins/datasource/cloudwatch/partials/query.editor.html @@ -33,61 +33,16 @@ - -
- - -
- - -
-
- -
-
+ diff --git a/public/app/plugins/datasource/cloudwatch/partials/query.parameter.html b/public/app/plugins/datasource/cloudwatch/partials/query.parameter.html new file mode 100644 index 00000000000..6e2dde5bf48 --- /dev/null +++ b/public/app/plugins/datasource/cloudwatch/partials/query.parameter.html @@ -0,0 +1,53 @@ +
+ + +
+
+ +
+ + +
+
+ +
+ + +
+
+ diff --git a/public/app/plugins/datasource/cloudwatch/query_ctrl.js b/public/app/plugins/datasource/cloudwatch/query_ctrl.js index d0f6fe5b52a..e24b73cd068 100644 --- a/public/app/plugins/datasource/cloudwatch/query_ctrl.js +++ b/public/app/plugins/datasource/cloudwatch/query_ctrl.js @@ -7,173 +7,10 @@ function (angular, _) { var module = angular.module('grafana.controllers'); - module.controller('CloudWatchQueryCtrl', function($scope, templateSrv, uiSegmentSrv, $q) { + module.controller('CloudWatchQueryCtrl', function($scope) { $scope.init = function() { - var target = $scope.target; - target.namespace = target.namespace || ''; - target.metricName = target.metricName || ''; - target.statistics = target.statistics || ['Average']; - target.dimensions = target.dimensions || {}; - target.period = target.period || ''; - target.region = target.region || $scope.datasource.getDefaultRegion(); - $scope.aliasSyntax = '{{metric}} {{stat}} {{namespace}} {{region}} {{}}'; - - $scope.regionSegment = uiSegmentSrv.getSegmentForValue($scope.target.region, 'select region'); - $scope.namespaceSegment = uiSegmentSrv.getSegmentForValue($scope.target.namespace, 'select namespace'); - $scope.metricSegment = uiSegmentSrv.getSegmentForValue($scope.target.metricName, 'select metric'); - - $scope.dimSegments = _.reduce($scope.target.dimensions, function(memo, value, key) { - memo.push(uiSegmentSrv.newKey(key)); - memo.push(uiSegmentSrv.newOperator("=")); - memo.push(uiSegmentSrv.newKeyValue(value)); - return memo; - }, []); - - $scope.statSegments = _.map($scope.target.statistics, function(stat) { - return uiSegmentSrv.getSegmentForValue(stat); - }); - - $scope.ensurePlusButton($scope.statSegments); - $scope.ensurePlusButton($scope.dimSegments); - $scope.removeDimSegment = uiSegmentSrv.newSegment({fake: true, value: '-- remove dimension --'}); - $scope.removeStatSegment = uiSegmentSrv.newSegment({fake: true, value: '-- remove stat --'}); - }; - - $scope.getStatSegments = function() { - return $q.when([ - angular.copy($scope.removeStatSegment), - uiSegmentSrv.getSegmentForValue('Average'), - uiSegmentSrv.getSegmentForValue('Maximum'), - uiSegmentSrv.getSegmentForValue('Minimum'), - uiSegmentSrv.getSegmentForValue('Sum'), - uiSegmentSrv.getSegmentForValue('SampleCount'), - ]); - }; - - $scope.statSegmentChanged = function(segment, index) { - if (segment.value === $scope.removeStatSegment.value) { - $scope.statSegments.splice(index, 1); - } else { - segment.type = 'value'; - } - - $scope.target.statistics = _.reduce($scope.statSegments, function(memo, seg) { - if (!seg.fake) { memo.push(seg.value); } return memo; - }, []); - - $scope.ensurePlusButton($scope.statSegments); - $scope.get_data(); - }; - - $scope.ensurePlusButton = function(segments) { - var count = segments.length; - var lastSegment = segments[Math.max(count-1, 0)]; - - if (!lastSegment || lastSegment.type !== 'plus-button') { - segments.push(uiSegmentSrv.newPlusButton()); - } - }; - - $scope.getDimSegments = function(segment, $index) { - if (segment.type === 'operator') { return $q.when([]); } - - var target = $scope.target; - var query = $q.when([]); - - if (segment.type === 'key' || segment.type === 'plus-button') { - query = $scope.datasource.getDimensionKeys($scope.target.namespace); - } else if (segment.type === 'value') { - var dimensionKey = $scope.dimSegments[$index-2].value; - query = $scope.datasource.getDimensionValues(target.region, target.namespace, target.metricName, dimensionKey, {}); - } - - return query.then($scope.transformToSegments(true)).then(function(results) { - if (segment.type === 'key') { - results.splice(0, 0, angular.copy($scope.removeDimSegment)); - } - return results; - }); - }; - - $scope.dimSegmentChanged = function(segment, index) { - $scope.dimSegments[index] = segment; - - if (segment.value === $scope.removeDimSegment.value) { - $scope.dimSegments.splice(index, 3); - } - else if (segment.type === 'plus-button') { - $scope.dimSegments.push(uiSegmentSrv.newOperator('=')); - $scope.dimSegments.push(uiSegmentSrv.newFake('select dimension value', 'value', 'query-segment-value')); - segment.type = 'key'; - segment.cssClass = 'query-segment-key'; - } - - $scope.syncDimSegmentsWithModel(); - $scope.ensurePlusButton($scope.dimSegments); - $scope.get_data(); - }; - - $scope.syncDimSegmentsWithModel = function() { - var dims = {}; - var length = $scope.dimSegments.length; - - for (var i = 0; i < length - 2; i += 3) { - var keySegment = $scope.dimSegments[i]; - var valueSegment = $scope.dimSegments[i + 2]; - if (!valueSegment.fake) { - dims[keySegment.value] = valueSegment.value; - } - } - - $scope.target.dimensions = dims; - }; - - $scope.getRegions = function() { - return $scope.datasource.metricFindQuery('regions()') - .then($scope.transformToSegments(true)); - }; - - $scope.getNamespaces = function() { - return $scope.datasource.metricFindQuery('namespaces()') - .then($scope.transformToSegments(true)); - }; - - $scope.getMetrics = function() { - return $scope.datasource.metricFindQuery('metrics(' + $scope.target.namespace + ')') - .then($scope.transformToSegments(true)); - }; - - $scope.regionChanged = function() { - $scope.target.region = $scope.regionSegment.value; - $scope.get_data(); - }; - - $scope.namespaceChanged = function() { - $scope.target.namespace = $scope.namespaceSegment.value; - $scope.get_data(); - }; - - $scope.metricChanged = function() { - $scope.target.metricName = $scope.metricSegment.value; - $scope.get_data(); - }; - - $scope.transformToSegments = function(addTemplateVars) { - return function(results) { - var segments = _.map(results, function(segment) { - return uiSegmentSrv.newSegment({ value: segment.text, expandable: segment.expandable }); - }); - - if (addTemplateVars) { - _.each(templateSrv.variables, function(variable) { - segments.unshift(uiSegmentSrv.newSegment({ type: 'template', value: '$' + variable.name, expandable: true })); - }); - } - - return segments; - }; }; $scope.refreshMetricData = function() { diff --git a/public/app/plugins/datasource/cloudwatch/query_parameter_ctrl.js b/public/app/plugins/datasource/cloudwatch/query_parameter_ctrl.js new file mode 100644 index 00000000000..0ed23aff205 --- /dev/null +++ b/public/app/plugins/datasource/cloudwatch/query_parameter_ctrl.js @@ -0,0 +1,192 @@ +define([ + 'angular', + 'lodash', +], +function (angular, _) { + 'use strict'; + + var module = angular.module('grafana.controllers'); + + module.controller('CloudWatchQueryParameterCtrl', function($scope, templateSrv, uiSegmentSrv, datasourceSrv, $q) { + + $scope.init = function() { + var target = $scope.target; + target.namespace = target.namespace || ''; + target.metricName = target.metricName || ''; + target.statistics = target.statistics || ['Average']; + target.dimensions = target.dimensions || {}; + target.period = target.period || ''; + target.region = target.region || ''; + + $scope.regionSegment = uiSegmentSrv.getSegmentForValue($scope.target.region, 'select region'); + $scope.namespaceSegment = uiSegmentSrv.getSegmentForValue($scope.target.namespace, 'select namespace'); + $scope.metricSegment = uiSegmentSrv.getSegmentForValue($scope.target.metricName, 'select metric'); + + $scope.dimSegments = _.reduce($scope.target.dimensions, function(memo, value, key) { + memo.push(uiSegmentSrv.newKey(key)); + memo.push(uiSegmentSrv.newOperator("=")); + memo.push(uiSegmentSrv.newKeyValue(value)); + return memo; + }, []); + + $scope.statSegments = _.map($scope.target.statistics, function(stat) { + return uiSegmentSrv.getSegmentForValue(stat); + }); + + $scope.ensurePlusButton($scope.statSegments); + $scope.ensurePlusButton($scope.dimSegments); + $scope.removeDimSegment = uiSegmentSrv.newSegment({fake: true, value: '-- remove dimension --'}); + $scope.removeStatSegment = uiSegmentSrv.newSegment({fake: true, value: '-- remove stat --'}); + + datasourceSrv.get($scope.datasourceName).then(function(datasource) { + $scope.datasource = datasource; + if (_.isEmpty($scope.target.region)) { + $scope.target.region = $scope.datasource.getDefaultRegion(); + } + }); + + if (!$scope.onChange) { + $scope.onChange = function() {}; + } + }; + + $scope.getStatSegments = function() { + return $q.when([ + angular.copy($scope.removeStatSegment), + uiSegmentSrv.getSegmentForValue('Average'), + uiSegmentSrv.getSegmentForValue('Maximum'), + uiSegmentSrv.getSegmentForValue('Minimum'), + uiSegmentSrv.getSegmentForValue('Sum'), + uiSegmentSrv.getSegmentForValue('SampleCount'), + ]); + }; + + $scope.statSegmentChanged = function(segment, index) { + if (segment.value === $scope.removeStatSegment.value) { + $scope.statSegments.splice(index, 1); + } else { + segment.type = 'value'; + } + + $scope.target.statistics = _.reduce($scope.statSegments, function(memo, seg) { + if (!seg.fake) { memo.push(seg.value); } return memo; + }, []); + + $scope.ensurePlusButton($scope.statSegments); + $scope.onChange(); + }; + + $scope.ensurePlusButton = function(segments) { + var count = segments.length; + var lastSegment = segments[Math.max(count-1, 0)]; + + if (!lastSegment || lastSegment.type !== 'plus-button') { + segments.push(uiSegmentSrv.newPlusButton()); + } + }; + + $scope.getDimSegments = function(segment, $index) { + if (segment.type === 'operator') { return $q.when([]); } + + var target = $scope.target; + var query = $q.when([]); + + if (segment.type === 'key' || segment.type === 'plus-button') { + query = $scope.datasource.getDimensionKeys($scope.target.namespace); + } else if (segment.type === 'value') { + var dimensionKey = $scope.dimSegments[$index-2].value; + query = $scope.datasource.getDimensionValues(target.region, target.namespace, target.metricName, dimensionKey, {}); + } + + return query.then($scope.transformToSegments(true)).then(function(results) { + if (segment.type === 'key') { + results.splice(0, 0, angular.copy($scope.removeDimSegment)); + } + return results; + }); + }; + + $scope.dimSegmentChanged = function(segment, index) { + $scope.dimSegments[index] = segment; + + if (segment.value === $scope.removeDimSegment.value) { + $scope.dimSegments.splice(index, 3); + } + else if (segment.type === 'plus-button') { + $scope.dimSegments.push(uiSegmentSrv.newOperator('=')); + $scope.dimSegments.push(uiSegmentSrv.newFake('select dimension value', 'value', 'query-segment-value')); + segment.type = 'key'; + segment.cssClass = 'query-segment-key'; + } + + $scope.syncDimSegmentsWithModel(); + $scope.ensurePlusButton($scope.dimSegments); + $scope.onChange(); + }; + + $scope.syncDimSegmentsWithModel = function() { + var dims = {}; + var length = $scope.dimSegments.length; + + for (var i = 0; i < length - 2; i += 3) { + var keySegment = $scope.dimSegments[i]; + var valueSegment = $scope.dimSegments[i + 2]; + if (!valueSegment.fake) { + dims[keySegment.value] = valueSegment.value; + } + } + + $scope.target.dimensions = dims; + }; + + $scope.getRegions = function() { + return $scope.datasource.metricFindQuery('regions()') + .then($scope.transformToSegments(true)); + }; + + $scope.getNamespaces = function() { + return $scope.datasource.metricFindQuery('namespaces()') + .then($scope.transformToSegments(true)); + }; + + $scope.getMetrics = function() { + return $scope.datasource.metricFindQuery('metrics(' + $scope.target.namespace + ')') + .then($scope.transformToSegments(true)); + }; + + $scope.regionChanged = function() { + $scope.target.region = $scope.regionSegment.value; + $scope.onChange(); + }; + + $scope.namespaceChanged = function() { + $scope.target.namespace = $scope.namespaceSegment.value; + $scope.onChange(); + }; + + $scope.metricChanged = function() { + $scope.target.metricName = $scope.metricSegment.value; + $scope.onChange(); + }; + + $scope.transformToSegments = function(addTemplateVars) { + return function(results) { + var segments = _.map(results, function(segment) { + return uiSegmentSrv.newSegment({ value: segment.text, expandable: segment.expandable }); + }); + + if (addTemplateVars) { + _.each(templateSrv.variables, function(variable) { + segments.unshift(uiSegmentSrv.newSegment({ type: 'template', value: '$' + variable.name, expandable: true })); + }); + } + + return segments; + }; + }; + + $scope.init(); + + }); + +});