mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Datasources: add support for POST HTTP verb for InfluxDB (#16690)
A new parameter `queryMode` is added to the InfluxDB datasource to provide a way to use POST instead of GET when querying the database. This prevents to get any error when querying the database with a heavy request. Default configuration is kept to GET for backward compatibility. Tests and documentation have been added for this new behaviour.
This commit is contained in:
committed by
Andrej Ocenas
parent
2596ce5076
commit
3866839b19
@@ -17,6 +17,7 @@ export default class InfluxDatasource {
|
||||
withCredentials: any;
|
||||
interval: any;
|
||||
responseParser: any;
|
||||
httpMode: string;
|
||||
|
||||
/** @ngInject */
|
||||
constructor(instanceSettings, private $q, private backendSrv, private templateSrv) {
|
||||
@@ -33,6 +34,7 @@ export default class InfluxDatasource {
|
||||
this.withCredentials = instanceSettings.withCredentials;
|
||||
this.interval = (instanceSettings.jsonData || {}).timeInterval;
|
||||
this.responseParser = new ResponseParser();
|
||||
this.httpMode = instanceSettings.jsonData.httpMode;
|
||||
}
|
||||
|
||||
query(options) {
|
||||
@@ -190,7 +192,7 @@ export default class InfluxDatasource {
|
||||
query = query.replace('$timeFilter', timeFilter);
|
||||
}
|
||||
|
||||
return this._influxRequest('GET', '/query', { q: query, epoch: 'ms' }, options);
|
||||
return this._influxRequest(this.httpMode, '/query', { q: query, epoch: 'ms' }, options);
|
||||
}
|
||||
|
||||
serializeParams(params) {
|
||||
@@ -245,7 +247,12 @@ export default class InfluxDatasource {
|
||||
params.db = this.database;
|
||||
}
|
||||
|
||||
if (method === 'GET') {
|
||||
if (method === 'POST' && _.has(data, 'q')) {
|
||||
// verb is POST and 'q' param is defined
|
||||
_.extend(params, _.omit(data, ['q']));
|
||||
data = this.serializeParams(_.pick(data, ['q']));
|
||||
} else if (method === 'GET' || method === 'POST') {
|
||||
// verb is GET, or POST without 'q' param
|
||||
_.extend(params, data);
|
||||
data = null;
|
||||
}
|
||||
@@ -268,6 +275,10 @@ export default class InfluxDatasource {
|
||||
req.headers.Authorization = this.basicAuth;
|
||||
}
|
||||
|
||||
if (method === 'POST') {
|
||||
req.headers['Content-type'] = 'application/x-www-form-urlencoded';
|
||||
}
|
||||
|
||||
return this.backendSrv.datasourceRequest(req).then(
|
||||
result => {
|
||||
return result.data;
|
||||
|
||||
@@ -15,7 +15,10 @@ class InfluxConfigCtrl {
|
||||
constructor() {
|
||||
this.onPasswordReset = createResetHandler(this, PasswordFieldEnum.Password);
|
||||
this.onPasswordChange = createChangeHandler(this, PasswordFieldEnum.Password);
|
||||
this.current.jsonData.httpMode = this.current.jsonData.httpMode || 'GET';
|
||||
}
|
||||
|
||||
httpMode = [{ name: 'GET', value: 'GET' }, { name: 'POST', value: 'POST' }];
|
||||
}
|
||||
|
||||
class InfluxAnnotationsQueryCtrl {
|
||||
|
||||
@@ -26,6 +26,19 @@
|
||||
/>
|
||||
</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.httpMode" ng-options="f.value as f.name for f in ctrl.httpMode"></select>
|
||||
<info-popover mode="right-absolute">
|
||||
You can use either <code>GET</code> or <code>POST</code> HTTP method to query your InfluxDB database. The <code>POST</code>
|
||||
method allows you to perform heavy requests (with a lots of <code>WHERE</code> clause) while the <code>GET</code> method
|
||||
will restrict you and return an error if the query is too large.
|
||||
</info-popover>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ describe('InfluxDataSource', () => {
|
||||
backendSrv: {},
|
||||
$q: $q,
|
||||
templateSrv: new TemplateSrvStub(),
|
||||
instanceSettings: { url: 'url', name: 'influxDb', jsonData: {} },
|
||||
instanceSettings: { url: 'url', name: 'influxDb', jsonData: { httpMode: 'GET' } },
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -23,11 +23,13 @@ describe('InfluxDataSource', () => {
|
||||
to: '2018-01-02T00:00:00Z',
|
||||
},
|
||||
};
|
||||
let requestQuery;
|
||||
let requestQuery, requestMethod, requestData;
|
||||
|
||||
beforeEach(async () => {
|
||||
ctx.backendSrv.datasourceRequest = req => {
|
||||
requestMethod = req.method;
|
||||
requestQuery = req.params.q;
|
||||
requestData = req.data;
|
||||
return ctx.$q.when({
|
||||
results: [
|
||||
{
|
||||
@@ -49,5 +51,69 @@ describe('InfluxDataSource', () => {
|
||||
it('should replace $timefilter', () => {
|
||||
expect(requestQuery).toMatch('time >= 1514764800000ms and time <= 1514851200000ms');
|
||||
});
|
||||
|
||||
it('should use the HTTP GET method', () => {
|
||||
expect(requestMethod).toBe('GET');
|
||||
});
|
||||
|
||||
it('should not have any data in request body', () => {
|
||||
expect(requestData).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('InfluxDataSource in POST query mode', () => {
|
||||
const ctx: any = {
|
||||
backendSrv: {},
|
||||
$q: $q,
|
||||
templateSrv: new TemplateSrvStub(),
|
||||
instanceSettings: { url: 'url', name: 'influxDb', jsonData: { httpMode: 'POST' } },
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
ctx.instanceSettings.url = '/api/datasources/proxy/1';
|
||||
ctx.ds = new InfluxDatasource(ctx.instanceSettings, ctx.$q, ctx.backendSrv, ctx.templateSrv);
|
||||
});
|
||||
|
||||
describe('When issuing metricFindQuery', () => {
|
||||
const query = 'SELECT max(value) FROM measurement';
|
||||
const queryOptions: any = {};
|
||||
let requestMethod, requestQueryParameter, queryEncoded, requestQuery;
|
||||
|
||||
beforeEach(async () => {
|
||||
ctx.backendSrv.datasourceRequest = req => {
|
||||
requestMethod = req.method;
|
||||
requestQueryParameter = req.params;
|
||||
requestQuery = req.data;
|
||||
return ctx.$q.when({
|
||||
results: [
|
||||
{
|
||||
series: [
|
||||
{
|
||||
name: 'measurement',
|
||||
columns: ['max'],
|
||||
values: [[1]],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
};
|
||||
|
||||
queryEncoded = await ctx.ds.serializeParams({ q: query });
|
||||
await ctx.ds.metricFindQuery(query, queryOptions).then(_ => {});
|
||||
});
|
||||
|
||||
it('should have the query form urlencoded', () => {
|
||||
expect(requestQuery).toBe(queryEncoded);
|
||||
});
|
||||
|
||||
it('should use the HTTP POST method', () => {
|
||||
expect(requestMethod).toBe('POST');
|
||||
});
|
||||
|
||||
it('should not have q as a query parameter', () => {
|
||||
expect(requestQueryParameter).not.toHaveProperty('q');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user