Forráskód Böngészése

feat(examples): add datasource plugin example

bergquist 9 éve
szülő
commit
3435df8b9c

+ 13 - 0
examples/datasource-plugin-genericdatasource/.jscs.json

@@ -0,0 +1,13 @@
+{
+    "disallowImplicitTypeConversion": ["string"],
+    "disallowKeywords": ["with"],
+    "disallowMultipleLineBreaks": true,
+    "disallowMixedSpacesAndTabs": true,
+    "disallowTrailingWhitespace": true,
+    "requireSpacesInFunctionExpression": {
+        "beforeOpeningCurlyBrace": true
+    },
+    "disallowSpacesInsideArrayBrackets": true,
+    "disallowSpacesInsideParentheses": true,
+    "validateIndentation": 2
+}

+ 36 - 0
examples/datasource-plugin-genericdatasource/.jshintrc

@@ -0,0 +1,36 @@
+{
+  "browser": true,
+  "esnext": true,
+
+  "bitwise":false,
+  "curly": true,
+  "eqnull": true,
+  "devel": true,
+  "eqeqeq": true,
+  "forin": false,
+  "immed": true,
+  "supernew": true,
+  "expr": true,
+  "indent": 2,
+  "latedef": true,
+  "newcap": true,
+  "noarg": true,
+  "noempty": true,
+  "undef": true,
+  "boss": true,
+  "trailing": true,
+  "laxbreak": true,
+  "laxcomma": true,
+  "sub": true,
+  "unused": true,
+  "maxdepth": 6,
+  "maxlen": 140,
+
+  "globals": {
+    "System": true,
+    "define": true,
+    "require": true,
+    "Chromath": false,
+    "setImmediate": true
+  }
+}

+ 54 - 0
examples/datasource-plugin-genericdatasource/Gruntfile.js

@@ -0,0 +1,54 @@
+module.exports = function(grunt) {
+
+  require('load-grunt-tasks')(grunt);
+
+  grunt.loadNpmTasks('grunt-execute');
+  grunt.loadNpmTasks('grunt-contrib-clean');
+
+  grunt.initConfig({
+
+    clean: ["dist"],
+
+    copy: {
+      src_to_dist: {
+        cwd: 'src',
+        expand: true,
+        src: ['**/*', '!**/*.js', '!**/*.scss'],
+        dest: 'dist'
+      },
+      pluginDef: {
+        expand: true,
+        src: 'plugin.json',
+        dest: 'dist',
+      }
+    },
+
+    watch: {
+      rebuild_all: {
+        files: ['src/**/*', 'plugin.json'],
+        tasks: ['default'],
+        options: {spawn: false}
+      },
+    },
+
+    babel: {
+      options: {
+        sourceMap: true,
+        presets:  ["es2015"],
+        plugins: ['transform-es2015-modules-systemjs', "transform-es2015-for-of"],
+      },
+      dist: {
+        files: [{
+          cwd: 'src',
+          expand: true,
+          src: ['**/*.js'],
+          dest: 'dist',
+          ext:'.js'
+        }]
+      },
+    },
+
+  });
+
+  grunt.registerTask('default', ['clean', 'copy:src_to_dist', 'copy:pluginDef', 'babel']);
+};

+ 75 - 0
examples/datasource-plugin-genericdatasource/README.md

