Return plugin error when requesting settings (#86052)

pull/86518/head
Andres Martinez Gotor 1 year ago committed by GitHub
parent 8373fc3544
commit eac02a61e1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      pkg/api/plugins.go
  2. 86
      pkg/api/plugins_test.go
  3. 1
      pkg/plugins/ifaces.go
  4. 17
      pkg/plugins/models.go
  5. 4
      pkg/services/pluginsintegration/loader/fakes.go
  6. 2
      pkg/services/pluginsintegration/pipeline/pipeline.go
  7. 15
      pkg/services/pluginsintegration/pluginerrs/errors.go

@ -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]
}

Loading…
Cancel
Save