Advisor: Include deprecated and filter by plugin slug (#105383)

pull/105486/head
Andres Martinez Gotor 2 months ago committed by GitHub
parent 634fa9a67d
commit 76d4953879
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 24
      apps/advisor/pkg/app/checks/datasourcecheck/check.go
  2. 2
      apps/advisor/pkg/app/checks/datasourcecheck/check_test.go
  3. 10
      apps/advisor/pkg/app/checks/plugincheck/check.go
  4. 2
      apps/advisor/pkg/app/checks/plugincheck/check_test.go
  5. 2
      pkg/plugins/manager/fakes/fakes.go
  6. 2
      pkg/plugins/repo/ifaces.go
  7. 60
      pkg/plugins/repo/service.go
  8. 6
      pkg/plugins/repo/service_test.go

@ -32,7 +32,6 @@ type check struct {
PluginClient plugins.Client
PluginRepo repo.Service
GrafanaVersion string
pluginIndex map[string]repo.PluginInfo
}
func New(
@ -81,15 +80,6 @@ func (c *check) ID() string {
}
func (c *check) Init(ctx context.Context) error {
compatOpts := repo.NewCompatOpts(c.GrafanaVersion, sysruntime.GOOS, sysruntime.GOARCH)
plugins, err := c.PluginRepo.GetPluginsInfo(ctx, compatOpts)
if err != nil {
return err
}
c.pluginIndex = make(map[string]repo.PluginInfo)
for _, p := range plugins {
c.pluginIndex[p.Slug] = p
}
return nil
}
@ -102,8 +92,8 @@ func (c *check) Steps() []checks.Step {
},
&missingPluginStep{
PluginStore: c.PluginStore,
PluginRepo: c.PluginRepo,
GrafanaVersion: c.GrafanaVersion,
pluginIndex: c.pluginIndex,
},
}
}
@ -221,8 +211,8 @@ func (s *healthCheckStep) Run(ctx context.Context, log logging.Logger, obj *advi
type missingPluginStep struct {
PluginStore pluginstore.Store
PluginRepo repo.Service
GrafanaVersion string
pluginIndex map[string]repo.PluginInfo
}
func (s *missingPluginStep) Title() string {
@ -255,8 +245,14 @@ func (s *missingPluginStep) Run(ctx context.Context, log logging.Logger, obj *ad
Url: fmt.Sprintf("/connections/datasources/edit/%s", ds.UID),
},
}
_, ok := s.pluginIndex[ds.Type]
if ok {
plugins, err := s.PluginRepo.GetPluginsInfo(ctx, repo.GetPluginsInfoOptions{
IncludeDeprecated: true,
Plugins: []string{ds.Type},
}, repo.NewCompatOpts(s.GrafanaVersion, sysruntime.GOOS, sysruntime.GOARCH))
if err != nil {
return nil, err
}
if len(plugins) > 0 {
// Plugin is available in the repo
links = append(links, advisor.CheckErrorLink{
Message: "Install plugin",

@ -276,6 +276,6 @@ type MockPluginRepo struct {
plugins []repo.PluginInfo
}
func (m *MockPluginRepo) GetPluginsInfo(context.Context, repo.CompatOpts) ([]repo.PluginInfo, error) {
func (m *MockPluginRepo) GetPluginsInfo(context.Context, repo.GetPluginsInfoOptions, repo.CompatOpts) ([]repo.PluginInfo, error) {
return m.plugins, nil
}

@ -64,7 +64,15 @@ func (c *check) Item(ctx context.Context, id string) (any, error) {
func (c *check) Init(ctx context.Context) error {
compatOpts := repo.NewCompatOpts(c.GrafanaVersion, sysruntime.GOOS, sysruntime.GOARCH)
plugins, err := c.PluginRepo.GetPluginsInfo(ctx, compatOpts)
ps := c.PluginStore.Plugins(ctx)
pluginIDs := make([]string, len(ps))
for i, p := range ps {
pluginIDs[i] = p.ID
}
plugins, err := c.PluginRepo.GetPluginsInfo(ctx, repo.GetPluginsInfoOptions{
IncludeDeprecated: true,
Plugins: pluginIDs,
}, compatOpts)
if err != nil {
return err
}

@ -168,7 +168,7 @@ type mockPluginRepo struct {
pluginInfo []repo.PluginInfo
}
func (m *mockPluginRepo) GetPluginsInfo(ctx context.Context, compatOpts repo.CompatOpts) ([]repo.PluginInfo, error) {
func (m *mockPluginRepo) GetPluginsInfo(ctx context.Context, options repo.GetPluginsInfoOptions, compatOpts repo.CompatOpts) ([]repo.PluginInfo, error) {
return m.pluginInfo, nil
}

@ -276,7 +276,7 @@ func (r *FakePluginRepo) PluginInfo(ctx context.Context, pluginID string, compat
return &repo.PluginInfo{}, nil
}
func (r *FakePluginRepo) GetPluginsInfo(ctx context.Context, compatOpts repo.CompatOpts) ([]repo.PluginInfo, error) {
func (r *FakePluginRepo) GetPluginsInfo(ctx context.Context, options repo.GetPluginsInfoOptions, compatOpts repo.CompatOpts) ([]repo.PluginInfo, error) {
return []repo.PluginInfo{}, nil
}

@ -17,7 +17,7 @@ type Service interface {
// PluginVersion will return plugin version based on the requested information.
PluginVersion(ctx context.Context, pluginID, version string, compatOpts CompatOpts) (VersionData, error)
// GetPluginsInfo will return a list of plugins from grafana.com/api/plugins.
GetPluginsInfo(ctx context.Context, compatOpts CompatOpts) ([]PluginInfo, error)
GetPluginsInfo(ctx context.Context, options GetPluginsInfoOptions, compatOpts CompatOpts) ([]PluginInfo, error)
}
type CompatOpts struct {

@ -13,6 +13,10 @@ import (
"github.com/grafana/grafana/pkg/plugins/log"
)
const (
getPluginsInfoMaxPlugins = 50
)
type Manager struct {
client *Client
@ -132,25 +136,55 @@ func (m *Manager) grafanaCompatiblePluginVersions(ctx context.Context, pluginID
return v.Versions, nil
}
func (m *Manager) GetPluginsInfo(ctx context.Context, compatOpts CompatOpts) ([]PluginInfo, error) {
u, err := url.Parse(m.client.grafanaComAPIURL)
if err != nil {
return nil, err
}
type GetPluginsInfoOptions struct {
IncludeDeprecated bool
Plugins []string
}
body, err := m.client.SendReq(ctx, u, compatOpts)
func (m *Manager) GetPluginsInfo(ctx context.Context, options GetPluginsInfoOptions, compatOpts CompatOpts) ([]PluginInfo, error) {
u, err := url.Parse(m.client.grafanaComAPIURL)
if err != nil {
return nil, err
}
var v struct {
Items []PluginInfo `json:"items"`
// If we are requesting more than 50 plugins, split the request into multiple requests to avoid
// the URL limit (local testing shows that the URL is <2000 characters for 100 plugins, so 50 is
// a safe limit).
plugins := [][]string{}
results := []PluginInfo{}
if len(options.Plugins) > getPluginsInfoMaxPlugins {
for i := 0; i < len(options.Plugins); i += getPluginsInfoMaxPlugins {
plugins = append(plugins, options.Plugins[i:min(i+getPluginsInfoMaxPlugins, len(options.Plugins))])
}
} else {
plugins = [][]string{options.Plugins}
}
err = json.Unmarshal(body, &v)
if err != nil {
m.log.Error("Failed to unmarshal plugin repo response", "error", err)
return nil, err
for _, p := range plugins {
q := u.Query()
if options.IncludeDeprecated {
q.Set("includeDeprecated", "true")
}
if len(p) > 0 {
q.Set("slugIn", strings.Join(p, ","))
}
u.RawQuery = q.Encode()
body, err := m.client.SendReq(ctx, u, compatOpts)
if err != nil {
return nil, err
}
var v struct {
Items []PluginInfo `json:"items"`
}
err = json.Unmarshal(body, &v)
if err != nil {
m.log.Error("Failed to unmarshal plugin repo response", "error", err)
return nil, err
}
results = append(results, v.Items...)
}
return v.Items, nil
return results, nil
}

@ -116,6 +116,7 @@ func TestPluginIndex(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "12.0.0", r.Header.Get("grafana-version"))
require.Equal(t, "grafana 12.0.0", r.Header.Get("User-Agent"))
require.Equal(t, "includeDeprecated=true&slugIn=grafana-test-datasource", r.URL.RawQuery)
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
_, _ = fmt.Fprintf(w, `{"items": [{ "id": 1, "slug": "%s", "status": "active" }]}`, pluginID)
@ -127,7 +128,10 @@ func TestPluginIndex(t *testing.T) {
BaseURL: srv.URL,
Logger: log.NewTestPrettyLogger(),
})
pi, err := m.GetPluginsInfo(context.Background(), CompatOpts{
pi, err := m.GetPluginsInfo(context.Background(), GetPluginsInfoOptions{
IncludeDeprecated: true,
Plugins: []string{pluginID},
}, CompatOpts{
grafanaVersion: "12.0.0",
system: SystemCompatOpts{
os: "darwin",

Loading…
Cancel
Save