Feature: Allow to skip plugin loading (#74840)

This commit is contained in:
Andres Martinez Gotor
2023-09-14 12:58:12 +02:00
committed by GitHub
parent 05f01dee0c
commit 96b55ea37c
12 changed files with 125 additions and 4 deletions

View File

@ -1478,6 +1478,8 @@ public_key_retrieval_disabled = false
# Force download of the public key for verifying plugin signature on startup. If disabled, the public key will be retrieved every 10 days. # Force download of the public key for verifying plugin signature on startup. If disabled, the public key will be retrieved every 10 days.
# Requires public_key_retrieval_disabled to be false to have any effect. # Requires public_key_retrieval_disabled to be false to have any effect.
public_key_retrieval_on_startup = false public_key_retrieval_on_startup = false
# Enter a comma-separated list of plugin identifiers to avoid loading (including core plugins). These plugins will be hidden in the catalog.
disable_plugins =
#################################### Grafana Live ########################################## #################################### Grafana Live ##########################################
[live] [live]

View File

@ -1372,6 +1372,8 @@
# Force download of the public key for verifying plugin signature on startup. If disabled, the public key will be retrieved every 10 days. # Force download of the public key for verifying plugin signature on startup. If disabled, the public key will be retrieved every 10 days.
# Requires public_key_retrieval_disabled to be false to have any effect. # Requires public_key_retrieval_disabled to be false to have any effect.
; public_key_retrieval_on_startup = false ; public_key_retrieval_on_startup = false
# Enter a comma-separated list of plugin identifiers to avoid loading (including core plugins). These plugins will be hidden in the catalog.
; disable_plugins =
#################################### Grafana Live ########################################## #################################### Grafana Live ##########################################
[live] [live]

View File

@ -2112,6 +2112,10 @@ Disable download of the public key for verifying plugin signature. The default i
Force download of the public key for verifying plugin signature on startup. The default is `false`. If disabled, the public key will be retrieved every 10 days. Requires `public_key_retrieval_disabled` to be false to have any effect. Force download of the public key for verifying plugin signature on startup. The default is `false`. If disabled, the public key will be retrieved every 10 days. Requires `public_key_retrieval_disabled` to be false to have any effect.
### disable_plugins
Enter a comma-separated list of plugin identifiers to avoid loading (including core plugins). These plugins will be hidden in the catalog.
<hr> <hr>
## [live] ## [live]

View File

@ -1,8 +1,6 @@
package backendplugin package backendplugin
import ( import "errors"
"errors"
)
var ( var (
// ErrPluginNotRegistered error returned when plugin is not registered. // ErrPluginNotRegistered error returned when plugin is not registered.

View File

@ -17,6 +17,7 @@ type Cfg struct {
PluginSettings setting.PluginSettings PluginSettings setting.PluginSettings
PluginsAllowUnsigned []string PluginsAllowUnsigned []string
DisablePlugins []string
// AWS Plugin Auth // AWS Plugin Auth
AWSAllowedAuthProviders []string AWSAllowedAuthProviders []string
@ -50,7 +51,7 @@ type Cfg struct {
func NewCfg(devMode bool, pluginsPath string, pluginSettings setting.PluginSettings, pluginsAllowUnsigned []string, func NewCfg(devMode bool, pluginsPath string, pluginSettings setting.PluginSettings, pluginsAllowUnsigned []string,
awsAllowedAuthProviders []string, awsAssumeRoleEnabled bool, awsExternalId string, azure *azsettings.AzureSettings, secureSocksDSProxy setting.SecureSocksDSProxySettings, awsAllowedAuthProviders []string, awsAssumeRoleEnabled bool, awsExternalId string, azure *azsettings.AzureSettings, secureSocksDSProxy setting.SecureSocksDSProxySettings,
grafanaVersion string, logDatasourceRequests bool, pluginsCDNURLTemplate string, appURL string, appSubURL string, tracing Tracing, features plugins.FeatureToggles, angularSupportEnabled bool, grafanaVersion string, logDatasourceRequests bool, pluginsCDNURLTemplate string, appURL string, appSubURL string, tracing Tracing, features plugins.FeatureToggles, angularSupportEnabled bool,
grafanaComURL string) *Cfg { grafanaComURL string, disablePlugins []string) *Cfg {
return &Cfg{ return &Cfg{
log: log.New("plugin.cfg"), log: log.New("plugin.cfg"),
PluginsPath: pluginsPath, PluginsPath: pluginsPath,
@ -58,6 +59,7 @@ func NewCfg(devMode bool, pluginsPath string, pluginSettings setting.PluginSetti
DevMode: devMode, DevMode: devMode,
PluginSettings: pluginSettings, PluginSettings: pluginSettings,
PluginsAllowUnsigned: pluginsAllowUnsigned, PluginsAllowUnsigned: pluginsAllowUnsigned,
DisablePlugins: disablePlugins,
AWSAllowedAuthProviders: awsAllowedAuthProviders, AWSAllowedAuthProviders: awsAllowedAuthProviders,
AWSAssumeRoleEnabled: awsAssumeRoleEnabled, AWSAssumeRoleEnabled: awsAssumeRoleEnabled,
AWSExternalId: awsExternalId, AWSExternalId: awsExternalId,

View File

@ -46,6 +46,7 @@ func ProvideConfig(settingProvider setting.Provider, grafanaCfg *setting.Cfg, fe
features, features,
grafanaCfg.AngularSupportEnabled, grafanaCfg.AngularSupportEnabled,
grafanaCfg.GrafanaComURL, grafanaCfg.GrafanaComURL,
grafanaCfg.DisablePlugins,
), nil ), nil
} }

View File

@ -30,6 +30,9 @@ func ProvideDiscoveryStage(cfg *config.Cfg, pf finder.Finder, pr registry.Servic
func(ctx context.Context, _ plugins.Class, b []*plugins.FoundBundle) ([]*plugins.FoundBundle, error) { func(ctx context.Context, _ plugins.Class, b []*plugins.FoundBundle) ([]*plugins.FoundBundle, error) {
return discovery.NewDuplicatePluginFilterStep(pr).Filter(ctx, b) return discovery.NewDuplicatePluginFilterStep(pr).Filter(ctx, b)
}, },
func(_ context.Context, _ plugins.Class, b []*plugins.FoundBundle) ([]*plugins.FoundBundle, error) {
return NewDisablePluginsStep(cfg).Filter(b)
},
}, },
}) })
} }

