| 
									
										
										
										
											2023-12-15 00:33:29 +08:00
										 |  |  | package renderer | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							|  |  |  | 	"errors" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-19 17:28:23 +08:00
										 |  |  | 	"go.opentelemetry.io/otel/trace" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-15 00:33:29 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/infra/log" | 
					
						
							| 
									
										
										
										
											2024-10-11 08:30:56 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/infra/tracing" | 
					
						
							| 
									
										
										
										
											2023-12-15 00:33:29 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/plugins" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/plugins/backendplugin/pluginextensionv2" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/plugins/backendplugin/provider" | 
					
						
							| 
									
										
										
										
											2024-03-11 23:28:46 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/plugins/config" | 
					
						
							| 
									
										
										
										
											2023-12-15 00:33:29 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/plugins/envvars" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/plugins/manager/loader" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/plugins/manager/pipeline/bootstrap" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/plugins/manager/pipeline/discovery" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/plugins/manager/pipeline/initialization" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/plugins/manager/pipeline/termination" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/plugins/manager/pipeline/validation" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/plugins/manager/registry" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/plugins/manager/signature" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/plugins/manager/sources" | 
					
						
							| 
									
										
										
										
											2024-02-12 19:47:49 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/pluginsintegration/pipeline" | 
					
						
							| 
									
										
										
										
											2024-04-11 22:18:04 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginerrs" | 
					
						
							| 
									
										
										
										
											2023-12-15 00:33:29 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/rendering" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-11 23:28:46 +08:00
										 |  |  | func ProvideService(cfg *config.PluginManagementCfg, pluginEnvProvider envvars.Provider, | 
					
						
							| 
									
										
										
										
											2024-10-11 08:30:56 +08:00
										 |  |  | 	registry registry.Service, tracer tracing.Tracer) (*Manager, error) { | 
					
						
							|  |  |  | 	l, err := createLoader(cfg, pluginEnvProvider, registry, tracer) | 
					
						
							| 
									
										
										
										
											2023-12-15 00:33:29 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-18 18:06:33 +08:00
										 |  |  | 	return NewManager(cfg, l), nil | 
					
						
							| 
									
										
										
										
											2023-12-15 00:33:29 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type Manager struct { | 
					
						
							| 
									
										
										
										
											2024-03-11 23:28:46 +08:00
										 |  |  | 	cfg    *config.PluginManagementCfg | 
					
						
							| 
									
										
										
										
											2023-12-15 00:33:29 +08:00
										 |  |  | 	loader loader.Service | 
					
						
							|  |  |  | 	log    log.Logger | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	renderer *Plugin | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-11 23:28:46 +08:00
										 |  |  | func NewManager(cfg *config.PluginManagementCfg, loader loader.Service) *Manager { | 
					
						
							| 
									
										
										
										
											2024-01-18 18:06:33 +08:00
										 |  |  | 	return &Manager{ | 
					
						
							|  |  |  | 		cfg:    cfg, | 
					
						
							|  |  |  | 		loader: loader, | 
					
						
							|  |  |  | 		log:    log.New("renderer.manager"), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-15 00:33:29 +08:00
										 |  |  | type Plugin struct { | 
					
						
							|  |  |  | 	plugin *plugins.Plugin | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	started bool | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *Plugin) Client() (pluginextensionv2.RendererPlugin, error) { | 
					
						
							|  |  |  | 	if !p.started { | 
					
						
							|  |  |  | 		return nil, errors.New("renderer plugin not started") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if p.plugin.Renderer == nil { | 
					
						
							|  |  |  | 		return nil, errors.New("renderer client not available") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return p.plugin.Renderer, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *Plugin) Start(ctx context.Context) error { | 
					
						
							|  |  |  | 	p.started = true | 
					
						
							|  |  |  | 	return p.plugin.Start(ctx) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *Plugin) Version() string { | 
					
						
							| 
									
										
										
										
											2025-04-10 20:42:23 +08:00
										 |  |  | 	return p.plugin.Info.Version | 
					
						
							| 
									
										
										
										
											2023-12-15 00:33:29 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (m *Manager) Renderer(ctx context.Context) (rendering.Plugin, bool) { | 
					
						
							|  |  |  | 	if m.renderer != nil { | 
					
						
							|  |  |  | 		return m.renderer, true | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-19 17:28:23 +08:00
										 |  |  | 	srcs, err := sources.DirAsLocalSources(m.cfg, m.cfg.PluginsPath, plugins.ClassExternal) | 
					
						
							| 
									
										
										
										
											2023-12-15 00:33:29 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2024-01-18 18:06:33 +08:00
										 |  |  | 		m.log.Error("Failed to get renderer plugin sources", "error", err) | 
					
						
							| 
									
										
										
										
											2023-12-15 00:33:29 +08:00
										 |  |  | 		return nil, false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-18 18:06:33 +08:00
										 |  |  | 	for _, src := range srcs { | 
					
						
							|  |  |  | 		ps, err := m.loader.Load(ctx, src) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			m.log.Error("Failed to load renderer plugin", "error", err) | 
					
						
							|  |  |  | 			return nil, false | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if len(ps) >= 1 { | 
					
						
							|  |  |  | 			m.renderer = &Plugin{plugin: ps[0]} | 
					
						
							|  |  |  | 			return m.renderer, true | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-12-15 00:33:29 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil, false | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-11 23:28:46 +08:00
										 |  |  | func createLoader(cfg *config.PluginManagementCfg, pluginEnvProvider envvars.Provider, | 
					
						
							| 
									
										
										
										
											2024-10-11 08:30:56 +08:00
										 |  |  | 	pr registry.Service, tracer trace.Tracer) (loader.Service, error) { | 
					
						
							| 
									
										
										
										
											2024-03-11 23:28:46 +08:00
										 |  |  | 	d := discovery.New(cfg, discovery.Opts{ | 
					
						
							| 
									
										
										
										
											2025-06-19 17:28:23 +08:00
										 |  |  | 		FilterFuncs: []discovery.FilterFunc{ | 
					
						
							| 
									
										
										
										
											2023-12-15 00:33:29 +08:00
										 |  |  | 			discovery.NewPermittedPluginTypesFilterStep([]plugins.Type{plugins.TypeRenderer}), | 
					
						
							|  |  |  | 			func(ctx context.Context, class plugins.Class, bundles []*plugins.FoundBundle) ([]*plugins.FoundBundle, error) { | 
					
						
							| 
									
										
										
										
											2024-02-12 19:47:49 +08:00
										 |  |  | 				return pipeline.NewDuplicatePluginIDFilterStep(pr).Filter(ctx, bundles) | 
					
						
							| 
									
										
										
										
											2023-12-15 00:33:29 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2024-03-11 23:28:46 +08:00
										 |  |  | 	b := bootstrap.New(cfg, bootstrap.Opts{ | 
					
						
							| 
									
										
										
										
											2023-12-15 00:33:29 +08:00
										 |  |  | 		DecorateFuncs: []bootstrap.DecorateFunc{}, // no decoration required
 | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2024-03-11 23:28:46 +08:00
										 |  |  | 	v := validation.New(cfg, validation.Opts{ | 
					
						
							| 
									
										
										
										
											2023-12-15 00:33:29 +08:00
										 |  |  | 		ValidateFuncs: []validation.ValidateFunc{ | 
					
						
							| 
									
										
										
										
											2024-03-11 23:28:46 +08:00
										 |  |  | 			validation.SignatureValidationStep(signature.NewValidator(signature.NewUnsignedAuthorizer(cfg))), | 
					
						
							| 
									
										
										
										
											2023-12-15 00:33:29 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2024-03-11 23:28:46 +08:00
										 |  |  | 	i := initialization.New(cfg, initialization.Opts{ | 
					
						
							| 
									
										
										
										
											2023-12-15 00:33:29 +08:00
										 |  |  | 		InitializeFuncs: []initialization.InitializeFunc{ | 
					
						
							| 
									
										
										
										
											2024-10-11 08:30:56 +08:00
										 |  |  | 			initialization.BackendClientInitStep(pluginEnvProvider, provider.New(provider.RendererProvider), tracer), | 
					
						
							| 
									
										
										
										
											2023-12-15 00:33:29 +08:00
										 |  |  | 			initialization.PluginRegistrationStep(pr), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2024-03-11 23:28:46 +08:00
										 |  |  | 	t, err := termination.New(cfg, termination.Opts{ | 
					
						
							| 
									
										
										
										
											2023-12-15 00:33:29 +08:00
										 |  |  | 		TerminateFuncs: []termination.TerminateFunc{ | 
					
						
							|  |  |  | 			termination.DeregisterStep(pr), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-11 22:18:04 +08:00
										 |  |  | 	et := pluginerrs.ProvideErrorTracker() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-07 18:07:08 +08:00
										 |  |  | 	return loader.New(cfg, d, b, v, i, t, et), nil | 
					
						
							| 
									
										
										
										
											2023-12-15 00:33:29 +08:00
										 |  |  | } |