backend plugins: manage plugins lifecycle with context

This commit is contained in:
bergquist 2017-12-11 15:05:06 +01:00
parent 1af4f7a1b4
commit 411e8a16c2
3 changed files with 37 additions and 30 deletions

View File

@ -63,11 +63,11 @@ func (g *GrafanaServerImpl) Start() error {
login.Init()
social.NewOAuthService()
pluginCloser, err := plugins.Init()
pluginManager, err := plugins.NewPluginManager()
if err != nil {
return fmt.Errorf("Failed to start plugins. error: %v", err)
}
defer pluginCloser()
g.childRoutines.Go(func() error { return pluginManager.Run(g.context) })
if err := provisioning.Init(g.context, setting.HomePath, setting.Cfg); err != nil {
return fmt.Errorf("Failed to provision Grafana from config. error: %v", err)

View File

@ -20,19 +20,12 @@ type BackendDatasource struct {
*PluginBase
Executable string
log log.Logger
client *plugin.Client
}
type Killable interface {
Kill()
}
type NoopKiller struct{}
func (nk NoopKiller) Kill() {}
func (p *BackendDatasource) initBackendPlugin() (Killable, error) {
logger := log.New("grafana.plugins")
func (p *BackendDatasource) initBackendPlugin(log log.Logger) error {
p.log = log.New("plugin-id", p.Id)
p.client = plugin.NewClient(&plugin.ClientConfig{
HandshakeConfig: plugin.HandshakeConfig{
@ -43,33 +36,33 @@ func (p *BackendDatasource) initBackendPlugin() (Killable, error) {
Plugins: map[string]plugin.Plugin{p.Id: &shared.TsdbPluginImpl{}},
Cmd: exec.Command("sh", "-c", path.Join(p.PluginDir, p.Executable)),
AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC},
Logger: backend.LogWrapper{Logger: logger},
Logger: backend.LogWrapper{Logger: p.log},
})
rpcClient, err := p.client.Client()
if err != nil {
return NoopKiller{}, err
return err
}
raw, err := rpcClient.Dispense(p.Id)
if err != nil {
return NoopKiller{}, err
return err
}
plugin := raw.(shared.TsdbPlugin)
response, err := plugin.Query(context.Background(), &proto.TsdbQuery{})
if err != nil {
logger.Error("Response from plugin. ", "response", response)
p.log.Error("Response from plugin. ", "response", response)
} else {
logger.Info("Response from plugin. ", "response", response)
p.log.Info("Response from plugin. ", "response", response)
}
tsdb.RegisterTsdbQueryEndpoint(p.Id, func(dsInfo *models.DataSource) (tsdb.TsdbQueryEndpoint, error) {
return &shared.TsdbWrapper{TsdbPlugin: plugin}, nil
})
return p.client, nil
return nil
}
func (p *BackendDatasource) Kill() {

View File

@ -1,6 +1,7 @@
package plugins
import (
"context"
"encoding/json"
"errors"
"fmt"
@ -37,7 +38,29 @@ type PluginScanner struct {
type Dispose func()
func Init() (Dispose, error) {
type PluginManager struct {
log log.Logger
}
func NewPluginManager() (*PluginManager, error) {
Init()
return &PluginManager{
log: log.New("plugins"),
}, nil
}
func (p *PluginManager) Run(ctx context.Context) error {
<-ctx.Done()
for _, p := range BackendDatasources {
p.Kill()
}
p.log.Info("Stopped Plugins", "error", ctx.Err())
return ctx.Err()
}
func Init() error {
plog = log.New("plugins")
DataSources = make(map[string]*DataSourcePlugin)
@ -82,26 +105,17 @@ func Init() (Dispose, error) {
app.initApp()
}
killers := []Killable{}
for _, be := range BackendDatasources {
killable, err := be.initBackendPlugin()
err := be.initBackendPlugin(plog)
if err != nil {
plog.Error("failed to init plugin", "id", be.Id, "error", err)
} else {
killers = append(killers, killable)
}
}
go StartPluginUpdateChecker()
go updateAppDashboards()
return dispose, nil
}
func dispose() {
for _, p := range BackendDatasources {
p.Kill()
}
return nil
}
func checkPluginPaths() error {