mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
292 lines
8.9 KiB
JavaScript
292 lines
8.9 KiB
JavaScript
define([
|
|
'angular',
|
|
'lodash',
|
|
'moment',
|
|
'./query_ctrl',
|
|
'./directives',
|
|
],
|
|
function (angular, _) {
|
|
'use strict';
|
|
|
|
var module = angular.module('grafana.services');
|
|
|
|
module.factory('CloudWatchDatasource', function($q, backendSrv, templateSrv) {
|
|
|
|
function CloudWatchDatasource(datasource) {
|
|
this.type = 'cloudwatch';
|
|
this.name = datasource.name;
|
|
this.supportMetrics = true;
|
|
this.proxyUrl = datasource.url;
|
|
this.defaultRegion = datasource.jsonData.defaultRegion;
|
|
}
|
|
|
|
CloudWatchDatasource.prototype.query = function(options) {
|
|
var start = convertToCloudWatchTime(options.range.from);
|
|
var end = convertToCloudWatchTime(options.range.to);
|
|
|
|
var queries = [];
|
|
_.each(options.targets, _.bind(function(target) {
|
|
if (target.hide || !target.namespace || !target.metricName || _.isEmpty(target.statistics)) {
|
|
return;
|
|
}
|
|
|
|
var query = {};
|
|
query.region = templateSrv.replace(target.region, options.scopedVars);
|
|
query.namespace = templateSrv.replace(target.namespace, options.scopedVars);
|
|
query.metricName = templateSrv.replace(target.metricName, options.scopedVars);
|
|
query.dimensions = convertDimensionFormat(target.dimensions);
|
|
query.statistics = target.statistics;
|
|
query.period = parseInt(target.period, 10);
|
|
|
|
var range = end - start;
|
|
// CloudWatch limit datapoints up to 1440
|
|
if (range / query.period >= 1440) {
|
|
query.period = Math.floor(range / 1440 / 60) * 60;
|
|
}
|
|
|
|
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) {
|
|
return this.performTimeSeriesQuery(query, start, end);
|
|
}, this);
|
|
|
|
return $q.all(allQueryPromise).then(function(allResponse) {
|
|
var result = [];
|
|
|
|
_.each(allResponse, function(response, index) {
|
|
var metrics = transformMetricData(response, options.targets[index]);
|
|
result = result.concat(metrics);
|
|
});
|
|
|
|
return { data: result };
|
|
});
|
|
};
|
|
|
|
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
|
|
}
|
|
});
|
|
};
|
|
|
|
CloudWatchDatasource.prototype.getRegions = function() {
|
|
return this.awsRequest({action: '__GetRegions'});
|
|
};
|
|
|
|
CloudWatchDatasource.prototype.getNamespaces = function() {
|
|
return this.awsRequest({action: '__GetNamespaces'});
|
|
};
|
|
|
|
CloudWatchDatasource.prototype.getMetrics = function(namespace) {
|
|
return this.awsRequest({
|
|
action: '__GetMetrics',
|
|
parameters: {
|
|
namespace: templateSrv.replace(namespace)
|
|
}
|
|
});
|
|
};
|
|
|
|
CloudWatchDatasource.prototype.getDimensionKeys = function(namespace) {
|
|
return this.awsRequest({
|
|
action: '__GetDimensions',
|
|
parameters: {
|
|
namespace: templateSrv.replace(namespace)
|
|
}
|
|
});
|
|
};
|
|
|
|
CloudWatchDatasource.prototype.getDimensionValues = function(region, namespace, metricName, dimensions) {
|
|
var request = {
|
|
region: templateSrv.replace(region),
|
|
action: 'ListMetrics',
|
|
parameters: {
|
|
namespace: templateSrv.replace(namespace),
|
|
metricName: templateSrv.replace(metricName),
|
|
dimensions: convertDimensionFormat(dimensions),
|
|
}
|
|
};
|
|
|
|
return this.awsRequest(request).then(function(result) {
|
|
return _.chain(result.Metrics).map(function(metric) {
|
|
return _.pluck(metric.Dimensions, 'Value');
|
|
}).flatten().uniq().sortBy(function(name) {
|
|
return name;
|
|
}).map(function(value) {
|
|
return {value: value, text: value};
|
|
}).value();
|
|
});
|
|
};
|
|
|
|
CloudWatchDatasource.prototype.performEC2DescribeInstances = function(region, filters, instanceIds) {
|
|
return this.awsRequest({
|
|
region: region,
|
|
action: 'DescribeInstances',
|
|
parameters: { filter: filters, instanceIds: instanceIds }
|
|
});
|
|
};
|
|
|
|
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\(\)/);
|
|
if (regionQuery) {
|
|
return this.getRegions();
|
|
}
|
|
|
|
var namespaceQuery = query.match(/^namespaces\(\)/);
|
|
if (namespaceQuery) {
|
|
return this.getNamespaces();
|
|
}
|
|
|
|
var metricNameQuery = query.match(/^metrics\(([^\)]+?)\)/);
|
|
if (metricNameQuery) {
|
|
return this.getMetrics(metricNameQuery[1]);
|
|
}
|
|
|
|
var dimensionKeysQuery = query.match(/^dimension_keys\(([^\)]+?)\)/);
|
|
if (dimensionKeysQuery) {
|
|
return this.getDimensionKeys(dimensionKeysQuery[1]);
|
|
}
|
|
|
|
var dimensionValuesQuery = query.match(/^dimension_values\(([^,]+?),\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 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];
|
|
});
|
|
}
|
|
|
|
return this.getDimensionValues(region, namespace, metricName, dimensions);
|
|
}
|
|
|
|
var ebsVolumeIdsQuery = query.match(/^ebs_volume_ids\(([^,]+?),\s?([^,]+?)\)/);
|
|
if (ebsVolumeIdsQuery) {
|
|
region = templateSrv.replace(ebsVolumeIdsQuery[1]);
|
|
var instanceId = templateSrv.replace(ebsVolumeIdsQuery[2]);
|
|
var instanceIds = [
|
|
instanceId
|
|
];
|
|
|
|
return this.performEC2DescribeInstances(region, [], instanceIds).then(function(result) {
|
|
var volumeIds = _.map(result.Reservations[0].Instances[0].BlockDeviceMappings, function(mapping) {
|
|
return mapping.EBS.VolumeID;
|
|
});
|
|
|
|
return transformSuggestData(volumeIds);
|
|
});
|
|
}
|
|
|
|
return $q.when([]);
|
|
};
|
|
|
|
CloudWatchDatasource.prototype.testDatasource = function() {
|
|
/* use billing metrics for test */
|
|
var region = 'us-east-1';
|
|
var namespace = 'AWS/Billing';
|
|
var metricName = 'EstimatedCharges';
|
|
var dimensions = {};
|
|
|
|
return this.getDimensionValues(region, namespace, metricName, dimensions).then(function () {
|
|
return { status: 'success', message: 'Data source is working', title: 'Success' };
|
|
});
|
|
};
|
|
|
|
CloudWatchDatasource.prototype.awsRequest = function(data) {
|
|
var options = {
|
|
method: 'POST',
|
|
url: this.proxyUrl,
|
|
data: data
|
|
};
|
|
|
|
return backendSrv.datasourceRequest(options).then(function(result) {
|
|
return result.data;
|
|
});
|
|
};
|
|
|
|
CloudWatchDatasource.prototype.getDefaultRegion = function() {
|
|
return this.defaultRegion;
|
|
};
|
|
|
|
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);
|
|
|
|
return _.map(options.statistics, function(stat) {
|
|
var dps = _.chain(md.Datapoints).map(function(dp) {
|
|
return [dp[stat], new Date(dp.Timestamp).getTime()];
|
|
})
|
|
.sortBy(function(dp) {
|
|
return dp[1];
|
|
}).value();
|
|
|
|
aliasData.stat = stat;
|
|
var seriesName = aliasPattern.replace(aliasRegex, function(match, g1) {
|
|
if (aliasData[g1]) {
|
|
return aliasData[g1];
|
|
}
|
|
return g1;
|
|
});
|
|
|
|
return {target: seriesName, datapoints: dps};
|
|
});
|
|
}
|
|
|
|
function convertToCloudWatchTime(date) {
|
|
return Math.round(date.valueOf() / 1000);
|
|
}
|
|
|
|
function convertDimensionFormat(dimensions) {
|
|
return _.map(dimensions, function(value, key) {
|
|
return {
|
|
Name: templateSrv.replace(key),
|
|
Value: templateSrv.replace(value)
|
|
};
|
|
});
|
|
}
|
|
|
|
return CloudWatchDatasource;
|
|
});
|
|
|
|
});
|