Plugins: Update renderer plugin source (#80643)

* rework renderer plugin source

* add tests
This commit is contained in:
Will Browne
2024-01-18 11:06:33 +01:00
committed by GitHub
parent 4b113f87f9
commit 3885497553
10 changed files with 233 additions and 41 deletions
@@ -2,6 +2,10 @@ package sources
import (
"context"
"errors"
"os"
"path/filepath"
"slices"
"github.com/grafana/grafana/pkg/plugins"
)
@@ -36,3 +40,31 @@ func (s *LocalSource) DefaultSignature(_ context.Context) (plugins.Signature, bo
return plugins.Signature{}, false
}
}
func DirAsLocalSources(pluginsPath string, class plugins.Class) ([]*LocalSource, error) {
if pluginsPath == "" {
return []*LocalSource{}, errors.New("plugins path not configured")
}
// 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 {
return []*LocalSource{}, errors.New("failed to open plugins path")
}
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)
var sources []*LocalSource
for _, dir := range pluginDirs {
sources = append(sources, NewLocalSource(class, []string{dir}))
}
return sources, nil
}
@@ -0,0 +1,71 @@
package sources
import (
"errors"
"path/filepath"
"testing"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/plugins"
)
func TestDirAsLocalSources(t *testing.T) {
testdataDir := "../testdata"
tests := []struct {
name string
pluginsPath string
expected []*LocalSource
err error
}{
{
name: "Empty path returns an error",
pluginsPath: "",
expected: []*LocalSource{},
err: errors.New("plugins path not configured"),
},
{
name: "Directory with subdirectories",
pluginsPath: filepath.Join(testdataDir, "pluginRootWithDist"),
expected: []*LocalSource{
{
paths: []string{filepath.Join(testdataDir, "pluginRootWithDist", "datasource")},
class: plugins.ClassExternal,
},
{
paths: []string{filepath.Join(testdataDir, "pluginRootWithDist", "dist")},
class: plugins.ClassExternal,
},
{
paths: []string{filepath.Join(testdataDir, "pluginRootWithDist", "panel")},
class: plugins.ClassExternal,
},
},
},
{
name: "Directory with no subdirectories",
pluginsPath: filepath.Join(testdataDir, "pluginRootWithDist", "datasource"),
expected: nil,
},
{
name: "Directory with a symlink to a directory",
pluginsPath: filepath.Join(testdataDir, "symbolic-plugin-dirs"),
expected: []*LocalSource{
{
paths: []string{filepath.Join(testdataDir, "symbolic-plugin-dirs", "plugin")},
class: plugins.ClassExternal,
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := DirAsLocalSources(tt.pluginsPath, plugins.ClassExternal)
if tt.err != nil {
require.Errorf(t, err, tt.err.Error())
}
require.Equal(t, tt.expected, got)
})
}
}
+7 -25
View File
@@ -2,9 +2,7 @@ package sources
import (
"context"
"os"
"path/filepath"
"slices"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/log"
@@ -34,33 +32,17 @@ func (s *Service) List(_ context.Context) []plugins.PluginSource {
}
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)
localSrcs, err := DirAsLocalSources(s.cfg.PluginsPath, plugins.ClassExternal)
if err != nil {
s.log.Error("Failed to open plugins path", "path", pluginsPath, "error", err)
return sources
s.log.Error("Failed to load external plugins", "error", err)
return []plugins.PluginSource{}
}
var pluginDirs []string
for _, dir := range d {
if dir.IsDir() || dir.Type()&os.ModeSymlink == os.ModeSymlink {
pluginDirs = append(pluginDirs, filepath.Join(pluginsPath, dir.Name()))
}
var srcs []plugins.PluginSource
for _, src := range localSrcs {
srcs = append(srcs, src)
}
slices.Sort(pluginDirs)
for _, dir := range pluginDirs {
sources = append(sources, NewLocalSource(plugins.ClassExternal, []string{dir}))
}
return sources
return srcs
}
func (s *Service) pluginSettingSources() []plugins.PluginSource {