Browse Source

add pluginBundle backend api methods and SQL storage

woodsaj 10 năm trước cách đây
mục cha
commit
c4a0fe0234

+ 10 - 4
pkg/api/api.go

@@ -13,7 +13,7 @@ func Register(r *macaron.Macaron) {
 	reqSignedIn := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true})
 	reqGrafanaAdmin := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true, ReqGrafanaAdmin: true})
 	reqEditorRole := middleware.RoleAuth(m.ROLE_EDITOR, m.ROLE_ADMIN)
-	regOrgAdmin := middleware.RoleAuth(m.ROLE_ADMIN)
+	reqOrgAdmin := middleware.RoleAuth(m.ROLE_ADMIN)
 	quota := middleware.Quota
 	bind := binding.Bind
 
@@ -113,7 +113,7 @@ func Register(r *macaron.Macaron) {
 			r.Get("/invites", wrap(GetPendingOrgInvites))
 			r.Post("/invites", quota("user"), bind(dtos.AddInviteForm{}), wrap(AddOrgInvite))
 			r.Patch("/invites/:code/revoke", wrap(RevokeInvite))
-		}, regOrgAdmin)
+		}, reqOrgAdmin)
 
 		// create new org
 		r.Post("/orgs", quota("org"), bind(m.CreateOrgCommand{}), wrap(CreateOrg))
@@ -140,7 +140,7 @@ func Register(r *macaron.Macaron) {
 			r.Get("/", wrap(GetApiKeys))
 			r.Post("/", quota("api_key"), bind(m.AddApiKeyCommand{}), wrap(AddApiKey))
 			r.Delete("/:id", wrap(DeleteApiKey))
-		}, regOrgAdmin)
+		}, reqOrgAdmin)
 
 		// Data sources
 		r.Group("/datasources", func() {
@@ -150,7 +150,13 @@ func Register(r *macaron.Macaron) {
 			r.Delete("/:id", DeleteDataSource)
 			r.Get("/:id", wrap(GetDataSourceById))
 			r.Get("/plugins", GetDataSourcePlugins)
-		}, regOrgAdmin)
+		}, reqOrgAdmin)
+
+		// PluginBundles
+		r.Group("/plugins", func() {
+			r.Get("/", wrap(GetPluginBundles))
+			r.Post("/", bind(m.UpdatePluginBundleCmd{}), wrap(UpdatePluginBundle))
+		}, reqOrgAdmin)
 
 		r.Get("/frontend/settings/", GetFrontendSettings)
 		r.Any("/datasources/proxy/:id/*", reqSignedIn, ProxyDataSourceRequest)

+ 7 - 3
pkg/api/datasources.go

