Commit 703f728c by Carl Bergquist Committed by GitHub

Dashboards: Make path to default dashboard configurable (#25595)

Closes #25463

Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com>
Co-authored-by: Diana Payton <52059945+oddlittlebird@users.noreply.github.com>
parent cc95754e
...@@ -234,6 +234,9 @@ versions_to_keep = 20 ...@@ -234,6 +234,9 @@ versions_to_keep = 20
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m. # The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
min_refresh_interval = 5s min_refresh_interval = 5s
# Path to the default home dashboard. If this value is empty, then Grafana uses StaticRootPath + "dashboards/home.json"
default_home_dashboard_path =
#################################### Users ############################### #################################### Users ###############################
[users] [users]
# disable user signup / registration # disable user signup / registration
......
...@@ -233,6 +233,9 @@ ...@@ -233,6 +233,9 @@
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m. # The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
;min_refresh_interval = 5s ;min_refresh_interval = 5s
# Path to the default home dashboard. If this value is empty, then Grafana uses StaticRootPath + "dashboards/home.json"
;default_home_dashboard_path =
#################################### Users ############################### #################################### Users ###############################
[users] [users]
# disable user signup / registration # disable user signup / registration
......
...@@ -525,6 +525,11 @@ Number dashboard versions to keep (per dashboard). Default: `20`, Minimum: `1`. ...@@ -525,6 +525,11 @@ Number dashboard versions to keep (per dashboard). Default: `20`, Minimum: `1`.
This will restrict users to set the refresh interval of a dashboard lower than given interval. Per default this is 5 seconds. This will restrict users to set the refresh interval of a dashboard lower than given interval. Per default this is 5 seconds.
The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. `30s` or `1m`. The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. `30s` or `1m`.
### default_home_dashboard_path
Path to the default home dashboard. If this value is empty, then Grafana uses StaticRootPath + "dashboards/home.json"
## [dashboards.json] ## [dashboards.json]
> This have been replaced with dashboards [provisioning]({{< relref "../administration/provisioning" >}}) in 5.0+ > This have been replaced with dashboards [provisioning]({{< relref "../administration/provisioning" >}}) in 5.0+
......
...@@ -298,7 +298,7 @@ func (hs *HTTPServer) registerRoutes() { ...@@ -298,7 +298,7 @@ func (hs *HTTPServer) registerRoutes() {
dashboardRoute.Post("/calculate-diff", bind(dtos.CalculateDiffOptions{}), Wrap(CalculateDashboardDiff)) dashboardRoute.Post("/calculate-diff", bind(dtos.CalculateDiffOptions{}), Wrap(CalculateDashboardDiff))
dashboardRoute.Post("/db", bind(models.SaveDashboardCommand{}), Wrap(hs.PostDashboard)) dashboardRoute.Post("/db", bind(models.SaveDashboardCommand{}), Wrap(hs.PostDashboard))
dashboardRoute.Get("/home", Wrap(GetHomeDashboard)) dashboardRoute.Get("/home", Wrap(hs.GetHomeDashboard))
dashboardRoute.Get("/tags", GetDashboardTags) dashboardRoute.Get("/tags", GetDashboardTags)
dashboardRoute.Post("/import", bind(dtos.ImportDashboardCommand{}), Wrap(ImportDashboard)) dashboardRoute.Post("/import", bind(dtos.ImportDashboardCommand{}), Wrap(ImportDashboard))
......
...@@ -19,7 +19,6 @@ import ( ...@@ -19,7 +19,6 @@ import (
"github.com/grafana/grafana/pkg/infra/metrics" "github.com/grafana/grafana/pkg/infra/metrics"
"github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
) )
...@@ -315,15 +314,16 @@ func dashboardSaveErrorToApiResponse(err error) Response { ...@@ -315,15 +314,16 @@ func dashboardSaveErrorToApiResponse(err error) Response {
return Error(500, "Failed to save dashboard", err) return Error(500, "Failed to save dashboard", err)
} }
func GetHomeDashboard(c *models.ReqContext) Response { // GetHomeDashboard returns the home dashboard.
func (hs *HTTPServer) GetHomeDashboard(c *models.ReqContext) Response {
prefsQuery := models.GetPreferencesWithDefaultsQuery{User: c.SignedInUser} prefsQuery := models.GetPreferencesWithDefaultsQuery{User: c.SignedInUser}
if err := bus.Dispatch(&prefsQuery); err != nil { if err := hs.Bus.Dispatch(&prefsQuery); err != nil {
return Error(500, "Failed to get preferences", err) return Error(500, "Failed to get preferences", err)
} }
if prefsQuery.Result.HomeDashboardId != 0 { if prefsQuery.Result.HomeDashboardId != 0 {
slugQuery := models.GetDashboardRefByIdQuery{Id: prefsQuery.Result.HomeDashboardId} slugQuery := models.GetDashboardRefByIdQuery{Id: prefsQuery.Result.HomeDashboardId}
err := bus.Dispatch(&slugQuery) err := hs.Bus.Dispatch(&slugQuery)
if err == nil { if err == nil {
url := models.GetDashboardUrl(slugQuery.Result.Uid, slugQuery.Result.Slug) url := models.GetDashboardUrl(slugQuery.Result.Uid, slugQuery.Result.Slug)
dashRedirect := dtos.DashboardRedirect{RedirectUri: url} dashRedirect := dtos.DashboardRedirect{RedirectUri: url}
...@@ -332,7 +332,11 @@ func GetHomeDashboard(c *models.ReqContext) Response { ...@@ -332,7 +332,11 @@ func GetHomeDashboard(c *models.ReqContext) Response {
log.Warn("Failed to get slug from database, %s", err.Error()) log.Warn("Failed to get slug from database, %s", err.Error())
} }
filePath := path.Join(setting.StaticRootPath, "dashboards/home.json") filePath := hs.Cfg.DefaultHomeDashboardPath
if filePath == "" {
filePath = path.Join(hs.Cfg.StaticRootPath, "dashboards/home.json")
}
file, err := os.Open(filePath) file, err := os.Open(filePath)
if err != nil { if err != nil {
return Error(500, "Failed to load home dashboard", err) return Error(500, "Failed to load home dashboard", err)
......
...@@ -3,6 +3,7 @@ package api ...@@ -3,6 +3,7 @@ package api
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil"
"testing" "testing"
"github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/dtos"
...@@ -13,10 +14,58 @@ import ( ...@@ -13,10 +14,58 @@ import (
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/provisioning" "github.com/grafana/grafana/pkg/services/provisioning"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/stretchr/testify/require"
. "github.com/smartystreets/goconvey/convey" . "github.com/smartystreets/goconvey/convey"
) )
func TestGetHomeDashboard(t *testing.T) {
req := &models.ReqContext{SignedInUser: &models.SignedInUser{}}
cfg := setting.NewCfg()
cfg.StaticRootPath = "../../public/"
hs := &HTTPServer{Cfg: cfg, Bus: bus.New()}
hs.Bus.AddHandler(func(query *models.GetPreferencesWithDefaultsQuery) error {
query.Result = &models.Preferences{
HomeDashboardId: 0,
}
return nil
})
tests := []struct {
name string
defaultSetting string
expectedDashboardPath string
}{
{name: "using default config", defaultSetting: "", expectedDashboardPath: "../../public/dashboards/home.json"},
{name: "custom path", defaultSetting: "../../public/dashboards/default.json", expectedDashboardPath: "../../public/dashboards/default.json"},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
dash := dtos.DashboardFullWithMeta{}
dash.Meta.IsHome = true
dash.Meta.FolderTitle = "General"
homeDashJSON, err := ioutil.ReadFile(tc.expectedDashboardPath)
require.NoError(t, err, "must be able to read expected dashboard file")
hs.Cfg.DefaultHomeDashboardPath = tc.defaultSetting
bytes, err := simplejson.NewJson(homeDashJSON)
require.NoError(t, err, "must be able to encode file as JSON")
dash.Dashboard = bytes
b, err := json.Marshal(dash)
require.NoError(t, err, "must be able to marshal object to JSON")
res := hs.GetHomeDashboard(req)
nr, ok := res.(*NormalResponse)
require.True(t, ok, "should return *NormalResponse")
require.Equal(t, b, nr.body, "default home dashboard should equal content on disk")
})
}
}
// This tests three main scenarios. // This tests three main scenarios.
// If a user has access to execute an action on a dashboard: // If a user has access to execute an action on a dashboard:
// 1. and the dashboard is in a folder which does not have an acl // 1. and the dashboard is in a folder which does not have an acl
......
...@@ -227,6 +227,7 @@ type Cfg struct { ...@@ -227,6 +227,7 @@ type Cfg struct {
AppUrl string AppUrl string
AppSubUrl string AppSubUrl string
ServeFromSubPath bool ServeFromSubPath bool
StaticRootPath string
// build // build
BuildVersion string BuildVersion string
...@@ -272,6 +273,9 @@ type Cfg struct { ...@@ -272,6 +273,9 @@ type Cfg struct {
DisableSanitizeHtml bool DisableSanitizeHtml bool
EnterpriseLicensePath string EnterpriseLicensePath string
// Dashboards
DefaultHomeDashboardPath string
// Auth // Auth
LoginCookieName string LoginCookieName string
LoginMaxInactiveLifetimeDays int LoginMaxInactiveLifetimeDays int
...@@ -699,6 +703,7 @@ func (cfg *Cfg) Load(args *CommandLineArgs) error { ...@@ -699,6 +703,7 @@ func (cfg *Cfg) Load(args *CommandLineArgs) error {
return err return err
} }
StaticRootPath = makeAbsolute(staticRoot, HomePath) StaticRootPath = makeAbsolute(staticRoot, HomePath)
cfg.StaticRootPath = StaticRootPath
if err := cfg.validateStaticRootPath(); err != nil { if err := cfg.validateStaticRootPath(); err != nil {
return err return err
...@@ -778,6 +783,8 @@ func (cfg *Cfg) Load(args *CommandLineArgs) error { ...@@ -778,6 +783,8 @@ func (cfg *Cfg) Load(args *CommandLineArgs) error {
return err return err
} }
cfg.DefaultHomeDashboardPath = dashboards.Key("default_home_dashboard_path").MustString("")
// read data source proxy white list // read data source proxy white list
DataProxyWhiteList = make(map[string]bool) DataProxyWhiteList = make(map[string]bool)
securityStr, err := valueAsString(security, "data_source_proxy_whitelist", "") securityStr, err := valueAsString(security, "data_source_proxy_whitelist", "")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment