From 08a73a5291b1f7112e5fb104f5100a0b0fe19e68 Mon Sep 17 00:00:00 2001 From: Will Browne Date: Thu, 29 Jul 2021 11:52:23 +0200 Subject: [PATCH] Plugins: Perform plugin update check prior to uninstall (#36909) * only uninstall if update is possible * add . * update lingo for clarity --- pkg/plugins/ifaces.go | 5 +++-- pkg/plugins/manager/installer/installer.go | 25 +++++++++++++++++++--- pkg/plugins/manager/manager.go | 14 ++++++++++-- pkg/plugins/manager/manager_test.go | 4 ++++ pkg/plugins/models.go | 4 ++++ 5 files changed, 45 insertions(+), 7 deletions(-) diff --git a/pkg/plugins/ifaces.go b/pkg/plugins/ifaces.go index eb091797e7a..783bbcfc289 100644 --- a/pkg/plugins/ifaces.go +++ b/pkg/plugins/ifaces.go @@ -74,11 +74,12 @@ type DataRequestHandler interface { } type PluginInstaller interface { - // Install finds the plugin given the provided information - // and installs in the provided plugins directory. + // Install finds the plugin given the provided information and installs in the provided plugins directory. Install(ctx context.Context, pluginID, version, pluginsDirectory, pluginZipURL, pluginRepoURL string) error // Uninstall removes the specified plugin from the provided plugins directory. Uninstall(ctx context.Context, pluginPath string) error + // GetUpdateInfo returns update information if the requested plugin is supported on the running system. + GetUpdateInfo(pluginID, version, pluginRepoURL string) (UpdateInfo, error) } type PluginInstallerLogger interface { diff --git a/pkg/plugins/manager/installer/installer.go b/pkg/plugins/manager/installer/installer.go index 9b9d5480228..999972c86c1 100644 --- a/pkg/plugins/manager/installer/installer.go +++ b/pkg/plugins/manager/installer/installer.go @@ -410,9 +410,28 @@ func normalizeVersion(version string) string { return normalized } -// selectVersion returns latest version if none is specified or the specified version. If the version string is not -// matched to existing version it errors out. It also errors out if version that is matched is not available for current -// os and platform. It expects plugin.Versions to be sorted so the newest version is first. +func (i *Installer) GetUpdateInfo(pluginID, version, pluginRepoURL string) (plugins.UpdateInfo, error) { + plugin, err := i.getPluginMetadataFromPluginRepo(pluginID, pluginRepoURL) + if err != nil { + return plugins.UpdateInfo{}, err + } + + v, err := i.selectVersion(&plugin, version) + if err != nil { + return plugins.UpdateInfo{}, err + } + + return plugins.UpdateInfo{ + PluginZipURL: fmt.Sprintf("%s/%s/versions/%s/download", pluginRepoURL, pluginID, v.Version), + }, nil +} + +// selectVersion selects the most appropriate plugin version +// returns the specified version if supported. +// returns latest version if no specific version is specified. +// returns error if the supplied version does not exist. +// returns error if supplied version exists but is not supported. +// NOTE: It expects plugin.Versions to be sorted so the newest version is first. func (i *Installer) selectVersion(plugin *Plugin, version string) (*Version, error) { var ver Version diff --git a/pkg/plugins/manager/manager.go b/pkg/plugins/manager/manager.go index 308050d3405..f2cf70f8421 100644 --- a/pkg/plugins/manager/manager.go +++ b/pkg/plugins/manager/manager.go @@ -726,6 +726,8 @@ func (pm *PluginManager) StaticRoutes() []*plugins.PluginStaticRoute { func (pm *PluginManager) Install(ctx context.Context, pluginID, version string) error { plugin := pm.GetPlugin(pluginID) + + var pluginZipURL string if plugin != nil { if plugin.IsCorePlugin { return plugins.ErrInstallCorePlugin @@ -738,14 +740,22 @@ func (pm *PluginManager) Install(ctx context.Context, pluginID, version string) } } + // get plugin update information to confirm if upgrading is possible + updateInfo, err := pm.pluginInstaller.GetUpdateInfo(pluginID, version, grafanaComURL) + if err != nil { + return err + } + + pluginZipURL = updateInfo.PluginZipURL + // remove existing installation of plugin - err := pm.Uninstall(context.Background(), plugin.Id) + err = pm.Uninstall(context.Background(), plugin.Id) if err != nil { return err } } - err := pm.pluginInstaller.Install(ctx, pluginID, version, pm.Cfg.PluginsPath, "", grafanaComURL) + err := pm.pluginInstaller.Install(ctx, pluginID, version, pm.Cfg.PluginsPath, pluginZipURL, grafanaComURL) if err != nil { return err } diff --git a/pkg/plugins/manager/manager_test.go b/pkg/plugins/manager/manager_test.go index 3d09ea28128..d1a18af6dd5 100644 --- a/pkg/plugins/manager/manager_test.go +++ b/pkg/plugins/manager/manager_test.go @@ -702,6 +702,10 @@ func (f *fakePluginInstaller) Uninstall(ctx context.Context, pluginPath string) return nil } +func (f *fakePluginInstaller) GetUpdateInfo(pluginID, version, pluginRepoURL string) (plugins.UpdateInfo, error) { + return plugins.UpdateInfo{}, nil +} + func createManager(t *testing.T, cbs ...func(*PluginManager)) *PluginManager { t.Helper() diff --git a/pkg/plugins/models.go b/pkg/plugins/models.go index e4672d7657f..414ad9b0b77 100644 --- a/pkg/plugins/models.go +++ b/pkg/plugins/models.go @@ -158,3 +158,7 @@ type EnabledPlugins struct { DataSources map[string]*DataSourcePlugin Apps []*AppPlugin } + +type UpdateInfo struct { + PluginZipURL string +}