Skip to content
This repository has been archived by the owner on Dec 11, 2020. It is now read-only.

Commit

Permalink
Merge pull request #16 from ryantxu/support-17
Browse files Browse the repository at this point in the history
Use `bucket` selector rather than `db` for influx 1.7+
  • Loading branch information
davkal authored Jan 23, 2019
2 parents 0fd2afd + 075c831 commit e0f5f14
Show file tree
Hide file tree
Showing 10 changed files with 72 additions and 51 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Read more about InfluxDB here:

Getting started:

1. Install a recent [InfluxDB nightly](https://portal.influxdata.com/downloads), then run `influxd -config` and catch that config as config.toml. Then run `influxd -config config.toml`. The recent nighlies contain the Flux engine.
1. Install [InfluxDB 1.7+](https://portal.influxdata.com/downloads), then edit `influxdb.conf` setting [`[http] flux-enabled = true`](https://docs.influxdata.com/influxdb/v1.7/administration/config#flux-enabled-false) See also: [https://docs.influxdata.com/flux/v0.7/introduction/installation/](https://docs.influxdata.com/flux/v0.7/introduction/installation/)

2. Install telegraph to get some data: brew install telegraf. Then run telegraf.

Expand Down
19 changes: 12 additions & 7 deletions specs/datasource.jest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import Datasource from '../src/datasource';

describe('InfluxDB (Flux)', () => {
const templateSrv = new TemplateSrv();
const ds = new Datasource({ url: '' }, {}, templateSrv);
const ds = new Datasource({url: ''}, {}, templateSrv);
const DEFAULT_OPTIONS = {
rangeRaw: { to: 'now', from: 'now - 3h' },
rangeRaw: {to: 'now', from: 'now - 3h'},
scopedVars: {},
targets: [],
};
Expand All @@ -18,23 +18,28 @@ describe('InfluxDB (Flux)', () => {
let target: any;

it.skip('replaces $range variable', () => {
target = ds.prepareQueryTarget({ query: 'from(db: "test") |> range($range)' }, DEFAULT_OPTIONS);
expect(target.query).toBe('from(db: "test") |> range(start: -3h)');
target = ds.prepareQueryTarget(
{query: 'from(bucket: "test") |> range($range)'},
DEFAULT_OPTIONS
);
expect(target.query).toBe('from(bucket: "test") |> range(start: -3h)');
});

it.skip('replaces $range variable with custom dates', () => {
const to = moment();
const from = moment().subtract(1, 'hours');
target = ds.prepareQueryTarget(
{ query: 'from(db: "test") |> range($range)' },
{query: 'from(bucket: "test") |> range($range)'},
{
...DEFAULT_OPTIONS,
rangeRaw: { to, from },
rangeRaw: {to, from},
}
);
const start = from.toISOString();
const stop = to.toISOString();
expect(target.query).toBe(`from(db: "test") |> range(start: ${start}, stop: ${stop})`);
expect(target.query).toBe(
`from(bucket: "test") |> range(start: ${start}, stop: ${stop})`
);
});
});
});
16 changes: 9 additions & 7 deletions specs/metric_find_query.jest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import expandMacros from '../src/metric_find_query';
describe('metric find query', () => {
describe('expandMacros()', () => {
it('returns a non-macro query unadulterated', () => {
const query = 'from(db:"telegraf") |> last()';
const query = 'from(bucket:"telegraf") |> last()';
const result = expandMacros(query);
expect(result).toBe(query);
});
Expand All @@ -12,31 +12,33 @@ describe('metric find query', () => {
const query = ' measurements(mydb) ';
const result = expandMacros(query).replace(/\s/g, '');
expect(result).toBe(
'from(db:"mydb")|>range($range)|>group(by:["_measurement"])|>distinct(column:"_measurement")|>group(none:true)'
'from(bucket:"mydb")|>range($range)|>group(by:["_measurement"])|>distinct(column:"_measurement")|>group(none:true)'
);
});

it('returns a tags query for tags()', () => {
const query = ' tags(mydb , mymetric) ';
const result = expandMacros(query).replace(/\s/g, '');
expect(result).toBe('from(db:"mydb")|>range($range)|>filter(fn:(r)=>r._measurement=="mymetric")|>keys()');
expect(result).toBe(
'from(bucket:"mydb")|>range($range)|>filter(fn:(r)=>r._measurement=="mymetric")|>keys()'
);
});

it('returns a tag values query for tag_values()', () => {
const query = ' tag_values(mydb , mymetric, mytag) ';
const result = expandMacros(query).replace(/\s/g, '');
expect(result).toBe(
'from(db:"mydb")|>range($range)|>filter(fn:(r)=>r._measurement=="mymetric")' +
'|>group(by:["mytag"])|>distinct(column:"mytag")|>group(none:true)'
'from(bucket:"mydb")|>range($range)|>filter(fn:(r)=>r._measurement=="mymetric")' +
'|>group(by:["mytag"])|>distinct(column:"mytag")|>group(none:true)'
);
});

it('returns a field keys query for field_keys()', () => {
const query = ' field_keys(mydb , mymetric) ';
const result = expandMacros(query).replace(/\s/g, '');
expect(result).toBe(
'from(db:"mydb")|>range($range)|>filter(fn:(r)=>r._measurement=="mymetric")' +
'|>group(by:["_field"])|>distinct(column:"_field")|>group(none:true)'
'from(bucket:"mydb")|>range($range)|>filter(fn:(r)=>r._measurement=="mymetric")' +
'|>group(by:["_field"])|>distinct(column:"_field")|>group(none:true)'
);
});
});
Expand Down
35 changes: 21 additions & 14 deletions src/datasource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ export default class InfluxDatasource {
username: string;
password: string;
name: string;
orgName: string;
database: any;
bucket: any;
basicAuth: any;
withCredentials: any;
interval: any;
Expand All @@ -34,11 +33,10 @@ export default class InfluxDatasource {
this.username = instanceSettings.username;
this.password = instanceSettings.password;
this.name = instanceSettings.name;
this.orgName = instanceSettings.orgName || 'defaultorgname';
this.basicAuth = instanceSettings.basicAuth;
this.withCredentials = instanceSettings.withCredentials;
this.interval = (instanceSettings.jsonData || {}).timeInterval;
this.database = (instanceSettings.jsonData || {}).database;
this.bucket = (instanceSettings.jsonData || {}).bucket;
this.supportAnnotations = true;
this.supportMetrics = true;
}
Expand Down Expand Up @@ -133,13 +131,21 @@ export default class InfluxDatasource {
if (!query) {
return Promise.resolve({data: ''});
}
return this._influxRequest('POST', '/api/v2/query', {query: query}, options);
return this._influxRequest('POST', '/api/v2/query', query, options);
}

testDatasource() {
const query = `from(bucket:"${this.database}") |> last()`;
const query = `from(bucket:"${this.bucket}")
|> range(start:-10y)
|> last()`;
if (this.bucket.indexOf('/') < 0) {
return Promise.resolve({
status: 'error',
message: 'The bucket is missing a retention policy',
});
}

return this._influxRequest('POST', '/api/v2/query', {query: query})
return this._influxRequest('POST', '/api/v2/query', query)
.then(res => {
if (res && res.data && res.data.trim()) {
return {
Expand All @@ -150,18 +156,16 @@ export default class InfluxDatasource {
return {
status: 'error',
message:
'Data source connected, but has no data. Verify the "Database" field and make sure the database has data.',
'Data source connected, but has no data. Verify the "bucket" field and make sure the bucket has data.',
};
})
.catch(err => {
return {status: 'error', message: err.message};
});
}

_influxRequest(method: string, url: string, data: any, options?: any) {
let params: any = {
organization: `my-org`,
};
_influxRequest(method: string, url: string, query: string, options?: any) {
let params: any = {};

if (this.username) {
params.u = this.username;
Expand All @@ -172,12 +176,15 @@ export default class InfluxDatasource {
method: method,
url: this.url + url,
params: params,
data: data,
data: query,
precision: 'ms',
inspect: {type: this.type},
};

req.headers = {};
req.headers = {
Accept: 'application/csv',
'Content-Type': 'application/vnd.flux',
};

if (this.basicAuth || this.withCredentials) {
req.withCredentials = true;
Expand Down
8 changes: 4 additions & 4 deletions src/editor/FluxQueryField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ const wrapText = text => ({ text });
const RATE_RANGES = ['1m', '5m', '10m', '30m', '1h'];
const DEFAULT_DATABASE = 'telegraf';

function expandQuery(database, measurement, field) {
function expandQuery(bucket, measurement, field) {
if (field) {
return (
`from(db: "${database}")\n` +
`from(bucket: "${bucket}")\n` +
` |> filter(fn: (r) => r["_measurement"] == "${measurement}" AND r["_field"] == "${field}")\n |> range($range)\n |> limit(n: 1000)`
);
}
return `from(db: "${database}")\n |> filter(fn: (r) => r["_measurement"] == "${measurement}")\n |> range($range)\n |> limit(n: 1000)`;
return `from(bucket: "${bucket}")\n |> filter(fn: (r) => r["_measurement"] == "${measurement}")\n |> range($range)\n |> limit(n: 1000)`;
}

export default class FluxQueryField extends QueryField {
Expand Down Expand Up @@ -154,7 +154,7 @@ export default class FluxQueryField extends QueryField {
suggestionGroups.push({
prefixMatch: true,
label: 'Templates',
items: [`from(db: "${database}") |> range($range) `].map(wrapText),
items: [`from(bucket: "${database}") |> range($range) `].map(wrapText),
});
suggestionGroups.push({
prefixMatch: true,
Expand Down
4 changes: 2 additions & 2 deletions src/editor/flux.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ export const FUNCTIONS = [
},
{
text: 'from',
display: 'from(db: "database)',
hint: 'Starting point of a query, produces a table from the given "db".',
display: 'from(bucket: "database/policy")',
hint: 'Starting point of a query, produces a table from the given bucket.',
},
{
text: 'group',
Expand Down
8 changes: 4 additions & 4 deletions src/metric_find_query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default function expandMacros(query) {
const measurementsQuery = query.match(MEASUREMENTS_REGEXP);
if (measurementsQuery) {
const database = measurementsQuery[1];
return `from(db:"${database}")
return `from(bucket:"${database}")
|> range($range)
|> group(by:["_measurement"])
|> distinct(column:"_measurement")
Expand All @@ -27,7 +27,7 @@ export default function expandMacros(query) {
if (tagsQuery) {
const database = tagsQuery[1];
const measurement = tagsQuery[2];
return `from(db:"${database}")
return `from(bucket:"${database}")
|> range($range)
|> filter(fn:(r) => r._measurement == "${measurement}")
|> keys()`;
Expand All @@ -38,7 +38,7 @@ export default function expandMacros(query) {
const database = tagValuesQuery[1];
const measurement = tagValuesQuery[2];
const tag = tagValuesQuery[3];
return `from(db:"${database}")
return `from(bucket:"${database}")
|> range($range)
|> filter(fn:(r) => r._measurement == "${measurement}")
|> group(by:["${tag}"])
Expand All @@ -50,7 +50,7 @@ export default function expandMacros(query) {
if (fieldKeysQuery) {
const database = fieldKeysQuery[1];
const measurement = fieldKeysQuery[2];
return `from(db:"${database}")
return `from(bucket:"${database}")
|> range($range)
|> filter(fn:(r) => r._measurement == "${measurement}")
|> group(by:["_field"])
Expand Down
2 changes: 1 addition & 1 deletion src/partials/annotations.editor.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<div class="gf-form-group">
<div class="gf-form">
<input type="text" class="gf-form-input" ng-model='ctrl.annotation.query' placeholder='from(db:"telegraf") |> range($range)'></input>
<input type="text" class="gf-form-input" ng-model='ctrl.annotation.query' placeholder='from(bucket:"telegraf/autogen") |> range($range)'></input>
</div>
</div>

Expand Down
9 changes: 6 additions & 3 deletions src/partials/config.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ <h3 class="page-heading">InfluxDB Details</h3>
<div class="gf-form-group">
<div class="gf-form-inline">
<div class="gf-form max-width-30">
<span class="gf-form-label width-7">Default Database</span>
<input type="text" class="gf-form-input" ng-model='ctrl.current.jsonData.database' placeholder="" required></input>
<span class="gf-form-label width-10">Default Bucket</span>
<input type="text" class="gf-form-input" ng-model='ctrl.current.jsonData.bucket' placeholder="database/policy" required></input>
<info-popover mode="right-absolute">
<p>A combination of the default database and retention policy</p>
</info-popover>
</div>
</div>

<div class="gf-form-inline">
<div class="gf-form max-width-15">
<span class="gf-form-label width-7">User</span>
<span class="gf-form-label width-10">Username</span>
<input type="text" class="gf-form-input" ng-model='ctrl.current.user' placeholder=""></input>
</div>
<div class="gf-form max-width-15">
Expand Down
20 changes: 12 additions & 8 deletions src/query_ctrl.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import appEvents from 'grafana/app/core/app_events';
import { QueryCtrl } from 'grafana/app/plugins/sdk';
import {QueryCtrl} from 'grafana/app/plugins/sdk';

import './editor/editor_component';

function makeDefaultQuery(database) {
return `from(db: "${database}")
function makeDefaultQuery(bucket) {
return `from(bucket: "${bucket}")
|> range($range)
|> limit(n:1000)
`;
Expand All @@ -13,7 +13,7 @@ export class InfluxFluxQueryCtrl extends QueryCtrl {
static templateUrl = 'partials/query.editor.html';

dataPreview: string;
defaultDatabase: string;
defaultBucket: string;
resultRecordCount: string;
resultTableCount: string;
resultFormats: any[];
Expand All @@ -26,11 +26,14 @@ export class InfluxFluxQueryCtrl extends QueryCtrl {
this.resultTableCount = '';

if (this.target.query === undefined) {
this.target.query = makeDefaultQuery(this.datasource.database);
this.target.query = makeDefaultQuery(this.datasource.bucket);
}

this.defaultDatabase = this.datasource.database;
this.resultFormats = [{ text: 'Time series', value: 'time_series' }, { text: 'Table', value: 'table' }];
this.defaultBucket = this.datasource.bucket;
this.resultFormats = [
{text: 'Time series', value: 'time_series'},
{text: 'Table', value: 'table'},
];

appEvents.on('ds-request-response', this.onResponseReceived, $scope);
this.panelCtrl.events.on('refresh', this.onRefresh, $scope);
Expand All @@ -39,7 +42,8 @@ export class InfluxFluxQueryCtrl extends QueryCtrl {

onDataReceived = dataList => {
this.resultRecordCount = dataList.reduce((count, model) => {
const records = model.type === 'table' ? model.rows.length : model.datapoints.length;
const records =
model.type === 'table' ? model.rows.length : model.datapoints.length;
return count + records;
}, 0);
this.resultTableCount = dataList.length;
Expand Down

0 comments on commit e0f5f14

Please sign in to comment.