Files
grafana/public/app/plugins/datasource/cloudwatch/datasource.js

296 lines
9.1 KiB
JavaScript
Raw Normal View History

2015-07-30 11:37:31 +09:00
define([
'angular',
'lodash',
'moment',
'./query_ctrl',
'./directives',
2015-07-30 11:37:31 +09:00
],
2015-09-26 02:10:22 +09:00
function (angular, _) {
2015-07-30 11:37:31 +09:00
'use strict';
var module = angular.module('grafana.services');
module.factory('CloudWatchDatasource', function($q, backendSrv, templateSrv) {
2015-07-30 11:37:31 +09:00
function CloudWatchDatasource(datasource) {
this.type = 'cloudwatch';
this.name = datasource.name;
this.supportMetrics = true;
2015-08-13 21:20:47 +09:00
this.proxyUrl = datasource.url;
2015-08-10 23:15:25 +09:00
this.defaultRegion = datasource.jsonData.defaultRegion;
2015-07-30 11:37:31 +09:00
}
CloudWatchDatasource.prototype.query = function(options) {
var start = convertToCloudWatchTime(options.range.from);
var end = convertToCloudWatchTime(options.range.to);
var queries = [];
options = _.clone(options);
2015-07-30 11:37:31 +09:00
_.each(options.targets, _.bind(function(target) {
if (target.hide || !target.namespace || !target.metricName || _.isEmpty(target.statistics)) {
2015-07-30 11:37:31 +09:00
return;
}
var query = {};
2015-08-10 23:15:25 +09:00
query.region = templateSrv.replace(target.region, options.scopedVars);
2015-07-30 11:37:31 +09:00
query.namespace = templateSrv.replace(target.namespace, options.scopedVars);
query.metricName = templateSrv.replace(target.metricName, options.scopedVars);
2015-10-28 19:36:49 +09:00
query.dimensions = convertDimensionFormat(target.dimensions, options.scopedVars);
query.statistics = target.statistics;
2015-07-30 11:37:31 +09:00
2015-08-13 21:20:47 +09:00
var range = end - start;
query.period = parseInt(target.period, 10) || (query.namespace === 'AWS/EC2' ? 300 : 60);
2015-07-30 11:37:31 +09:00
if (range / query.period >= 1440) {
query.period = Math.ceil(range / 1440 / 60) * 60;
2015-07-30 11:37:31 +09:00
}
target.period = query.period;
2015-07-30 11:37:31 +09:00
queries.push(query);
}, this));
// No valid targets, return the empty result to save a round trip.
if (_.isEmpty(queries)) {
var d = $q.defer();
d.resolve({ data: [] });
return d.promise;
}
var allQueryPromise = _.map(queries, function(query) {
2015-07-30 11:37:31 +09:00
return this.performTimeSeriesQuery(query, start, end);
}, this);
2015-07-30 11:37:31 +09:00
return $q.all(allQueryPromise).then(function(allResponse) {
var result = [];
2015-07-30 11:37:31 +09:00
_.each(allResponse, function(response, index) {
var metrics = transformMetricData(response, options.targets[index]);
result = result.concat(metrics);
2015-07-30 11:37:31 +09:00
});
return { data: result };
});
2015-07-30 11:37:31 +09:00
};
CloudWatchDatasource.prototype.performTimeSeriesQuery = function(query, start, end) {
return this.awsRequest({
region: query.region,
action: 'GetMetricStatistics',
parameters: {
namespace: query.namespace,
metricName: query.metricName,
dimensions: query.dimensions,
statistics: query.statistics,
startTime: start,
endTime: end,
period: query.period
}
});
2015-07-30 11:37:31 +09:00
};
CloudWatchDatasource.prototype.getRegions = function() {
return this.awsRequest({action: '__GetRegions'});
2015-08-11 10:25:25 +09:00
};
CloudWatchDatasource.prototype.getNamespaces = function() {
return this.awsRequest({action: '__GetNamespaces'});
2015-08-11 10:25:25 +09:00
};
CloudWatchDatasource.prototype.getMetrics = function(namespace) {
return this.awsRequest({
action: '__GetMetrics',
parameters: {
namespace: templateSrv.replace(namespace)
}
});
2015-08-11 10:25:25 +09:00
};
CloudWatchDatasource.prototype.getDimensionKeys = function(namespace) {
return this.awsRequest({
action: '__GetDimensions',
parameters: {
namespace: templateSrv.replace(namespace)
}
});
2015-08-11 10:25:25 +09:00
};
2015-11-17 22:49:46 +09:00
CloudWatchDatasource.prototype.getDimensionValues = function(region, namespace, metricName, dimensionKey, filterDimensions) {
var request = {
region: templateSrv.replace(region),
action: 'ListMetrics',
parameters: {
namespace: templateSrv.replace(namespace),
metricName: templateSrv.replace(metricName),
dimensions: convertDimensionFormat(filterDimensions, {}),
}
};
2015-08-11 10:25:25 +09:00
return this.awsRequest(request).then(function(result) {
2015-11-17 22:49:46 +09:00
return _.chain(result.Metrics)
.pluck('Dimensions')
.flatten()
.filter(function(dimension) {
return dimension.Name === dimensionKey;
})
2015-11-16 16:47:28 +09:00
.pluck('Value')
.uniq()
.sortBy()
.map(function(value) {
return {value: value, text: value};
}).value();
2015-07-30 11:37:31 +09:00
});
};
2015-09-18 20:00:11 +09:00
CloudWatchDatasource.prototype.performEC2DescribeInstances = function(region, filters, instanceIds) {
return this.awsRequest({
region: region,
action: 'DescribeInstances',
parameters: { filter: filters, instanceIds: instanceIds }
});
};
2015-08-11 00:09:25 +09:00
CloudWatchDatasource.prototype.metricFindQuery = function(query) {
var region;
var namespace;
var metricName;
var transformSuggestData = function(suggestData) {
return _.map(suggestData, function(v) {
return { text: v };
});
};
var regionQuery = query.match(/^regions\(\)/);
2015-08-11 00:09:25 +09:00
if (regionQuery) {
return this.getRegions();
2015-08-11 00:09:25 +09:00
}
var namespaceQuery = query.match(/^namespaces\(\)/);
2015-08-11 00:09:25 +09:00
if (namespaceQuery) {
return this.getNamespaces();
2015-08-11 00:09:25 +09:00
}
var metricNameQuery = query.match(/^metrics\(([^\)]+?)\)/);
if (metricNameQuery) {
return this.getMetrics(metricNameQuery[1]);
2015-08-11 00:09:25 +09:00
}
var dimensionKeysQuery = query.match(/^dimension_keys\(([^\)]+?)\)/);
if (dimensionKeysQuery) {
return this.getDimensionKeys(dimensionKeysQuery[1]);
2015-08-11 00:09:25 +09:00
}
2015-12-04 01:02:25 +09:00
var dimensionValuesQuery = query.match(/^dimension_values\(([^,]+?),\s?([^,]+?),\s?([^,]+?),\s?([^,]+?)\)/);
2015-08-11 00:09:25 +09:00
if (dimensionValuesQuery) {
2015-08-18 13:29:17 +09:00
region = templateSrv.replace(dimensionValuesQuery[1]);
namespace = templateSrv.replace(dimensionValuesQuery[2]);
metricName = templateSrv.replace(dimensionValuesQuery[3]);
var dimensionKey = templateSrv.replace(dimensionValuesQuery[4]);
2015-12-04 01:02:25 +09:00
return this.getDimensionValues(region, namespace, metricName, dimensionKey, {});
2015-08-11 00:09:25 +09:00
}
2015-09-17 18:07:40 +09:00
var ebsVolumeIdsQuery = query.match(/^ebs_volume_ids\(([^,]+?),\s?([^,]+?)\)/);
if (ebsVolumeIdsQuery) {
region = templateSrv.replace(ebsVolumeIdsQuery[1]);
var instanceId = templateSrv.replace(ebsVolumeIdsQuery[2]);
2015-09-18 20:00:11 +09:00
var instanceIds = [
instanceId
];
2015-09-17 18:07:40 +09:00
return this.performEC2DescribeInstances(region, [], instanceIds).then(function(result) {
2015-09-18 20:00:11 +09:00
var volumeIds = _.map(result.Reservations[0].Instances[0].BlockDeviceMappings, function(mapping) {
2015-11-11 19:04:51 +09:00
return mapping.Ebs.VolumeId;
2015-09-17 18:07:40 +09:00
});
2015-09-18 20:00:11 +09:00
return transformSuggestData(volumeIds);
2015-09-17 18:07:40 +09:00
});
}
2015-08-11 00:09:25 +09:00
return $q.when([]);
};
2015-07-30 11:37:31 +09:00
CloudWatchDatasource.prototype.testDatasource = function() {
2015-08-11 10:25:25 +09:00
/* use billing metrics for test */
var region = this.defaultRegion;
2015-08-11 10:25:25 +09:00
var namespace = 'AWS/Billing';
var metricName = 'EstimatedCharges';
var dimensions = {};
2015-11-17 22:49:46 +09:00
return this.getDimensionValues(region, namespace, metricName, 'ServiceName', dimensions).then(function () {
2015-07-30 11:37:31 +09:00
return { status: 'success', message: 'Data source is working', title: 'Success' };
});
};
CloudWatchDatasource.prototype.awsRequest = function(data) {
var options = {
method: 'POST',
url: this.proxyUrl,
data: data
};
2015-08-13 21:20:47 +09:00
return backendSrv.datasourceRequest(options).then(function(result) {
return result.data;
});
2015-08-10 23:15:25 +09:00
};
CloudWatchDatasource.prototype.getDefaultRegion = function() {
return this.defaultRegion;
};
2015-07-30 11:37:31 +09:00
function transformMetricData(md, options) {
var aliasRegex = /\{\{(.+?)\}\}/g;
var aliasPattern = options.alias || '{{metric}}_{{stat}}';
var aliasData = {
region: templateSrv.replace(options.region),
namespace: templateSrv.replace(options.namespace),
metric: templateSrv.replace(options.metricName),
};
_.extend(aliasData, options.dimensions);
var periodMs = options.period * 1000;
return _.map(options.statistics, function(stat) {
var dps = [];
var lastTimestamp = null;
_.chain(md.Datapoints)
.sortBy(function(dp) {
return dp.Timestamp;
})
.each(function(dp) {
var timestamp = new Date(dp.Timestamp).getTime();
2015-11-20 13:06:25 +09:00
if (lastTimestamp && (timestamp - lastTimestamp) > periodMs) {
dps.push([null, lastTimestamp + periodMs]);
}
lastTimestamp = timestamp;
dps.push([dp[stat], timestamp]);
});
2015-07-30 11:37:31 +09:00
aliasData.stat = stat;
var seriesName = aliasPattern.replace(aliasRegex, function(match, g1) {
if (aliasData[g1]) {
return aliasData[g1];
}
return g1;
2015-07-30 11:37:31 +09:00
});
return {target: seriesName, datapoints: dps};
2015-08-06 14:41:06 +09:00
});
}
2015-07-30 11:37:31 +09:00
function convertToCloudWatchTime(date) {
2015-09-26 02:15:27 +09:00
return Math.round(date.valueOf() / 1000);
2015-07-30 11:37:31 +09:00
}
2015-10-28 19:36:49 +09:00
function convertDimensionFormat(dimensions, scopedVars) {
return _.map(dimensions, function(value, key) {
2015-08-25 15:45:09 +09:00
return {
2015-10-28 19:36:49 +09:00
Name: templateSrv.replace(key, scopedVars),
Value: templateSrv.replace(value, scopedVars)
2015-08-25 15:45:09 +09:00
};
});
}
2015-07-30 11:37:31 +09:00
return CloudWatchDatasource;
});
});