Files
grafana/pkg/plugins/manager/pipeline/termination/steps.go
T
Will Browne 60b4a0b2a4 Plugins: Add termination stage to plugin loader pipeline (#72822)
* add termination stage

* uid -> pluginID (for now)

* also fix fakes

* add simple test

* Fix logger name

Co-authored-by: Giuseppe Guerra <giuseppe.guerra@grafana.com>

* inline stop func call

Co-authored-by: Giuseppe Guerra <giuseppe.guerra@grafana.com>

---------

Co-authored-by: Giuseppe Guerra <giuseppe.guerra@grafana.com>
2023-08-04 11:57:49 +02:00

108 lines
3.4 KiB
Go

package termination
import (
"context"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/log"
"github.com/grafana/grafana/pkg/plugins/manager/process"
"github.com/grafana/grafana/pkg/plugins/manager/registry"
)
// TerminablePluginResolver implements a ResolveFunc for resolving a plugin that can be terminated.
type TerminablePluginResolver struct {
pluginRegistry registry.Service
log log.Logger
}
// TerminablePluginResolverStep returns a new ResolveFunc for resolving a plugin that can be terminated.
func TerminablePluginResolverStep(pluginRegistry registry.Service) ResolveFunc {
return newTerminablePluginResolver(pluginRegistry).Resolve
}
func newTerminablePluginResolver(pluginRegistry registry.Service) *TerminablePluginResolver {
return &TerminablePluginResolver{
pluginRegistry: pluginRegistry,
log: log.New("plugins.resolver"),
}
}
// Resolve returns a plugin that can be terminated.
func (r *TerminablePluginResolver) Resolve(ctx context.Context, pluginID string) (*plugins.Plugin, error) {
p, exists := r.pluginRegistry.Plugin(ctx, pluginID)
if !exists {
return nil, plugins.ErrPluginNotInstalled
}
// core plugins and bundled plugins cannot be terminated
if p.IsCorePlugin() || p.IsBundledPlugin() {
return nil, plugins.ErrUninstallCorePlugin
}
return p, nil
}
// BackendProcessTerminator implements a TerminateFunc for stopping a backend plugin process.
//
// It uses the process.Service to stop the backend plugin process.
type BackendProcessTerminator struct {
processManager process.Service
log log.Logger
}
// BackendProcessTerminatorStep returns a new TerminateFunc for stopping a backend plugin process.
func BackendProcessTerminatorStep(processManager process.Service) TerminateFunc {
return newBackendProcessTerminator(processManager).Terminate
}
func newBackendProcessTerminator(processManager process.Service) *BackendProcessTerminator {
return &BackendProcessTerminator{
processManager: processManager,
log: log.New("plugins.backend.termination"),
}
}
// Terminate stops a backend plugin process.
func (t *BackendProcessTerminator) Terminate(ctx context.Context, p *plugins.Plugin) error {
t.log.Debug("Stopping plugin process", "pluginId", p.ID)
return t.processManager.Stop(ctx, p.ID)
}
// Deregister implements a TerminateFunc for removing a plugin from the plugin registry.
type Deregister struct {
pluginRegistry registry.Service
log log.Logger
}
// DeregisterStep returns a new TerminateFunc for removing a plugin from the plugin registry.
func DeregisterStep(pluginRegistry registry.Service) TerminateFunc {
return newDeregister(pluginRegistry).Deregister
}
func newDeregister(pluginRegistry registry.Service) *Deregister {
return &Deregister{
pluginRegistry: pluginRegistry,
log: log.New("plugins.deregister"),
}
}
// Deregister removes a plugin from the plugin registry.
func (d *Deregister) Deregister(ctx context.Context, p *plugins.Plugin) error {
if err := d.pluginRegistry.Remove(ctx, p.ID); err != nil {
return err
}
d.log.Debug("Plugin unregistered", "pluginId", p.ID)
return nil
}
// FSRemoval implements a TerminateFunc for removing plugin files from the filesystem.
func FSRemoval(_ context.Context, p *plugins.Plugin) error {
if remover, ok := p.FS.(plugins.FSRemover); ok {
if err := remover.Remove(); err != nil {
return err
}
}
return nil
}