mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Backend plugins: Implement support for resources (#21805)
Implements initial support for resources using v0.14.0 of SDK. Ref #21512
This commit is contained in:
committed by
GitHub
parent
5345868148
commit
0390b5601e
@@ -251,6 +251,9 @@ func (hs *HTTPServer) registerRoutes() {
|
||||
apiRoute.Get("/plugins", Wrap(hs.GetPluginList))
|
||||
apiRoute.Get("/plugins/:pluginId/settings", Wrap(GetPluginSettingByID))
|
||||
apiRoute.Get("/plugins/:pluginId/markdown/:name", Wrap(GetPluginMarkdown))
|
||||
apiRoute.Get("/plugins/:pluginId/health", Wrap(hs.CheckHealth))
|
||||
apiRoute.Any("/plugins/:pluginId/resources", Wrap(hs.CallResource))
|
||||
apiRoute.Any("/plugins/:pluginId/resources/*", Wrap(hs.CallResource))
|
||||
|
||||
apiRoute.Group("/plugins", func(pluginRoute routing.RouteRegister) {
|
||||
pluginRoute.Get("/:pluginId/dashboards/", Wrap(GetPluginDashboards))
|
||||
@@ -260,6 +263,8 @@ func (hs *HTTPServer) registerRoutes() {
|
||||
apiRoute.Get("/frontend/settings/", hs.GetFrontendSettings)
|
||||
apiRoute.Any("/datasources/proxy/:id/*", reqSignedIn, hs.ProxyDataSourceRequest)
|
||||
apiRoute.Any("/datasources/proxy/:id", reqSignedIn, hs.ProxyDataSourceRequest)
|
||||
apiRoute.Any("/datasources/:id/resources", Wrap(hs.CallDatasourceResource))
|
||||
apiRoute.Any("/datasources/:id/resources/*", Wrap(hs.CallDatasourceResource))
|
||||
|
||||
// Folders
|
||||
apiRoute.Group("/folders", func(folderRoute routing.RouteRegister) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/backendplugin"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
|
||||
@@ -253,6 +254,60 @@ func GetDataSourceIdByName(c *m.ReqContext) Response {
|
||||
return JSON(200, &dtos)
|
||||
}
|
||||
|
||||
// /api/datasources/:id/resources/*
|
||||
func (hs *HTTPServer) CallDatasourceResource(c *m.ReqContext) Response {
|
||||
datasourceID := c.ParamsInt64(":id")
|
||||
ds, err := hs.DatasourceCache.GetDatasource(datasourceID, c.SignedInUser, c.SkipCache)
|
||||
if err != nil {
|
||||
if err == m.ErrDataSourceAccessDenied {
|
||||
return Error(403, "Access denied to datasource", err)
|
||||
}
|
||||
return Error(500, "Unable to load datasource meta data", err)
|
||||
}
|
||||
|
||||
// find plugin
|
||||
plugin, ok := plugins.DataSources[ds.Type]
|
||||
if !ok {
|
||||
return Error(500, "Unable to find datasource plugin", err)
|
||||
}
|
||||
|
||||
body, err := c.Req.Body().Bytes()
|
||||
if err != nil {
|
||||
return Error(500, "Failed to read request body", err)
|
||||
}
|
||||
req := backendplugin.CallResourceRequest{
|
||||
Config: backendplugin.PluginConfig{
|
||||
OrgID: c.OrgId,
|
||||
PluginID: plugin.Id,
|
||||
Instance: &backendplugin.PluginInstance{
|
||||
ID: ds.Id,
|
||||
Name: ds.Name,
|
||||
Type: ds.Type,
|
||||
URL: ds.Url,
|
||||
},
|
||||
},
|
||||
Path: c.Params("*"),
|
||||
Method: c.Req.Method,
|
||||
URL: c.Req.URL.String(),
|
||||
Headers: c.Req.Header.Clone(),
|
||||
Body: body,
|
||||
}
|
||||
resp, err := hs.BackendPluginManager.CallResource(c.Req.Context(), req)
|
||||
if err != nil {
|
||||
return Error(500, "Failed to call datasource resource", err)
|
||||
}
|
||||
|
||||
if resp.Status >= 400 {
|
||||
return Error(resp.Status, "", nil)
|
||||
}
|
||||
|
||||
return &NormalResponse{
|
||||
body: resp.Body,
|
||||
status: resp.Status,
|
||||
header: resp.Headers,
|
||||
}
|
||||
}
|
||||
|
||||
func convertModelToDtos(ds *m.DataSource) dtos.DataSource {
|
||||
dto := dtos.DataSource{
|
||||
Id: ds.Id,
|
||||
|
||||
@@ -10,6 +10,8 @@ import (
|
||||
"path"
|
||||
"sync"
|
||||
|
||||
"github.com/grafana/grafana/pkg/plugins/backendplugin"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/live"
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
httpstatic "github.com/grafana/grafana/pkg/api/static"
|
||||
@@ -57,19 +59,20 @@ type HTTPServer struct {
|
||||
streamManager *live.StreamManager
|
||||
httpSrv *http.Server
|
||||
|
||||
RouteRegister routing.RouteRegister `inject:""`
|
||||
Bus bus.Bus `inject:""`
|
||||
RenderService rendering.Service `inject:""`
|
||||
Cfg *setting.Cfg `inject:""`
|
||||
HooksService *hooks.HooksService `inject:""`
|
||||
CacheService *localcache.CacheService `inject:""`
|
||||
DatasourceCache datasources.CacheService `inject:""`
|
||||
AuthTokenService models.UserTokenService `inject:""`
|
||||
QuotaService *quota.QuotaService `inject:""`
|
||||
RemoteCacheService *remotecache.RemoteCache `inject:""`
|
||||
ProvisioningService ProvisioningService `inject:""`
|
||||
Login *login.LoginService `inject:""`
|
||||
License models.Licensing `inject:""`
|
||||
RouteRegister routing.RouteRegister `inject:""`
|
||||
Bus bus.Bus `inject:""`
|
||||
RenderService rendering.Service `inject:""`
|
||||
Cfg *setting.Cfg `inject:""`
|
||||
HooksService *hooks.HooksService `inject:""`
|
||||
CacheService *localcache.CacheService `inject:""`
|
||||
DatasourceCache datasources.CacheService `inject:""`
|
||||
AuthTokenService models.UserTokenService `inject:""`
|
||||
QuotaService *quota.QuotaService `inject:""`
|
||||
RemoteCacheService *remotecache.RemoteCache `inject:""`
|
||||
ProvisioningService ProvisioningService `inject:""`
|
||||
Login *login.LoginService `inject:""`
|
||||
License models.Licensing `inject:""`
|
||||
BackendPluginManager backendplugin.Manager `inject:""`
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) Init() error {
|
||||
|
||||
@@ -3,6 +3,8 @@ package api
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/grafana/grafana/pkg/plugins/backendplugin"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
@@ -200,3 +202,74 @@ func ImportDashboard(c *m.ReqContext, apiCmd dtos.ImportDashboardCommand) Respon
|
||||
|
||||
return JSON(200, cmd.Result)
|
||||
}
|
||||
|
||||
// /api/plugins/:pluginId/health
|
||||
func (hs *HTTPServer) CheckHealth(c *m.ReqContext) Response {
|
||||
pluginID := c.Params("pluginId")
|
||||
resp, err := hs.BackendPluginManager.CheckHealth(c.Req.Context(), pluginID)
|
||||
if err != nil {
|
||||
if err == backendplugin.ErrPluginNotRegistered {
|
||||
return Error(404, "Plugin not found", err)
|
||||
}
|
||||
|
||||
// Return status unknown instead?
|
||||
if err == backendplugin.ErrDiagnosticsNotSupported {
|
||||
return Error(404, "Health check not implemented", err)
|
||||
}
|
||||
|
||||
// Return status unknown or error instead?
|
||||
if err == backendplugin.ErrHealthCheckFailed {
|
||||
return Error(500, "Plugin health check failed", err)
|
||||
}
|
||||
}
|
||||
|
||||
payload := map[string]interface{}{
|
||||
"status": resp.Status.String(),
|
||||
"info": resp.Info,
|
||||
}
|
||||
|
||||
if resp.Status != backendplugin.HealthStatusOk {
|
||||
return JSON(503, payload)
|
||||
}
|
||||
|
||||
return JSON(200, payload)
|
||||
}
|
||||
|
||||
// /api/plugins/:pluginId/resources/*
|
||||
func (hs *HTTPServer) CallResource(c *m.ReqContext) Response {
|
||||
pluginID := c.Params("pluginId")
|
||||
_, exists := plugins.Plugins[pluginID]
|
||||
if !exists {
|
||||
return Error(404, "Plugin not found, no installed plugin with that id", nil)
|
||||
}
|
||||
|
||||
body, err := c.Req.Body().Bytes()
|
||||
if err != nil {
|
||||
return Error(500, "Failed to read request body", err)
|
||||
}
|
||||
req := backendplugin.CallResourceRequest{
|
||||
Config: backendplugin.PluginConfig{
|
||||
OrgID: c.OrgId,
|
||||
PluginID: pluginID,
|
||||
},
|
||||
Path: c.Params("*"),
|
||||
Method: c.Req.Method,
|
||||
URL: c.Req.URL.String(),
|
||||
Headers: c.Req.Header.Clone(),
|
||||
Body: body,
|
||||
}
|
||||
resp, err := hs.BackendPluginManager.CallResource(c.Req.Context(), req)
|
||||
if err != nil {
|
||||
return Error(500, "Failed to call resource", err)
|
||||
}
|
||||
|
||||
if resp.Status >= 400 {
|
||||
return Error(resp.Status, "", nil)
|
||||
}
|
||||
|
||||
return &NormalResponse{
|
||||
body: resp.Body,
|
||||
status: resp.Status,
|
||||
header: resp.Headers,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user