8 |
9 |
10 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "target": "ES5",
5 | "module": "system",
6 | "sourceMap": true,
7 | "declaration": true,
8 | "emitDecoratorMetadata": true,
9 | "experimentalDecorators": true,
10 | "noImplicitAny": false
11 | },
12 | "exclude": [
13 | "node_modules"
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/.jscs.json:
--------------------------------------------------------------------------------
1 | {
2 | "esnext": true,
3 | "disallowImplicitTypeConversion": ["string"],
4 | "disallowKeywords": ["with"],
5 | "disallowMultipleLineBreaks": true,
6 | "disallowMixedSpacesAndTabs": true,
7 | "disallowTrailingWhitespace": true,
8 | "requireSpacesInFunctionExpression": {
9 | "beforeOpeningCurlyBrace": true
10 | },
11 | "disallowSpacesInsideArrayBrackets": true,
12 | "disallowSpacesInsideParentheses": true,
13 | "validateIndentation": 2
14 | }
15 |
--------------------------------------------------------------------------------
/dist/module.d.ts:
--------------------------------------------------------------------------------
1 | import { SwisDatasource } from './datasource';
2 | import { SwisQueryCtrl } from './query_ctrl';
3 | declare class SwisConfigCtrl {
4 | static templateUrl: string;
5 | }
6 | declare class SwisAnnotationsQueryCtrl {
7 | static templateUrl: string;
8 | annotation: any;
9 | /** @ngInject */
10 | constructor();
11 | }
12 | export { SwisDatasource, SwisDatasource as Datasource, SwisQueryCtrl as QueryCtrl, SwisConfigCtrl as ConfigCtrl, SwisAnnotationsQueryCtrl as AnnotationsQueryCtrl };
13 |
--------------------------------------------------------------------------------
/dist/module.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"module.js","sourceRoot":"","sources":["module.ts"],"names":["SwisConfigCtrl","SwisConfigCtrl.constructor","SwisAnnotationsQueryCtrl","SwisAnnotationsQueryCtrl.constructor"],"mappings":";;;;;;;;;;;;YAGA;gBAAAA;gBAEAC,CAACA;gBADQD,0BAAWA,GAAGA,sBAAsBA,CAACA;gBAC9CA,qBAACA;YAADA,CAACA,AAFD,IAEC;YAED;gBAKEE,gBAAgBA;gBAChBA;oBACEC,IAAIA,CAACA,UAAUA,CAACA,QAAQA,GAAGA,IAAIA,CAACA,UAAUA,CAACA,QAAQA,CAACA;gBACtDA,CAACA;gBAPMD,oCAAWA,GAAGA,kCAAkCA,CAACA;gBAQ1DA,+BAACA;YAADA,CAACA,AATD,IASC;YAGC,wDAAc;YACI,oDAAU;YACX,kDAAS;YACR,uCAAU;YACA,2DAAoB"}
--------------------------------------------------------------------------------
/specs/lib/common.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | var _global = (window);
4 | var beforeEach = _global.beforeEach;
5 | var before = _global.before;
6 | var describe = _global.describe;
7 | var it = _global.it;
8 | var sinon = _global.sinon;
9 | var expect = _global.expect;
10 |
11 | var angularMocks = {
12 | module: _global.module,
13 | inject: _global.inject,
14 | };
15 |
16 | export {
17 | beforeEach,
18 | before,
19 | describe,
20 | it,
21 | sinon,
22 | expect,
23 | angularMocks,
24 | };
25 |
--------------------------------------------------------------------------------
/specs/lib/time_srv_stub.ts:
--------------------------------------------------------------------------------
1 | import {sinon} from '../lib/common';
2 | import dateMath from 'app/core/utils/datemath';
3 |
4 | export default class TimeSrvStub {
5 | init = sinon.spy();
6 | time = { from: 'now-1h', to: 'now'};
7 |
8 | timeRange(parse) {
9 | if (parse === false) {
10 | return this.time;
11 | }
12 |
13 | return {
14 | from : dateMath.parse(this.time.from, false),
15 | to : dateMath.parse(this.time.to, true)
16 | };
17 | }
18 |
19 | replace(target) {
20 | return target;
21 | }
22 |
23 | setTime(time) {
24 | this.time = time;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .vs
2 | node_modules
3 | npm-debug.log
4 | coverage/
5 | .aws-config.json
6 | awsconfig
7 | /emails/dist
8 | /public_gen
9 | /tmp
10 | vendor/phantomjs/phantomjs
11 |
12 | docs/AWS_S3_BUCKET
13 | docs/GIT_BRANCH
14 | docs/VERSION
15 | docs/GITCOMMIT
16 | docs/changed-files
17 | docs/changed-files
18 |
19 | # locally required config files
20 | public/css/*.min.css
21 |
22 | # Editor junk
23 | *.sublime-workspace
24 | *.swp
25 | .idea/
26 | *.iml
27 |
28 | /data/*
29 | /bin/*
30 |
31 | conf/custom.ini
32 | fig.yml
33 | profile.cov
34 | grafana
35 | .notouch
36 |
37 | # Test artifacts
38 | /dist/test/
39 |
--------------------------------------------------------------------------------
/dist/module.ts:
--------------------------------------------------------------------------------
1 | import { SwisDatasource } from './datasource';
2 | import { SwisQueryCtrl } from './query_ctrl';
3 |
4 | class SwisConfigCtrl {
5 | static templateUrl = 'partials/config.html';
6 | }
7 |
8 | class SwisAnnotationsQueryCtrl {
9 | static templateUrl = 'partials/annotations.editor.html';
10 |
11 | annotation: any;
12 |
13 | /** @ngInject */
14 | constructor() {
15 | this.annotation.rawQuery = this.annotation.rawQuery;
16 | }
17 | }
18 |
19 | export {
20 | SwisDatasource,
21 | SwisDatasource as Datasource,
22 | SwisQueryCtrl as QueryCtrl,
23 | SwisConfigCtrl as ConfigCtrl,
24 | SwisAnnotationsQueryCtrl as AnnotationsQueryCtrl,
25 | };
26 |
--------------------------------------------------------------------------------
/src/module.ts:
--------------------------------------------------------------------------------
1 | import { SwisDatasource } from './datasource';
2 | import { SwisQueryCtrl } from './query_ctrl';
3 |
4 | class SwisConfigCtrl {
5 | static templateUrl = 'partials/config.html';
6 | }
7 |
8 | class SwisAnnotationsQueryCtrl {
9 | static templateUrl = 'partials/annotations.editor.html';
10 |
11 | annotation: any;
12 |
13 | /** @ngInject */
14 | constructor() {
15 | this.annotation.rawQuery = this.annotation.rawQuery;
16 | }
17 | }
18 |
19 | export {
20 | SwisDatasource,
21 | SwisDatasource as Datasource,
22 | SwisQueryCtrl as QueryCtrl,
23 | SwisConfigCtrl as ConfigCtrl,
24 | SwisAnnotationsQueryCtrl as AnnotationsQueryCtrl,
25 | };
26 |
--------------------------------------------------------------------------------
/specs/lib/template_srv_stub.ts:
--------------------------------------------------------------------------------
1 | import _ from 'lodash';
2 |
3 | export default class TemplateSrvStub {
4 | variables = [];
5 | templateSettings = { interpolate : /\[\[([\s\S]+?)\]\]/g };
6 | data = {};
7 |
8 | replace(text) {
9 | return _.template(text, this.templateSettings)(this.data);
10 | }
11 |
12 | getAdhocFilters() {
13 | return [];
14 | }
15 |
16 | variableExists() {
17 | return false;
18 | }
19 |
20 | highlightVariablesAsHtml(str) {
21 | return str;
22 | }
23 |
24 | setGrafanaVariable(name, value) {
25 | this.data[name] = value;
26 | }
27 |
28 | init() {}
29 | fillVariableValuesForUrl() {}
30 | updateTemplateData() {}
31 | }
32 |
--------------------------------------------------------------------------------
/dist/query_ctrl.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | import { QueryCtrl } from 'app/plugins/sdk';
3 | export interface SwisQuery {
4 | refId: string;
5 | format: string;
6 | alias: string;
7 | rawSql: string;
8 | }
9 | export interface QueryMeta {
10 | sql: string;
11 | }
12 | export declare class SwisQueryCtrl extends QueryCtrl {
13 | static templateUrl: string;
14 | showLastQuerySQL: boolean;
15 | formats: any[];
16 | target: SwisQuery;
17 | lastQueryMeta: QueryMeta;
18 | lastQueryError: string;
19 | showHelp: boolean;
20 | constructor($scope: any, $injector: any);
21 | onDataReceived(dataList: any): void;
22 | onDataError(err: any): void;
23 | }
24 |
--------------------------------------------------------------------------------
/dist/plugin.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "SolarWinds SWIS DataSource",
3 | "id": "solarwinds-swis-datasource",
4 | "type": "datasource",
5 |
6 | "partials": {
7 | "config": "public/app/plugins/datasource/swis/partials/config.html"
8 | },
9 | "metrics": true,
10 | "annotations": true,
11 | "alerting": true,
12 | "backend": false,
13 | "info": {
14 | "description": "DataSource plugin for SolarWinds via SWIS HTTP REST endpoint",
15 | "author": {
16 | "name": "Eduard Tichy"
17 | },
18 | "logos": {
19 | "small": "img/solarwinds-icon.svg",
20 | "large": "img/solarwinds-icon.svg"
21 | },
22 | "links": [
23 | {"name": "GitHub", "url": "https://github.com/etichy/grafana-swis-datasource"},
24 | {"name": "License", "url": "https://github.com/etichy/grafana-swis-datasource/blob/master/LICENSE"}
25 | ],
26 | "version": "1.0.0",
27 | "updated": "2019-05-24"
28 | },
29 |
30 | "dependencies": {
31 | "grafanaVersion": "5.x.x",
32 | "plugins": [ ]
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/plugin.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "SolarWinds SWIS DataSource",
3 | "id": "solarwinds-swis-datasource",
4 | "type": "datasource",
5 |
6 | "partials": {
7 | "config": "public/app/plugins/datasource/swis/partials/config.html"
8 | },
9 | "metrics": true,
10 | "annotations": true,
11 | "alerting": true,
12 | "backend": false,
13 | "info": {
14 | "description": "DataSource plugin for SolarWinds via SWIS HTTP REST endpoint",
15 | "author": {
16 | "name": "Eduard Tichy"
17 | },
18 | "logos": {
19 | "small": "img/solarwinds-icon.svg",
20 | "large": "img/solarwinds-icon.svg"
21 | },
22 | "links": [
23 | {"name": "GitHub", "url": "https://github.com/etichy/grafana-swis-datasource"},
24 | {"name": "License", "url": "https://github.com/etichy/grafana-swis-datasource/blob/master/LICENSE"}
25 | ],
26 | "version": "1.0.0",
27 | "updated": "2019-05-24"
28 | },
29 |
30 | "dependencies": {
31 | "grafanaVersion": "5.x.x",
32 | "plugins": [ ]
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Grafana
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/dist/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Grafana
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/dist/datasource.d.ts:
--------------------------------------------------------------------------------
1 | export declare class SwisDatasource {
2 | url: string;
3 | q: any;
4 | backendSrv: any;
5 | templateSrv: any;
6 | withCredentials: boolean;
7 | headers: any;
8 | constructor(instanceSettings: any, $q: any, backendSrv: any, templateSrv: any);
9 | testDatasource(): any;
10 | interpolateVariable(value: any, variable: any): any;
11 | query(options: any): any;
12 | doQuery(query: any, options: any): any;
13 | timeSpan(ms: any): string;
14 | resolveMacros(rawSql: any, options: any): any;
15 | processMetadata(res: any, query: any): void;
16 | translateType(type: any): any;
17 | processQueryResult(res: any, query: any): any;
18 | processQueryResultAnnotation(res: any, query: any): any;
19 | processQueryResultSearch(res: any, query: any): any;
20 | processQueryResultTable(res: any, query: any): {
21 | columns: any;
22 | rows: any;
23 | type: any;
24 | };
25 | correctTime(dtString: string): number;
26 | processQueryResultMetric(res: any, query: any): any[];
27 | annotationQuery(options: any): any;
28 | metricFindQuery(rawSql: any): any;
29 | doRequest(options: any): any;
30 | }
31 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "datasource-solarwinds-swis",
3 | "version": "0.0.1",
4 | "description": "DataSource for SolarWinds SWIS HTTP REST endpoint.",
5 | "scripts": {
6 | "build": "grunt",
7 | "watch": "grunt watch",
8 | "test": "./node_modules/karma/bin/karma start"
9 | },
10 | "author": "Eduard Tichy",
11 | "license": "Apache",
12 | "dependencies": {
13 | "lodash": "^4.17.14",
14 | "moment": "^2.18.1",
15 | "q": "^1.5.0",
16 | "systemjs": "^0.19.47"
17 | },
18 | "devDependencies": {
19 | "@types/lodash": "^4.14.136",
20 | "grafana-sdk-mocks": "github:grafana/grafana-sdk-mocks",
21 | "grunt": "^1.0.1",
22 | "grunt-contrib-clean": "^1.1.0",
23 | "grunt-contrib-copy": "^1.0.0",
24 | "grunt-contrib-watch": "^1.0.0",
25 | "grunt-string-replace": "^1.3",
26 | "grunt-typescript": "^0.8.0",
27 | "karma": "^4.0.1",
28 | "karma-chrome-launcher": "^2.2.0",
29 | "karma-expect": "^1.1.3",
30 | "karma-mocha": "^1.3.0",
31 | "karma-mocha-reporter": "2.0.3",
32 | "karma-phantomjs-launcher": "^1.0.4",
33 | "karma-sinon": "^1.0.5",
34 | "karma-systemjs": "^0.16.0",
35 | "load-grunt-tasks": "^3.5.2",
36 | "mocha": "^5.1.1",
37 | "plugin-typescript": "^7.1.0",
38 | "sinon": "^3.2.1",
39 | "systemjs-plugin-css": "^0.1.35"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/dist/module.js:
--------------------------------------------------------------------------------
1 | System.register(['./datasource', './query_ctrl'], function(exports_1) {
2 | var datasource_1, query_ctrl_1;
3 | var SwisConfigCtrl, SwisAnnotationsQueryCtrl;
4 | return {
5 | setters:[
6 | function (datasource_1_1) {
7 | datasource_1 = datasource_1_1;
8 | },
9 | function (query_ctrl_1_1) {
10 | query_ctrl_1 = query_ctrl_1_1;
11 | }],
12 | execute: function() {
13 | SwisConfigCtrl = (function () {
14 | function SwisConfigCtrl() {
15 | }
16 | SwisConfigCtrl.templateUrl = 'partials/config.html';
17 | return SwisConfigCtrl;
18 | })();
19 | SwisAnnotationsQueryCtrl = (function () {
20 | /** @ngInject */
21 | function SwisAnnotationsQueryCtrl() {
22 | this.annotation.rawQuery = this.annotation.rawQuery;
23 | }
24 | SwisAnnotationsQueryCtrl.templateUrl = 'partials/annotations.editor.html';
25 | return SwisAnnotationsQueryCtrl;
26 | })();
27 | exports_1("SwisDatasource", datasource_1.SwisDatasource);
28 | exports_1("Datasource", datasource_1.SwisDatasource);
29 | exports_1("QueryCtrl", query_ctrl_1.SwisQueryCtrl);
30 | exports_1("ConfigCtrl", SwisConfigCtrl);
31 | exports_1("AnnotationsQueryCtrl", SwisAnnotationsQueryCtrl);
32 | }
33 | }
34 | });
35 | //# sourceMappingURL=module.js.map
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "class-name": true,
4 | "comment-format": [false, "check-space"],
5 | "curly": true,
6 | "eofline": true,
7 | "forin": false,
8 | "indent": [true, "spaces"],
9 | "label-position": true,
10 | "label-undefined": true,
11 | "max-line-length": [true, 140],
12 | "member-access": false,
13 | "no-arg": true,
14 | "no-bitwise": true,
15 | "no-console": [true,
16 | "debug",
17 | "info",
18 | "time",
19 | "timeEnd",
20 | "trace"
21 | ],
22 | "no-construct": true,
23 | "no-debugger": true,
24 | "no-duplicate-key": true,
25 | "no-duplicate-variable": true,
26 | "no-empty": false,
27 | "no-eval": true,
28 | "no-inferrable-types": true,
29 | "no-shadowed-variable": false,
30 | "no-string-literal": false,
31 | "no-switch-case-fall-through": false,
32 | "no-trailing-whitespace": true,
33 | "no-unused-expression": false,
34 | "no-unused-variable": false,
35 | "no-unreachable": true,
36 | "no-use-before-declare": true,
37 | "no-var-keyword": false,
38 | "object-literal-sort-keys": false,
39 | "one-line": [true,
40 | "check-open-brace",
41 | "check-catch",
42 | "check-else"
43 | ],
44 | "radix": false,
45 | "semicolon": true,
46 | "triple-equals": [true, "allow-null-check"],
47 | "typedef-whitespace": [true, {
48 | "call-signature": "nospace",
49 | "index-signature": "nospace",
50 | "parameter": "nospace",
51 | "property-declaration": "nospace",
52 | "variable-declaration": "nospace"
53 | }],
54 | "variable-name": [true, "ban-keywords"],
55 | "whitespace": [true,
56 | "check-branch",
57 | "check-decl",
58 | "check-type"
59 | ]
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/dist/query_ctrl.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"query_ctrl.js","sourceRoot":"","sources":["query_ctrl.ts"],"names":["SwisQueryCtrl","SwisQueryCtrl.constructor","SwisQueryCtrl.onDataReceived","SwisQueryCtrl.onDataError"],"mappings":"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"}
--------------------------------------------------------------------------------
/src/query_ctrl.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | import _ from "lodash";
4 | import { QueryCtrl } from 'app/plugins/sdk';
5 | import './css/query-editor.css!'
6 |
7 | export interface SwisQuery {
8 | refId: string;
9 | format: string;
10 | alias: string;
11 | rawSql: string;
12 | }
13 |
14 | export interface QueryMeta {
15 | sql: string;
16 | }
17 |
18 | const defaultQuery = `SELECT TOP 5
19 | LastSync,
20 | Caption,
21 | CPULoad,
22 | ResponseTime
23 | FROM
24 | Orion.Nodes`;
25 |
26 | export class SwisQueryCtrl extends QueryCtrl {
27 | static templateUrl = 'partials/query.editor.html';
28 |
29 | showLastQuerySQL: boolean;
30 | formats: any[];
31 | target: SwisQuery;
32 | lastQueryMeta: QueryMeta;
33 | lastQueryError: string;
34 | showHelp: boolean;
35 |
36 |
37 | constructor($scope, $injector) {
38 | super($scope, $injector);
39 |
40 | this.target.format = this.target.format || 'time_series';
41 | this.target.alias = '';
42 | this.formats = [{ text: 'Time series', value: 'time_series' }, { text: 'Table', value: 'table' }];
43 |
44 | if (!this.target.rawSql) {
45 | // special handling when in table panel
46 | if (this.panelCtrl.panel.type === 'table') {
47 | this.target.format = 'table';
48 | this.target.rawSql = 'SELECT 1';
49 | } else {
50 | this.target.rawSql = defaultQuery;
51 | }
52 | }
53 |
54 | this.panelCtrl.events.on('data-received', this.onDataReceived.bind(this), $scope);
55 | this.panelCtrl.events.on('data-error', this.onDataError.bind(this), $scope);
56 | }
57 |
58 | onDataReceived(dataList) {
59 | this.lastQueryMeta = null;
60 | this.lastQueryError = null;
61 |
62 | const anySeriesFromQuery = _.find(dataList, { refId: this.target.refId });
63 | if (anySeriesFromQuery) {
64 | this.lastQueryMeta = anySeriesFromQuery.meta;
65 | }
66 | }
67 |
68 | onDataError(err) {
69 | if (err.data && err.data.results) {
70 | const queryRes = err.data.results[this.target.refId];
71 | if (queryRes) {
72 | this.lastQueryMeta = queryRes.meta;
73 | this.lastQueryError = queryRes.error;
74 | }
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/dist/query_ctrl.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | import _ from "lodash";
4 | import { QueryCtrl } from 'app/plugins/sdk';
5 | import './css/query-editor.css!'
6 |
7 | export interface SwisQuery {
8 | refId: string;
9 | format: string;
10 | alias: string;
11 | rawSql: string;
12 | }
13 |
14 | export interface QueryMeta {
15 | sql: string;
16 | }
17 |
18 | const defaultQuery = `SELECT TOP 5
19 | LastSync,
20 | Caption,
21 | CPULoad,
22 | ResponseTime
23 | FROM
24 | Orion.Nodes`;
25 |
26 | export class SwisQueryCtrl extends QueryCtrl {
27 | static templateUrl = 'partials/query.editor.html';
28 |
29 | showLastQuerySQL: boolean;
30 | formats: any[];
31 | target: SwisQuery;
32 | lastQueryMeta: QueryMeta;
33 | lastQueryError: string;
34 | showHelp: boolean;
35 |
36 |
37 | constructor($scope, $injector) {
38 | super($scope, $injector);
39 |
40 | this.target.format = this.target.format || 'time_series';
41 | this.target.alias = '';
42 | this.formats = [{ text: 'Time series', value: 'time_series' }, { text: 'Table', value: 'table' }];
43 |
44 | if (!this.target.rawSql) {
45 | // special handling when in table panel
46 | if (this.panelCtrl.panel.type === 'table') {
47 | this.target.format = 'table';
48 | this.target.rawSql = 'SELECT 1';
49 | } else {
50 | this.target.rawSql = defaultQuery;
51 | }
52 | }
53 |
54 | this.panelCtrl.events.on('data-received', this.onDataReceived.bind(this), $scope);
55 | this.panelCtrl.events.on('data-error', this.onDataError.bind(this), $scope);
56 | }
57 |
58 | onDataReceived(dataList) {
59 | this.lastQueryMeta = null;
60 | this.lastQueryError = null;
61 |
62 | const anySeriesFromQuery = _.find(dataList, { refId: this.target.refId });
63 | if (anySeriesFromQuery) {
64 | this.lastQueryMeta = anySeriesFromQuery.meta;
65 | }
66 | }
67 |
68 | onDataError(err) {
69 | if (err.data && err.data.results) {
70 | const queryRes = err.data.results[this.target.refId];
71 | if (queryRes) {
72 | this.lastQueryMeta = queryRes.meta;
73 | this.lastQueryError = queryRes.error;
74 | }
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 | require('load-grunt-tasks')(grunt);
3 |
4 | var pkgJson = require('./package.json');
5 |
6 | grunt.loadNpmTasks('grunt-contrib-clean');
7 | grunt.loadNpmTasks('grunt-typescript');
8 | grunt.loadNpmTasks('grunt-contrib-watch');
9 | grunt.loadNpmTasks('grunt-string-replace');
10 |
11 | grunt.initConfig({
12 | clean: ['dist'],
13 |
14 | copy: {
15 | dist_js: {
16 | expand: true,
17 | cwd: 'src',
18 | src: ['**/*.ts', '**/*.d.ts'],
19 | dest: 'dist'
20 | },
21 | dist_html: {
22 | expand: true,
23 | flatten: true,
24 | cwd: 'src/partials',
25 | src: ['*.html'],
26 | dest: 'dist/partials/'
27 | },
28 | dist_css: {
29 | expand: true,
30 | flatten: true,
31 | cwd: 'src/css',
32 | src: ['*.css'],
33 | dest: 'dist/css/'
34 | },
35 | dist_img: {
36 | expand: true,
37 | flatten: true,
38 | cwd: 'src/img',
39 | src: ['*.*'],
40 | dest: 'dist/img/'
41 | },
42 | dist_statics: {
43 | expand: true,
44 | flatten: true,
45 | src: ['src/plugin.json', 'LICENSE', 'README.md'],
46 | dest: 'dist/'
47 | }
48 | },
49 |
50 | typescript: {
51 | build: {
52 | src: ['dist/**/*.ts', '!**/*.d.ts'],
53 | dest: 'dist',
54 | options: {
55 | module: 'system',
56 | target: 'es5',
57 | rootDir: 'dist/',
58 | declaration: true,
59 | emitDecoratorMetadata: true,
60 | experimentalDecorators: true,
61 | sourceMap: true,
62 | noImplicitAny: false,
63 | }
64 | }
65 | },
66 |
67 | 'string-replace': {
68 | dist: {
69 | files: [{
70 | cwd: 'src',
71 | expand: true,
72 | src: ["**/plugin.json"],
73 | dest: 'dist'
74 | }],
75 | options: {
76 | replacements: [{
77 | pattern: '%VERSION%',
78 | replacement: pkgJson.version
79 | },{
80 | pattern: '%TODAY%',
81 | replacement: '<%= grunt.template.today("yyyy-mm-dd") %>'
82 | }]
83 | }
84 | }
85 | },
86 |
87 | watch: {
88 | files: ['src/**/*.ts', 'src/**/*.html', 'src/**/*.css', 'src/img/*.*', 'src/plugin.json', 'README.md'],
89 | tasks: ['default'],
90 | options: {
91 | debounceDelay: 250,
92 | },
93 | }
94 | });
95 |
96 | grunt.registerTask('default', [
97 | 'clean',
98 | 'copy:dist_js',
99 | 'typescript:build',
100 | 'copy:dist_html',
101 | 'copy:dist_css',
102 | 'copy:dist_img',
103 | 'copy:dist_statics',
104 | 'string-replace'
105 | ]);
106 | };
107 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SolarWinds SWIS DataSource based on Simple JSON Datasource
2 |
3 | SWIS (SolarWinds Information Service) uses SWQL language - [learn more](https://github.com/solarwinds/OrionSDK/wiki/About-SWIS)
4 |
5 | DataSource connects to SWIS HTTP REST endpoint. As URl specify SWIS HTTP endpoint address which is by default
6 | - https://orionservername:17778/SolarWinds/InformationService/v3/Json/
7 |
8 | Unfortunately this endpoint doesn't support CORS so we can connect only via Server(default)
9 | and due to self-signed certificate we need to check option 'Skip TLS Verify'. Anonymous connection
10 | is not permited so you need to fill in your orion account credentials.
11 |
12 |
13 | 
14 |
15 | # SWIS query language
16 | SWQL language is proprietal solarwinds query language to get data from all their data sources, [learn more](https://github.com/solarwinds/OrionSDK/wiki/About-SWIS)
17 |
18 | ## Time Series:
19 | For time series data there are these conditions.
20 | 1. There has to be time column
21 | 2. There has to be string column to define metric name
22 | 3. There has to be value column(s), in case more columns are specified we will add suffix to metric name.
23 | 4. Data must be ordered by time
24 |
25 | ## Table:
26 | - No restriction to data queries
27 |
28 | Grafana macros available to use:
29 | - $from - time interval start
30 | - $to - time interval end
31 | - $__interval - interval length for sampling
32 |
33 | ## Time Sampling:
34 | - For sampling you must use function downsample([timecolumn]). Sampling interval is used automaticaly from variable $__interval
35 |
36 | ## Variable queries:
37 | - you need to define __text (manadatory) and __value columns:
38 | ``` sql
39 | SELECT Caption as __text, NodeID as __value FROM Orion.Nodes
40 | ```
41 | Variables are used in query via its name with prefix $.
42 | ``` sql
43 | SELECT .... FROM ... WHERE .... AND NodeID IN ($Node)
44 | ```
45 |
46 | ## For annotation queries:
47 | - you need to specify datetime column (mandatory) and then you can set text and tags columns
48 | ``` sql
49 | SELECT EventTime as time, Message as text, s.EventTypeProperties.Name as tags
50 | FROM Orion.Events s WHERE EventTime BETWEEN $from AND $to
51 | ```
52 |
53 | Example of query with time sampling to display CPUload and memory per node:
54 | ``` sql
55 | SELECT
56 | downsample(ObservationTimeStamp) as time,
57 | a.Node.Caption,
58 | AVG(AvgLoad) as CpuLoad,
59 | AVG(AvgMemoryUsed) as MemoryUsed
60 | FROM Orion.CPULoad a
61 | WHERE ObservationTimeStamp BETWEEN $from AND $to
62 | GROUP BY downsample(ObservationTimeStamp), a.Node.Caption, a.NodeID
63 | ORDER BY time DESC
64 | ```
65 | ## Installation Manually
66 | 1. Download sources zip file.
67 | 2. Extract the zip file into the data/plugins subdirectory for Grafana.
68 | 3. Because this plugin is not signed, you need to add exception into your grafana configuration. Navigate to grafana folder /conf/defaults.ini and find option *allow_loading_unsigned_plugins* which has to be equal
69 | ```
70 | allow_loading_unsigned_plugins = solarwinds-swis-datasource
71 | ```
72 | 3. Restart the Grafana server
73 | 4. To make sure the plugin was installed, check the list of installed data sources.
74 |
--------------------------------------------------------------------------------
/dist/README.md:
--------------------------------------------------------------------------------
1 | # SolarWinds SWIS DataSource based on Simple JSON Datasource
2 |
3 | SWIS (SolarWinds Information Service) uses SWQL language - [learn more](https://github.com/solarwinds/OrionSDK/wiki/About-SWIS)
4 |
5 | DataSource connects to SWIS HTTP REST endpoint. As URl specify SWIS HTTP endpoint address which is by default
6 | - https://orionservername:17778/SolarWinds/InformationService/v3/Json/
7 |
8 | Unfortunately this endpoint doesn't support CORS so we can connect only via Server(default)
9 | and due to self-signed certificate we need to check option 'Skip TLS Verify'. Anonymous connection
10 | is not permited so you need to fill in your orion account credentials.
11 |
12 |
13 | 
14 |
15 | # SWIS query language
16 | SWQL language is proprietal solarwinds query language to get data from all their data sources, [learn more](https://github.com/solarwinds/OrionSDK/wiki/About-SWIS)
17 |
18 | ## Time Series:
19 | For time series data there are these conditions.
20 | 1. There has to be time column
21 | 2. There has to be string column to define metric name
22 | 3. There has to be value column(s), in case more columns are specified we will add suffix to metric name.
23 | 4. Data must be ordered by time
24 |
25 | ## Table:
26 | - No restriction to data queries
27 |
28 | Grafana macros available to use:
29 | - $from - time interval start
30 | - $to - time interval end
31 | - $__interval - interval length for sampling
32 |
33 | ## Time Sampling:
34 | - For sampling you must use function downsample([timecolumn]). Sampling interval is used automaticaly from variable $__interval
35 |
36 | ## Variable queries:
37 | - you need to define __text (manadatory) and __value columns:
38 | ``` sql
39 | SELECT Caption as __text, NodeID as __value FROM Orion.Nodes
40 | ```
41 | Variables are used in query via its name with prefix $.
42 | ``` sql
43 | SELECT .... FROM ... WHERE .... AND NodeID IN ($Node)
44 | ```
45 |
46 | ## For annotation queries:
47 | - you need to specify datetime column (mandatory) and then you can set text and tags columns
48 | ``` sql
49 | SELECT EventTime as time, Message as text, s.EventTypeProperties.Name as tags
50 | FROM Orion.Events s WHERE EventTime BETWEEN $from AND $to
51 | ```
52 |
53 | Example of query with time sampling to display CPUload and memory per node:
54 | ``` sql
55 | SELECT
56 | downsample(ObservationTimeStamp) as time,
57 | a.Node.Caption,
58 | AVG(AvgLoad) as CpuLoad,
59 | AVG(AvgMemoryUsed) as MemoryUsed
60 | FROM Orion.CPULoad a
61 | WHERE ObservationTimeStamp BETWEEN $from AND $to
62 | GROUP BY downsample(ObservationTimeStamp), a.Node.Caption, a.NodeID
63 | ORDER BY time DESC
64 | ```
65 | ## Installation Manually
66 | 1. Download sources zip file.
67 | 2. Extract the zip file into the data/plugins subdirectory for Grafana.
68 | 3. Because this plugin is not signed, you need to add exception into your grafana configuration. Navigate to grafana folder /conf/defaults.ini and find option *allow_loading_unsigned_plugins* which has to be equal
69 | ```
70 | allow_loading_unsigned_plugins = solarwinds-swis-datasource
71 | ```
72 | 3. Restart the Grafana server
73 | 4. To make sure the plugin was installed, check the list of installed data sources.
74 |
--------------------------------------------------------------------------------
/specs/datasource_specs.ts:
--------------------------------------------------------------------------------
1 | import {SwisDatasource} from "../src/datasource";
2 | import TemplateSrvStub from './lib/template_srv_stub';
3 | import Q from "q";
4 |
5 | describe('GenericDatasource', function() {
6 | var ctx = {
7 | ds: {},
8 | $q: {},
9 | backendSrv: {},
10 | templateSrv: new TemplateSrvStub()
11 | };
12 |
13 | beforeEach(function() {
14 | ctx.$q = Q;
15 | ctx.backendSrv = {};
16 | ctx.templateSrv = new TemplateSrvStub();
17 | ctx.ds = new SwisDatasource({url:'swis'}, ctx.$q, ctx.backendSrv, ctx.templateSrv);
18 | });
19 |
20 | it('should return an empty array when no targets are set', function(done) {
21 | ctx.ds.query({targets: []}).then(function(result) {
22 | expect(result.data).to.have.length(0);
23 | done();
24 | });
25 | });
26 | it('should return correctly translated time series data', function(done) {
27 | ctx.backendSrv.datasourceRequest = function(request) {
28 |
29 | expect(request.url).to.equal('swis/Query');
30 | expect(request.method).to.equal('POST');
31 |
32 | var result = '';
33 | // metadata query is first
34 | if( request.data.query.indexOf(' WITH SCHEMAONLY') !== -1) {
35 | result = '{"results":[{"Index":0,"Name":"LastSync","Alias":"LastSync","Type":"property","DataType":"System.DateTime","Entity":"Orion.Nodes"},'+
36 | '{"Index":1,"Name":"Caption","Alias":"Caption","Type":"property","DataType":"System.String","Entity":"Orion.Nodes"},'+
37 | '{"Index":2,"Name":"CPULoad","Alias":"CPULoad","Type":"property","DataType":"System.Int32","Entity":"Orion.Nodes"}]}'
38 | }
39 | else {
40 | result = '{"results":[{"LastSync":"2019-05-27T07:11:47.3900000","Caption":"server1","CPULoad":19},'+
41 | '{"LastSync":"2019-05-27T07:10:43.8200000","Caption":"server2","CPULoad":-2}]}';
42 | }
43 |
44 | return ctx.$q.when({
45 | data: JSON.parse(result)
46 | });
47 | };
48 |
49 | ctx.templateSrv.replace = function(data) {
50 | return data;
51 | }
52 |
53 | ctx.ds.query({
54 | targets: [{
55 | format: 'time_series',
56 | rawSql: 'SELECT LastSync, Caption, CpuLoad FROM Orion.Nodes'
57 | }]
58 | }).then(function(result) {
59 |
60 | expect(result.data).to.have.length(2);
61 |
62 | var series = result.data[0];
63 | expect(series.target).to.equal('server1');
64 | expect(series.datapoints).to.have.length(1);
65 | expect(series.datapoints[0][0]).to.be(19);
66 | expect(series.datapoints[0][1]).to.be(Date.parse('2019-05-27T07:11:47.3900000Z'));
67 |
68 | series = result.data[1];
69 | expect(series.target).to.equal('server2');
70 | expect(series.datapoints).to.have.length(1);
71 | expect(series.datapoints[0][0]).to.be(-2);
72 | expect(series.datapoints[0][1]).to.be(Date.parse('2019-05-27T07:10:43.8200000Z'));
73 |
74 | done();
75 | });
76 | });
77 | });
78 |
--------------------------------------------------------------------------------
/dist/query_ctrl.js:
--------------------------------------------------------------------------------
1 | ///
2 | System.register(["lodash", 'app/plugins/sdk', './css/query-editor.css!'], function(exports_1) {
3 | var __extends = (this && this.__extends) || function (d, b) {
4 | for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
5 | function __() { this.constructor = d; }
6 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
7 | };
8 | var lodash_1, sdk_1;
9 | var defaultQuery, SwisQueryCtrl;
10 | return {
11 | setters:[
12 | function (lodash_1_1) {
13 | lodash_1 = lodash_1_1;
14 | },
15 | function (sdk_1_1) {
16 | sdk_1 = sdk_1_1;
17 | },
18 | function (_1) {}],
19 | execute: function() {
20 | defaultQuery = "SELECT TOP 5\n LastSync, \n Caption,\n CPULoad, \n ResponseTime \nFROM\n Orion.Nodes";
21 | SwisQueryCtrl = (function (_super) {
22 | __extends(SwisQueryCtrl, _super);
23 | function SwisQueryCtrl($scope, $injector) {
24 | _super.call(this, $scope, $injector);
25 | this.target.format = this.target.format || 'time_series';
26 | this.target.alias = '';
27 | this.formats = [{ text: 'Time series', value: 'time_series' }, { text: 'Table', value: 'table' }];
28 | if (!this.target.rawSql) {
29 | // special handling when in table panel
30 | if (this.panelCtrl.panel.type === 'table') {
31 | this.target.format = 'table';
32 | this.target.rawSql = 'SELECT 1';
33 | }
34 | else {
35 | this.target.rawSql = defaultQuery;
36 | }
37 | }
38 | this.panelCtrl.events.on('data-received', this.onDataReceived.bind(this), $scope);
39 | this.panelCtrl.events.on('data-error', this.onDataError.bind(this), $scope);
40 | }
41 | SwisQueryCtrl.prototype.onDataReceived = function (dataList) {
42 | this.lastQueryMeta = null;
43 | this.lastQueryError = null;
44 | var anySeriesFromQuery = lodash_1.default.find(dataList, { refId: this.target.refId });
45 | if (anySeriesFromQuery) {
46 | this.lastQueryMeta = anySeriesFromQuery.meta;
47 | }
48 | };
49 | SwisQueryCtrl.prototype.onDataError = function (err) {
50 | if (err.data && err.data.results) {
51 | var queryRes = err.data.results[this.target.refId];
52 | if (queryRes) {
53 | this.lastQueryMeta = queryRes.meta;
54 | this.lastQueryError = queryRes.error;
55 | }
56 | }
57 | };
58 | SwisQueryCtrl.templateUrl = 'partials/query.editor.html';
59 | return SwisQueryCtrl;
60 | })(sdk_1.QueryCtrl);
61 | exports_1("SwisQueryCtrl", SwisQueryCtrl);
62 | }
63 | }
64 | });
65 | //# sourceMappingURL=query_ctrl.js.map
--------------------------------------------------------------------------------
/dist/partials/query.editor.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
21 |
22 |
23 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
{{ctrl.lastQueryMeta.sql}}
35 |
36 |
37 |
Time series:
38 | Write SWQL queries to be used as Metric series or regular table. For Series there has to be defined time column.
39 | As metric is taken first string column or next data column in row. In case there's multiple data columns, each column is taken as metrix suffix
40 |
41 | Optional:
42 | - return column named metric to represent the series name.
43 | - If multiple value columns are returned the metric column is used as prefix.
44 | - If no column named metric is found the column name of the value column is used as series name
45 |
46 | Table:
47 | - return any set of columns
48 |
49 | Grafana macros to use:
50 | - $from - time interval start
51 | - $to - time interval end
52 |
53 | Time Series:
54 | - for sampling you must use function downsample([timecolumn]). TimeInterval is used from grafanata $__interval variable
55 | - you must also sort result by time
56 |
57 | Example time series query:
58 | SELECT
59 | downsample(ObservationTimeStamp) as time,
60 | a.Node.Caption,
61 | AVG(AvgLoad) as CpuLoad,
62 | AVG(AvgMemoryUsed) as MemoryUsed
63 | FROM Orion.CPULoad a
64 | WHERE ObservationTimeStamp BETWEEN $from AND $to
65 | GROUP BY downsample(ObservationTimeStamp), a.Node.Caption, a.NodeID
66 | ORDER BY time DESC
67 |
Time series:
38 | Write SWQL queries to be used as Metric series or regular table. For Series there has to be defined time column.
39 | As metric is taken first string column or next data column in row. In case there's multiple data columns, each column is taken as metrix suffix
40 |
41 | Optional:
42 | - return column named metric to represent the series name.
43 | - If multiple value columns are returned the metric column is used as prefix.
44 | - If no column named metric is found the column name of the value column is used as series name
45 |
46 | Table:
47 | - return any set of columns
48 |
49 | Grafana macros to use:
50 | - $from - time interval start
51 | - $to - time interval end
52 |
53 | Time Series:
54 | - for sampling you must use function downsample([timecolumn]). TimeInterval is used from grafanata $__interval variable
55 | - you must also sort result by time
56 |
57 | Example time series query:
58 | SELECT
59 | downsample(ObservationTimeStamp) as time,
60 | a.Node.Caption,
61 | AVG(AvgLoad) as CpuLoad,
62 | AVG(AvgMemoryUsed) as MemoryUsed
63 | FROM Orion.CPULoad a
64 | WHERE ObservationTimeStamp BETWEEN $from AND $to
65 | GROUP BY downsample(ObservationTimeStamp), a.Node.Caption, a.NodeID
66 | ORDER BY time DESC
67 |