diff --git a/pkg/api/alerting.go b/pkg/api/alerting.go index d36222678a5..6cc3a5c91ee 100644 --- a/pkg/api/alerting.go +++ b/pkg/api/alerting.go @@ -20,7 +20,6 @@ import ( "github.com/grafana/grafana/pkg/services/notifications" "github.com/grafana/grafana/pkg/services/search" "github.com/grafana/grafana/pkg/services/search/model" - "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/web" ) @@ -522,7 +521,7 @@ func (hs *HTTPServer) fillWithSecureSettingsData(ctx context.Context, cmd *alert return err } - secureSettings, err := hs.EncryptionService.DecryptJsonData(ctx, res.SecureSettings, setting.SecretKey) + secureSettings, err := hs.EncryptionService.DecryptJsonData(ctx, res.SecureSettings, hs.Cfg.SecretKey) if err != nil { return err } @@ -551,7 +550,7 @@ func (hs *HTTPServer) fillWithSecureSettingsDataByUID(ctx context.Context, cmd * return err } - secureSettings, err := hs.EncryptionService.DecryptJsonData(ctx, res.SecureSettings, setting.SecretKey) + secureSettings, err := hs.EncryptionService.DecryptJsonData(ctx, res.SecureSettings, hs.Cfg.SecretKey) if err != nil { return err } diff --git a/pkg/api/annotations.go b/pkg/api/annotations.go index 79237b4dbd9..aae4d96ddb5 100644 --- a/pkg/api/annotations.go +++ b/pkg/api/annotations.go @@ -69,7 +69,7 @@ func (hs *HTTPServer) GetAnnotations(c *contextmodel.ReqContext) response.Respon dashboardCache := make(map[int64]*string) for _, item := range items { if item.Email != "" { - item.AvatarURL = dtos.GetGravatarUrl(item.Email) + item.AvatarURL = dtos.GetGravatarUrl(hs.Cfg, item.Email) } if item.DashboardID != 0 { @@ -485,7 +485,7 @@ func (hs *HTTPServer) GetAnnotationByID(c *contextmodel.ReqContext) response.Res } if annotation.Email != "" { - annotation.AvatarURL = dtos.GetGravatarUrl(annotation.Email) + annotation.AvatarURL = dtos.GetGravatarUrl(hs.Cfg, annotation.Email) } return response.JSON(200, annotation) diff --git a/pkg/api/api.go b/pkg/api/api.go index df5cca6946a..8ef843e5676 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -46,7 +46,6 @@ import ( publicdashboardsapi "github.com/grafana/grafana/pkg/services/publicdashboards/api" "github.com/grafana/grafana/pkg/services/serviceaccounts" "github.com/grafana/grafana/pkg/services/user" - "github.com/grafana/grafana/pkg/setting" ) var plog = log.New("api") @@ -511,7 +510,7 @@ func (hs *HTTPServer) registerRoutes() { apiRoute.Group("/alerts", func(alertsRoute routing.RouteRegister) { alertsRoute.Post("/test", routing.Wrap(hs.AlertTest)) - alertsRoute.Post("/:alertId/pause", reqEditorRole, routing.Wrap(hs.PauseAlert(setting.AlertingEnabled))) + alertsRoute.Post("/:alertId/pause", reqEditorRole, routing.Wrap(hs.PauseAlert(hs.Cfg.AlertingEnabled))) alertsRoute.Get("/:alertId", hs.ValidateOrgAlert, routing.Wrap(hs.GetAlert)) alertsRoute.Get("/", routing.Wrap(hs.GetAlerts)) alertsRoute.Get("/states-for-dashboard", routing.Wrap(hs.GetAlertStatesForDashboard)) @@ -583,7 +582,7 @@ func (hs *HTTPServer) registerRoutes() { adminRoute.Get("/settings", authorize(ac.EvalPermission(ac.ActionSettingsRead)), routing.Wrap(hs.AdminGetSettings)) adminRoute.Get("/settings-verbose", authorize(ac.EvalPermission(ac.ActionSettingsRead)), routing.Wrap(hs.AdminGetVerboseSettings)) adminRoute.Get("/stats", authorize(ac.EvalPermission(ac.ActionServerStatsRead)), routing.Wrap(hs.AdminGetStats)) - adminRoute.Post("/pause-all-alerts", reqGrafanaAdmin, routing.Wrap(hs.PauseAllAlerts(setting.AlertingEnabled))) + adminRoute.Post("/pause-all-alerts", reqGrafanaAdmin, routing.Wrap(hs.PauseAllAlerts(hs.Cfg.AlertingEnabled))) adminRoute.Post("/encryption/rotate-data-keys", reqGrafanaAdmin, routing.Wrap(hs.AdminRotateDataEncryptionKeys)) adminRoute.Post("/encryption/reencrypt-data-keys", reqGrafanaAdmin, routing.Wrap(hs.AdminReEncryptEncryptionKeys)) diff --git a/pkg/api/avatar/avatar.go b/pkg/api/avatar/avatar.go index d331cee8664..864d6187af0 100644 --- a/pkg/api/avatar/avatar.go +++ b/pkg/api/avatar/avatar.go @@ -107,7 +107,7 @@ func (a *AvatarCacheServer) Handler(ctx *contextmodel.ReqContext) { return } - avatar := a.GetAvatarForHash(hash) + avatar := a.GetAvatarForHash(a.cfg, hash) ctx.Resp.Header().Set("Content-Type", "image/jpeg") @@ -123,8 +123,8 @@ func (a *AvatarCacheServer) Handler(ctx *contextmodel.ReqContext) { } } -func (a *AvatarCacheServer) GetAvatarForHash(hash string) *Avatar { - if setting.DisableGravatar { +func (a *AvatarCacheServer) GetAvatarForHash(cfg *setting.Cfg, hash string) *Avatar { + if cfg.DisableGravatar { alog.Warn("'GetGravatarForHash' called despite gravatars being disabled; returning default profile image") return a.notFound } diff --git a/pkg/api/dashboard_permission.go b/pkg/api/dashboard_permission.go index c4fa0c04114..88e6cb826ab 100644 --- a/pkg/api/dashboard_permission.go +++ b/pkg/api/dashboard_permission.go @@ -69,10 +69,10 @@ func (hs *HTTPServer) GetDashboardPermissionList(c *contextmodel.ReqContext) res continue } - perm.UserAvatarURL = dtos.GetGravatarUrl(perm.UserEmail) + perm.UserAvatarURL = dtos.GetGravatarUrl(hs.Cfg, perm.UserEmail) if perm.TeamID > 0 { - perm.TeamAvatarURL = dtos.GetGravatarUrlWithDefault(perm.TeamEmail, perm.Team) + perm.TeamAvatarURL = dtos.GetGravatarUrlWithDefault(hs.Cfg, perm.TeamEmail, perm.Team) } if perm.Slug != "" { perm.URL = dashboards.GetDashboardFolderURL(perm.IsFolder, perm.UID, perm.Slug) diff --git a/pkg/api/dtos/models.go b/pkg/api/dtos/models.go index 64e868239a7..c0291f65c30 100644 --- a/pkg/api/dtos/models.go +++ b/pkg/api/dtos/models.go @@ -108,9 +108,9 @@ func (mr *MetricRequest) CloneWithQueries(queries []*simplejson.Json) MetricRequ } } -func GetGravatarUrl(text string) string { - if setting.DisableGravatar { - return setting.AppSubUrl + "/public/img/user_profile.png" +func GetGravatarUrl(cfg *setting.Cfg, text string) string { + if cfg.DisableGravatar { + return cfg.AppSubURL + "/public/img/user_profile.png" } if text == "" { @@ -118,7 +118,7 @@ func GetGravatarUrl(text string) string { } hash, _ := GetGravatarHash(text) - return fmt.Sprintf(setting.AppSubUrl+"/avatar/%x", hash) + return fmt.Sprintf(cfg.AppSubURL+"/avatar/%x", hash) } func GetGravatarHash(text string) ([]byte, bool) { @@ -133,14 +133,14 @@ func GetGravatarHash(text string) ([]byte, bool) { return hasher.Sum(nil), true } -func GetGravatarUrlWithDefault(text string, defaultText string) string { +func GetGravatarUrlWithDefault(cfg *setting.Cfg, text string, defaultText string) string { if text != "" { - return GetGravatarUrl(text) + return GetGravatarUrl(cfg, text) } text = regNonAlphaNumeric.ReplaceAllString(defaultText, "") + "@localhost" - return GetGravatarUrl(text) + return GetGravatarUrl(cfg, text) } func IsHiddenUser(userLogin string, signedInUser identity.Requester, cfg *setting.Cfg) bool { diff --git a/pkg/api/folder_bench_test.go b/pkg/api/folder_bench_test.go index dd7a39289d4..83f326e1d49 100644 --- a/pkg/api/folder_bench_test.go +++ b/pkg/api/folder_bench_test.go @@ -451,11 +451,12 @@ func setupServer(b testing.TB, sc benchScenario, features featuremgmt.FeatureTog ac := acimpl.ProvideAccessControl(sc.cfg) folderServiceWithFlagOn := folderimpl.ProvideService(ac, bus.ProvideBus(tracing.InitializeTracerForTest()), sc.cfg, dashStore, folderStore, sc.db, features, nil) + cfg := setting.NewCfg() folderPermissions, err := ossaccesscontrol.ProvideFolderPermissions( - features, routing.NewRouteRegister(), sc.db, ac, license, &dashboards.FakeDashboardStore{}, folderServiceWithFlagOn, acSvc, sc.teamSvc, sc.userSvc) + cfg, features, routing.NewRouteRegister(), sc.db, ac, license, &dashboards.FakeDashboardStore{}, folderServiceWithFlagOn, acSvc, sc.teamSvc, sc.userSvc) require.NoError(b, err) dashboardPermissions, err := ossaccesscontrol.ProvideDashboardPermissions( - features, routing.NewRouteRegister(), sc.db, ac, license, &dashboards.FakeDashboardStore{}, folderServiceWithFlagOn, acSvc, sc.teamSvc, sc.userSvc) + cfg, features, routing.NewRouteRegister(), sc.db, ac, license, &dashboards.FakeDashboardStore{}, folderServiceWithFlagOn, acSvc, sc.teamSvc, sc.userSvc) require.NoError(b, err) dashboardSvc, err := dashboardservice.ProvideDashboardServiceImpl( diff --git a/pkg/api/folder_permission.go b/pkg/api/folder_permission.go index 10e34c3ffe7..08f6f76ad21 100644 --- a/pkg/api/folder_permission.go +++ b/pkg/api/folder_permission.go @@ -50,10 +50,10 @@ func (hs *HTTPServer) GetFolderPermissionList(c *contextmodel.ReqContext) respon perm.FolderID = folder.ID perm.DashboardID = 0 - perm.UserAvatarURL = dtos.GetGravatarUrl(perm.UserEmail) + perm.UserAvatarURL = dtos.GetGravatarUrl(hs.Cfg, perm.UserEmail) if perm.TeamID > 0 { - perm.TeamAvatarURL = dtos.GetGravatarUrlWithDefault(perm.TeamEmail, perm.Team) + perm.TeamAvatarURL = dtos.GetGravatarUrlWithDefault(hs.Cfg, perm.TeamEmail, perm.Team) } if perm.Slug != "" { diff --git a/pkg/api/frontendsettings.go b/pkg/api/frontendsettings.go index d91f0b5e461..ce055ded32b 100644 --- a/pkg/api/frontendsettings.go +++ b/pkg/api/frontendsettings.go @@ -165,29 +165,29 @@ func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.Fro frontendSettings := &dtos.FrontendSettingsDTO{ DefaultDatasource: defaultDS, Datasources: dataSources, - MinRefreshInterval: setting.MinRefreshInterval, + MinRefreshInterval: hs.Cfg.MinRefreshInterval, Panels: panels, Apps: apps, AppUrl: hs.Cfg.AppURL, AppSubUrl: hs.Cfg.AppSubURL, - AllowOrgCreate: (setting.AllowUserOrgCreate && c.IsSignedIn) || c.IsGrafanaAdmin, + AllowOrgCreate: (hs.Cfg.AllowUserOrgCreate && c.IsSignedIn) || c.IsGrafanaAdmin, AuthProxyEnabled: hs.Cfg.AuthProxyEnabled, LdapEnabled: hs.Cfg.LDAPAuthEnabled, JwtHeaderName: hs.Cfg.JWTAuthHeaderName, JwtUrlLogin: hs.Cfg.JWTAuthURLLogin, - AlertingErrorOrTimeout: setting.AlertingErrorOrTimeout, - AlertingNoDataOrNullValues: setting.AlertingNoDataOrNullValues, - AlertingMinInterval: setting.AlertingMinInterval, + AlertingErrorOrTimeout: hs.Cfg.AlertingErrorOrTimeout, + AlertingNoDataOrNullValues: hs.Cfg.AlertingNoDataOrNullValues, + AlertingMinInterval: hs.Cfg.AlertingMinInterval, LiveEnabled: hs.Cfg.LiveMaxConnections != 0, AutoAssignOrg: hs.Cfg.AutoAssignOrg, - VerifyEmailEnabled: setting.VerifyEmailEnabled, - SigV4AuthEnabled: setting.SigV4AuthEnabled, - AzureAuthEnabled: setting.AzureAuthEnabled, + VerifyEmailEnabled: hs.Cfg.VerifyEmailEnabled, + SigV4AuthEnabled: hs.Cfg.SigV4AuthEnabled, + AzureAuthEnabled: hs.Cfg.AzureAuthEnabled, RbacEnabled: true, - ExploreEnabled: setting.ExploreEnabled, - HelpEnabled: setting.HelpEnabled, - ProfileEnabled: setting.ProfileEnabled, - NewsFeedEnabled: setting.NewsFeedEnabled, + ExploreEnabled: hs.Cfg.ExploreEnabled, + HelpEnabled: hs.Cfg.HelpEnabled, + ProfileEnabled: hs.Cfg.ProfileEnabled, + NewsFeedEnabled: hs.Cfg.NewsFeedEnabled, QueryHistoryEnabled: hs.Cfg.QueryHistoryEnabled, GoogleAnalyticsId: hs.Cfg.GoogleAnalyticsID, GoogleAnalytics4Id: hs.Cfg.GoogleAnalytics4ID, @@ -201,12 +201,12 @@ func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.Fro ApplicationInsightsConnectionString: hs.Cfg.ApplicationInsightsConnectionString, ApplicationInsightsEndpointUrl: hs.Cfg.ApplicationInsightsEndpointUrl, DisableLoginForm: hs.Cfg.DisableLoginForm, - DisableUserSignUp: !setting.AllowUserSignUp, - LoginHint: setting.LoginHint, - PasswordHint: setting.PasswordHint, - ExternalUserMngInfo: setting.ExternalUserMngInfo, - ExternalUserMngLinkUrl: setting.ExternalUserMngLinkUrl, - ExternalUserMngLinkName: setting.ExternalUserMngLinkName, + DisableUserSignUp: !hs.Cfg.AllowUserSignUp, + LoginHint: hs.Cfg.LoginHint, + PasswordHint: hs.Cfg.PasswordHint, + ExternalUserMngInfo: hs.Cfg.ExternalUserMngInfo, + ExternalUserMngLinkUrl: hs.Cfg.ExternalUserMngLinkUrl, + ExternalUserMngLinkName: hs.Cfg.ExternalUserMngLinkName, ViewersCanEdit: hs.Cfg.ViewersCanEdit, AngularSupportEnabled: hs.Cfg.AngularSupportEnabled, EditorsCanAdmin: hs.Cfg.EditorsCanAdmin, @@ -228,7 +228,7 @@ func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.Fro Edition: hs.License.Edition(), LatestVersion: hs.grafanaUpdateChecker.LatestVersion(), HasUpdate: hs.grafanaUpdateChecker.UpdateAvailable(), - Env: setting.Env, + Env: hs.Cfg.Env, }, LicenseInfo: dtos.FrontendSettingsLicenseInfoDTO{ @@ -303,8 +303,8 @@ func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.Fro frontendSettings.UnifiedAlertingEnabled = *hs.Cfg.UnifiedAlerting.Enabled } - if setting.AlertingEnabled != nil { - frontendSettings.AlertingEnabled = *setting.AlertingEnabled + if hs.Cfg.AlertingEnabled != nil { + frontendSettings.AlertingEnabled = *(hs.Cfg.AlertingEnabled) } // It returns false if the provider is not enabled or the skip org role sync is false. diff --git a/pkg/api/frontendsettings_test.go b/pkg/api/frontendsettings_test.go index b14a0a63bff..53a3a322377 100644 --- a/pkg/api/frontendsettings_test.go +++ b/pkg/api/frontendsettings_test.go @@ -41,11 +41,9 @@ func setupTestEnvironment(t *testing.T, cfg *setting.Cfg, features featuremgmt.F { oldVersion := setting.BuildVersion oldCommit := setting.BuildCommit - oldEnv := setting.Env t.Cleanup(func() { setting.BuildVersion = oldVersion setting.BuildCommit = oldCommit - setting.Env = oldEnv }) } @@ -83,7 +81,7 @@ func setupTestEnvironment(t *testing.T, cfg *setting.Cfg, features featuremgmt.F m := web.New() m.Use(getContextHandler(t, cfg).Middleware) - m.UseMiddleware(web.Renderer(filepath.Join(setting.StaticRootPath, "views"), "[[", "]]")) + m.UseMiddleware(web.Renderer(filepath.Join("", "views"), "[[", "]]")) m.Get("/api/frontend/settings/", hs.GetFrontendSettings) return m, hs @@ -111,7 +109,6 @@ func TestHTTPServer_GetFrontendSettings_hideVersionAnonymous(t *testing.T) { // TODO: Remove setting.BuildVersion = cfg.BuildVersion setting.BuildCommit = cfg.BuildCommit - setting.Env = cfg.Env tests := []struct { desc string @@ -125,7 +122,7 @@ func TestHTTPServer_GetFrontendSettings_hideVersionAnonymous(t *testing.T) { BuildInfo: buildInfo{ Version: setting.BuildVersion, Commit: setting.BuildCommit, - Env: setting.Env, + Env: cfg.Env, }, }, }, @@ -136,7 +133,7 @@ func TestHTTPServer_GetFrontendSettings_hideVersionAnonymous(t *testing.T) { BuildInfo: buildInfo{ Version: "", Commit: "", - Env: setting.Env, + Env: cfg.Env, }, }, }, diff --git a/pkg/api/index.go b/pkg/api/index.go index 7c67ddb6250..75483655916 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -60,7 +60,7 @@ func (hs *HTTPServer) setIndexViewData(c *contextmodel.ReqContext) (*dtos.IndexV locale = parts[0] } - appURL := setting.AppUrl + appURL := hs.Cfg.AppURL appSubURL := hs.Cfg.AppSubURL // special case when doing localhost call from image renderer @@ -100,7 +100,7 @@ func (hs *HTTPServer) setIndexViewData(c *contextmodel.ReqContext) (*dtos.IndexV OrgName: c.OrgName, OrgRole: c.SignedInUser.GetOrgRole(), OrgCount: hs.getUserOrgCount(c, userID), - GravatarUrl: dtos.GetGravatarUrl(c.SignedInUser.GetEmail()), + GravatarUrl: dtos.GetGravatarUrl(hs.Cfg, c.SignedInUser.GetEmail()), IsGrafanaAdmin: c.IsGrafanaAdmin, Theme: theme.ID, LightTheme: theme.Type == "light", @@ -117,7 +117,7 @@ func (hs *HTTPServer) setIndexViewData(c *contextmodel.ReqContext) (*dtos.IndexV ThemeType: theme.Type, AppUrl: appURL, AppSubUrl: appSubURL, - NewsFeedEnabled: setting.NewsFeedEnabled, + NewsFeedEnabled: hs.Cfg.NewsFeedEnabled, GoogleAnalyticsId: settings.GoogleAnalyticsId, GoogleAnalytics4Id: settings.GoogleAnalytics4Id, GoogleAnalytics4SendManualPageViews: hs.Cfg.GoogleAnalytics4SendManualPageViews, @@ -149,7 +149,7 @@ func (hs *HTTPServer) setIndexViewData(c *contextmodel.ReqContext) (*dtos.IndexV data.User.Permissions = ac.BuildPermissionsMap(userPermissions) - if setting.DisableGravatar { + if hs.Cfg.DisableGravatar { data.User.GravatarUrl = hs.Cfg.AppSubURL + "/public/img/user_profile.png" } @@ -170,7 +170,7 @@ func (hs *HTTPServer) buildUserAnalyticsSettings(c *contextmodel.ReqContext) dto // Anonymous users do not have an email or auth info if namespace != identity.NamespaceUser { - return dtos.AnalyticsSettings{Identifier: "@" + setting.AppUrl} + return dtos.AnalyticsSettings{Identifier: "@" + hs.Cfg.AppURL} } if !c.IsSignedIn { @@ -180,10 +180,10 @@ func (hs *HTTPServer) buildUserAnalyticsSettings(c *contextmodel.ReqContext) dto userID, err := identity.IntIdentifier(namespace, id) if err != nil { hs.log.Error("Failed to parse user ID", "error", err) - return dtos.AnalyticsSettings{Identifier: "@" + setting.AppUrl} + return dtos.AnalyticsSettings{Identifier: "@" + hs.Cfg.AppURL} } - identifier := c.SignedInUser.GetEmail() + "@" + setting.AppUrl + identifier := c.SignedInUser.GetEmail() + "@" + hs.Cfg.AppURL authInfo, err := hs.authInfoService.GetAuthInfo(c.Req.Context(), &login.GetAuthInfoQuery{UserId: userID}) if err != nil && !errors.Is(err, user.ErrUserNotFound) { diff --git a/pkg/api/login_test.go b/pkg/api/login_test.go index 9dadd5470d5..35048e3cedb 100644 --- a/pkg/api/login_test.go +++ b/pkg/api/login_test.go @@ -122,16 +122,14 @@ func TestLoginErrorCookieAPIEndpoint(t *testing.T) { }) cfg.LoginCookieName = loginCookieName - setting.SecretKey = "login_testing" - cfg.OAuthAutoLogin = true oauthError := errors.New("User not a member of one of the required organizations") encryptedError, err := hs.SecretsService.Encrypt(context.Background(), []byte(oauthError.Error()), secrets.WithoutScope()) require.NoError(t, err) expCookiePath := "/" - if len(setting.AppSubUrl) > 0 { - expCookiePath = setting.AppSubUrl + if len(cfg.AppSubURL) > 0 { + expCookiePath = cfg.AppSubURL } cookie := http.Cookie{ Name: loginErrorCookieName, diff --git a/pkg/api/org_users.go b/pkg/api/org_users.go index 7a8c993bce6..2181539199d 100644 --- a/pkg/api/org_users.go +++ b/pkg/api/org_users.go @@ -305,7 +305,7 @@ func (hs *HTTPServer) searchOrgUsersHelper(c *contextmodel.ReqContext, query *or if dtos.IsHiddenUser(user.Login, c.SignedInUser, hs.Cfg) { continue } - user.AvatarURL = dtos.GetGravatarUrl(user.Email) + user.AvatarURL = dtos.GetGravatarUrl(hs.Cfg, user.Email) userIDs[fmt.Sprint(user.UserID)] = true authLabelsUserIDs = append(authLabelsUserIDs, user.UserID) diff --git a/pkg/api/pluginproxy/ds_proxy.go b/pkg/api/pluginproxy/ds_proxy.go index f3bdf7d6467..90ba974f864 100644 --- a/pkg/api/pluginproxy/ds_proxy.go +++ b/pkg/api/pluginproxy/ds_proxy.go @@ -275,7 +275,7 @@ func (proxy *DataSourceProxy) director(req *http.Request) { } func (proxy *DataSourceProxy) validateRequest() error { - if !checkWhiteList(proxy.ctx, proxy.targetUrl.Host) { + if !proxy.checkWhiteList() { return errors.New("target URL is not a valid target") } @@ -354,10 +354,10 @@ func (proxy *DataSourceProxy) logRequest() { "body", body) } -func checkWhiteList(c *contextmodel.ReqContext, host string) bool { - if host != "" && len(setting.DataProxyWhiteList) > 0 { - if _, exists := setting.DataProxyWhiteList[host]; !exists { - c.JsonApiErr(403, "Data proxy hostname and ip are not included in whitelist", nil) +func (proxy *DataSourceProxy) checkWhiteList() bool { + if proxy.targetUrl.Host != "" && len(proxy.cfg.DataProxyWhiteList) > 0 { + if _, exists := proxy.cfg.DataProxyWhiteList[proxy.targetUrl.Host]; !exists { + proxy.ctx.JsonApiErr(403, "Data proxy hostname and ip are not included in whitelist", nil) return false } } diff --git a/pkg/api/pluginproxy/pluginproxy_test.go b/pkg/api/pluginproxy/pluginproxy_test.go index 9668693482a..bbd9fe27de1 100644 --- a/pkg/api/pluginproxy/pluginproxy_test.go +++ b/pkg/api/pluginproxy/pluginproxy_test.go @@ -28,7 +28,6 @@ import ( ) func TestPluginProxy(t *testing.T) { - setting.SecretKey = "password" secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore()) t.Run("When getting proxy headers", func(t *testing.T) { diff --git a/pkg/api/short_url.go b/pkg/api/short_url.go index b7f3603c001..6a1292c65b8 100644 --- a/pkg/api/short_url.go +++ b/pkg/api/short_url.go @@ -26,7 +26,7 @@ func (hs *HTTPServer) createShortURL(c *contextmodel.ReqContext) response.Respon return response.Err(err) } - url := fmt.Sprintf("%s/goto/%s?orgId=%d", strings.TrimSuffix(setting.AppUrl, "/"), shortURL.Uid, c.SignedInUser.GetOrgID()) + url := fmt.Sprintf("%s/goto/%s?orgId=%d", strings.TrimSuffix(hs.Cfg.AppURL, "/"), shortURL.Uid, c.SignedInUser.GetOrgID()) c.Logger.Debug("Created short URL", "url", url) dto := dtos.ShortURL{ diff --git a/pkg/api/signup.go b/pkg/api/signup.go index 0f9310d35f6..ed5a5e048e1 100644 --- a/pkg/api/signup.go +++ b/pkg/api/signup.go @@ -14,7 +14,6 @@ import ( contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" tempuser "github.com/grafana/grafana/pkg/services/temp_user" "github.com/grafana/grafana/pkg/services/user" - "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/web" ) @@ -22,7 +21,7 @@ import ( // GET /api/user/signup/options func (hs *HTTPServer) GetSignUpOptions(c *contextmodel.ReqContext) response.Response { return response.JSON(http.StatusOK, util.DynMap{ - "verifyEmailEnabled": setting.VerifyEmailEnabled, + "verifyEmailEnabled": hs.Cfg.VerifyEmailEnabled, "autoAssignOrg": hs.Cfg.AutoAssignOrg, }) } @@ -34,7 +33,7 @@ func (hs *HTTPServer) SignUp(c *contextmodel.ReqContext) response.Response { if err = web.Bind(c.Req, &form); err != nil { return response.Error(http.StatusBadRequest, "bad request data", err) } - if !setting.AllowUserSignUp { + if !hs.Cfg.AllowUserSignUp { return response.Error(401, "User signup is disabled", nil) } @@ -86,7 +85,7 @@ func (hs *HTTPServer) SignUpStep2(c *contextmodel.ReqContext) response.Response if err := web.Bind(c.Req, &form); err != nil { return response.Error(http.StatusBadRequest, "bad request data", err) } - if !setting.AllowUserSignUp { + if !hs.Cfg.AllowUserSignUp { return response.Error(401, "User signup is disabled", nil) } @@ -102,7 +101,7 @@ func (hs *HTTPServer) SignUpStep2(c *contextmodel.ReqContext) response.Response } // verify email - if setting.VerifyEmailEnabled { + if hs.Cfg.VerifyEmailEnabled { if ok, rsp := hs.verifyUserSignUpEmail(c.Req.Context(), form.Email, form.Code); !ok { return rsp } diff --git a/pkg/api/user.go b/pkg/api/user.go index d3be2f47661..1a08e1b636c 100644 --- a/pkg/api/user.go +++ b/pkg/api/user.go @@ -79,7 +79,7 @@ func (hs *HTTPServer) getUserUserProfile(c *contextmodel.ReqContext, userID int6 } userProfile.AccessControl = hs.getAccessControlMetadata(c, c.SignedInUser.GetOrgID(), "global.users:id:", strconv.FormatInt(userID, 10)) - userProfile.AvatarURL = dtos.GetGravatarUrl(userProfile.Email) + userProfile.AvatarURL = dtos.GetGravatarUrl(hs.Cfg, userProfile.Email) return response.JSON(http.StatusOK, userProfile) } @@ -324,7 +324,7 @@ func (hs *HTTPServer) getUserTeamList(c *contextmodel.ReqContext, orgID int64, u } for _, team := range queryResult { - team.AvatarURL = dtos.GetGravatarUrlWithDefault(team.Email, team.Name) + team.AvatarURL = dtos.GetGravatarUrlWithDefault(hs.Cfg, team.Email, team.Name) } return response.JSON(http.StatusOK, queryResult) } diff --git a/pkg/api/user_test.go b/pkg/api/user_test.go index 16c9fcfaf51..fa1fc14c2ee 100644 --- a/pkg/api/user_test.go +++ b/pkg/api/user_test.go @@ -103,7 +103,7 @@ func TestUserAPIEndpoint_userLoggedIn(t *testing.T) { } err = srv.UpdateAuthInfo(context.Background(), cmd) require.NoError(t, err) - avatarUrl := dtos.GetGravatarUrl("@test.com") + avatarUrl := dtos.GetGravatarUrl(hs.Cfg, "@test.com") sc.fakeReqWithParams("GET", sc.url, map[string]string{"id": fmt.Sprintf("%v", usr.ID)}).exec() expected := user.UserProfileDTO{ @@ -160,7 +160,7 @@ func TestUserAPIEndpoint_userLoggedIn(t *testing.T) { loggedInUserScenario(t, "When calling GET on", "/api/users", "/api/users", func(sc *scenarioContext) { userMock.ExpectedSearchUsers = mockResult - searchUsersService := searchusers.ProvideUsersService(filters.ProvideOSSSearchUserFilter(), userMock) + searchUsersService := searchusers.ProvideUsersService(sc.cfg, filters.ProvideOSSSearchUserFilter(), userMock) sc.handlerFunc = searchUsersService.SearchUsers sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec() @@ -173,7 +173,7 @@ func TestUserAPIEndpoint_userLoggedIn(t *testing.T) { loggedInUserScenario(t, "When calling GET with page and limit querystring parameters on", "/api/users", "/api/users", func(sc *scenarioContext) { userMock.ExpectedSearchUsers = mockResult - searchUsersService := searchusers.ProvideUsersService(filters.ProvideOSSSearchUserFilter(), userMock) + searchUsersService := searchusers.ProvideUsersService(sc.cfg, filters.ProvideOSSSearchUserFilter(), userMock) sc.handlerFunc = searchUsersService.SearchUsers sc.fakeReqWithParams("GET", sc.url, map[string]string{"perpage": "10", "page": "2"}).exec() @@ -186,7 +186,7 @@ func TestUserAPIEndpoint_userLoggedIn(t *testing.T) { loggedInUserScenario(t, "When calling GET on", "/api/users/search", "/api/users/search", func(sc *scenarioContext) { userMock.ExpectedSearchUsers = mockResult - searchUsersService := searchusers.ProvideUsersService(filters.ProvideOSSSearchUserFilter(), userMock) + searchUsersService := searchusers.ProvideUsersService(sc.cfg, filters.ProvideOSSSearchUserFilter(), userMock) sc.handlerFunc = searchUsersService.SearchUsersWithPaging sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec() @@ -202,7 +202,7 @@ func TestUserAPIEndpoint_userLoggedIn(t *testing.T) { loggedInUserScenario(t, "When calling GET with page and perpage querystring parameters on", "/api/users/search", "/api/users/search", func(sc *scenarioContext) { userMock.ExpectedSearchUsers = mockResult - searchUsersService := searchusers.ProvideUsersService(filters.ProvideOSSSearchUserFilter(), userMock) + searchUsersService := searchusers.ProvideUsersService(sc.cfg, filters.ProvideOSSSearchUserFilter(), userMock) sc.handlerFunc = searchUsersService.SearchUsersWithPaging sc.fakeReqWithParams("GET", sc.url, map[string]string{"perpage": "10", "page": "2"}).exec() diff --git a/pkg/cmd/grafana-cli/commands/commands.go b/pkg/cmd/grafana-cli/commands/commands.go index 30eacb2827c..ab2293bc353 100644 --- a/pkg/cmd/grafana-cli/commands/commands.go +++ b/pkg/cmd/grafana-cli/commands/commands.go @@ -30,7 +30,7 @@ func runRunnerCommand(command func(commandLine utils.CommandLine, runner server. } } -func runDbCommand(command func(commandLine utils.CommandLine, sqlStore db.DB) error) func(context *cli.Context) error { +func runDbCommand(command func(commandLine utils.CommandLine, cfg *setting.Cfg, sqlStore db.DB) error) func(context *cli.Context) error { return func(context *cli.Context) error { cmd := &utils.ContextCommandLine{Context: context} runner, err := initializeRunner(cmd) @@ -38,8 +38,9 @@ func runDbCommand(command func(commandLine utils.CommandLine, sqlStore db.DB) er return fmt.Errorf("%v: %w", "failed to initialize runner", err) } + cfg := runner.Cfg sqlStore := runner.SQLStore - if err := command(cmd, sqlStore); err != nil { + if err := command(cmd, cfg, sqlStore); err != nil { return err } diff --git a/pkg/cmd/grafana-cli/commands/datamigrations/encrypt_datasource_passwords.go b/pkg/cmd/grafana-cli/commands/datamigrations/encrypt_datasource_passwords.go index 2b244d8beee..13519423f8c 100644 --- a/pkg/cmd/grafana-cli/commands/datamigrations/encrypt_datasource_passwords.go +++ b/pkg/cmd/grafana-cli/commands/datamigrations/encrypt_datasource_passwords.go @@ -27,14 +27,14 @@ var ( // EncryptDatasourcePasswords migrates unencrypted secrets on datasources // to the secureJson Column. -func EncryptDatasourcePasswords(c utils.CommandLine, sqlStore db.DB) error { +func EncryptDatasourcePasswords(c utils.CommandLine, cfg *setting.Cfg, sqlStore db.DB) error { return sqlStore.WithDbSession(context.Background(), func(session *db.Session) error { - passwordsUpdated, err := migrateColumn(session, "password") + passwordsUpdated, err := migrateColumn(cfg, session, "password") if err != nil { return err } - basicAuthUpdated, err := migrateColumn(session, "basic_auth_password") + basicAuthUpdated, err := migrateColumn(cfg, session, "basic_auth_password") if err != nil { return err } @@ -61,7 +61,7 @@ func EncryptDatasourcePasswords(c utils.CommandLine, sqlStore db.DB) error { }) } -func migrateColumn(session *db.Session, column string) (int, error) { +func migrateColumn(cfg *setting.Cfg, session *db.Session, column string) (int, error) { var rows []map[string][]byte session.Cols("id", column, "secure_json_data") @@ -74,18 +74,18 @@ func migrateColumn(session *db.Session, column string) (int, error) { return 0, fmt.Errorf("failed to select column: %s: %w", column, err) } - rowsUpdated, err := updateRows(session, rows, column) + rowsUpdated, err := updateRows(cfg, session, rows, column) if err != nil { return rowsUpdated, fmt.Errorf("failed to update column: %s: %w", column, err) } return rowsUpdated, err } -func updateRows(session *db.Session, rows []map[string][]byte, passwordFieldName string) (int, error) { +func updateRows(cfg *setting.Cfg, session *db.Session, rows []map[string][]byte, passwordFieldName string) (int, error) { var rowsUpdated int for _, row := range rows { - newSecureJSONData, err := getUpdatedSecureJSONData(row, passwordFieldName) + newSecureJSONData, err := getUpdatedSecureJSONData(cfg.SecretKey, row, passwordFieldName) if err != nil { return 0, err } @@ -111,8 +111,8 @@ func updateRows(session *db.Session, rows []map[string][]byte, passwordFieldName return rowsUpdated, nil } -func getUpdatedSecureJSONData(row map[string][]byte, passwordFieldName string) (map[string]any, error) { - encryptedPassword, err := util.Encrypt(row[passwordFieldName], setting.SecretKey) +func getUpdatedSecureJSONData(secretKey string, row map[string][]byte, passwordFieldName string) (map[string]any, error) { + encryptedPassword, err := util.Encrypt(row[passwordFieldName], secretKey) if err != nil { return nil, err } diff --git a/pkg/cmd/grafana-cli/commands/datamigrations/encrypt_datasource_passwords_test.go b/pkg/cmd/grafana-cli/commands/datamigrations/encrypt_datasource_passwords_test.go index 1ba6516cfc4..99b89d59eb6 100644 --- a/pkg/cmd/grafana-cli/commands/datamigrations/encrypt_datasource_passwords_test.go +++ b/pkg/cmd/grafana-cli/commands/datamigrations/encrypt_datasource_passwords_test.go @@ -38,8 +38,10 @@ func passwordMigration(t *testing.T, session *db.Session, sqlstore db.DB) { ds.Created = time.Now() ds.Updated = time.Now() + cfg := setting.NewCfg() + if ds.Name == "elasticsearch" { - key, err := util.Encrypt([]byte("value"), setting.SecretKey) + key, err := util.Encrypt([]byte("value"), cfg.SecretKey) require.NoError(t, err) ds.SecureJsonData = map[string][]byte{"key": key} @@ -58,7 +60,7 @@ func passwordMigration(t *testing.T, session *db.Session, sqlstore db.DB) { // run migration c, err := commandstest.NewCliContext(map[string]string{}) require.Nil(t, err) - err = EncryptDatasourcePasswords(c, sqlstore) + err = EncryptDatasourcePasswords(c, setting.NewCfg(), sqlstore) require.NoError(t, err) // verify that no datasources still have password or basic_auth @@ -68,7 +70,8 @@ func passwordMigration(t *testing.T, session *db.Session, sqlstore db.DB) { assert.Equal(t, len(dss), 4) for _, ds := range dss { - sj, err := DecryptSecureJsonData(ds) + cfg := setting.NewCfg() + sj, err := DecryptSecureJsonData(cfg.SecretKey, ds) require.NoError(t, err) if ds.Name == "influxdb" { @@ -101,10 +104,10 @@ func passwordMigration(t *testing.T, session *db.Session, sqlstore db.DB) { } } -func DecryptSecureJsonData(ds *datasources.DataSource) (map[string]string, error) { +func DecryptSecureJsonData(secretKey string, ds *datasources.DataSource) (map[string]string, error) { decrypted := make(map[string]string) for key, data := range ds.SecureJsonData { - decryptedData, err := util.Decrypt(data, setting.SecretKey) + decryptedData, err := util.Decrypt(data, secretKey) if err != nil { return nil, err } diff --git a/pkg/components/imguploader/azureblobuploader_test.go b/pkg/components/imguploader/azureblobuploader_test.go index ca7a663ab0f..01afb1755df 100644 --- a/pkg/components/imguploader/azureblobuploader_test.go +++ b/pkg/components/imguploader/azureblobuploader_test.go @@ -18,7 +18,7 @@ func TestUploadToAzureBlob(t *testing.T) { }) require.NoError(t, err) - uploader, _ := NewImageUploader() + uploader, _ := NewImageUploader(cfg) path, err := uploader.Upload(context.Background(), "../../../public/img/logo_transparent_400x.png") diff --git a/pkg/components/imguploader/imguploader.go b/pkg/components/imguploader/imguploader.go index 7e0aee0028b..7d3999abfeb 100644 --- a/pkg/components/imguploader/imguploader.go +++ b/pkg/components/imguploader/imguploader.go @@ -32,10 +32,10 @@ var ( logger = log.New("imguploader") ) -func NewImageUploader() (ImageUploader, error) { - switch setting.ImageUploadProvider { +func NewImageUploader(cfg *setting.Cfg) (ImageUploader, error) { + switch cfg.ImageUploadProvider { case "s3": - s3sec, err := setting.Raw.GetSection("external_image_storage.s3") + s3sec, err := cfg.Raw.GetSection("external_image_storage.s3") if err != nil { return nil, err } @@ -64,7 +64,7 @@ func NewImageUploader() (ImageUploader, error) { return NewS3Uploader(endpoint, region, bucket, path, "public-read", accessKey, secretKey, pathStyleAccess), nil case "webdav": - webdavSec, err := setting.Raw.GetSection("external_image_storage.webdav") + webdavSec, err := cfg.Raw.GetSection("external_image_storage.webdav") if err != nil { return nil, err } @@ -80,7 +80,7 @@ func NewImageUploader() (ImageUploader, error) { return NewWebdavImageUploader(url, username, password, public_url) case "gcs": - gcssec, err := setting.Raw.GetSection("external_image_storage.gcs") + gcssec, err := cfg.Raw.GetSection("external_image_storage.gcs") if err != nil { return nil, err } @@ -102,7 +102,7 @@ func NewImageUploader() (ImageUploader, error) { return gcs.NewUploader(keyFile, bucketName, path, enableSignedURLs, suExp) case "azure_blob": - azureBlobSec, err := setting.Raw.GetSection("external_image_storage.azure_blob") + azureBlobSec, err := cfg.Raw.GetSection("external_image_storage.azure_blob") if err != nil { return nil, err } @@ -118,8 +118,8 @@ func NewImageUploader() (ImageUploader, error) { return NewLocalImageUploader() } - if setting.ImageUploadProvider != "" { - logger.Error("The external image storage configuration is invalid", "unsupported provider", setting.ImageUploadProvider) + if cfg.ImageUploadProvider != "" { + logger.Error("The external image storage configuration is invalid", "unsupported provider", cfg.ImageUploadProvider) } return NopImageUploader{}, nil diff --git a/pkg/components/imguploader/imguploader_test.go b/pkg/components/imguploader/imguploader_test.go index a6acb346c34..db0c277169b 100644 --- a/pkg/components/imguploader/imguploader_test.go +++ b/pkg/components/imguploader/imguploader_test.go @@ -17,10 +17,10 @@ func TestImageUploaderFactory(t *testing.T) { }) require.NoError(t, err) - setting.ImageUploadProvider = "s3" + cfg.ImageUploadProvider = "s3" t.Run("with bucket url https://foo.bar.baz.s3-us-east-2.amazonaws.com", func(t *testing.T) { - s3sec, err := setting.Raw.GetSection("external_image_storage.s3") + s3sec, err := cfg.Raw.GetSection("external_image_storage.s3") require.NoError(t, err) _, err = s3sec.NewKey("bucket_url", "https://foo.bar.baz.s3-us-east-2.amazonaws.com") require.NoError(t, err) @@ -29,7 +29,7 @@ func TestImageUploaderFactory(t *testing.T) { _, err = s3sec.NewKey("secret_key", "secret_key") require.NoError(t, err) - uploader, err := NewImageUploader() + uploader, err := NewImageUploader(cfg) require.NoError(t, err) original, ok := uploader.(*S3Uploader) @@ -41,7 +41,7 @@ func TestImageUploaderFactory(t *testing.T) { }) t.Run("with bucket url https://s3.amazonaws.com/mybucket", func(t *testing.T) { - s3sec, err := setting.Raw.GetSection("external_image_storage.s3") + s3sec, err := cfg.Raw.GetSection("external_image_storage.s3") require.NoError(t, err) _, err = s3sec.NewKey("bucket_url", "https://s3.amazonaws.com/my.bucket.com") require.NoError(t, err) @@ -50,7 +50,7 @@ func TestImageUploaderFactory(t *testing.T) { _, err = s3sec.NewKey("secret_key", "secret_key") require.NoError(t, err) - uploader, err := NewImageUploader() + uploader, err := NewImageUploader(cfg) require.NoError(t, err) original, ok := uploader.(*S3Uploader) @@ -62,7 +62,7 @@ func TestImageUploaderFactory(t *testing.T) { }) t.Run("with bucket url https://s3-us-west-2.amazonaws.com/mybucket", func(t *testing.T) { - s3sec, err := setting.Raw.GetSection("external_image_storage.s3") + s3sec, err := cfg.Raw.GetSection("external_image_storage.s3") require.NoError(t, err) _, err = s3sec.NewKey("bucket_url", "https://s3-us-west-2.amazonaws.com/my.bucket.com") require.NoError(t, err) @@ -71,7 +71,7 @@ func TestImageUploaderFactory(t *testing.T) { _, err = s3sec.NewKey("secret_key", "secret_key") require.NoError(t, err) - uploader, err := NewImageUploader() + uploader, err := NewImageUploader(cfg) require.NoError(t, err) original, ok := uploader.(*S3Uploader) @@ -90,7 +90,7 @@ func TestImageUploaderFactory(t *testing.T) { }) require.NoError(t, err) - setting.ImageUploadProvider = "webdav" + cfg.ImageUploadProvider = "webdav" webdavSec, err := cfg.Raw.GetSection("external_image_storage.webdav") require.NoError(t, err) @@ -101,7 +101,7 @@ func TestImageUploaderFactory(t *testing.T) { _, err = webdavSec.NewKey("password", "password") require.NoError(t, err) - uploader, err := NewImageUploader() + uploader, err := NewImageUploader(cfg) require.NoError(t, err) original, ok := uploader.(*WebdavUploader) @@ -118,7 +118,7 @@ func TestImageUploaderFactory(t *testing.T) { }) require.NoError(t, err) - setting.ImageUploadProvider = "gcs" + cfg.ImageUploadProvider = "gcs" gcpSec, err := cfg.Raw.GetSection("external_image_storage.gcs") require.NoError(t, err) @@ -127,7 +127,7 @@ func TestImageUploaderFactory(t *testing.T) { _, err = gcpSec.NewKey("bucket", "project-grafana-east") require.NoError(t, err) - uploader, err := NewImageUploader() + uploader, err := NewImageUploader(cfg) require.NoError(t, err) original, ok := uploader.(*gcs.Uploader) @@ -143,7 +143,7 @@ func TestImageUploaderFactory(t *testing.T) { }) require.NoError(t, err) - setting.ImageUploadProvider = "azure_blob" + cfg.ImageUploadProvider = "azure_blob" t.Run("with container name", func(t *testing.T) { azureBlobSec, err := cfg.Raw.GetSection("external_image_storage.azure_blob") @@ -157,7 +157,7 @@ func TestImageUploaderFactory(t *testing.T) { _, err = azureBlobSec.NewKey("sas_token_expiration_days", "sas_token_expiration_days") require.NoError(t, err) - uploader, err := NewImageUploader() + uploader, err := NewImageUploader(cfg) require.NoError(t, err) original, ok := uploader.(*AzureBlobUploader) @@ -176,9 +176,9 @@ func TestImageUploaderFactory(t *testing.T) { }) require.NoError(t, err) - setting.ImageUploadProvider = "local" + cfg.ImageUploadProvider = "local" - uploader, err := NewImageUploader() + uploader, err := NewImageUploader(cfg) require.NoError(t, err) original, ok := uploader.(*LocalUploader) diff --git a/pkg/components/imguploader/s3uploader_test.go b/pkg/components/imguploader/s3uploader_test.go index 8d5bc4a64e7..637e5ffe386 100644 --- a/pkg/components/imguploader/s3uploader_test.go +++ b/pkg/components/imguploader/s3uploader_test.go @@ -17,7 +17,7 @@ func TestUploadToS3(t *testing.T) { }) require.NoError(t, err) - s3Uploader, err := NewImageUploader() + s3Uploader, err := NewImageUploader(cfg) require.NoError(t, err) path, err := s3Uploader.Upload(context.Background(), "../../../public/img/logo_transparent_400x.png") diff --git a/pkg/infra/metrics/settings.go b/pkg/infra/metrics/settings.go index e07f5533a00..54715db249e 100644 --- a/pkg/infra/metrics/settings.go +++ b/pkg/infra/metrics/settings.go @@ -8,7 +8,6 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/grafana/grafana/pkg/infra/metrics/graphitebridge" - "github.com/grafana/grafana/pkg/setting" ) func (im *InternalMetricsService) readSettings() error { @@ -48,7 +47,7 @@ func (im *InternalMetricsService) parseGraphiteSettings() error { ErrorHandling: graphitebridge.ContinueOnError, } - safeInstanceName := strings.ReplaceAll(setting.InstanceName, ".", "_") + safeInstanceName := strings.ReplaceAll(im.Cfg.InstanceName, ".", "_") prefix := graphiteSection.Key("prefix").Value() if prefix == "" { diff --git a/pkg/infra/usagestats/service/api_test.go b/pkg/infra/usagestats/service/api_test.go index 7f45b7ca97d..f2b749f5dff 100644 --- a/pkg/infra/usagestats/service/api_test.go +++ b/pkg/infra/usagestats/service/api_test.go @@ -4,7 +4,6 @@ import ( "encoding/json" "net/http" "net/http/httptest" - "path" "testing" "github.com/stretchr/testify/require" @@ -15,7 +14,6 @@ import ( contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" "github.com/grafana/grafana/pkg/services/stats" "github.com/grafana/grafana/pkg/services/user" - "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/web" ) @@ -80,7 +78,7 @@ func getUsageStats(t *testing.T, server *web.Mux) (*stats.SystemStats, *httptest func setupTestServer(t *testing.T, user *user.SignedInUser, service *UsageStats) *web.Mux { server := web.New() - server.UseMiddleware(web.Renderer(path.Join(setting.StaticRootPath, "views"), "[[", "]]")) + server.UseMiddleware(web.Renderer("views", "[[", "]]")) server.Use(contextProvider(&testContext{user})) service.RouteRegister.Register(server) return server diff --git a/pkg/login/social/connectors/gitlab_oauth.go b/pkg/login/social/connectors/gitlab_oauth.go index ee59a8b6e92..4025c26d1bf 100644 --- a/pkg/login/social/connectors/gitlab_oauth.go +++ b/pkg/login/social/connectors/gitlab_oauth.go @@ -255,7 +255,7 @@ func (s *SocialGitlab) extractFromAPI(ctx context.Context, client *http.Client, idData.Role = role } - if setting.Env == setting.Dev { + if s.cfg.Env == setting.Dev { s.log.Debug("Resolved ID", "data", fmt.Sprintf("%+v", idData)) } diff --git a/pkg/login/social/connectors/google_oauth.go b/pkg/login/social/connectors/google_oauth.go index c4c731068ca..1398f045397 100644 --- a/pkg/login/social/connectors/google_oauth.go +++ b/pkg/login/social/connectors/google_oauth.go @@ -216,7 +216,7 @@ func (s *SocialGoogle) extractFromToken(ctx context.Context, client *http.Client return nil, nil } - if setting.Env == setting.Dev { + if s.cfg.Env == setting.Dev { s.log.Debug("Received id_token", "raw_json", string(rawJSON)) } diff --git a/pkg/middleware/recovery.go b/pkg/middleware/recovery.go index 7d339eefe32..59127e15029 100644 --- a/pkg/middleware/recovery.go +++ b/pkg/middleware/recovery.go @@ -152,7 +152,7 @@ func Recovery(cfg *setting.Cfg, license licensing.Licensing) web.Middleware { Assets *dtos.EntryPointAssets }{"Server Error", "Grafana", cfg.AppSubURL, cfg.DefaultTheme, "", assets} - if setting.Env == setting.Dev { + if cfg.Env == setting.Dev { if err, ok := r.(error); ok { data.Title = err.Error() } diff --git a/pkg/services/accesscontrol/ossaccesscontrol/permissions_services.go b/pkg/services/accesscontrol/ossaccesscontrol/permissions_services.go index aaa75e17cee..cf549bd6389 100644 --- a/pkg/services/accesscontrol/ossaccesscontrol/permissions_services.go +++ b/pkg/services/accesscontrol/ossaccesscontrol/permissions_services.go @@ -22,6 +22,7 @@ import ( "github.com/grafana/grafana/pkg/services/team" "github.com/grafana/grafana/pkg/services/team/teamimpl" "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/setting" ) type TeamPermissionsService struct { @@ -43,7 +44,7 @@ var ( ) func ProvideTeamPermissions( - features featuremgmt.FeatureToggles, router routing.RouteRegister, sql db.DB, + cfg *setting.Cfg, features featuremgmt.FeatureToggles, router routing.RouteRegister, sql db.DB, ac accesscontrol.AccessControl, license licensing.Licensing, service accesscontrol.Service, teamService team.Service, userService user.Service, ) (*TeamPermissionsService, error) { @@ -101,7 +102,7 @@ func ProvideTeamPermissions( }, } - srv, err := resourcepermissions.New(options, features, router, license, ac, service, sql, teamService, userService) + srv, err := resourcepermissions.New(cfg, options, features, router, license, ac, service, sql, teamService, userService) if err != nil { return nil, err } @@ -117,7 +118,7 @@ var DashboardEditActions = append(DashboardViewActions, []string{dashboards.Acti var DashboardAdminActions = append(DashboardEditActions, []string{dashboards.ActionDashboardsPermissionsRead, dashboards.ActionDashboardsPermissionsWrite}...) func ProvideDashboardPermissions( - features featuremgmt.FeatureToggles, router routing.RouteRegister, sql db.DB, ac accesscontrol.AccessControl, + cfg *setting.Cfg, features featuremgmt.FeatureToggles, router routing.RouteRegister, sql db.DB, ac accesscontrol.AccessControl, license licensing.Licensing, dashboardStore dashboards.Store, folderService folder.Service, service accesscontrol.Service, teamService team.Service, userService user.Service, ) (*DashboardPermissionsService, error) { @@ -183,7 +184,7 @@ func ProvideDashboardPermissions( RoleGroup: "Dashboards", } - srv, err := resourcepermissions.New(options, features, router, license, ac, service, sql, teamService, userService) + srv, err := resourcepermissions.New(cfg, options, features, router, license, ac, service, sql, teamService, userService) if err != nil { return nil, err } @@ -209,7 +210,7 @@ var FolderEditActions = append(FolderViewActions, []string{ var FolderAdminActions = append(FolderEditActions, []string{dashboards.ActionFoldersPermissionsRead, dashboards.ActionFoldersPermissionsWrite}...) func ProvideFolderPermissions( - features featuremgmt.FeatureToggles, router routing.RouteRegister, sql db.DB, accesscontrol accesscontrol.AccessControl, + cfg *setting.Cfg, features featuremgmt.FeatureToggles, router routing.RouteRegister, sql db.DB, accesscontrol accesscontrol.AccessControl, license licensing.Licensing, dashboardStore dashboards.Store, folderService folder.Service, service accesscontrol.Service, teamService team.Service, userService user.Service, ) (*FolderPermissionsService, error) { @@ -247,7 +248,7 @@ func ProvideFolderPermissions( WriterRoleName: "Folder permission writer", RoleGroup: "Folders", } - srv, err := resourcepermissions.New(options, features, router, license, accesscontrol, service, sql, teamService, userService) + srv, err := resourcepermissions.New(cfg, options, features, router, license, accesscontrol, service, sql, teamService, userService) if err != nil { return nil, err } @@ -309,7 +310,7 @@ type ServiceAccountPermissionsService struct { } func ProvideServiceAccountPermissions( - features featuremgmt.FeatureToggles, router routing.RouteRegister, sql db.DB, ac accesscontrol.AccessControl, + cfg *setting.Cfg, features featuremgmt.FeatureToggles, router routing.RouteRegister, sql db.DB, ac accesscontrol.AccessControl, license licensing.Licensing, serviceAccountRetrieverService *retriever.Service, service accesscontrol.Service, teamService team.Service, userService user.Service, ) (*ServiceAccountPermissionsService, error) { @@ -338,7 +339,7 @@ func ProvideServiceAccountPermissions( RoleGroup: "Service accounts", } - srv, err := resourcepermissions.New(options, features, router, license, ac, service, sql, teamService, userService) + srv, err := resourcepermissions.New(cfg, options, features, router, license, ac, service, sql, teamService, userService) if err != nil { return nil, err } diff --git a/pkg/services/accesscontrol/resourcepermissions/api.go b/pkg/services/accesscontrol/resourcepermissions/api.go index 9bc2eb80253..9b433b0c505 100644 --- a/pkg/services/accesscontrol/resourcepermissions/api.go +++ b/pkg/services/accesscontrol/resourcepermissions/api.go @@ -11,23 +11,25 @@ import ( "github.com/grafana/grafana/pkg/services/accesscontrol" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" "github.com/grafana/grafana/pkg/services/org" + "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/web" ) type api struct { + cfg *setting.Cfg ac accesscontrol.AccessControl router routing.RouteRegister service *Service permissions []string } -func newApi(ac accesscontrol.AccessControl, router routing.RouteRegister, manager *Service) *api { +func newApi(cfg *setting.Cfg, ac accesscontrol.AccessControl, router routing.RouteRegister, manager *Service) *api { permissions := make([]string, 0, len(manager.permissions)) // reverse the permissions order for display for i := len(manager.permissions) - 1; i >= 0; i-- { permissions = append(permissions, manager.permissions[i]) } - return &api{ac, router, manager, permissions} + return &api{cfg, ac, router, manager, permissions} } func (a *api) registerEndpoints() { @@ -157,7 +159,7 @@ func (a *api) getPermissions(c *contextmodel.ReqContext) response.Response { if permission := a.service.MapActions(p); permission != "" { teamAvatarUrl := "" if p.TeamId != 0 { - teamAvatarUrl = dtos.GetGravatarUrlWithDefault(p.TeamEmail, p.Team) + teamAvatarUrl = dtos.GetGravatarUrlWithDefault(a.cfg, p.TeamEmail, p.Team) } dto = append(dto, resourcePermissionDTO{ @@ -165,7 +167,7 @@ func (a *api) getPermissions(c *contextmodel.ReqContext) response.Response { RoleName: p.RoleName, UserID: p.UserId, UserLogin: p.UserLogin, - UserAvatarUrl: dtos.GetGravatarUrl(p.UserEmail), + UserAvatarUrl: dtos.GetGravatarUrl(a.cfg, p.UserEmail), Team: p.Team, TeamID: p.TeamId, TeamAvatarUrl: teamAvatarUrl, diff --git a/pkg/services/accesscontrol/resourcepermissions/api_test.go b/pkg/services/accesscontrol/resourcepermissions/api_test.go index 797e51de737..ae6c15d7a3a 100644 --- a/pkg/services/accesscontrol/resourcepermissions/api_test.go +++ b/pkg/services/accesscontrol/resourcepermissions/api_test.go @@ -6,7 +6,6 @@ import ( "fmt" "net/http" "net/http/httptest" - "path" "strconv" "strings" "testing" @@ -25,7 +24,6 @@ import ( "github.com/grafana/grafana/pkg/services/team/teamimpl" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/services/user/userimpl" - "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/web" ) @@ -432,7 +430,7 @@ func TestApi_setUserPermission(t *testing.T) { func setupTestServer(t *testing.T, user *user.SignedInUser, service *Service) *web.Mux { server := web.New() - server.UseMiddleware(web.Renderer(path.Join(setting.StaticRootPath, "views"), "[[", "]]")) + server.UseMiddleware(web.Renderer("views", "[[", "]]")) server.Use(contextProvider(&testContext{user})) service.api.router.Register(server) return server diff --git a/pkg/services/accesscontrol/resourcepermissions/service.go b/pkg/services/accesscontrol/resourcepermissions/service.go index 235e2240dd0..cf2e638275f 100644 --- a/pkg/services/accesscontrol/resourcepermissions/service.go +++ b/pkg/services/accesscontrol/resourcepermissions/service.go @@ -14,6 +14,7 @@ import ( "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/team" "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/setting" ) type Store interface { @@ -52,7 +53,7 @@ type Store interface { DeleteResourcePermissions(ctx context.Context, orgID int64, cmd *DeleteResourcePermissionsCmd) error } -func New( +func New(cfg *setting.Cfg, options Options, features featuremgmt.FeatureToggles, router routing.RouteRegister, license licensing.Licensing, ac accesscontrol.AccessControl, service accesscontrol.Service, sqlStore db.DB, teamService team.Service, userService user.Service, @@ -89,7 +90,7 @@ func New( userService: userService, } - s.api = newApi(ac, router, s) + s.api = newApi(cfg, ac, router, s) if err := s.declareFixedRoles(); err != nil { return nil, err diff --git a/pkg/services/accesscontrol/resourcepermissions/service_test.go b/pkg/services/accesscontrol/resourcepermissions/service_test.go index dbf040b4cb6..abab7822d5a 100644 --- a/pkg/services/accesscontrol/resourcepermissions/service_test.go +++ b/pkg/services/accesscontrol/resourcepermissions/service_test.go @@ -245,7 +245,7 @@ func setupTestEnvironment(t *testing.T, ops Options) (*Service, *sqlstore.SQLSto ac := acimpl.ProvideAccessControl(cfg) acService := &actest.FakeService{} service, err := New( - ops, featuremgmt.WithFeatures(), routing.NewRouteRegister(), license, + cfg, ops, featuremgmt.WithFeatures(), routing.NewRouteRegister(), license, ac, acService, sql, teamSvc, userSvc, ) require.NoError(t, err) diff --git a/pkg/services/alerting/engine.go b/pkg/services/alerting/engine.go index e81e7fadf1d..ac103c5f4af 100644 --- a/pkg/services/alerting/engine.go +++ b/pkg/services/alerting/engine.go @@ -57,7 +57,7 @@ type AlertEngine struct { // IsDisabled returns true if the alerting service is disabled for this instance. func (e *AlertEngine) IsDisabled() bool { - return setting.AlertingEnabled == nil || !*setting.AlertingEnabled || !setting.ExecuteAlerts || e.Cfg.UnifiedAlerting.IsEnabled() + return e.Cfg.AlertingEnabled == nil || !*(e.Cfg.AlertingEnabled) || !e.Cfg.ExecuteAlerts || e.Cfg.UnifiedAlerting.IsEnabled() } // ProvideAlertEngine returns a new AlertEngine. @@ -80,11 +80,11 @@ func ProvideAlertEngine(renderer rendering.Service, requestValidator validations annotationsRepo: annotationsRepo, } e.execQueue = make(chan *Job, 1000) - e.scheduler = newScheduler() + e.scheduler = newScheduler(cfg) e.evalHandler = NewEvalHandler(e.DataService) e.ruleReader = newRuleReader(store) e.log = log.New("alerting.engine") - e.resultHandler = newResultHandler(e.RenderService, store, notificationService, encryptionService.GetDecryptedValue) + e.resultHandler = newResultHandler(cfg, e.RenderService, store, notificationService, encryptionService.GetDecryptedValue) e.registerUsageMetrics() @@ -153,7 +153,7 @@ func (e *AlertEngine) processJobWithRetry(grafanaCtx context.Context, job *Job) } }() - cancelChan := make(chan context.CancelFunc, setting.AlertingMaxAttempts*2) + cancelChan := make(chan context.CancelFunc, e.Cfg.AlertingMaxAttempts*2) attemptChan := make(chan int, 1) // Initialize with first attemptID=1 @@ -197,7 +197,7 @@ func (e *AlertEngine) processJob(attemptID int, attemptChan chan int, cancelChan } }() - alertCtx, cancelFn := context.WithTimeout(context.Background(), setting.AlertingEvaluationTimeout) + alertCtx, cancelFn := context.WithTimeout(context.Background(), e.Cfg.AlertingEvaluationTimeout) cancelChan <- cancelFn alertCtx, span := e.tracer.Start(alertCtx, "alert execution") evalContext := NewEvalContext(alertCtx, job.Rule, e.RequestValidator, e.AlertStore, e.dashboardService, e.datasourceService, e.annotationsRepo) @@ -228,7 +228,7 @@ func (e *AlertEngine) processJob(attemptID int, attemptChan chan int, cancelChan span.SetStatus(codes.Error, "alerting execution attempt failed") span.RecordError(evalContext.Error) - if attemptID < setting.AlertingMaxAttempts { + if attemptID < e.Cfg.AlertingMaxAttempts { span.End() e.log.Debug("Job Execution attempt triggered retry", "timeMs", evalContext.GetDurationMs(), "alertId", evalContext.Rule.ID, "name", evalContext.Rule.Name, "firing", evalContext.Firing, "attemptID", attemptID) attemptChan <- (attemptID + 1) @@ -237,7 +237,7 @@ func (e *AlertEngine) processJob(attemptID int, attemptChan chan int, cancelChan } // create new context with timeout for notifications - resultHandleCtx, resultHandleCancelFn := context.WithTimeout(context.Background(), setting.AlertingNotificationTimeout) + resultHandleCtx, resultHandleCancelFn := context.WithTimeout(context.Background(), e.Cfg.AlertingNotificationTimeout) cancelChan <- resultHandleCancelFn // override the context used for evaluation with a new context for notifications. diff --git a/pkg/services/alerting/engine_integration_test.go b/pkg/services/alerting/engine_integration_test.go index bc114528e7b..8fcc6b7495d 100644 --- a/pkg/services/alerting/engine_integration_test.go +++ b/pkg/services/alerting/engine_integration_test.go @@ -37,16 +37,17 @@ func TestIntegrationEngineTimeouts(t *testing.T) { tracer := tracing.InitializeTracerForTest() dsMock := &datasources.FakeDataSourceService{} annotationsRepo := annotationstest.NewFakeAnnotationsRepo() - engine := ProvideAlertEngine(nil, nil, nil, usMock, usValidatorMock, encService, nil, tracer, nil, setting.NewCfg(), nil, nil, localcache.New(time.Minute, time.Minute), dsMock, annotationsRepo) - setting.AlertingNotificationTimeout = 30 * time.Second - setting.AlertingMaxAttempts = 3 + cfg := setting.NewCfg() + engine := ProvideAlertEngine(nil, nil, nil, usMock, usValidatorMock, encService, nil, tracer, nil, cfg, nil, nil, localcache.New(time.Minute, time.Minute), dsMock, annotationsRepo) + cfg.AlertingNotificationTimeout = 30 * time.Second + cfg.AlertingMaxAttempts = 3 engine.resultHandler = &FakeResultHandler{} job := &Job{running: true, Rule: &Rule{}} t.Run("Should trigger as many retries as needed", func(t *testing.T) { t.Run("pended alert for datasource -> result handler should be worked", func(t *testing.T) { // reduce alert timeout to test quickly - setting.AlertingEvaluationTimeout = 30 * time.Second + cfg.AlertingEvaluationTimeout = 30 * time.Second transportTimeoutInterval := 2 * time.Second serverBusySleepDuration := 1 * time.Second @@ -62,7 +63,7 @@ func TestIntegrationEngineTimeouts(t *testing.T) { require.Equal(t, true, resultHandler.ResultHandleSucceed) // initialize for other tests. - setting.AlertingEvaluationTimeout = 2 * time.Second + cfg.AlertingEvaluationTimeout = 2 * time.Second engine.resultHandler = &FakeResultHandler{} }) }) diff --git a/pkg/services/alerting/engine_test.go b/pkg/services/alerting/engine_test.go index bcdd30ed157..71a8f88a101 100644 --- a/pkg/services/alerting/engine_test.go +++ b/pkg/services/alerting/engine_test.go @@ -122,7 +122,8 @@ func TestEngineProcessJob(t *testing.T) { usValidatorMock := &validator.FakeUsageStatsValidator{} encProvider := encryptionprovider.ProvideEncryptionProvider() - encService, err := encryptionservice.ProvideEncryptionService(encProvider, usMock, setting.NewCfg()) + cfg := setting.NewCfg() + encService, err := encryptionservice.ProvideEncryptionService(encProvider, usMock, cfg) require.NoError(t, err) tracer := tracing.InitializeTracerForTest() @@ -130,10 +131,10 @@ func TestEngineProcessJob(t *testing.T) { dsMock := &fd.FakeDataSourceService{ DataSources: []*datasources.DataSource{{ID: 1, Type: datasources.DS_PROMETHEUS}}, } - engine := ProvideAlertEngine(nil, nil, nil, usMock, usValidatorMock, encService, nil, tracer, store, setting.NewCfg(), nil, nil, localcache.New(time.Minute, time.Minute), dsMock, annotationstest.NewFakeAnnotationsRepo()) - setting.AlertingEvaluationTimeout = 30 * time.Second - setting.AlertingNotificationTimeout = 30 * time.Second - setting.AlertingMaxAttempts = 3 + engine := ProvideAlertEngine(nil, nil, nil, usMock, usValidatorMock, encService, nil, tracer, store, cfg, nil, nil, localcache.New(time.Minute, time.Minute), dsMock, annotationstest.NewFakeAnnotationsRepo()) + cfg.AlertingEvaluationTimeout = 30 * time.Second + cfg.AlertingNotificationTimeout = 30 * time.Second + cfg.AlertingMaxAttempts = 3 engine.resultHandler = &FakeResultHandler{} job := &Job{running: true, Rule: &Rule{}} @@ -157,9 +158,9 @@ func TestEngineProcessJob(t *testing.T) { t.Run("error + not last attempt -> retry", func(t *testing.T) { engine.evalHandler = NewFakeEvalHandler(0) - for i := 1; i < setting.AlertingMaxAttempts; i++ { + for i := 1; i < cfg.AlertingMaxAttempts; i++ { attemptChan := make(chan int, 1) - cancelChan := make(chan context.CancelFunc, setting.AlertingMaxAttempts) + cancelChan := make(chan context.CancelFunc, cfg.AlertingMaxAttempts) engine.processJob(i, attemptChan, cancelChan, job) nextAttemptID, more := <-attemptChan @@ -173,9 +174,9 @@ func TestEngineProcessJob(t *testing.T) { t.Run("error + last attempt -> no retry", func(t *testing.T) { engine.evalHandler = NewFakeEvalHandler(0) attemptChan := make(chan int, 1) - cancelChan := make(chan context.CancelFunc, setting.AlertingMaxAttempts) + cancelChan := make(chan context.CancelFunc, cfg.AlertingMaxAttempts) - engine.processJob(setting.AlertingMaxAttempts, attemptChan, cancelChan, job) + engine.processJob(cfg.AlertingMaxAttempts, attemptChan, cancelChan, job) nextAttemptID, more := <-attemptChan require.Equal(t, 0, nextAttemptID) @@ -186,7 +187,7 @@ func TestEngineProcessJob(t *testing.T) { t.Run("no error -> no retry", func(t *testing.T) { engine.evalHandler = NewFakeEvalHandler(1) attemptChan := make(chan int, 1) - cancelChan := make(chan context.CancelFunc, setting.AlertingMaxAttempts) + cancelChan := make(chan context.CancelFunc, cfg.AlertingMaxAttempts) engine.processJob(1, attemptChan, cancelChan, job) nextAttemptID, more := <-attemptChan @@ -199,7 +200,7 @@ func TestEngineProcessJob(t *testing.T) { t.Run("Should trigger as many retries as needed", func(t *testing.T) { t.Run("never success -> max retries number", func(t *testing.T) { - expectedAttempts := setting.AlertingMaxAttempts + expectedAttempts := cfg.AlertingMaxAttempts evalHandler := NewFakeEvalHandler(0) engine.evalHandler = evalHandler @@ -219,7 +220,7 @@ func TestEngineProcessJob(t *testing.T) { }) t.Run("some errors before success -> some retries", func(t *testing.T) { - expectedAttempts := int(math.Ceil(float64(setting.AlertingMaxAttempts) / 2)) + expectedAttempts := int(math.Ceil(float64(cfg.AlertingMaxAttempts) / 2)) evalHandler := NewFakeEvalHandler(expectedAttempts) engine.evalHandler = evalHandler diff --git a/pkg/services/alerting/notifier.go b/pkg/services/alerting/notifier.go index 593d4610512..400355b1146 100644 --- a/pkg/services/alerting/notifier.go +++ b/pkg/services/alerting/notifier.go @@ -20,8 +20,8 @@ import ( // for stubbing in tests // //nolint:gocritic -var newImageUploaderProvider = func() (imguploader.ImageUploader, error) { - return imguploader.NewImageUploader() +var newImageUploaderProvider = func(cfg *setting.Cfg) (imguploader.ImageUploader, error) { + return imguploader.NewImageUploader(cfg) } // NotifierPlugin holds meta information about a notifier. @@ -87,8 +87,9 @@ type ShowWhen struct { Is string `json:"is"` } -func newNotificationService(renderService rendering.Service, sqlStore AlertStore, notificationSvc *notifications.NotificationService, decryptFn GetDecryptedValueFn) *notificationService { +func newNotificationService(cfg *setting.Cfg, renderService rendering.Service, sqlStore AlertStore, notificationSvc *notifications.NotificationService, decryptFn GetDecryptedValueFn) *notificationService { return ¬ificationService{ + cfg: cfg, log: log.New("alerting.notifier"), renderService: renderService, sqlStore: sqlStore, @@ -98,6 +99,7 @@ func newNotificationService(renderService rendering.Service, sqlStore AlertStore } type notificationService struct { + cfg *setting.Cfg log log.Logger renderService rendering.Service sqlStore AlertStore @@ -119,7 +121,7 @@ func (n *notificationService) SendIfNeeded(evalCtx *EvalContext) error { if notifierStates.ShouldUploadImage() { // Create a copy of EvalContext and give it a new, shorter, timeout context to upload the image uploadEvalCtx := *evalCtx - timeout := setting.AlertingNotificationTimeout / 2 + timeout := n.cfg.AlertingNotificationTimeout / 2 var uploadCtxCancel func() uploadEvalCtx.Ctx, uploadCtxCancel = context.WithTimeout(evalCtx.Ctx, timeout) @@ -202,7 +204,7 @@ func (n *notificationService) sendNotifications(evalContext *EvalContext, notifi } func (n *notificationService) renderAndUploadImage(evalCtx *EvalContext, timeout time.Duration) (err error) { - uploader, err := newImageUploaderProvider() + uploader, err := newImageUploaderProvider(n.cfg) if err != nil { return err } @@ -217,7 +219,7 @@ func (n *notificationService) renderAndUploadImage(evalCtx *EvalContext, timeout }, Width: 1000, Height: 500, - ConcurrentLimit: setting.AlertingRenderLimit, + ConcurrentLimit: n.cfg.AlertingRenderLimit, Theme: models.ThemeDark, } @@ -266,7 +268,7 @@ func (n *notificationService) getNeededNotifiers(orgID int64, notificationUids [ var result notifierStateSlice for _, notification := range res { - not, err := InitNotifier(notification, n.decryptFn, n.notificationService) + not, err := InitNotifier(n.cfg, notification, n.decryptFn, n.notificationService) if err != nil { n.log.Error("Could not create notifier", "notifier", notification.UID, "error", err) continue @@ -296,13 +298,13 @@ func (n *notificationService) getNeededNotifiers(orgID int64, notificationUids [ } // InitNotifier instantiate a new notifier based on the model. -func InitNotifier(model *alertmodels.AlertNotification, fn GetDecryptedValueFn, notificationService *notifications.NotificationService) (Notifier, error) { +func InitNotifier(cfg *setting.Cfg, model *alertmodels.AlertNotification, fn GetDecryptedValueFn, notificationService *notifications.NotificationService) (Notifier, error) { notifierPlugin, found := notifierFactories[model.Type] if !found { return nil, fmt.Errorf("unsupported notification type %q", model.Type) } - return notifierPlugin.Factory(model, fn, notificationService) + return notifierPlugin.Factory(cfg, model, fn, notificationService) } // GetDecryptedValueFn is a function that returns the decrypted value of @@ -310,7 +312,7 @@ func InitNotifier(model *alertmodels.AlertNotification, fn GetDecryptedValueFn, type GetDecryptedValueFn func(ctx context.Context, sjd map[string][]byte, key string, fallback string, secret string) string // NotifierFactory is a signature for creating notifiers. -type NotifierFactory func(*alertmodels.AlertNotification, GetDecryptedValueFn, notifications.Service) (Notifier, error) +type NotifierFactory func(*setting.Cfg, *alertmodels.AlertNotification, GetDecryptedValueFn, notifications.Service) (Notifier, error) var notifierFactories = make(map[string]*NotifierPlugin) diff --git a/pkg/services/alerting/notifier_test.go b/pkg/services/alerting/notifier_test.go index 93342526f51..b550586d436 100644 --- a/pkg/services/alerting/notifier_test.go +++ b/pkg/services/alerting/notifier_test.go @@ -71,7 +71,7 @@ func TestNotificationService(t *testing.T) { notificationServiceScenario(t, "Given alert rule with upload image enabled and render times out should send notification", evalCtx, true, func(sc *scenarioContext) { - setting.AlertingNotificationTimeout = 200 * time.Millisecond + sc.notificationService.cfg.AlertingNotificationTimeout = 200 * time.Millisecond sc.renderProvider = func(ctx context.Context, opts rendering.Opts) (*rendering.RenderResult, error) { wait := make(chan bool) @@ -101,7 +101,7 @@ func TestNotificationService(t *testing.T) { notificationServiceScenario(t, "Given alert rule with upload image enabled and upload times out should send notification", evalCtx, true, func(sc *scenarioContext) { - setting.AlertingNotificationTimeout = 200 * time.Millisecond + sc.notificationService.cfg.AlertingNotificationTimeout = 200 * time.Millisecond sc.uploadProvider = func(ctx context.Context, path string) (string, error) { wait := make(chan bool) @@ -204,8 +204,6 @@ func notificationServiceScenario(t *testing.T, name string, evalCtx *EvalContext }, nil } - setting.AlertingNotificationTimeout = 30 * time.Second - scenarioCtx := &scenarioContext{ t: t, evalCtx: evalCtx, @@ -229,7 +227,7 @@ func notificationServiceScenario(t *testing.T, name string, evalCtx *EvalContext } origNewImageUploaderProvider := newImageUploaderProvider - newImageUploaderProvider = func() (imguploader.ImageUploader, error) { + newImageUploaderProvider = func(cfg *setting.Cfg) (imguploader.ImageUploader, error) { return imageUploader, nil } defer func() { @@ -258,7 +256,8 @@ func notificationServiceScenario(t *testing.T, name string, evalCtx *EvalContext }, } - scenarioCtx.notificationService = newNotificationService(renderService, store, nil, nil) + scenarioCtx.notificationService = newNotificationService(setting.NewCfg(), renderService, store, nil, nil) + scenarioCtx.notificationService.cfg.AlertingNotificationTimeout = 30 * time.Second fn(scenarioCtx) }) } @@ -274,7 +273,7 @@ type testNotifier struct { Frequency time.Duration } -func newTestNotifier(model *alertmodels.AlertNotification, _ GetDecryptedValueFn, ns notifications.Service) (Notifier, error) { +func newTestNotifier(_ *setting.Cfg, model *alertmodels.AlertNotification, _ GetDecryptedValueFn, ns notifications.Service) (Notifier, error) { uploadImage := true value, exist := model.Settings.CheckGet("uploadImage") if exist { diff --git a/pkg/services/alerting/notifiers/alertmanager.go b/pkg/services/alerting/notifiers/alertmanager.go index 4936dee2cdb..940f2b7b3df 100644 --- a/pkg/services/alerting/notifiers/alertmanager.go +++ b/pkg/services/alerting/notifiers/alertmanager.go @@ -50,7 +50,7 @@ func init() { } // NewAlertmanagerNotifier returns a new Alertmanager notifier -func NewAlertmanagerNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { +func NewAlertmanagerNotifier(cfg *setting.Cfg, model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { urlString := model.Settings.Get("url").MustString() if urlString == "" { return nil, alerting.ValidationError{Reason: "Could not find url property in settings"} @@ -64,7 +64,7 @@ func NewAlertmanagerNotifier(model *models.AlertNotification, fn alerting.GetDec } } basicAuthUser := model.Settings.Get("basicAuthUser").MustString() - basicAuthPassword := fn(context.Background(), model.SecureSettings, "basicAuthPassword", model.Settings.Get("basicAuthPassword").MustString(), setting.SecretKey) + basicAuthPassword := fn(context.Background(), model.SecureSettings, "basicAuthPassword", model.Settings.Get("basicAuthPassword").MustString(), cfg.SecretKey) return &AlertmanagerNotifier{ NotifierBase: NewNotifierBase(model, ns), diff --git a/pkg/services/alerting/notifiers/alertmanager_test.go b/pkg/services/alerting/notifiers/alertmanager_test.go index 4f3b8e762bd..1b46dda95f2 100644 --- a/pkg/services/alerting/notifiers/alertmanager_test.go +++ b/pkg/services/alerting/notifiers/alertmanager_test.go @@ -14,6 +14,7 @@ import ( "github.com/grafana/grafana/pkg/services/annotations/annotationstest" encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/grafana/grafana/pkg/services/validations" + "github.com/grafana/grafana/pkg/setting" ) func TestReplaceIllegalCharswithUnderscore(t *testing.T) { @@ -95,7 +96,7 @@ func TestAlertmanagerNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := NewAlertmanagerNotifier(model, encryptionService.GetDecryptedValue, nil) + _, err := NewAlertmanagerNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -109,7 +110,7 @@ func TestAlertmanagerNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewAlertmanagerNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewAlertmanagerNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) alertmanagerNotifier := not.(*AlertmanagerNotifier) require.NoError(t, err) @@ -128,7 +129,7 @@ func TestAlertmanagerNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewAlertmanagerNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewAlertmanagerNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) alertmanagerNotifier := not.(*AlertmanagerNotifier) require.NoError(t, err) diff --git a/pkg/services/alerting/notifiers/dingding.go b/pkg/services/alerting/notifiers/dingding.go index ab4f452e988..dda508e9f2f 100644 --- a/pkg/services/alerting/notifiers/dingding.go +++ b/pkg/services/alerting/notifiers/dingding.go @@ -9,6 +9,7 @@ import ( "github.com/grafana/grafana/pkg/services/alerting" "github.com/grafana/grafana/pkg/services/alerting/models" "github.com/grafana/grafana/pkg/services/notifications" + "github.com/grafana/grafana/pkg/setting" ) const defaultDingdingMsgType = "link" @@ -47,7 +48,7 @@ func init() { }) } -func newDingDingNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { +func newDingDingNotifier(_ *setting.Cfg, model *models.AlertNotification, _ alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { url := model.Settings.Get("url").MustString() if url == "" { return nil, alerting.ValidationError{Reason: "Could not find url property in settings"} diff --git a/pkg/services/alerting/notifiers/dingding_test.go b/pkg/services/alerting/notifiers/dingding_test.go index 0ff465837c1..15349c76842 100644 --- a/pkg/services/alerting/notifiers/dingding_test.go +++ b/pkg/services/alerting/notifiers/dingding_test.go @@ -27,7 +27,7 @@ func TestDingDingNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := newDingDingNotifier(model, encryptionService.GetDecryptedValue, nil) + _, err := newDingDingNotifier(nil, model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) t.Run("settings should trigger incident", func(t *testing.T) { @@ -40,7 +40,7 @@ func TestDingDingNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := newDingDingNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := newDingDingNotifier(nil, model, encryptionService.GetDecryptedValue, nil) notifier := not.(*DingDingNotifier) require.Nil(t, err) diff --git a/pkg/services/alerting/notifiers/discord.go b/pkg/services/alerting/notifiers/discord.go index b27336c3fa6..a9eedc0847d 100644 --- a/pkg/services/alerting/notifiers/discord.go +++ b/pkg/services/alerting/notifiers/discord.go @@ -57,7 +57,7 @@ func init() { }) } -func newDiscordNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { +func newDiscordNotifier(_ *setting.Cfg, model *models.AlertNotification, _ alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { avatar := model.Settings.Get("avatar_url").MustString() content := model.Settings.Get("content").MustString() url := model.Settings.Get("url").MustString() diff --git a/pkg/services/alerting/notifiers/discord_test.go b/pkg/services/alerting/notifiers/discord_test.go index d173a85d215..e2e5ec937b2 100644 --- a/pkg/services/alerting/notifiers/discord_test.go +++ b/pkg/services/alerting/notifiers/discord_test.go @@ -24,7 +24,7 @@ func TestDiscordNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := newDiscordNotifier(model, encryptionService.GetDecryptedValue, nil) + _, err := newDiscordNotifier(nil, model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -43,7 +43,7 @@ func TestDiscordNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := newDiscordNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := newDiscordNotifier(nil, model, encryptionService.GetDecryptedValue, nil) discordNotifier := not.(*DiscordNotifier) require.Nil(t, err) diff --git a/pkg/services/alerting/notifiers/email.go b/pkg/services/alerting/notifiers/email.go index 08bfe238719..00e4bce7176 100644 --- a/pkg/services/alerting/notifiers/email.go +++ b/pkg/services/alerting/notifiers/email.go @@ -43,11 +43,12 @@ type EmailNotifier struct { Addresses []string SingleEmail bool log log.Logger + appURL string } // NewEmailNotifier is the constructor function // for the EmailNotifier. -func NewEmailNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { +func NewEmailNotifier(cfg *setting.Cfg, model *models.AlertNotification, _ alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { addressesString := model.Settings.Get("addresses").MustString() singleEmail := model.Settings.Get("singleEmail").MustBool(false) @@ -63,6 +64,7 @@ func NewEmailNotifier(model *models.AlertNotification, _ alerting.GetDecryptedVa Addresses: addresses, SingleEmail: singleEmail, log: log.New("alerting.notifier.email"), + appURL: cfg.AppURL, }, nil } @@ -94,7 +96,7 @@ func (en *EmailNotifier) Notify(evalContext *alerting.EvalContext) error { "RuleUrl": ruleURL, "ImageLink": "", "EmbeddedImage": "", - "AlertPageUrl": setting.AppUrl + "alerting", + "AlertPageUrl": en.appURL + "alerting", "EvalMatches": evalContext.EvalMatches, }, To: en.Addresses, diff --git a/pkg/services/alerting/notifiers/email_test.go b/pkg/services/alerting/notifiers/email_test.go index 69ca1bffd21..85bfa1b2715 100644 --- a/pkg/services/alerting/notifiers/email_test.go +++ b/pkg/services/alerting/notifiers/email_test.go @@ -8,6 +8,7 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/services/alerting/models" encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" + "github.com/grafana/grafana/pkg/setting" ) func TestEmailNotifier(t *testing.T) { @@ -24,7 +25,7 @@ func TestEmailNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := NewEmailNotifier(model, encryptionService.GetDecryptedValue, nil) + _, err := NewEmailNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -41,7 +42,7 @@ func TestEmailNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewEmailNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewEmailNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) emailNotifier := not.(*EmailNotifier) require.Nil(t, err) @@ -65,7 +66,7 @@ func TestEmailNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewEmailNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewEmailNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) emailNotifier := not.(*EmailNotifier) require.Nil(t, err) diff --git a/pkg/services/alerting/notifiers/googlechat.go b/pkg/services/alerting/notifiers/googlechat.go index 7af742e6403..b19537d535c 100644 --- a/pkg/services/alerting/notifiers/googlechat.go +++ b/pkg/services/alerting/notifiers/googlechat.go @@ -33,7 +33,7 @@ func init() { }) } -func newGoogleChatNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { +func newGoogleChatNotifier(_ *setting.Cfg, model *models.AlertNotification, _ alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { url := model.Settings.Get("url").MustString() if url == "" { return nil, alerting.ValidationError{Reason: "Could not find url property in settings"} diff --git a/pkg/services/alerting/notifiers/googlechat_test.go b/pkg/services/alerting/notifiers/googlechat_test.go index 48c102a1fe7..dd00ee88509 100644 --- a/pkg/services/alerting/notifiers/googlechat_test.go +++ b/pkg/services/alerting/notifiers/googlechat_test.go @@ -24,7 +24,7 @@ func TestGoogleChatNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := newGoogleChatNotifier(model, encryptionService.GetDecryptedValue, nil) + _, err := newGoogleChatNotifier(nil, model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -41,7 +41,7 @@ func TestGoogleChatNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := newGoogleChatNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := newGoogleChatNotifier(nil, model, encryptionService.GetDecryptedValue, nil) webhookNotifier := not.(*GoogleChatNotifier) require.Nil(t, err) diff --git a/pkg/services/alerting/notifiers/hipchat.go b/pkg/services/alerting/notifiers/hipchat.go index 85817731077..3a345306f65 100644 --- a/pkg/services/alerting/notifiers/hipchat.go +++ b/pkg/services/alerting/notifiers/hipchat.go @@ -10,6 +10,7 @@ import ( "github.com/grafana/grafana/pkg/services/alerting" "github.com/grafana/grafana/pkg/services/alerting/models" "github.com/grafana/grafana/pkg/services/notifications" + "github.com/grafana/grafana/pkg/setting" ) func init() { @@ -52,7 +53,7 @@ const ( // NewHipChatNotifier is the constructor functions // for the HipChatNotifier -func NewHipChatNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { +func NewHipChatNotifier(_ *setting.Cfg, model *models.AlertNotification, _ alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { url := model.Settings.Get("url").MustString() url = strings.TrimSuffix(url, "/") if url == "" { diff --git a/pkg/services/alerting/notifiers/hipchat_test.go b/pkg/services/alerting/notifiers/hipchat_test.go index 625eb14da8c..d8e7d23986c 100644 --- a/pkg/services/alerting/notifiers/hipchat_test.go +++ b/pkg/services/alerting/notifiers/hipchat_test.go @@ -25,7 +25,7 @@ func TestHipChatNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := NewHipChatNotifier(model, encryptionService.GetDecryptedValue, nil) + _, err := NewHipChatNotifier(nil, model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -41,7 +41,7 @@ func TestHipChatNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewHipChatNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewHipChatNotifier(nil, model, encryptionService.GetDecryptedValue, nil) hipchatNotifier := not.(*HipChatNotifier) require.Nil(t, err) @@ -67,7 +67,7 @@ func TestHipChatNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewHipChatNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewHipChatNotifier(nil, model, encryptionService.GetDecryptedValue, nil) hipchatNotifier := not.(*HipChatNotifier) require.Nil(t, err) diff --git a/pkg/services/alerting/notifiers/kafka.go b/pkg/services/alerting/notifiers/kafka.go index 601e64351ca..46c14187a5d 100644 --- a/pkg/services/alerting/notifiers/kafka.go +++ b/pkg/services/alerting/notifiers/kafka.go @@ -9,6 +9,7 @@ import ( "github.com/grafana/grafana/pkg/services/alerting" "github.com/grafana/grafana/pkg/services/alerting/models" "github.com/grafana/grafana/pkg/services/notifications" + "github.com/grafana/grafana/pkg/setting" ) func init() { @@ -40,7 +41,7 @@ func init() { } // NewKafkaNotifier is the constructor function for the Kafka notifier. -func NewKafkaNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { +func NewKafkaNotifier(_ *setting.Cfg, model *models.AlertNotification, _ alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { endpoint := model.Settings.Get("kafkaRestProxy").MustString() if endpoint == "" { return nil, alerting.ValidationError{Reason: "Could not find kafka rest proxy endpoint property in settings"} diff --git a/pkg/services/alerting/notifiers/kafka_test.go b/pkg/services/alerting/notifiers/kafka_test.go index 95dbaedf57d..0e7aafb1faf 100644 --- a/pkg/services/alerting/notifiers/kafka_test.go +++ b/pkg/services/alerting/notifiers/kafka_test.go @@ -24,7 +24,7 @@ func TestKafkaNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := NewKafkaNotifier(model, encryptionService.GetDecryptedValue, nil) + _, err := NewKafkaNotifier(nil, model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -42,7 +42,7 @@ func TestKafkaNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewKafkaNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewKafkaNotifier(nil, model, encryptionService.GetDecryptedValue, nil) kafkaNotifier := not.(*KafkaNotifier) require.Nil(t, err) diff --git a/pkg/services/alerting/notifiers/line.go b/pkg/services/alerting/notifiers/line.go index 3bf4d09831e..8cc30ff9ab0 100644 --- a/pkg/services/alerting/notifiers/line.go +++ b/pkg/services/alerting/notifiers/line.go @@ -37,8 +37,8 @@ const ( ) // NewLINENotifier is the constructor for the LINE notifier -func NewLINENotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { - token := fn(context.Background(), model.SecureSettings, "token", model.Settings.Get("token").MustString(), setting.SecretKey) +func NewLINENotifier(cfg *setting.Cfg, model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { + token := fn(context.Background(), model.SecureSettings, "token", model.Settings.Get("token").MustString(), cfg.SecretKey) if token == "" { return nil, alerting.ValidationError{Reason: "Could not find token in settings"} } diff --git a/pkg/services/alerting/notifiers/line_test.go b/pkg/services/alerting/notifiers/line_test.go index c6086e09c3b..1cbea02ce7d 100644 --- a/pkg/services/alerting/notifiers/line_test.go +++ b/pkg/services/alerting/notifiers/line_test.go @@ -8,6 +8,7 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/services/alerting/models" encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" + "github.com/grafana/grafana/pkg/setting" ) func TestLineNotifier(t *testing.T) { @@ -23,7 +24,7 @@ func TestLineNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := NewLINENotifier(model, encryptionService.GetDecryptedValue, nil) + _, err := NewLINENotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) t.Run("settings should trigger incident", func(t *testing.T) { @@ -38,7 +39,7 @@ func TestLineNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewLINENotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewLINENotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) lineNotifier := not.(*LineNotifier) require.Nil(t, err) diff --git a/pkg/services/alerting/notifiers/opsgenie.go b/pkg/services/alerting/notifiers/opsgenie.go index dcf6b7b35ee..10dfe485866 100644 --- a/pkg/services/alerting/notifiers/opsgenie.go +++ b/pkg/services/alerting/notifiers/opsgenie.go @@ -84,10 +84,10 @@ const ( ) // NewOpsGenieNotifier is the constructor for OpsGenie. -func NewOpsGenieNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { +func NewOpsGenieNotifier(cfg *setting.Cfg, model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { autoClose := model.Settings.Get("autoClose").MustBool(true) overridePriority := model.Settings.Get("overridePriority").MustBool(true) - apiKey := fn(context.Background(), model.SecureSettings, "apiKey", model.Settings.Get("apiKey").MustString(), setting.SecretKey) + apiKey := fn(context.Background(), model.SecureSettings, "apiKey", model.Settings.Get("apiKey").MustString(), cfg.SecretKey) apiURL := model.Settings.Get("apiUrl").MustString() if apiKey == "" { return nil, alerting.ValidationError{Reason: "Could not find api key property in settings"} diff --git a/pkg/services/alerting/notifiers/opsgenie_test.go b/pkg/services/alerting/notifiers/opsgenie_test.go index 1ff97eef074..bd9503f4534 100644 --- a/pkg/services/alerting/notifiers/opsgenie_test.go +++ b/pkg/services/alerting/notifiers/opsgenie_test.go @@ -16,6 +16,7 @@ import ( "github.com/grafana/grafana/pkg/services/notifications" "github.com/grafana/grafana/pkg/services/tag" "github.com/grafana/grafana/pkg/services/validations" + "github.com/grafana/grafana/pkg/setting" ) func TestOpsGenieNotifier(t *testing.T) { @@ -32,7 +33,7 @@ func TestOpsGenieNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := NewOpsGenieNotifier(model, encryptionService.GetDecryptedValue, nil) + _, err := NewOpsGenieNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -49,7 +50,7 @@ func TestOpsGenieNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewOpsGenieNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewOpsGenieNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) opsgenieNotifier := not.(*OpsGenieNotifier) require.Nil(t, err) @@ -73,7 +74,7 @@ func TestOpsGenieNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := NewOpsGenieNotifier(model, encryptionService.GetDecryptedValue, nil) + _, err := NewOpsGenieNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) require.Equal(t, reflect.TypeOf(err), reflect.TypeOf(alerting.ValidationError{})) require.True(t, strings.HasSuffix(err.Error(), "Invalid value for sendTagsAs: \"not_a_valid_value\"")) @@ -97,7 +98,7 @@ func TestOpsGenieNotifier(t *testing.T) { } notificationService := notifications.MockNotificationService() - notifier, notifierErr := NewOpsGenieNotifier(model, encryptionService.GetDecryptedValue, notificationService) // unhandled error + notifier, notifierErr := NewOpsGenieNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, notificationService) // unhandled error opsgenieNotifier := notifier.(*OpsGenieNotifier) @@ -146,7 +147,7 @@ func TestOpsGenieNotifier(t *testing.T) { } notificationService := notifications.MockNotificationService() - notifier, notifierErr := NewOpsGenieNotifier(model, encryptionService.GetDecryptedValue, notificationService) // unhandled error + notifier, notifierErr := NewOpsGenieNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, notificationService) // unhandled error opsgenieNotifier := notifier.(*OpsGenieNotifier) @@ -195,7 +196,7 @@ func TestOpsGenieNotifier(t *testing.T) { } notificationService := notifications.MockNotificationService() - notifier, notifierErr := NewOpsGenieNotifier(model, encryptionService.GetDecryptedValue, notificationService) // unhandled error + notifier, notifierErr := NewOpsGenieNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, notificationService) // unhandled error opsgenieNotifier := notifier.(*OpsGenieNotifier) diff --git a/pkg/services/alerting/notifiers/pagerduty.go b/pkg/services/alerting/notifiers/pagerduty.go index 2ecf0833285..0dc0739c507 100644 --- a/pkg/services/alerting/notifiers/pagerduty.go +++ b/pkg/services/alerting/notifiers/pagerduty.go @@ -76,10 +76,10 @@ var ( ) // NewPagerdutyNotifier is the constructor for the PagerDuty notifier -func NewPagerdutyNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { +func NewPagerdutyNotifier(cfg *setting.Cfg, model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { severity := model.Settings.Get("severity").MustString("critical") autoResolve := model.Settings.Get("autoResolve").MustBool(false) - key := fn(context.Background(), model.SecureSettings, "integrationKey", model.Settings.Get("integrationKey").MustString(), setting.SecretKey) + key := fn(context.Background(), model.SecureSettings, "integrationKey", model.Settings.Get("integrationKey").MustString(), cfg.SecretKey) messageInDetails := model.Settings.Get("messageInDetails").MustBool(false) if key == "" { return nil, alerting.ValidationError{Reason: "Could not find integration key property in settings"} diff --git a/pkg/services/alerting/notifiers/pagerduty_test.go b/pkg/services/alerting/notifiers/pagerduty_test.go index c2b200ff69c..3c2f04858b1 100644 --- a/pkg/services/alerting/notifiers/pagerduty_test.go +++ b/pkg/services/alerting/notifiers/pagerduty_test.go @@ -16,6 +16,7 @@ import ( encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/grafana/grafana/pkg/services/tag" "github.com/grafana/grafana/pkg/services/validations" + "github.com/grafana/grafana/pkg/setting" ) func presenceComparer(a, b string) bool { @@ -43,7 +44,7 @@ func TestPagerdutyNotifier(t *testing.T) { Settings: settingsJSON, } - _, err = NewPagerdutyNotifier(model, encryptionService.GetDecryptedValue, nil) + _, err = NewPagerdutyNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -59,7 +60,7 @@ func TestPagerdutyNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewPagerdutyNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewPagerdutyNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) pagerdutyNotifier := not.(*PagerdutyNotifier) require.Nil(t, err) @@ -82,7 +83,7 @@ func TestPagerdutyNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewPagerdutyNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewPagerdutyNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) pagerdutyNotifier := not.(*PagerdutyNotifier) require.Nil(t, err) @@ -109,7 +110,7 @@ func TestPagerdutyNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewPagerdutyNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewPagerdutyNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) pagerdutyNotifier := not.(*PagerdutyNotifier) require.Nil(t, err) @@ -134,7 +135,7 @@ func TestPagerdutyNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewPagerdutyNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewPagerdutyNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) require.Nil(t, err) pagerdutyNotifier := not.(*PagerdutyNotifier) @@ -191,7 +192,7 @@ func TestPagerdutyNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewPagerdutyNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewPagerdutyNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) require.Nil(t, err) pagerdutyNotifier := not.(*PagerdutyNotifier) @@ -248,7 +249,7 @@ func TestPagerdutyNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewPagerdutyNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewPagerdutyNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) require.Nil(t, err) pagerdutyNotifier := not.(*PagerdutyNotifier) @@ -318,7 +319,7 @@ func TestPagerdutyNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewPagerdutyNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewPagerdutyNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) require.NoError(t, err) pagerdutyNotifier := not.(*PagerdutyNotifier) @@ -398,7 +399,7 @@ func TestPagerdutyNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewPagerdutyNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewPagerdutyNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) require.NoError(t, err) pagerdutyNotifier := not.(*PagerdutyNotifier) @@ -477,7 +478,7 @@ func TestPagerdutyNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewPagerdutyNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewPagerdutyNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) require.NoError(t, err) pagerdutyNotifier := not.(*PagerdutyNotifier) diff --git a/pkg/services/alerting/notifiers/pushover.go b/pkg/services/alerting/notifiers/pushover.go index dcfd187d683..e267c9ff747 100644 --- a/pkg/services/alerting/notifiers/pushover.go +++ b/pkg/services/alerting/notifiers/pushover.go @@ -193,9 +193,9 @@ func init() { } // NewPushoverNotifier is the constructor for the Pushover Notifier -func NewPushoverNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { - userKey := fn(context.Background(), model.SecureSettings, "userKey", model.Settings.Get("userKey").MustString(), setting.SecretKey) - APIToken := fn(context.Background(), model.SecureSettings, "apiToken", model.Settings.Get("apiToken").MustString(), setting.SecretKey) +func NewPushoverNotifier(cfg *setting.Cfg, model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { + userKey := fn(context.Background(), model.SecureSettings, "userKey", model.Settings.Get("userKey").MustString(), cfg.SecretKey) + APIToken := fn(context.Background(), model.SecureSettings, "apiToken", model.Settings.Get("apiToken").MustString(), cfg.SecretKey) device := model.Settings.Get("device").MustString() alertingPriority, err := strconv.Atoi(model.Settings.Get("priority").MustString("0")) // default Normal if err != nil { diff --git a/pkg/services/alerting/notifiers/pushover_test.go b/pkg/services/alerting/notifiers/pushover_test.go index 371e78fcd71..86ad2a2cb4c 100644 --- a/pkg/services/alerting/notifiers/pushover_test.go +++ b/pkg/services/alerting/notifiers/pushover_test.go @@ -13,6 +13,7 @@ import ( "github.com/grafana/grafana/pkg/services/annotations/annotationstest" encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/grafana/grafana/pkg/services/validations" + "github.com/grafana/grafana/pkg/setting" ) func TestPushoverNotifier(t *testing.T) { @@ -29,7 +30,7 @@ func TestPushoverNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := NewPushoverNotifier(model, encryptionService.GetDecryptedValue, nil) + _, err := NewPushoverNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -51,7 +52,7 @@ func TestPushoverNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewPushoverNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewPushoverNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) pushoverNotifier := not.(*PushoverNotifier) require.Nil(t, err) diff --git a/pkg/services/alerting/notifiers/sensu.go b/pkg/services/alerting/notifiers/sensu.go index c00dad176dc..af3d70cc6ce 100644 --- a/pkg/services/alerting/notifiers/sensu.go +++ b/pkg/services/alerting/notifiers/sensu.go @@ -61,7 +61,7 @@ func init() { } // NewSensuNotifier is the constructor for the Sensu Notifier. -func NewSensuNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { +func NewSensuNotifier(cfg *setting.Cfg, model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { url := model.Settings.Get("url").MustString() if url == "" { return nil, alerting.ValidationError{Reason: "Could not find url property in settings"} @@ -72,7 +72,7 @@ func NewSensuNotifier(model *models.AlertNotification, fn alerting.GetDecryptedV URL: url, User: model.Settings.Get("username").MustString(), Source: model.Settings.Get("source").MustString(), - Password: fn(context.Background(), model.SecureSettings, "password", model.Settings.Get("password").MustString(), setting.SecretKey), + Password: fn(context.Background(), model.SecureSettings, "password", model.Settings.Get("password").MustString(), cfg.SecretKey), Handler: model.Settings.Get("handler").MustString(), log: log.New("alerting.notifier.sensu"), }, nil diff --git a/pkg/services/alerting/notifiers/sensu_test.go b/pkg/services/alerting/notifiers/sensu_test.go index 5b6503f798f..c8e47930ea1 100644 --- a/pkg/services/alerting/notifiers/sensu_test.go +++ b/pkg/services/alerting/notifiers/sensu_test.go @@ -8,6 +8,7 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/services/alerting/models" encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" + "github.com/grafana/grafana/pkg/setting" ) func TestSensuNotifier(t *testing.T) { @@ -24,7 +25,7 @@ func TestSensuNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := NewSensuNotifier(model, encryptionService.GetDecryptedValue, nil) + _, err := NewSensuNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -43,7 +44,7 @@ func TestSensuNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewSensuNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewSensuNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) sensuNotifier := not.(*SensuNotifier) require.Nil(t, err) diff --git a/pkg/services/alerting/notifiers/sensugo.go b/pkg/services/alerting/notifiers/sensugo.go index d5f6a4dbfaf..55650e584dd 100644 --- a/pkg/services/alerting/notifiers/sensugo.go +++ b/pkg/services/alerting/notifiers/sensugo.go @@ -72,9 +72,9 @@ func init() { } // NewSensuGoNotifier is the constructor for the Sensu Go Notifier. -func NewSensuGoNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { +func NewSensuGoNotifier(cfg *setting.Cfg, model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { url := model.Settings.Get("url").MustString() - apikey := fn(context.Background(), model.SecureSettings, "apikey", model.Settings.Get("apikey").MustString(), setting.SecretKey) + apikey := fn(context.Background(), model.SecureSettings, "apikey", model.Settings.Get("apikey").MustString(), cfg.SecretKey) if url == "" { return nil, alerting.ValidationError{Reason: "Could not find URL property in settings"} diff --git a/pkg/services/alerting/notifiers/sensugo_test.go b/pkg/services/alerting/notifiers/sensugo_test.go index 73d30ecf73b..4d8c82f7ad2 100644 --- a/pkg/services/alerting/notifiers/sensugo_test.go +++ b/pkg/services/alerting/notifiers/sensugo_test.go @@ -9,6 +9,7 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/services/alerting/models" encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" + "github.com/grafana/grafana/pkg/setting" ) func TestSensuGoNotifier(t *testing.T) { @@ -24,7 +25,7 @@ func TestSensuGoNotifier(t *testing.T) { encryptionService := encryptionservice.SetupTestService(t) - _, err = NewSensuGoNotifier(model, encryptionService.GetDecryptedValue, nil) + _, err = NewSensuGoNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) json = ` @@ -45,7 +46,7 @@ func TestSensuGoNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewSensuGoNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewSensuGoNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) require.NoError(t, err) sensuGoNotifier := not.(*SensuGoNotifier) diff --git a/pkg/services/alerting/notifiers/slack.go b/pkg/services/alerting/notifiers/slack.go index 7a673b99dd2..1b6810479f6 100644 --- a/pkg/services/alerting/notifiers/slack.go +++ b/pkg/services/alerting/notifiers/slack.go @@ -121,8 +121,8 @@ func init() { const slackAPIEndpoint = "https://slack.com/api/chat.postMessage" // NewSlackNotifier is the constructor for the Slack notifier. -func NewSlackNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { - urlStr := fn(context.Background(), model.SecureSettings, "url", model.Settings.Get("url").MustString(), setting.SecretKey) +func NewSlackNotifier(cfg *setting.Cfg, model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { + urlStr := fn(context.Background(), model.SecureSettings, "url", model.Settings.Get("url").MustString(), cfg.SecretKey) if urlStr == "" { urlStr = slackAPIEndpoint } @@ -143,7 +143,7 @@ func NewSlackNotifier(model *models.AlertNotification, fn alerting.GetDecryptedV mentionUsersStr := model.Settings.Get("mentionUsers").MustString() mentionGroupsStr := model.Settings.Get("mentionGroups").MustString() mentionChannel := model.Settings.Get("mentionChannel").MustString() - token := fn(context.Background(), model.SecureSettings, "token", model.Settings.Get("token").MustString(), setting.SecretKey) + token := fn(context.Background(), model.SecureSettings, "token", model.Settings.Get("token").MustString(), cfg.SecretKey) if token == "" && apiURL.String() == slackAPIEndpoint { return nil, alerting.ValidationError{ Reason: "token must be specified when using the Slack chat API", @@ -185,6 +185,7 @@ func NewSlackNotifier(model *models.AlertNotification, fn alerting.GetDecryptedV token: token, upload: uploadImage, log: log.New("alerting.notifier.slack"), + homePath: cfg.HomePath, }, nil } @@ -203,6 +204,7 @@ type SlackNotifier struct { token string upload bool log log.Logger + homePath string } // Notify sends an alert notification to Slack. @@ -408,7 +410,7 @@ func (sn *SlackNotifier) slackFileUpload(evalContext *alerting.EvalContext, log if evalContext.ImageOnDiskPath == "" { // nolint:gosec // We can ignore the gosec G304 warning on this one because `setting.HomePath` comes from Grafana's configuration file. - evalContext.ImageOnDiskPath = filepath.Join(setting.HomePath, "public/img/mixed_styles.png") + evalContext.ImageOnDiskPath = filepath.Join(sn.homePath, "public/img/mixed_styles.png") } log.Info("Uploading to slack via file.upload API") headers, uploadBody, err := sn.generateSlackBody(evalContext.ImageOnDiskPath, token, recipient) diff --git a/pkg/services/alerting/notifiers/slack_test.go b/pkg/services/alerting/notifiers/slack_test.go index 909257c741a..26270d36084 100644 --- a/pkg/services/alerting/notifiers/slack_test.go +++ b/pkg/services/alerting/notifiers/slack_test.go @@ -30,7 +30,7 @@ func TestSlackNotifier(t *testing.T) { Settings: settingsJSON, } - _, err = NewSlackNotifier(model, encryptionService.GetDecryptedValue, nil) + _, err = NewSlackNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) assert.EqualError(t, err, "alert validation error: recipient must be specified when using the Slack chat API") }) @@ -48,7 +48,7 @@ func TestSlackNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewSlackNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewSlackNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) require.NoError(t, err) slackNotifier := not.(*SlackNotifier) assert.Equal(t, "ops", slackNotifier.Name) @@ -86,7 +86,7 @@ func TestSlackNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewSlackNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewSlackNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) require.NoError(t, err) slackNotifier := not.(*SlackNotifier) assert.Equal(t, "ops", slackNotifier.Name) @@ -120,11 +120,12 @@ func TestSlackNotifier(t *testing.T) { require.NoError(t, err) encryptionService := encryptionService + cfg := setting.NewCfg() securedSettingsJSON, err := encryptionService.EncryptJsonData( context.Background(), map[string]string{ "token": "xenc-XXXXXXXX-XXXXXXXX-XXXXXXXXXX", - }, setting.SecretKey) + }, cfg.SecretKey) require.NoError(t, err) model := &models.AlertNotification{ @@ -134,7 +135,7 @@ func TestSlackNotifier(t *testing.T) { SecureSettings: securedSettingsJSON, } - not, err := NewSlackNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewSlackNotifier(cfg, model, encryptionService.GetDecryptedValue, nil) require.NoError(t, err) slackNotifier := not.(*SlackNotifier) assert.Equal(t, "ops", slackNotifier.Name) @@ -165,7 +166,7 @@ func TestSlackNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewSlackNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewSlackNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) require.NoError(t, err) slackNotifier := not.(*SlackNotifier) assert.Equal(t, "1ABCDE", slackNotifier.recipient) @@ -258,7 +259,7 @@ func TestSendSlackRequest(t *testing.T) { encryptionService := encryptionservice.SetupTestService(t) - not, err := NewSlackNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewSlackNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) require.NoError(t, err) slackNotifier := not.(*SlackNotifier) diff --git a/pkg/services/alerting/notifiers/teams.go b/pkg/services/alerting/notifiers/teams.go index a2a10a706c5..9543f528a39 100644 --- a/pkg/services/alerting/notifiers/teams.go +++ b/pkg/services/alerting/notifiers/teams.go @@ -7,6 +7,7 @@ import ( "github.com/grafana/grafana/pkg/services/alerting" "github.com/grafana/grafana/pkg/services/alerting/models" "github.com/grafana/grafana/pkg/services/notifications" + "github.com/grafana/grafana/pkg/setting" ) func init() { @@ -30,7 +31,7 @@ func init() { } // NewTeamsNotifier is the constructor for Teams notifier. -func NewTeamsNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { +func NewTeamsNotifier(_ *setting.Cfg, model *models.AlertNotification, _ alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { url := model.Settings.Get("url").MustString() if url == "" { return nil, alerting.ValidationError{Reason: "Could not find url property in settings"} diff --git a/pkg/services/alerting/notifiers/teams_test.go b/pkg/services/alerting/notifiers/teams_test.go index ce100158882..93d5cd2a141 100644 --- a/pkg/services/alerting/notifiers/teams_test.go +++ b/pkg/services/alerting/notifiers/teams_test.go @@ -24,7 +24,7 @@ func TestTeamsNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := NewTeamsNotifier(model, encryptionService.GetDecryptedValue, nil) + _, err := NewTeamsNotifier(nil, model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -41,7 +41,7 @@ func TestTeamsNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewTeamsNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewTeamsNotifier(nil, model, encryptionService.GetDecryptedValue, nil) teamsNotifier := not.(*TeamsNotifier) require.Nil(t, err) @@ -63,7 +63,7 @@ func TestTeamsNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewTeamsNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewTeamsNotifier(nil, model, encryptionService.GetDecryptedValue, nil) teamsNotifier := not.(*TeamsNotifier) require.Nil(t, err) diff --git a/pkg/services/alerting/notifiers/telegram.go b/pkg/services/alerting/notifiers/telegram.go index 0dcf34afb67..9fb362d2d75 100644 --- a/pkg/services/alerting/notifiers/telegram.go +++ b/pkg/services/alerting/notifiers/telegram.go @@ -63,12 +63,12 @@ type TelegramNotifier struct { } // NewTelegramNotifier is the constructor for the Telegram notifier -func NewTelegramNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { +func NewTelegramNotifier(cfg *setting.Cfg, model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { if model.Settings == nil { return nil, alerting.ValidationError{Reason: "No Settings Supplied"} } - botToken := fn(context.Background(), model.SecureSettings, "bottoken", model.Settings.Get("bottoken").MustString(), setting.SecretKey) + botToken := fn(context.Background(), model.SecureSettings, "bottoken", model.Settings.Get("bottoken").MustString(), cfg.SecretKey) chatID := model.Settings.Get("chatid").MustString() uploadImage := model.Settings.Get("uploadImage").MustBool() diff --git a/pkg/services/alerting/notifiers/telegram_test.go b/pkg/services/alerting/notifiers/telegram_test.go index f9c1650edb4..e82061080d6 100644 --- a/pkg/services/alerting/notifiers/telegram_test.go +++ b/pkg/services/alerting/notifiers/telegram_test.go @@ -12,6 +12,7 @@ import ( "github.com/grafana/grafana/pkg/services/annotations/annotationstest" encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/grafana/grafana/pkg/services/validations" + "github.com/grafana/grafana/pkg/setting" ) func TestTelegramNotifier(t *testing.T) { @@ -28,7 +29,7 @@ func TestTelegramNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := NewTelegramNotifier(model, encryptionService.GetDecryptedValue, nil) + _, err := NewTelegramNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -46,7 +47,7 @@ func TestTelegramNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewTelegramNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewTelegramNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) telegramNotifier := not.(*TelegramNotifier) require.Nil(t, err) diff --git a/pkg/services/alerting/notifiers/threema.go b/pkg/services/alerting/notifiers/threema.go index 6fc3589e099..142b4290b66 100644 --- a/pkg/services/alerting/notifiers/threema.go +++ b/pkg/services/alerting/notifiers/threema.go @@ -71,14 +71,14 @@ type ThreemaNotifier struct { } // NewThreemaNotifier is the constructor for the Threema notifier -func NewThreemaNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { +func NewThreemaNotifier(cfg *setting.Cfg, model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { if model.Settings == nil { return nil, alerting.ValidationError{Reason: "No Settings Supplied"} } gatewayID := model.Settings.Get("gateway_id").MustString() recipientID := model.Settings.Get("recipient_id").MustString() - apiSecret := fn(context.Background(), model.SecureSettings, "api_secret", model.Settings.Get("api_secret").MustString(), setting.SecretKey) + apiSecret := fn(context.Background(), model.SecureSettings, "api_secret", model.Settings.Get("api_secret").MustString(), cfg.SecretKey) // Validation if gatewayID == "" { diff --git a/pkg/services/alerting/notifiers/threema_test.go b/pkg/services/alerting/notifiers/threema_test.go index 42b1aea6c8f..a7dd7bd6023 100644 --- a/pkg/services/alerting/notifiers/threema_test.go +++ b/pkg/services/alerting/notifiers/threema_test.go @@ -10,6 +10,7 @@ import ( "github.com/grafana/grafana/pkg/services/alerting" "github.com/grafana/grafana/pkg/services/alerting/models" encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" + "github.com/grafana/grafana/pkg/setting" ) func TestThreemaNotifier(t *testing.T) { @@ -26,7 +27,7 @@ func TestThreemaNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := NewThreemaNotifier(model, encryptionService.GetDecryptedValue, nil) + _, err := NewThreemaNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -45,7 +46,7 @@ func TestThreemaNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewThreemaNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewThreemaNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) require.Nil(t, err) threemaNotifier := not.(*ThreemaNotifier) @@ -72,7 +73,7 @@ func TestThreemaNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewThreemaNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewThreemaNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) require.Nil(t, not) var valErr alerting.ValidationError require.True(t, errors.As(err, &valErr)) @@ -94,7 +95,7 @@ func TestThreemaNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewThreemaNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewThreemaNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) require.Nil(t, not) var valErr alerting.ValidationError require.True(t, errors.As(err, &valErr)) @@ -116,7 +117,7 @@ func TestThreemaNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewThreemaNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewThreemaNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) require.Nil(t, not) var valErr alerting.ValidationError require.True(t, errors.As(err, &valErr)) diff --git a/pkg/services/alerting/notifiers/victorops.go b/pkg/services/alerting/notifiers/victorops.go index 4da542562d7..3f8b6edb48f 100644 --- a/pkg/services/alerting/notifiers/victorops.go +++ b/pkg/services/alerting/notifiers/victorops.go @@ -47,7 +47,7 @@ func init() { // NewVictoropsNotifier creates an instance of VictoropsNotifier that // handles posting notifications to Victorops REST API -func NewVictoropsNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { +func NewVictoropsNotifier(_ *setting.Cfg, model *models.AlertNotification, _ alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { autoResolve := model.Settings.Get("autoResolve").MustBool(true) url := model.Settings.Get("url").MustString() if url == "" { diff --git a/pkg/services/alerting/notifiers/victorops_test.go b/pkg/services/alerting/notifiers/victorops_test.go index 39134ab2c0c..010448875f9 100644 --- a/pkg/services/alerting/notifiers/victorops_test.go +++ b/pkg/services/alerting/notifiers/victorops_test.go @@ -39,7 +39,7 @@ func TestVictoropsNotifier(t *testing.T) { Settings: settingsJSON, } - _, err := NewVictoropsNotifier(model, encryptionService.GetDecryptedValue, nil) + _, err := NewVictoropsNotifier(nil, model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -56,7 +56,7 @@ func TestVictoropsNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewVictoropsNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewVictoropsNotifier(nil, model, encryptionService.GetDecryptedValue, nil) victoropsNotifier := not.(*VictoropsNotifier) require.Nil(t, err) @@ -80,7 +80,7 @@ func TestVictoropsNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewVictoropsNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewVictoropsNotifier(nil, model, encryptionService.GetDecryptedValue, nil) require.Nil(t, err) victoropsNotifier := not.(*VictoropsNotifier) @@ -128,7 +128,7 @@ func TestVictoropsNotifier(t *testing.T) { Settings: settingsJSON, } - not, err := NewVictoropsNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewVictoropsNotifier(nil, model, encryptionService.GetDecryptedValue, nil) require.Nil(t, err) victoropsNotifier := not.(*VictoropsNotifier) diff --git a/pkg/services/alerting/notifiers/webhook.go b/pkg/services/alerting/notifiers/webhook.go index 4342ee46b2a..ad21b5c4afc 100644 --- a/pkg/services/alerting/notifiers/webhook.go +++ b/pkg/services/alerting/notifiers/webhook.go @@ -60,13 +60,13 @@ func init() { // NewWebHookNotifier is the constructor for // the WebHook notifier. -func NewWebHookNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { +func NewWebHookNotifier(cfg *setting.Cfg, model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) { url := model.Settings.Get("url").MustString() if url == "" { return nil, alerting.ValidationError{Reason: "Could not find url property in settings"} } - password := fn(context.Background(), model.SecureSettings, "password", model.Settings.Get("password").MustString(), setting.SecretKey) + password := fn(context.Background(), model.SecureSettings, "password", model.Settings.Get("password").MustString(), cfg.SecretKey) return &WebhookNotifier{ NotifierBase: NewNotifierBase(model, ns), diff --git a/pkg/services/alerting/notifiers/webhook_test.go b/pkg/services/alerting/notifiers/webhook_test.go index 05c489f61ec..f2a9c5777d3 100644 --- a/pkg/services/alerting/notifiers/webhook_test.go +++ b/pkg/services/alerting/notifiers/webhook_test.go @@ -9,6 +9,7 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/services/alerting/models" encryptionservice "github.com/grafana/grafana/pkg/services/encryption/service" + "github.com/grafana/grafana/pkg/setting" ) func TestWebhookNotifier_parsingFromSettings(t *testing.T) { @@ -25,7 +26,7 @@ func TestWebhookNotifier_parsingFromSettings(t *testing.T) { Settings: settingsJSON, } - _, err = NewWebHookNotifier(model, encryptionService.GetDecryptedValue, nil) + _, err = NewWebHookNotifier(nil, model, encryptionService.GetDecryptedValue, nil) require.Error(t, err) }) @@ -40,7 +41,7 @@ func TestWebhookNotifier_parsingFromSettings(t *testing.T) { Settings: settingsJSON, } - not, err := NewWebHookNotifier(model, encryptionService.GetDecryptedValue, nil) + not, err := NewWebHookNotifier(setting.NewCfg(), model, encryptionService.GetDecryptedValue, nil) require.NoError(t, err) webhookNotifier := not.(*WebhookNotifier) diff --git a/pkg/services/alerting/result_handler.go b/pkg/services/alerting/result_handler.go index c6c3d2c507f..625874f5d61 100644 --- a/pkg/services/alerting/result_handler.go +++ b/pkg/services/alerting/result_handler.go @@ -12,6 +12,7 @@ import ( "github.com/grafana/grafana/pkg/services/annotations" "github.com/grafana/grafana/pkg/services/notifications" "github.com/grafana/grafana/pkg/services/rendering" + "github.com/grafana/grafana/pkg/setting" ) type resultHandler interface { @@ -24,11 +25,11 @@ type defaultResultHandler struct { log log.Logger } -func newResultHandler(renderService rendering.Service, sqlStore AlertStore, notificationService *notifications.NotificationService, decryptFn GetDecryptedValueFn) *defaultResultHandler { +func newResultHandler(cfg *setting.Cfg, renderService rendering.Service, sqlStore AlertStore, notificationService *notifications.NotificationService, decryptFn GetDecryptedValueFn) *defaultResultHandler { return &defaultResultHandler{ log: log.New("alerting.resultHandler"), sqlStore: sqlStore, - notifier: newNotificationService(renderService, sqlStore, notificationService, decryptFn), + notifier: newNotificationService(cfg, renderService, sqlStore, notificationService, decryptFn), } } diff --git a/pkg/services/alerting/scheduler.go b/pkg/services/alerting/scheduler.go index 4e9286c04bd..18a824ec5c2 100644 --- a/pkg/services/alerting/scheduler.go +++ b/pkg/services/alerting/scheduler.go @@ -10,12 +10,14 @@ import ( ) type schedulerImpl struct { + cfg *setting.Cfg jobs map[int64]*Job log log.Logger } -func newScheduler() scheduler { +func newScheduler(cfg *setting.Cfg) scheduler { return &schedulerImpl{ + cfg: cfg, jobs: make(map[int64]*Job), log: log.New("alerting.scheduler"), } @@ -64,8 +66,8 @@ func (s *schedulerImpl) Tick(tickTime time.Time, execQueue chan *Job) { // Check the job frequency against the minimum interval required interval := job.Rule.Frequency - if interval < setting.AlertingMinInterval { - interval = setting.AlertingMinInterval + if interval < s.cfg.AlertingMinInterval { + interval = s.cfg.AlertingMinInterval } if now%interval == 0 { diff --git a/pkg/services/alerting/service.go b/pkg/services/alerting/service.go index df8730820e1..ae23cdfcbfa 100644 --- a/pkg/services/alerting/service.go +++ b/pkg/services/alerting/service.go @@ -13,14 +13,16 @@ import ( ) type AlertNotificationService struct { + cfg *setting.Cfg SQLStore AlertNotificationStore EncryptionService encryption.Internal NotificationService *notifications.NotificationService } -func ProvideService(store db.DB, encryptionService encryption.Internal, +func ProvideService(cfg *setting.Cfg, store db.DB, encryptionService encryption.Internal, notificationService *notifications.NotificationService) *AlertNotificationService { s := &AlertNotificationService{ + cfg: cfg, SQLStore: &sqlStore{db: store}, EncryptionService: encryptionService, NotificationService: notificationService, @@ -38,7 +40,7 @@ func (s *AlertNotificationService) CreateAlertNotificationCommand(ctx context.Co return nil, ValidationError{Reason: "Invalid UID: Must be 40 characters or less"} } - cmd.EncryptedSecureSettings, err = s.EncryptionService.EncryptJsonData(ctx, cmd.SecureSettings, setting.SecretKey) + cmd.EncryptedSecureSettings, err = s.EncryptionService.EncryptJsonData(ctx, cmd.SecureSettings, s.cfg.SecretKey) if err != nil { return nil, err } @@ -61,7 +63,7 @@ func (s *AlertNotificationService) UpdateAlertNotification(ctx context.Context, return nil, ValidationError{Reason: "Invalid UID: Must be 40 characters or less"} } - cmd.EncryptedSecureSettings, err = s.EncryptionService.EncryptJsonData(ctx, cmd.SecureSettings, setting.SecretKey) + cmd.EncryptedSecureSettings, err = s.EncryptionService.EncryptJsonData(ctx, cmd.SecureSettings, s.cfg.SecretKey) if err != nil { return nil, err } @@ -140,7 +142,7 @@ func (s *AlertNotificationService) createNotifier(ctx context.Context, model *mo if res.SecureSettings != nil { var err error - secureSettingsMap, err = s.EncryptionService.DecryptJsonData(ctx, res.SecureSettings, setting.SecretKey) + secureSettingsMap, err = s.EncryptionService.DecryptJsonData(ctx, res.SecureSettings, s.cfg.SecretKey) if err != nil { return nil, err } @@ -152,12 +154,12 @@ func (s *AlertNotificationService) createNotifier(ctx context.Context, model *mo } var err error - model.SecureSettings, err = s.EncryptionService.EncryptJsonData(ctx, secureSettingsMap, setting.SecretKey) + model.SecureSettings, err = s.EncryptionService.EncryptJsonData(ctx, secureSettingsMap, s.cfg.SecretKey) if err != nil { return nil, err } - notifier, err := InitNotifier(model, s.EncryptionService.GetDecryptedValue, s.NotificationService) + notifier, err := InitNotifier(s.cfg, model, s.EncryptionService.GetDecryptedValue, s.NotificationService) if err != nil { logger.Error("Failed to create notifier", "error", err.Error()) return nil, err diff --git a/pkg/services/alerting/service_test.go b/pkg/services/alerting/service_test.go index 0cea01be6d3..d3470094baf 100644 --- a/pkg/services/alerting/service_test.go +++ b/pkg/services/alerting/service_test.go @@ -33,16 +33,17 @@ func TestService(t *testing.T) { usMock := &usagestats.UsageStatsMock{T: t} encProvider := encryptionprovider.ProvideEncryptionProvider() - encService, err := encryptionservice.ProvideEncryptionService(encProvider, usMock, setting.NewCfg()) + cfg := setting.NewCfg() + encService, err := encryptionservice.ProvideEncryptionService(encProvider, usMock, cfg) require.NoError(t, err) - s := ProvideService(sqlStore.db, encService, nil) + s := ProvideService(cfg, sqlStore.db, encService, nil) - origSecret := setting.SecretKey - setting.SecretKey = "alert_notification_service_test" + origSecret := cfg.SecretKey + cfg.SecretKey = "alert_notification_service_test" t.Cleanup(func() { - setting.SecretKey = origSecret + cfg.SecretKey = origSecret }) t.Run("create alert notification should reject an invalid command", func(t *testing.T) { @@ -64,7 +65,7 @@ func TestService(t *testing.T) { an, err := s.CreateAlertNotificationCommand(ctx, &cmd) require.NoError(t, err) - decrypted, err := s.EncryptionService.DecryptJsonData(ctx, an.SecureSettings, setting.SecretKey) + decrypted, err := s.EncryptionService.DecryptJsonData(ctx, an.SecureSettings, cfg.SecretKey) require.NoError(t, err) require.Equal(t, ss, decrypted) @@ -116,7 +117,7 @@ func TestService(t *testing.T) { n2, err := s.UpdateAlertNotification(ctx, &updateCmd) require.NoError(t, err) - decrypted, err := s.EncryptionService.DecryptJsonData(ctx, n2.SecureSettings, setting.SecretKey) + decrypted, err := s.EncryptionService.DecryptJsonData(ctx, n2.SecureSettings, cfg.SecretKey) require.NoError(t, err) require.Equal(t, ss, decrypted) @@ -153,7 +154,7 @@ func TestService(t *testing.T) { func registerTestNotifier(notifierType string) { RegisterNotifier(&NotifierPlugin{ Type: notifierType, - Factory: func(*models.AlertNotification, GetDecryptedValueFn, notifications.Service) (Notifier, error) { + Factory: func(*setting.Cfg, *models.AlertNotification, GetDecryptedValueFn, notifications.Service) (Notifier, error) { return nil, nil }, }) diff --git a/pkg/services/alerting/test_notification.go b/pkg/services/alerting/test_notification.go index e844b2d1a57..bda7c9ccc90 100644 --- a/pkg/services/alerting/test_notification.go +++ b/pkg/services/alerting/test_notification.go @@ -30,7 +30,7 @@ var ( ) func (s *AlertNotificationService) HandleNotificationTestCommand(ctx context.Context, cmd *NotificationTestCommand) error { - notificationSvc := newNotificationService(nil, nil, nil, nil) + notificationSvc := newNotificationService(nil, nil, nil, nil, nil) model := models.AlertNotification{ ID: cmd.ID, diff --git a/pkg/services/anonymous/anonimpl/api/api.go b/pkg/services/anonymous/anonimpl/api/api.go index d545f252deb..95774e1682b 100644 --- a/pkg/services/anonymous/anonimpl/api/api.go +++ b/pkg/services/anonymous/anonimpl/api/api.go @@ -84,7 +84,7 @@ func (api *AnonDeviceServiceAPI) ListDevices(c *contextmodel.ReqContext) respons resDevices = append(resDevices, &deviceDTO{ Device: *device, LastSeenAt: util.GetAgeString(device.UpdatedAt), - AvatarUrl: dtos.GetGravatarUrl(device.DeviceID), + AvatarUrl: dtos.GetGravatarUrl(api.cfg, device.DeviceID), }) } diff --git a/pkg/services/anonymous/anonimpl/impl.go b/pkg/services/anonymous/anonimpl/impl.go index 8a7e0ac6586..e1cc21415f7 100644 --- a/pkg/services/anonymous/anonimpl/impl.go +++ b/pkg/services/anonymous/anonimpl/impl.go @@ -88,7 +88,7 @@ func (a *AnonDeviceService) tagDeviceUI(ctx context.Context, httpReq *http.Reque a.localCache.SetDefault(key, struct{}{}) - if setting.Env == setting.Dev { + if a.cfg.Env == setting.Dev { a.log.Debug("Tagging device for UI", "deviceID", device.DeviceID, "device", device, "key", key) } diff --git a/pkg/services/auth/authimpl/auth_token.go b/pkg/services/auth/authimpl/auth_token.go index c4879c7f3ef..2b28327e6d5 100644 --- a/pkg/services/auth/authimpl/auth_token.go +++ b/pkg/services/auth/authimpl/auth_token.go @@ -66,7 +66,7 @@ type UserAuthTokenService struct { } func (s *UserAuthTokenService) CreateToken(ctx context.Context, user *user.User, clientIP net.IP, userAgent string) (*auth.UserToken, error) { - token, hashedToken, err := generateAndHashToken() + token, hashedToken, err := generateAndHashToken(s.cfg.SecretKey) if err != nil { return nil, err } @@ -112,7 +112,7 @@ func (s *UserAuthTokenService) CreateToken(ctx context.Context, user *user.User, } func (s *UserAuthTokenService) LookupToken(ctx context.Context, unhashedToken string) (*auth.UserToken, error) { - hashedToken := hashToken(unhashedToken) + hashedToken := hashToken(s.cfg.SecretKey, unhashedToken) var model userAuthToken var exists bool var err error @@ -249,7 +249,7 @@ func (s *UserAuthTokenService) rotateToken(ctx context.Context, token *auth.User clientIPStr = clientIP.String() } - newToken, hashedToken, err := generateAndHashToken() + newToken, hashedToken, err := generateAndHashToken(s.cfg.SecretKey) if err != nil { return nil, err } @@ -338,7 +338,7 @@ func (s *UserAuthTokenService) TryRotateToken(ctx context.Context, token *auth.U if err != nil { return nil, err } - hashedToken := hashToken(newToken) + hashedToken := hashToken(s.cfg.SecretKey, newToken) // very important that auth_token_seen is set after the prev_auth_token = case when ... for mysql to function correctly sql := ` @@ -627,18 +627,18 @@ func createToken() (string, error) { return token, nil } -func hashToken(token string) string { - hashBytes := sha256.Sum256([]byte(token + setting.SecretKey)) +func hashToken(secretKey string, token string) string { + hashBytes := sha256.Sum256([]byte(token + secretKey)) return hex.EncodeToString(hashBytes[:]) } -func generateAndHashToken() (string, string, error) { +func generateAndHashToken(secretKey string) (string, string, error) { token, err := createToken() if err != nil { return "", "", err } - return token, hashToken(token), nil + return token, hashToken(secretKey, token), nil } func readQuotaConfig(cfg *setting.Cfg) (*quota.Map, error) { diff --git a/pkg/services/auth/authimpl/auth_token_test.go b/pkg/services/auth/authimpl/auth_token_test.go index 6c3db6c8bc4..5b947fb915b 100644 --- a/pkg/services/auth/authimpl/auth_token_test.go +++ b/pkg/services/auth/authimpl/auth_token_test.go @@ -479,14 +479,14 @@ func TestIntegrationUserAuthToken(t *testing.T) { token, err = ctx.tokenService.RotateToken(context.Background(), auth.RotateCommand{UnHashedToken: token.UnhashedToken}) require.NoError(t, err) assert.True(t, token.UnhashedToken != prev) - assert.True(t, token.PrevAuthToken == hashToken(prev)) + assert.True(t, token.PrevAuthToken == hashToken("", prev)) }) t.Run("should rotate token when called with previous", func(t *testing.T) { newPrev := token.UnhashedToken token, err = ctx.tokenService.RotateToken(context.Background(), auth.RotateCommand{UnHashedToken: prev}) require.NoError(t, err) - assert.True(t, token.PrevAuthToken == hashToken(newPrev)) + assert.True(t, token.PrevAuthToken == hashToken("", newPrev)) }) t.Run("should not rotate token when called with old previous", func(t *testing.T) { diff --git a/pkg/services/auth/jwt/auth_test.go b/pkg/services/auth/jwt/auth_test.go index 3cc93a5f912..f8ffc542ccd 100644 --- a/pkg/services/auth/jwt/auth_test.go +++ b/pkg/services/auth/jwt/auth_test.go @@ -127,12 +127,8 @@ func TestVerifyUsingJWKSetURL(t *testing.T) { }) require.NoError(t, err) - oldEnv := setting.Env - setting.Env = setting.Prod - defer func() { - setting.Env = oldEnv - }() _, err = initAuthService(t, func(t *testing.T, cfg *setting.Cfg) { + cfg.Env = setting.Prod cfg.JWTAuthJWKSetURL = "http://example.com/.well-known/jwks.json" }) require.Error(t, err) diff --git a/pkg/services/auth/jwt/key_sets.go b/pkg/services/auth/jwt/key_sets.go index cd6fac5c30b..f981b21a591 100644 --- a/pkg/services/auth/jwt/key_sets.go +++ b/pkg/services/auth/jwt/key_sets.go @@ -152,7 +152,7 @@ func (s *AuthService) initKeySet() error { if err != nil { return err } - if urlParsed.Scheme != "https" && setting.Env != setting.Dev { + if urlParsed.Scheme != "https" && s.Cfg.Env != setting.Dev { return ErrJWTSetURLMustHaveHTTPSScheme } s.keySet = &keySetHTTP{ diff --git a/pkg/services/dashboards/service/dashboard_service.go b/pkg/services/dashboards/service/dashboard_service.go index 89c9fd2d8a9..62d1f4040f0 100644 --- a/pkg/services/dashboards/service/dashboard_service.go +++ b/pkg/services/dashboards/service/dashboard_service.go @@ -129,7 +129,7 @@ func (dr *DashboardServiceImpl) BuildSaveDashboardCommand(ctx context.Context, d return nil, dashboards.ErrDashboardUidTooLong } - if err := validateDashboardRefreshInterval(dash); err != nil { + if err := validateDashboardRefreshInterval(dr.cfg.MinRefreshInterval, dash); err != nil { return nil, err } @@ -274,8 +274,8 @@ func getGuardianForSavePermissionCheck(ctx context.Context, d *dashboards.Dashbo return guard, nil } -func validateDashboardRefreshInterval(dash *dashboards.Dashboard) error { - if setting.MinRefreshInterval == "" { +func validateDashboardRefreshInterval(minRefreshInterval string, dash *dashboards.Dashboard) error { + if minRefreshInterval == "" { return nil } @@ -285,16 +285,16 @@ func validateDashboardRefreshInterval(dash *dashboards.Dashboard) error { return nil } - minRefreshInterval, err := gtime.ParseDuration(setting.MinRefreshInterval) + minRefreshIntervalDur, err := gtime.ParseDuration(minRefreshInterval) if err != nil { - return fmt.Errorf("parsing min refresh interval %q failed: %w", setting.MinRefreshInterval, err) + return fmt.Errorf("parsing min refresh interval %q failed: %w", minRefreshInterval, err) } d, err := gtime.ParseDuration(refresh) if err != nil { return fmt.Errorf("parsing refresh duration %q failed: %w", refresh, err) } - if d < minRefreshInterval { + if d < minRefreshIntervalDur { return dashboards.ErrDashboardRefreshIntervalTooShort } @@ -303,15 +303,15 @@ func validateDashboardRefreshInterval(dash *dashboards.Dashboard) error { func (dr *DashboardServiceImpl) SaveProvisionedDashboard(ctx context.Context, dto *dashboards.SaveDashboardDTO, provisioning *dashboards.DashboardProvisioning) (*dashboards.Dashboard, error) { - if err := validateDashboardRefreshInterval(dto.Dashboard); err != nil { + if err := validateDashboardRefreshInterval(dr.cfg.MinRefreshInterval, dto.Dashboard); err != nil { dr.log.Warn("Changing refresh interval for provisioned dashboard to minimum refresh interval", "dashboardUid", - dto.Dashboard.UID, "dashboardTitle", dto.Dashboard.Title, "minRefreshInterval", setting.MinRefreshInterval) - dto.Dashboard.Data.Set("refresh", setting.MinRefreshInterval) + dto.Dashboard.UID, "dashboardTitle", dto.Dashboard.Title, "minRefreshInterval", dr.cfg.MinRefreshInterval) + dto.Dashboard.Data.Set("refresh", dr.cfg.MinRefreshInterval) } dto.User = accesscontrol.BackgroundUser("dashboard_provisioning", dto.OrgID, org.RoleAdmin, provisionerPermissions) - cmd, err := dr.BuildSaveDashboardCommand(ctx, dto, setting.IsLegacyAlertingEnabled(), false) + cmd, err := dr.BuildSaveDashboardCommand(ctx, dto, dr.cfg.IsLegacyAlertingEnabled(), false) if err != nil { return nil, err } @@ -330,7 +330,7 @@ func (dr *DashboardServiceImpl) SaveProvisionedDashboard(ctx context.Context, dt } // extract/save legacy alerts only if legacy alerting is enabled - if setting.IsLegacyAlertingEnabled() { + if dr.cfg.IsLegacyAlertingEnabled() { alerts, err := dr.dashAlertExtractor.GetAlerts(ctx, dashAlertInfo) if err != nil { return nil, err @@ -364,14 +364,14 @@ func (dr *DashboardServiceImpl) SaveFolderForProvisionedDashboards(ctx context.C func (dr *DashboardServiceImpl) SaveDashboard(ctx context.Context, dto *dashboards.SaveDashboardDTO, allowUiUpdate bool) (*dashboards.Dashboard, error) { - if err := validateDashboardRefreshInterval(dto.Dashboard); err != nil { + if err := validateDashboardRefreshInterval(dr.cfg.MinRefreshInterval, dto.Dashboard); err != nil { dr.log.Warn("Changing refresh interval for imported dashboard to minimum refresh interval", "dashboardUid", dto.Dashboard.UID, "dashboardTitle", dto.Dashboard.Title, "minRefreshInterval", - setting.MinRefreshInterval) - dto.Dashboard.Data.Set("refresh", setting.MinRefreshInterval) + dr.cfg.MinRefreshInterval) + dto.Dashboard.Data.Set("refresh", dr.cfg.MinRefreshInterval) } - cmd, err := dr.BuildSaveDashboardCommand(ctx, dto, setting.IsLegacyAlertingEnabled(), !allowUiUpdate) + cmd, err := dr.BuildSaveDashboardCommand(ctx, dto, dr.cfg.IsLegacyAlertingEnabled(), !allowUiUpdate) if err != nil { return nil, err } @@ -388,7 +388,7 @@ func (dr *DashboardServiceImpl) SaveDashboard(ctx context.Context, dto *dashboar } // extract/save legacy alerts only if legacy alerting is enabled - if setting.IsLegacyAlertingEnabled() { + if dr.cfg.IsLegacyAlertingEnabled() { alerts, err := dr.dashAlertExtractor.GetAlerts(ctx, dashAlertInfo) if err != nil { return nil, err @@ -440,11 +440,11 @@ func (dr *DashboardServiceImpl) deleteDashboard(ctx context.Context, dashboardId func (dr *DashboardServiceImpl) ImportDashboard(ctx context.Context, dto *dashboards.SaveDashboardDTO) ( *dashboards.Dashboard, error) { - if err := validateDashboardRefreshInterval(dto.Dashboard); err != nil { + if err := validateDashboardRefreshInterval(dr.cfg.MinRefreshInterval, dto.Dashboard); err != nil { dr.log.Warn("Changing refresh interval for imported dashboard to minimum refresh interval", "dashboardUid", dto.Dashboard.UID, "dashboardTitle", dto.Dashboard.Title, - "minRefreshInterval", setting.MinRefreshInterval) - dto.Dashboard.Data.Set("refresh", setting.MinRefreshInterval) + "minRefreshInterval", dr.cfg.MinRefreshInterval) + dto.Dashboard.Data.Set("refresh", dr.cfg.MinRefreshInterval) } cmd, err := dr.BuildSaveDashboardCommand(ctx, dto, false, true) diff --git a/pkg/services/dashboards/service/dashboard_service_test.go b/pkg/services/dashboards/service/dashboard_service_test.go index b4316dd9fcb..eeb3a62a4ff 100644 --- a/pkg/services/dashboards/service/dashboard_service_test.go +++ b/pkg/services/dashboards/service/dashboard_service_test.go @@ -118,17 +118,17 @@ func TestDashboardService(t *testing.T) { }) t.Run("Should return validation error if alert data is invalid", func(t *testing.T) { - origAlertingEnabledSet := setting.AlertingEnabled != nil + origAlertingEnabledSet := service.cfg.AlertingEnabled != nil origAlertingEnabledVal := false if origAlertingEnabledSet { - origAlertingEnabledVal = *setting.AlertingEnabled + origAlertingEnabledVal = *(service.cfg.AlertingEnabled) } - setting.AlertingEnabled = util.Pointer(true) + service.cfg.AlertingEnabled = util.Pointer(true) t.Cleanup(func() { if !origAlertingEnabledSet { - setting.AlertingEnabled = nil + service.cfg.AlertingEnabled = nil } else { - setting.AlertingEnabled = &origAlertingEnabledVal + service.cfg.AlertingEnabled = &origAlertingEnabledVal } }) @@ -163,9 +163,9 @@ func TestDashboardService(t *testing.T) { fakeStore.On("ValidateDashboardBeforeSave", mock.Anything, mock.Anything, mock.AnythingOfType("bool")).Return(true, nil).Once() fakeStore.On("SaveProvisionedDashboard", mock.Anything, mock.AnythingOfType("dashboards.SaveDashboardCommand"), mock.AnythingOfType("*dashboards.DashboardProvisioning")).Return(&dashboards.Dashboard{Data: simplejson.New()}, nil).Once() - oldRefreshInterval := setting.MinRefreshInterval - setting.MinRefreshInterval = "5m" - defer func() { setting.MinRefreshInterval = oldRefreshInterval }() + oldRefreshInterval := service.cfg.MinRefreshInterval + service.cfg.MinRefreshInterval = "5m" + defer func() { service.cfg.MinRefreshInterval = oldRefreshInterval }() dto.Dashboard = dashboards.NewDashboard("Dash") dto.Dashboard.SetID(3) diff --git a/pkg/services/dashboardsnapshots/database/database_test.go b/pkg/services/dashboardsnapshots/database/database_test.go index 7646a02e4ef..6982d241776 100644 --- a/pkg/services/dashboardsnapshots/database/database_test.go +++ b/pkg/services/dashboardsnapshots/database/database_test.go @@ -23,12 +23,13 @@ func TestIntegrationDashboardSnapshotDBAccess(t *testing.T) { t.Skip("skipping integration test") } sqlstore := db.InitTestDB(t) - dashStore := ProvideStore(sqlstore, setting.NewCfg()) + cfg := setting.NewCfg() + dashStore := ProvideStore(sqlstore, cfg) - origSecret := setting.SecretKey - setting.SecretKey = "dashboard_snapshot_testing" + origSecret := cfg.SecretKey + cfg.SecretKey = "dashboard_snapshot_testing" t.Cleanup(func() { - setting.SecretKey = origSecret + cfg.SecretKey = origSecret }) secretsService := fakes.NewFakeSecretsService() dashboard := simplejson.NewFromAny(map[string]any{"hello": "mupp"}) diff --git a/pkg/services/dashboardsnapshots/service/service_test.go b/pkg/services/dashboardsnapshots/service/service_test.go index d18e77cea67..638a584d910 100644 --- a/pkg/services/dashboardsnapshots/service/service_test.go +++ b/pkg/services/dashboardsnapshots/service/service_test.go @@ -17,14 +17,15 @@ import ( func TestDashboardSnapshotsService(t *testing.T) { sqlStore := db.InitTestDB(t) - dsStore := dashsnapdb.ProvideStore(sqlStore, setting.NewCfg()) + cfg := setting.NewCfg() + dsStore := dashsnapdb.ProvideStore(sqlStore, cfg) secretsService := secretsManager.SetupTestService(t, database.ProvideSecretsStore(sqlStore)) s := ProvideService(dsStore, secretsService) - origSecret := setting.SecretKey - setting.SecretKey = "dashboard_snapshot_service_test" + origSecret := cfg.SecretKey + cfg.SecretKey = "dashboard_snapshot_service_test" t.Cleanup(func() { - setting.SecretKey = origSecret + cfg.SecretKey = origSecret }) dashboardKey := "12345" diff --git a/pkg/services/dashboardversion/dashverimpl/dashver.go b/pkg/services/dashboardversion/dashverimpl/dashver.go index f8b090560ba..04fed84c9bd 100644 --- a/pkg/services/dashboardversion/dashverimpl/dashver.go +++ b/pkg/services/dashboardversion/dashverimpl/dashver.go @@ -17,13 +17,15 @@ const ( ) type Service struct { + cfg *setting.Cfg store store dashSvc dashboards.DashboardService log log.Logger } -func ProvideService(db db.DB, dashboardService dashboards.DashboardService) dashver.Service { +func ProvideService(cfg *setting.Cfg, db db.DB, dashboardService dashboards.DashboardService) dashver.Service { return &Service{ + cfg: cfg, store: &sqlStore{ db: db, dialect: db.GetDialect(), @@ -63,7 +65,7 @@ func (s *Service) Get(ctx context.Context, query *dashver.GetDashboardVersionQue } func (s *Service) DeleteExpired(ctx context.Context, cmd *dashver.DeleteExpiredVersionsCommand) error { - versionsToKeep := setting.DashboardVersionsToKeep + versionsToKeep := s.cfg.DashboardVersionsToKeep if versionsToKeep < 1 { versionsToKeep = 1 } diff --git a/pkg/services/dashboardversion/dashverimpl/dashver_test.go b/pkg/services/dashboardversion/dashverimpl/dashver_test.go index 6f672f62714..7ec8fc4ef64 100644 --- a/pkg/services/dashboardversion/dashverimpl/dashver_test.go +++ b/pkg/services/dashboardversion/dashverimpl/dashver_test.go @@ -36,11 +36,13 @@ func TestDashboardVersionService(t *testing.T) { func TestDeleteExpiredVersions(t *testing.T) { versionsToKeep := 5 - setting.DashboardVersionsToKeep = versionsToKeep + cfg := setting.NewCfg() + cfg.DashboardVersionsToKeep = versionsToKeep dashboardVersionStore := newDashboardVersionStoreFake() dashboardService := dashboards.NewFakeDashboardService(t) - dashboardVersionService := Service{store: dashboardVersionStore, dashSvc: dashboardService} + dashboardVersionService := Service{ + cfg: cfg, store: dashboardVersionStore, dashSvc: dashboardService} t.Run("Don't delete anything if there are no expired versions", func(t *testing.T) { err := dashboardVersionService.DeleteExpired(context.Background(), &dashver.DeleteExpiredVersionsCommand{DeletedRows: 4}) diff --git a/pkg/services/datasources/service/datasource.go b/pkg/services/datasources/service/datasource.go index 9a0ec8c7932..a73e71b8870 100644 --- a/pkg/services/datasources/service/datasource.go +++ b/pkg/services/datasources/service/datasource.go @@ -554,7 +554,7 @@ func (s *Service) httpClientOptions(ctx context.Context, ds *datasources.DataSou opts.ProxyOptions = proxyOpts } - if ds.JsonData != nil && ds.JsonData.Get("sigV4Auth").MustBool(false) && setting.SigV4AuthEnabled { + if ds.JsonData != nil && ds.JsonData.Get("sigV4Auth").MustBool(false) && s.cfg.SigV4AuthEnabled { opts.SigV4 = &sdkhttpclient.SigV4Config{ Service: awsServiceNamespace(ds.Type, ds.JsonData), Region: ds.JsonData.Get("sigV4Region").MustString(), diff --git a/pkg/services/datasources/service/datasource_test.go b/pkg/services/datasources/service/datasource_test.go index f041ea09204..3672bb9e817 100644 --- a/pkg/services/datasources/service/datasource_test.go +++ b/pkg/services/datasources/service/datasource_test.go @@ -608,7 +608,7 @@ func TestService_GetHttpTransport(t *testing.T) { }, }) - setting.SecretKey = "password" + cfg.SecretKey = "password" sjson := simplejson.New() sjson.Set("tlsAuthWithCACert", true) @@ -659,7 +659,7 @@ func TestService_GetHttpTransport(t *testing.T) { }, }) - setting.SecretKey = "password" + cfg.SecretKey = "password" sjson := simplejson.New() sjson.Set("tlsAuth", true) @@ -706,7 +706,7 @@ func TestService_GetHttpTransport(t *testing.T) { }, }) - setting.SecretKey = "password" + cfg.SecretKey = "password" sjson := simplejson.New() sjson.Set("tlsAuthWithCACert", true) @@ -968,10 +968,10 @@ func TestService_GetHttpTransport(t *testing.T) { }, }) - origSigV4Enabled := setting.SigV4AuthEnabled - setting.SigV4AuthEnabled = true + origSigV4Enabled := cfg.SigV4AuthEnabled + cfg.SigV4AuthEnabled = true t.Cleanup(func() { - setting.SigV4AuthEnabled = origSigV4Enabled + cfg.SigV4AuthEnabled = origSigV4Enabled }) sjson, err := simplejson.NewJson([]byte(`{ "sigV4Auth": true }`)) diff --git a/pkg/services/featuremgmt/service.go b/pkg/services/featuremgmt/service.go index 28ab29be842..0c25dd77f00 100644 --- a/pkg/services/featuremgmt/service.go +++ b/pkg/services/featuremgmt/service.go @@ -20,7 +20,7 @@ var ( func ProvideManagerService(cfg *setting.Cfg, licensing licensing.Licensing) (*FeatureManager, error) { mgmt := &FeatureManager{ - isDevMod: setting.Env != setting.Prod, + isDevMod: cfg.Env != setting.Prod, licensing: licensing, flags: make(map[string]*FeatureFlag, 30), enabled: make(map[string]bool), diff --git a/pkg/services/libraryelements/database.go b/pkg/services/libraryelements/database.go index 3622bbd59a9..7259b1c38df 100644 --- a/pkg/services/libraryelements/database.go +++ b/pkg/services/libraryelements/database.go @@ -208,12 +208,12 @@ func (l *LibraryElementService) createLibraryElement(c context.Context, signedIn CreatedBy: librarypanel.LibraryElementDTOMetaUser{ Id: element.CreatedBy, Name: signedInUser.GetLogin(), - AvatarUrl: dtos.GetGravatarUrl(signedInUser.GetEmail()), + AvatarUrl: dtos.GetGravatarUrl(l.Cfg, signedInUser.GetEmail()), }, UpdatedBy: librarypanel.LibraryElementDTOMetaUser{ Id: element.UpdatedBy, Name: signedInUser.GetLogin(), - AvatarUrl: dtos.GetGravatarUrl(signedInUser.GetEmail()), + AvatarUrl: dtos.GetGravatarUrl(l.Cfg, signedInUser.GetEmail()), }, }, } @@ -335,12 +335,12 @@ func (l *LibraryElementService) getLibraryElements(c context.Context, store db.D CreatedBy: librarypanel.LibraryElementDTOMetaUser{ Id: libraryElement.CreatedBy, Name: libraryElement.CreatedByName, - AvatarUrl: dtos.GetGravatarUrl(libraryElement.CreatedByEmail), + AvatarUrl: dtos.GetGravatarUrl(l.Cfg, libraryElement.CreatedByEmail), }, UpdatedBy: librarypanel.LibraryElementDTOMetaUser{ Id: libraryElement.UpdatedBy, Name: libraryElement.UpdatedByName, - AvatarUrl: dtos.GetGravatarUrl(libraryElement.UpdatedByEmail), + AvatarUrl: dtos.GetGravatarUrl(l.Cfg, libraryElement.UpdatedByEmail), }, }, } @@ -457,12 +457,12 @@ func (l *LibraryElementService) getAllLibraryElements(c context.Context, signedI CreatedBy: librarypanel.LibraryElementDTOMetaUser{ Id: element.CreatedBy, Name: element.CreatedByName, - AvatarUrl: dtos.GetGravatarUrl(element.CreatedByEmail), + AvatarUrl: dtos.GetGravatarUrl(l.Cfg, element.CreatedByEmail), }, UpdatedBy: librarypanel.LibraryElementDTOMetaUser{ Id: element.UpdatedBy, Name: element.UpdatedByName, - AvatarUrl: dtos.GetGravatarUrl(element.UpdatedByEmail), + AvatarUrl: dtos.GetGravatarUrl(l.Cfg, element.UpdatedByEmail), }, }, }) @@ -630,12 +630,12 @@ func (l *LibraryElementService) patchLibraryElement(c context.Context, signedInU CreatedBy: librarypanel.LibraryElementDTOMetaUser{ Id: elementInDB.CreatedBy, Name: elementInDB.CreatedByName, - AvatarUrl: dtos.GetGravatarUrl(elementInDB.CreatedByEmail), + AvatarUrl: dtos.GetGravatarUrl(l.Cfg, elementInDB.CreatedByEmail), }, UpdatedBy: librarypanel.LibraryElementDTOMetaUser{ Id: libraryElement.UpdatedBy, Name: signedInUser.GetLogin(), - AvatarUrl: dtos.GetGravatarUrl(signedInUser.GetEmail()), + AvatarUrl: dtos.GetGravatarUrl(l.Cfg, signedInUser.GetEmail()), }, }, } @@ -683,7 +683,7 @@ func (l *LibraryElementService) getConnections(c context.Context, signedInUser i CreatedBy: librarypanel.LibraryElementDTOMetaUser{ Id: connection.CreatedBy, Name: connection.CreatedByName, - AvatarUrl: dtos.GetGravatarUrl(connection.CreatedByEmail), + AvatarUrl: dtos.GetGravatarUrl(l.Cfg, connection.CreatedByEmail), }, }) } @@ -732,12 +732,12 @@ func (l *LibraryElementService) getElementsForDashboardID(c context.Context, das CreatedBy: librarypanel.LibraryElementDTOMetaUser{ Id: element.CreatedBy, Name: element.CreatedByName, - AvatarUrl: dtos.GetGravatarUrl(element.CreatedByEmail), + AvatarUrl: dtos.GetGravatarUrl(l.Cfg, element.CreatedByEmail), }, UpdatedBy: librarypanel.LibraryElementDTOMetaUser{ Id: element.UpdatedBy, Name: element.UpdatedByName, - AvatarUrl: dtos.GetGravatarUrl(element.UpdatedByEmail), + AvatarUrl: dtos.GetGravatarUrl(l.Cfg, element.UpdatedByEmail), }, }, } diff --git a/pkg/services/navtree/navtreeimpl/navtree.go b/pkg/services/navtree/navtreeimpl/navtree.go index 56764dc4988..55636be1d0a 100644 --- a/pkg/services/navtree/navtreeimpl/navtree.go +++ b/pkg/services/navtree/navtreeimpl/navtree.go @@ -116,7 +116,7 @@ func (s *ServiceImpl) GetNavTree(c *contextmodel.ReqContext, prefs *pref.Prefere treeRoot.AddSection(dashboardLink) } - if setting.ExploreEnabled && hasAccess(ac.EvalPermission(ac.ActionDatasourcesExplore)) { + if s.cfg.ExploreEnabled && hasAccess(ac.EvalPermission(ac.ActionDatasourcesExplore)) { exploreChildNavLinks := s.buildExploreNavLinks(c) treeRoot.AddSection(&navtree.NavLink{ Text: "Explore", @@ -129,14 +129,14 @@ func (s *ServiceImpl) GetNavTree(c *contextmodel.ReqContext, prefs *pref.Prefere }) } - if setting.ProfileEnabled && c.IsSignedIn { + if s.cfg.ProfileEnabled && c.IsSignedIn { treeRoot.AddSection(s.getProfileNode(c)) } _, uaIsDisabledForOrg := s.cfg.UnifiedAlerting.DisabledOrgs[c.SignedInUser.GetOrgID()] uaVisibleForOrg := s.cfg.UnifiedAlerting.IsEnabled() && !uaIsDisabledForOrg - if setting.AlertingEnabled != nil && *setting.AlertingEnabled { + if s.cfg.AlertingEnabled != nil && *(s.cfg.AlertingEnabled) { if legacyAlertSection := s.buildLegacyAlertNavLinks(c); legacyAlertSection != nil { treeRoot.AddSection(legacyAlertSection) } @@ -208,7 +208,7 @@ func getShortCommitHash(commitHash string, maxLength int) string { } func (s *ServiceImpl) addHelpLinks(treeRoot *navtree.NavTreeRoot, c *contextmodel.ReqContext) { - if setting.HelpEnabled { + if s.cfg.HelpEnabled { helpVersion := fmt.Sprintf(`%s v%s (%s)`, setting.ApplicationName, setting.BuildVersion, getShortCommitHash(setting.BuildCommit, 10)) if s.cfg.AnonymousHideVersion && !c.IsSignedIn { helpVersion = setting.ApplicationName @@ -252,7 +252,7 @@ func (s *ServiceImpl) getProfileNode(c *contextmodel.ReqContext) *navtree.NavLin if c.SignedInUser.GetLogin() != c.SignedInUser.GetDisplayName() { login = c.SignedInUser.GetLogin() } - gravatarURL := dtos.GetGravatarUrl(c.SignedInUser.GetEmail()) + gravatarURL := dtos.GetGravatarUrl(s.cfg, c.SignedInUser.GetEmail()) children := []*navtree.NavLink{ { @@ -271,7 +271,7 @@ func (s *ServiceImpl) getProfileNode(c *contextmodel.ReqContext) *navtree.NavLin }) } - if !setting.DisableSignoutMenu { + if !s.cfg.DisableSignoutMenu { // add sign out first children = append(children, &navtree.NavLink{ Text: "Sign out", diff --git a/pkg/services/ngalert/image/service.go b/pkg/services/ngalert/image/service.go index edaedb13832..39d1e4f9f0b 100644 --- a/pkg/services/ngalert/image/service.go +++ b/pkg/services/ngalert/image/service.go @@ -93,12 +93,12 @@ func NewScreenshotImageServiceFromCfg(cfg *setting.Cfg, db *store.DBstore, ds da if cfg.UnifiedAlerting.Screenshots.Capture { cache = NewInmemCacheService(screenshotCacheTTL, r) limiter = screenshot.NewTokenRateLimiter(cfg.UnifiedAlerting.Screenshots.MaxConcurrentScreenshots) - screenshots = screenshot.NewHeadlessScreenshotService(ds, rs, r) + screenshots = screenshot.NewHeadlessScreenshotService(cfg, ds, rs, r) screenshotTimeout = cfg.UnifiedAlerting.Screenshots.CaptureTimeout // Image uploading is an optional feature if cfg.UnifiedAlerting.Screenshots.UploadExternalImageStorage { - m, err := imguploader.NewImageUploader() + m, err := imguploader.NewImageUploader(cfg) if err != nil { return nil, fmt.Errorf("failed to initialize uploading screenshot service: %w", err) } diff --git a/pkg/services/ngalert/migration/channel.go b/pkg/services/ngalert/migration/channel.go index 770711c2c68..ab51387774e 100644 --- a/pkg/services/ngalert/migration/channel.go +++ b/pkg/services/ngalert/migration/channel.go @@ -146,7 +146,7 @@ var secureKeysToMigrate = map[string][]string{ // migrateSettingsToSecureSettings takes care of that. func (om *OrgMigration) migrateSettingsToSecureSettings(chanType string, settings *simplejson.Json, secureSettings SecureJsonData) (*simplejson.Json, map[string]string, error) { keys := secureKeysToMigrate[chanType] - newSecureSettings := secureSettings.Decrypt() + newSecureSettings := secureSettings.Decrypt(om.cfg.SecretKey) cloneSettings := simplejson.New() settingsMap, err := settings.Map() if err != nil { diff --git a/pkg/services/ngalert/migration/channel_test.go b/pkg/services/ngalert/migration/channel_test.go index eac2672dc92..5e68beb9abe 100644 --- a/pkg/services/ngalert/migration/channel_test.go +++ b/pkg/services/ngalert/migration/channel_test.go @@ -174,8 +174,9 @@ func TestCreateReceivers(t *testing.T) { } func TestMigrateNotificationChannelSecureSettings(t *testing.T) { + cfg := setting.NewCfg() legacyEncryptFn := func(data string) string { - raw, err := util.Encrypt([]byte(data), setting.SecretKey) + raw, err := util.Encrypt([]byte(data), cfg.SecretKey) require.NoError(t, err) return string(raw) } diff --git a/pkg/services/ngalert/migration/securejsondata.go b/pkg/services/ngalert/migration/securejsondata.go index 9de357bb00a..810b695a7ce 100644 --- a/pkg/services/ngalert/migration/securejsondata.go +++ b/pkg/services/ngalert/migration/securejsondata.go @@ -4,7 +4,6 @@ import ( "os" "github.com/grafana/grafana/pkg/infra/log" - "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" ) @@ -16,10 +15,10 @@ var seclogger = log.New("securejsondata") // Decrypt returns map of the same type but where the all the values are decrypted. Opposite of what // GetEncryptedJsonData is doing. -func (s SecureJsonData) Decrypt() map[string]string { +func (s SecureJsonData) Decrypt(secretKey string) map[string]string { decrypted := make(map[string]string) for key, data := range s { - decryptedData, err := util.Decrypt(data, setting.SecretKey) + decryptedData, err := util.Decrypt(data, secretKey) if err != nil { seclogger.Error(err.Error()) os.Exit(1) diff --git a/pkg/services/ngalert/migration/store/testing.go b/pkg/services/ngalert/migration/store/testing.go index 40fa3a7ac2b..f9345b5e104 100644 --- a/pkg/services/ngalert/migration/store/testing.go +++ b/pkg/services/ngalert/migration/store/testing.go @@ -73,10 +73,10 @@ func NewTestMigrationStore(t testing.TB, sqlStore *sqlstore.SQLStore, cfg *setti require.NoError(t, err) folderPermissions, err := ossaccesscontrol.ProvideFolderPermissions( - features, routeRegister, sqlStore, ac, license, dashboardStore, folderService, acSvc, teamSvc, userSvc) + cfg, features, routeRegister, sqlStore, ac, license, dashboardStore, folderService, acSvc, teamSvc, userSvc) require.NoError(t, err) dashboardPermissions, err := ossaccesscontrol.ProvideDashboardPermissions( - features, routeRegister, sqlStore, ac, license, dashboardStore, folderService, acSvc, teamSvc, userSvc) + cfg, features, routeRegister, sqlStore, ac, license, dashboardStore, folderService, acSvc, teamSvc, userSvc) require.NoError(t, err) dashboardService, err := dashboardservice.ProvideDashboardServiceImpl( @@ -103,6 +103,6 @@ func NewTestMigrationStore(t testing.TB, sqlStore *sqlstore.SQLStore, cfg *setti folderPermissions: folderPermissions, dashboardPermissions: dashboardPermissions, orgService: orgService, - legacyAlertNotificationService: legacyalerting.ProvideService(sqlStore, encryptionservice.SetupTestService(t), nil), + legacyAlertNotificationService: legacyalerting.ProvideService(cfg, sqlStore, encryptionservice.SetupTestService(t), nil), } } diff --git a/pkg/services/notifications/codes.go b/pkg/services/notifications/codes.go index d345755191e..de3c7bfaa79 100644 --- a/pkg/services/notifications/codes.go +++ b/pkg/services/notifications/codes.go @@ -19,7 +19,7 @@ const timeLimitCodeLength = timeLimitStartDateLength + timeLimitMinutesLength + // create a time limit code // code format: 12 length date time string + 6 minutes string + 64 HMAC-SHA256 encoded string -func createTimeLimitCode(payload string, minutes int, startStr string) (string, error) { +func createTimeLimitCode(secretKey string, payload string, minutes int, startStr string) (string, error) { format := "200601021504" var start, end time.Time @@ -42,7 +42,7 @@ func createTimeLimitCode(payload string, minutes int, startStr string) (string, endStr = end.Format(format) // create HMAC-SHA256 encoded string - key := []byte(setting.SecretKey) + key := []byte(secretKey) h := hmac.New(sha256.New, key) if _, err := h.Write([]byte(payload + startStr + endStr)); err != nil { return "", fmt.Errorf("cannot create hmac: %v", err) @@ -71,7 +71,7 @@ func validateUserEmailCode(cfg *setting.Cfg, user *user.User, code string) (bool // right active code payload := strconv.FormatInt(user.ID, 10) + user.Email + user.Login + user.Password + user.Rands - expectedCode, err := createTimeLimitCode(payload, minutes, startStr) + expectedCode, err := createTimeLimitCode(cfg.SecretKey, payload, minutes, startStr) if err != nil { return false, err } @@ -104,7 +104,7 @@ func getLoginForEmailCode(code string) string { func createUserEmailCode(cfg *setting.Cfg, user *user.User, startStr string) (string, error) { minutes := cfg.EmailCodeValidMinutes payload := strconv.FormatInt(user.ID, 10) + user.Email + user.Login + user.Password + user.Rands - code, err := createTimeLimitCode(payload, minutes, startStr) + code, err := createTimeLimitCode(cfg.SecretKey, payload, minutes, startStr) if err != nil { return "", err } diff --git a/pkg/services/notifications/codes_test.go b/pkg/services/notifications/codes_test.go index fbcfce51e19..5ea255e0c64 100644 --- a/pkg/services/notifications/codes_test.go +++ b/pkg/services/notifications/codes_test.go @@ -76,7 +76,7 @@ func TestTimeLimitCodes(t *testing.T) { for _, test := range tests { t.Run(test.desc, func(t *testing.T) { - code, err := createTimeLimitCode(test.payload, test.minutes, test.start.Format(format)) + code, err := createTimeLimitCode(cfg.SecretKey, test.payload, test.minutes, test.start.Format(format)) require.NoError(t, err) isValid, err := validateUserEmailCode(cfg, user, code) @@ -86,7 +86,7 @@ func TestTimeLimitCodes(t *testing.T) { } t.Run("tampered minutes", func(t *testing.T) { - code, err := createTimeLimitCode(mailPayload, 5, tenMinutesAgo.Format(format)) + code, err := createTimeLimitCode(cfg.SecretKey, mailPayload, 5, tenMinutesAgo.Format(format)) require.NoError(t, err) // code is expired @@ -102,7 +102,7 @@ func TestTimeLimitCodes(t *testing.T) { }) t.Run("tampered start string", func(t *testing.T) { - code, err := createTimeLimitCode(mailPayload, 5, tenMinutesAgo.Format(format)) + code, err := createTimeLimitCode(cfg.SecretKey, mailPayload, 5, tenMinutesAgo.Format(format)) require.NoError(t, err) // code is expired diff --git a/pkg/services/notifications/email.go b/pkg/services/notifications/email.go index 2b2fa0fce64..e50646b9662 100644 --- a/pkg/services/notifications/email.go +++ b/pkg/services/notifications/email.go @@ -25,7 +25,7 @@ type Message struct { } func setDefaultTemplateData(cfg *setting.Cfg, data map[string]any, u *user.User) { - data["AppUrl"] = setting.AppUrl + data["AppUrl"] = cfg.AppURL data["BuildVersion"] = setting.BuildVersion data["BuildStamp"] = setting.BuildStamp data["EmailCodeValidHours"] = cfg.EmailCodeValidMinutes / 60 diff --git a/pkg/services/notifications/notifications.go b/pkg/services/notifications/notifications.go index d95e52a6a35..7773883b610 100644 --- a/pkg/services/notifications/notifications.go +++ b/pkg/services/notifications/notifications.go @@ -258,7 +258,7 @@ func (ns *NotificationService) ValidateResetPasswordCode(ctx context.Context, qu } func (ns *NotificationService) signUpStartedHandler(ctx context.Context, evt *events.SignUpStarted) error { - if !setting.VerifyEmailEnabled { + if !ns.Cfg.VerifyEmailEnabled { return nil } diff --git a/pkg/services/notifications/smtp.go b/pkg/services/notifications/smtp.go index df69d7d4ef4..2c46982b352 100644 --- a/pkg/services/notifications/smtp.go +++ b/pkg/services/notifications/smtp.go @@ -159,12 +159,8 @@ func (sc *SmtpClient) createDialer() (*gomail.Dialer, error) { d := gomail.NewDialer(host, iPort, sc.cfg.User, sc.cfg.Password) d.TLSConfig = tlsconfig d.StartTLSPolicy = getStartTLSPolicy(sc.cfg.StartTLSPolicy) + d.LocalName = sc.cfg.EhloIdentity - if sc.cfg.EhloIdentity != "" { - d.LocalName = sc.cfg.EhloIdentity - } else { - d.LocalName = setting.InstanceName - } return d, nil } diff --git a/pkg/services/provisioning/notifiers/alert_notifications.go b/pkg/services/provisioning/notifiers/alert_notifications.go index a7baedb8a4a..eff7e4621da 100644 --- a/pkg/services/provisioning/notifiers/alert_notifications.go +++ b/pkg/services/provisioning/notifiers/alert_notifications.go @@ -8,6 +8,7 @@ import ( "github.com/grafana/grafana/pkg/services/encryption" "github.com/grafana/grafana/pkg/services/notifications" "github.com/grafana/grafana/pkg/services/org" + "github.com/grafana/grafana/pkg/setting" ) type Manager interface { @@ -26,8 +27,8 @@ type Manager interface { } // Provision alert notifiers -func Provision(ctx context.Context, configDirectory string, alertingService Manager, orgService org.Service, encryptionService encryption.Internal, notificationService *notifications.NotificationService) error { - dc := newNotificationProvisioner(orgService, alertingService, encryptionService, notificationService, log.New("provisioning.notifiers")) +func Provision(ctx context.Context, cfg *setting.Cfg, configDirectory string, alertingService Manager, orgService org.Service, encryptionService encryption.Internal, notificationService *notifications.NotificationService) error { + dc := newNotificationProvisioner(cfg, orgService, alertingService, encryptionService, notificationService, log.New("provisioning.notifiers")) return dc.applyChanges(ctx, configDirectory) } @@ -39,11 +40,12 @@ type NotificationProvisioner struct { orgService org.Service } -func newNotificationProvisioner(orgService org.Service, alertingManager Manager, encryptionService encryption.Internal, notifiationService *notifications.NotificationService, log log.Logger) NotificationProvisioner { +func newNotificationProvisioner(cfg *setting.Cfg, orgService org.Service, alertingManager Manager, encryptionService encryption.Internal, notifiationService *notifications.NotificationService, log log.Logger) NotificationProvisioner { return NotificationProvisioner{ log: log, alertingManager: alertingManager, cfgProvider: &configReader{ + cfg: cfg, encryptionService: encryptionService, notificationService: notifiationService, log: log, diff --git a/pkg/services/provisioning/notifiers/config_reader.go b/pkg/services/provisioning/notifiers/config_reader.go index 7e87891a932..cf96ce7f33f 100644 --- a/pkg/services/provisioning/notifiers/config_reader.go +++ b/pkg/services/provisioning/notifiers/config_reader.go @@ -21,6 +21,7 @@ import ( ) type configReader struct { + cfg *setting.Cfg encryptionService encryption.Internal notificationService *notifications.NotificationService orgService org.Service @@ -168,14 +169,14 @@ func (cr *configReader) validateNotifications(notifications []*notificationsAsCo encryptedSecureSettings, err := cr.encryptionService.EncryptJsonData( context.Background(), notification.SecureSettings, - setting.SecretKey, + cr.cfg.SecretKey, ) if err != nil { return err } - _, err = alerting.InitNotifier(&models.AlertNotification{ + _, err = alerting.InitNotifier(cr.cfg, &models.AlertNotification{ Name: notification.Name, Settings: notification.SettingsToJSON(), SecureSettings: encryptedSecureSettings, diff --git a/pkg/services/provisioning/notifiers/config_reader_test.go b/pkg/services/provisioning/notifiers/config_reader_test.go index 8f0bd71bb67..979a1c9dd21 100644 --- a/pkg/services/provisioning/notifiers/config_reader_test.go +++ b/pkg/services/provisioning/notifiers/config_reader_test.go @@ -18,6 +18,7 @@ import ( "github.com/grafana/grafana/pkg/services/org/orgimpl" "github.com/grafana/grafana/pkg/services/quota/quotatest" "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/setting" ) var ( @@ -46,7 +47,7 @@ func TestNotificationAsConfig(t *testing.T) { sqlStore = db.InitTestDB(t) orgService, _ = orgimpl.ProvideService(sqlStore, sqlStore.Cfg, quotatest.New(false, nil)) nm := ¬ifications.NotificationService{} - ns = alerting.ProvideService(sqlStore, encryptionService, nm) + ns = alerting.ProvideService(sqlStore.Cfg, sqlStore, encryptionService, nm) for i := 1; i < 5; i++ { orgCommand := org.CreateOrgCommand{Name: fmt.Sprintf("Main Org. %v", i)} @@ -71,6 +72,7 @@ func TestNotificationAsConfig(t *testing.T) { setup() t.Setenv("TEST_VAR", "default") cfgProvider := &configReader{ + cfg: setting.NewCfg(), orgService: orgService, encryptionService: encryptionService, log: log.New("test logger"), @@ -150,7 +152,7 @@ func TestNotificationAsConfig(t *testing.T) { setup() fakeAlertNotification := &fakeAlertNotification{} fakeAlertNotification.ExpectedAlertNotification = &models.AlertNotification{OrgID: 1} - dc := newNotificationProvisioner(orgService, fakeAlertNotification, encryptionService, nil, logger) + dc := newNotificationProvisioner(setting.NewCfg(), orgService, fakeAlertNotification, encryptionService, nil, logger) err := dc.applyChanges(context.Background(), twoNotificationsConfig) if err != nil { @@ -176,7 +178,7 @@ func TestNotificationAsConfig(t *testing.T) { require.Equal(t, len(results), 1) t.Run("should update one notification", func(t *testing.T) { - dc := newNotificationProvisioner(orgService, &fakeAlertNotification{}, encryptionService, nil, logger) + dc := newNotificationProvisioner(setting.NewCfg(), orgService, &fakeAlertNotification{}, encryptionService, nil, logger) err = dc.applyChanges(context.Background(), twoNotificationsConfig) if err != nil { t.Fatalf("applyChanges return an error %v", err) @@ -186,7 +188,7 @@ func TestNotificationAsConfig(t *testing.T) { t.Run("Two notifications with is_default", func(t *testing.T) { setup() - dc := newNotificationProvisioner(orgService, &fakeAlertNotification{}, encryptionService, nil, logger) + dc := newNotificationProvisioner(setting.NewCfg(), orgService, &fakeAlertNotification{}, encryptionService, nil, logger) err := dc.applyChanges(context.Background(), doubleNotificationsConfig) t.Run("should both be inserted", func(t *testing.T) { require.NoError(t, err) @@ -221,7 +223,7 @@ func TestNotificationAsConfig(t *testing.T) { require.Equal(t, len(res), 2) t.Run("should have two new notifications", func(t *testing.T) { - dc := newNotificationProvisioner(orgService, &fakeAlertNotification{}, encryptionService, nil, logger) + dc := newNotificationProvisioner(setting.NewCfg(), orgService, &fakeAlertNotification{}, encryptionService, nil, logger) err := dc.applyChanges(context.Background(), twoNotificationsConfig) if err != nil { t.Fatalf("applyChanges return an error %v", err) @@ -242,7 +244,7 @@ func TestNotificationAsConfig(t *testing.T) { _, err := ns.SQLStore.CreateAlertNotificationCommand(context.Background(), &existingNotificationCmd) require.NoError(t, err) - dc := newNotificationProvisioner(orgService, &fakeAlertNotification{}, encryptionService, nil, logger) + dc := newNotificationProvisioner(setting.NewCfg(), orgService, &fakeAlertNotification{}, encryptionService, nil, logger) err = dc.applyChanges(context.Background(), correctPropertiesWithOrgName) if err != nil { t.Fatalf("applyChanges return an error %v", err) @@ -251,7 +253,7 @@ func TestNotificationAsConfig(t *testing.T) { t.Run("Config doesn't contain required field", func(t *testing.T) { setup() - dc := newNotificationProvisioner(orgService, &fakeAlertNotification{}, encryptionService, nil, logger) + dc := newNotificationProvisioner(setting.NewCfg(), orgService, &fakeAlertNotification{}, encryptionService, nil, logger) err := dc.applyChanges(context.Background(), noRequiredFields) require.NotNil(t, err) @@ -265,7 +267,7 @@ func TestNotificationAsConfig(t *testing.T) { t.Run("Empty yaml file", func(t *testing.T) { t.Run("should have not changed repo", func(t *testing.T) { setup() - dc := newNotificationProvisioner(orgService, &fakeAlertNotification{}, encryptionService, nil, logger) + dc := newNotificationProvisioner(setting.NewCfg(), orgService, &fakeAlertNotification{}, encryptionService, nil, logger) err := dc.applyChanges(context.Background(), emptyFile) if err != nil { t.Fatalf("applyChanges return an error %v", err) @@ -279,6 +281,7 @@ func TestNotificationAsConfig(t *testing.T) { t.Run("Broken yaml should return error", func(t *testing.T) { reader := &configReader{ + cfg: setting.NewCfg(), orgService: orgService, encryptionService: encryptionService, log: log.New("test logger"), @@ -290,6 +293,7 @@ func TestNotificationAsConfig(t *testing.T) { t.Run("Skip invalid directory", func(t *testing.T) { cfgProvider := &configReader{ + cfg: setting.NewCfg(), orgService: orgService, encryptionService: encryptionService, log: log.New("test logger"), @@ -304,6 +308,7 @@ func TestNotificationAsConfig(t *testing.T) { t.Run("Unknown notifier should return error", func(t *testing.T) { cfgProvider := &configReader{ + cfg: setting.NewCfg(), orgService: orgService, encryptionService: encryptionService, log: log.New("test logger"), @@ -315,6 +320,7 @@ func TestNotificationAsConfig(t *testing.T) { t.Run("Read incorrect properties", func(t *testing.T) { cfgProvider := &configReader{ + cfg: setting.NewCfg(), orgService: orgService, encryptionService: encryptionService, log: log.New("test logger"), diff --git a/pkg/services/provisioning/provisioning.go b/pkg/services/provisioning/provisioning.go index b4394df1391..47e5fad7916 100644 --- a/pkg/services/provisioning/provisioning.go +++ b/pkg/services/provisioning/provisioning.go @@ -107,7 +107,7 @@ func NewProvisioningServiceImpl() *ProvisioningServiceImpl { // Used for testing purposes func newProvisioningServiceImpl( newDashboardProvisioner dashboards.DashboardProvisionerFactory, - provisionNotifiers func(context.Context, string, notifiers.Manager, org.Service, encryption.Internal, *notifications.NotificationService) error, + provisionNotifiers func(context.Context, *setting.Cfg, string, notifiers.Manager, org.Service, encryption.Internal, *notifications.NotificationService) error, provisionDatasources func(context.Context, string, datasources.Store, datasources.CorrelationsStore, org.Service) error, provisionPlugins func(context.Context, string, pluginstore.Store, pluginsettings.Service, org.Service) error, ) *ProvisioningServiceImpl { @@ -132,7 +132,7 @@ type ProvisioningServiceImpl struct { pollingCtxCancel context.CancelFunc newDashboardProvisioner dashboards.DashboardProvisionerFactory dashboardProvisioner dashboards.DashboardProvisioner - provisionNotifiers func(context.Context, string, notifiers.Manager, org.Service, encryption.Internal, *notifications.NotificationService) error + provisionNotifiers func(context.Context, *setting.Cfg, string, notifiers.Manager, org.Service, encryption.Internal, *notifications.NotificationService) error provisionDatasources func(context.Context, string, datasources.Store, datasources.CorrelationsStore, org.Service) error provisionPlugins func(context.Context, string, pluginstore.Store, pluginsettings.Service, org.Service) error provisionAlerting func(context.Context, prov_alerting.ProvisionerConfig) error @@ -231,7 +231,7 @@ func (ps *ProvisioningServiceImpl) ProvisionPlugins(ctx context.Context) error { func (ps *ProvisioningServiceImpl) ProvisionNotifications(ctx context.Context) error { alertNotificationsPath := filepath.Join(ps.Cfg.ProvisioningPath, "notifiers") - if err := ps.provisionNotifiers(ctx, alertNotificationsPath, ps.alertingService, ps.orgService, ps.EncryptionService, ps.NotificationService); err != nil { + if err := ps.provisionNotifiers(ctx, ps.Cfg, alertNotificationsPath, ps.alertingService, ps.orgService, ps.EncryptionService, ps.NotificationService); err != nil { err = fmt.Errorf("%v: %w", "Alert notification provisioning error", err) ps.log.Error("Failed to provision alert notifications", "error", err) return err diff --git a/pkg/services/rendering/rendering.go b/pkg/services/rendering/rendering.go index 0b6080d102b..ded649ef67a 100644 --- a/pkg/services/rendering/rendering.go +++ b/pkg/services/rendering/rendering.go @@ -244,7 +244,7 @@ func (rs *RenderingService) renderUnavailableImage() *RenderResult { imgPath := "public/img/rendering_plugin_not_installed.png" return &RenderResult{ - FilePath: filepath.Join(setting.HomePath, imgPath), + FilePath: filepath.Join(rs.Cfg.HomePath, imgPath), } } diff --git a/pkg/services/screenshot/screenshot.go b/pkg/services/screenshot/screenshot.go index da3fd5b2166..799d46538f1 100644 --- a/pkg/services/screenshot/screenshot.go +++ b/pkg/services/screenshot/screenshot.go @@ -43,18 +43,20 @@ type ScreenshotService interface { // HeadlessScreenshotService takes screenshots using a headless browser. type HeadlessScreenshotService struct { - ds dashboards.DashboardService - rs rendering.Service + cfg *setting.Cfg + ds dashboards.DashboardService + rs rendering.Service duration prometheus.Histogram failures *prometheus.CounterVec successes prometheus.Counter } -func NewHeadlessScreenshotService(ds dashboards.DashboardService, rs rendering.Service, r prometheus.Registerer) ScreenshotService { +func NewHeadlessScreenshotService(cfg *setting.Cfg, ds dashboards.DashboardService, rs rendering.Service, r prometheus.Registerer) ScreenshotService { return &HeadlessScreenshotService{ - ds: ds, - rs: rs, + cfg: cfg, + ds: ds, + rs: rs, duration: promauto.With(r).NewHistogram(prometheus.HistogramOpts{ Name: "duration_seconds", Buckets: []float64{0.1, 0.25, 0.5, 1, 2, 5, 10, 15}, @@ -120,7 +122,7 @@ func (s *HeadlessScreenshotService) Take(ctx context.Context, opts ScreenshotOpt Width: opts.Width, Height: opts.Height, Theme: opts.Theme, - ConcurrentLimit: setting.AlertingRenderLimit, + ConcurrentLimit: s.cfg.AlertingRenderLimit, Path: u.String(), } diff --git a/pkg/services/screenshot/screenshot_test.go b/pkg/services/screenshot/screenshot_test.go index 24794ea8527..e39b60224b6 100644 --- a/pkg/services/screenshot/screenshot_test.go +++ b/pkg/services/screenshot/screenshot_test.go @@ -23,7 +23,8 @@ func TestHeadlessScreenshotService(t *testing.T) { d := dashboards.FakeDashboardService{} r := rendering.NewMockService(c) - s := NewHeadlessScreenshotService(&d, r, prometheus.NewRegistry()) + cfg := setting.NewCfg() + s := NewHeadlessScreenshotService(cfg, &d, r, prometheus.NewRegistry()) // a non-existent dashboard should return error d.On("GetDashboard", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardQuery")).Return(nil, dashboards.ErrDashboardNotFound).Once() @@ -53,7 +54,7 @@ func TestHeadlessScreenshotService(t *testing.T) { Height: DefaultHeight, Theme: DefaultTheme, Path: "d-solo/foo/bar?from=now-6h&orgId=2&panelId=4&to=now-2h", - ConcurrentLimit: setting.AlertingRenderLimit, + ConcurrentLimit: cfg.AlertingRenderLimit, } opts.From = "now-6h" diff --git a/pkg/services/searchusers/searchusers.go b/pkg/services/searchusers/searchusers.go index efddf8fe51d..2389de178da 100644 --- a/pkg/services/searchusers/searchusers.go +++ b/pkg/services/searchusers/searchusers.go @@ -9,6 +9,7 @@ import ( "github.com/grafana/grafana/pkg/services/login" "github.com/grafana/grafana/pkg/services/searchusers/sortopts" "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/setting" ) type Service interface { @@ -17,13 +18,15 @@ type Service interface { } type OSSService struct { + cfg *setting.Cfg searchUserFilter user.SearchUserFilter userService user.Service } -func ProvideUsersService(searchUserFilter user.SearchUserFilter, userService user.Service, +func ProvideUsersService(cfg *setting.Cfg, searchUserFilter user.SearchUserFilter, userService user.Service, ) *OSSService { return &OSSService{ + cfg: cfg, searchUserFilter: searchUserFilter, userService: userService, } @@ -108,7 +111,7 @@ func (s *OSSService) SearchUser(c *contextmodel.ReqContext) (*user.SearchUserQue } for _, user := range res.Users { - user.AvatarURL = dtos.GetGravatarUrl(user.Email) + user.AvatarURL = dtos.GetGravatarUrl(s.cfg, user.Email) user.AuthLabels = make([]string, 0) if user.AuthModule != nil && len(user.AuthModule) > 0 { for _, authModule := range user.AuthModule { diff --git a/pkg/services/secrets/manager/helpers.go b/pkg/services/secrets/manager/helpers.go index cc1df3e9a07..9633bde3508 100644 --- a/pkg/services/secrets/manager/helpers.go +++ b/pkg/services/secrets/manager/helpers.go @@ -26,9 +26,6 @@ func SetupDisabledTestService(tb testing.TB, store secrets.Store) *SecretsServic func setupTestService(tb testing.TB, store secrets.Store, features featuremgmt.FeatureToggles) *SecretsService { tb.Helper() defaultKey := "SdlklWklckeLS" - if len(setting.SecretKey) > 0 { - defaultKey = setting.SecretKey - } raw, err := ini.Load([]byte(` [security] secret_key = ` + defaultKey + ` diff --git a/pkg/services/secrets/manager/manager.go b/pkg/services/secrets/manager/manager.go index 669e7217c98..eb8179ece19 100644 --- a/pkg/services/secrets/manager/manager.go +++ b/pkg/services/secrets/manager/manager.go @@ -160,7 +160,7 @@ var b64 = base64.RawStdEncoding func (s *SecretsService) Encrypt(ctx context.Context, payload []byte, opt secrets.EncryptionOptions) ([]byte, error) { // Use legacy encryption service if featuremgmt.FlagDisableEnvelopeEncryption toggle is on if s.features.IsEnabled(ctx, featuremgmt.FlagDisableEnvelopeEncryption) { - return s.enc.Encrypt(ctx, payload, setting.SecretKey) + return s.enc.Encrypt(ctx, payload, s.cfg.SecretKey) } var err error diff --git a/pkg/services/serviceaccounts/api/api.go b/pkg/services/serviceaccounts/api/api.go index 98abc9eb0c9..8d52d7c8d3e 100644 --- a/pkg/services/serviceaccounts/api/api.go +++ b/pkg/services/serviceaccounts/api/api.go @@ -147,7 +147,7 @@ func (api *ServiceAccountsAPI) RetrieveServiceAccount(ctx *contextmodel.ReqConte saIDString := strconv.FormatInt(serviceAccount.Id, 10) metadata := api.getAccessControlMetadata(ctx, map[string]bool{saIDString: true}) - serviceAccount.AvatarUrl = dtos.GetGravatarUrlWithDefault("", serviceAccount.Name) + serviceAccount.AvatarUrl = dtos.GetGravatarUrlWithDefault(api.cfg, "", serviceAccount.Name) serviceAccount.AccessControl = metadata[saIDString] tokens, err := api.service.ListTokens(ctx.Req.Context(), &serviceaccounts.GetSATokensQuery{ @@ -198,7 +198,7 @@ func (api *ServiceAccountsAPI) UpdateServiceAccount(c *contextmodel.ReqContext) saIDString := strconv.FormatInt(resp.Id, 10) metadata := api.getAccessControlMetadata(c, map[string]bool{saIDString: true}) - resp.AvatarUrl = dtos.GetGravatarUrlWithDefault("", resp.Name) + resp.AvatarUrl = dtos.GetGravatarUrlWithDefault(api.cfg, "", resp.Name) resp.AccessControl = metadata[saIDString] return response.JSON(http.StatusOK, util.DynMap{ @@ -296,7 +296,7 @@ func (api *ServiceAccountsAPI) SearchOrgServiceAccountsWithPaging(c *contextmode saIDs := map[string]bool{} for i := range serviceAccountSearch.ServiceAccounts { sa := serviceAccountSearch.ServiceAccounts[i] - sa.AvatarUrl = dtos.GetGravatarUrlWithDefault("", sa.Name) + sa.AvatarUrl = dtos.GetGravatarUrlWithDefault(api.cfg, "", sa.Name) saIDString := strconv.FormatInt(sa.Id, 10) saIDs[saIDString] = true diff --git a/pkg/services/sqlstore/migrations/external_alertmanagers.go b/pkg/services/sqlstore/migrations/external_alertmanagers.go index 78d91192a9d..067feee3a17 100644 --- a/pkg/services/sqlstore/migrations/external_alertmanagers.go +++ b/pkg/services/sqlstore/migrations/external_alertmanagers.go @@ -77,7 +77,7 @@ func (e externalAlertmanagerToDatasources) Exec(sess *xorm.Session, mg *migrator ds.BasicAuth = true ds.BasicAuthUser = u.User.Username() if password, ok := u.User.Password(); ok { - ds.SecureJsonData = getEncryptedJsonData(map[string]string{ + ds.SecureJsonData = getEncryptedJsonData(mg.Cfg, map[string]string{ "basicAuthPassword": password, }, log.New("securejsondata")) } @@ -132,10 +132,10 @@ func generateNewDatasourceUid(sess *xorm.Session, orgId int64) (string, error) { type secureJsonData map[string][]byte // getEncryptedJsonData returns map where all keys are encrypted. -func getEncryptedJsonData(sjd map[string]string, log log.Logger) secureJsonData { +func getEncryptedJsonData(cfg *setting.Cfg, sjd map[string]string, log log.Logger) secureJsonData { encrypted := make(secureJsonData) for key, data := range sjd { - encryptedData, err := util.Encrypt([]byte(data), setting.SecretKey) + encryptedData, err := util.Encrypt([]byte(data), cfg.SecretKey) if err != nil { log.Error(err.Error()) os.Exit(1) diff --git a/pkg/services/store/config.go b/pkg/services/store/config.go index 68ff6a632fc..d2f86616702 100644 --- a/pkg/services/store/config.go +++ b/pkg/services/store/config.go @@ -52,7 +52,7 @@ func LoadStorageConfig(cfg *setting.Cfg, features featuremgmt.FeatureToggles) (* } // Save a template version in config - if changed && setting.Env != setting.Prod { + if changed && cfg.Env != setting.Prod { return g, g.save() } return g, nil diff --git a/pkg/services/store/service.go b/pkg/services/store/service.go index 8136b2e0a9a..fe523f80f52 100644 --- a/pkg/services/store/service.go +++ b/pkg/services/store/service.go @@ -125,7 +125,7 @@ func ProvideService( } // Development dashboards - if settings.AddDevEnv && setting.Env != setting.Prod { + if settings.AddDevEnv && cfg.Env != setting.Prod { devenv := filepath.Join(cfg.StaticRootPath, "..", "devenv") if _, err := os.Stat(devenv); !os.IsNotExist(err) { s := newDiskStorage(RootStorageMeta{ diff --git a/pkg/services/team/teamapi/team.go b/pkg/services/team/teamapi/team.go index b12757856d2..7a807a803bf 100644 --- a/pkg/services/team/teamapi/team.go +++ b/pkg/services/team/teamapi/team.go @@ -182,7 +182,7 @@ func (tapi *TeamAPI) searchTeams(c *contextmodel.ReqContext) response.Response { teamIDs := map[string]bool{} for _, team := range queryResult.Teams { - team.AvatarURL = dtos.GetGravatarUrlWithDefault(team.Email, team.Name) + team.AvatarURL = dtos.GetGravatarUrlWithDefault(tapi.cfg, team.Email, team.Name) teamIDs[strconv.FormatInt(team.ID, 10)] = true } @@ -234,7 +234,7 @@ func (tapi *TeamAPI) getTeamByID(c *contextmodel.ReqContext) response.Response { // Add accesscontrol metadata queryResult.AccessControl = tapi.getAccessControlMetadata(c, c.SignedInUser.GetOrgID(), "teams:id:", strconv.FormatInt(queryResult.ID, 10)) - queryResult.AvatarURL = dtos.GetGravatarUrlWithDefault(queryResult.Email, queryResult.Name) + queryResult.AvatarURL = dtos.GetGravatarUrlWithDefault(tapi.cfg, queryResult.Email, queryResult.Name) return response.JSON(http.StatusOK, &queryResult) } diff --git a/pkg/services/team/teamapi/team_members.go b/pkg/services/team/teamapi/team_members.go index 75c3317e8af..89419b8ff09 100644 --- a/pkg/services/team/teamapi/team_members.go +++ b/pkg/services/team/teamapi/team_members.go @@ -47,7 +47,7 @@ func (tapi *TeamAPI) getTeamMembers(c *contextmodel.ReqContext) response.Respons continue } - member.AvatarURL = dtos.GetGravatarUrl(member.Email) + member.AvatarURL = dtos.GetGravatarUrl(tapi.cfg, member.Email) member.Labels = []string{} if tapi.license.FeatureEnabled("teamgroupsync") && member.External { diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go index b650691c5d5..b487ac37a47 100644 --- a/pkg/setting/setting.go +++ b/pkg/setting/setting.go @@ -55,12 +55,12 @@ const ( const zoneInfo = "ZONEINFO" var ( + customInitPath = "conf/custom.ini" + // App settings. - Env = Dev - AppUrl string - AppSubUrl string - ServeFromSubPath bool - InstanceName string + Env = Dev + AppUrl string + AppSubUrl string // build BuildVersion string @@ -73,76 +73,9 @@ var ( // packaging Packaging = "unknown" - // Paths - HomePath string - CustomInitPath = "conf/custom.ini" - - // HTTP server options - StaticRootPath string - - // Security settings. - SecretKey string - DisableGravatar bool - DataProxyWhiteList map[string]bool CookieSecure bool CookieSameSiteDisabled bool CookieSameSiteMode http.SameSite - - // Dashboard history - DashboardVersionsToKeep int - MinRefreshInterval string - - // User settings - AllowUserSignUp bool - AllowUserOrgCreate bool - VerifyEmailEnabled bool - LoginHint string - PasswordHint string - DisableSignoutMenu bool - ExternalUserMngLinkUrl string - ExternalUserMngLinkName string - ExternalUserMngInfo string - - // HTTP auth - SigV4AuthEnabled bool - AzureAuthEnabled bool - - // Global setting objects. - Raw *ini.File - - // for logging purposes - configFiles []string - appliedCommandLineProperties []string - appliedEnvOverrides []string - - // Alerting - AlertingEnabled *bool - ExecuteAlerts bool - AlertingRenderLimit int - AlertingErrorOrTimeout string - AlertingNoDataOrNullValues string - - AlertingEvaluationTimeout time.Duration - AlertingNotificationTimeout time.Duration - AlertingMaxAttempts int - AlertingMinInterval int64 - - // Explore UI - ExploreEnabled bool - - // Help UI - HelpEnabled bool - - // Profile UI - ProfileEnabled bool - - // News Feed - NewsFeedEnabled bool - - // Grafana.NET URL - GrafanaComUrl string - - ImageUploadProvider string ) // TODO move all global vars to this struct @@ -151,13 +84,20 @@ type Cfg struct { Raw *ini.File Logger log.Logger + // for logging purposes + configFiles []string + appliedCommandLineProperties []string + appliedEnvOverrides []string + // HTTP Server Settings CertFile string KeyFile string HTTPAddr string HTTPPort string + Env string AppURL string AppSubURL string + InstanceName string ServeFromSubPath bool StaticRootPath string Protocol Scheme @@ -231,6 +171,8 @@ type Cfg struct { CSPReportOnlyTemplate string AngularSupportEnabled bool DisableFrontendSandboxForPlugins []string + DisableGravatar bool + DataProxyWhiteList map[string]bool TempDataLifetime time.Duration @@ -269,6 +211,8 @@ type Cfg struct { MetricsGrafanaEnvironmentInfo map[string]string // Dashboards + DashboardVersionsToKeep int + MinRefreshInterval string DefaultHomeDashboardPath string // Auth @@ -417,8 +361,6 @@ type Cfg struct { ErrTemplateName string - Env string - StackID string Slug string @@ -460,6 +402,16 @@ type Cfg struct { Quota QuotaSettings + // User settings + AllowUserSignUp bool + AllowUserOrgCreate bool + VerifyEmailEnabled bool + LoginHint string + PasswordHint string + DisableSignoutMenu bool + ExternalUserMngLinkUrl string + ExternalUserMngLinkName string + ExternalUserMngInfo string AutoAssignOrg bool AutoAssignOrgId int AutoAssignOrgRole string @@ -549,6 +501,30 @@ type Cfg struct { // Feature Management Settings FeatureManagement FeatureMgmtSettings + + // Alerting + AlertingEnabled *bool + ExecuteAlerts bool + AlertingRenderLimit int + AlertingErrorOrTimeout string + AlertingNoDataOrNullValues string + + AlertingEvaluationTimeout time.Duration + AlertingNotificationTimeout time.Duration + AlertingMaxAttempts int + AlertingMinInterval int64 + + // Explore UI + ExploreEnabled bool + + // Help UI + HelpEnabled bool + + // Profile UI + ProfileEnabled bool + + // News Feed + NewsFeedEnabled bool } // AddChangePasswordLink returns if login form is disabled or not since @@ -659,8 +635,8 @@ func RedactedURL(value string) (string, error) { return strings.Join(chunks, " "), nil } -func applyEnvVariableOverrides(file *ini.File) error { - appliedEnvOverrides = make([]string, 0) +func (cfg *Cfg) applyEnvVariableOverrides(file *ini.File) error { + cfg.appliedEnvOverrides = make([]string, 0) for _, section := range file.Sections() { for _, key := range section.Keys() { envKey := EnvKey(section.Name(), key.Name()) @@ -668,7 +644,7 @@ func applyEnvVariableOverrides(file *ini.File) error { if len(envValue) > 0 { key.SetValue(envValue) - appliedEnvOverrides = append(appliedEnvOverrides, fmt.Sprintf("%s=%s", envKey, RedactedValue(envKey, envValue))) + cfg.appliedEnvOverrides = append(cfg.appliedEnvOverrides, fmt.Sprintf("%s=%s", envKey, RedactedValue(envKey, envValue))) } } } @@ -762,22 +738,22 @@ func EnvKey(sectionName string, keyName string) string { return envKey } -func applyCommandLineDefaultProperties(props map[string]string, file *ini.File) { - appliedCommandLineProperties = make([]string, 0) +func (cfg *Cfg) applyCommandLineDefaultProperties(props map[string]string, file *ini.File) { + cfg.appliedCommandLineProperties = make([]string, 0) for _, section := range file.Sections() { for _, key := range section.Keys() { keyString := fmt.Sprintf("default.%s.%s", section.Name(), key.Name()) value, exists := props[keyString] if exists { key.SetValue(value) - appliedCommandLineProperties = append(appliedCommandLineProperties, + cfg.appliedCommandLineProperties = append(cfg.appliedCommandLineProperties, fmt.Sprintf("%s=%s", keyString, RedactedValue(keyString, value))) } } } } -func applyCommandLineProperties(props map[string]string, file *ini.File) { +func (cfg *Cfg) applyCommandLineProperties(props map[string]string, file *ini.File) { for _, section := range file.Sections() { sectionName := section.Name() + "." if section.Name() == ini.DefaultSection { @@ -787,7 +763,7 @@ func applyCommandLineProperties(props map[string]string, file *ini.File) { keyString := sectionName + key.Name() value, exists := props[keyString] if exists { - appliedCommandLineProperties = append(appliedCommandLineProperties, fmt.Sprintf("%s=%s", keyString, value)) + cfg.appliedCommandLineProperties = append(cfg.appliedCommandLineProperties, fmt.Sprintf("%s=%s", keyString, value)) key.SetValue(value) } } @@ -823,7 +799,7 @@ func makeAbsolute(path string, root string) string { func (cfg *Cfg) loadSpecifiedConfigFile(configFile string, masterFile *ini.File) error { if configFile == "" { - configFile = filepath.Join(cfg.HomePath, CustomInitPath) + configFile = filepath.Join(cfg.HomePath, customInitPath) // return without error if custom file does not exist if !pathExists(configFile) { return nil @@ -855,14 +831,14 @@ func (cfg *Cfg) loadSpecifiedConfigFile(configFile string, masterFile *ini.File) } } - configFiles = append(configFiles, configFile) + cfg.configFiles = append(cfg.configFiles, configFile) return nil } func (cfg *Cfg) loadConfiguration(args CommandLineArgs) (*ini.File, error) { // load config defaults - defaultConfigFile := path.Join(HomePath, "conf/defaults.ini") - configFiles = append(configFiles, defaultConfigFile) + defaultConfigFile := path.Join(cfg.HomePath, "conf/defaults.ini") + cfg.configFiles = append(cfg.configFiles, defaultConfigFile) // check if config file exists if _, err := os.Stat(defaultConfigFile); os.IsNotExist(err) { @@ -883,7 +859,7 @@ func (cfg *Cfg) loadConfiguration(args CommandLineArgs) (*ini.File, error) { // command line props commandLineProps := cfg.getCommandLineProperties(args.Args) // load default overrides - applyCommandLineDefaultProperties(commandLineProps, parsedFile) + cfg.applyCommandLineDefaultProperties(commandLineProps, parsedFile) // load specified config file err = cfg.loadSpecifiedConfigFile(args.Config, parsedFile) @@ -897,13 +873,13 @@ func (cfg *Cfg) loadConfiguration(args CommandLineArgs) (*ini.File, error) { } // apply environment overrides - err = applyEnvVariableOverrides(parsedFile) + err = cfg.applyEnvVariableOverrides(parsedFile) if err != nil { return nil, err } // apply command line overrides - applyCommandLineProperties(commandLineProps, parsedFile) + cfg.applyCommandLineProperties(commandLineProps, parsedFile) // evaluate config values containing environment variables err = expandConfig(parsedFile) @@ -914,7 +890,7 @@ func (cfg *Cfg) loadConfiguration(args CommandLineArgs) (*ini.File, error) { // update data path and logging config dataPath := valueAsString(parsedFile.Section("paths"), "data", "") - cfg.DataPath = makeAbsolute(dataPath, HomePath) + cfg.DataPath = makeAbsolute(dataPath, cfg.HomePath) err = cfg.initLogging(parsedFile) if err != nil { return nil, err @@ -939,7 +915,6 @@ func pathExists(path string) bool { func (cfg *Cfg) setHomePath(args CommandLineArgs) { if args.HomePath != "" { cfg.HomePath = args.HomePath - HomePath = cfg.HomePath return } @@ -949,7 +924,6 @@ func (cfg *Cfg) setHomePath(args CommandLineArgs) { panic(err) } - HomePath = cfg.HomePath // check if homepath is correct if pathExists(filepath.Join(cfg.HomePath, "conf/defaults.ini")) { return @@ -958,7 +932,6 @@ func (cfg *Cfg) setHomePath(args CommandLineArgs) { // try down one path if pathExists(filepath.Join(cfg.HomePath, "../conf/defaults.ini")) { cfg.HomePath = filepath.Join(cfg.HomePath, "../") - HomePath = cfg.HomePath } } @@ -966,6 +939,7 @@ var skipStaticRootValidation = false func NewCfg() *Cfg { return &Cfg{ + Env: Dev, Target: []string{"all"}, Logger: log.New("settings"), Raw: ini.Empty(), @@ -995,26 +969,48 @@ func NewCfgFromArgs(args CommandLineArgs) (*Cfg, error) { return cfg, nil } +// NewCfgFromBytes specialized function to create a new Cfg from bytes (INI file). +func NewCfgFromBytes(bytes []byte) (*Cfg, error) { + parsedFile, err := ini.Load(bytes) + if err != nil { + return nil, fmt.Errorf("failed to parse bytes as INI file: %w", err) + } + + parsedFile.BlockMode = false + + return NewCfgFromINIFile(parsedFile) +} + +// NewCfgFromINIFile specialized function to create a new Cfg from an ini.File. +func NewCfgFromINIFile(iniFile *ini.File) (*Cfg, error) { + cfg := NewCfg() + + if err := cfg.parseINIFile(iniFile); err != nil { + return nil, fmt.Errorf("failed to parse setting from INI file: %w", err) + } + + return cfg, nil +} + func (cfg *Cfg) validateStaticRootPath() error { if skipStaticRootValidation { return nil } - if _, err := os.Stat(path.Join(StaticRootPath, "build")); err != nil { + if _, err := os.Stat(path.Join(cfg.StaticRootPath, "build")); err != nil { cfg.Logger.Error("Failed to detect generated javascript files in public/build") } return nil } -// nolint:gocyclo func (cfg *Cfg) Load(args CommandLineArgs) error { cfg.setHomePath(args) // Fix for missing IANA db on Windows _, zoneInfoSet := os.LookupEnv(zoneInfo) if runtime.GOOS == "windows" && !zoneInfoSet { - if err := os.Setenv(zoneInfo, filepath.Join(HomePath, "tools", "zoneinfo.zip")); err != nil { + if err := os.Setenv(zoneInfo, filepath.Join(cfg.HomePath, "tools", "zoneinfo.zip")); err != nil { cfg.Logger.Error("Can't set ZONEINFO environment variable", "err", err) } } @@ -1024,10 +1020,19 @@ func (cfg *Cfg) Load(args CommandLineArgs) error { return err } - cfg.Raw = iniFile + err = cfg.parseINIFile(iniFile) + if err != nil { + return err + } - // Temporarily keep global, to make refactor in steps - Raw = cfg.Raw + cfg.LogConfigSources() + + return nil +} + +// nolint:gocyclo +func (cfg *Cfg) parseINIFile(iniFile *ini.File) error { + cfg.Raw = iniFile cfg.BuildVersion = BuildVersion cfg.BuildCommit = BuildCommit @@ -1043,18 +1048,17 @@ func (cfg *Cfg) Load(args CommandLineArgs) error { if Target != "" { cfg.Target = util.SplitString(Target) } - Env = valueAsString(iniFile.Section(""), "app_mode", "development") - cfg.Env = Env + cfg.Env = valueAsString(iniFile.Section(""), "app_mode", "development") cfg.StackID = valueAsString(iniFile.Section("environment"), "stack_id", "") cfg.Slug = valueAsString(iniFile.Section("environment"), "stack_slug", "") //nolint:staticcheck cfg.ForceMigration = iniFile.Section("").Key("force_migration").MustBool(false) - InstanceName = valueAsString(iniFile.Section(""), "instance_name", "unknown_instance_name") + cfg.InstanceName = valueAsString(iniFile.Section(""), "instance_name", "unknown_instance_name") plugins := valueAsString(iniFile.Section("paths"), "plugins", "") - cfg.PluginsPath = makeAbsolute(plugins, HomePath) - cfg.BundledPluginsPath = makeAbsolute("plugins-bundled", HomePath) + cfg.PluginsPath = makeAbsolute(plugins, cfg.HomePath) + cfg.BundledPluginsPath = makeAbsolute("plugins-bundled", cfg.HomePath) provisioning := valueAsString(iniFile.Section("paths"), "provisioning", "") - cfg.ProvisioningPath = makeAbsolute(provisioning, HomePath) + cfg.ProvisioningPath = makeAbsolute(provisioning, cfg.HomePath) if err := cfg.readServerSettings(iniFile); err != nil { return err @@ -1078,9 +1082,8 @@ func (cfg *Cfg) Load(args CommandLineArgs) error { // read dashboard settings dashboards := iniFile.Section("dashboards") - DashboardVersionsToKeep = dashboards.Key("versions_to_keep").MustInt(20) - MinRefreshInterval = valueAsString(dashboards, "min_refresh_interval", "5s") - + cfg.DashboardVersionsToKeep = dashboards.Key("versions_to_keep").MustInt(20) + cfg.MinRefreshInterval = valueAsString(dashboards, "min_refresh_interval", "5s") cfg.DefaultHomeDashboardPath = dashboards.Key("default_home_dashboard_path").MustString("") if err := readUserSettings(iniFile, cfg); err != nil { @@ -1134,21 +1137,21 @@ func (cfg *Cfg) Load(args CommandLineArgs) error { cfg.ApplicationInsightsEndpointUrl = analytics.Key("application_insights_endpoint_url").String() cfg.FeedbackLinksEnabled = analytics.Key("feedback_links_enabled").MustBool(true) - if err := readAlertingSettings(iniFile); err != nil { + if err := cfg.readAlertingSettings(iniFile); err != nil { return err } explore := iniFile.Section("explore") - ExploreEnabled = explore.Key("enabled").MustBool(true) + cfg.ExploreEnabled = explore.Key("enabled").MustBool(true) help := iniFile.Section("help") - HelpEnabled = help.Key("enabled").MustBool(true) + cfg.HelpEnabled = help.Key("enabled").MustBool(true) profile := iniFile.Section("profile") - ProfileEnabled = profile.Key("enabled").MustBool(true) + cfg.ProfileEnabled = profile.Key("enabled").MustBool(true) news := iniFile.Section("news") - NewsFeedEnabled = news.Key("news_feed_enabled").MustBool(true) + cfg.NewsFeedEnabled = news.Key("news_feed_enabled").MustBool(true) queryHistory := iniFile.Section("query_history") cfg.QueryHistoryEnabled = queryHistory.Key("enabled").MustBool(true) @@ -1199,6 +1202,7 @@ func (cfg *Cfg) Load(args CommandLineArgs) error { cfg.Storage = readStorageSettings(iniFile) cfg.Search = readSearchSettings(iniFile) + var err error cfg.SecureSocksDSProxy, err = readSecureSocksDSProxySettings(iniFile) if err != nil { // if the proxy is misconfigured, disable it rather than crashing @@ -1206,22 +1210,21 @@ func (cfg *Cfg) Load(args CommandLineArgs) error { cfg.Logger.Error("secure_socks_datasource_proxy unable to start up", "err", err.Error()) } - if VerifyEmailEnabled && !cfg.Smtp.Enabled { + if cfg.VerifyEmailEnabled && !cfg.Smtp.Enabled { cfg.Logger.Warn("require_email_validation is enabled but smtp is disabled") } // check old key name - GrafanaComUrl = valueAsString(iniFile.Section("grafana_net"), "url", "") - if GrafanaComUrl == "" { - GrafanaComUrl = valueAsString(iniFile.Section("grafana_com"), "url", "https://grafana.com") + grafanaComUrl := valueAsString(iniFile.Section("grafana_net"), "url", "") + if grafanaComUrl == "" { + grafanaComUrl = valueAsString(iniFile.Section("grafana_com"), "url", "https://grafana.com") } - cfg.GrafanaComURL = GrafanaComUrl + cfg.GrafanaComURL = grafanaComUrl - cfg.GrafanaComAPIURL = valueAsString(iniFile.Section("grafana_com"), "api_url", GrafanaComUrl+"/api") + cfg.GrafanaComAPIURL = valueAsString(iniFile.Section("grafana_com"), "api_url", grafanaComUrl+"/api") imageUploadingSection := iniFile.Section("external_image_storage") cfg.ImageUploadProvider = valueAsString(imageUploadingSection, "provider", "") - ImageUploadProvider = cfg.ImageUploadProvider enterprise := iniFile.Section("enterprise") cfg.EnterpriseLicensePath = valueAsString(enterprise, "license_path", filepath.Join(cfg.DataPath, "license.jwt")) @@ -1243,7 +1246,7 @@ func (cfg *Cfg) Load(args CommandLineArgs) error { basemapJSON := valueAsString(geomapSection, "default_baselayer_config", "") if basemapJSON != "" { layer := make(map[string]any) - err = json.Unmarshal([]byte(basemapJSON), &layer) + err := json.Unmarshal([]byte(basemapJSON), &layer) if err != nil { cfg.Logger.Error("Error reading json from default_baselayer_config", "error", err) } else { @@ -1259,8 +1262,6 @@ func (cfg *Cfg) Load(args CommandLineArgs) error { return err } - cfg.LogConfigSources() - databaseSection := iniFile.Section("database") cfg.DatabaseInstrumentQueries = databaseSection.Key("instrument_queries").MustBool(false) @@ -1349,32 +1350,32 @@ func (cfg *Cfg) initLogging(file *ini.File) error { logModes = strings.Split(logModeStr, " ") } logsPath := valueAsString(file.Section("paths"), "logs", "") - cfg.LogsPath = makeAbsolute(logsPath, HomePath) + cfg.LogsPath = makeAbsolute(logsPath, cfg.HomePath) return log.ReadLoggingConfig(logModes, cfg.LogsPath, file) } func (cfg *Cfg) LogConfigSources() { var text bytes.Buffer - for _, file := range configFiles { + for _, file := range cfg.configFiles { cfg.Logger.Info("Config loaded from", "file", file) } - if len(appliedCommandLineProperties) > 0 { - for _, prop := range appliedCommandLineProperties { + if len(cfg.appliedCommandLineProperties) > 0 { + for _, prop := range cfg.appliedCommandLineProperties { cfg.Logger.Info("Config overridden from command line", "arg", prop) } } - if len(appliedEnvOverrides) > 0 { + if len(cfg.appliedEnvOverrides) > 0 { text.WriteString("\tEnvironment variables used:\n") - for _, prop := range appliedEnvOverrides { + for _, prop := range cfg.appliedEnvOverrides { cfg.Logger.Info("Config overridden from Environment variable", "var", prop) } } cfg.Logger.Info("Target", "target", cfg.Target) - cfg.Logger.Info("Path Home", "path", HomePath) + cfg.Logger.Info("Path Home", "path", cfg.HomePath) cfg.Logger.Info("Path Data", "path", cfg.DataPath) cfg.Logger.Info("Path Logs", "path", cfg.LogsPath) cfg.Logger.Info("Path Plugins", "path", cfg.PluginsPath) @@ -1424,9 +1425,8 @@ func (cfg *Cfg) SectionWithEnvOverrides(s string) *DynamicSection { func readSecuritySettings(iniFile *ini.File, cfg *Cfg) error { security := iniFile.Section("security") - SecretKey = valueAsString(security, "secret_key", "") - cfg.SecretKey = SecretKey - DisableGravatar = security.Key("disable_gravatar").MustBool(true) + cfg.SecretKey = valueAsString(security, "secret_key", "") + cfg.DisableGravatar = security.Key("disable_gravatar").MustBool(true) cfg.DisableBruteForceLoginProtection = security.Key("disable_brute_force_login_protection").MustBool(false) CookieSecure = security.Key("cookie_secure").MustBool(false) @@ -1481,11 +1481,11 @@ func readSecuritySettings(iniFile *ini.File, cfg *Cfg) error { } // read data source proxy whitelist - DataProxyWhiteList = make(map[string]bool) + cfg.DataProxyWhiteList = make(map[string]bool) securityStr := valueAsString(security, "data_source_proxy_whitelist", "") for _, hostAndIP := range util.SplitString(securityStr) { - DataProxyWhiteList[hostAndIP] = true + cfg.DataProxyWhiteList[hostAndIP] = true } // admin @@ -1528,7 +1528,7 @@ func readAuthSettings(iniFile *ini.File, cfg *Cfg) (err error) { cfg.AuthConfigUIAdminAccess = auth.Key("config_ui_admin_access").MustBool(false) cfg.DisableLoginForm = auth.Key("disable_login_form").MustBool(false) - DisableSignoutMenu = auth.Key("disable_signout_menu").MustBool(false) + cfg.DisableSignoutMenu = auth.Key("disable_signout_menu").MustBool(false) // Deprecated cfg.OAuthAutoLogin = auth.Key("oauth_auto_login").MustBool(false) @@ -1547,13 +1547,11 @@ func readAuthSettings(iniFile *ini.File, cfg *Cfg) (err error) { cfg.DisableLogin = auth.Key("disable_login").MustBool(false) // SigV4 - SigV4AuthEnabled = auth.Key("sigv4_auth_enabled").MustBool(false) - cfg.SigV4AuthEnabled = SigV4AuthEnabled + cfg.SigV4AuthEnabled = auth.Key("sigv4_auth_enabled").MustBool(false) cfg.SigV4VerboseLogging = auth.Key("sigv4_verbose_logging").MustBool(false) // Azure Auth - AzureAuthEnabled = auth.Key("azure_auth_enabled").MustBool(false) - cfg.AzureAuthEnabled = AzureAuthEnabled + cfg.AzureAuthEnabled = auth.Key("azure_auth_enabled").MustBool(false) // ID response header cfg.IDResponseHeaderEnabled = auth.Key("id_response_header_enabled").MustBool(false) @@ -1651,8 +1649,8 @@ func readOAuth2ServerSettings(cfg *Cfg) { func readUserSettings(iniFile *ini.File, cfg *Cfg) error { users := iniFile.Section("users") - AllowUserSignUp = users.Key("allow_sign_up").MustBool(true) - AllowUserOrgCreate = users.Key("allow_org_create").MustBool(true) + cfg.AllowUserSignUp = users.Key("allow_sign_up").MustBool(true) + cfg.AllowUserOrgCreate = users.Key("allow_org_create").MustBool(true) cfg.AutoAssignOrg = users.Key("auto_assign_org").MustBool(true) cfg.AutoAssignOrgId = users.Key("auto_assign_org_id").MustInt(1) cfg.AutoAssignOrgRole = users.Key("auto_assign_org_role").In( @@ -1661,18 +1659,18 @@ func readUserSettings(iniFile *ini.File, cfg *Cfg) error { string(roletype.RoleViewer), string(roletype.RoleEditor), string(roletype.RoleAdmin)}) - VerifyEmailEnabled = users.Key("verify_email_enabled").MustBool(false) + cfg.VerifyEmailEnabled = users.Key("verify_email_enabled").MustBool(false) cfg.CaseInsensitiveLogin = users.Key("case_insensitive_login").MustBool(true) - LoginHint = valueAsString(users, "login_hint", "") - PasswordHint = valueAsString(users, "password_hint", "") + cfg.LoginHint = valueAsString(users, "login_hint", "") + cfg.PasswordHint = valueAsString(users, "password_hint", "") cfg.DefaultTheme = valueAsString(users, "default_theme", "") cfg.DefaultLanguage = valueAsString(users, "default_language", "") cfg.HomePage = valueAsString(users, "home_page", "") - ExternalUserMngLinkUrl = valueAsString(users, "external_manage_link_url", "") - ExternalUserMngLinkName = valueAsString(users, "external_manage_link_name", "") - ExternalUserMngInfo = valueAsString(users, "external_manage_info", "") + cfg.ExternalUserMngLinkUrl = valueAsString(users, "external_manage_link_url", "") + cfg.ExternalUserMngLinkName = valueAsString(users, "external_manage_link_name", "") + cfg.ExternalUserMngInfo = valueAsString(users, "external_manage_info", "") cfg.ViewersCanEdit = users.Key("viewers_can_edit").MustBool(false) cfg.EditorsCanAdmin = users.Key("editors_can_admin").MustBool(false) @@ -1734,29 +1732,35 @@ func (cfg *Cfg) readRenderingSettings(iniFile *ini.File) error { return nil } -func readAlertingSettings(iniFile *ini.File) error { +func (cfg *Cfg) readAlertingSettings(iniFile *ini.File) error { alerting := iniFile.Section("alerting") enabled, err := alerting.Key("enabled").Bool() - AlertingEnabled = nil + cfg.AlertingEnabled = nil if err == nil { - AlertingEnabled = &enabled + cfg.AlertingEnabled = &enabled } - ExecuteAlerts = alerting.Key("execute_alerts").MustBool(true) - AlertingRenderLimit = alerting.Key("concurrent_render_limit").MustInt(5) + cfg.ExecuteAlerts = alerting.Key("execute_alerts").MustBool(true) + cfg.AlertingRenderLimit = alerting.Key("concurrent_render_limit").MustInt(5) - AlertingErrorOrTimeout = valueAsString(alerting, "error_or_timeout", "alerting") - AlertingNoDataOrNullValues = valueAsString(alerting, "nodata_or_nullvalues", "no_data") + cfg.AlertingErrorOrTimeout = valueAsString(alerting, "error_or_timeout", "alerting") + cfg.AlertingNoDataOrNullValues = valueAsString(alerting, "nodata_or_nullvalues", "no_data") evaluationTimeoutSeconds := alerting.Key("evaluation_timeout_seconds").MustInt64(30) - AlertingEvaluationTimeout = time.Second * time.Duration(evaluationTimeoutSeconds) + cfg.AlertingEvaluationTimeout = time.Second * time.Duration(evaluationTimeoutSeconds) notificationTimeoutSeconds := alerting.Key("notification_timeout_seconds").MustInt64(30) - AlertingNotificationTimeout = time.Second * time.Duration(notificationTimeoutSeconds) - AlertingMaxAttempts = alerting.Key("max_attempts").MustInt(3) - AlertingMinInterval = alerting.Key("min_interval_seconds").MustInt64(1) + cfg.AlertingNotificationTimeout = time.Second * time.Duration(notificationTimeoutSeconds) + cfg.AlertingMaxAttempts = alerting.Key("max_attempts").MustInt(3) + cfg.AlertingMinInterval = alerting.Key("min_interval_seconds").MustInt64(1) return nil } +// IsLegacyAlertingEnabled returns whether the legacy alerting is enabled or not. +// It's safe to be used only after readAlertingSettings() and ReadUnifiedAlertingSettings() are executed. +func (cfg *Cfg) IsLegacyAlertingEnabled() bool { + return cfg.AlertingEnabled != nil && *(cfg.AlertingEnabled) +} + func readGRPCServerSettings(cfg *Cfg, iniFile *ini.File) error { server := iniFile.Section("grpc_server") errPrefix := "grpc_server:" @@ -1819,12 +1823,6 @@ func readGRPCServerSettings(cfg *Cfg, iniFile *ini.File) error { return nil } -// IsLegacyAlertingEnabled returns whether the legacy alerting is enabled or not. -// It's safe to be used only after readAlertingSettings() and ReadUnifiedAlertingSettings() are executed. -func IsLegacyAlertingEnabled() bool { - return AlertingEnabled != nil && *AlertingEnabled -} - func readSnapshotsSettings(cfg *Cfg, iniFile *ini.File) error { snapshots := iniFile.Section("snapshots") @@ -1847,12 +1845,11 @@ func (cfg *Cfg) readServerSettings(iniFile *ini.File) error { if err != nil { return err } - ServeFromSubPath = server.Key("serve_from_sub_path").MustBool(false) cfg.AppURL = AppUrl cfg.AppSubURL = AppSubUrl - cfg.ServeFromSubPath = ServeFromSubPath cfg.Protocol = HTTPScheme + cfg.ServeFromSubPath = server.Key("serve_from_sub_path").MustBool(false) protocolStr := valueAsString(server, "protocol", "http") @@ -1886,8 +1883,7 @@ func (cfg *Cfg) readServerSettings(iniFile *ini.File) error { cfg.EnableGzip = server.Key("enable_gzip").MustBool(false) cfg.EnforceDomain = server.Key("enforce_domain").MustBool(false) staticRoot := valueAsString(server, "static_root_path", "") - StaticRootPath = makeAbsolute(staticRoot, HomePath) - cfg.StaticRootPath = StaticRootPath + cfg.StaticRootPath = makeAbsolute(staticRoot, cfg.HomePath) if err := cfg.validateStaticRootPath(); err != nil { return err diff --git a/pkg/setting/setting_smtp.go b/pkg/setting/setting_smtp.go index 2428c7d3825..dfcbe859dd5 100644 --- a/pkg/setting/setting_smtp.go +++ b/pkg/setting/setting_smtp.go @@ -41,6 +41,9 @@ func (cfg *Cfg) readSmtpSettings() error { cfg.Smtp.FromAddress = sec.Key("from_address").String() cfg.Smtp.FromName = sec.Key("from_name").String() cfg.Smtp.EhloIdentity = sec.Key("ehlo_identity").String() + if cfg.Smtp.EhloIdentity == "" { + cfg.Smtp.EhloIdentity = cfg.InstanceName + } cfg.Smtp.StartTLSPolicy = sec.Key("startTLS_policy").String() cfg.Smtp.SkipVerify = sec.Key("skip_verify").MustBool(false) diff --git a/pkg/setting/setting_test.go b/pkg/setting/setting_test.go index a309211be1d..08a20bd0125 100644 --- a/pkg/setting/setting_test.go +++ b/pkg/setting/setting_test.go @@ -54,13 +54,13 @@ func TestLoadingSettings(t *testing.T) { }) t.Run("sample.ini should load successfully", func(t *testing.T) { - customInitPath := CustomInitPath - CustomInitPath = "conf/sample.ini" + oldCustomInitPath := customInitPath + customInitPath = "conf/sample.ini" cfg := NewCfg() err := cfg.Load(CommandLineArgs{HomePath: "../../"}) require.Nil(t, err) // Restore CustomInitPath to avoid side effects. - CustomInitPath = customInitPath + customInitPath = oldCustomInitPath }) t.Run("Should be able to override via environment variables", func(t *testing.T) { @@ -71,7 +71,7 @@ func TestLoadingSettings(t *testing.T) { require.Nil(t, err) require.Equal(t, "superduper", cfg.AdminUser) - require.Equal(t, filepath.Join(HomePath, "data"), cfg.DataPath) + require.Equal(t, filepath.Join(cfg.HomePath, "data"), cfg.DataPath) require.Equal(t, filepath.Join(cfg.DataPath, "log"), cfg.LogsPath) }) @@ -95,7 +95,7 @@ func TestLoadingSettings(t *testing.T) { err := cfg.Load(CommandLineArgs{HomePath: "../../"}) require.Nil(t, err) - require.Contains(t, appliedEnvOverrides, "GF_SECURITY_ADMIN_PASSWORD=*********") + require.Contains(t, cfg.appliedEnvOverrides, "GF_SECURITY_ADMIN_PASSWORD=*********") }) t.Run("Should replace password in URL when url environment is defined", func(t *testing.T) { @@ -105,7 +105,7 @@ func TestLoadingSettings(t *testing.T) { err := cfg.Load(CommandLineArgs{HomePath: "../../"}) require.Nil(t, err) - require.Contains(t, appliedEnvOverrides, "GF_DATABASE_URL=mysql://user:xxxxx@localhost:3306/database") + require.Contains(t, cfg.appliedEnvOverrides, "GF_DATABASE_URL=mysql://user:xxxxx@localhost:3306/database") }) t.Run("Should get property map from command line args array", func(t *testing.T) { @@ -147,7 +147,7 @@ func TestLoadingSettings(t *testing.T) { Args: []string{ "cfg:default.server.domain=test2", }, - Config: filepath.Join(HomePath, "pkg/setting/testdata/override.ini"), + Config: filepath.Join("../../", "pkg/setting/testdata/override.ini"), }) require.Nil(t, err) @@ -161,7 +161,7 @@ func TestLoadingSettings(t *testing.T) { Args: []string{ "cfg:default.server.min_tls_version=TLS1.3", }, - Config: filepath.Join(HomePath, "pkg/setting/testdata/override.ini"), + Config: filepath.Join("../../", "pkg/setting/testdata/override.ini"), }) require.Nil(t, err) @@ -173,7 +173,7 @@ func TestLoadingSettings(t *testing.T) { cfg := NewCfg() err := cfg.Load(CommandLineArgs{ HomePath: "../../", - Config: filepath.Join(HomePath, "pkg/setting/testdata/override_windows.ini"), + Config: filepath.Join("../../", "pkg/setting/testdata/override_windows.ini"), Args: []string{`cfg:default.paths.data=c:\tmp\data`}, }) require.Nil(t, err) @@ -183,7 +183,7 @@ func TestLoadingSettings(t *testing.T) { cfg := NewCfg() err := cfg.Load(CommandLineArgs{ HomePath: "../../", - Config: filepath.Join(HomePath, "pkg/setting/testdata/override.ini"), + Config: filepath.Join("../../", "pkg/setting/testdata/override.ini"), Args: []string{"cfg:default.paths.data=/tmp/data"}, }) require.Nil(t, err) @@ -197,7 +197,7 @@ func TestLoadingSettings(t *testing.T) { cfg := NewCfg() err := cfg.Load(CommandLineArgs{ HomePath: "../../", - Config: filepath.Join(HomePath, "pkg/setting/testdata/override_windows.ini"), + Config: filepath.Join("../../", "pkg/setting/testdata/override_windows.ini"), Args: []string{`cfg:paths.data=c:\tmp\data`}, }) require.Nil(t, err) @@ -207,7 +207,7 @@ func TestLoadingSettings(t *testing.T) { cfg := NewCfg() err := cfg.Load(CommandLineArgs{ HomePath: "../../", - Config: filepath.Join(HomePath, "pkg/setting/testdata/override.ini"), + Config: filepath.Join("../../", "pkg/setting/testdata/override.ini"), Args: []string{"cfg:paths.data=/tmp/data"}, }) require.Nil(t, err) @@ -249,7 +249,7 @@ func TestLoadingSettings(t *testing.T) { hostname, err := os.Hostname() require.Nil(t, err) - require.Equal(t, hostname, InstanceName) + require.Equal(t, hostname, cfg.InstanceName) }) t.Run("Reading callback_url should add trailing slash", func(t *testing.T) { @@ -275,7 +275,10 @@ func TestLoadingSettings(t *testing.T) { }) t.Run("Test reading string values from .ini file", func(t *testing.T) { - iniFile, err := ini.Load(path.Join(HomePath, "pkg/setting/testdata/invalid.ini")) + cfg := NewCfg() + err := cfg.Load(CommandLineArgs{HomePath: "../../"}) + require.Nil(t, err) + iniFile, err := ini.Load(path.Join(cfg.HomePath, "pkg/setting/testdata/invalid.ini")) require.Nil(t, err) t.Run("If key is found - should return value from ini file", func(t *testing.T) { @@ -474,7 +477,7 @@ func TestAlertingEnabled(t *testing.T) { unifiedAlertingEnabled: "false", isEnterprise: anyBoolean(), verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) { - err := readAlertingSettings(f) + err := cfg.readAlertingSettings(f) require.NoError(t, err) err = cfg.readFeatureToggles(f) require.NoError(t, err) @@ -482,8 +485,8 @@ func TestAlertingEnabled(t *testing.T) { require.NoError(t, err) assert.NotNil(t, cfg.UnifiedAlerting.Enabled) assert.Equal(t, *cfg.UnifiedAlerting.Enabled, false) - assert.NotNil(t, AlertingEnabled) - assert.Equal(t, *AlertingEnabled, true) + assert.NotNil(t, cfg.AlertingEnabled) + assert.Equal(t, *(cfg.AlertingEnabled), true) }, }, { @@ -492,7 +495,7 @@ func TestAlertingEnabled(t *testing.T) { unifiedAlertingEnabled: "true", isEnterprise: anyBoolean(), verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) { - err := readAlertingSettings(f) + err := cfg.readAlertingSettings(f) require.NoError(t, err) err = cfg.readFeatureToggles(f) require.NoError(t, err) @@ -500,8 +503,8 @@ func TestAlertingEnabled(t *testing.T) { require.NoError(t, err) assert.NotNil(t, cfg.UnifiedAlerting.Enabled) assert.Equal(t, *cfg.UnifiedAlerting.Enabled, true) - assert.NotNil(t, AlertingEnabled) - assert.Equal(t, *AlertingEnabled, false) + assert.NotNil(t, cfg.AlertingEnabled) + assert.Equal(t, *(cfg.AlertingEnabled), false) }, }, { @@ -510,7 +513,7 @@ func TestAlertingEnabled(t *testing.T) { unifiedAlertingEnabled: "true", isEnterprise: anyBoolean(), verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) { - err := readAlertingSettings(f) + err := cfg.readAlertingSettings(f) require.NoError(t, err) err = cfg.readFeatureToggles(f) require.NoError(t, err) @@ -524,7 +527,7 @@ func TestAlertingEnabled(t *testing.T) { unifiedAlertingEnabled: "false", isEnterprise: anyBoolean(), verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) { - err := readAlertingSettings(f) + err := cfg.readAlertingSettings(f) require.NoError(t, err) err = cfg.readFeatureToggles(f) require.NoError(t, err) @@ -532,8 +535,8 @@ func TestAlertingEnabled(t *testing.T) { require.NoError(t, err) assert.NotNil(t, cfg.UnifiedAlerting.Enabled) assert.Equal(t, *cfg.UnifiedAlerting.Enabled, false) - assert.NotNil(t, AlertingEnabled) - assert.Equal(t, *AlertingEnabled, true) + assert.NotNil(t, cfg.AlertingEnabled) + assert.Equal(t, *(cfg.AlertingEnabled), true) }, }, { @@ -542,7 +545,7 @@ func TestAlertingEnabled(t *testing.T) { unifiedAlertingEnabled: "true", isEnterprise: anyBoolean(), verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) { - err := readAlertingSettings(f) + err := cfg.readAlertingSettings(f) require.NoError(t, err) err = cfg.readFeatureToggles(f) require.NoError(t, err) @@ -550,8 +553,8 @@ func TestAlertingEnabled(t *testing.T) { require.NoError(t, err) assert.NotNil(t, cfg.UnifiedAlerting.Enabled) assert.Equal(t, *cfg.UnifiedAlerting.Enabled, true) - assert.NotNil(t, AlertingEnabled) - assert.Equal(t, *AlertingEnabled, false) + assert.NotNil(t, cfg.AlertingEnabled) + assert.Equal(t, *(cfg.AlertingEnabled), false) }, }, { @@ -560,7 +563,7 @@ func TestAlertingEnabled(t *testing.T) { unifiedAlertingEnabled: "", isEnterprise: false, verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) { - err := readAlertingSettings(f) + err := cfg.readAlertingSettings(f) require.NoError(t, err) err = cfg.readFeatureToggles(f) require.NoError(t, err) @@ -568,8 +571,8 @@ func TestAlertingEnabled(t *testing.T) { require.NoError(t, err) assert.NotNil(t, cfg.UnifiedAlerting.Enabled) assert.Equal(t, true, *cfg.UnifiedAlerting.Enabled) - assert.NotNil(t, AlertingEnabled) - assert.Equal(t, false, *AlertingEnabled) + assert.NotNil(t, cfg.AlertingEnabled) + assert.Equal(t, false, *(cfg.AlertingEnabled)) }, }, { @@ -578,15 +581,15 @@ func TestAlertingEnabled(t *testing.T) { unifiedAlertingEnabled: "invalid", isEnterprise: false, verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) { - err := readAlertingSettings(f) + err := cfg.readAlertingSettings(f) require.NoError(t, err) err = cfg.readFeatureToggles(f) require.NoError(t, err) err = cfg.ReadUnifiedAlertingSettings(f) assert.EqualError(t, err, "failed to read unified alerting enabled setting: invalid value invalid, should be either true or false") assert.Nil(t, cfg.UnifiedAlerting.Enabled) - assert.NotNil(t, AlertingEnabled) - assert.Equal(t, false, *AlertingEnabled) + assert.NotNil(t, cfg.AlertingEnabled) + assert.Equal(t, false, *(cfg.AlertingEnabled)) }, }, { @@ -595,7 +598,7 @@ func TestAlertingEnabled(t *testing.T) { unifiedAlertingEnabled: "", isEnterprise: true, verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) { - err := readAlertingSettings(f) + err := cfg.readAlertingSettings(f) require.NoError(t, err) err = cfg.readFeatureToggles(f) require.NoError(t, err) @@ -603,8 +606,8 @@ func TestAlertingEnabled(t *testing.T) { require.NoError(t, err) assert.NotNil(t, cfg.UnifiedAlerting.Enabled) assert.Equal(t, true, *cfg.UnifiedAlerting.Enabled) - assert.NotNil(t, AlertingEnabled) - assert.Equal(t, false, *AlertingEnabled) + assert.NotNil(t, cfg.AlertingEnabled) + assert.Equal(t, false, *(cfg.AlertingEnabled)) }, }, { @@ -613,15 +616,15 @@ func TestAlertingEnabled(t *testing.T) { unifiedAlertingEnabled: "invalid", isEnterprise: false, verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) { - err := readAlertingSettings(f) + err := cfg.readAlertingSettings(f) require.NoError(t, err) err = cfg.readFeatureToggles(f) require.NoError(t, err) err = cfg.ReadUnifiedAlertingSettings(f) assert.EqualError(t, err, "failed to read unified alerting enabled setting: invalid value invalid, should be either true or false") assert.Nil(t, cfg.UnifiedAlerting.Enabled) - assert.NotNil(t, AlertingEnabled) - assert.Equal(t, false, *AlertingEnabled) + assert.NotNil(t, cfg.AlertingEnabled) + assert.Equal(t, false, *(cfg.AlertingEnabled)) }, }, { @@ -630,7 +633,7 @@ func TestAlertingEnabled(t *testing.T) { unifiedAlertingEnabled: "", isEnterprise: false, verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) { - err := readAlertingSettings(f) + err := cfg.readAlertingSettings(f) require.NoError(t, err) err = cfg.readFeatureToggles(f) require.NoError(t, err) @@ -638,8 +641,8 @@ func TestAlertingEnabled(t *testing.T) { require.NoError(t, err) assert.NotNil(t, cfg.UnifiedAlerting.Enabled) assert.Equal(t, *cfg.UnifiedAlerting.Enabled, true) - assert.NotNil(t, AlertingEnabled) - assert.Equal(t, *AlertingEnabled, false) + assert.NotNil(t, cfg.AlertingEnabled) + assert.Equal(t, *(cfg.AlertingEnabled), false) }, }, { @@ -648,15 +651,15 @@ func TestAlertingEnabled(t *testing.T) { unifiedAlertingEnabled: "invalid", isEnterprise: false, verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) { - err := readAlertingSettings(f) + err := cfg.readAlertingSettings(f) require.NoError(t, err) err = cfg.readFeatureToggles(f) require.NoError(t, err) err = cfg.ReadUnifiedAlertingSettings(f) assert.EqualError(t, err, "failed to read unified alerting enabled setting: invalid value invalid, should be either true or false") assert.Nil(t, cfg.UnifiedAlerting.Enabled) - assert.NotNil(t, AlertingEnabled) - assert.Equal(t, false, *AlertingEnabled) + assert.NotNil(t, cfg.AlertingEnabled) + assert.Equal(t, false, *(cfg.AlertingEnabled)) }, }, { @@ -665,7 +668,7 @@ func TestAlertingEnabled(t *testing.T) { unifiedAlertingEnabled: "", isEnterprise: true, verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) { - err := readAlertingSettings(f) + err := cfg.readAlertingSettings(f) require.NoError(t, err) err = cfg.readFeatureToggles(f) require.NoError(t, err) @@ -673,8 +676,8 @@ func TestAlertingEnabled(t *testing.T) { require.NoError(t, err) assert.NotNil(t, cfg.UnifiedAlerting.Enabled) assert.Equal(t, *cfg.UnifiedAlerting.Enabled, true) - assert.NotNil(t, AlertingEnabled) - assert.Equal(t, *AlertingEnabled, false) + assert.NotNil(t, cfg.AlertingEnabled) + assert.Equal(t, *(cfg.AlertingEnabled), false) }, }, { @@ -683,15 +686,15 @@ func TestAlertingEnabled(t *testing.T) { unifiedAlertingEnabled: "invalid", isEnterprise: false, verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) { - err := readAlertingSettings(f) + err := cfg.readAlertingSettings(f) require.NoError(t, err) err = cfg.readFeatureToggles(f) require.NoError(t, err) err = cfg.ReadUnifiedAlertingSettings(f) assert.EqualError(t, err, "failed to read unified alerting enabled setting: invalid value invalid, should be either true or false") assert.Nil(t, cfg.UnifiedAlerting.Enabled) - assert.NotNil(t, AlertingEnabled) - assert.Equal(t, false, *AlertingEnabled) + assert.NotNil(t, cfg.AlertingEnabled) + assert.Equal(t, false, *(cfg.AlertingEnabled)) }, }, { @@ -700,7 +703,7 @@ func TestAlertingEnabled(t *testing.T) { unifiedAlertingEnabled: "", isEnterprise: false, verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) { - err := readAlertingSettings(f) + err := cfg.readAlertingSettings(f) require.NoError(t, err) err = cfg.readFeatureToggles(f) require.NoError(t, err) @@ -708,7 +711,7 @@ func TestAlertingEnabled(t *testing.T) { require.NoError(t, err) assert.NotNil(t, cfg.UnifiedAlerting.Enabled) assert.True(t, *cfg.UnifiedAlerting.Enabled) - assert.Nil(t, AlertingEnabled) + assert.Nil(t, cfg.AlertingEnabled) }, }, { @@ -717,15 +720,15 @@ func TestAlertingEnabled(t *testing.T) { unifiedAlertingEnabled: "invalid", isEnterprise: false, verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) { - err := readAlertingSettings(f) + err := cfg.readAlertingSettings(f) require.NoError(t, err) err = cfg.readFeatureToggles(f) require.NoError(t, err) err = cfg.ReadUnifiedAlertingSettings(f) assert.EqualError(t, err, "failed to read unified alerting enabled setting: invalid value invalid, should be either true or false") assert.Nil(t, cfg.UnifiedAlerting.Enabled) - assert.NotNil(t, AlertingEnabled) - assert.Equal(t, false, *AlertingEnabled) + assert.NotNil(t, cfg.AlertingEnabled) + assert.Equal(t, false, *(cfg.AlertingEnabled)) }, }, { @@ -734,7 +737,7 @@ func TestAlertingEnabled(t *testing.T) { unifiedAlertingEnabled: "", isEnterprise: true, verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) { - err := readAlertingSettings(f) + err := cfg.readAlertingSettings(f) require.NoError(t, err) err = cfg.readFeatureToggles(f) require.NoError(t, err) @@ -742,7 +745,7 @@ func TestAlertingEnabled(t *testing.T) { require.NoError(t, err) assert.NotNil(t, cfg.UnifiedAlerting.Enabled) assert.True(t, *cfg.UnifiedAlerting.Enabled) - assert.Nil(t, AlertingEnabled) + assert.Nil(t, cfg.AlertingEnabled) }, }, { @@ -751,15 +754,15 @@ func TestAlertingEnabled(t *testing.T) { unifiedAlertingEnabled: "invalid", isEnterprise: false, verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) { - err := readAlertingSettings(f) + err := cfg.readAlertingSettings(f) require.NoError(t, err) err = cfg.readFeatureToggles(f) require.NoError(t, err) err = cfg.ReadUnifiedAlertingSettings(f) assert.EqualError(t, err, "failed to read unified alerting enabled setting: invalid value invalid, should be either true or false") assert.Nil(t, cfg.UnifiedAlerting.Enabled) - assert.NotNil(t, AlertingEnabled) - assert.Equal(t, false, *AlertingEnabled) + assert.NotNil(t, cfg.AlertingEnabled) + assert.Equal(t, false, *(cfg.AlertingEnabled)) }, }, { @@ -768,7 +771,7 @@ func TestAlertingEnabled(t *testing.T) { unifiedAlertingEnabled: "false", isEnterprise: anyBoolean(), verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) { - err := readAlertingSettings(f) + err := cfg.readAlertingSettings(f) require.NoError(t, err) err = cfg.readFeatureToggles(f) require.NoError(t, err) @@ -776,8 +779,8 @@ func TestAlertingEnabled(t *testing.T) { require.NoError(t, err) assert.NotNil(t, cfg.UnifiedAlerting.Enabled) assert.Equal(t, *cfg.UnifiedAlerting.Enabled, false) - assert.NotNil(t, AlertingEnabled) - assert.Equal(t, *AlertingEnabled, false) + assert.NotNil(t, cfg.AlertingEnabled) + assert.Equal(t, *(cfg.AlertingEnabled), false) }, }, } @@ -790,9 +793,6 @@ func TestAlertingEnabled(t *testing.T) { for _, tc := range testCases { t.Run(tc.desc, func(t *testing.T) { IsEnterprise = tc.isEnterprise - t.Cleanup(func() { - AlertingEnabled = nil - }) f := ini.Empty() cfg := NewCfg() @@ -919,3 +919,30 @@ func TestHandleAWSSettings(t *testing.T) { assert.Equal(t, 400, cfg.AWSListMetricsPageLimit) }) } + +const iniString = ` +app_mode = production + +[server] +domain = test.com +` + +func TestNewCfgFromBytes(t *testing.T) { + cfg, err := NewCfgFromBytes([]byte(iniString)) + require.NoError(t, err) + require.NotNil(t, cfg) + require.Equal(t, Prod, cfg.Env) + require.Equal(t, "test.com", cfg.Domain) +} + +func TestNewCfgFromINIFile(t *testing.T) { + parsedFile, err := ini.Load([]byte(iniString)) + require.NoError(t, err) + require.NotNil(t, parsedFile) + + cfg, err := NewCfgFromINIFile(parsedFile) + require.NoError(t, err) + require.NotNil(t, cfg) + require.Equal(t, Prod, cfg.Env) + require.Equal(t, "test.com", cfg.Domain) +} diff --git a/pkg/setting/setting_unified_alerting.go b/pkg/setting/setting_unified_alerting.go index 87c53db0cdb..3657430c89d 100644 --- a/pkg/setting/setting_unified_alerting.go +++ b/pkg/setting/setting_unified_alerting.go @@ -170,20 +170,20 @@ func (cfg *Cfg) readUnifiedAlertingEnabledSetting(section *ini.Section) (*bool, cfg.Logger.Warn("ngalert feature flag is deprecated: use unified alerting enabled setting instead") // feature flag overrides the legacy alerting setting legacyAlerting := false - AlertingEnabled = &legacyAlerting + cfg.AlertingEnabled = &legacyAlerting unifiedAlerting := true return &unifiedAlerting, nil } // if legacy alerting has not been configured then enable unified alerting - if AlertingEnabled == nil { + if cfg.AlertingEnabled == nil { unifiedAlerting := true return &unifiedAlerting, nil } // enable unified alerting and disable legacy alerting legacyAlerting := false - AlertingEnabled = &legacyAlerting + cfg.AlertingEnabled = &legacyAlerting unifiedAlerting := true return &unifiedAlerting, nil } @@ -192,18 +192,18 @@ func (cfg *Cfg) readUnifiedAlertingEnabledSetting(section *ini.Section) (*bool, if err != nil { // the value for unified alerting is invalid so disable all alerting legacyAlerting := false - AlertingEnabled = &legacyAlerting + cfg.AlertingEnabled = &legacyAlerting return nil, fmt.Errorf("invalid value %s, should be either true or false", section.Key("enabled")) } // If both legacy and unified alerting are enabled then return an error - if AlertingEnabled != nil && *AlertingEnabled && unifiedAlerting { + if cfg.AlertingEnabled != nil && *(cfg.AlertingEnabled) && unifiedAlerting { return nil, errors.New("legacy and unified alerting cannot both be enabled at the same time, please disable one of them and restart Grafana") } - if AlertingEnabled == nil { + if cfg.AlertingEnabled == nil { legacyAlerting := !unifiedAlerting - AlertingEnabled = &legacyAlerting + cfg.AlertingEnabled = &legacyAlerting } return &unifiedAlerting, nil