mirror of
https://github.com/grafana/grafana.git
synced 2025-08-01 01:51:49 +08:00

* Plugins: Loader: Fix symlinks not followed when loading external plugins * Add test case
84 lines
2.2 KiB
Go
84 lines
2.2 KiB
Go
package sources
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"slices"
|
|
|
|
"github.com/grafana/grafana/pkg/plugins"
|
|
"github.com/grafana/grafana/pkg/plugins/log"
|
|
"github.com/grafana/grafana/pkg/setting"
|
|
)
|
|
|
|
type Service struct {
|
|
cfg *setting.Cfg
|
|
log log.Logger
|
|
}
|
|
|
|
func ProvideService(cfg *setting.Cfg) *Service {
|
|
return &Service{
|
|
cfg: cfg,
|
|
log: log.New("plugin.sources"),
|
|
}
|
|
}
|
|
|
|
func (s *Service) List(_ context.Context) []plugins.PluginSource {
|
|
r := []plugins.PluginSource{
|
|
NewLocalSource(plugins.ClassCore, corePluginPaths(s.cfg.StaticRootPath)),
|
|
NewLocalSource(plugins.ClassBundled, []string{s.cfg.BundledPluginsPath}),
|
|
}
|
|
r = append(r, s.externalPluginSources()...)
|
|
r = append(r, s.pluginSettingSources()...)
|
|
return r
|
|
}
|
|
|
|
func (s *Service) externalPluginSources() []plugins.PluginSource {
|
|
var sources []plugins.PluginSource
|
|
if s.cfg.PluginsPath == "" {
|
|
return sources
|
|
}
|
|
|
|
pluginsPath := s.cfg.PluginsPath
|
|
// It's safe to ignore gosec warning G304 since the variable part of the file path comes from a configuration
|
|
// variable.
|
|
// nolint:gosec
|
|
d, err := os.ReadDir(pluginsPath)
|
|
if err != nil {
|
|
s.log.Error("Failed to open plugins path", "path", pluginsPath, "error", err)
|
|
return sources
|
|
}
|
|
|
|
var pluginDirs []string
|
|
for _, dir := range d {
|
|
if dir.IsDir() || dir.Type()&os.ModeSymlink == os.ModeSymlink {
|
|
pluginDirs = append(pluginDirs, filepath.Join(pluginsPath, dir.Name()))
|
|
}
|
|
}
|
|
slices.Sort(pluginDirs)
|
|
|
|
for _, dir := range pluginDirs {
|
|
sources = append(sources, NewLocalSource(plugins.ClassExternal, []string{dir}))
|
|
}
|
|
return sources
|
|
}
|
|
|
|
func (s *Service) pluginSettingSources() []plugins.PluginSource {
|
|
var sources []plugins.PluginSource
|
|
for _, ps := range s.cfg.PluginSettings {
|
|
path, exists := ps["path"]
|
|
if !exists || path == "" {
|
|
continue
|
|
}
|
|
sources = append(sources, NewLocalSource(plugins.ClassExternal, []string{path}))
|
|
}
|
|
return sources
|
|
}
|
|
|
|
// corePluginPaths provides a list of the Core plugin file system paths
|
|
func corePluginPaths(staticRootPath string) []string {
|
|
datasourcePaths := filepath.Join(staticRootPath, "app/plugins/datasource")
|
|
panelsPath := filepath.Join(staticRootPath, "app/plugins/panel")
|
|
return []string{datasourcePaths, panelsPath}
|
|
}
|