-
Notifications
You must be signed in to change notification settings - Fork 65
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Alternatives for serving plugin #99
Changes from all commits
c1d1fd6
05a17f2
57a3311
613aa44
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package datasource | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/grafana/grafana-plugin-sdk-go/backend" | ||
) | ||
|
||
// CheckDataSourceHealthRequest contains the healthcheck request | ||
type CheckDataSourceHealthRequest struct { | ||
pluginConfig backend.PluginConfig | ||
OrgID int64 | ||
DataSourceConfig backend.DataSourceConfig | ||
} | ||
|
||
// CheckDataSourceHealthHandler enables users to send health check | ||
// requests to a data source plugin. | ||
type CheckDataSourceHealthHandler interface { | ||
CheckDataSourceHealth(ctx context.Context, req *CheckDataSourceHealthRequest) (*backend.CheckHealthResult, error) | ||
} | ||
|
||
type CheckDataSourceHealthHandlerFunc func(ctx context.Context, req *CheckDataSourceHealthRequest) (*backend.CheckHealthResult, error) | ||
|
||
func (fn CheckDataSourceHealthHandlerFunc) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) { | ||
return fn(ctx, &CheckDataSourceHealthRequest{ | ||
pluginConfig: req.PluginConfig, | ||
OrgID: req.PluginConfig.OrgID, | ||
DataSourceConfig: *(req.PluginConfig.DataSourceConfig), | ||
}) | ||
} | ||
|
||
type CallDataSourceResourceRequest struct { | ||
pluginConfig backend.PluginConfig | ||
OrgID int64 | ||
DataSourceConfig backend.DataSourceConfig | ||
Comment on lines
+34
to
+35
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Only OrgID and DataSourceConfig exposed here compared to regular Helps not confusing plugin developer to use PluginConfig (currently only app plugins) when should be using DataSourceConfig. |
||
Path string | ||
Method string | ||
URL string | ||
Headers map[string][]string | ||
Body []byte | ||
User *backend.User | ||
} | ||
|
||
// CallDataSourceResourceHandler handles resource calls. | ||
type CallDataSourceResourceHandler interface { | ||
CallDataSourceResource(ctx context.Context, req *CallDataSourceResourceRequest, sender backend.CallResourceResponseSender) error | ||
} | ||
|
||
type CallDataSourceResourceHandlerFunc func(ctx context.Context, req *CallDataSourceResourceRequest, sender backend.CallResourceResponseSender) error | ||
|
||
func (fn CallDataSourceResourceHandlerFunc) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error { | ||
return fn(ctx, &CallDataSourceResourceRequest{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not super found of this mapping back and forth, but removes the need of implementing yet another interface in resource and httpadapter packages. |
||
pluginConfig: req.PluginConfig, | ||
OrgID: req.PluginConfig.OrgID, | ||
DataSourceConfig: *(req.PluginConfig.DataSourceConfig), | ||
User: req.User, | ||
Path: req.Path, | ||
URL: req.URL, | ||
Method: req.Method, | ||
Headers: req.Headers, | ||
Body: req.Body, | ||
}, sender) | ||
} | ||
|
||
func NewCheckDataSourceHealthHandlerFunc(h backend.CheckHealthHandler) CheckDataSourceHealthHandlerFunc { | ||
return func(ctx context.Context, req *CheckDataSourceHealthRequest) (*backend.CheckHealthResult, error) { | ||
return h.CheckHealth(ctx, &backend.CheckHealthRequest{ | ||
PluginConfig: req.pluginConfig, | ||
}) | ||
} | ||
} | ||
|
||
func NewCallDataSourceResourceHandlerFunc(h backend.CallResourceHandler) CallDataSourceResourceHandlerFunc { | ||
return func(ctx context.Context, req *CallDataSourceResourceRequest, sender backend.CallResourceResponseSender) error { | ||
return h.CallResource(ctx, &backend.CallResourceRequest{ | ||
PluginConfig: req.pluginConfig, | ||
User: req.User, | ||
Path: req.Path, | ||
URL: req.URL, | ||
Method: req.Method, | ||
Headers: req.Headers, | ||
Body: req.Body, | ||
}, sender) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package datasource | ||
|
||
import ( | ||
"github.com/grafana/grafana-plugin-sdk-go/backend" | ||
"github.com/grafana/grafana-plugin-sdk-go/backend/log" | ||
) | ||
|
||
type Plugin interface { | ||
CheckDataSourceHealthHandler | ||
CallDataSourceResourceHandler | ||
backend.QueryDataHandler | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To be correct, this one should probably have a new interface in this package as well to only include DataSourceConfig in request and not PluginConfig. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could be an interface similar to https://github.com/grafana/grafana/blob/master/pkg/tsdb/query_endpoint.go#L11, basically using similar |
||
} | ||
|
||
type PluginFactoryFunc func(logger log.Logger, c backend.ConfigurePlugin) Plugin | ||
|
||
func Serve(fn PluginFactoryFunc) { | ||
backend.Serve(func(logger log.Logger, c backend.ConfigurePlugin) backend.ServeOpts { | ||
ds := fn(logger, c) | ||
return backend.ServeOpts{ | ||
CheckHealthHandler: CheckDataSourceHealthHandlerFunc(ds.CheckDataSourceHealth), | ||
CallResourceHandler: CallDataSourceResourceHandlerFunc(ds.CallDataSourceResource), | ||
QueryDataHandler: ds, | ||
} | ||
}) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
// Package diagnostics provides support for handling health checks. | ||
package diagnostics |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package diagnostics | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/grafana/grafana-plugin-sdk-go/backend" | ||
) | ||
|
||
type okHandler struct { | ||
} | ||
|
||
func (h *okHandler) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) { | ||
return &backend.CheckHealthResult{ | ||
Status: backend.HealthStatusOk, | ||
}, nil | ||
} | ||
|
||
// OKCheckHealthHandler check health handler that returns backend.HealthStatusOk status. | ||
func OKCheckHealthHandler() backend.CheckHealthHandler { | ||
return &okHandler{} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
// Package resource provides support for handling resource calls. | ||
package resource |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package resource | ||
|
||
import ( | ||
"context" | ||
"net/http" | ||
|
||
"github.com/grafana/grafana-plugin-sdk-go/backend" | ||
) | ||
|
||
type notFoundHandler struct { | ||
} | ||
|
||
func (h *notFoundHandler) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error { | ||
return sender.Send(&backend.CallResourceResponse{ | ||
Status: http.StatusNotFound, | ||
}) | ||
} | ||
|
||
// NotFoundHandler call resource handler that returns HTTP 404 status code. | ||
func NotFoundHandler() backend.CallResourceHandler { | ||
return ¬FoundHandler{} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ package backend | |
|
||
import ( | ||
"github.com/grafana/grafana-plugin-sdk-go/backend/grpcplugin" | ||
"github.com/grafana/grafana-plugin-sdk-go/backend/log" | ||
"github.com/prometheus/client_golang/prometheus" | ||
) | ||
|
||
|
@@ -13,8 +14,20 @@ type ServeOpts struct { | |
TransformDataHandler TransformDataHandler | ||
} | ||
|
||
type ConfigurePlugin struct { | ||
Metrics prometheus.Registerer | ||
} | ||
|
||
type ServePluginFunc func(logger log.Logger, c ConfigurePlugin) ServeOpts | ||
|
||
// Serve starts serving the plugin over gRPC. | ||
func Serve(opts ServeOpts) error { | ||
func Serve(fn ServePluginFunc) { | ||
logger := log.New() | ||
c := ConfigurePlugin{ | ||
Metrics: prometheus.DefaultRegisterer, | ||
} | ||
opts := fn(logger, c) | ||
|
||
pluginOpts := grpcplugin.ServeOpts{ | ||
DiagnosticsServer: newDiagnosticsSDKAdapter(prometheus.DefaultGatherer, opts.CheckHealthHandler), | ||
} | ||
|
@@ -31,5 +44,99 @@ func Serve(opts ServeOpts) error { | |
pluginOpts.TransformServer = newTransformSDKAdapter(opts.TransformDataHandler) | ||
} | ||
|
||
return grpcplugin.Serve(pluginOpts) | ||
grpcplugin.Serve(pluginOpts) | ||
} | ||
|
||
type Plugin interface { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comments please for these exported interfaces and the types that Follow There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah good point, but still a draft. So only consider the concept/examples |
||
CheckHealthHandler | ||
CallResourceHandler | ||
} | ||
|
||
type DataSourcePlugin interface { | ||
Plugin | ||
QueryDataHandler | ||
} | ||
|
||
type TransformPlugin interface { | ||
TransformDataHandler | ||
} | ||
|
||
type PluginFactoryFunc func(logger log.Logger, c ConfigurePlugin) Plugin | ||
type DataSourcePluginFactoryFunc func(logger log.Logger, c ConfigurePlugin) DataSourcePlugin | ||
type TransformPluginFactoryFunc func(logger log.Logger, c ConfigurePlugin) TransformPlugin | ||
|
||
//ServePluginOpts options for serving plugins. | ||
type ServePluginOpts struct { | ||
PluginProvider PluginFactoryFunc | ||
DataSourcePluginProvider DataSourcePluginFactoryFunc | ||
TransformPluginProvider TransformPluginFactoryFunc | ||
} | ||
|
||
func ServePluginExample(opts ServePluginOpts) { | ||
logger := log.New() | ||
c := ConfigurePlugin{ | ||
Metrics: prometheus.DefaultRegisterer, | ||
} | ||
|
||
if opts.PluginProvider != nil { | ||
p := opts.PluginProvider(logger, c) | ||
grpcplugin.Serve(grpcplugin.ServeOpts{ | ||
DiagnosticsServer: newDiagnosticsSDKAdapter(prometheus.DefaultGatherer, p), | ||
ResourceServer: newResourceSDKAdapter(p), | ||
}) | ||
return | ||
} | ||
|
||
if opts.DataSourcePluginProvider != nil { | ||
p := opts.DataSourcePluginProvider(logger, c) | ||
grpcplugin.Serve(grpcplugin.ServeOpts{ | ||
DiagnosticsServer: newDiagnosticsSDKAdapter(prometheus.DefaultGatherer, p), | ||
ResourceServer: newResourceSDKAdapter(p), | ||
DataServer: newDataSDKAdapter(p), | ||
}) | ||
return | ||
} | ||
|
||
if opts.TransformPluginProvider != nil { | ||
p := opts.TransformPluginProvider(logger, c) | ||
grpcplugin.Serve(grpcplugin.ServeOpts{ | ||
TransformServer: newTransformSDKAdapter(p), | ||
}) | ||
return | ||
} | ||
|
||
panic("invalid arguments for serve plugin") | ||
} | ||
|
||
// ServePlugin starts serving the plugin over gRPC. | ||
func ServePlugin(factory PluginFactoryFunc) { | ||
if factory == nil { | ||
panic("factory func cannot be nil") | ||
} | ||
|
||
ServePluginExample(ServePluginOpts{ | ||
PluginProvider: factory, | ||
}) | ||
} | ||
|
||
// ServeDataSourcePlugin starts serving the data source plugin over gRPC. | ||
func ServeDataSourcePlugin(factory DataSourcePluginFactoryFunc) { | ||
if factory == nil { | ||
panic("factory func cannot be nil") | ||
} | ||
|
||
ServePluginExample(ServePluginOpts{ | ||
DataSourcePluginProvider: factory, | ||
}) | ||
} | ||
|
||
// ServeTransformPlugin starts serving the plugin over gRPC. | ||
func ServeTransformPlugin(factory TransformPluginFactoryFunc) { | ||
if factory == nil { | ||
panic("factory func cannot be nil") | ||
} | ||
|
||
ServePluginExample(ServePluginOpts{ | ||
TransformPluginProvider: factory, | ||
}) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Package datasource ....