From 3965e68c8d241cb2c7fdee1f15cf1000370279ca Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 13:54:47 +0300 Subject: [PATCH] [v11.2.x] Plugins: Skip install errors if dependency plugin already exists (#94717) Plugins: Skip install errors if dependency plugin already exists (#94710) * skip install errors if dependency plugin already exists * add test (cherry picked from commit f97f489c2c580c8bfd24351e59279b6bdae3ff7a) Co-authored-by: Will Browne --- pkg/plugins/manager/installer.go | 5 +++ pkg/plugins/manager/installer_test.go | 44 +++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/pkg/plugins/manager/installer.go b/pkg/plugins/manager/installer.go index b1db5662c51..227d8a35450 100644 --- a/pkg/plugins/manager/installer.go +++ b/pkg/plugins/manager/installer.go @@ -75,6 +75,11 @@ func (m *PluginInstaller) Add(ctx context.Context, pluginID, version string, opt err = m.Add(ctx, dep.ID, dep.Version, opts) if err != nil { + var dupeErr plugins.DuplicateError + if errors.As(err, &dupeErr) { + m.log.Info("Dependency already installed", "pluginId", dep.ID) + continue + } return fmt.Errorf("%v: %w", fmt.Sprintf("failed to download plugin %s from repository", dep.ID), err) } } diff --git a/pkg/plugins/manager/installer_test.go b/pkg/plugins/manager/installer_test.go index f90c3ba11c3..bb4564c7d25 100644 --- a/pkg/plugins/manager/installer_test.go +++ b/pkg/plugins/manager/installer_test.go @@ -279,6 +279,50 @@ func TestPluginManager_Add_Remove(t *testing.T) { require.NoError(t, err) require.Equal(t, []string{p2Zip, p1Zip}, loadedPaths) }) + + t.Run("Plugin can successfully install even if dependency plugin is already installed", func(t *testing.T) { + const pluginDependencyID = "test-plugin-dependency" + reg := &fakes.FakePluginRegistry{ + Store: map[string]*plugins.Plugin{ + pluginDependencyID: createPlugin(t, pluginDependencyID, plugins.ClassExternal, false, false), + }, + } + + var loadedPaths []string + loader := &fakes.FakeLoader{ + LoadFunc: func(ctx context.Context, src plugins.PluginSource) ([]*plugins.Plugin, error) { + loadedPaths = append(loadedPaths, src.PluginURIs(ctx)...) + return []*plugins.Plugin{}, nil + }, + } + + pluginRepo := &fakes.FakePluginRepo{ + GetPluginArchiveFunc: func(_ context.Context, id, version string, _ repo.CompatOpts) (*repo.PluginArchive, error) { + return &repo.PluginArchive{File: &zip.ReadCloser{Reader: zip.Reader{File: []*zip.File{{ + FileHeader: zip.FileHeader{Name: fmt.Sprintf("%s.zip", id)}, + }}}}}, nil + }, + } + + fs := &fakes.FakePluginStorage{ + ExtractFunc: func(_ context.Context, id string, _ storage.DirNameGeneratorFunc, z *zip.ReadCloser) (*storage.ExtractedPluginArchive, error) { + switch id { + case testPluginID: + return &storage.ExtractedPluginArchive{ + Dependencies: []*storage.Dependency{{ID: pluginDependencyID}}, + Path: "test-plugin.zip", + }, nil + default: + return nil, fmt.Errorf("unknown plugin %s", id) + } + }, + } + + inst := New(reg, loader, pluginRepo, fs, storage.SimpleDirNameGeneratorFunc, &fakes.FakeAuthService{}) + err := inst.Add(context.Background(), testPluginID, "", testCompatOpts()) + require.NoError(t, err) + require.Equal(t, []string{"test-plugin.zip"}, loadedPaths) + }) } func createPlugin(t *testing.T, pluginID string, class plugins.Class, managed, backend bool, cbs ...func(*plugins.Plugin)) *plugins.Plugin {