From 47f13abf7ad0e5c50cdeea4b76e6bb91f65afc98 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Wed, 10 Mar 2021 12:41:29 +0100 Subject: [PATCH] Backend: Migrate to using non-global configuration (#31856) Signed-off-by: Arve Knudsen --- pkg/api/api.go | 2 +- pkg/api/avatar/avatar.go | 12 +- pkg/api/health_test.go | 22 +- pkg/api/http_server.go | 52 ++--- pkg/api/index.go | 74 +++---- pkg/api/login.go | 16 +- pkg/api/plugins.go | 3 +- pkg/api/user.go | 2 +- pkg/middleware/recovery.go | 2 +- pkg/plugins/app_plugin.go | 13 +- pkg/plugins/frontend_plugin.go | 18 +- pkg/plugins/frontend_plugin_test.go | 3 +- pkg/plugins/manager/manager.go | 8 +- pkg/plugins/manager/manager_test.go | 190 ++++++++---------- pkg/services/notifications/notifications.go | 2 +- .../notifications/notifications_test.go | 43 ++-- pkg/services/rendering/rendering.go | 6 +- pkg/services/rendering/rendering_test.go | 2 +- pkg/setting/setting.go | 31 +-- 19 files changed, 241 insertions(+), 260 deletions(-) diff --git a/pkg/api/api.go b/pkg/api/api.go index 2fdd9cb968a..cff827fe263 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -435,7 +435,7 @@ func (hs *HTTPServer) registerRoutes() { r.Any("/api/gnet/*", reqSignedIn, ProxyGnetRequest) // Gravatar service. - avatarCacheServer := avatar.NewCacheServer() + avatarCacheServer := avatar.NewCacheServer(hs.Cfg) r.Get("/avatar/:hash", avatarCacheServer.Handler) // Snapshots diff --git a/pkg/api/avatar/avatar.go b/pkg/api/avatar/avatar.go index b633a2f9100..2c3952684c0 100644 --- a/pkg/api/avatar/avatar.go +++ b/pkg/api/avatar/avatar.go @@ -69,6 +69,7 @@ func (a *Avatar) Update() (err error) { } type CacheServer struct { + cfg *setting.Cfg notFound *Avatar cache *gocache.Cache } @@ -109,7 +110,7 @@ func (a *CacheServer) Handler(ctx *models.ReqContext) { ctx.Resp.Header().Set("Content-Type", "image/jpeg") - if !setting.EnableGzip { + if !a.cfg.EnableGzip { ctx.Resp.Header().Set("Content-Length", strconv.Itoa(len(avatar.data.Bytes()))) } @@ -121,21 +122,22 @@ func (a *CacheServer) Handler(ctx *models.ReqContext) { } } -func NewCacheServer() *CacheServer { +func NewCacheServer(cfg *setting.Cfg) *CacheServer { return &CacheServer{ - notFound: newNotFound(), + cfg: cfg, + notFound: newNotFound(cfg), cache: gocache.New(time.Hour, time.Hour*2), } } -func newNotFound() *Avatar { +func newNotFound(cfg *setting.Cfg) *Avatar { avatar := &Avatar{notFound: true} // load user_profile png into buffer // It's safe to ignore gosec warning G304 since the variable part of the file path comes from a configuration // variable. // nolint:gosec - path := filepath.Join(setting.StaticRootPath, "img", "user_profile.png") + path := filepath.Join(cfg.StaticRootPath, "img", "user_profile.png") // It's safe to ignore gosec warning G304 since the variable part of the file path comes from a configuration // variable. // nolint:gosec diff --git a/pkg/api/health_test.go b/pkg/api/health_test.go index 0c937dbdf81..b6f90691928 100644 --- a/pkg/api/health_test.go +++ b/pkg/api/health_test.go @@ -16,9 +16,10 @@ import ( ) func TestHealthAPI_Version(t *testing.T) { - m, _ := setupHealthAPITestEnvironment(t) - setting.BuildVersion = "7.4.0" - setting.BuildCommit = "59906ab1bf" + m, _ := setupHealthAPITestEnvironment(t, func(cfg *setting.Cfg) { + cfg.BuildVersion = "7.4.0" + cfg.BuildCommit = "59906ab1bf" + }) bus.AddHandler("test", func(query *models.GetDBHealthQuery) error { return nil @@ -166,23 +167,20 @@ func TestHealthAPI_DatabaseHealthCached(t *testing.T) { require.True(t, healthy.(bool)) } -func setupHealthAPITestEnvironment(t *testing.T) (*macaron.Macaron, *HTTPServer) { +func setupHealthAPITestEnvironment(t *testing.T, cbs ...func(*setting.Cfg)) (*macaron.Macaron, *HTTPServer) { t.Helper() - oldVersion := setting.BuildVersion - oldCommit := setting.BuildCommit - t.Cleanup(func() { - setting.BuildVersion = oldVersion - setting.BuildCommit = oldCommit - }) - bus.ClearBusHandlers() t.Cleanup(bus.ClearBusHandlers) m := macaron.New() + cfg := setting.NewCfg() + for _, cb := range cbs { + cb(cfg) + } hs := &HTTPServer{ CacheService: localcache.New(5*time.Minute, 10*time.Minute), - Cfg: setting.NewCfg(), + Cfg: cfg, } m.Get("/api/health", hs.apiHealthHandler) diff --git a/pkg/api/http_server.go b/pkg/api/http_server.go index feedf8ff70b..436159a429a 100644 --- a/pkg/api/http_server.go +++ b/pkg/api/http_server.go @@ -111,9 +111,9 @@ func (hs *HTTPServer) Run(ctx context.Context) error { hs.applyRoutes() // Remove any square brackets enclosing IPv6 addresses, a format we support for backwards compatibility - host := strings.TrimSuffix(strings.TrimPrefix(setting.HttpAddr, "["), "]") + host := strings.TrimSuffix(strings.TrimPrefix(hs.Cfg.HTTPAddr, "["), "]") hs.httpSrv = &http.Server{ - Addr: net.JoinHostPort(host, setting.HttpPort), + Addr: net.JoinHostPort(host, hs.Cfg.HTTPPort), Handler: hs.macaron, } switch hs.Cfg.Protocol { @@ -159,7 +159,7 @@ func (hs *HTTPServer) Run(ctx context.Context) error { return err } case setting.HTTP2Scheme, setting.HTTPSScheme: - if err := hs.httpSrv.ServeTLS(listener, setting.CertFile, setting.KeyFile); err != nil { + if err := hs.httpSrv.ServeTLS(listener, hs.Cfg.CertFile, hs.Cfg.KeyFile); err != nil { if errors.Is(err, http.ErrServerClosed) { hs.log.Debug("server was shutdown gracefully") return nil @@ -207,20 +207,20 @@ func (hs *HTTPServer) getListener() (net.Listener, error) { } func (hs *HTTPServer) configureHttps() error { - if setting.CertFile == "" { + if hs.Cfg.CertFile == "" { return fmt.Errorf("cert_file cannot be empty when using HTTPS") } - if setting.KeyFile == "" { + if hs.Cfg.KeyFile == "" { return fmt.Errorf("cert_key cannot be empty when using HTTPS") } - if _, err := os.Stat(setting.CertFile); os.IsNotExist(err) { - return fmt.Errorf(`cannot find SSL cert_file at %q`, setting.CertFile) + if _, err := os.Stat(hs.Cfg.CertFile); os.IsNotExist(err) { + return fmt.Errorf(`cannot find SSL cert_file at %q`, hs.Cfg.CertFile) } - if _, err := os.Stat(setting.KeyFile); os.IsNotExist(err) { - return fmt.Errorf(`cannot find SSL key_file at %q`, setting.KeyFile) + if _, err := os.Stat(hs.Cfg.KeyFile); os.IsNotExist(err) { + return fmt.Errorf(`cannot find SSL key_file at %q`, hs.Cfg.KeyFile) } tlsCfg := &tls.Config{ @@ -248,20 +248,20 @@ func (hs *HTTPServer) configureHttps() error { } func (hs *HTTPServer) configureHttp2() error { - if setting.CertFile == "" { + if hs.Cfg.CertFile == "" { return fmt.Errorf("cert_file cannot be empty when using HTTP2") } - if setting.KeyFile == "" { + if hs.Cfg.KeyFile == "" { return fmt.Errorf("cert_key cannot be empty when using HTTP2") } - if _, err := os.Stat(setting.CertFile); os.IsNotExist(err) { - return fmt.Errorf(`cannot find SSL cert_file at %q`, setting.CertFile) + if _, err := os.Stat(hs.Cfg.CertFile); os.IsNotExist(err) { + return fmt.Errorf(`cannot find SSL cert_file at %q`, hs.Cfg.CertFile) } - if _, err := os.Stat(setting.KeyFile); os.IsNotExist(err) { - return fmt.Errorf(`cannot find SSL key_file at %q`, setting.KeyFile) + if _, err := os.Stat(hs.Cfg.KeyFile); os.IsNotExist(err) { + return fmt.Errorf(`cannot find SSL key_file at %q`, hs.Cfg.KeyFile) } tlsCfg := &tls.Config{ @@ -312,7 +312,7 @@ func (hs *HTTPServer) addMiddlewaresAndStaticRoutes() { m.Use(middleware.Logger(hs.Cfg)) - if setting.EnableGzip { + if hs.Cfg.EnableGzip { m.Use(middleware.Gziper()) } @@ -324,22 +324,22 @@ func (hs *HTTPServer) addMiddlewaresAndStaticRoutes() { hs.mapStatic(m, route.Directory, "", pluginRoute) } - hs.mapStatic(m, setting.StaticRootPath, "build", "public/build") - hs.mapStatic(m, setting.StaticRootPath, "", "public") - hs.mapStatic(m, setting.StaticRootPath, "robots.txt", "robots.txt") + hs.mapStatic(m, hs.Cfg.StaticRootPath, "build", "public/build") + hs.mapStatic(m, hs.Cfg.StaticRootPath, "", "public") + hs.mapStatic(m, hs.Cfg.StaticRootPath, "robots.txt", "robots.txt") - if setting.ImageUploadProvider == "local" { + if hs.Cfg.ImageUploadProvider == "local" { hs.mapStatic(m, hs.Cfg.ImagesDir, "", "/public/img/attachments") } m.Use(middleware.AddDefaultResponseHeaders(hs.Cfg)) - if setting.ServeFromSubPath && setting.AppSubUrl != "" { - m.SetURLPrefix(setting.AppSubUrl) + if hs.Cfg.ServeFromSubPath && hs.Cfg.AppSubURL != "" { + m.SetURLPrefix(hs.Cfg.AppSubURL) } m.Use(macaron.Renderer(macaron.RenderOptions{ - Directory: filepath.Join(setting.StaticRootPath, "views"), + Directory: filepath.Join(hs.Cfg.StaticRootPath, "views"), IndentJSON: macaron.Env != macaron.PROD, Delims: macaron.Delims{Left: "[[", Right: "]]"}, })) @@ -354,7 +354,7 @@ func (hs *HTTPServer) addMiddlewaresAndStaticRoutes() { m.Use(middleware.OrgRedirect(hs.Cfg)) // needs to be after context handler - if setting.EnforceDomain { + if hs.Cfg.EnforceDomain { m.Use(middleware.ValidateHostHeader(hs.Cfg)) } @@ -411,8 +411,8 @@ func (hs *HTTPServer) apiHealthHandler(ctx *macaron.Context) { data := simplejson.New() data.Set("database", "ok") if !hs.Cfg.AnonymousHideVersion { - data.Set("version", setting.BuildVersion) - data.Set("commit", setting.BuildCommit) + data.Set("version", hs.Cfg.BuildVersion) + data.Set("commit", hs.Cfg.BuildCommit) } if !hs.databaseHealthy() { diff --git a/pkg/api/index.go b/pkg/api/index.go index 80f4804954d..e97b6e075ab 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -17,7 +17,7 @@ const ( darkName = "dark" ) -func getProfileNode(c *models.ReqContext) *dtos.NavLink { +func (hs *HTTPServer) getProfileNode(c *models.ReqContext) *dtos.NavLink { // Only set login if it's different from the name var login string if c.SignedInUser.Login != c.SignedInUser.NameOrFallback() { @@ -27,13 +27,13 @@ func getProfileNode(c *models.ReqContext) *dtos.NavLink { children := []*dtos.NavLink{ { - Text: "Preferences", Id: "profile-settings", Url: setting.AppSubUrl + "/profile", Icon: "sliders-v-alt", + Text: "Preferences", Id: "profile-settings", Url: hs.Cfg.AppSubURL + "/profile", Icon: "sliders-v-alt", }, } if setting.AddChangePasswordLink() { children = append(children, &dtos.NavLink{ - Text: "Change Password", Id: "change-password", Url: setting.AppSubUrl + "/profile/password", + Text: "Change Password", Id: "change-password", Url: hs.Cfg.AppSubURL + "/profile/password", Icon: "lock", HideFromMenu: true, }) } @@ -43,7 +43,7 @@ func getProfileNode(c *models.ReqContext) *dtos.NavLink { children = append(children, &dtos.NavLink{ Text: "Sign out", Id: "sign-out", - Url: setting.AppSubUrl + "/logout", + Url: hs.Cfg.AppSubURL + "/logout", Icon: "arrow-from-right", Target: "_self", HideFromTabs: true, @@ -55,7 +55,7 @@ func getProfileNode(c *models.ReqContext) *dtos.NavLink { SubTitle: login, Id: "profile", Img: gravatarURL, - Url: setting.AppSubUrl + "/profile", + Url: hs.Cfg.AppSubURL + "/profile", HideFromMenu: true, SortWeight: dtos.WeightProfile, Children: children, @@ -91,7 +91,7 @@ func (hs *HTTPServer) getAppLinks(c *models.ReqContext) ([]*dtos.NavLink, error) var link *dtos.NavLink if len(include.Path) > 0 { link = &dtos.NavLink{ - Url: setting.AppSubUrl + include.Path, + Url: hs.Cfg.AppSubURL + include.Path, Text: include.Name, } if include.DefaultNav { @@ -99,7 +99,7 @@ func (hs *HTTPServer) getAppLinks(c *models.ReqContext) ([]*dtos.NavLink, error) } } else { link = &dtos.NavLink{ - Url: setting.AppSubUrl + "/plugins/" + plugin.Id + "/page/" + include.Slug, + Url: hs.Cfg.AppSubURL + "/plugins/" + plugin.Id + "/page/" + include.Slug, Text: include.Name, } } @@ -109,7 +109,7 @@ func (hs *HTTPServer) getAppLinks(c *models.ReqContext) ([]*dtos.NavLink, error) if include.Type == "dashboard" && include.AddToNav { link := &dtos.NavLink{ - Url: setting.AppSubUrl + "/dashboard/db/" + include.Slug, + Url: hs.Cfg.AppSubURL + "/dashboard/db/" + include.Slug, Text: include.Name, } appLink.Children = append(appLink.Children, link) @@ -129,40 +129,40 @@ func (hs *HTTPServer) getNavTree(c *models.ReqContext, hasEditPerm bool) ([]*dto if hasEditPerm { children := []*dtos.NavLink{ - {Text: "Dashboard", Icon: "apps", Url: setting.AppSubUrl + "/dashboard/new"}, + {Text: "Dashboard", Icon: "apps", Url: hs.Cfg.AppSubURL + "/dashboard/new"}, } if c.OrgRole == models.ROLE_ADMIN || c.OrgRole == models.ROLE_EDITOR { children = append(children, &dtos.NavLink{ Text: "Folder", SubTitle: "Create a new folder to organize your dashboards", Id: "folder", - Icon: "folder-plus", Url: setting.AppSubUrl + "/dashboards/folder/new", + Icon: "folder-plus", Url: hs.Cfg.AppSubURL + "/dashboards/folder/new", }) } children = append(children, &dtos.NavLink{ Text: "Import", SubTitle: "Import dashboard from file or Grafana.com", Id: "import", Icon: "import", - Url: setting.AppSubUrl + "/dashboard/import", + Url: hs.Cfg.AppSubURL + "/dashboard/import", }) navTree = append(navTree, &dtos.NavLink{ Text: "Create", Id: "create", Icon: "plus", - Url: setting.AppSubUrl + "/dashboard/new", + Url: hs.Cfg.AppSubURL + "/dashboard/new", Children: children, SortWeight: dtos.WeightCreate, }) } dashboardChildNavs := []*dtos.NavLink{ - {Text: "Home", Id: "home", Url: setting.AppSubUrl + "/", Icon: "home-alt", HideFromTabs: true}, + {Text: "Home", Id: "home", Url: hs.Cfg.AppSubURL + "/", Icon: "home-alt", HideFromTabs: true}, {Text: "Divider", Divider: true, Id: "divider", HideFromTabs: true}, - {Text: "Manage", Id: "manage-dashboards", Url: setting.AppSubUrl + "/dashboards", Icon: "sitemap"}, - {Text: "Playlists", Id: "playlists", Url: setting.AppSubUrl + "/playlists", Icon: "presentation-play"}, + {Text: "Manage", Id: "manage-dashboards", Url: hs.Cfg.AppSubURL + "/dashboards", Icon: "sitemap"}, + {Text: "Playlists", Id: "playlists", Url: hs.Cfg.AppSubURL + "/playlists", Icon: "presentation-play"}, } if c.IsSignedIn { dashboardChildNavs = append(dashboardChildNavs, &dtos.NavLink{ Text: "Snapshots", Id: "snapshots", - Url: setting.AppSubUrl + "/dashboard/snapshots", + Url: hs.Cfg.AppSubURL + "/dashboard/snapshots", Icon: "camera", }) } @@ -172,7 +172,7 @@ func (hs *HTTPServer) getNavTree(c *models.ReqContext, hasEditPerm bool) ([]*dto Id: "dashboards", SubTitle: "Manage dashboards & folders", Icon: "apps", - Url: setting.AppSubUrl + "/", + Url: hs.Cfg.AppSubURL + "/", SortWeight: dtos.WeightDashboard, Children: dashboardChildNavs, }) @@ -184,19 +184,19 @@ func (hs *HTTPServer) getNavTree(c *models.ReqContext, hasEditPerm bool) ([]*dto SubTitle: "Explore your data", Icon: "compass", SortWeight: dtos.WeightExplore, - Url: setting.AppSubUrl + "/explore", + Url: hs.Cfg.AppSubURL + "/explore", }) } if c.IsSignedIn { - navTree = append(navTree, getProfileNode(c)) + navTree = append(navTree, hs.getProfileNode(c)) } if setting.AlertingEnabled && (c.OrgRole == models.ROLE_ADMIN || c.OrgRole == models.ROLE_EDITOR) { alertChildNavs := []*dtos.NavLink{ - {Text: "Alert Rules", Id: "alert-list", Url: setting.AppSubUrl + "/alerting/list", Icon: "list-ul"}, + {Text: "Alert Rules", Id: "alert-list", Url: hs.Cfg.AppSubURL + "/alerting/list", Icon: "list-ul"}, { - Text: "Notification channels", Id: "channels", Url: setting.AppSubUrl + "/alerting/notifications", + Text: "Notification channels", Id: "channels", Url: hs.Cfg.AppSubURL + "/alerting/notifications", Icon: "comment-alt-share", }, } @@ -206,7 +206,7 @@ func (hs *HTTPServer) getNavTree(c *models.ReqContext, hasEditPerm bool) ([]*dto SubTitle: "Alert rules & notifications", Id: "alerting", Icon: "bell", - Url: setting.AppSubUrl + "/alerting/list", + Url: hs.Cfg.AppSubURL + "/alerting/list", Children: alertChildNavs, SortWeight: dtos.WeightAlerting, }) @@ -226,14 +226,14 @@ func (hs *HTTPServer) getNavTree(c *models.ReqContext, hasEditPerm bool) ([]*dto Icon: "database", Description: "Add and configure data sources", Id: "datasources", - Url: setting.AppSubUrl + "/datasources", + Url: hs.Cfg.AppSubURL + "/datasources", }) configNodes = append(configNodes, &dtos.NavLink{ Text: "Users", Id: "users", Description: "Manage org members", Icon: "user", - Url: setting.AppSubUrl + "/org/users", + Url: hs.Cfg.AppSubURL + "/org/users", }) } @@ -243,7 +243,7 @@ func (hs *HTTPServer) getNavTree(c *models.ReqContext, hasEditPerm bool) ([]*dto Id: "teams", Description: "Manage org groups", Icon: "users-alt", - Url: setting.AppSubUrl + "/org/teams", + Url: hs.Cfg.AppSubURL + "/org/teams", }) } @@ -253,7 +253,7 @@ func (hs *HTTPServer) getNavTree(c *models.ReqContext, hasEditPerm bool) ([]*dto Id: "plugins", Description: "View and configure plugins", Icon: "plug", - Url: setting.AppSubUrl + "/plugins", + Url: hs.Cfg.AppSubURL + "/plugins", }) configNodes = append(configNodes, &dtos.NavLink{ @@ -261,14 +261,14 @@ func (hs *HTTPServer) getNavTree(c *models.ReqContext, hasEditPerm bool) ([]*dto Id: "org-settings", Description: "Organization preferences", Icon: "sliders-v-alt", - Url: setting.AppSubUrl + "/org", + Url: hs.Cfg.AppSubURL + "/org", }) configNodes = append(configNodes, &dtos.NavLink{ Text: "API Keys", Id: "apikeys", Description: "Create & manage API keys", Icon: "key-skeleton-alt", - Url: setting.AppSubUrl + "/org/apikeys", + Url: hs.Cfg.AppSubURL + "/org/apikeys", }) } @@ -286,15 +286,15 @@ func (hs *HTTPServer) getNavTree(c *models.ReqContext, hasEditPerm bool) ([]*dto if c.IsGrafanaAdmin { adminNavLinks := []*dtos.NavLink{ - {Text: "Users", Id: "global-users", Url: setting.AppSubUrl + "/admin/users", Icon: "user"}, - {Text: "Orgs", Id: "global-orgs", Url: setting.AppSubUrl + "/admin/orgs", Icon: "building"}, - {Text: "Settings", Id: "server-settings", Url: setting.AppSubUrl + "/admin/settings", Icon: "sliders-v-alt"}, - {Text: "Stats", Id: "server-stats", Url: setting.AppSubUrl + "/admin/stats", Icon: "graph-bar"}, + {Text: "Users", Id: "global-users", Url: hs.Cfg.AppSubURL + "/admin/users", Icon: "user"}, + {Text: "Orgs", Id: "global-orgs", Url: hs.Cfg.AppSubURL + "/admin/orgs", Icon: "building"}, + {Text: "Settings", Id: "server-settings", Url: hs.Cfg.AppSubURL + "/admin/settings", Icon: "sliders-v-alt"}, + {Text: "Stats", Id: "server-stats", Url: hs.Cfg.AppSubURL + "/admin/stats", Icon: "graph-bar"}, } if hs.Cfg.LDAPEnabled { adminNavLinks = append(adminNavLinks, &dtos.NavLink{ - Text: "LDAP", Id: "ldap", Url: setting.AppSubUrl + "/admin/ldap", Icon: "book", + Text: "LDAP", Id: "ldap", Url: hs.Cfg.AppSubURL + "/admin/ldap", Icon: "book", }) } @@ -304,7 +304,7 @@ func (hs *HTTPServer) getNavTree(c *models.ReqContext, hasEditPerm bool) ([]*dto HideFromTabs: true, Id: "admin", Icon: "shield", - Url: setting.AppSubUrl + "/admin/users", + Url: hs.Cfg.AppSubURL + "/admin/users", SortWeight: dtos.WeightAdmin, Children: adminNavLinks, }) @@ -359,11 +359,11 @@ func (hs *HTTPServer) setIndexViewData(c *models.ReqContext) (*dtos.IndexViewDat } appURL := setting.AppUrl - appSubURL := setting.AppSubUrl + appSubURL := hs.Cfg.AppSubURL // special case when doing localhost call from image renderer if c.IsRenderCall && !hs.Cfg.ServeFromSubPath { - appURL = fmt.Sprintf("%s://localhost:%s", hs.Cfg.Protocol, setting.HttpPort) + appURL = fmt.Sprintf("%s://localhost:%s", hs.Cfg.Protocol, hs.Cfg.HTTPPort) appSubURL = "" settings["appSubUrl"] = "" } @@ -414,7 +414,7 @@ func (hs *HTTPServer) setIndexViewData(c *models.ReqContext) (*dtos.IndexViewDat } if setting.DisableGravatar { - data.User.GravatarUrl = setting.AppSubUrl + "/public/img/user_profile.png" + data.User.GravatarUrl = hs.Cfg.AppSubURL + "/public/img/user_profile.png" } if len(data.User.Name) == 0 { diff --git a/pkg/api/login.go b/pkg/api/login.go index 50cdeaefb22..efd1696c107 100644 --- a/pkg/api/login.go +++ b/pkg/api/login.go @@ -109,7 +109,7 @@ func (hs *HTTPServer) LoginView(c *models.ReqContext) { return } - if tryOAuthAutoLogin(c) { + if hs.tryOAuthAutoLogin(c) { return } @@ -136,14 +136,14 @@ func (hs *HTTPServer) LoginView(c *models.ReqContext) { return } - c.Redirect(setting.AppSubUrl + "/") + c.Redirect(hs.Cfg.AppSubURL + "/") return } c.HTML(200, getViewIndex(), viewData) } -func tryOAuthAutoLogin(c *models.ReqContext) bool { +func (hs *HTTPServer) tryOAuthAutoLogin(c *models.ReqContext) bool { if !setting.OAuthAutoLogin { return false } @@ -153,7 +153,7 @@ func tryOAuthAutoLogin(c *models.ReqContext) bool { return false } for key := range setting.OAuthService.OAuthInfos { - redirectUrl := setting.AppSubUrl + "/login/" + key + redirectUrl := hs.Cfg.AppSubURL + "/login/" + key log.Infof("OAuth auto login enabled. Redirecting to " + redirectUrl) c.Redirect(redirectUrl, 307) return true @@ -279,7 +279,7 @@ func (hs *HTTPServer) loginUserWithUser(user *models.User, c *models.ReqContext) func (hs *HTTPServer) Logout(c *models.ReqContext) { if hs.Cfg.SAMLEnabled && hs.Cfg.SAMLSingleLogoutEnabled && hs.License.HasValidLicense() { - c.Redirect(setting.AppSubUrl + "/logout/saml") + c.Redirect(hs.Cfg.AppSubURL + "/logout/saml") return } @@ -294,7 +294,7 @@ func (hs *HTTPServer) Logout(c *models.ReqContext) { c.Redirect(setting.SignoutRedirectUrl) } else { hs.log.Info("Successful Logout", "User", c.Email) - c.Redirect(setting.AppSubUrl + "/login") + c.Redirect(hs.Cfg.AppSubURL + "/login") } } @@ -330,7 +330,7 @@ func (hs *HTTPServer) redirectWithError(ctx *models.ReqContext, err error, v ... hs.log.Error("Failed to set encrypted cookie", "err", err) } - ctx.Redirect(setting.AppSubUrl + "/login") + ctx.Redirect(hs.Cfg.AppSubURL + "/login") } func (hs *HTTPServer) RedirectResponseWithError(ctx *models.ReqContext, err error, v ...interface{}) *response.RedirectResponse { @@ -339,7 +339,7 @@ func (hs *HTTPServer) RedirectResponseWithError(ctx *models.ReqContext, err erro hs.log.Error("Failed to set encrypted cookie", "err", err) } - return response.Redirect(setting.AppSubUrl + "/login") + return response.Redirect(hs.Cfg.AppSubURL + "/login") } func getLoginExternalError(err error) string { diff --git a/pkg/api/plugins.go b/pkg/api/plugins.go index fe93e00c3f0..bf5ef1bb284 100644 --- a/pkg/api/plugins.go +++ b/pkg/api/plugins.go @@ -17,7 +17,6 @@ import ( "github.com/grafana/grafana/pkg/plugins/adapters" "github.com/grafana/grafana/pkg/plugins/backendplugin" "github.com/grafana/grafana/pkg/plugins/manager" - "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util/errutil" ) @@ -122,7 +121,7 @@ func (hs *HTTPServer) GetPluginList(c *models.ReqContext) response.Response { } if listItem.DefaultNavUrl == "" || !listItem.Enabled { - listItem.DefaultNavUrl = setting.AppSubUrl + "/plugins/" + listItem.Id + "/" + listItem.DefaultNavUrl = hs.Cfg.AppSubURL + "/plugins/" + listItem.Id + "/" } // filter out disabled plugins diff --git a/pkg/api/user.go b/pkg/api/user.go index 7f3aa1fdc7c..8b01f67b27e 100644 --- a/pkg/api/user.go +++ b/pkg/api/user.go @@ -213,7 +213,7 @@ func (hs *HTTPServer) ChangeActiveOrgAndRedirectToHome(c *models.ReqContext) { hs.NotFoundHandler(c) } - c.Redirect(setting.AppSubUrl + "/") + c.Redirect(hs.Cfg.AppSubURL + "/") } func ChangeUserPassword(c *models.ReqContext, cmd models.ChangeUserPasswordCommand) response.Response { diff --git a/pkg/middleware/recovery.go b/pkg/middleware/recovery.go index 5f564135826..336a3425da9 100644 --- a/pkg/middleware/recovery.go +++ b/pkg/middleware/recovery.go @@ -133,7 +133,7 @@ func Recovery(cfg *setting.Cfg) macaron.Handler { } c.Data["Title"] = "Server Error" - c.Data["AppSubUrl"] = setting.AppSubUrl + c.Data["AppSubUrl"] = cfg.AppSubURL c.Data["Theme"] = cfg.DefaultTheme if setting.Env == setting.Dev { diff --git a/pkg/plugins/app_plugin.go b/pkg/plugins/app_plugin.go index 1cbc003378d..5c159b0577b 100644 --- a/pkg/plugins/app_plugin.go +++ b/pkg/plugins/app_plugin.go @@ -77,13 +77,14 @@ func (app *AppPlugin) Load(decoder *json.Decoder, base *PluginBase, backendPlugi return app, nil } -func (app *AppPlugin) InitApp(panels map[string]*PanelPlugin, dataSources map[string]*DataSourcePlugin) []*PluginStaticRoute { - staticRoutes := app.InitFrontendPlugin() +func (app *AppPlugin) InitApp(panels map[string]*PanelPlugin, dataSources map[string]*DataSourcePlugin, + cfg *setting.Cfg) []*PluginStaticRoute { + staticRoutes := app.InitFrontendPlugin(cfg) // check if we have child panels for _, panel := range panels { if strings.HasPrefix(panel.PluginDir, app.PluginDir) { - panel.setPathsBasedOnApp(app) + panel.setPathsBasedOnApp(app, cfg) app.FoundChildPlugins = append(app.FoundChildPlugins, &PluginInclude{ Name: panel.Name, Id: panel.Id, @@ -95,7 +96,7 @@ func (app *AppPlugin) InitApp(panels map[string]*PanelPlugin, dataSources map[st // check if we have child datasources for _, ds := range dataSources { if strings.HasPrefix(ds.PluginDir, app.PluginDir) { - ds.setPathsBasedOnApp(app) + ds.setPathsBasedOnApp(app, cfg) app.FoundChildPlugins = append(app.FoundChildPlugins, &PluginInclude{ Name: ds.Name, Id: ds.Id, @@ -110,10 +111,10 @@ func (app *AppPlugin) InitApp(panels map[string]*PanelPlugin, dataSources map[st include.Slug = slug.Make(include.Name) } if include.Type == "page" && include.DefaultNav { - app.DefaultNavUrl = setting.AppSubUrl + "/plugins/" + app.Id + "/page/" + include.Slug + app.DefaultNavUrl = cfg.AppSubURL + "/plugins/" + app.Id + "/page/" + include.Slug } if include.Type == "dashboard" && include.DefaultNav { - app.DefaultNavUrl = setting.AppSubUrl + "/dashboard/db/" + include.Slug + app.DefaultNavUrl = cfg.AppSubURL + "/dashboard/db/" + include.Slug } } diff --git a/pkg/plugins/frontend_plugin.go b/pkg/plugins/frontend_plugin.go index 49b52d2115c..0de13b9e81c 100644 --- a/pkg/plugins/frontend_plugin.go +++ b/pkg/plugins/frontend_plugin.go @@ -14,9 +14,9 @@ type FrontendPluginBase struct { PluginBase } -func (fp *FrontendPluginBase) InitFrontendPlugin() []*PluginStaticRoute { +func (fp *FrontendPluginBase) InitFrontendPlugin(cfg *setting.Cfg) []*PluginStaticRoute { var staticRoutes []*PluginStaticRoute - if isExternalPlugin(fp.PluginDir) { + if isExternalPlugin(fp.PluginDir, cfg) { staticRoutes = []*PluginStaticRoute{ { Directory: fp.PluginDir, @@ -25,7 +25,7 @@ func (fp *FrontendPluginBase) InitFrontendPlugin() []*PluginStaticRoute { } } - fp.handleModuleDefaults() + fp.handleModuleDefaults(cfg) fp.Info.Logos.Small = getPluginLogoUrl(fp.Type, fp.Info.Logos.Small, fp.BaseUrl) fp.Info.Logos.Large = getPluginLogoUrl(fp.Type, fp.Info.Logos.Large, fp.BaseUrl) @@ -45,20 +45,20 @@ func getPluginLogoUrl(pluginType, path, baseUrl string) string { return evalRelativePluginUrlPath(path, baseUrl) } -func (fp *FrontendPluginBase) setPathsBasedOnApp(app *AppPlugin) { +func (fp *FrontendPluginBase) setPathsBasedOnApp(app *AppPlugin, cfg *setting.Cfg) { appSubPath := strings.ReplaceAll(strings.Replace(fp.PluginDir, app.PluginDir, "", 1), "\\", "/") fp.IncludedInAppId = app.Id fp.BaseUrl = app.BaseUrl - if isExternalPlugin(app.PluginDir) { + if isExternalPlugin(app.PluginDir, cfg) { fp.Module = util.JoinURLFragments("plugins/"+app.Id, appSubPath) + "/module" } else { fp.Module = util.JoinURLFragments("app/plugins/app/"+app.Id, appSubPath) + "/module" } } -func (fp *FrontendPluginBase) handleModuleDefaults() { - if isExternalPlugin(fp.PluginDir) { +func (fp *FrontendPluginBase) handleModuleDefaults(cfg *setting.Cfg) { + if isExternalPlugin(fp.PluginDir, cfg) { fp.Module = path.Join("plugins", fp.Id, "module") fp.BaseUrl = path.Join("public/plugins", fp.Id) return @@ -75,8 +75,8 @@ func (fp *FrontendPluginBase) handleModuleDefaults() { fp.BaseUrl = path.Join("public/app/plugins", fp.Type, currentDir) } -func isExternalPlugin(pluginDir string) bool { - return !strings.Contains(pluginDir, setting.StaticRootPath) +func isExternalPlugin(pluginDir string, cfg *setting.Cfg) bool { + return !strings.Contains(pluginDir, cfg.StaticRootPath) } func evalRelativePluginUrlPath(pathStr string, baseUrl string) string { diff --git a/pkg/plugins/frontend_plugin_test.go b/pkg/plugins/frontend_plugin_test.go index 8164a440f7c..ee315af27b3 100644 --- a/pkg/plugins/frontend_plugin_test.go +++ b/pkg/plugins/frontend_plugin_test.go @@ -26,7 +26,8 @@ func TestFrontendPlugin(t *testing.T) { }, }, } - fp.setPathsBasedOnApp(app) + cfg := setting.NewCfg() + fp.setPathsBasedOnApp(app, cfg) So(fp.Module, ShouldEqual, "app/plugins/app/testdata/datasources/datasource/module") }) diff --git a/pkg/plugins/manager/manager.go b/pkg/plugins/manager/manager.go index 06b7ec48503..903c979c3f8 100644 --- a/pkg/plugins/manager/manager.go +++ b/pkg/plugins/manager/manager.go @@ -130,22 +130,22 @@ func (pm *PluginManager) Init() error { } for _, panel := range Panels { - staticRoutes := panel.InitFrontendPlugin() + staticRoutes := panel.InitFrontendPlugin(pm.Cfg) StaticRoutes = append(StaticRoutes, staticRoutes...) } for _, ds := range DataSources { - staticRoutes := ds.InitFrontendPlugin() + staticRoutes := ds.InitFrontendPlugin(pm.Cfg) StaticRoutes = append(StaticRoutes, staticRoutes...) } for _, app := range Apps { - staticRoutes := app.InitApp(Panels, DataSources) + staticRoutes := app.InitApp(Panels, DataSources, pm.Cfg) StaticRoutes = append(StaticRoutes, staticRoutes...) } if Renderer != nil { - staticRoutes := Renderer.InitFrontendPlugin() + staticRoutes := Renderer.InitFrontendPlugin(pm.Cfg) StaticRoutes = append(StaticRoutes, staticRoutes...) } diff --git a/pkg/plugins/manager/manager_test.go b/pkg/plugins/manager/manager_test.go index b142bbb2792..871f98943f9 100644 --- a/pkg/plugins/manager/manager_test.go +++ b/pkg/plugins/manager/manager_test.go @@ -18,34 +18,14 @@ import ( ) func TestPluginManager_Init(t *testing.T) { - staticRootPath, err := filepath.Abs("../../../public/") - require.NoError(t, err) - - origRootPath := setting.StaticRootPath - origRaw := setting.Raw - origEnv := setting.Env - t.Cleanup(func() { - setting.StaticRootPath = origRootPath - setting.Raw = origRaw - setting.Env = origEnv - }) - setting.StaticRootPath = staticRootPath - setting.Raw = ini.Empty() - setting.Env = setting.Prod - t.Run("Base case", func(t *testing.T) { - pm := &PluginManager{ - Cfg: &setting.Cfg{ - Raw: ini.Empty(), - Env: setting.Prod, - StaticRootPath: staticRootPath, - PluginSettings: setting.PluginSettings{ - "nginx-app": map[string]string{ - "path": "testdata/test-app", - }, + pm := createManager(t, func(pm *PluginManager) { + pm.Cfg.PluginSettings = setting.PluginSettings{ + "nginx-app": map[string]string{ + "path": "testdata/test-app", }, - }, - } + } + }) err := pm.Init() require.NoError(t, err) @@ -59,9 +39,9 @@ func TestPluginManager_Init(t *testing.T) { }) t.Run("With external back-end plugin lacking signature", func(t *testing.T) { - pm := &PluginManager{ - Cfg: &setting.Cfg{PluginsPath: "testdata/unsigned"}, - } + pm := createManager(t, func(pm *PluginManager) { + pm.Cfg.PluginsPath = "testdata/unsigned" + }) err := pm.Init() require.NoError(t, err) @@ -69,13 +49,10 @@ func TestPluginManager_Init(t *testing.T) { }) t.Run("With external unsigned back-end plugin and configuration disabling signature check of this plugin", func(t *testing.T) { - pm := &PluginManager{ - Cfg: &setting.Cfg{ - PluginsPath: "testdata/unsigned", - PluginsAllowUnsigned: []string{"test"}, - }, - BackendPluginManager: &fakeBackendPluginManager{}, - } + pm := createManager(t, func(pm *PluginManager) { + pm.Cfg.PluginsPath = "testdata/unsigned" + pm.Cfg.PluginsAllowUnsigned = []string{"test"} + }) err := pm.Init() require.NoError(t, err) @@ -83,11 +60,9 @@ func TestPluginManager_Init(t *testing.T) { }) t.Run("With external back-end plugin with invalid v1 signature", func(t *testing.T) { - pm := &PluginManager{ - Cfg: &setting.Cfg{ - PluginsPath: "testdata/invalid-v1-signature", - }, - } + pm := createManager(t, func(pm *PluginManager) { + pm.Cfg.PluginsPath = "testdata/invalid-v1-signature" + }) err := pm.Init() require.NoError(t, err) @@ -96,12 +71,10 @@ func TestPluginManager_Init(t *testing.T) { t.Run("With external back-end plugin lacking files listed in manifest", func(t *testing.T) { fm := &fakeBackendPluginManager{} - pm := &PluginManager{ - Cfg: &setting.Cfg{ - PluginsPath: "testdata/lacking-files", - }, - BackendPluginManager: fm, - } + pm := createManager(t, func(pm *PluginManager) { + pm.Cfg.PluginsPath = "testdata/lacking-files" + pm.BackendPluginManager = fm + }) err := pm.Init() require.NoError(t, err) @@ -110,12 +83,10 @@ func TestPluginManager_Init(t *testing.T) { t.Run("Transform plugins should be ignored when expressions feature is off", func(t *testing.T) { fm := fakeBackendPluginManager{} - pm := &PluginManager{ - Cfg: &setting.Cfg{ - PluginsPath: "testdata/behind-feature-flag", - }, - BackendPluginManager: &fm, - } + pm := createManager(t, func(pm *PluginManager) { + pm.Cfg.PluginsPath = "testdata/behind-feature-flag" + pm.BackendPluginManager = &fm + }) err := pm.Init() require.NoError(t, err) @@ -124,11 +95,9 @@ func TestPluginManager_Init(t *testing.T) { }) t.Run("With nested plugin duplicating parent", func(t *testing.T) { - pm := &PluginManager{ - Cfg: &setting.Cfg{ - PluginsPath: "testdata/duplicate-plugins", - }, - } + pm := createManager(t, func(pm *PluginManager) { + pm.Cfg.PluginsPath = "testdata/duplicate-plugins" + }) err := pm.Init() require.NoError(t, err) @@ -137,26 +106,23 @@ func TestPluginManager_Init(t *testing.T) { }) t.Run("With external back-end plugin with valid v2 signature", func(t *testing.T) { - pm := &PluginManager{ - Cfg: &setting.Cfg{ - PluginsPath: "testdata/valid-v2-signature", - }, - BackendPluginManager: &fakeBackendPluginManager{}, - } + pm := createManager(t, func(manager *PluginManager) { + manager.Cfg.PluginsPath = "testdata/valid-v2-signature" + }) err := pm.Init() require.NoError(t, err) require.Empty(t, pm.scanningErrors) - pluginId := "test" - assert.NotNil(t, Plugins[pluginId]) - assert.Equal(t, "datasource", Plugins[pluginId].Type) - assert.Equal(t, "Test", Plugins[pluginId].Name) - assert.Equal(t, pluginId, Plugins[pluginId].Id) - assert.Equal(t, "1.0.0", Plugins[pluginId].Info.Version) - assert.Equal(t, plugins.PluginSignatureValid, Plugins[pluginId].Signature) - assert.Equal(t, plugins.GrafanaType, Plugins[pluginId].SignatureType) - assert.Equal(t, "Grafana Labs", Plugins[pluginId].SignatureOrg) - assert.False(t, Plugins[pluginId].IsCorePlugin) + const pluginID = "test" + assert.NotNil(t, Plugins[pluginID]) + assert.Equal(t, "datasource", Plugins[pluginID].Type) + assert.Equal(t, "Test", Plugins[pluginID].Name) + assert.Equal(t, pluginID, Plugins[pluginID].Id) + assert.Equal(t, "1.0.0", Plugins[pluginID].Info.Version) + assert.Equal(t, plugins.PluginSignatureValid, Plugins[pluginID].Signature) + assert.Equal(t, plugins.GrafanaType, Plugins[pluginID].SignatureType) + assert.Equal(t, "Grafana Labs", Plugins[pluginID].SignatureOrg) + assert.False(t, Plugins[pluginID].IsCorePlugin) }) t.Run("With back-end plugin with invalid v2 private signature (mismatched root URL)", func(t *testing.T) { @@ -166,11 +132,9 @@ func TestPluginManager_Init(t *testing.T) { }) setting.AppUrl = "http://localhost:1234" - pm := &PluginManager{ - Cfg: &setting.Cfg{ - PluginsPath: "testdata/valid-v2-pvt-signature", - }, - } + pm := createManager(t, func(pm *PluginManager) { + pm.Cfg.PluginsPath = "testdata/valid-v2-pvt-signature" + }) err := pm.Init() require.NoError(t, err) @@ -185,26 +149,23 @@ func TestPluginManager_Init(t *testing.T) { }) setting.AppUrl = "http://localhost:3000/" - pm := &PluginManager{ - Cfg: &setting.Cfg{ - PluginsPath: "testdata/valid-v2-pvt-signature", - }, - BackendPluginManager: &fakeBackendPluginManager{}, - } + pm := createManager(t, func(pm *PluginManager) { + pm.Cfg.PluginsPath = "testdata/valid-v2-pvt-signature" + }) err := pm.Init() require.NoError(t, err) require.Empty(t, pm.scanningErrors) - pluginId := "test" - assert.NotNil(t, Plugins[pluginId]) - assert.Equal(t, "datasource", Plugins[pluginId].Type) - assert.Equal(t, "Test", Plugins[pluginId].Name) - assert.Equal(t, pluginId, Plugins[pluginId].Id) - assert.Equal(t, "1.0.0", Plugins[pluginId].Info.Version) - assert.Equal(t, plugins.PluginSignatureValid, Plugins[pluginId].Signature) - assert.Equal(t, plugins.PrivateType, Plugins[pluginId].SignatureType) - assert.Equal(t, "Will Browne", Plugins[pluginId].SignatureOrg) - assert.False(t, Plugins[pluginId].IsCorePlugin) + const pluginID = "test" + assert.NotNil(t, Plugins[pluginID]) + assert.Equal(t, "datasource", Plugins[pluginID].Type) + assert.Equal(t, "Test", Plugins[pluginID].Name) + assert.Equal(t, pluginID, Plugins[pluginID].Id) + assert.Equal(t, "1.0.0", Plugins[pluginID].Info.Version) + assert.Equal(t, plugins.PluginSignatureValid, Plugins[pluginID].Signature) + assert.Equal(t, plugins.PrivateType, Plugins[pluginID].SignatureType) + assert.Equal(t, "Will Browne", Plugins[pluginID].SignatureOrg) + assert.False(t, Plugins[pluginID].IsCorePlugin) }) t.Run("With back-end plugin with modified v2 signature (missing file from plugin dir)", func(t *testing.T) { @@ -214,12 +175,9 @@ func TestPluginManager_Init(t *testing.T) { }) setting.AppUrl = "http://localhost:3000/" - pm := &PluginManager{ - Cfg: &setting.Cfg{ - PluginsPath: "testdata/invalid-v2-signature", - }, - BackendPluginManager: &fakeBackendPluginManager{}, - } + pm := createManager(t, func(pm *PluginManager) { + pm.Cfg.PluginsPath = "testdata/invalid-v2-signature" + }) err := pm.Init() require.NoError(t, err) assert.Equal(t, []error{fmt.Errorf(`plugin "test"'s signature has been modified`)}, pm.scanningErrors) @@ -233,12 +191,9 @@ func TestPluginManager_Init(t *testing.T) { }) setting.AppUrl = "http://localhost:3000/" - pm := &PluginManager{ - Cfg: &setting.Cfg{ - PluginsPath: "testdata/invalid-v2-signature-2", - }, - BackendPluginManager: &fakeBackendPluginManager{}, - } + pm := createManager(t, func(pm *PluginManager) { + pm.Cfg.PluginsPath = "testdata/invalid-v2-signature-2" + }) err := pm.Init() require.NoError(t, err) assert.Equal(t, []error{fmt.Errorf(`plugin "test"'s signature has been modified`)}, pm.scanningErrors) @@ -291,3 +246,24 @@ func (f *fakeBackendPluginManager) CheckHealth(ctx context.Context, pCtx backend func (f *fakeBackendPluginManager) CallResource(pluginConfig backend.PluginContext, ctx *models.ReqContext, path string) { } + +func createManager(t *testing.T, cbs ...func(*PluginManager)) *PluginManager { + t.Helper() + + staticRootPath, err := filepath.Abs("../../../public/") + require.NoError(t, err) + + pm := &PluginManager{ + Cfg: &setting.Cfg{ + Raw: ini.Empty(), + Env: setting.Prod, + StaticRootPath: staticRootPath, + }, + BackendPluginManager: &fakeBackendPluginManager{}, + } + for _, cb := range cbs { + cb(pm) + } + + return pm +} diff --git a/pkg/services/notifications/notifications.go b/pkg/services/notifications/notifications.go index beea82f43e6..a6d709ac338 100644 --- a/pkg/services/notifications/notifications.go +++ b/pkg/services/notifications/notifications.go @@ -56,7 +56,7 @@ func (ns *NotificationService) Init() error { "Subject": subjectTemplateFunc, }) - templatePattern := filepath.Join(setting.StaticRootPath, ns.Cfg.Smtp.TemplatesPattern) + templatePattern := filepath.Join(ns.Cfg.StaticRootPath, ns.Cfg.Smtp.TemplatesPattern) _, err := mailTemplates.ParseGlob(templatePattern) if err != nil { return err diff --git a/pkg/services/notifications/notifications_test.go b/pkg/services/notifications/notifications_test.go index e7680c3943d..5f8744b6ec6 100644 --- a/pkg/services/notifications/notifications_test.go +++ b/pkg/services/notifications/notifications_test.go @@ -6,32 +6,31 @@ import ( "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/setting" - . "github.com/smartystreets/goconvey/convey" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) -func TestNotifications(t *testing.T) { - Convey("Given the notifications service", t, func() { - setting.StaticRootPath = "../../../public/" +func TestNotificationService(t *testing.T) { + ns := &NotificationService{ + Cfg: setting.NewCfg(), + } + ns.Cfg.StaticRootPath = "../../../public/" + ns.Cfg.Smtp.Enabled = true + ns.Cfg.Smtp.TemplatesPattern = "emails/*.html" + ns.Cfg.Smtp.FromAddress = "from@address.com" + ns.Cfg.Smtp.FromName = "Grafana Admin" + ns.Bus = bus.New() - ns := &NotificationService{} - ns.Bus = bus.New() - ns.Cfg = setting.NewCfg() - ns.Cfg.Smtp.Enabled = true - ns.Cfg.Smtp.TemplatesPattern = "emails/*.html" - ns.Cfg.Smtp.FromAddress = "from@address.com" - ns.Cfg.Smtp.FromName = "Grafana Admin" + err := ns.Init() + require.NoError(t, err) - err := ns.Init() - So(err, ShouldBeNil) + t.Run("When sending reset email password", func(t *testing.T) { + err := ns.sendResetPasswordEmail(&models.SendResetPasswordEmailCommand{User: &models.User{Email: "asd@asd.com"}}) + require.NoError(t, err) - Convey("When sending reset email password", func() { - err := ns.sendResetPasswordEmail(&models.SendResetPasswordEmailCommand{User: &models.User{Email: "asd@asd.com"}}) - So(err, ShouldBeNil) - - sentMsg := <-ns.mailQueue - So(sentMsg.Body, ShouldContainSubstring, "body") - So(sentMsg.Subject, ShouldEqual, "Reset your Grafana password - asd@asd.com") - So(sentMsg.Body, ShouldNotContainSubstring, "Subject") - }) + sentMsg := <-ns.mailQueue + assert.Contains(t, sentMsg.Body, "body") + assert.Equal(t, "Reset your Grafana password - asd@asd.com", sentMsg.Subject) + assert.NotContains(t, sentMsg.Body, "Subject") }) } diff --git a/pkg/services/rendering/rendering.go b/pkg/services/rendering/rendering.go index 847ee787fe8..b23804b8553 100644 --- a/pkg/services/rendering/rendering.go +++ b/pkg/services/rendering/rendering.go @@ -67,8 +67,8 @@ func (rs *RenderingService) Init() error { // RendererCallbackUrl has already been passed, it won't generate an error. u, _ := url.Parse(rs.Cfg.RendererCallbackUrl) rs.domain = u.Hostname() - case setting.HttpAddr != setting.DefaultHTTPAddr: - rs.domain = setting.HttpAddr + case rs.Cfg.HTTPAddr != setting.DefaultHTTPAddr: + rs.domain = rs.Cfg.HTTPAddr default: rs.domain = "localhost" } @@ -244,7 +244,7 @@ func (rs *RenderingService) getURL(path string) string { } // &render=1 signals to the legacy redirect layer to - return fmt.Sprintf("%s://%s:%s%s/%s&render=1", protocol, rs.domain, setting.HttpPort, subPath, path) + return fmt.Sprintf("%s://%s:%s%s/%s&render=1", protocol, rs.domain, rs.Cfg.HTTPPort, subPath, path) } func (rs *RenderingService) generateAndStoreRenderKey(orgId, userId int64, orgRole models.RoleType) (string, error) { diff --git a/pkg/services/rendering/rendering_test.go b/pkg/services/rendering/rendering_test.go index e0064b134f8..3390b0e9225 100644 --- a/pkg/services/rendering/rendering_test.go +++ b/pkg/services/rendering/rendering_test.go @@ -23,7 +23,7 @@ func TestGetUrl(t *testing.T) { t.Run("When renderer url not configured", func(t *testing.T) { rs.Cfg.RendererUrl = "" rs.domain = "localhost" - setting.HttpPort = "3000" + rs.Cfg.HTTPPort = "3000" t.Run("And protocol HTTP configured should return expected path", func(t *testing.T) { rs.Cfg.ServeFromSubPath = false diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go index c026d3f3eb4..b97ae595486 100644 --- a/pkg/setting/setting.go +++ b/pkg/setting/setting.go @@ -70,8 +70,6 @@ var ( CustomInitPath = "conf/custom.ini" // HTTP server options - HttpAddr, HttpPort string - CertFile, KeyFile string DataProxyLogging bool DataProxyTimeout int DataProxyTLSHandshakeTimeout int @@ -80,8 +78,6 @@ var ( DataProxyKeepAlive int DataProxyIdleConnTimeout int StaticRootPath string - EnableGzip bool - EnforceDomain bool // Security settings. SecretKey string @@ -187,6 +183,10 @@ type Cfg struct { Logger log.Logger // HTTP Server Settings + CertFile string + KeyFile string + HTTPAddr string + HTTPPort string AppURL string AppSubURL string ServeFromSubPath bool @@ -196,6 +196,8 @@ type Cfg struct { RouterLogging bool Domain string CDNRootURL *url.URL + EnableGzip bool + EnforceDomain bool // build BuildVersion string @@ -353,6 +355,8 @@ type Cfg struct { // ExpressionsEnabled specifies whether expressions are enabled. ExpressionsEnabled bool + + ImageUploadProvider string } // IsLiveEnabled returns if grafana live should be enabled @@ -895,7 +899,8 @@ func (cfg *Cfg) Load(args *CommandLineArgs) error { } imageUploadingSection := iniFile.Section("external_image_storage") - ImageUploadProvider = valueAsString(imageUploadingSection, "provider", "") + cfg.ImageUploadProvider = valueAsString(imageUploadingSection, "provider", "") + ImageUploadProvider = cfg.ImageUploadProvider enterprise := iniFile.Section("enterprise") cfg.EnterpriseLicensePath = valueAsString(enterprise, "license_path", filepath.Join(cfg.DataPath, "license.jwt")) @@ -1303,13 +1308,13 @@ func (cfg *Cfg) readServerSettings(iniFile *ini.File) error { if protocolStr == "https" { cfg.Protocol = HTTPSScheme - CertFile = server.Key("cert_file").String() - KeyFile = server.Key("cert_key").String() + cfg.CertFile = server.Key("cert_file").String() + cfg.KeyFile = server.Key("cert_key").String() } if protocolStr == "h2" { cfg.Protocol = HTTP2Scheme - CertFile = server.Key("cert_file").String() - KeyFile = server.Key("cert_key").String() + cfg.CertFile = server.Key("cert_file").String() + cfg.KeyFile = server.Key("cert_key").String() } if protocolStr == "socket" { cfg.Protocol = SocketScheme @@ -1317,12 +1322,12 @@ func (cfg *Cfg) readServerSettings(iniFile *ini.File) error { } cfg.Domain = valueAsString(server, "domain", "localhost") - HttpAddr = valueAsString(server, "http_addr", DefaultHTTPAddr) - HttpPort = valueAsString(server, "http_port", "3000") + cfg.HTTPAddr = valueAsString(server, "http_addr", DefaultHTTPAddr) + cfg.HTTPPort = valueAsString(server, "http_port", "3000") cfg.RouterLogging = server.Key("router_logging").MustBool(false) - EnableGzip = server.Key("enable_gzip").MustBool(false) - EnforceDomain = server.Key("enforce_domain").MustBool(false) + 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