Commit c4a0fe02 by woodsaj

add pluginBundle backend api methods and SQL storage

parent bd4cb549
......@@ -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)
......
......@@ -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 {
......
package dtos
type PluginBundle struct {
Type string `json:"type"`
Enabled bool `json:"enabled"`
Module string `json:"module"`
JsonData map[string]interface{} `json:"jsonData"`
}
......@@ -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
......
......@@ -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)
......
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")
}
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
}
......@@ -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 {
......
......@@ -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
}
......
......@@ -18,6 +18,7 @@ func AddMigrations(mg *Migrator) {
addApiKeyMigrations(mg)
addDashboardSnapshotMigrations(mg)
addQuotaMigration(mg)
addPluginBundleMigration(mg)
}
func addMigrationLogMigrations(mg *Migrator) {
......
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)
}
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
}
})
}
{
"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": []
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment