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

Use bucket selector rather than db for influx 1.7+ #16

Merged
merged 3 commits into from
Jan 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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