mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
refactor.
Rename externalPlugin to apiPlugin Rename bundle to app Move js, css, menuItem and staticRoot to be properties os App Add "app" field to panel, datasource and api plugin models. If populated then the plugin is only enabled if the specific app is enabled for the Org. If app is "", then the plugin is enabled for all orgs and can't be disabled.
This commit is contained in:
parent
0697274695
commit
c35b51a268
@ -157,8 +157,8 @@ func Register(r *macaron.Macaron) {
|
|||||||
|
|
||||||
// PluginBundles
|
// PluginBundles
|
||||||
r.Group("/plugins", func() {
|
r.Group("/plugins", func() {
|
||||||
r.Get("/", wrap(GetPluginBundles))
|
r.Get("/", wrap(GetAppPlugins))
|
||||||
r.Post("/", bind(m.UpdatePluginBundleCmd{}), wrap(UpdatePluginBundle))
|
r.Post("/", bind(m.UpdateAppPluginCmd{}), wrap(UpdateAppPlugin))
|
||||||
}, reqOrgAdmin)
|
}, reqOrgAdmin)
|
||||||
|
|
||||||
r.Get("/frontend/settings/", GetFrontendSettings)
|
r.Get("/frontend/settings/", GetFrontendSettings)
|
||||||
@ -196,7 +196,7 @@ func Register(r *macaron.Macaron) {
|
|||||||
// rendering
|
// rendering
|
||||||
r.Get("/render/*", reqSignedIn, RenderToPng)
|
r.Get("/render/*", reqSignedIn, RenderToPng)
|
||||||
|
|
||||||
InitExternalPluginRoutes(r)
|
InitApiPluginRoutes(r)
|
||||||
|
|
||||||
r.NotFound(NotFoundHandler)
|
r.NotFound(NotFoundHandler)
|
||||||
}
|
}
|
||||||
|
@ -14,9 +14,9 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/util"
|
"github.com/grafana/grafana/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func InitExternalPluginRoutes(r *macaron.Macaron) {
|
func InitApiPluginRoutes(r *macaron.Macaron) {
|
||||||
for _, plugin := range plugins.ExternalPlugins {
|
for _, plugin := range plugins.ApiPlugins {
|
||||||
log.Info("Plugin: Adding proxy routes for backend plugin")
|
log.Info("Plugin: Adding proxy routes for api plugin")
|
||||||
for _, route := range plugin.Routes {
|
for _, route := range plugin.Routes {
|
||||||
url := util.JoinUrlFragments("/api/plugin-proxy/", route.Path)
|
url := util.JoinUrlFragments("/api/plugin-proxy/", route.Path)
|
||||||
handlers := make([]macaron.Handler, 0)
|
handlers := make([]macaron.Handler, 0)
|
||||||
@ -33,14 +33,14 @@ func InitExternalPluginRoutes(r *macaron.Macaron) {
|
|||||||
handlers = append(handlers, middleware.RoleAuth(m.ROLE_EDITOR, m.ROLE_ADMIN))
|
handlers = append(handlers, middleware.RoleAuth(m.ROLE_EDITOR, m.ROLE_ADMIN))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
handlers = append(handlers, ExternalPlugin(route.Url))
|
handlers = append(handlers, ApiPlugin(route.Url))
|
||||||
r.Route(url, route.Method, handlers...)
|
r.Route(url, route.Method, handlers...)
|
||||||
log.Info("Plugin: Adding route %s", url)
|
log.Info("Plugin: Adding route %s", url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExternalPlugin(routeUrl string) macaron.Handler {
|
func ApiPlugin(routeUrl string) macaron.Handler {
|
||||||
return func(c *middleware.Context) {
|
return func(c *middleware.Context) {
|
||||||
path := c.Params("*")
|
path := c.Params("*")
|
||||||
|
|
||||||
@ -51,13 +51,13 @@ func ExternalPlugin(routeUrl string) macaron.Handler {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
targetUrl, _ := url.Parse(routeUrl)
|
targetUrl, _ := url.Parse(routeUrl)
|
||||||
proxy := NewExternalPluginProxy(string(ctx), path, targetUrl)
|
proxy := NewApiPluginProxy(string(ctx), path, targetUrl)
|
||||||
proxy.Transport = dataProxyTransport
|
proxy.Transport = dataProxyTransport
|
||||||
proxy.ServeHTTP(c.RW(), c.Req.Request)
|
proxy.ServeHTTP(c.RW(), c.Req.Request)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewExternalPluginProxy(ctx string, proxyPath string, targetUrl *url.URL) *httputil.ReverseProxy {
|
func NewApiPluginProxy(ctx string, proxyPath string, targetUrl *url.URL) *httputil.ReverseProxy {
|
||||||
director := func(req *http.Request) {
|
director := func(req *http.Request) {
|
||||||
req.URL.Scheme = targetUrl.Scheme
|
req.URL.Scheme = targetUrl.Scheme
|
||||||
req.URL.Host = targetUrl.Host
|
req.URL.Host = targetUrl.Host
|
65
pkg/api/app_plugin.go
Normal file
65
pkg/api/app_plugin.go
Normal file
@ -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 GetAppPlugins(c *middleware.Context) Response {
|
||||||
|
query := m.GetAppPluginsQuery{OrgId: c.OrgId}
|
||||||
|
|
||||||
|
if err := bus.Dispatch(&query); err != nil {
|
||||||
|
return ApiError(500, "Failed to list Plugin Bundles", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
installedAppsMap := make(map[string]*dtos.AppPlugin)
|
||||||
|
for t, a := range plugins.Apps {
|
||||||
|
installedAppsMap[t] = &dtos.AppPlugin{
|
||||||
|
Type: a.Type,
|
||||||
|
Enabled: a.Enabled,
|
||||||
|
Module: a.Module,
|
||||||
|
JsonData: make(map[string]interface{}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
seenApps := make(map[string]bool)
|
||||||
|
|
||||||
|
result := make([]*dtos.AppPlugin, 0)
|
||||||
|
for _, b := range query.Result {
|
||||||
|
if def, ok := installedAppsMap[b.Type]; ok {
|
||||||
|
result = append(result, &dtos.AppPlugin{
|
||||||
|
Type: b.Type,
|
||||||
|
Enabled: b.Enabled,
|
||||||
|
Module: def.Module,
|
||||||
|
JsonData: b.JsonData,
|
||||||
|
})
|
||||||
|
seenApps[b.Type] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for t, a := range installedAppsMap {
|
||||||
|
if _, ok := seenApps[t]; !ok {
|
||||||
|
result = append(result, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Json(200, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateAppPlugin(c *middleware.Context, cmd m.UpdateAppPluginCmd) Response {
|
||||||
|
cmd.OrgId = c.OrgId
|
||||||
|
|
||||||
|
if _, ok := plugins.Apps[cmd.Type]; !ok {
|
||||||
|
return ApiError(404, "App type not installed.", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := bus.Dispatch(&cmd)
|
||||||
|
if err != nil {
|
||||||
|
return ApiError(500, "Failed to update App Plugin", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ApiSuccess("App updated")
|
||||||
|
}
|
@ -3,6 +3,7 @@ package api
|
|||||||
import (
|
import (
|
||||||
"github.com/grafana/grafana/pkg/api/dtos"
|
"github.com/grafana/grafana/pkg/api/dtos"
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
|
//"github.com/grafana/grafana/pkg/log"
|
||||||
"github.com/grafana/grafana/pkg/middleware"
|
"github.com/grafana/grafana/pkg/middleware"
|
||||||
m "github.com/grafana/grafana/pkg/models"
|
m "github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/plugins"
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
@ -114,14 +115,14 @@ func UpdateDataSource(c *middleware.Context, cmd m.UpdateDataSourceCommand) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetDataSourcePlugins(c *middleware.Context) {
|
func GetDataSourcePlugins(c *middleware.Context) {
|
||||||
dsList := make(map[string]interface{})
|
dsList := make(map[string]*plugins.DataSourcePlugin)
|
||||||
|
|
||||||
orgBundles := m.GetPluginBundlesQuery{OrgId: c.OrgId}
|
orgApps := m.GetAppPluginsQuery{OrgId: c.OrgId}
|
||||||
err := bus.Dispatch(&orgBundles)
|
err := bus.Dispatch(&orgApps)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JsonApiErr(500, "Failed to get org plugin Bundles", err)
|
c.JsonApiErr(500, "Failed to get org plugin Bundles", err)
|
||||||
}
|
}
|
||||||
enabledPlugins := plugins.GetEnabledPlugins(orgBundles.Result)
|
enabledPlugins := plugins.GetEnabledPlugins(orgApps.Result)
|
||||||
|
|
||||||
for key, value := range enabledPlugins.DataSourcePlugins {
|
for key, value := range enabledPlugins.DataSourcePlugins {
|
||||||
if !value.BuiltIn {
|
if !value.BuiltIn {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package dtos
|
package dtos
|
||||||
|
|
||||||
type PluginBundle struct {
|
type AppPlugin struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
Module string `json:"module"`
|
Module string `json:"module"`
|
@ -29,12 +29,12 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro
|
|||||||
datasources := make(map[string]interface{})
|
datasources := make(map[string]interface{})
|
||||||
var defaultDatasource string
|
var defaultDatasource string
|
||||||
|
|
||||||
orgBundles := m.GetPluginBundlesQuery{OrgId: c.OrgId}
|
orgApps := m.GetAppPluginsQuery{OrgId: c.OrgId}
|
||||||
err := bus.Dispatch(&orgBundles)
|
err := bus.Dispatch(&orgApps)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
enabledPlugins := plugins.GetEnabledPlugins(orgBundles.Result)
|
enabledPlugins := plugins.GetEnabledPlugins(orgApps.Result)
|
||||||
|
|
||||||
for _, ds := range orgDataSources {
|
for _, ds := range orgDataSources {
|
||||||
url := ds.Url
|
url := ds.Url
|
||||||
|
@ -67,14 +67,14 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
orgBundles := m.GetPluginBundlesQuery{OrgId: c.OrgId}
|
orgApps := m.GetAppPluginsQuery{OrgId: c.OrgId}
|
||||||
err = bus.Dispatch(&orgBundles)
|
err = bus.Dispatch(&orgApps)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
enabledPlugins := plugins.GetEnabledPlugins(orgBundles.Result)
|
enabledPlugins := plugins.GetEnabledPlugins(orgApps.Result)
|
||||||
|
|
||||||
for _, plugin := range enabledPlugins.ExternalPlugins {
|
for _, plugin := range enabledPlugins.AppPlugins {
|
||||||
for _, js := range plugin.Js {
|
for _, js := range plugin.Js {
|
||||||
data.PluginJs = append(data.PluginJs, js.Module)
|
data.PluginJs = append(data.PluginJs, js.Module)
|
||||||
}
|
}
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
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")
|
|
||||||
}
|
|
@ -2,7 +2,7 @@ package models
|
|||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
type PluginBundle struct {
|
type AppPlugin struct {
|
||||||
Id int64
|
Id int64
|
||||||
Type string
|
Type string
|
||||||
OrgId int64
|
OrgId int64
|
||||||
@ -17,7 +17,7 @@ type PluginBundle struct {
|
|||||||
// COMMANDS
|
// COMMANDS
|
||||||
|
|
||||||
// Also acts as api DTO
|
// Also acts as api DTO
|
||||||
type UpdatePluginBundleCmd struct {
|
type UpdateAppPluginCmd struct {
|
||||||
Type string `json:"type" binding:"Required"`
|
Type string `json:"type" binding:"Required"`
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
JsonData map[string]interface{} `json:"jsonData"`
|
JsonData map[string]interface{} `json:"jsonData"`
|
||||||
@ -28,7 +28,7 @@ type UpdatePluginBundleCmd struct {
|
|||||||
|
|
||||||
// ---------------------
|
// ---------------------
|
||||||
// QUERIES
|
// QUERIES
|
||||||
type GetPluginBundlesQuery struct {
|
type GetAppPluginsQuery struct {
|
||||||
OrgId int64
|
OrgId int64
|
||||||
Result []*PluginBundle
|
Result []*AppPlugin
|
||||||
}
|
}
|
@ -12,6 +12,7 @@ type DataSourcePlugin struct {
|
|||||||
Annotations bool `json:"annotations"`
|
Annotations bool `json:"annotations"`
|
||||||
Metrics bool `json:"metrics"`
|
Metrics bool `json:"metrics"`
|
||||||
BuiltIn bool `json:"builtIn"`
|
BuiltIn bool `json:"builtIn"`
|
||||||
|
App string `json:"app"`
|
||||||
StaticRootConfig *StaticRootConfig `json:"staticRoot"`
|
StaticRootConfig *StaticRootConfig `json:"staticRoot"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20,6 +21,7 @@ type PanelPlugin struct {
|
|||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Module string `json:"module"`
|
Module string `json:"module"`
|
||||||
StaticRootConfig *StaticRootConfig `json:"staticRoot"`
|
StaticRootConfig *StaticRootConfig `json:"staticRoot"`
|
||||||
|
App string `json:"app"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type StaticRootConfig struct {
|
type StaticRootConfig struct {
|
||||||
@ -27,59 +29,63 @@ type StaticRootConfig struct {
|
|||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ExternalPluginRoute struct {
|
type ApiPluginRoute struct {
|
||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
Method string `json:"method"`
|
Method string `json:"method"`
|
||||||
ReqSignedIn bool `json:"reqSignedIn"`
|
ReqSignedIn bool `json:"reqSignedIn"`
|
||||||
ReqGrafanaAdmin bool `json:"reqGrafanaAdmin"`
|
ReqGrafanaAdmin bool `json:"reqGrafanaAdmin"`
|
||||||
ReqRole models.RoleType `json:"reqRole"`
|
ReqRole models.RoleType `json:"reqRole"`
|
||||||
Url string `json:"url"`
|
Url string `json:"url"`
|
||||||
|
App string `json:"app"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ExternalPluginJs struct {
|
type AppPluginJs struct {
|
||||||
Module string `json:"module"`
|
Module string `json:"module"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ExternalPluginNavLink struct {
|
type AppPluginNavLink struct {
|
||||||
Text string `json:"text"`
|
Text string `json:"text"`
|
||||||
Icon string `json:"icon"`
|
Icon string `json:"icon"`
|
||||||
Href string `json:"href"`
|
Href string `json:"href"`
|
||||||
ReqRole models.RoleType `json:"reqRole"`
|
ReqRole models.RoleType `json:"reqRole"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ExternalPluginCss struct {
|
type AppPluginCss struct {
|
||||||
Light string `json:"light"`
|
Light string `json:"light"`
|
||||||
Dark string `json:"dark"`
|
Dark string `json:"dark"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ExternalPlugin struct {
|
type ApiPlugin struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Routes []*ExternalPluginRoute `json:"routes"`
|
Routes []*ApiPluginRoute `json:"routes"`
|
||||||
Js []*ExternalPluginJs `json:"js"`
|
App string `json:"app"`
|
||||||
Css []*ExternalPluginCss `json:"css"`
|
|
||||||
MainNavLinks []*ExternalPluginNavLink `json:"mainNavLinks"`
|
|
||||||
StaticRootConfig *StaticRootConfig `json:"staticRoot"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type PluginBundle struct {
|
type AppPlugin struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
PanelPlugins []string `json:"panelPlugins"`
|
PanelPlugins []string `json:"panelPlugins"`
|
||||||
DatasourcePlugins []string `json:"datasourcePlugins"`
|
DatasourcePlugins []string `json:"datasourcePlugins"`
|
||||||
ExternalPlugins []string `json:"externalPlugins"`
|
ApiPlugins []string `json:"apiPlugins"`
|
||||||
Module string `json:"module"`
|
Module string `json:"module"`
|
||||||
|
Js []*AppPluginJs `json:"js"`
|
||||||
|
Css []*AppPluginCss `json:"css"`
|
||||||
|
MainNavLinks []*AppPluginNavLink `json:"mainNavLinks"`
|
||||||
|
StaticRootConfig *StaticRootConfig `json:"staticRoot"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type EnabledPlugins struct {
|
type EnabledPlugins struct {
|
||||||
PanelPlugins []*PanelPlugin
|
PanelPlugins []*PanelPlugin
|
||||||
DataSourcePlugins map[string]*DataSourcePlugin
|
DataSourcePlugins map[string]*DataSourcePlugin
|
||||||
ExternalPlugins []*ExternalPlugin
|
ApiPlugins []*ApiPlugin
|
||||||
|
AppPlugins []*AppPlugin
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEnabledPlugins() EnabledPlugins {
|
func NewEnabledPlugins() EnabledPlugins {
|
||||||
return EnabledPlugins{
|
return EnabledPlugins{
|
||||||
PanelPlugins: make([]*PanelPlugin, 0),
|
PanelPlugins: make([]*PanelPlugin, 0),
|
||||||
DataSourcePlugins: make(map[string]*DataSourcePlugin),
|
DataSourcePlugins: make(map[string]*DataSourcePlugin),
|
||||||
ExternalPlugins: make([]*ExternalPlugin, 0),
|
ApiPlugins: make([]*ApiPlugin, 0),
|
||||||
|
AppPlugins: make([]*AppPlugin, 0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,11 +14,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
DataSources map[string]DataSourcePlugin
|
DataSources map[string]*DataSourcePlugin
|
||||||
Panels map[string]PanelPlugin
|
Panels map[string]*PanelPlugin
|
||||||
ExternalPlugins map[string]ExternalPlugin
|
ApiPlugins map[string]*ApiPlugin
|
||||||
StaticRoutes []*StaticRootConfig
|
StaticRoutes []*StaticRootConfig
|
||||||
Bundles map[string]PluginBundle
|
Apps map[string]*AppPlugin
|
||||||
)
|
)
|
||||||
|
|
||||||
type PluginScanner struct {
|
type PluginScanner struct {
|
||||||
@ -27,39 +27,39 @@ type PluginScanner struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Init() error {
|
func Init() error {
|
||||||
DataSources = make(map[string]DataSourcePlugin)
|
DataSources = make(map[string]*DataSourcePlugin)
|
||||||
ExternalPlugins = make(map[string]ExternalPlugin)
|
ApiPlugins = make(map[string]*ApiPlugin)
|
||||||
StaticRoutes = make([]*StaticRootConfig, 0)
|
StaticRoutes = make([]*StaticRootConfig, 0)
|
||||||
Panels = make(map[string]PanelPlugin)
|
Panels = make(map[string]*PanelPlugin)
|
||||||
Bundles = make(map[string]PluginBundle)
|
Apps = make(map[string]*AppPlugin)
|
||||||
|
|
||||||
scan(path.Join(setting.StaticRootPath, "app/plugins"))
|
scan(path.Join(setting.StaticRootPath, "app/plugins"))
|
||||||
checkExternalPluginPaths()
|
checkPluginPaths()
|
||||||
checkDependencies()
|
checkDependencies()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkDependencies() {
|
func checkDependencies() {
|
||||||
for bundleType, bundle := range Bundles {
|
for appType, app := range Apps {
|
||||||
for _, reqPanel := range bundle.PanelPlugins {
|
for _, reqPanel := range app.PanelPlugins {
|
||||||
if _, ok := Panels[reqPanel]; !ok {
|
if _, ok := Panels[reqPanel]; !ok {
|
||||||
log.Fatal(4, "Bundle %s requires Panel type %s, but it is not present.", bundleType, reqPanel)
|
log.Fatal(4, "App %s requires Panel type %s, but it is not present.", appType, reqPanel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, reqDataSource := range bundle.DatasourcePlugins {
|
for _, reqDataSource := range app.DatasourcePlugins {
|
||||||
if _, ok := DataSources[reqDataSource]; !ok {
|
if _, ok := DataSources[reqDataSource]; !ok {
|
||||||
log.Fatal(4, "Bundle %s requires DataSource type %s, but it is not present.", bundleType, reqDataSource)
|
log.Fatal(4, "App %s requires DataSource type %s, but it is not present.", appType, reqDataSource)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, reqExtPlugin := range bundle.ExternalPlugins {
|
for _, reqApiPlugin := range app.ApiPlugins {
|
||||||
if _, ok := ExternalPlugins[reqExtPlugin]; !ok {
|
if _, ok := ApiPlugins[reqApiPlugin]; !ok {
|
||||||
log.Fatal(4, "Bundle %s requires DataSource type %s, but it is not present.", bundleType, reqExtPlugin)
|
log.Fatal(4, "App %s requires ApiPlugin type %s, but it is not present.", appType, reqApiPlugin)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkExternalPluginPaths() error {
|
func checkPluginPaths() error {
|
||||||
for _, section := range setting.Cfg.Sections() {
|
for _, section := range setting.Cfg.Sections() {
|
||||||
if strings.HasPrefix(section.Name(), "plugin.") {
|
if strings.HasPrefix(section.Name(), "plugin.") {
|
||||||
path := section.Key("path").String()
|
path := section.Key("path").String()
|
||||||
@ -146,7 +146,7 @@ func (scanner *PluginScanner) loadPluginJson(pluginJsonFilePath string) error {
|
|||||||
return errors.New("Did not find type property in plugin.json")
|
return errors.New("Did not find type property in plugin.json")
|
||||||
}
|
}
|
||||||
|
|
||||||
DataSources[p.Type] = p
|
DataSources[p.Type] = &p
|
||||||
addStaticRoot(p.StaticRootConfig, currentDir)
|
addStaticRoot(p.StaticRootConfig, currentDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,12 +161,12 @@ func (scanner *PluginScanner) loadPluginJson(pluginJsonFilePath string) error {
|
|||||||
return errors.New("Did not find type property in plugin.json")
|
return errors.New("Did not find type property in plugin.json")
|
||||||
}
|
}
|
||||||
|
|
||||||
Panels[p.Type] = p
|
Panels[p.Type] = &p
|
||||||
addStaticRoot(p.StaticRootConfig, currentDir)
|
addStaticRoot(p.StaticRootConfig, currentDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
if pluginType == "external" {
|
if pluginType == "api" {
|
||||||
p := ExternalPlugin{}
|
p := ApiPlugin{}
|
||||||
reader.Seek(0, 0)
|
reader.Seek(0, 0)
|
||||||
if err := jsonParser.Decode(&p); err != nil {
|
if err := jsonParser.Decode(&p); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -174,12 +174,11 @@ func (scanner *PluginScanner) loadPluginJson(pluginJsonFilePath string) error {
|
|||||||
if p.Type == "" {
|
if p.Type == "" {
|
||||||
return errors.New("Did not find type property in plugin.json")
|
return errors.New("Did not find type property in plugin.json")
|
||||||
}
|
}
|
||||||
ExternalPlugins[p.Type] = p
|
ApiPlugins[p.Type] = &p
|
||||||
addStaticRoot(p.StaticRootConfig, currentDir)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if pluginType == "bundle" {
|
if pluginType == "app" {
|
||||||
p := PluginBundle{}
|
p := AppPlugin{}
|
||||||
reader.Seek(0, 0)
|
reader.Seek(0, 0)
|
||||||
if err := jsonParser.Decode(&p); err != nil {
|
if err := jsonParser.Decode(&p); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -187,44 +186,81 @@ func (scanner *PluginScanner) loadPluginJson(pluginJsonFilePath string) error {
|
|||||||
if p.Type == "" {
|
if p.Type == "" {
|
||||||
return errors.New("Did not find type property in plugin.json")
|
return errors.New("Did not find type property in plugin.json")
|
||||||
}
|
}
|
||||||
Bundles[p.Type] = p
|
Apps[p.Type] = &p
|
||||||
|
addStaticRoot(p.StaticRootConfig, currentDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetEnabledPlugins(orgBundles []*models.PluginBundle) EnabledPlugins {
|
func GetEnabledPlugins(orgApps []*models.AppPlugin) EnabledPlugins {
|
||||||
enabledPlugins := NewEnabledPlugins()
|
enabledPlugins := NewEnabledPlugins()
|
||||||
|
|
||||||
orgBundlesMap := make(map[string]*models.PluginBundle)
|
orgAppsMap := make(map[string]*models.AppPlugin)
|
||||||
for _, orgBundle := range orgBundles {
|
for _, orgApp := range orgApps {
|
||||||
orgBundlesMap[orgBundle.Type] = orgBundle
|
orgAppsMap[orgApp.Type] = orgApp
|
||||||
}
|
}
|
||||||
|
seenPanels := make(map[string]bool)
|
||||||
|
seenApi := make(map[string]bool)
|
||||||
|
|
||||||
for bundleType, bundle := range Bundles {
|
for appType, app := range Apps {
|
||||||
enabled := bundle.Enabled
|
// start with enabled set to the default state listed in the json config.
|
||||||
// check if the bundle is stored in the DB.
|
enabled := app.Enabled
|
||||||
if b, ok := orgBundlesMap[bundleType]; ok {
|
|
||||||
|
// check if the app is stored in the DB for this org and if so, use the
|
||||||
|
// enabled state stored there.
|
||||||
|
if b, ok := orgAppsMap[appType]; ok {
|
||||||
enabled = b.Enabled
|
enabled = b.Enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
if enabled {
|
if enabled {
|
||||||
for _, d := range bundle.DatasourcePlugins {
|
for _, d := range app.DatasourcePlugins {
|
||||||
if ds, ok := DataSources[d]; ok {
|
if ds, ok := DataSources[d]; ok {
|
||||||
enabledPlugins.DataSourcePlugins[d] = &ds
|
enabledPlugins.DataSourcePlugins[d] = ds
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, p := range bundle.PanelPlugins {
|
for _, p := range app.PanelPlugins {
|
||||||
if panel, ok := Panels[p]; ok {
|
if panel, ok := Panels[p]; ok {
|
||||||
enabledPlugins.PanelPlugins = append(enabledPlugins.PanelPlugins, &panel)
|
if _, ok := seenPanels[p]; !ok {
|
||||||
|
seenPanels[p] = true
|
||||||
|
enabledPlugins.PanelPlugins = append(enabledPlugins.PanelPlugins, panel)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, e := range bundle.ExternalPlugins {
|
for _, a := range app.ApiPlugins {
|
||||||
if external, ok := ExternalPlugins[e]; ok {
|
if api, ok := ApiPlugins[a]; ok {
|
||||||
enabledPlugins.ExternalPlugins = append(enabledPlugins.ExternalPlugins, &external)
|
if _, ok := seenApi[a]; !ok {
|
||||||
|
seenApi[a] = true
|
||||||
|
enabledPlugins.ApiPlugins = append(enabledPlugins.ApiPlugins, api)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
enabledPlugins.AppPlugins = append(enabledPlugins.AppPlugins, app)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add all plugins that are not part of an App.
|
||||||
|
for d, installedDs := range DataSources {
|
||||||
|
if installedDs.App == "" {
|
||||||
|
enabledPlugins.DataSourcePlugins[d] = installedDs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for p, panel := range Panels {
|
||||||
|
if panel.App == "" {
|
||||||
|
if _, ok := seenPanels[p]; !ok {
|
||||||
|
seenPanels[p] = true
|
||||||
|
enabledPlugins.PanelPlugins = append(enabledPlugins.PanelPlugins, panel)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for a, api := range ApiPlugins {
|
||||||
|
if api.App == "" {
|
||||||
|
if _, ok := seenApi[a]; !ok {
|
||||||
|
seenApi[a] = true
|
||||||
|
enabledPlugins.ApiPlugins = append(enabledPlugins.ApiPlugins, api)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return enabledPlugins
|
return enabledPlugins
|
||||||
}
|
}
|
||||||
|
@ -8,25 +8,25 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
bus.AddHandler("sql", GetPluginBundles)
|
bus.AddHandler("sql", GetAppPlugins)
|
||||||
bus.AddHandler("sql", UpdatePluginBundle)
|
bus.AddHandler("sql", UpdateAppPlugin)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPluginBundles(query *m.GetPluginBundlesQuery) error {
|
func GetAppPlugins(query *m.GetAppPluginsQuery) error {
|
||||||
sess := x.Where("org_id=?", query.OrgId)
|
sess := x.Where("org_id=?", query.OrgId)
|
||||||
|
|
||||||
query.Result = make([]*m.PluginBundle, 0)
|
query.Result = make([]*m.AppPlugin, 0)
|
||||||
return sess.Find(&query.Result)
|
return sess.Find(&query.Result)
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdatePluginBundle(cmd *m.UpdatePluginBundleCmd) error {
|
func UpdateAppPlugin(cmd *m.UpdateAppPluginCmd) error {
|
||||||
return inTransaction2(func(sess *session) error {
|
return inTransaction2(func(sess *session) error {
|
||||||
var bundle m.PluginBundle
|
var app m.AppPlugin
|
||||||
|
|
||||||
exists, err := sess.Where("org_id=? and type=?", cmd.OrgId, cmd.Type).Get(&bundle)
|
exists, err := sess.Where("org_id=? and type=?", cmd.OrgId, cmd.Type).Get(&app)
|
||||||
sess.UseBool("enabled")
|
sess.UseBool("enabled")
|
||||||
if !exists {
|
if !exists {
|
||||||
bundle = m.PluginBundle{
|
app = m.AppPlugin{
|
||||||
Type: cmd.Type,
|
Type: cmd.Type,
|
||||||
OrgId: cmd.OrgId,
|
OrgId: cmd.OrgId,
|
||||||
Enabled: cmd.Enabled,
|
Enabled: cmd.Enabled,
|
||||||
@ -34,12 +34,12 @@ func UpdatePluginBundle(cmd *m.UpdatePluginBundleCmd) error {
|
|||||||
Created: time.Now(),
|
Created: time.Now(),
|
||||||
Updated: time.Now(),
|
Updated: time.Now(),
|
||||||
}
|
}
|
||||||
_, err = sess.Insert(&bundle)
|
_, err = sess.Insert(&app)
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
bundle.Enabled = cmd.Enabled
|
app.Enabled = cmd.Enabled
|
||||||
bundle.JsonData = cmd.JsonData
|
app.JsonData = cmd.JsonData
|
||||||
_, err = sess.Id(bundle.Id).Update(&bundle)
|
_, err = sess.Id(app.Id).Update(&app)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
})
|
})
|
@ -2,10 +2,10 @@ package migrations
|
|||||||
|
|
||||||
import . "github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
import . "github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||||
|
|
||||||
func addPluginBundleMigration(mg *Migrator) {
|
func addAppPluginMigration(mg *Migrator) {
|
||||||
|
|
||||||
var pluginBundleV1 = Table{
|
var appPluginV1 = Table{
|
||||||
Name: "plugin_bundle",
|
Name: "app_plugin",
|
||||||
Columns: []*Column{
|
Columns: []*Column{
|
||||||
{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
|
{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
|
||||||
{Name: "org_id", Type: DB_BigInt, Nullable: true},
|
{Name: "org_id", Type: DB_BigInt, Nullable: true},
|
||||||
@ -19,8 +19,8 @@ func addPluginBundleMigration(mg *Migrator) {
|
|||||||
{Cols: []string{"org_id", "type"}, Type: UniqueIndex},
|
{Cols: []string{"org_id", "type"}, Type: UniqueIndex},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
mg.AddMigration("create plugin_bundle table v1", NewAddTableMigration(pluginBundleV1))
|
mg.AddMigration("create app_plugin table v1", NewAddTableMigration(appPluginV1))
|
||||||
|
|
||||||
//------- indexes ------------------
|
//------- indexes ------------------
|
||||||
addTableIndicesMigrations(mg, "v1", pluginBundleV1)
|
addTableIndicesMigrations(mg, "v1", appPluginV1)
|
||||||
}
|
}
|
@ -18,7 +18,7 @@ func AddMigrations(mg *Migrator) {
|
|||||||
addApiKeyMigrations(mg)
|
addApiKeyMigrations(mg)
|
||||||
addDashboardSnapshotMigrations(mg)
|
addDashboardSnapshotMigrations(mg)
|
||||||
addQuotaMigration(mg)
|
addQuotaMigration(mg)
|
||||||
addPluginBundleMigration(mg)
|
addAppPluginMigration(mg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func addMigrationLogMigrations(mg *Migrator) {
|
func addMigrationLogMigrations(mg *Migrator) {
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"pluginType": "bundle",
|
|
||||||
"type": "core",
|
|
||||||
"module": "",
|
|
||||||
"enabled": true,
|
|
||||||
"panelPlugins": ["graph", "singlestat", "text", "dashlist", "table"],
|
|
||||||
"datasourcePlugins": ["mixed", "grafana", "graphite", "cloudwatch", "elasticsearch", "influxdb", "influxdb_08", "kairosdb", "opentsdb", "prometheus"],
|
|
||||||
"externalPlugins": []
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user