From 1626982a3a2460bf9da94dfb32e87e17adb4b386 Mon Sep 17 00:00:00 2001 From: Mitsuhiro Tanda Date: Mon, 26 Oct 2015 15:47:34 +0900 Subject: [PATCH] add CloudWatch Annotation --- .../datasource/cloudwatch/datasource.js | 68 +++++++++++++++++++ .../datasource/cloudwatch/directives.js | 4 ++ .../partials/annotations.editor.html | 38 +++++++++++ .../plugins/datasource/cloudwatch/plugin.json | 3 +- .../cloudwatch/specs/datasource_specs.ts | 47 +++++++++++++ 5 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 public/app/plugins/datasource/cloudwatch/partials/annotations.editor.html diff --git a/public/app/plugins/datasource/cloudwatch/datasource.js b/public/app/plugins/datasource/cloudwatch/datasource.js index e01bdce6096..aeee1e59bf8 100644 --- a/public/app/plugins/datasource/cloudwatch/datasource.js +++ b/public/app/plugins/datasource/cloudwatch/datasource.js @@ -209,6 +209,74 @@ function (angular, _) { return $q.when([]); }; + CloudWatchDatasource.prototype.performDescribeAlarmsForMetric = function(region, namespace, metricName, dimensions, statistic, period) { + return this.awsRequest({ + region: region, + action: 'DescribeAlarmsForMetric', + parameters: { namespace: namespace, metricName: metricName, dimensions: dimensions, statistic: statistic, period: period } + }); + }; + + CloudWatchDatasource.prototype.performDescribeAlarmHistory = function(region, alarmName, startDate, endDate) { + return this.awsRequest({ + region: region, + action: 'DescribeAlarmHistory', + parameters: { alarmName: alarmName, startDate: startDate, endDate: endDate } + }); + }; + + CloudWatchDatasource.prototype.annotationQuery = function(annotation, range) { + 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 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); + + var d = $q.defer(); + var self = this; + this.performDescribeAlarmsForMetric(region, namespace, metricName, dimensions, statistic, period).then(function(alarms) { + var eventList = []; + + var start = convertToCloudWatchTime(range.from); + var end = convertToCloudWatchTime(range.to); + _.each(alarms.MetricAlarms, function(alarm) { + self.performDescribeAlarmHistory(region, alarm.AlarmName, start, end).then(function(history) { + _.each(history.AlarmHistoryItems, function(h) { + var event = { + annotation: annotation, + time: Date.parse(h.Timestamp), + title: h.AlarmName, + tags: [h.HistoryItemType], + text: h.HistorySummary + }; + + eventList.push(event); + }); + + d.resolve(eventList); + }); + }); + }); + + return d.promise; + }; + CloudWatchDatasource.prototype.testDatasource = function() { /* use billing metrics for test */ var region = this.defaultRegion; diff --git a/public/app/plugins/datasource/cloudwatch/directives.js b/public/app/plugins/datasource/cloudwatch/directives.js index c758aa34e5c..22a98e036e4 100644 --- a/public/app/plugins/datasource/cloudwatch/directives.js +++ b/public/app/plugins/datasource/cloudwatch/directives.js @@ -10,4 +10,8 @@ function (angular) { return {controller: 'CloudWatchQueryCtrl', templateUrl: 'app/plugins/datasource/cloudwatch/partials/query.editor.html'}; }); + module.directive('annotationsQueryEditorCloudwatch', function() { + return {templateUrl: 'app/plugins/datasource/cloudwatch/partials/annotations.editor.html'}; + }); + }); diff --git a/public/app/plugins/datasource/cloudwatch/partials/annotations.editor.html b/public/app/plugins/datasource/cloudwatch/partials/annotations.editor.html new file mode 100644 index 00000000000..1db6eb704b3 --- /dev/null +++ b/public/app/plugins/datasource/cloudwatch/partials/annotations.editor.html @@ -0,0 +1,38 @@ +
+
+
Metric name
+
+ +
+
+
+ +
+
+
Field mappings
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+
diff --git a/public/app/plugins/datasource/cloudwatch/plugin.json b/public/app/plugins/datasource/cloudwatch/plugin.json index 1fa46416ca6..f1cf0e5512c 100644 --- a/public/app/plugins/datasource/cloudwatch/plugin.json +++ b/public/app/plugins/datasource/cloudwatch/plugin.json @@ -12,5 +12,6 @@ "query": "app/plugins/datasource/cloudwatch/partials/query.editor.html" }, - "metrics": true + "metrics": true, + "annotations": true } diff --git a/public/app/plugins/datasource/cloudwatch/specs/datasource_specs.ts b/public/app/plugins/datasource/cloudwatch/specs/datasource_specs.ts index f3b105c5da5..fa7f23c46b8 100644 --- a/public/app/plugins/datasource/cloudwatch/specs/datasource_specs.ts +++ b/public/app/plugins/datasource/cloudwatch/specs/datasource_specs.ts @@ -2,6 +2,7 @@ /// import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common'; +import moment = require('moment'); declare var helpers: any; @@ -189,4 +190,50 @@ describe('CloudWatchDatasource', function() { }); }); + describe('When performing annotationQuery', function() { + var annotation = { + region: 'us-east-1', + namespace: 'AWS/EC2', + metricName: 'CPUUtilization', + dimensions: 'InstanceId=i-12345678' + }; + var alarmResponse = { + MetricAlarms: [ + { + AlarmName: 'test_alarm_name' + } + ] + }; + var historyResponse = { + AlarmHistoryItems: [ + { + Timestamp: '2015-01-01T00:00:00.000Z', + HistoryItemType: 'StateUpdate', + AlarmName: 'test_alarm_name', + HistoryData: '{}', + HistorySummary: 'test_history_summary' + } + ] + }; + beforeEach(function() { + ctx.backendSrv.datasourceRequest = function(params) { + switch (params.data.action) { + case 'DescribeAlarmsForMetric': + return ctx.$q.when({data: alarmResponse}); + break; + case 'DescribeAlarmHistory': + return ctx.$q.when({data: historyResponse}); + break; + } + }; + }); + it('should return annotation list', function(done) { + ctx.ds.annotationQuery(annotation, {from: moment(1443438674760), to: moment(1443460274760)}).then(function(result) { + expect(result[0].title).to.be('test_alarm_name'); + expect(result[0].text).to.be('test_history_summary'); + done(); + }); + ctx.$rootScope.$apply(); + }); + }); });