@@ -0,0 +1,75 @@
+#Generic backend datasource#
+
+This is a very minimalistic datasource that forwards http requests in a defined format. The idea is that anybody should be able to build an api and retrieve data from any datasource without built-in support in grafana.
+
+Its also serves as an living example implementation of a datasource.
+
+A guide for installing plugins can be found at [placeholder for links].
+
+Your backend need implement 3 urls
+ * "/" Should return 200 ok. Used for "Test connection" on the datasource config page.
+ * "/search" Used by the find metric options on the query tab in panels
+ * "/query" Should return metrics based on input
+
+## Metric discovery ##
+
+### Request ###
+```
+{ refId: 'F', target: 'select metric' }
+```
+### Expected Response ###
+
+An array of options based on the target input
+
+####Example####
+```
+["upper_25","upper_50","upper_75","upper_90","upper_95"]
+```
+
+## Metric query ##
+
+### Request ###
+```
+{
+  range: { from: '2015-12-22T03:06:13.851Z',to: '2015-12-22T06:48:24.137Z' },
+  interval: '5s',
+  targets:
+   [ { refId: 'B', target: 'upper_75' },
+     { refId: 'A', target: 'upper_90' } ],
+  format: 'json',
+  maxDataPoints: 2495 //decided by the panel
+}
+```
+### Expected response ###
+
+An array of
+```
+{
+  "target":"target_name",
+  "datapoints":[
+    [intvalue, timestamp in epoch],
+    [intvalue, timestamp in epoch]
+  ]
+}
+```
+###Example###
+```
+[
+  {
+    "target":"upper_75",
+    "datapoints":[
+      [622,1450754160000],
+      [365,1450754220000]
+    ]
+  },
+  {
+    "target":"upper_90",
+    "datapoints":[
+      [861,1450754160000],
+      [767,1450754220000]
+    ]
+  }
+]
+```
+## Example backend implementation ##
+https://gist.github.com/bergquist/bc4aa5baface3cffa109

+ 37 - 0
examples/datasource-plugin-genericdatasource/package.json

@@ -0,0 +1,37 @@
+{
+  "name": "kentik-app",
+  "private": true,
+  "version": "1.0.0",
+  "description": "",
+  "main": "index.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/raintank/kentik-app-poc.git"
+  },
+  "author": "",
+  "license": "ISC",
+  "bugs": {
+    "url": "https://github.com/raintank/kentik-app-poc/issues"
+  },
+  "devDependencies": {
+    "grunt": "~0.4.5",
+    "babel": "~6.5.1",
+    "grunt-babel": "~6.0.0",
+    "grunt-contrib-copy": "~0.8.2",
+    "grunt-contrib-watch": "^0.6.1",
+    "grunt-contrib-uglify": "~0.11.0",
+    "grunt-systemjs-builder": "^0.2.5",
+    "load-grunt-tasks": "~3.2.0",
+    "grunt-execute": "~0.2.2",
+    "grunt-contrib-clean": "~0.6.0"
+  },
+  "dependencies": {
+    "babel-plugin-transform-es2015-modules-systemjs": "^6.5.0",
+    "babel-preset-es2015": "^6.5.0",
+    "lodash": "~4.0.0"
+  },
+  "homepage": "https://github.com/raintank/kentik-app-poc#readme"
+}

+ 27 - 0
examples/datasource-plugin-genericdatasource/plugin.json

@@ -0,0 +1,27 @@
+{
+  "name": "GenericDatasource",
+  "id": "datasource-plugin-genericdatasource",
+  "type": "datasource",
+
+  "module": "plugins/genericdatasource/datasource",
+
+  "staticRoot": ".",
+
+  "metrics": true,
+  "annotations": false,
+
+  "info": {
+    "description": "generic datsource plugin",
+    "author": {
+      "name": "Raintank Inc.",
+      "url": "http://raintank.io"
+    },
+    "version": "0.9.0",
+    "updated": "2016-02-10"
+  },
+
+  "dependencies": {
+    "grafanaVersion": "2.6.x",
+    "plugins": [ ]
+  }
+}

+ 3 - 0
examples/datasource-plugin-genericdatasource/src/css/query-editor.css

@@ -0,0 +1,3 @@
+.generic-datasource-query-row .query-keyword {
+  width: 75px;
+}

+ 65 - 0
examples/datasource-plugin-genericdatasource/src/datasource.js

