mirror of
https://github.com/grafana/grafana.git
synced 2025-07-29 11:22:21 +08:00
Plugins: Add Plugin FS abstraction (#63734)
* unexport pluginDir from dto * first pass * tidy * naming + add mutex * add dupe checking * fix func typo * interface + move logic from renderer * remote finder * remote signing * fix tests * tidy up * tidy markdown logic * split changes * fix tests * slim interface down * fix status code * tidy exec path func * fixup * undo changes * remove unused func * remove unused func * fix goimports * fetch remotely * simultaneous support * fix linter * use var * add exception for gosec warning * fixup * fix tests * tidy * rework cfg pattern * simplify * PR feedback * fix dupe field * remove g304 nolint * apply PR feedback * remove unnecessary gosec nolint * fix finder loop and update comment * fix map alloc * fix test * remove commented code
This commit is contained in:
@ -6,8 +6,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"path"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
@ -26,8 +25,8 @@ var ErrFileNotExist = errors.New("file does not exist")
|
||||
type Plugin struct {
|
||||
JSONData
|
||||
|
||||
PluginDir string
|
||||
Class Class
|
||||
FS FS
|
||||
Class Class
|
||||
|
||||
// App fields
|
||||
IncludedInAppID string
|
||||
@ -55,8 +54,8 @@ type Plugin struct {
|
||||
type PluginDTO struct {
|
||||
JSONData
|
||||
|
||||
fs FS
|
||||
logger log.Logger
|
||||
pluginDir string
|
||||
supportsStreaming bool
|
||||
|
||||
Class Class
|
||||
@ -81,6 +80,10 @@ func (p PluginDTO) SupportsStreaming() bool {
|
||||
return p.supportsStreaming
|
||||
}
|
||||
|
||||
func (p PluginDTO) Base() string {
|
||||
return p.fs.Base()
|
||||
}
|
||||
|
||||
func (p PluginDTO) IsApp() bool {
|
||||
return p.Type == App
|
||||
}
|
||||
@ -96,21 +99,15 @@ func (p PluginDTO) File(name string) (fs.File, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
absPluginDir, err := filepath.Abs(p.pluginDir)
|
||||
if p.fs == nil {
|
||||
return nil, ErrFileNotExist
|
||||
}
|
||||
|
||||
f, err := p.fs.Open(cleanPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
absFilePath := filepath.Join(absPluginDir, cleanPath)
|
||||
// Wrapping in filepath.Clean to properly handle
|
||||
// gosec G304 Potential file inclusion via variable rule.
|
||||
f, err := os.Open(filepath.Clean(absFilePath))
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, ErrFileNotExist
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
@ -337,6 +334,18 @@ func (p *Plugin) Client() (PluginClient, bool) {
|
||||
}
|
||||
|
||||
func (p *Plugin) ExecutablePath() string {
|
||||
if p.IsRenderer() {
|
||||
return p.executablePath("plugin_start")
|
||||
}
|
||||
|
||||
if p.IsSecretsManager() {
|
||||
return p.executablePath("secrets_plugin_start")
|
||||
}
|
||||
|
||||
return p.executablePath(p.Executable)
|
||||
}
|
||||
|
||||
func (p *Plugin) executablePath(f string) string {
|
||||
os := strings.ToLower(runtime.GOOS)
|
||||
arch := runtime.GOARCH
|
||||
extension := ""
|
||||
@ -344,15 +353,7 @@ func (p *Plugin) ExecutablePath() string {
|
||||
if os == "windows" {
|
||||
extension = ".exe"
|
||||
}
|
||||
if p.IsRenderer() {
|
||||
return filepath.Join(p.PluginDir, fmt.Sprintf("%s_%s_%s%s", "plugin_start", os, strings.ToLower(arch), extension))
|
||||
}
|
||||
|
||||
if p.IsSecretsManager() {
|
||||
return filepath.Join(p.PluginDir, fmt.Sprintf("%s_%s_%s%s", "secrets_plugin_start", os, strings.ToLower(arch), extension))
|
||||
}
|
||||
|
||||
return filepath.Join(p.PluginDir, fmt.Sprintf("%s_%s_%s%s", p.Executable, os, strings.ToLower(arch), extension))
|
||||
return path.Join(p.FS.Base(), fmt.Sprintf("%s_%s_%s%s", f, os, strings.ToLower(arch), extension))
|
||||
}
|
||||
|
||||
type PluginClient interface {
|
||||
@ -366,9 +367,10 @@ type PluginClient interface {
|
||||
func (p *Plugin) ToDTO() PluginDTO {
|
||||
return PluginDTO{
|
||||
logger: p.Logger(),
|
||||
pluginDir: p.PluginDir,
|
||||
JSONData: p.JSONData,
|
||||
fs: p.FS,
|
||||
supportsStreaming: p.client != nil && p.client.(backend.StreamHandler) != nil,
|
||||
Class: p.Class,
|
||||
JSONData: p.JSONData,
|
||||
IncludedInAppID: p.IncludedInAppID,
|
||||
DefaultNavURL: p.DefaultNavURL,
|
||||
Pinned: p.Pinned,
|
||||
@ -378,7 +380,6 @@ func (p *Plugin) ToDTO() PluginDTO {
|
||||
SignatureError: p.SignatureError,
|
||||
Module: p.Module,
|
||||
BaseURL: p.BaseURL,
|
||||
supportsStreaming: p.client != nil && p.client.(backend.StreamHandler) != nil,
|
||||
}
|
||||
}
|
||||
|
||||
@ -387,7 +388,11 @@ func (p *Plugin) StaticRoute() *StaticRoute {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &StaticRoute{Directory: p.PluginDir, PluginID: p.ID}
|
||||
if p.FS == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &StaticRoute{Directory: p.FS.Base(), PluginID: p.ID}
|
||||
}
|
||||
|
||||
func (p *Plugin) IsRenderer() bool {
|
||||
@ -414,15 +419,6 @@ func (p *Plugin) IsExternalPlugin() bool {
|
||||
return p.Class == External
|
||||
}
|
||||
|
||||
func (p *Plugin) Manifest() []byte {
|
||||
d, err := os.ReadFile(filepath.Join(p.PluginDir, "MANIFEST.txt"))
|
||||
if err != nil {
|
||||
return []byte{}
|
||||
}
|
||||
|
||||
return d
|
||||
}
|
||||
|
||||
type Class string
|
||||
|
||||
const (
|
||||
|
Reference in New Issue
Block a user