diff --git a/conf/defaults.ini b/conf/defaults.ini
index b5d12b62f38..bacb8195eb8 100644
--- a/conf/defaults.ini
+++ b/conf/defaults.ini
@@ -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.
# Requires public_key_retrieval_disabled to be false to have any effect.
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 ##########################################
[live]
diff --git a/conf/sample.ini b/conf/sample.ini
index f9c7703429c..e70d3a978a0 100644
--- a/conf/sample.ini
+++ b/conf/sample.ini
@@ -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.
# Requires public_key_retrieval_disabled to be false to have any effect.
; 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 ##########################################
[live]
diff --git a/docs/sources/setup-grafana/configure-grafana/_index.md b/docs/sources/setup-grafana/configure-grafana/_index.md
index 1477e3b510d..79ca5a1bc9d 100644
--- a/docs/sources/setup-grafana/configure-grafana/_index.md
+++ b/docs/sources/setup-grafana/configure-grafana/_index.md
@@ -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.
+### disable_plugins
+
+Enter a comma-separated list of plugin identifiers to avoid loading (including core plugins). These plugins will be hidden in the catalog.
+
## [live]
diff --git a/pkg/plugins/backendplugin/errors.go b/pkg/plugins/backendplugin/errors.go
index 59067ce29c3..b7395586c45 100644
--- a/pkg/plugins/backendplugin/errors.go
+++ b/pkg/plugins/backendplugin/errors.go
@@ -1,8 +1,6 @@
package backendplugin
-import (
- "errors"
-)
+import "errors"
var (
// ErrPluginNotRegistered error returned when plugin is not registered.
diff --git a/pkg/plugins/config/config.go b/pkg/plugins/config/config.go
index 3c849754084..905349bfb81 100644
--- a/pkg/plugins/config/config.go
+++ b/pkg/plugins/config/config.go
@@ -17,6 +17,7 @@ type Cfg struct {
PluginSettings setting.PluginSettings
PluginsAllowUnsigned []string
+ DisablePlugins []string
// AWS Plugin Auth
AWSAllowedAuthProviders []string
@@ -50,7 +51,7 @@ type Cfg struct {
func NewCfg(devMode bool, pluginsPath string, pluginSettings setting.PluginSettings, pluginsAllowUnsigned []string,
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,
- grafanaComURL string) *Cfg {
+ grafanaComURL string, disablePlugins []string) *Cfg {
return &Cfg{
log: log.New("plugin.cfg"),
PluginsPath: pluginsPath,
@@ -58,6 +59,7 @@ func NewCfg(devMode bool, pluginsPath string, pluginSettings setting.PluginSetti
DevMode: devMode,
PluginSettings: pluginSettings,
PluginsAllowUnsigned: pluginsAllowUnsigned,
+ DisablePlugins: disablePlugins,
AWSAllowedAuthProviders: awsAllowedAuthProviders,
AWSAssumeRoleEnabled: awsAssumeRoleEnabled,
AWSExternalId: awsExternalId,
diff --git a/pkg/services/pluginsintegration/config/config.go b/pkg/services/pluginsintegration/config/config.go
index 590b0e7826c..823e8f89ebf 100644
--- a/pkg/services/pluginsintegration/config/config.go
+++ b/pkg/services/pluginsintegration/config/config.go
@@ -46,6 +46,7 @@ func ProvideConfig(settingProvider setting.Provider, grafanaCfg *setting.Cfg, fe
features,
grafanaCfg.AngularSupportEnabled,
grafanaCfg.GrafanaComURL,
+ grafanaCfg.DisablePlugins,
), nil
}
diff --git a/pkg/services/pluginsintegration/pipeline/pipeline.go b/pkg/services/pluginsintegration/pipeline/pipeline.go
index 86fac1193a8..2656bf5936c 100644
--- a/pkg/services/pluginsintegration/pipeline/pipeline.go
+++ b/pkg/services/pluginsintegration/pipeline/pipeline.go
@@ -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) {
return discovery.NewDuplicatePluginFilterStep(pr).Filter(ctx, b)
},
+ func(_ context.Context, _ plugins.Class, b []*plugins.FoundBundle) ([]*plugins.FoundBundle, error) {
+ return NewDisablePluginsStep(cfg).Filter(b)
+ },
},
})
}
diff --git a/pkg/services/pluginsintegration/pipeline/steps.go b/pkg/services/pluginsintegration/pipeline/steps.go
index 47c9b60ed04..34b4eef139b 100644
--- a/pkg/services/pluginsintegration/pipeline/steps.go
+++ b/pkg/services/pluginsintegration/pipeline/steps.go
@@ -121,3 +121,39 @@ func (v *SignatureValidation) Validate(ctx context.Context, p *plugins.Plugin) e
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
+}
diff --git a/pkg/services/pluginsintegration/pipeline/steps_test.go b/pkg/services/pluginsintegration/pipeline/steps_test.go
new file mode 100644
index 00000000000..0b4f1b3f0b2
--- /dev/null
+++ b/pkg/services/pluginsintegration/pipeline/steps_test.go
@@ -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")
+}
diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go
index 57cbfff3f07..d23707f852c 100644
--- a/pkg/setting/setting.go
+++ b/pkg/setting/setting.go
@@ -243,6 +243,7 @@ type Cfg struct {
PluginAdminExternalManageEnabled bool
PluginForcePublicKeyDownload bool
PluginSkipPublicKeyDownload bool
+ DisablePlugins []string
PluginsCDNURLTemplate string
PluginLogBackendRequests bool
diff --git a/pkg/setting/setting_plugins.go b/pkg/setting/setting_plugins.go
index 8eaaf1f8f04..29b8e9102b1 100644
--- a/pkg/setting/setting_plugins.go
+++ b/pkg/setting/setting_plugins.go
@@ -40,6 +40,14 @@ func (cfg *Cfg) readPluginSettings(iniFile *ini.File) error {
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.PluginAdminEnabled = pluginsSection.Key("plugin_admin_enabled").MustBool(true)
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)
cfg.PluginCatalogHiddenPlugins = append(cfg.PluginCatalogHiddenPlugins, plug)
}
+ // Pull disablep plugins from the catalog
+ cfg.PluginCatalogHiddenPlugins = append(cfg.PluginCatalogHiddenPlugins, cfg.DisablePlugins...)
// Plugins CDN settings
cfg.PluginsCDNURLTemplate = strings.TrimRight(pluginsSection.Key("cdn_base_url").MustString(""), "/")
diff --git a/pkg/setting/setting_plugins_test.go b/pkg/setting/setting_plugins_test.go
index 7b666dea6f8..781cdfbb05e 100644
--- a/pkg/setting/setting_plugins_test.go
+++ b/pkg/setting/setting_plugins_test.go
@@ -41,3 +41,20 @@ func TestPluginSettings(t *testing.T) {
require.Equal(t, ps["plugin2"]["key3"], "value3")
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)
+ })
+}