@@ -0,0 +1,65 @@
+export class GenericDatasource {
+
+  constructor(instanceSettings, $q, backendSrv) {
+    this.type = instanceSettings.type;
+    this.url = instanceSettings.url;
+    this.name = instanceSettings.name;
+    this.q = $q;
+    this.backendSrv = backendSrv;
+  }
+
+  // Called once per panel (graph)
+  query(options) {
+    var query = this.buildQueryParameters(options);
+
+    if (query.targets.length <= 0) {
+      return this.q.when([]);
+    }
+
+    return this.backendSrv.datasourceRequest({
+      url: this.url + '/query',
+      data: query,
+      method: 'POST',
+      headers: { 'Content-Type': 'application/json' }
+    });
+  }
+
+  // Required
+  // Used for testing datasource in datasource configuration pange
+  testDatasource() {
+    return this.backendSrv.datasourceRequest({
+      url: this.url + '/',
+      method: 'GET'
+    }).then(response => {
+      if (response.status === 200) {
+        return { status: "success", message: "Data source is working", title: "Success" };
+      }
+    });
+  }
+
+  // Optional
+  // Required for templating
+  metricFindQuery(options) {
+    return this.backendSrv.datasourceRequest({
+      url: this.url + '/search',
+      data: options,
+      method: 'POST',
+      headers: { 'Content-Type': 'application/json' }
+    }).then(this.mapToTextValue);
+  }
+
+  mapToTextValue(result) {
+    return _.map(result.data, (d, i) => {
+      return { text: d, value: i};
+    });
+  }
+
+  buildQueryParameters(options) {
+    //remove placeholder targets
+    options.targets = _.filter(options.targets, target => {
+      return target.target !== 'select metric';
+    });
+
+    return options;
+  }
+}

+ 15 - 0
examples/datasource-plugin-genericdatasource/src/module.js

@@ -0,0 +1,15 @@
+import {GenericDatasource} from './datasource';
+import {GenericDatasourceQueryCtrl} from './query_ctrl';
+
+class GenericConfigCtrl {}
+GenericConfigCtrl.templateUrl = 'partials/config.html';
+
+class GenericQueryOptionsCtrl {}
+GenericQueryOptionsCtrl.templateUrl = 'partials/query.options.html';
+
+export {
+  GenericDatasource as Datasource,
+  GenericDatasourceQueryCtrl as QueryCtrl,
+  GenericConfigCtrl as ConfigCtrl,
+  GenericQueryOptionsCtrl as QueryOptionsCtrl
+};

+ 2 - 0
examples/datasource-plugin-genericdatasource/src/partials/config.html

@@ -0,0 +1,2 @@
+<datasource-http-settings current="ctrl.current">
+</datasource-http-settings>

+ 8 - 0
examples/datasource-plugin-genericdatasource/src/partials/query.editor.html

@@ -0,0 +1,8 @@
+<query-editor-row ctrl="ctrl" class="generic-datasource-query-row">
+	<ul class="tight-form-list">
+    <li class="tight-form-item query-keyword">Query</li>
+    <li>
+      <metric-segment-model property="ctrl.target.target" get-options="ctrl.getOptions()" on-change="ctrl.onChangeInternal()" css-class="tight-form-item-xxlarge"></metric-segment-model>
+    </li>
+  </ul>
+</query-editor-row>

+ 4 - 0
examples/datasource-plugin-genericdatasource/src/partials/query.options.html

@@ -0,0 +1,4 @@
+<section class="grafana-metric-options" >
+  <div class="gf-form">
+  </div>
+</section>

+ 26 - 0
examples/datasource-plugin-genericdatasource/src/query_ctrl.js

@@ -0,0 +1,26 @@
+import {QueryCtrl} from 'app/plugins/sdk';
+import './css/query-editor.css!'
+
+export class GenericDatasourceQueryCtrl extends QueryCtrl {
+
+  constructor($scope, $injector, uiSegmentSrv)  {
+    super($scope, $injector);
+
+    this.scope = $scope;
+    this.uiSegmentSrv = uiSegmentSrv;
+    this.target.target = this.target.target || 'select metric';
+  }
+
+  getOptions() {
+    return this.datasource.metricFindQuery(this.target)
+      .then(this.uiSegmentSrv.transformToSegments(false));
+      // Options have to be transformed by uiSegmentSrv to be usable by metric-segment-model directive
+  }
+
+  onChangeInternal() {
+    this.panelCtrl.refresh(); // Asks the panel to refresh data.
+  }
+}
+
+GenericDatasourceQueryCtrl.templateUrl = 'partials/query.editor.html';
+