Plugins: Add plugins auto update feature (#104112)

This commit is contained in:
Hugo Kiyodi Oshiro
2025-05-09 15:58:04 +02:00
committed by GitHub
parent 42028a1b03
commit 43748e43bb
24 changed files with 446 additions and 220 deletions
@@ -9,8 +9,8 @@ import (
"github.com/grafana/grafana/pkg/plugins/repo"
"github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/pluginsintegration/managedplugins"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginchecker"
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugininstaller"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
"github.com/grafana/grafana/pkg/services/pluginsintegration/provisionedplugins"
"github.com/grafana/grafana/pkg/services/ssosettings"
@@ -27,7 +27,8 @@ type Service struct {
pluginContextProvider *plugincontext.Provider
pluginClient plugins.Client
pluginRepo repo.Service
pluginPreinstall plugininstaller.Preinstall
updateChecker pluginchecker.PluginUpdateChecker
pluginPreinstall pluginchecker.Preinstall
managedPlugins managedplugins.Manager
provisionedPlugins provisionedplugins.Manager
ssoSettingsSvc ssosettings.Service
@@ -36,9 +37,9 @@ type Service struct {
func ProvideService(datasourceSvc datasources.DataSourceService, pluginStore pluginstore.Store,
pluginContextProvider *plugincontext.Provider, pluginClient plugins.Client,
pluginRepo repo.Service, pluginPreinstall plugininstaller.Preinstall, managedPlugins managedplugins.Manager,
updateChecker pluginchecker.PluginUpdateChecker,
pluginRepo repo.Service, pluginPreinstall pluginchecker.Preinstall, managedPlugins managedplugins.Manager,
provisionedPlugins provisionedplugins.Manager, ssoSettingsSvc ssosettings.Service, settings *setting.Cfg,
) *Service {
return &Service{
datasourceSvc: datasourceSvc,
@@ -46,6 +47,7 @@ func ProvideService(datasourceSvc datasources.DataSourceService, pluginStore plu
pluginContextProvider: pluginContextProvider,
pluginClient: pluginClient,
pluginRepo: pluginRepo,
updateChecker: updateChecker,
pluginPreinstall: pluginPreinstall,
managedPlugins: managedPlugins,
provisionedPlugins: provisionedPlugins,
@@ -67,9 +69,7 @@ func (s *Service) Checks() []checks.Check {
plugincheck.New(
s.pluginStore,
s.pluginRepo,
s.pluginPreinstall,
s.managedPlugins,
s.provisionedPlugins,
s.updateChecker,
s.GrafanaVersion,
),
authchecks.New(s.ssoSettingsSvc),
+24 -112
View File
@@ -4,17 +4,14 @@ import (
"context"
"fmt"
sysruntime "runtime"
"slices"
"github.com/Masterminds/semver/v3"
"github.com/grafana/grafana-app-sdk/logging"
advisor "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
"github.com/grafana/grafana/pkg/plugins/repo"
"github.com/grafana/grafana/pkg/services/pluginsintegration/managedplugins"
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugininstaller"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginchecker"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
"github.com/grafana/grafana/pkg/services/pluginsintegration/provisionedplugins"
)
const (
@@ -26,28 +23,22 @@ const (
func New(
pluginStore pluginstore.Store,
pluginRepo repo.Service,
pluginPreinstall plugininstaller.Preinstall,
managedPlugins managedplugins.Manager,
provisionedPlugins provisionedplugins.Manager,
updateChecker pluginchecker.PluginUpdateChecker,
grafanaVersion string,
) checks.Check {
return &check{
PluginStore: pluginStore,
PluginRepo: pluginRepo,
PluginPreinstall: pluginPreinstall,
ManagedPlugins: managedPlugins,
ProvisionedPlugins: provisionedPlugins,
GrafanaVersion: grafanaVersion,
PluginStore: pluginStore,
PluginRepo: pluginRepo,
GrafanaVersion: grafanaVersion,
updateChecker: updateChecker,
}
}
type check struct {
PluginStore pluginstore.Store
PluginRepo repo.Service
PluginPreinstall plugininstaller.Preinstall
ManagedPlugins managedplugins.Manager
ProvisionedPlugins provisionedplugins.Manager
GrafanaVersion string
PluginStore pluginstore.Store
PluginRepo repo.Service
updateChecker pluginchecker.PluginUpdateChecker
GrafanaVersion string
}
func (c *check) ID() string {
@@ -74,29 +65,22 @@ func (c *check) Item(ctx context.Context, id string) (any, error) {
func (c *check) Steps() []checks.Step {
return []checks.Step{
&deprecationStep{
PluginRepo: c.PluginRepo,
PluginPreinstall: c.PluginPreinstall,
ManagedPlugins: c.ManagedPlugins,
ProvisionedPlugins: c.ProvisionedPlugins,
GrafanaVersion: c.GrafanaVersion,
PluginRepo: c.PluginRepo,
GrafanaVersion: c.GrafanaVersion,
updateChecker: c.updateChecker,
},
&updateStep{
PluginRepo: c.PluginRepo,
PluginPreinstall: c.PluginPreinstall,
ManagedPlugins: c.ManagedPlugins,
ProvisionedPlugins: c.ProvisionedPlugins,
GrafanaVersion: c.GrafanaVersion,
PluginRepo: c.PluginRepo,
GrafanaVersion: c.GrafanaVersion,
updateChecker: c.updateChecker,
},
}
}
type deprecationStep struct {
PluginRepo repo.Service
PluginPreinstall plugininstaller.Preinstall
ManagedPlugins managedplugins.Manager
ProvisionedPlugins provisionedplugins.Manager
GrafanaVersion string
provisionedPlugins []string
PluginRepo repo.Service
GrafanaVersion string
updateChecker pluginchecker.PluginUpdateChecker
}
func (s *deprecationStep) Title() string {
@@ -122,21 +106,7 @@ func (s *deprecationStep) Run(ctx context.Context, log logging.Logger, _ *adviso
return nil, fmt.Errorf("invalid item type %T", it)
}
// Skip if it's a core plugin
if p.IsCorePlugin() {
log.Debug("Skipping core plugin", "plugin", p.ID)
return nil, nil
}
// Skip if it's managed or pinned
if s.isManaged(ctx, p.ID) || s.PluginPreinstall.IsPinned(p.ID) {
log.Debug("Skipping managed or pinned plugin", "plugin", p.ID)
return nil, nil
}
// Skip if it's provisioned
if s.isProvisioned(ctx, p.ID) {
log.Debug("Skipping provisioned plugin", "plugin", p.ID)
if !s.updateChecker.IsUpdatable(ctx, p) {
return nil, nil
}
@@ -165,12 +135,9 @@ func (s *deprecationStep) Run(ctx context.Context, log logging.Logger, _ *adviso
}
type updateStep struct {
PluginRepo repo.Service
PluginPreinstall plugininstaller.Preinstall
ManagedPlugins managedplugins.Manager
ProvisionedPlugins provisionedplugins.Manager
provisionedPlugins []string
GrafanaVersion string
PluginRepo repo.Service
GrafanaVersion string
updateChecker pluginchecker.PluginUpdateChecker
}
func (s *updateStep) Title() string {
@@ -195,21 +162,7 @@ func (s *updateStep) Run(ctx context.Context, log logging.Logger, _ *advisor.Che
return nil, fmt.Errorf("invalid item type %T", i)
}
// Skip if it's a core plugin
if p.IsCorePlugin() {
log.Debug("Skipping core plugin", "plugin", p.ID)
return nil, nil
}
// Skip if it's managed or pinned
if s.isManaged(ctx, p.ID) || s.PluginPreinstall.IsPinned(p.ID) {
log.Debug("Skipping managed or pinned plugin", "plugin", p.ID)
return nil, nil
}
// Skip if it's provisioned
if s.isProvisioned(ctx, p.ID) {
log.Debug("Skipping provisioned plugin", "plugin", p.ID)
if !s.updateChecker.IsUpdatable(ctx, p) {
return nil, nil
}
@@ -248,44 +201,3 @@ func hasUpdate(current pluginstore.Plugin, latest *repo.PluginArchiveInfo) bool
// In other case, assume that a different latest version will always be newer
return current.Info.Version != latest.Version
}
func (s *updateStep) isManaged(ctx context.Context, pluginID string) bool {
for _, managedPlugin := range s.ManagedPlugins.ManagedPlugins(ctx) {
if managedPlugin == pluginID {
return true
}
}
return false
}
func (s *updateStep) isProvisioned(ctx context.Context, pluginID string) bool {
if s.provisionedPlugins == nil {
var err error
s.provisionedPlugins, err = s.ProvisionedPlugins.ProvisionedPlugins(ctx)
if err != nil {
return false
}
}
return slices.Contains(s.provisionedPlugins, pluginID)
}
// Temporary duplicated code until there is a common IsUpdatable function
func (s *deprecationStep) isManaged(ctx context.Context, pluginID string) bool {
for _, managedPlugin := range s.ManagedPlugins.ManagedPlugins(ctx) {
if managedPlugin == pluginID {
return true
}
}
return false
}
func (s *deprecationStep) isProvisioned(ctx context.Context, pluginID string) bool {
if s.provisionedPlugins == nil {
var err error
s.provisionedPlugins, err = s.ProvisionedPlugins.ProvisionedPlugins(ctx)
if err != nil {
return false
}
}
return slices.Contains(s.provisionedPlugins, pluginID)
}
@@ -9,7 +9,7 @@ import (
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/repo"
"github.com/grafana/grafana/pkg/services/pluginsintegration/managedplugins"
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugininstaller"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginchecker"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
"github.com/grafana/grafana/pkg/services/pluginsintegration/provisionedplugins"
"github.com/stretchr/testify/assert"
@@ -163,7 +163,8 @@ func TestRun(t *testing.T) {
pluginPreinstall := &mockPluginPreinstall{pinned: tt.pluginPreinstalled}
managedPlugins := &mockManagedPlugins{managed: tt.pluginManaged}
provisionedPlugins := &mockProvisionedPlugins{provisioned: tt.pluginProvisioned}
check := New(pluginStore, pluginRepo, pluginPreinstall, managedPlugins, provisionedPlugins, "12.0.0")
updateChecker := pluginchecker.ProvideService(managedPlugins, provisionedPlugins, pluginPreinstall)
check := New(pluginStore, pluginRepo, updateChecker, "12.0.0")
items, err := check.Items(context.Background())
assert.NoError(t, err)
@@ -208,7 +209,7 @@ func (m *mockPluginRepo) GetPluginArchiveInfo(ctx context.Context, id, version s
}
type mockPluginPreinstall struct {
plugininstaller.Preinstall
pluginchecker.Preinstall
pinned []string
}