Explorar o código

add CloudWatch Annotation

Mitsuhiro Tanda %!s(int64=10) %!d(string=hai) anos
pai
achega
1626982a3a

+ 68 - 0
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;

+ 4 - 0
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'};
+  });
+
 });

+ 38 - 0
public/app/plugins/datasource/cloudwatch/partials/annotations.editor.html

@@ -0,0 +1,38 @@
+<div class="editor-row">
+	<div class="section">
+		<h5>Metric name</h5>
+		<div class="editor-option">
+			<input type="text" class="span6" ng-model='currentAnnotation.metricName' placeholder="CPUUtilization"></input>
+		</div>
+	</div>
+</div>
+
+<div class="editor-row">
+	<div class="section">
+		<h5>Field mappings</h5>
+		<div class="editor-option">
+			<label class="small">Region</label>
+			<input type="text" class="input-small" ng-model='currentAnnotation.region' placeholder="us-east-1"></input>
+		</div>
+
+		<div class="editor-option">
+			<label class="small">Namespace</label>
+			<input type="text" class="input-small" ng-model='currentAnnotation.namespace' placeholder="AWS/EC2"></input>
+		</div>
+
+		<div class="editor-option">
+			<label class="small">Dimensions</label>
+			<input type="text" class="input-small" ng-model='currentAnnotation.dimensions' placeholder="InstanceId=i-12345678"></input>
+		</div>
+
+		<div class="editor-option">
+			<label class="small">Statistic</label>
+			<input type="text" class="input-small" ng-model='currentAnnotation.statistic' placeholder="Average"></input>
+		</div>
+
+		<div class="editor-option">
+			<label class="small">Period</label>
+			<input type="text" class="input-small" ng-model='currentAnnotation.period' placeholder="300"></input>
+		</div>
+	</div>
+</div>

+ 2 - 1
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
 }

+ 47 - 0
public/app/plugins/datasource/cloudwatch/specs/datasource_specs.ts

@@ -2,6 +2,7 @@
 ///<amd-dependency path="test/specs/helpers" name="helpers" />
 
 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();
+    });
+  });
 });