Began work on plugin system

This commit is contained in:
Torkel Ödegaard 2015-02-27 13:45:00 +01:00
parent 011fdf7ab6
commit 5bd5713a52
16 changed files with 222 additions and 89 deletions

View File

@ -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,

View File

@ -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
pkg/plugins/plugins.go Normal file
View File

@ -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
}

View File

@ -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)
})
}

View File

@ -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 }]
}
]
});
};

View File

@ -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',

View File

@ -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) {

View File

@ -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) {

View File

@ -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;
});
});

View File

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

View File

@ -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' }

View File

@ -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'
}
}
};
module.service('datasourceSrv', function($q, $injector, $rootScope) {
var self = this;
this.datasources = {};
this.init = function(dsSettingList) {
config.datasources = dsSettingList;
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;
}
// 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.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);
}
return this.default;
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 deferred.promise;
};
this.getAll = function() {