View File

@ -121,3 +121,39 @@ func (v *SignatureValidation) Validate(ctx context.Context, p *plugins.Plugin) e
return nil return nil
} }
// DisablePlugins is a filter step that will filter out any configured plugins
type DisablePlugins struct {
log log.Logger
cfg *config.Cfg
}
// NewDisablePluginsStep returns a new DisablePlugins.
func NewDisablePluginsStep(cfg *config.Cfg) *DisablePlugins {
return &DisablePlugins{
cfg: cfg,
log: log.New("plugins.disable"),
}
}
// Filter will filter out any plugins that are marked to be disabled.
func (c *DisablePlugins) Filter(bundles []*plugins.FoundBundle) ([]*plugins.FoundBundle, error) {
if len(c.cfg.DisablePlugins) == 0 {
return bundles, nil
}
disablePluginsMap := make(map[string]bool)
for _, pluginID := range c.cfg.DisablePlugins {
disablePluginsMap[pluginID] = true
}
res := []*plugins.FoundBundle{}
for _, bundle := range bundles {
if disablePluginsMap[bundle.Primary.JSONData.ID] {
c.log.Debug("Disabling plugin load", "pluginID", bundle.Primary.JSONData.ID)
} else {
res = append(res, bundle)
}
}
return res, nil
}

View File

@ -0,0 +1,45 @@
package pipeline
import (
"testing"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/config"
"github.com/stretchr/testify/require"
)
func TestSkipPlugins(t *testing.T) {
cfg := &config.Cfg{
DisablePlugins: []string{"plugin1", "plugin2"},
}
s := NewDisablePluginsStep(cfg)
bundles := []*plugins.FoundBundle{
{
Primary: plugins.FoundPlugin{
JSONData: plugins.JSONData{
ID: "plugin1",
},
},
},
{
Primary: plugins.FoundPlugin{
JSONData: plugins.JSONData{
ID: "plugin2",
},
},
},
{
Primary: plugins.FoundPlugin{
JSONData: plugins.JSONData{
ID: "plugin3",
},
},
},
}
filtered, err := s.Filter(bundles)
require.NoError(t, err)
require.Len(t, filtered, 1)
require.Equal(t, filtered[0].Primary.JSONData.ID, "plugin3")
}

