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() login.Init()
social.NewOAuthService() social.NewOAuthService()
pluginCloser, err := plugins.Init() pluginManager, err := plugins.NewPluginManager()
if err != nil { if err != nil {
return fmt.Errorf("Failed to start plugins. error: %v", err) 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 { if err := provisioning.Init(g.context, setting.HomePath, setting.Cfg); err != nil {
return fmt.Errorf("Failed to provision Grafana from config. error: %v", err) return fmt.Errorf("Failed to provision Grafana from config. error: %v", err)

View File

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

View File

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