mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
feat(plugins): removed external plugins and bundle code, not ready for master yet, will revert this commit in seperate branch
This commit is contained in:
parent
2ec5bc77d7
commit
5eab5dc47b
@ -156,12 +156,6 @@ func Register(r *macaron.Macaron) {
|
||||
r.Get("/plugins", GetDataSourcePlugins)
|
||||
}, 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)
|
||||
r.Any("/datasources/proxy/:id", reqSignedIn, ProxyDataSourceRequest)
|
||||
@ -197,7 +191,5 @@ func Register(r *macaron.Macaron) {
|
||||
// rendering
|
||||
r.Get("/render/*", reqSignedIn, RenderToPng)
|
||||
|
||||
InitExternalPluginRoutes(r)
|
||||
|
||||
r.NotFound(NotFoundHandler)
|
||||
}
|
||||
|
@ -117,14 +117,7 @@ func UpdateDataSource(c *middleware.Context, cmd m.UpdateDataSourceCommand) {
|
||||
func GetDataSourcePlugins(c *middleware.Context) {
|
||||
dsList := make(map[string]interface{})
|
||||
|
||||
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 {
|
||||
for key, value := range plugins.DataSources {
|
||||
if !value.BuiltIn {
|
||||
dsList[key] = value
|
||||
}
|
||||
|
@ -1,75 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
|
||||
"github.com/Unknwon/macaron"
|
||||
"github.com/grafana/grafana/pkg/log"
|
||||
"github.com/grafana/grafana/pkg/middleware"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
|
||||
func InitExternalPluginRoutes(r *macaron.Macaron) {
|
||||
for _, plugin := range plugins.ExternalPlugins {
|
||||
log.Info("Plugin: Adding proxy routes for backend plugin")
|
||||
for _, route := range plugin.Routes {
|
||||
url := util.JoinUrlFragments("/api/plugin-proxy/", route.Path)
|
||||
handlers := make([]macaron.Handler, 0)
|
||||
if route.ReqSignedIn {
|
||||
handlers = append(handlers, middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true}))
|
||||
}
|
||||
if route.ReqGrafanaAdmin {
|
||||
handlers = append(handlers, middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true, ReqGrafanaAdmin: true}))
|
||||
}
|
||||
if route.ReqSignedIn && route.ReqRole != "" {
|
||||
if route.ReqRole == m.ROLE_ADMIN {
|
||||
handlers = append(handlers, middleware.RoleAuth(m.ROLE_ADMIN))
|
||||
} else if route.ReqRole == m.ROLE_EDITOR {
|
||||
handlers = append(handlers, middleware.RoleAuth(m.ROLE_EDITOR, m.ROLE_ADMIN))
|
||||
}
|
||||
}
|
||||
handlers = append(handlers, ExternalPlugin(route.Url))
|
||||
r.Route(url, route.Method, handlers...)
|
||||
log.Info("Plugin: Adding route %s", url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ExternalPlugin(routeUrl string) macaron.Handler {
|
||||
return func(c *middleware.Context) {
|
||||
path := c.Params("*")
|
||||
|
||||
//Create a HTTP header with the context in it.
|
||||
ctx, err := json.Marshal(c.SignedInUser)
|
||||
if err != nil {
|
||||
c.JsonApiErr(500, "failed to marshal context to json.", err)
|
||||
return
|
||||
}
|
||||
targetUrl, _ := url.Parse(routeUrl)
|
||||
proxy := NewExternalPluginProxy(string(ctx), path, targetUrl)
|
||||
proxy.Transport = dataProxyTransport
|
||||
proxy.ServeHTTP(c.RW(), c.Req.Request)
|
||||
}
|
||||
}
|
||||
|
||||
func NewExternalPluginProxy(ctx string, proxyPath string, targetUrl *url.URL) *httputil.ReverseProxy {
|
||||
director := func(req *http.Request) {
|
||||
req.URL.Scheme = targetUrl.Scheme
|
||||
req.URL.Host = targetUrl.Host
|
||||
req.Host = targetUrl.Host
|
||||
|
||||
req.URL.Path = util.JoinUrlFragments(targetUrl.Path, proxyPath)
|
||||
|
||||
// clear cookie headers
|
||||
req.Header.Del("Cookie")
|
||||
req.Header.Del("Set-Cookie")
|
||||
req.Header.Add("Grafana-Context", ctx)
|
||||
}
|
||||
|
||||
return &httputil.ReverseProxy{Director: director}
|
||||
}
|
@ -29,13 +29,6 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro
|
||||
datasources := make(map[string]interface{})
|
||||
var defaultDatasource string
|
||||
|
||||
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
|
||||
|
||||
@ -49,7 +42,7 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro
|
||||
"url": url,
|
||||
}
|
||||
|
||||
meta, exists := enabledPlugins.DataSourcePlugins[ds.Type]
|
||||
meta, exists := plugins.DataSources[ds.Type]
|
||||
if !exists {
|
||||
log.Error(3, "Could not find plugin definition for data source: %v", ds.Type)
|
||||
continue
|
||||
@ -117,7 +110,7 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro
|
||||
}
|
||||
|
||||
panels := map[string]interface{}{}
|
||||
for _, panel := range enabledPlugins.PanelPlugins {
|
||||
for _, panel := range plugins.Panels {
|
||||
panels[panel.Type] = map[string]interface{}{
|
||||
"module": panel.Module,
|
||||
"name": panel.Name,
|
||||
|
@ -2,10 +2,8 @@ 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"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
@ -60,53 +58,9 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
|
||||
Text: "Data Sources",
|
||||
Icon: "fa fa-fw fa-database",
|
||||
Href: "/datasources",
|
||||
}, &dtos.NavLink{
|
||||
Text: "Plugins",
|
||||
Icon: "fa fa-fw fa-cubes",
|
||||
Href: "/plugins",
|
||||
})
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
for _, css := range plugin.Css {
|
||||
data.PluginCss = append(data.PluginCss, &dtos.PluginCss{Light: css.Light, Dark: css.Dark})
|
||||
}
|
||||
for _, item := range plugin.MainNavLinks {
|
||||
// only show menu items for the specified roles.
|
||||
var validRoles []m.RoleType
|
||||
if string(item.ReqRole) == "" || item.ReqRole == m.ROLE_VIEWER {
|
||||
validRoles = []m.RoleType{m.ROLE_ADMIN, m.ROLE_EDITOR, m.ROLE_VIEWER}
|
||||
} else if item.ReqRole == m.ROLE_EDITOR {
|
||||
validRoles = []m.RoleType{m.ROLE_ADMIN, m.ROLE_EDITOR}
|
||||
} else if item.ReqRole == m.ROLE_ADMIN {
|
||||
validRoles = []m.RoleType{m.ROLE_ADMIN}
|
||||
}
|
||||
ok := true
|
||||
if len(validRoles) > 0 {
|
||||
ok = false
|
||||
for _, role := range validRoles {
|
||||
if role == c.OrgRole {
|
||||
ok = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if ok {
|
||||
data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{Text: item.Text, Href: item.Href, Icon: item.Icon})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &data, nil
|
||||
}
|
||||
|
||||
|
@ -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")
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
package plugins
|
||||
|
||||
import "github.com/grafana/grafana/pkg/models"
|
||||
|
||||
type DataSourcePlugin struct {
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
@ -26,60 +24,3 @@ type StaticRootConfig struct {
|
||||
Url string `json:"url"`
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
type ExternalPluginRoute struct {
|
||||
Path string `json:"path"`
|
||||
Method string `json:"method"`
|
||||
ReqSignedIn bool `json:"reqSignedIn"`
|
||||
ReqGrafanaAdmin bool `json:"reqGrafanaAdmin"`
|
||||
ReqRole models.RoleType `json:"reqRole"`
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
type ExternalPluginJs struct {
|
||||
Module string `json:"module"`
|
||||
}
|
||||
|
||||
type ExternalPluginNavLink struct {
|
||||
Text string `json:"text"`
|
||||
Icon string `json:"icon"`
|
||||
Href string `json:"href"`
|
||||
ReqRole models.RoleType `json:"reqRole"`
|
||||
}
|
||||
|
||||
type ExternalPluginCss struct {
|
||||
Light string `json:"light"`
|
||||
Dark string `json:"dark"`
|
||||
}
|
||||
|
||||
type ExternalPlugin struct {
|
||||
Type string `json:"type"`
|
||||
Routes []*ExternalPluginRoute `json:"routes"`
|
||||
Js []*ExternalPluginJs `json:"js"`
|
||||
Css []*ExternalPluginCss `json:"css"`
|
||||
MainNavLinks []*ExternalPluginNavLink `json:"mainNavLinks"`
|
||||
StaticRootConfig *StaticRootConfig `json:"staticRoot"`
|
||||
}
|
||||
|
||||
type PluginBundle struct {
|
||||
Type string `json:"type"`
|
||||
Enabled bool `json:"enabled"`
|
||||
PanelPlugins []string `json:"panelPlugins"`
|
||||
DatasourcePlugins []string `json:"datasourcePlugins"`
|
||||
ExternalPlugins []string `json:"externalPlugins"`
|
||||
Module string `json:"module"`
|
||||
}
|
||||
|
||||
type EnabledPlugins struct {
|
||||
PanelPlugins []*PanelPlugin
|
||||
DataSourcePlugins map[string]*DataSourcePlugin
|
||||
ExternalPlugins []*ExternalPlugin
|
||||
}
|
||||
|
||||
func NewEnabledPlugins() EnabledPlugins {
|
||||
return EnabledPlugins{
|
||||
PanelPlugins: make([]*PanelPlugin, 0),
|
||||
DataSourcePlugins: make(map[string]*DataSourcePlugin),
|
||||
ExternalPlugins: make([]*ExternalPlugin, 0),
|
||||
}
|
||||
}
|
||||
|
@ -9,16 +9,13 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/grafana/grafana/pkg/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
var (
|
||||
DataSources map[string]DataSourcePlugin
|
||||
Panels map[string]PanelPlugin
|
||||
ExternalPlugins map[string]ExternalPlugin
|
||||
StaticRoutes []*StaticRootConfig
|
||||
Bundles map[string]PluginBundle
|
||||
DataSources map[string]DataSourcePlugin
|
||||
Panels map[string]PanelPlugin
|
||||
StaticRoutes []*StaticRootConfig
|
||||
)
|
||||
|
||||
type PluginScanner struct {
|
||||
@ -28,37 +25,14 @@ type PluginScanner struct {
|
||||
|
||||
func Init() error {
|
||||
DataSources = make(map[string]DataSourcePlugin)
|
||||
ExternalPlugins = make(map[string]ExternalPlugin)
|
||||
StaticRoutes = make([]*StaticRootConfig, 0)
|
||||
Panels = make(map[string]PanelPlugin)
|
||||
Bundles = make(map[string]PluginBundle)
|
||||
|
||||
scan(path.Join(setting.StaticRootPath, "app/plugins"))
|
||||
checkExternalPluginPaths()
|
||||
checkDependencies()
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkDependencies() {
|
||||
for bundleType, bundle := range Bundles {
|
||||
for _, reqPanel := range bundle.PanelPlugins {
|
||||
if _, ok := Panels[reqPanel]; !ok {
|
||||
log.Fatal(4, "Bundle %s requires Panel type %s, but it is not present.", bundleType, reqPanel)
|
||||
}
|
||||
}
|
||||
for _, reqDataSource := range bundle.DatasourcePlugins {
|
||||
if _, ok := DataSources[reqDataSource]; !ok {
|
||||
log.Fatal(4, "Bundle %s requires DataSource type %s, but it is not present.", bundleType, reqDataSource)
|
||||
}
|
||||
}
|
||||
for _, reqExtPlugin := range bundle.ExternalPlugins {
|
||||
if _, ok := ExternalPlugins[reqExtPlugin]; !ok {
|
||||
log.Fatal(4, "Bundle %s requires DataSource type %s, but it is not present.", bundleType, reqExtPlugin)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func checkExternalPluginPaths() error {
|
||||
for _, section := range setting.Cfg.Sections() {
|
||||
if strings.HasPrefix(section.Name(), "plugin.") {
|
||||
@ -165,66 +139,5 @@ func (scanner *PluginScanner) loadPluginJson(pluginJsonFilePath string) error {
|
||||
addStaticRoot(p.StaticRootConfig, currentDir)
|
||||
}
|
||||
|
||||
if pluginType == "external" {
|
||||
p := ExternalPlugin{}
|
||||
reader.Seek(0, 0)
|
||||
if err := jsonParser.Decode(&p); err != nil {
|
||||
return err
|
||||
}
|
||||
if p.Type == "" {
|
||||
return errors.New("Did not find type property in plugin.json")
|
||||
}
|
||||
ExternalPlugins[p.Type] = p
|
||||
addStaticRoot(p.StaticRootConfig, currentDir)
|
||||
}
|
||||
|
||||
if pluginType == "bundle" {
|
||||
p := PluginBundle{}
|
||||
reader.Seek(0, 0)
|
||||
if err := jsonParser.Decode(&p); err != nil {
|
||||
return err
|
||||
}
|
||||
if p.Type == "" {
|
||||
return errors.New("Did not find type property in plugin.json")
|
||||
}
|
||||
Bundles[p.Type] = p
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
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 := orgBundlesMap[bundleType]; ok {
|
||||
enabled = b.Enabled
|
||||
}
|
||||
|
||||
if enabled {
|
||||
for _, d := range bundle.DatasourcePlugins {
|
||||
if ds, ok := DataSources[d]; ok {
|
||||
enabledPlugins.DataSourcePlugins[d] = &ds
|
||||
}
|
||||
}
|
||||
for _, p := range bundle.PanelPlugins {
|
||||
if panel, ok := Panels[p]; ok {
|
||||
enabledPlugins.PanelPlugins = append(enabledPlugins.PanelPlugins, &panel)
|
||||
}
|
||||
}
|
||||
for _, e := range bundle.ExternalPlugins {
|
||||
if external, ok := ExternalPlugins[e]; ok {
|
||||
enabledPlugins.ExternalPlugins = append(enabledPlugins.ExternalPlugins, &external)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return enabledPlugins
|
||||
}
|
||||
|
13
public/app/plugins/external/example/readme.md
vendored
13
public/app/plugins/external/example/readme.md
vendored
@ -1,13 +0,0 @@
|
||||
Example app is available at https://github.com/raintank/grafana-plugin-example
|
||||
|
||||
* Clone plugin repo git@github.com:raintank/grafana-plugin-example.git
|
||||
|
||||
* Modify grafana.ini (or custom.ini if your developing Grafana locally)
|
||||
|
||||
```ini
|
||||
[plugin.external-test]
|
||||
path = /<the_path_were_you_cloned_it>/grafana-plugin-example
|
||||
```
|
||||
|
||||
|
||||
|
@ -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