View File

@ -243,6 +243,7 @@ type Cfg struct {
PluginAdminExternalManageEnabled bool PluginAdminExternalManageEnabled bool
PluginForcePublicKeyDownload bool PluginForcePublicKeyDownload bool
PluginSkipPublicKeyDownload bool PluginSkipPublicKeyDownload bool
DisablePlugins []string
PluginsCDNURLTemplate string PluginsCDNURLTemplate string
PluginLogBackendRequests bool PluginLogBackendRequests bool

View File

@ -40,6 +40,14 @@ func (cfg *Cfg) readPluginSettings(iniFile *ini.File) error {
cfg.PluginsAllowUnsigned = append(cfg.PluginsAllowUnsigned, plug) cfg.PluginsAllowUnsigned = append(cfg.PluginsAllowUnsigned, plug)
} }
disablePlugins := pluginsSection.Key("disable_plugins").MustString("")
for _, plug := range strings.Split(disablePlugins, ",") {
plug = strings.TrimSpace(plug)
if plug != "" {
cfg.DisablePlugins = append(cfg.DisablePlugins, plug)
}
}
cfg.PluginCatalogURL = pluginsSection.Key("plugin_catalog_url").MustString("https://grafana.com/grafana/plugins/") cfg.PluginCatalogURL = pluginsSection.Key("plugin_catalog_url").MustString("https://grafana.com/grafana/plugins/")
cfg.PluginAdminEnabled = pluginsSection.Key("plugin_admin_enabled").MustBool(true) cfg.PluginAdminEnabled = pluginsSection.Key("plugin_admin_enabled").MustBool(true)
cfg.PluginAdminExternalManageEnabled = pluginsSection.Key("plugin_admin_external_manage_enabled").MustBool(false) cfg.PluginAdminExternalManageEnabled = pluginsSection.Key("plugin_admin_external_manage_enabled").MustBool(false)
@ -49,6 +57,8 @@ func (cfg *Cfg) readPluginSettings(iniFile *ini.File) error {
plug = strings.TrimSpace(plug) plug = strings.TrimSpace(plug)
cfg.PluginCatalogHiddenPlugins = append(cfg.PluginCatalogHiddenPlugins, plug) cfg.PluginCatalogHiddenPlugins = append(cfg.PluginCatalogHiddenPlugins, plug)
} }
// Pull disablep plugins from the catalog
cfg.PluginCatalogHiddenPlugins = append(cfg.PluginCatalogHiddenPlugins, cfg.DisablePlugins...)
// Plugins CDN settings // Plugins CDN settings
cfg.PluginsCDNURLTemplate = strings.TrimRight(pluginsSection.Key("cdn_base_url").MustString(""), "/") cfg.PluginsCDNURLTemplate = strings.TrimRight(pluginsSection.Key("cdn_base_url").MustString(""), "/")

View File

@ -41,3 +41,20 @@ func TestPluginSettings(t *testing.T) {
require.Equal(t, ps["plugin2"]["key3"], "value3") require.Equal(t, ps["plugin2"]["key3"], "value3")
require.Equal(t, ps["plugin2"]["key4"], "value4") require.Equal(t, ps["plugin2"]["key4"], "value4")
} }
func Test_readPluginSettings(t *testing.T) {
t.Run("should parse disable_plugins", func(t *testing.T) {
cfg := NewCfg()
sec, err := cfg.Raw.NewSection("plugins")
require.NoError(t, err)
_, err = sec.NewKey("disable_plugins", "plugin1,plugin2")
require.NoError(t, err)
_, err = sec.NewKey("plugin_catalog_hidden_plugins", "plugin3")
require.NoError(t, err)
err = cfg.readPluginSettings(cfg.Raw)
require.NoError(t, err)
require.Equal(t, []string{"plugin1", "plugin2"}, cfg.DisablePlugins)
require.Equal(t, []string{"plugin3", "plugin1", "plugin2"}, cfg.PluginCatalogHiddenPlugins)
})
}