@@ -115,9 +115,13 @@ func UpdateDataSource(c *middleware.Context, cmd m.UpdateDataSourceCommand) {
 
 func GetDataSourcePlugins(c *middleware.Context) {
 	dsList := make(map[string]interface{})
-	//TODO(awoods): query DB for orgPlugins
-	orgPlugins := map[string]m.PluginBundle{}
-	enabledPlugins := plugins.GetEnabledPlugins(orgPlugins)
+
+	orgBundles := m.GetPluginBundlesQuery{OrgId: c.OrgId}
+	err := bus.Dispatch(&orgBundles)
+	if err != nil {
+		c.JsonApiErr(500, "Failed to get org plugin Bundles", err)
+	}
+	enabledPlugins := plugins.GetEnabledPlugins(orgBundles.Result)
 
 	for key, value := range enabledPlugins.DataSourcePlugins {
 		if !value.BuiltIn {

+ 8 - 0
pkg/api/dtos/plugin_bundle.go

@@ -0,0 +1,8 @@
+package dtos
+
+type PluginBundle struct {
+	Type     string                 `json:"type"`
+	Enabled  bool                   `json:"enabled"`
+	Module   string                 `json:"module"`
+	JsonData map[string]interface{} `json:"jsonData"`
+}

+ 6 - 3
pkg/api/frontendsettings.go

@@ -29,9 +29,12 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro
 	datasources := make(map[string]interface{})
 	var defaultDatasource string
 
-	//TODO(awoods): query DB to get list of the users plugin preferences.
-	orgPlugins := map[string]m.PluginBundle{}
-	enabledPlugins := plugins.GetEnabledPlugins(orgPlugins)
+	orgBundles := m.GetPluginBundlesQuery{OrgId: c.OrgId}
+	err := bus.Dispatch(&orgBundles)
+	if err != nil {
+		return nil, err
+	}
+	enabledPlugins := plugins.GetEnabledPlugins(orgBundles.Result)
 
 	for _, ds := range orgDataSources {
 		url := ds.Url

+ 8 - 3
pkg/api/index.go

@@ -2,6 +2,7 @@ package api
 
 import (
 	"github.com/grafana/grafana/pkg/api/dtos"
+	"github.com/grafana/grafana/pkg/bus"
 	"github.com/grafana/grafana/pkg/middleware"
 	m "github.com/grafana/grafana/pkg/models"
 	"github.com/grafana/grafana/pkg/plugins"
@@ -62,9 +63,13 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
 		})
 	}
 
-	//TODO(awoods): query DB to get list of the users plugin preferences.
-	orgPlugins := map[string]m.PluginBundle{}
-	enabledPlugins := plugins.GetEnabledPlugins(orgPlugins)
+	orgBundles := m.GetPluginBundlesQuery{OrgId: c.OrgId}
+	err = bus.Dispatch(&orgBundles)
+	if err != nil {
+		return nil, err
+	}
+	enabledPlugins := plugins.GetEnabledPlugins(orgBundles.Result)
+
 	for _, plugin := range enabledPlugins.ExternalPlugins {
 		for _, js := range plugin.Js {
 			data.PluginJs = append(data.PluginJs, js.Module)

+ 65 - 0
pkg/api/plugin_bundle.go

@@ -0,0 +1,65 @@
+package api
+
+import (
+	"github.com/grafana/grafana/pkg/api/dtos"
+	"github.com/grafana/grafana/pkg/bus"
+	"github.com/grafana/grafana/pkg/middleware"
+	m "github.com/grafana/grafana/pkg/models"
+	"github.com/grafana/grafana/pkg/plugins"
+)
+
+func GetPluginBundles(c *middleware.Context) Response {
+	query := m.GetPluginBundlesQuery{OrgId: c.OrgId}
+
+	if err := bus.Dispatch(&query); err != nil {
+		return ApiError(500, "Failed to list Plugin Bundles", err)
+	}
+
+	installedBundlesMap := make(map[string]*dtos.PluginBundle)
+	for t, b := range plugins.Bundles {
+		installedBundlesMap[t] = &dtos.PluginBundle{
+			Type:     b.Type,
+			Enabled:  b.Enabled,
+			Module:   b.Module,
+			JsonData: make(map[string]interface{}),
+		}
+	}
+
+	seenBundles := make(map[string]bool)
+
+	result := make([]*dtos.PluginBundle, 0)
+	for _, b := range query.Result {
+		if def, ok := installedBundlesMap[b.Type]; ok {
+			result = append(result, &dtos.PluginBundle{
+				Type:     b.Type,
+				Enabled:  b.Enabled,
+				Module:   def.Module,
+				JsonData: b.JsonData,
+			})
+			seenBundles[b.Type] = true
+		}
+	}
+
+	for t, b := range installedBundlesMap {
+		if _, ok := seenBundles[t]; !ok {
+			result = append(result, b)
+		}
+	}
+
+	return Json(200, result)
+}
+
+func UpdatePluginBundle(c *middleware.Context, cmd m.UpdatePluginBundleCmd) Response {
+	cmd.OrgId = c.OrgId
+
+	if _, ok := plugins.Bundles[cmd.Type]; !ok {
+		return ApiError(404, "Bundle type not installed.", nil)
+	}
+
+	err := bus.Dispatch(&cmd)
+	if err != nil {
+		return ApiError(500, "Failed to update plugin bundle", err)
+	}
+
+	return ApiSuccess("Plugin updated")
+}

+ 30 - 4
pkg/models/plugin_bundle.go

@@ -1,8 +1,34 @@
 package models
 
+import "time"
+
 type PluginBundle struct {
-	Id      int64
-	Type    string
-	Org     int64
-	Enabled bool
+	Id       int64
+	Type     string
+	OrgId    int64
+	Enabled  bool
+	JsonData map[string]interface{}
+
+	Created time.Time
+	Updated time.Time
+}
+
+// ----------------------
+// COMMANDS
+
+// Also acts as api DTO
+type UpdatePluginBundleCmd struct {
+	Type     string                 `json:"type" binding:"Required"`
+	Enabled  bool                   `json:"enabled"`
+	JsonData map[string]interface{} `json:"jsonData"`
+
+	Id    int64 `json:"-"`
+	OrgId int64 `json:"-"`
+}
+
+// ---------------------
+// QUERIES
+type GetPluginBundlesQuery struct {
+	OrgId  int64
+	Result []*PluginBundle
 }

+ 2 - 2
pkg/plugins/models.go

@@ -37,8 +37,7 @@ type ExternalPluginRoute struct {
 }
 
 type ExternalPluginJs struct {
-	Module    string `json:"module"`
-	Directive string `json:"Directive"`
+	Module string `json:"module"`
 }
 
 type ExternalPluginNavLink struct {
@@ -68,6 +67,7 @@ type PluginBundle struct {
 	PanelPlugins      []string `json:"panelPlugins"`
 	DatasourcePlugins []string `json:"datasourcePlugins"`
 	ExternalPlugins   []string `json:"externalPlugins"`
+	Module            string   `json:"module"`
 }
 
 type EnabledPlugins struct {

+ 7 - 2
pkg/plugins/plugins.go

@@ -172,13 +172,18 @@ func (scanner *PluginScanner) loadPluginJson(pluginJsonFilePath string) error {
 	return nil
 }
 
-func GetEnabledPlugins(bundles map[string]models.PluginBundle) EnabledPlugins {
+func GetEnabledPlugins(orgBundles []*models.PluginBundle) EnabledPlugins {
 	enabledPlugins := NewEnabledPlugins()
 
+	orgBundlesMap := make(map[string]*models.PluginBundle)
+	for _, orgBundle := range orgBundles {
+		orgBundlesMap[orgBundle.Type] = orgBundle
+	}
+
 	for bundleType, bundle := range Bundles {
 		enabled := bundle.Enabled
 		// check if the bundle is stored in the DB.
-		if b, ok := bundles[bundleType]; ok {
+		if b, ok := orgBundlesMap[bundleType]; ok {
 			enabled = b.Enabled
 		}
 

+ 1 - 0
pkg/services/sqlstore/migrations/migrations.go

@@ -18,6 +18,7 @@ func AddMigrations(mg *Migrator) {
 	addApiKeyMigrations(mg)
 	addDashboardSnapshotMigrations(mg)
 	addQuotaMigration(mg)
+	addPluginBundleMigration(mg)
 }
 
 func addMigrationLogMigrations(mg *Migrator) {

+ 26 - 0
pkg/services/sqlstore/migrations/plugin_bundle.go

@@ -0,0 +1,26 @@
+package migrations
+
+import . "github.com/grafana/grafana/pkg/services/sqlstore/migrator"
+
+func addPluginBundleMigration(mg *Migrator) {
+
+	var pluginBundleV1 = Table{
+		Name: "plugin_bundle",
+		Columns: []*Column{
+			{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
+			{Name: "org_id", Type: DB_BigInt, Nullable: true},
+			{Name: "type", Type: DB_NVarchar, Length: 255, Nullable: false},
+			{Name: "enabled", Type: DB_Bool, Nullable: false},
+			{Name: "json_data", Type: DB_Text, Nullable: true},
+			{Name: "created", Type: DB_DateTime, Nullable: false},
+			{Name: "updated", Type: DB_DateTime, Nullable: false},
+		},
+		Indices: []*Index{
+			{Cols: []string{"org_id", "type"}, Type: UniqueIndex},
+		},
+	}
+	mg.AddMigration("create plugin_bundle table v1", NewAddTableMigration(pluginBundleV1))
+
+	//-------  indexes ------------------
+	addTableIndicesMigrations(mg, "v1", pluginBundleV1)
+}

+ 46 - 0
pkg/services/sqlstore/plugin_bundle.go

@@ -0,0 +1,46 @@
+package sqlstore
+
+import (
+	"time"
+
+	"github.com/grafana/grafana/pkg/bus"
+	m "github.com/grafana/grafana/pkg/models"
+)
+
+func init() {
+	bus.AddHandler("sql", GetPluginBundles)
+	bus.AddHandler("sql", UpdatePluginBundle)
+}
+
+func GetPluginBundles(query *m.GetPluginBundlesQuery) error {
+	sess := x.Where("org_id=?", query.OrgId)
+
+	query.Result = make([]*m.PluginBundle, 0)
+	return sess.Find(&query.Result)
+}
+
+func UpdatePluginBundle(cmd *m.UpdatePluginBundleCmd) error {
+	return inTransaction2(func(sess *session) error {
+		var bundle m.PluginBundle
+
+		exists, err := sess.Where("org_id=? and type=?", cmd.OrgId, cmd.Type).Get(&bundle)
+		sess.UseBool("enabled")
+		if !exists {
+			bundle = m.PluginBundle{
+				Type:     cmd.Type,
+				OrgId:    cmd.OrgId,
+				Enabled:  cmd.Enabled,
+				JsonData: cmd.JsonData,
+				Created:  time.Now(),
+				Updated:  time.Now(),
+			}
+			_, err = sess.Insert(&bundle)
+			return err
+		} else {
+			bundle.Enabled = cmd.Enabled
+			bundle.JsonData = cmd.JsonData
+			_, err = sess.Id(bundle.Id).Update(&bundle)
+			return err
+		}
+	})
+}

+ 3 - 2
public/app/plugins/plugin.json

@@ -1,8 +1,9 @@
 {
   "pluginType": "bundle",
   "type": "core",
+  "module": "",
   "enabled": true,
-  "panelPlugins": ["graph", "singlestat", "text", "dashlist"],
-  "datasourcePlugins": ["grafana", "graphite"],
+  "panelPlugins": ["graph", "singlestat", "text", "dashlist", "table"],
+  "datasourcePlugins": ["mixed", "grafana", "graphite", "cloudwatch", "elasticsearch", "influxdb", "influxdb_08", "kairosdb", "opentsdb", "prometheus"],
   "externalPlugins": []
 }