mirror of
https://github.com/grafana/grafana.git
synced 2025-08-02 08:12:08 +08:00
Return plugin error when requesting settings (#86052)
This commit is contained in:

committed by
GitHub

parent
8373fc3544
commit
eac02a61e1
@ -173,6 +173,11 @@ func (hs *HTTPServer) GetPluginList(c *contextmodel.ReqContext) response.Respons
|
||||
func (hs *HTTPServer) GetPluginSettingByID(c *contextmodel.ReqContext) response.Response {
|
||||
pluginID := web.Params(c.Req)[":pluginId"]
|
||||
|
||||
perr := hs.pluginErrorResolver.PluginError(c.Req.Context(), pluginID)
|
||||
if perr != nil {
|
||||
return response.Error(http.StatusInternalServerError, perr.PublicMessage(), perr)
|
||||
}
|
||||
|
||||
plugin, exists := hs.pluginStore.Plugin(c.Req.Context(), pluginID)
|
||||
if !exists {
|
||||
return response.Error(http.StatusNotFound, "Plugin not found, no installed plugin with that id", nil)
|
||||
|
@ -38,6 +38,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/org/orgtest"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginaccesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginerrs"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
|
||||
"github.com/grafana/grafana/pkg/services/updatechecker"
|
||||
@ -764,3 +765,88 @@ func TestHTTPServer_hasPluginRequestedPermissions(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_PluginsSettings(t *testing.T) {
|
||||
pID := "test-datasource"
|
||||
p1 := createPlugin(plugins.JSONData{
|
||||
ID: pID, Type: "datasource", Name: pID,
|
||||
Info: plugins.Info{
|
||||
Version: "1.0.0",
|
||||
}}, plugins.ClassExternal, plugins.NewFakeFS())
|
||||
|
||||
pluginRegistry := &fakes.FakePluginRegistry{
|
||||
Store: map[string]*plugins.Plugin{
|
||||
p1.ID: p1,
|
||||
},
|
||||
}
|
||||
|
||||
pluginSettings := pluginsettings.FakePluginSettings{Plugins: map[string]*pluginsettings.DTO{
|
||||
pID: {ID: 0, OrgID: 1, PluginID: pID, PluginVersion: "1.0.0"},
|
||||
}}
|
||||
|
||||
type testCase struct {
|
||||
desc string
|
||||
expectedCode int
|
||||
errCode plugins.ErrorCode
|
||||
expectedSettings dtos.PluginSetting
|
||||
expectedError string
|
||||
}
|
||||
tcs := []testCase{
|
||||
{
|
||||
desc: "should only be able to get plugin settings",
|
||||
expectedCode: http.StatusOK,
|
||||
expectedSettings: dtos.PluginSetting{
|
||||
Id: pID,
|
||||
Name: pID,
|
||||
Type: "datasource",
|
||||
Info: plugins.Info{
|
||||
Version: "1.0.0",
|
||||
},
|
||||
SecureJsonFields: map[string]bool{},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "should return a plugin error",
|
||||
expectedCode: http.StatusInternalServerError,
|
||||
errCode: plugins.ErrorCodeFailedBackendStart,
|
||||
expectedError: "Plugin failed to start",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tcs {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
server := SetupAPITestServer(t, func(hs *HTTPServer) {
|
||||
hs.Cfg = setting.NewCfg()
|
||||
hs.PluginSettings = &pluginSettings
|
||||
hs.pluginStore = pluginstore.New(pluginRegistry, &fakes.FakeLoader{})
|
||||
hs.pluginFileStore = filestore.ProvideService(pluginRegistry)
|
||||
errTracker := pluginerrs.ProvideErrorTracker()
|
||||
if tc.errCode != "" {
|
||||
errTracker.Record(context.Background(), &plugins.Error{
|
||||
PluginID: pID,
|
||||
ErrorCode: tc.errCode,
|
||||
})
|
||||
}
|
||||
hs.pluginErrorResolver = pluginerrs.ProvideStore(errTracker)
|
||||
var err error
|
||||
hs.pluginsUpdateChecker, err = updatechecker.ProvidePluginsService(hs.Cfg, nil, tracing.InitializeTracerForTest())
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
res, err := server.Send(webtest.RequestWithSignedInUser(server.NewGetRequest("/api/plugins/"+pID+"/settings"), userWithPermissions(1, []ac.Permission{})))
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.expectedCode, res.StatusCode)
|
||||
if tc.expectedCode == http.StatusOK {
|
||||
var result dtos.PluginSetting
|
||||
require.NoError(t, json.NewDecoder(res.Body).Decode(&result))
|
||||
require.NoError(t, res.Body.Close())
|
||||
assert.Equal(t, tc.expectedSettings, result)
|
||||
} else {
|
||||
var respJson map[string]any
|
||||
err := json.NewDecoder(res.Body).Decode(&respJson)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.expectedError, respJson["message"])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -110,6 +110,7 @@ type StaticRouteResolver interface {
|
||||
|
||||
type ErrorResolver interface {
|
||||
PluginErrors(ctx context.Context) []*Error
|
||||
PluginError(ctx context.Context, pluginID string) *Error
|
||||
}
|
||||
|
||||
type PluginLoaderAuthorizer interface {
|
||||
|
@ -296,6 +296,23 @@ func (e *Error) WithMessage(m string) *Error {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e Error) PublicMessage() string {
|
||||
switch e.ErrorCode {
|
||||
case errorCodeSignatureInvalid:
|
||||
return "Invalid plugin signature"
|
||||
case errorCodeSignatureModified:
|
||||
return "Plugin signature does not match"
|
||||
case errorCodeSignatureMissing:
|
||||
return "Plugin signature is missing"
|
||||
case ErrorCodeFailedBackendStart:
|
||||
return "Plugin failed to start"
|
||||
case ErrorAngular:
|
||||
return "Angular plugins are not supported"
|
||||
}
|
||||
|
||||
return "Plugin failed to load"
|
||||
}
|
||||
|
||||
// Access-Control related definitions
|
||||
|
||||
// RoleRegistration stores a role and its assignments to basic roles
|
||||
|
@ -36,3 +36,7 @@ func (t *fakeErrorTracker) Errors(ctx context.Context) []*plugins.Error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *fakeErrorTracker) Error(ctx context.Context, pluginID string) *plugins.Error {
|
||||
return &plugins.Error{}
|
||||
}
|
||||
|
@ -65,10 +65,10 @@ func ProvideInitializationStage(cfg *config.PluginManagementCfg, pr registry.Ser
|
||||
InitializeFuncs: []initialization.InitializeFunc{
|
||||
ExternalServiceRegistrationStep(cfg, externalServiceRegistry, tracer),
|
||||
initialization.BackendClientInitStep(pluginEnvProvider, bp),
|
||||
initialization.PluginRegistrationStep(pr),
|
||||
initialization.BackendProcessStartStep(pm),
|
||||
RegisterPluginRolesStep(roleRegistry),
|
||||
ReportBuildMetrics,
|
||||
initialization.PluginRegistrationStep(pr),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -28,6 +28,16 @@ func (s *Store) PluginErrors(ctx context.Context) []*plugins.Error {
|
||||
return errs
|
||||
}
|
||||
|
||||
func (s *Store) PluginError(ctx context.Context, pluginID string) *plugins.Error {
|
||||
err := s.errs.Error(ctx, pluginID)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
err.ErrorCode = err.AsErrorCode()
|
||||
return err
|
||||
}
|
||||
|
||||
type ErrorRegistry struct {
|
||||
errs map[string]*plugins.Error
|
||||
log log.Logger
|
||||
@ -37,6 +47,7 @@ type ErrorTracker interface {
|
||||
Record(ctx context.Context, err *plugins.Error)
|
||||
Clear(ctx context.Context, pluginID string)
|
||||
Errors(ctx context.Context) []*plugins.Error
|
||||
Error(ctx context.Context, pluginID string) *plugins.Error
|
||||
}
|
||||
|
||||
func ProvideErrorTracker() *ErrorRegistry {
|
||||
@ -65,3 +76,7 @@ func (r *ErrorRegistry) Errors(_ context.Context) []*plugins.Error {
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
func (r *ErrorRegistry) Error(_ context.Context, pluginID string) *plugins.Error {
|
||||
return r.errs[pluginID]
|
||||
}
|
||||
|
Reference in New Issue
Block a user