Preinstall: Replace auto update feature flag with a permanent one (#113586)

This commit is contained in:
Andres Martinez Gotor
2025-11-10 15:06:30 +01:00
committed by GitHub
parent 9a542489a7
commit 1a2beae38a
19 changed files with 74 additions and 77 deletions
+3
View File
@@ -1934,6 +1934,9 @@ preinstall_disabled = false
# Update strategy for plugins.
# Available options: "latest", "minor"
update_strategy = minor
# Enable automatic updates for preinstalled plugins on startup.
# When enabled, preinstalled plugins without a pinned version will be updated to the latest version.
preinstall_auto_update = true
#################################### Grafana Live ##########################################
[live]
@@ -2622,6 +2622,15 @@ These will be installed before starting Grafana. Useful when used with provision
This option disables all preinstalled plugins. The default is `false`. To disable a specific plugin from being preinstalled, use the `disable_plugins` option.
#### `preinstall_auto_update`
Enable automatic updates for preinstalled plugins on start-up.
When enabled, preinstalled plugins without a pinned version are automatically updated to the latest version when Grafana starts.
The default is `true`.
To prevent automatic updates for specific plugins, pin them to a specific version using the format `plugin_id@version` in the `preinstall` setting.
<hr>
### `[live]`
@@ -66,7 +66,6 @@ Most [generally available](https://grafana.com/docs/release-life-cycle/#general-
| `useSessionStorageForRedirection` | Use session storage for handling the redirection after login | Yes |
| `pluginsSriChecks` | Enables SRI checks for plugin assets | |
| `azureMonitorDisableLogLimit` | Disables the log limit restriction for Azure Monitor when true. The limit is enabled by default. | |
| `preinstallAutoUpdate` | Enables automatic updates for pre-installed plugins | Yes |
| `alertingUIOptimizeReducer` | Enables removing the reducer from the alerting UI when creating a new alert rule and using instant query | Yes |
| `azureMonitorEnableUserAuth` | Enables user auth for Azure Monitor datasource only | Yes |
| `alertingNotificationsStepMode` | Enables simplified step mode in the notifications section | Yes |
@@ -311,6 +311,7 @@ export interface GrafanaConfig {
pluginCatalogHiddenPlugins: string[];
pluginCatalogManagedPlugins: string[];
pluginCatalogPreinstalledPlugins: PreinstalledPlugin[];
pluginCatalogPreinstalledAutoUpdate?: boolean;
pluginsCDNBaseURL: string;
tokenExpirationDayLimit: number;
listDashboardScopesEndpoint: string;
-5
View File
@@ -733,11 +733,6 @@ export interface FeatureToggles {
*/
azureMonitorDisableLogLimit?: boolean;
/**
* Enables automatic updates for pre-installed plugins
* @default true
*/
preinstallAutoUpdate?: boolean;
/**
* Enables experimental reconciler for playlists
*/
playlistsReconciler?: boolean;
+1
View File
@@ -169,6 +169,7 @@ export class GrafanaBootConfig {
pluginCatalogHiddenPlugins: string[] = [];
pluginCatalogManagedPlugins: string[] = [];
pluginCatalogPreinstalledPlugins: PreinstalledPluginGrafanaData[] = [];
pluginCatalogPreinstalledAutoUpdate?: boolean;
pluginsCDNBaseURL = '';
expressionsEnabled = false;
awsAllowedAuthProviders: string[] = [];
+24 -23
View File
@@ -235,29 +235,30 @@ type FrontendSettingsDTO struct {
LicenseInfo FrontendSettingsLicenseInfoDTO `json:"licenseInfo"`
FeatureToggles map[string]bool `json:"featureToggles"`
AnonymousEnabled bool `json:"anonymousEnabled"`
AnonymousDeviceLimit int64 `json:"anonymousDeviceLimit"`
RendererAvailable bool `json:"rendererAvailable"`
RendererVersion string `json:"rendererVersion"`
RendererDefaultImageWidth int `json:"rendererDefaultImageWidth"`
RendererDefaultImageHeight int `json:"rendererDefaultImageHeight"`
RendererDefaultImageScale float64 `json:"rendererDefaultImageScale"`
Http2Enabled bool `json:"http2Enabled"`
GrafanaJavascriptAgent setting.GrafanaJavascriptAgent `json:"grafanaJavascriptAgent"`
PluginCatalogURL string `json:"pluginCatalogURL"`
PluginAdminEnabled bool `json:"pluginAdminEnabled"`
PluginAdminExternalManageEnabled bool `json:"pluginAdminExternalManageEnabled"`
PluginCatalogHiddenPlugins []string `json:"pluginCatalogHiddenPlugins"`
PluginCatalogManagedPlugins []string `json:"pluginCatalogManagedPlugins"`
PluginCatalogPreinstalledPlugins []setting.InstallPlugin `json:"pluginCatalogPreinstalledPlugins"`
ExpressionsEnabled bool `json:"expressionsEnabled"`
AwsAllowedAuthProviders []string `json:"awsAllowedAuthProviders"`
AwsAssumeRoleEnabled bool `json:"awsAssumeRoleEnabled"`
SupportBundlesEnabled bool `json:"supportBundlesEnabled"`
SnapshotEnabled bool `json:"snapshotEnabled"`
SecureSocksDSProxyEnabled bool `json:"secureSocksDSProxyEnabled"`
ReportingStaticContext map[string]string `json:"reportingStaticContext"`
FeatureToggles map[string]bool `json:"featureToggles"`
AnonymousEnabled bool `json:"anonymousEnabled"`
AnonymousDeviceLimit int64 `json:"anonymousDeviceLimit"`
RendererAvailable bool `json:"rendererAvailable"`
RendererVersion string `json:"rendererVersion"`
RendererDefaultImageWidth int `json:"rendererDefaultImageWidth"`
RendererDefaultImageHeight int `json:"rendererDefaultImageHeight"`
RendererDefaultImageScale float64 `json:"rendererDefaultImageScale"`
Http2Enabled bool `json:"http2Enabled"`
GrafanaJavascriptAgent setting.GrafanaJavascriptAgent `json:"grafanaJavascriptAgent"`
PluginCatalogURL string `json:"pluginCatalogURL"`
PluginAdminEnabled bool `json:"pluginAdminEnabled"`
PluginAdminExternalManageEnabled bool `json:"pluginAdminExternalManageEnabled"`
PluginCatalogHiddenPlugins []string `json:"pluginCatalogHiddenPlugins"`
PluginCatalogManagedPlugins []string `json:"pluginCatalogManagedPlugins"`
PluginCatalogPreinstalledPlugins []setting.InstallPlugin `json:"pluginCatalogPreinstalledPlugins"`
PluginCatalogPreinstalledAutoUpdate bool `json:"pluginCatalogPreinstalledAutoUpdate"`
ExpressionsEnabled bool `json:"expressionsEnabled"`
AwsAllowedAuthProviders []string `json:"awsAllowedAuthProviders"`
AwsAssumeRoleEnabled bool `json:"awsAssumeRoleEnabled"`
SupportBundlesEnabled bool `json:"supportBundlesEnabled"`
SnapshotEnabled bool `json:"snapshotEnabled"`
SecureSocksDSProxyEnabled bool `json:"secureSocksDSProxyEnabled"`
ReportingStaticContext map[string]string `json:"reportingStaticContext"`
Azure FrontendSettingsAzureDTO `json:"azure"`
+21 -20
View File
@@ -290,26 +290,27 @@ func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.Fro
EnabledFeatures: hs.License.EnabledFeatures(),
},
FeatureToggles: featureToggles,
AnonymousEnabled: hs.Cfg.Anonymous.Enabled,
AnonymousDeviceLimit: hs.Cfg.Anonymous.DeviceLimit,
RendererAvailable: hs.RenderService.IsAvailable(c.Req.Context()),
RendererVersion: hs.RenderService.Version(),
RendererDefaultImageWidth: hs.Cfg.RendererDefaultImageWidth,
RendererDefaultImageHeight: hs.Cfg.RendererDefaultImageHeight,
RendererDefaultImageScale: hs.Cfg.RendererDefaultImageScale,
Http2Enabled: hs.Cfg.Protocol == setting.HTTP2Scheme,
GrafanaJavascriptAgent: hs.Cfg.GrafanaJavascriptAgent,
PluginCatalogURL: hs.Cfg.PluginCatalogURL,
PluginAdminEnabled: hs.Cfg.PluginAdminEnabled,
PluginAdminExternalManageEnabled: hs.Cfg.PluginAdminEnabled && hs.Cfg.PluginAdminExternalManageEnabled,
PluginCatalogHiddenPlugins: hs.Cfg.PluginCatalogHiddenPlugins,
PluginCatalogManagedPlugins: hs.managedPluginsService.ManagedPlugins(c.Req.Context()),
PluginCatalogPreinstalledPlugins: append(hs.Cfg.PreinstallPluginsAsync, hs.Cfg.PreinstallPluginsSync...),
ExpressionsEnabled: hs.Cfg.ExpressionsEnabled,
AwsAllowedAuthProviders: hs.Cfg.AWSAllowedAuthProviders,
AwsAssumeRoleEnabled: hs.Cfg.AWSAssumeRoleEnabled,
SupportBundlesEnabled: isSupportBundlesEnabled(hs),
FeatureToggles: featureToggles,
AnonymousEnabled: hs.Cfg.Anonymous.Enabled,
AnonymousDeviceLimit: hs.Cfg.Anonymous.DeviceLimit,
RendererAvailable: hs.RenderService.IsAvailable(c.Req.Context()),
RendererVersion: hs.RenderService.Version(),
RendererDefaultImageWidth: hs.Cfg.RendererDefaultImageWidth,
RendererDefaultImageHeight: hs.Cfg.RendererDefaultImageHeight,
RendererDefaultImageScale: hs.Cfg.RendererDefaultImageScale,
Http2Enabled: hs.Cfg.Protocol == setting.HTTP2Scheme,
GrafanaJavascriptAgent: hs.Cfg.GrafanaJavascriptAgent,
PluginCatalogURL: hs.Cfg.PluginCatalogURL,
PluginAdminEnabled: hs.Cfg.PluginAdminEnabled,
PluginAdminExternalManageEnabled: hs.Cfg.PluginAdminEnabled && hs.Cfg.PluginAdminExternalManageEnabled,
PluginCatalogHiddenPlugins: hs.Cfg.PluginCatalogHiddenPlugins,
PluginCatalogManagedPlugins: hs.managedPluginsService.ManagedPlugins(c.Req.Context()),
PluginCatalogPreinstalledPlugins: append(hs.Cfg.PreinstallPluginsAsync, hs.Cfg.PreinstallPluginsSync...),
PluginCatalogPreinstalledAutoUpdate: hs.Cfg.PreinstallAutoUpdate,
ExpressionsEnabled: hs.Cfg.ExpressionsEnabled,
AwsAllowedAuthProviders: hs.Cfg.AWSAllowedAuthProviders,
AwsAssumeRoleEnabled: hs.Cfg.AWSAssumeRoleEnabled,
SupportBundlesEnabled: isSupportBundlesEnabled(hs),
Azure: dtos.FrontendSettingsAzureDTO{
Cloud: hs.Cfg.Azure.Cloud,
+2 -2
View File
@@ -817,7 +817,7 @@ func Initialize(ctx context.Context, cfg *setting.Cfg, opts Options, apiOpts api
if err != nil {
return nil, err
}
plugininstallerService, err := plugininstaller.ProvideService(cfg, pluginstoreService, pluginInstaller, registerer, repoManager, featureToggles, plugincheckerService)
plugininstallerService, err := plugininstaller.ProvideService(cfg, pluginstoreService, pluginInstaller, registerer, repoManager, plugincheckerService)
if err != nil {
return nil, err
}
@@ -1455,7 +1455,7 @@ func InitializeForTest(ctx context.Context, t sqlutil.ITestDB, testingT interfac
if err != nil {
return nil, err
}
plugininstallerService, err := plugininstaller.ProvideService(cfg, pluginstoreService, pluginInstaller, registerer, repoManager, featureToggles, plugincheckerService)
plugininstallerService, err := plugininstaller.ProvideService(cfg, pluginstoreService, pluginInstaller, registerer, repoManager, plugincheckerService)
if err != nil {
return nil, err
}
-7
View File
@@ -1261,13 +1261,6 @@ var (
Owner: grafanaPartnerPluginsSquad,
Expression: "false",
},
{
Name: "preinstallAutoUpdate",
Description: "Enables automatic updates for pre-installed plugins",
Stage: FeatureStageGeneralAvailability,
Owner: grafanaPluginsPlatformSquad,
Expression: "true", // enabled by default
},
{
Name: "playlistsReconciler",
Description: "Enables experimental reconciler for playlists",
-1
View File
@@ -165,7 +165,6 @@ unifiedStorageBigObjectsSupport,experimental,@grafana/search-and-storage,false,f
timeRangeProvider,experimental,@grafana/grafana-frontend-platform,false,false,false
timeRangePan,experimental,@grafana/dataviz-squad,false,false,true
azureMonitorDisableLogLimit,GA,@grafana/partner-datasources,false,false,false
preinstallAutoUpdate,GA,@grafana/plugins-platform-backend,false,false,false
playlistsReconciler,experimental,@grafana/grafana-app-platform-squad,false,true,false
passwordlessMagicLinkAuthentication,experimental,@grafana/identity-access-team,false,false,false
exploreMetricsRelatedLogs,experimental,@grafana/observability-metrics,false,false,true
1 Name Stage Owner requiresDevMode RequiresRestart FrontendOnly
165 timeRangeProvider experimental @grafana/grafana-frontend-platform false false false
166 timeRangePan experimental @grafana/dataviz-squad false false true
167 azureMonitorDisableLogLimit GA @grafana/partner-datasources false false false
preinstallAutoUpdate GA @grafana/plugins-platform-backend false false false
168 playlistsReconciler experimental @grafana/grafana-app-platform-squad false true false
169 passwordlessMagicLinkAuthentication experimental @grafana/identity-access-team false false false
170 exploreMetricsRelatedLogs experimental @grafana/observability-metrics false false true
-4
View File
@@ -671,10 +671,6 @@ const (
// Disables the log limit restriction for Azure Monitor when true. The limit is enabled by default.
FlagAzureMonitorDisableLogLimit = "azureMonitorDisableLogLimit"
// FlagPreinstallAutoUpdate
// Enables automatic updates for pre-installed plugins
FlagPreinstallAutoUpdate = "preinstallAutoUpdate"
// FlagPlaylistsReconciler
// Enables experimental reconciler for playlists
FlagPlaylistsReconciler = "playlistsReconciler"
+2 -1
View File
@@ -3158,7 +3158,8 @@
"metadata": {
"name": "preinstallAutoUpdate",
"resourceVersion": "1753448760331",
"creationTimestamp": "2024-11-07T12:14:25Z"
"creationTimestamp": "2024-11-07T12:14:25Z",
"deletionTimestamp": "2025-11-07T10:10:01Z"
},
"spec": {
"description": "Enables automatic updates for pre-installed plugins",
@@ -12,7 +12,6 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/repo"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginchecker"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
"github.com/grafana/grafana/pkg/setting"
@@ -45,7 +44,6 @@ type Service struct {
pluginInstaller plugins.Installer
pluginStore pluginstore.Store
pluginRepo repo.Service
features featuremgmt.FeatureToggles
updateChecker pluginchecker.PluginUpdateChecker
installComplete chan struct{} // closed when all plugins are installed (used for testing)
}
@@ -56,7 +54,6 @@ func ProvideService(
pluginInstaller plugins.Installer,
promReg prometheus.Registerer,
pluginRepo repo.Service,
features featuremgmt.FeatureToggles,
updateChecker pluginchecker.PluginUpdateChecker,
) (*Service, error) {
once.Do(func() {
@@ -70,7 +67,6 @@ func ProvideService(
pluginInstaller: pluginInstaller,
pluginStore: pluginStore,
pluginRepo: pluginRepo,
features: features,
updateChecker: updateChecker,
installComplete: make(chan struct{}),
}
@@ -111,8 +107,8 @@ func (s *Service) installPlugins(ctx context.Context, pluginsToInstall []setting
continue
}
if installPlugin.Version == "" {
if !s.features.IsEnabled(ctx, featuremgmt.FlagPreinstallAutoUpdate) {
// Skip updating the plugin if the feature flag is disabled
if !s.cfg.PreinstallAutoUpdate {
// Skip updating the plugin if auto-update is disabled
continue
}
// The plugin is installed but it's not pinned to a specific version
@@ -9,7 +9,6 @@ import (
"github.com/grafana/grafana/pkg/plugins/manager/pluginfakes"
"github.com/grafana/grafana/pkg/plugins/manager/registry"
"github.com/grafana/grafana/pkg/plugins/repo"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/pluginsintegration/installsync/installsyncfakes"
"github.com/grafana/grafana/pkg/services/pluginsintegration/managedplugins"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginchecker"
@@ -31,7 +30,6 @@ func TestService_IsDisabled(t *testing.T) {
&pluginfakes.FakePluginInstaller{},
prometheus.NewRegistry(),
&pluginfakes.FakePluginRepo{},
featuremgmt.WithFeatures(),
&pluginchecker.FakePluginUpdateChecker{},
)
require.NoError(t, err)
@@ -167,6 +165,7 @@ func TestService_Run(t *testing.T) {
&setting.Cfg{
PreinstallPluginsAsync: tt.pluginsToInstall,
PreinstallPluginsSync: tt.pluginsToInstallSync,
PreinstallAutoUpdate: true,
},
store,
&pluginfakes.FakePluginInstaller{
@@ -199,7 +198,6 @@ func TestService_Run(t *testing.T) {
return tt.latestPlugin, nil
},
},
featuremgmt.WithFeatures(featuremgmt.FlagPreinstallAutoUpdate),
pluginchecker.ProvideService(
managedplugins.NewNoop(),
provisionedplugins.NewNoop(),
+1
View File
@@ -215,6 +215,7 @@ type Cfg struct {
ForwardHostEnvVars []string
PreinstallPluginsAsync []InstallPlugin
PreinstallPluginsSync []InstallPlugin
PreinstallAutoUpdate bool
PluginsCDNURLTemplate string
PluginLogBackendRequests bool
+2
View File
@@ -185,6 +185,8 @@ func (cfg *Cfg) readPluginSettings(iniFile *ini.File) error {
}
cfg.PreinstallPluginsAsync = nil
}
cfg.PreinstallAutoUpdate = pluginsSection.Key("preinstall_auto_update").MustBool(true)
}
cfg.PluginCatalogURL = pluginsSection.Key("plugin_catalog_url").MustString("https://grafana.com/grafana/plugins/")
@@ -15,6 +15,7 @@ describe('VersionInstallButton', () => {
...originalConfig.featureToggles,
};
config.pluginCatalogPreinstalledPlugins = originalConfig.pluginCatalogPreinstalledPlugins;
config.pluginCatalogPreinstalledAutoUpdate = originalConfig.pluginCatalogPreinstalledAutoUpdate;
});
it('should show install when no version is installed', () => {
const version: Version = {
@@ -120,7 +121,7 @@ describe('VersionInstallButton', () => {
grafanaDependency: null,
};
const installedVersion = '1.0.0';
config.featureToggles.preinstallAutoUpdate = true;
config.pluginCatalogPreinstalledAutoUpdate = true;
config.pluginCatalogPreinstalledPlugins = [{ id: 'test', version: '1.0.0' }];
renderWithStore(
<VersionInstallButton
@@ -142,7 +143,7 @@ describe('VersionInstallButton', () => {
grafanaDependency: null,
};
const installedVersion = '1.0.1';
config.featureToggles.preinstallAutoUpdate = true;
config.pluginCatalogPreinstalledAutoUpdate = true;
config.pluginCatalogPreinstalledPlugins = [{ id: 'test', version: '1.0.1' }];
renderWithStore(
<VersionInstallButton
@@ -164,7 +165,7 @@ describe('VersionInstallButton', () => {
grafanaDependency: null,
};
const installedVersion = '1.0.1';
config.featureToggles.preinstallAutoUpdate = true;
config.pluginCatalogPreinstalledAutoUpdate = true;
config.pluginCatalogPreinstalledPlugins = [{ id: 'test', version: '' }];
renderWithStore(
<VersionInstallButton
@@ -174,7 +174,7 @@ function getButtonHiddenState(installState: PluginStatus, isPreinstalled: { foun
// Handle downgrade case
if (installState === PluginStatus.DOWNGRADE) {
return isPreinstalled.found && Boolean(config.featureToggles.preinstallAutoUpdate);
return isPreinstalled.found && Boolean(config.pluginCatalogPreinstalledAutoUpdate);
}
// Handle upgrade case