Quellcode durchsuchen

Began work on plugin system

Torkel Ödegaard vor 10 Jahren
Ursprung
Commit
5bd5713a52

+ 10 - 5
pkg/api/frontendsettings.go

@@ -24,6 +24,7 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro
 	}
 
 	datasources := make(map[string]interface{})
+	var defaultDatasource string
 
 	for _, ds := range orgDataSources {
 		url := ds.Url
@@ -33,9 +34,12 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro
 		}
 
 		var dsMap = map[string]interface{}{
-			"type":    ds.Type,
-			"url":     url,
-			"default": ds.IsDefault,
+			"type": ds.Type,
+			"url":  url,
+		}
+
+		if ds.IsDefault {
+			defaultDatasource = ds.Name
 		}
 
 		if ds.Type == m.DS_INFLUXDB_08 {
@@ -69,8 +73,9 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro
 	}
 
 	jsonObj := map[string]interface{}{
-		"datasources": datasources,
-		"appSubUrl":   setting.AppSubUrl,
+		"defaultDatasource": defaultDatasource,
+		"datasources":       datasources,
+		"appSubUrl":         setting.AppSubUrl,
 		"buildInfo": map[string]interface{}{
 			"version":    setting.BuildVersion,
 			"commit":     setting.BuildCommit,

+ 2 - 0
pkg/cmd/dashboard.go

@@ -83,6 +83,8 @@ func importDashboard(path string, orgId int64) error {
 		return err
 	}
 
+	defer reader.Close()
+
 	dash := m.NewDashboard("temp")
 	jsonParser := json.NewDecoder(reader)
 

+ 81 - 0
pkg/plugins/plugins.go

@@ -0,0 +1,81 @@
+package plugins
+
+import (
+	"encoding/json"
+	"errors"
+	"os"
+	"path/filepath"
+
+	"github.com/grafana/grafana/pkg/log"
+)
+
+type PluginMeta struct {
+	Type string `json:"type"`
+	Name string `json:"name"`
+}
+
+var (
+	List []*PluginMeta
+)
+
+type PluginScanner struct {
+	pluginPath string
+	errors     []error
+}
+
+func Scan(pluginDir string) error {
+	List = make([]*PluginMeta, 0)
+
+	scanner := &PluginScanner{
+		pluginPath: pluginDir,
+	}
+
+	if err := filepath.Walk(pluginDir, scanner.walker); err != nil {
+		return err
+	}
+
+	if len(scanner.errors) > 0 {
+		return errors.New("Some plugins failed to load")
+	}
+
+	return nil
+}
+
+func (scanner *PluginScanner) walker(path string, f os.FileInfo, err error) error {
+	if err != nil {
+		return err
+	}
+
+	if f.IsDir() {
+		return nil
+	}
+
+	if f.Name() == "plugin.json" {
+		pluginMeta, err := loadPluginMeta(path)
+		if err != nil {
+			log.Error(3, "Failed to load plugin json file: %v,  err: %v", path, err)
+			scanner.errors = append(scanner.errors, err)
+		} else {
+			List = append(List, pluginMeta)
+		}
+	}
+	return nil
+}
+
+func loadPluginMeta(path string) (*PluginMeta, error) {
+	reader, err := os.Open(path)
+	if err != nil {
+		return nil, err
+	}
+
+	defer reader.Close()
+
+	jsonParser := json.NewDecoder(reader)
+
+	pluginMeta := &PluginMeta{}
+	if err := jsonParser.Decode(pluginMeta); err != nil {
+		return nil, err
+	}
+
+	return pluginMeta, nil
+}

+ 19 - 0
pkg/plugins/plugins_test.go

@@ -0,0 +1,19 @@
+package plugins
+
+import (
+	"path/filepath"
+	"testing"
+
+	. "github.com/smartystreets/goconvey/convey"
+)
+
+func TestPluginScans(t *testing.T) {
+
+	Convey("When scaning for plugins", t, func() {
+		path, _ := filepath.Abs("../../src/app/plugins")
+		err := Scan(path)
+
+		So(err, ShouldBeNil)
+		So(len(List), ShouldEqual, 1)
+	})
+}

+ 20 - 22
src/app/controllers/search.js

@@ -8,14 +8,13 @@ function (angular, _, config) {
 
   var module = angular.module('grafana.controllers');
 
-  module.controller('SearchCtrl', function($scope, $rootScope, $element, $location, datasourceSrv, $timeout) {
+  module.controller('SearchCtrl', function($scope, $location, $timeout, backendSrv) {
 
     $scope.init = function() {
       $scope.giveSearchFocus = 0;
       $scope.selectedIndex = -1;
       $scope.results = {dashboards: [], tags: [], metrics: []};
       $scope.query = { query: '', tag: '', starred: false };
-      $scope.db = datasourceSrv.getGrafanaDB();
       $scope.currentSearchId = 0;
 
       $timeout(function() {
@@ -61,21 +60,20 @@ function (angular, _, config) {
       $scope.currentSearchId = $scope.currentSearchId + 1;
       var localSearchId = $scope.currentSearchId;
 
-      return $scope.db.searchDashboards($scope.query)
-        .then(function(results) {
-          if (localSearchId < $scope.currentSearchId) { return; }
+      return backendSrv.get('/api/search', $scope.query).then(function(results) {
+        if (localSearchId < $scope.currentSearchId) { return; }
 
-          $scope.resultCount = results.tagsOnly ? results.tags.length : results.dashboards.length;
-          $scope.results.tags = results.tags;
-          $scope.results.dashboards = _.map(results.dashboards, function(dash) {
-            dash.url = 'dashboard/db/' + dash.slug;
-            return dash;
-          });
-
-          if ($scope.queryHasNoFilters()) {
-            $scope.results.dashboards.unshift({ title: 'Home', url: config.appSubUrl + '/', isHome: true });
-          }
+        $scope.resultCount = results.tagsOnly ? results.tags.length : results.dashboards.length;
+        $scope.results.tags = results.tags;
+        $scope.results.dashboards = _.map(results.dashboards, function(dash) {
+          dash.url = 'dashboard/db/' + dash.slug;
+          return dash;
         });
+
+        if ($scope.queryHasNoFilters()) {
+          $scope.results.dashboards.unshift({ title: 'Home', url: config.appSubUrl + '/', isHome: true });
+        }
+      });
     };
 
     $scope.queryHasNoFilters = function() {
@@ -118,13 +116,13 @@ function (angular, _, config) {
         height: '250px',
         editable: true,
         panels: [
-          {
-            type: 'graphite',
-            title: 'test',
-            span: 12,
-            targets: [{ target: metricId }]
-          }
-        ]
+      {
+        type: 'graphite',
+        title: 'test',
+        span: 12,
+        targets: [{ target: metricId }]
+      }
+      ]
       });
     };
 

+ 5 - 5
src/app/features/all.js

@@ -2,11 +2,11 @@ define([
   './panellinkeditor/module',
   './annotations/annotationsSrv',
   './templating/templateSrv',
-  './graphite/datasource',
-  './influxdb/datasource',
-  './influxdb_08/datasource',
-  './opentsdb/datasource',
-  './elasticsearch/datasource',
+//  './graphite/datasource',
+//  './influxdb/datasource',
+//  './influxdb_08/datasource',
+//  './opentsdb/datasource',
+//  './elasticsearch/datasource',
   './dashboard/all',
   './panel/all',
   './profile/profileCtrl',

+ 2 - 2
src/app/features/panel/panelSrv.js

@@ -94,8 +94,8 @@ function (angular, _, config) {
       $scope.fullscreen = false;
       $scope.editor = { index: 1 };
 
-      $scope.datasources = datasourceSrv.getMetricSources();
-      $scope.setDatasource($scope.panel.datasource);
+      // $scope.datasources = datasourceSrv.getMetricSources();
+      // $scope.setDatasource($scope.panel.datasource);
       $scope.dashboardViewState.registerPanel($scope);
 
       if ($scope.get_data) {

+ 12 - 10
src/app/panels/graph/module.js

@@ -23,7 +23,7 @@ function (angular, app, $, _, kbn, moment, TimeSeries, PanelMeta) {
     };
   });
 
-  module.controller('GraphCtrl', function($scope, $rootScope, panelSrv, annotationsSrv, timeSrv) {
+  module.controller('GraphCtrl', function($scope, $rootScope, panelSrv, annotationsSrv, timeSrv, datasourceSrv) {
 
     $scope.panelMeta = new PanelMeta({
       panelName: 'Graph',
@@ -183,15 +183,17 @@ function (angular, app, $, _, kbn, moment, TimeSeries, PanelMeta) {
 
       $scope.annotationsPromise = annotationsSrv.getAnnotations($scope.rangeUnparsed, $scope.dashboard);
 
-      return $scope.datasource.query(metricsQuery)
-        .then($scope.dataHandler)
-        .then(null, function(err) {
-          $scope.panelMeta.loading = false;
-          $scope.panelMeta.error = err.message || "Timeseries data request error";
-          $scope.inspector.error = err;
-          $scope.seriesList = [];
-          $scope.render([]);
-        });
+      return datasourceSrv.get($scope.panel.datasource).then(function(ds) {
+        return ds.query(metricsQuery)
+          .then($scope.dataHandler)
+          .then(null, function(err) {
+            $scope.panelMeta.loading = false;
+            $scope.panelMeta.error = err.message || "Timeseries data request error";
+            $scope.inspector.error = err;
+            $scope.seriesList = [];
+            $scope.render([]);
+          });
+      });
     };
 
     $scope.dataHandler = function(results) {

+ 0 - 0
src/plugins/custom.panel.example/editor.html → src/app/plugins/custom.panel.example/editor.html


+ 0 - 0
src/plugins/custom.panel.example/module.html → src/app/plugins/custom.panel.example/module.html


+ 0 - 0
src/plugins/custom.panel.example/module.js → src/app/plugins/custom.panel.example/module.js


+ 0 - 0
src/plugins/datasource.example.js → src/app/plugins/datasource.example.js


+ 20 - 0
src/app/plugins/datasources/graphite/module.js

@@ -0,0 +1,20 @@
+define([
+  'angular',
+],
+function (angular) {
+  'use strict';
+
+  var module = angular.module('grafana.services');
+
+  module.factory('MyDataSource', function() {
+
+    function MyDataSource(datasource) {
+      this.type = 'my_ds';
+      this.datasource = datasource;
+    }
+
+    return MyDataSource;
+
+  });
+
+});

+ 7 - 0
src/app/plugins/datasources/graphite/plugin.json

@@ -0,0 +1,7 @@
+{
+  "type": "datasource",
+  "name": "My Data source",
+  "keyName": "graphite"
+  "serviceName": "MyDataSource",
+  "editPartial": "./partials/edit.html",
+}

+ 3 - 5
src/app/routes/backend/dashboard.js

@@ -7,9 +7,7 @@ function (angular) {
 
   var module = angular.module('grafana.routes');
 
-  module.controller('DashFromDBProvider', function($scope, datasourceSrv, $routeParams, backendSrv) {
-
-    var db = datasourceSrv.getGrafanaDB();
+  module.controller('DashFromDBProvider', function($scope, $routeParams, backendSrv) {
 
     if (!$routeParams.id) {
       backendSrv.get('/api/dashboards/home').then(function(result) {
@@ -22,9 +20,9 @@ function (angular) {
       return;
     }
 
-    db.getDashboard($routeParams.id, false).then(function(result) {
+    return backendSrv.get('/api/dashboards/db/' + $routeParams.id).then(function(result) {
       $scope.initDashboard(result, $scope);
-    }).then(null, function() {
+    }, function() {
       $scope.initDashboard({
         meta: {},
         model: { title: 'Not found' }

+ 41 - 40
src/app/services/datasourceSrv.js

@@ -16,46 +16,22 @@ function (angular, _, config) {
     'grafana': 'GrafanaDatasource',
   };
 
-  module.service('datasourceSrv', function($q, $http, $injector) {
+  var plugins = {
+    datasources: {
+      'graphite': {
+        'serviceName': 'GraphiteDatasource',
+        'module': 'features/graphite/datasource'
+      }
+    }
+  };
 
-    this.init = function(dsSettingList) {
-      config.datasources = dsSettingList;
+  module.service('datasourceSrv', function($q, $injector, $rootScope) {
+    var self = this;
 
-      this.datasources = {};
-      this.metricSources = [];
-      this.annotationSources = [];
-
-      _.each(dsSettingList, function(value, key) {
-        var ds = this.datasourceFactory(value);
-        ds.name = key;
-        if (value.default) {
-          this.default = ds;
-          ds.default = true;
-        }
-        this.datasources[key] = ds;
-      }, this);
-
-      if (!this.default) {
-        this.default = this.datasources[_.keys(this.datasources)[0]];
-        this.default.default = true;
-      }
+    this.datasources = {};
 
-      // create list of different source types
-      _.each(this.datasources, function(value, key) {
-        if (value.supportMetrics) {
-          this.metricSources.push({
-            name: value.name,
-            value: value.default ? null : key,
-            default: value.default,
-          });
-        }
-        if (value.supportAnnotations) {
-          this.annotationSources.push({ name: key, editorSrc: value.annotationEditorSrc });
-        }
-        if (value.grafanaDB) {
-          this.grafanaDB = value;
-        }
-      }, this);
+    this.init = function(dsSettingList) {
+      config.datasources = dsSettingList;
     };
 
     this.datasourceFactory = function(ds) {
@@ -65,10 +41,35 @@ function (angular, _, config) {
     };
 
     this.get = function(name) {
-      if (!name) { return this.default; }
-      if (this.datasources[name]) { return this.datasources[name]; }
+      if (!name) {
+        return this.get(config.defaultDatasource);
+      }
+
+      if (this.datasources[name]) {
+        return $q.when(this.datasources[name]);
+      }
+
+      return this.loadDatasource(name);
+    };
+
+    this.loadDatasource = function(name) {
+      var datasourceConfig = config.datasources[name];
+      var pluginDef = plugins.datasources[datasourceConfig.type];
+
+      if (!pluginDef) {
+        throw { message: "No plugin definition for data source: " + name };
+      }
+
+      var deferred = $q.defer();
+
+      $rootScope.require([pluginDef.module], function() {
+        var AngularService = $injector.get(pluginDef.serviceName);
+        var instance = new AngularService(datasourceConfig);
+        self.datasources[name] = instance;
+        deferred.resolve(instance);
+      });
 
-      return this.default;
+      return deferred.promise;
     };
 
     this.getAll = function() {