mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
support POST for query and query_range
This commit is contained in:
parent
f1fc1672be
commit
a83ede0193
@ -189,8 +189,14 @@ func (proxy *DataSourceProxy) validateRequest() error {
|
||||
}
|
||||
|
||||
if proxy.ds.Type == m.DS_PROMETHEUS {
|
||||
if proxy.ctx.Req.Request.Method != http.MethodGet || !strings.HasPrefix(proxy.proxyPath, "api/") {
|
||||
return errors.New("GET is only allowed on proxied Prometheus datasource")
|
||||
if proxy.ctx.Req.Request.Method == "DELETE" {
|
||||
return errors.New("Deletes not allowed on proxied Prometheus datasource")
|
||||
}
|
||||
if proxy.ctx.Req.Request.Method == "PUT" {
|
||||
return errors.New("Puts not allowed on proxied Prometheus datasource")
|
||||
}
|
||||
if proxy.ctx.Req.Request.Method == "POST" && !(proxy.proxyPath == "api/v1/query" || proxy.proxyPath == "api/v1/query_range") {
|
||||
return errors.New("Posts not allowed on proxied Prometheus datasource except on /query and /query_range")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import _ from 'lodash';
|
||||
|
||||
import $ from 'jquery';
|
||||
import kbn from 'app/core/utils/kbn';
|
||||
import * as dateMath from 'app/core/utils/datemath';
|
||||
import PrometheusMetricFindQuery from './metric_find_query';
|
||||
@ -20,6 +21,7 @@ export class PrometheusDatasource {
|
||||
withCredentials: any;
|
||||
metricsNameCache: any;
|
||||
interval: string;
|
||||
httpMethod: string;
|
||||
|
||||
/** @ngInject */
|
||||
constructor(instanceSettings, private $q, private backendSrv, private templateSrv, private timeSrv) {
|
||||
@ -32,14 +34,33 @@ export class PrometheusDatasource {
|
||||
this.basicAuth = instanceSettings.basicAuth;
|
||||
this.withCredentials = instanceSettings.withCredentials;
|
||||
this.interval = instanceSettings.jsonData.timeInterval || '15s';
|
||||
this.httpMethod = instanceSettings.jsonData.httpMethod || 'GET';
|
||||
}
|
||||
|
||||
_request(method, url, requestId?) {
|
||||
_request(method, url, data?, requestId?) {
|
||||
var options: any = {
|
||||
url: this.url + url,
|
||||
method: method,
|
||||
requestId: requestId,
|
||||
};
|
||||
if (method === 'GET') {
|
||||
if (!_.isEmpty(data)) {
|
||||
options.url =
|
||||
options.url +
|
||||
'?' +
|
||||
_.map(data, (v, k) => {
|
||||
return encodeURIComponent(k) + '=' + encodeURIComponent(v);
|
||||
}).join('&');
|
||||
}
|
||||
} else {
|
||||
options.headers = {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
};
|
||||
options.transformRequest = data => {
|
||||
return $.param(data);
|
||||
};
|
||||
options.data = data;
|
||||
}
|
||||
|
||||
if (this.basicAuth || this.withCredentials) {
|
||||
options.withCredentials = true;
|
||||
@ -173,21 +194,23 @@ export class PrometheusDatasource {
|
||||
throw { message: 'Invalid time range' };
|
||||
}
|
||||
|
||||
var url =
|
||||
'/api/v1/query_range?query=' +
|
||||
encodeURIComponent(query.expr) +
|
||||
'&start=' +
|
||||
start +
|
||||
'&end=' +
|
||||
end +
|
||||
'&step=' +
|
||||
query.step;
|
||||
return this._request('GET', url, query.requestId);
|
||||
var url = '/api/v1/query_range';
|
||||
var data = {
|
||||
query: query.expr,
|
||||
start: start,
|
||||
end: end,
|
||||
step: query.step,
|
||||
};
|
||||
return this._request(this.httpMethod, url, data, query.requestId);
|
||||
}
|
||||
|
||||
performInstantQuery(query, time) {
|
||||
var url = '/api/v1/query?query=' + encodeURIComponent(query.expr) + '&time=' + time;
|
||||
return this._request('GET', url, query.requestId);
|
||||
var url = '/api/v1/query';
|
||||
var data = {
|
||||
query: query.expr,
|
||||
time: time,
|
||||
};
|
||||
return this._request(this.httpMethod, url, data, query.requestId);
|
||||
}
|
||||
|
||||
performSuggestQuery(query, cache = false) {
|
||||
@ -279,8 +302,13 @@ export class PrometheusDatasource {
|
||||
}
|
||||
|
||||
testDatasource() {
|
||||
return this.metricFindQuery('metrics(.*)').then(function() {
|
||||
return { status: 'success', message: 'Data source is working' };
|
||||
let now = new Date().getTime();
|
||||
return this.performInstantQuery({ expr: '1+1' }, now / 1000).then(response => {
|
||||
if (response.data.status === 'success') {
|
||||
return { status: 'success', message: 'Data source is working' };
|
||||
} else {
|
||||
return { status: 'error', message: response.error };
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -4,13 +4,23 @@
|
||||
<div class="gf-form-group">
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label">Scrape interval</span>
|
||||
<input type="text" class="gf-form-input width-6" ng-model="ctrl.current.jsonData.timeInterval" spellcheck='false' placeholder="15s"></input>
|
||||
<span class="gf-form-label width-8">Scrape interval</span>
|
||||
<input type="text" class="gf-form-input width-8" ng-model="ctrl.current.jsonData.timeInterval" spellcheck='false' placeholder="15s"></input>
|
||||
<info-popover mode="right-absolute">
|
||||
Set this to your global scrape interval defined in your Prometheus config file. This will be used as a lower limit for
|
||||
Set this to your global scrape interval defined in your Prometheus config file. This will be used as a lower limit for
|
||||
the Prometheus step query parameter.
|
||||
</info-popover>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-8">HTTP Method</label>
|
||||
<div class="gf-form-select-wrapper width-8 gf-form-select-wrapper--has-help-icon">
|
||||
<select class="gf-form-input" ng-model="ctrl.current.jsonData.httpMethod" ng-options="method for method in ['GET', 'POST']"></select>
|
||||
<info-popover mode="right-absolute">
|
||||
Specify the HTTP Method to query Prometheus. (POST is only available in Prometheus >= v2.1.0)
|
||||
</info-popover>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { describe, beforeEach, it, expect, angularMocks } from 'test/lib/common';
|
||||
import moment from 'moment';
|
||||
import $ from 'jquery';
|
||||
import helpers from 'test/specs/helpers';
|
||||
import { PrometheusDatasource } from '../datasource';
|
||||
|
||||
@ -10,7 +11,7 @@ describe('PrometheusDatasource', function() {
|
||||
directUrl: 'direct',
|
||||
user: 'test',
|
||||
password: 'mupp',
|
||||
jsonData: {},
|
||||
jsonData: { httpMethod: 'GET' },
|
||||
};
|
||||
|
||||
beforeEach(angularMocks.module('grafana.core'));
|
||||
@ -652,3 +653,70 @@ describe('PrometheusDatasource', function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('PrometheusDatasource for POST', function() {
|
||||
var ctx = new helpers.ServiceTestContext();
|
||||
var instanceSettings = {
|
||||
url: 'proxied',
|
||||
directUrl: 'direct',
|
||||
user: 'test',
|
||||
password: 'mupp',
|
||||
jsonData: { httpMethod: 'POST' },
|
||||
};
|
||||
|
||||
beforeEach(angularMocks.module('grafana.core'));
|
||||
beforeEach(angularMocks.module('grafana.services'));
|
||||
beforeEach(ctx.providePhase(['timeSrv']));
|
||||
|
||||
beforeEach(
|
||||
angularMocks.inject(function($q, $rootScope, $httpBackend, $injector) {
|
||||
ctx.$q = $q;
|
||||
ctx.$httpBackend = $httpBackend;
|
||||
ctx.$rootScope = $rootScope;
|
||||
ctx.ds = $injector.instantiate(PrometheusDatasource, { instanceSettings: instanceSettings });
|
||||
$httpBackend.when('GET', /\.html$/).respond('');
|
||||
})
|
||||
);
|
||||
|
||||
describe('When querying prometheus with one target using query editor target spec', function() {
|
||||
var results;
|
||||
var urlExpected = 'proxied/api/v1/query_range';
|
||||
var dataExpected = $.param({
|
||||
query: 'test{job="testjob"}',
|
||||
start: 1443438675,
|
||||
end: 1443460275,
|
||||
step: 60,
|
||||
});
|
||||
var query = {
|
||||
range: { from: moment(1443438674760), to: moment(1443460274760) },
|
||||
targets: [{ expr: 'test{job="testjob"}', format: 'time_series' }],
|
||||
interval: '60s',
|
||||
};
|
||||
var response = {
|
||||
status: 'success',
|
||||
data: {
|
||||
resultType: 'matrix',
|
||||
result: [
|
||||
{
|
||||
metric: { __name__: 'test', job: 'testjob' },
|
||||
values: [[1443454528, '3846']],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
beforeEach(function() {
|
||||
ctx.$httpBackend.expectPOST(urlExpected, dataExpected).respond(response);
|
||||
ctx.ds.query(query).then(function(data) {
|
||||
results = data;
|
||||
});
|
||||
ctx.$httpBackend.flush();
|
||||
});
|
||||
it('should generate the correct query', function() {
|
||||
ctx.$httpBackend.verifyNoOutstandingExpectation();
|
||||
});
|
||||
it('should return series list', function() {
|
||||
expect(results.data.length).to.be(1);
|
||||
expect(results.data[0].target).to.be('test{job="testjob"}');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -12,7 +12,7 @@ describe('PrometheusMetricFindQuery', function() {
|
||||
directUrl: 'direct',
|
||||
user: 'test',
|
||||
password: 'mupp',
|
||||
jsonData: {},
|
||||
jsonData: { httpMethod: 'GET' },
|
||||
};
|
||||
|
||||
beforeEach(angularMocks.module('grafana.core'));
|
||||
|
Loading…
Reference in New Issue
Block a user